From 06d8ea8743a85a022c7633ee924eaef76df6bec4 Mon Sep 17 00:00:00 2001 From: Tyrone Johnson <77393391+tjcloa@users.noreply.github.com> Date: Thu, 8 Feb 2024 17:39:44 +0300 Subject: [PATCH] SOV-3613 Electron release * compile all electron sipArgs into 1 * update the sipArgs for permit2 integration * update mainnet deployment * update testnet deployment files * ran prettier * SOV-3613: adding LoanOpenings and SwapsImplSovrynSwapLib deployment objects for integrated QA tests * SOV-3613: adding VestingFactory and VestingLogic deployment objects for integretaed QA tests * SOV-3161 Increase borrowing debt fix * fix increase borrowing bug & refactor (stack too deep) * SOV-625 remove governance withdraw tokens * remove governanceWithdrawTokens from vestingLogic * using vesting start date to start withdrawal * introduce partial withdraw tokens in vesting contract * add validation for loanOpenings in onchain test * redeploy VestingFactory and VestingLogic due to matadata issue --- .../Staking/modules/StakingWithdrawModule.sol | 40 +- .../modules/shared/CheckpointsShared.sol | 2 +- contracts/governance/Vesting/ITeamVesting.sol | 2 +- contracts/governance/Vesting/Vesting.sol | 1 - .../governance/Vesting/VestingFactory.sol | 1 + contracts/governance/Vesting/VestingLogic.sol | 78 +- contracts/modules/LoanOpenings.sol | 62 +- .../deploy/1020-deploy-FeeSharingCollector.js | 2 +- deployment/deploy/2060-deploy-VestingLogic.js | 101 + .../deploy/2070-deploy-ProtocolModules.js | 8 +- .../rskSovrynMainnet/LoanOpenings.json | 50 +- .../SwapsImplSovrynSwapLib.json | 28 +- .../rskSovrynMainnet/VestingFactory.json | 313 ++ .../rskSovrynMainnet/VestingLogic.json | 687 ++++ .../16608baccc4c89e15713f1946c71539a.json | 711 +++++ .../444414c40f489390e118f5b65a5947cc.json | 711 +++++ .../aca886878e9e0827277d5a4711a5589b.json | 708 +++++ .../f540a853a80d796e3963ceeb76f3366c.json | 708 +++++ .../rskSovrynTestnet/LoanOpenings.json | 46 +- .../SwapsImplSovrynSwapLib.json | 28 +- .../rskSovrynTestnet/VestingFactory.json | 313 ++ .../rskSovrynTestnet/VestingLogic.json | 687 ++++ .../444414c40f489390e118f5b65a5947cc.json | 711 +++++ .../85e0140014063bf09a4ea91c8a627911.json | 708 +++++ .../a007dc3b696b2fbb46f7704420ad9de4.json | 708 +++++ .../aca886878e9e0827277d5a4711a5589b.json | 708 +++++ .../rskMainnet/BorrowerOperations.json | 1391 +++++++++ .../BorrowerOperations_Implementation.json | 1572 ++++++++++ .../rskMainnet/BorrowerOperations_Proxy.json | 110 + .../rskMainnet/MocIntegration.json | 547 ++++ .../MocIntegration_Implementation.json | 571 ++++ .../rskMainnet/MocIntegration_Proxy.json | 267 ++ .../rskMainnet/MyntAdminProxy.json | 244 ++ external/deployments/rskMainnet/Permit2.json | 904 ++++++ .../deployments/rskMainnet/StabilityPool.json | 1534 +++++++++ .../StabilityPool_Implementation.json | 1943 ++++++++++++ .../rskMainnet/StabilityPool_Proxy.json | 110 + .../deployments/rskMainnet/TroveManager.json | 2091 +++++++++++++ .../rskMainnet/TroveManagerRedeemOps.json | 1587 ++++++++++ .../TroveManager_Implementation.json | 2752 +++++++++++++++++ .../rskMainnet/TroveManager_Proxy.json | 110 + .../rskTestnet/BorrowerOperations.json | 1391 +++++++++ .../BorrowerOperations_Implementation.json | 1572 ++++++++++ .../rskTestnet/BorrowerOperations_Proxy.json | 110 + .../rskTestnet/MocIntegration.json | 547 ++++ .../MocIntegration_Implementation.json | 571 ++++ .../rskTestnet/MocIntegration_Proxy.json | 233 ++ external/deployments/rskTestnet/Permit2.json | 904 ++++++ .../deployments/rskTestnet/StabilityPool.json | 1534 +++++++++ .../StabilityPool_Implementation.json | 1943 ++++++++++++ .../rskTestnet/StabilityPool_Proxy.json | 110 + .../deployments/rskTestnet/TroveManager.json | 2091 +++++++++++++ .../rskTestnet/TroveManagerRedeemOps.json | 1587 ++++++++++ .../TroveManager_Implementation.json | 2752 +++++++++++++++++ .../rskTestnet/TroveManager_Proxy.json | 110 + hardhat/tasks/sips/args/sipArgs.js | 155 + hardhat/tasks/utils.js | 1 - remix-compiler.config.js | 9 + tests-onchain/sip0074.test.js | 208 ++ tests-onchain/sipSov625.test.js | 165 + tests-onchain/sip_sov3161.test.js | 152 + tests-onchain/sov3161.test.js | 463 +++ tests/loan-token/BorrowingTestToken.test.js | 248 ++ tests/staking/PauseStaking.test.js | 68 +- tests/vesting/Vesting.js | 1022 +++++- 65 files changed, 41643 insertions(+), 158 deletions(-) create mode 100644 deployment/deploy/2060-deploy-VestingLogic.js create mode 100644 deployment/deployments/rskSovrynMainnet/VestingFactory.json create mode 100644 deployment/deployments/rskSovrynMainnet/VestingLogic.json create mode 100644 deployment/deployments/rskSovrynMainnet/solcInputs/16608baccc4c89e15713f1946c71539a.json create mode 100644 deployment/deployments/rskSovrynMainnet/solcInputs/444414c40f489390e118f5b65a5947cc.json create mode 100644 deployment/deployments/rskSovrynMainnet/solcInputs/aca886878e9e0827277d5a4711a5589b.json create mode 100644 deployment/deployments/rskSovrynMainnet/solcInputs/f540a853a80d796e3963ceeb76f3366c.json create mode 100644 deployment/deployments/rskSovrynTestnet/VestingFactory.json create mode 100644 deployment/deployments/rskSovrynTestnet/VestingLogic.json create mode 100644 deployment/deployments/rskSovrynTestnet/solcInputs/444414c40f489390e118f5b65a5947cc.json create mode 100644 deployment/deployments/rskSovrynTestnet/solcInputs/85e0140014063bf09a4ea91c8a627911.json create mode 100644 deployment/deployments/rskSovrynTestnet/solcInputs/a007dc3b696b2fbb46f7704420ad9de4.json create mode 100644 deployment/deployments/rskSovrynTestnet/solcInputs/aca886878e9e0827277d5a4711a5589b.json create mode 100644 external/deployments/rskMainnet/BorrowerOperations.json create mode 100644 external/deployments/rskMainnet/BorrowerOperations_Implementation.json create mode 100644 external/deployments/rskMainnet/BorrowerOperations_Proxy.json create mode 100644 external/deployments/rskMainnet/MocIntegration.json create mode 100644 external/deployments/rskMainnet/MocIntegration_Implementation.json create mode 100644 external/deployments/rskMainnet/MocIntegration_Proxy.json create mode 100644 external/deployments/rskMainnet/MyntAdminProxy.json create mode 100644 external/deployments/rskMainnet/Permit2.json create mode 100644 external/deployments/rskMainnet/StabilityPool.json create mode 100644 external/deployments/rskMainnet/StabilityPool_Implementation.json create mode 100644 external/deployments/rskMainnet/StabilityPool_Proxy.json create mode 100644 external/deployments/rskMainnet/TroveManager.json create mode 100644 external/deployments/rskMainnet/TroveManagerRedeemOps.json create mode 100644 external/deployments/rskMainnet/TroveManager_Implementation.json create mode 100644 external/deployments/rskMainnet/TroveManager_Proxy.json create mode 100644 external/deployments/rskTestnet/BorrowerOperations.json create mode 100644 external/deployments/rskTestnet/BorrowerOperations_Implementation.json create mode 100644 external/deployments/rskTestnet/BorrowerOperations_Proxy.json create mode 100644 external/deployments/rskTestnet/MocIntegration.json create mode 100644 external/deployments/rskTestnet/MocIntegration_Implementation.json create mode 100644 external/deployments/rskTestnet/MocIntegration_Proxy.json create mode 100644 external/deployments/rskTestnet/Permit2.json create mode 100644 external/deployments/rskTestnet/StabilityPool.json create mode 100644 external/deployments/rskTestnet/StabilityPool_Implementation.json create mode 100644 external/deployments/rskTestnet/StabilityPool_Proxy.json create mode 100644 external/deployments/rskTestnet/TroveManager.json create mode 100644 external/deployments/rskTestnet/TroveManagerRedeemOps.json create mode 100644 external/deployments/rskTestnet/TroveManager_Implementation.json create mode 100644 external/deployments/rskTestnet/TroveManager_Proxy.json create mode 100644 remix-compiler.config.js create mode 100644 tests-onchain/sip0074.test.js create mode 100644 tests-onchain/sipSov625.test.js create mode 100644 tests-onchain/sip_sov3161.test.js create mode 100644 tests-onchain/sov3161.test.js diff --git a/contracts/governance/Staking/modules/StakingWithdrawModule.sol b/contracts/governance/Staking/modules/StakingWithdrawModule.sol index 10caeaa99..0abb1708c 100644 --- a/contracts/governance/Staking/modules/StakingWithdrawModule.sol +++ b/contracts/governance/Staking/modules/StakingWithdrawModule.sol @@ -90,8 +90,15 @@ contract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShar * @param _receiver The receiving address. * @param _startFrom The start value for the iterations. * or just unlocked tokens (false). + * + * @return nextStartFrom is a timestamp to be used for next withdrawal. + * @return notCompleted flag that indicates that the cancel team vesting is not completely done. * */ - function _cancelTeamVesting(address _vesting, address _receiver, uint256 _startFrom) private { + function _cancelTeamVesting( + address _vesting, + address _receiver, + uint256 _startFrom + ) private returns (uint256 nextStartFrom, bool notCompleted) { require(_receiver != address(0), "receiver address invalid"); ITeamVesting teamVesting = ITeamVesting(_vesting); @@ -130,9 +137,12 @@ contract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShar } if (adjustedEnd < end) { - emit TeamVestingPartiallyCancelled(msg.sender, _receiver, adjustedEnd); + nextStartFrom = adjustedEnd + TWO_WEEKS; + emit TeamVestingPartiallyCancelled(msg.sender, _receiver, nextStartFrom); + return (nextStartFrom, true); } else { emit TeamVestingCancelled(msg.sender, _receiver); + return (end, false); } } @@ -322,7 +332,6 @@ contract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShar * @notice Withdraw tokens for vesting contract. * @param vesting The address of Vesting contract. * @param receiver The receiver of the tokens. If not specified, send to the msg.sender - * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting. * @dev This function is dedicated only to support backward compatibility for sovryn ecosystem that has been implementing this staking contract. * @dev Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward. * https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/4bbfe5bd0311ca71e4ef0e3af810d3791d8e4061/contracts/governance/Staking/modules/StakingWithdrawModule.sol#L78 @@ -331,9 +340,28 @@ contract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShar address vesting, address receiver ) public onlyAuthorized whenNotFrozen { - vestingWhitelist[vesting] = true; - ITeamVesting(vesting).governanceWithdrawTokens(receiver); - vestingWhitelist[vesting] = false; + require(vestingRegistryLogic.isTeamVesting(vesting), "Only team vesting allowed"); + + ITeamVesting teamVesting = ITeamVesting(vesting); + uint256 teamVestingStartDate = teamVesting.startDate(); + uint256 teamVestingCliff = teamVesting.cliff(); + + uint256 nextStartFrom = teamVestingStartDate + teamVestingCliff; + bool withdrawFlag = true; + + bool notCompleted; + + /** + * The withdrawal is limited to certain iterations (set in maxVestingWithdrawIterations), so in order to withdraw all, we need to iterate until it is fully withdrawn. + */ + while (withdrawFlag) { + /** + * notCompleted is the flag whether the withdrawal is fully withdrawn or not. + * As long as the notCompleted is true, we will keep the iteration using the nextStartFrom. + */ + (nextStartFrom, notCompleted) = _cancelTeamVesting(vesting, receiver, nextStartFrom); + withdrawFlag = notCompleted ? true : false; + } emit VestingTokensWithdrawn(vesting, receiver); } diff --git a/contracts/governance/Staking/modules/shared/CheckpointsShared.sol b/contracts/governance/Staking/modules/shared/CheckpointsShared.sol index cd2d37a19..aac23e919 100644 --- a/contracts/governance/Staking/modules/shared/CheckpointsShared.sol +++ b/contracts/governance/Staking/modules/shared/CheckpointsShared.sol @@ -84,7 +84,7 @@ contract CheckpointsShared is StakingStorageShared, SafeMath96 { event TeamVestingPartiallyCancelled( address indexed caller, address receiver, - uint256 lastProcessedDate + uint256 nextStartFrom ); constructor() internal { diff --git a/contracts/governance/Vesting/ITeamVesting.sol b/contracts/governance/Vesting/ITeamVesting.sol index 2053c99ff..55940a54c 100644 --- a/contracts/governance/Vesting/ITeamVesting.sol +++ b/contracts/governance/Vesting/ITeamVesting.sol @@ -3,7 +3,7 @@ pragma solidity ^0.5.17; /** * @title Interface for TeamVesting contract. * @dev Interfaces are used to cast a contract address into a callable instance. - * This interface is used by Staking contract to call governanceWithdrawTokens + * This interface is used by Staking contract to cancel the team vesting * function having the vesting contract instance address. */ interface ITeamVesting { diff --git a/contracts/governance/Vesting/Vesting.sol b/contracts/governance/Vesting/Vesting.sol index c367ed3a5..481d13ded 100644 --- a/contracts/governance/Vesting/Vesting.sol +++ b/contracts/governance/Vesting/Vesting.sol @@ -8,7 +8,6 @@ import "./TeamVesting.sol"; * @notice Team tokens and investor tokens are vested. Therefore, a smart * contract needs to be developed to enforce the vesting schedule. * - * @dev TODO add tests for governanceWithdrawTokens. * */ contract Vesting is TeamVesting { /** diff --git a/contracts/governance/Vesting/VestingFactory.sol b/contracts/governance/Vesting/VestingFactory.sol index 730e167f3..8ee9857b8 100644 --- a/contracts/governance/Vesting/VestingFactory.sol +++ b/contracts/governance/Vesting/VestingFactory.sol @@ -1,4 +1,5 @@ pragma solidity ^0.5.17; +pragma experimental ABIEncoderV2; import "../../openzeppelin/Ownable.sol"; import "./Vesting.sol"; diff --git a/contracts/governance/Vesting/VestingLogic.sol b/contracts/governance/Vesting/VestingLogic.sol index 4e3f2b898..0094f6f29 100644 --- a/contracts/governance/Vesting/VestingLogic.sol +++ b/contracts/governance/Vesting/VestingLogic.sol @@ -8,6 +8,7 @@ import "../IFeeSharingCollector.sol"; import "./IVesting.sol"; import "../ApprovalReceiver.sol"; import "./VestingStorage.sol"; +import "../../openzeppelin/SafeMath.sol"; /** * @title Vesting Logic contract. @@ -15,11 +16,17 @@ import "./VestingStorage.sol"; * @dev Deployed by a VestingFactory contract. * */ contract VestingLogic is IVesting, VestingStorage, ApprovalReceiver { + using SafeMath for uint256; /* Events */ event TokensStaked(address indexed caller, uint256 amount); event VotesDelegated(address indexed caller, address delegatee); - event TokensWithdrawn(address indexed caller, address receiver); + event TokensWithdrawn( + address indexed caller, + address receiver, + uint256 startFrom, + uint256 end + ); event DividendsCollected( address indexed caller, address loanPoolToken, @@ -110,26 +117,36 @@ contract VestingLogic is IVesting, VestingStorage, ApprovalReceiver { } /** - * @notice Withdraws all tokens from the staking contract and + * @notice Withdraws unlocked tokens from the staking contract and * forwards them to an address specified by the token owner. * @param receiver The receiving address. - * @dev Can be called only by owner. - * @dev **WARNING** This function should not be no longer used by Sovryn Protocol. - * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward. * */ - function governanceWithdrawTokens(address receiver) public { - require(msg.sender == address(staking), "unauthorized"); - - _withdrawTokens(receiver, true); + function withdrawTokens(address receiver) public onlyOwners { + uint256 startFrom = startDate + cliff; + _withdrawTokens(receiver, startFrom, block.timestamp); } /** - * @notice Withdraws unlocked tokens from the staking contract and + * @notice Withdraws unlocked tokens partially (based on the max withdraw iteration that has been set) from the staking contract and * forwards them to an address specified by the token owner. * @param receiver The receiving address. + * @param startFrom The start value for the iterations. + * @param maxWithdrawIterations max withdrawal iteration to work around block gas limit issue. * */ - function withdrawTokens(address receiver) public onlyOwners { - _withdrawTokens(receiver, false); + function withdrawTokensStartingFrom( + address receiver, + uint256 startFrom, + uint256 maxWithdrawIterations + ) public onlyOwners { + uint256 defaultStartFrom = startDate + cliff; + + startFrom = _timestampToLockDate(startFrom); + startFrom = startFrom < defaultStartFrom ? defaultStartFrom : startFrom; + + // @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1 + uint256 maxWithdrawDate = (startFrom + (FOUR_WEEKS * (maxWithdrawIterations.sub(1)))); + uint256 endAt = endDate < maxWithdrawDate ? endDate : maxWithdrawDate; + _withdrawTokens(receiver, startFrom, endAt); } /** @@ -137,10 +154,11 @@ contract VestingLogic is IVesting, VestingStorage, ApprovalReceiver { * to an address specified by the token owner. Low level function. * @dev Once here the caller permission is taken for granted. * @param receiver The receiving address. - * @param isGovernance Whether all tokens (true) + * @param startFrom start withdrawal from date. + * @param endAt end time for regular withdrawal * or just unlocked tokens (false). * */ - function _withdrawTokens(address receiver, bool isGovernance) internal { + function _withdrawTokens(address receiver, uint256 startFrom, uint256 endAt) internal { require(receiver != address(0), "receiver address invalid"); uint96 stake; @@ -148,32 +166,27 @@ contract VestingLogic is IVesting, VestingStorage, ApprovalReceiver { /// @dev Usually we just need to iterate over the possible dates until now. uint256 end; - /// @dev In the unlikely case that all tokens have been unlocked early, - /// allow to withdraw all of them. - if (staking.allUnlocked() || isGovernance) { - end = endDate; + if (staking.allUnlocked()) { + end = endAt < endDate ? endAt : endDate; } else { - end = block.timestamp; + end = endAt < block.timestamp ? endAt : block.timestamp; + if (end > endDate) end = endDate; } /// @dev Withdraw for each unlocked position. /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS /// workaround found, but it doesn't work with TWO_WEEKS - for (uint256 i = startDate + cliff; i <= end; i += FOUR_WEEKS) { + for (uint256 i = startFrom; i <= end; i += FOUR_WEEKS) { /// @dev Read amount to withdraw. stake = staking.getPriorUserStakeByDate(address(this), i, block.number - 1); /// @dev Withdraw if > 0 if (stake > 0) { - if (isGovernance) { - staking.governanceWithdraw(stake, i, receiver); - } else { - staking.withdraw(stake, i, receiver); - } + staking.withdraw(stake, i, receiver); } } - emit TokensWithdrawn(msg.sender, receiver); + emit TokensWithdrawn(msg.sender, receiver, startFrom, end); } /** @@ -224,4 +237,17 @@ contract VestingLogic is IVesting, VestingStorage, ApprovalReceiver { selectors[0] = this.stakeTokensWithApproval.selector; return selectors; } + + function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) { + // Optimize gas costs by reading kickoffTS from storage only once. + uint256 start = startDate + cliff; + require(timestamp >= start, "timestamp < contract creation"); // WS23 + /** + * @dev If staking timestamp does not match any of the unstaking dates + * , set the lockDate to the closest one before the timestamp. + * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks. + * */ + uint256 periodFromKickoff = (timestamp - start) / FOUR_WEEKS; + lockDate = periodFromKickoff * FOUR_WEEKS + start; + } } diff --git a/contracts/modules/LoanOpenings.sol b/contracts/modules/LoanOpenings.sol index 9ae4c0035..58d0c7ebf 100644 --- a/contracts/modules/LoanOpenings.sol +++ b/contracts/modules/LoanOpenings.sol @@ -350,6 +350,9 @@ contract LoanOpenings is "invalid interest" ); + // @note this fix is for borrowing only + uint256 sentNewPrincipal = isTorqueLoan ? sentValues.newPrincipal : 0; + /// Initialize loan. Loan storage loanLocal = loans[ _initializeLoan( @@ -393,25 +396,13 @@ contract LoanOpenings is } } else { /// Update collateral after trade. - uint256 receivedAmount; - (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap( + sentValues = _updateCollateralAfterTrade( loanId, - loanParamsLocal.loanToken, - loanParamsLocal.collateralToken, - sentAddresses.borrower, /// borrower - sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount) - 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount) - 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped) - false, /// bypassFee + loanParamsLocal, + sentAddresses, + sentValues, loanDataBytes ); - sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount); - - /// Check the minEntryPrice with the rate - require( - sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice, - "entry price above the minimum" - ); } /// Settle collateral. @@ -421,7 +412,8 @@ contract LoanOpenings is loanLocal, initialMargin, sentValues.collateralTokenSent, - collateralAmountRequired + collateralAmountRequired, + sentNewPrincipal ), "collateral insufficient" ); @@ -441,6 +433,36 @@ contract LoanOpenings is return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral } + function _updateCollateralAfterTrade( + bytes32 loanId, + LoanParams memory loanParamsLocal, + MarginTradeStructHelpers.SentAddresses memory sentAddresses, + MarginTradeStructHelpers.SentAmounts memory sentValues, + bytes memory loanDataBytes + ) internal returns (MarginTradeStructHelpers.SentAmounts memory) { + uint256 receivedAmount; + (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap( + loanId, + loanParamsLocal.loanToken, + loanParamsLocal.collateralToken, + sentAddresses.borrower, /// borrower + sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount) + 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount) + 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped) + false, /// bypassFee + loanDataBytes + ); + sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount); + + /// Check the minEntryPrice with the rate + require( + sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice, + "entry price above the minimum" + ); + + return sentValues; + } + /** * @notice Finalize an open loan. * @@ -602,6 +624,7 @@ contract LoanOpenings is * @param initialMargin The initial amount of margin. * @param newCollateral The amount of new collateral. * @param collateralAmountRequired The amount of required collateral. + * @param newPrincipal The amount to borrow. * * @return Whether the collateral is satisfied. * */ @@ -610,7 +633,8 @@ contract LoanOpenings is Loan memory loanLocal, uint256 initialMargin, uint256 newCollateral, - uint256 collateralAmountRequired + uint256 collateralAmountRequired, + uint256 newPrincipal ) internal view returns (bool) { /// Allow at most 2% under-collateralized. collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether); @@ -621,7 +645,7 @@ contract LoanOpenings is uint256 maxDrawdown = IPriceFeeds(priceFeeds).getMaxDrawdown( loanParamsLocal.loanToken, loanParamsLocal.collateralToken, - loanLocal.principal, + loanLocal.principal.sub(newPrincipal), // sub(newPrincipal) to exclude the new borrowed amount from the total principal to calculate maxDrawdown for existing loan loanLocal.collateral, initialMargin ); diff --git a/deployment/deploy/1020-deploy-FeeSharingCollector.js b/deployment/deploy/1020-deploy-FeeSharingCollector.js index 778925e8c..b702f9e2d 100644 --- a/deployment/deploy/1020-deploy-FeeSharingCollector.js +++ b/deployment/deploy/1020-deploy-FeeSharingCollector.js @@ -16,7 +16,7 @@ const func = async function (hre) { "FeeSharingCollector_Proxy", true, [], - [(await get("ISovryn")).address, (await get("StakingProxy")).address] + [(await get("SovrynProtocol")).address, (await get("StakingProxy")).address] ); }; func.tags = ["FeeSharingCollector"]; diff --git a/deployment/deploy/2060-deploy-VestingLogic.js b/deployment/deploy/2060-deploy-VestingLogic.js new file mode 100644 index 000000000..f85dd7c05 --- /dev/null +++ b/deployment/deploy/2060-deploy-VestingLogic.js @@ -0,0 +1,101 @@ +const path = require("path"); +const { getContractNameFromScriptFileName } = require("../helpers/utils"); +const col = require("cli-color"); +const { sendWithMultisig } = require("../helpers/helpers"); +const { getArgsSipSov625 } = require("../../hardhat/tasks/sips/args/sipArgs"); +const func = async function (hre) { + const { + deployments: { deploy, get, log }, + getNamedAccounts, + ethers, + } = hre; + const { deployer } = await getNamedAccounts(); //await ethers.getSigners(); // + let totalGas = ethers.BigNumber.from(0); + + // Deploy vestingLogic // + log(col.bgYellow("Deploying VestingLogic...")); + await deploy("VestingLogic", { + from: deployer, + args: [], + log: true, + contract: "VestingLogic", + }); + + const vestingLogicDeployment = await get("VestingLogic"); + + // Deploy vestingFactory // + log(col.bgYellow("Deploying VestingFactory...")); + await deploy("VestingFactory", { + from: deployer, + args: [vestingLogicDeployment.address], + log: true, + contract: "VestingFactory", + }); + + const vestingFactoryDeployment = await get("VestingFactory"); + const vestingRegistry = await ethers.getContract("VestingRegistry"); + const staking = await ethers.getContract("Staking"); + const vestingFactory = await ethers.getContract("VestingFactory"); + + log(col.bgYellow("Transferring ownership of vestingFactory to VestingRegistry...")); + await vestingFactory.transferOwnership(vestingRegistry.address); + log(col.bgYellow(`New vestingFactory owner ${await vestingFactory.owner()}`)); + + const multisigDeployment = await get("MultiSigWallet"); + + if (hre.network.tags["testnet"]) { + const data = vestingRegistry.interface.encodeFunctionData("setVestingFactory", [ + vestingFactoryDeployment.address, + ]); + + log( + col.bgYellow( + "Generating multisig transaction to set the new vestingFactory contract in vestingRegistry..." + ) + ); + await sendWithMultisig( + multisigDeployment.address, + vestingRegistry.address, + data, + deployer + ); + log( + col.bgBlue( + `>>> DONE. Requires Multisig (${multisigDeployment.address}) signatures to execute tx <<<` + ) + ); + + const dataAddContractCodeHash = staking.interface.encodeFunctionData( + "addContractCodeHash", + [vestingLogicDeployment.address] + ); + log( + col.bgYellow( + "Generating multisig transaction to add codeHash of new vestingLogic in staking contract..." + ) + ); + await sendWithMultisig( + multisigDeployment.address, + staking.address, + dataAddContractCodeHash, + deployer + ); + log( + col.bgBlue( + `>>> DONE. Requires Multisig (${multisigDeployment.address}) signatures to execute tx <<<` + ) + ); + } else if (hre.network.tags["mainnet"]) { + /** TODO: update the sipArgs depends on the actual SIP number */ + log( + col.bgBlue( + "Prepare and run SIP function in sips.js to create the proposal with params: getArgsSipSov625" + ) + ); + + const sipArgs = await getArgsSipSov625(hre); + log(col.bgBlue(JSON.stringify(sipArgs))); + } +}; +func.tags = ["DeployVestingLogic"]; +module.exports = func; diff --git a/deployment/deploy/2070-deploy-ProtocolModules.js b/deployment/deploy/2070-deploy-ProtocolModules.js index c5593aa2d..8a99d484c 100644 --- a/deployment/deploy/2070-deploy-ProtocolModules.js +++ b/deployment/deploy/2070-deploy-ProtocolModules.js @@ -14,7 +14,7 @@ const func = async function (hre) { // e.g. you have three contracts modified but want to deploy only one // then add the modules not ready for deployment to `dontDeployModules` const deployModules = { - Affiliates: { + /*Affiliates: { moduleName: "Affiliates", sampleFunction: "setAffiliatesReferrer(address,address)", requireSwapsImplSovrynSwapLib: false, @@ -33,13 +33,13 @@ const func = async function (hre) { moduleName: "LoanClosingsWith", sampleFunction: "closeWithDeposit(bytes32,address,uint256)", requireSwapsImplSovrynSwapLib: true, - }, + },*/ LoanOpenings: { moduleName: "LoanOpenings", sampleFunction: "setDelegatedManager(bytes32,address,bool)", requireSwapsImplSovrynSwapLib: true, }, - LoanMaintenance: { + /*LoanMaintenance: { moduleName: "LoanMaintenance", sampleFunction: "getActiveLoans(uint256,uint256,bool)", requireSwapsImplSovrynSwapLib: true, @@ -63,7 +63,7 @@ const func = async function (hre) { moduleName: "SwapsImplSovrynSwapModule", sampleFunction: "getSovrynSwapNetworkContract(address)", requireSwapsImplSovrynSwapLib: true, - }, + },*/ }; log(col.bgYellow("Deploying ProtocolModules...")); const modulesList = getProtocolModules(); diff --git a/deployment/deployments/rskSovrynMainnet/LoanOpenings.json b/deployment/deployments/rskSovrynMainnet/LoanOpenings.json index a7c500e2a..fe7deeb82 100644 --- a/deployment/deployments/rskSovrynMainnet/LoanOpenings.json +++ b/deployment/deployments/rskSovrynMainnet/LoanOpenings.json @@ -1,5 +1,5 @@ { - "address": "0x7b520c4BDB4527A2c1cA8E24c245660df9636b22", + "address": "0x000fec34466972987928d519948AA1b25EACD3E9", "abi": [ { "inputs": [], @@ -1979,45 +1979,45 @@ "type": "function" } ], - "transactionHash": "0x0604d1876d718a73e5a82cf8b1d530b5316e153ebef661e1599ab2730b5b9a42", + "transactionHash": "0x75d0b4246bdc132590f69284776bab0bd95543000c5f41725930631c9a3e4909", "receipt": { "to": null, - "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", - "contractAddress": "0x7b520c4BDB4527A2c1cA8E24c245660df9636b22", - "transactionIndex": 1, - "gasUsed": "5868155", - "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000400000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000002000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x3524abc520e48aa1042610466075dbdf2795fd4ea8eb9f7fe28fe74bc0bfc214", - "transactionHash": "0x0604d1876d718a73e5a82cf8b1d530b5316e153ebef661e1599ab2730b5b9a42", + "from": "0xFEe171A152C02F336021fb9E79b4fAc2304a9E7E", + "contractAddress": "0x000fec34466972987928d519948AA1b25EACD3E9", + "transactionIndex": 0, + "gasUsed": "5911938", + "logsBloom": "0x00000000000000000000000800000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000080000000000000000000000000000000020000000000000002000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000100000000000000000", + "blockHash": "0xdb38d8d5803a7b8b9a97f7971034208d0cf3ec25df2481ee3dc7bda610ac7a1f", + "transactionHash": "0x75d0b4246bdc132590f69284776bab0bd95543000c5f41725930631c9a3e4909", "logs": [ { - "transactionIndex": 1, - "blockNumber": 5889036, - "transactionHash": "0x0604d1876d718a73e5a82cf8b1d530b5316e153ebef661e1599ab2730b5b9a42", - "address": "0x7b520c4BDB4527A2c1cA8E24c245660df9636b22", + "transactionIndex": 0, + "blockNumber": 5996098, + "transactionHash": "0x75d0b4246bdc132590f69284776bab0bd95543000c5f41725930631c9a3e4909", + "address": "0x000fec34466972987928d519948AA1b25EACD3E9", "topics": [ "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + "0x000000000000000000000000fee171a152c02f336021fb9e79b4fac2304a9e7e" ], "data": "0x", "logIndex": 0, - "blockHash": "0x3524abc520e48aa1042610466075dbdf2795fd4ea8eb9f7fe28fe74bc0bfc214" + "blockHash": "0xdb38d8d5803a7b8b9a97f7971034208d0cf3ec25df2481ee3dc7bda610ac7a1f" } ], - "blockNumber": 5889036, - "cumulativeGasUsed": "5926996", + "blockNumber": 5996098, + "cumulativeGasUsed": "5911938", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 1, - "solcInputHash": "9310031b42d2950fea7a6220c73f2cc4", - "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCollateral\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestDuration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"collateralToLoanRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"currentMargin\",\"type\":\"uint256\"}],\"name\":\"Borrow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegated\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isActive\",\"type\":\"bool\"}],\"name\":\"DelegatedManagerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeRebatePercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"basisPoint\",\"type\":\"uint256\"}],\"name\":\"EarnReward\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeRebatePercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"basisPoint\",\"type\":\"uint256\"}],\"name\":\"EarnRewardFail\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sourceAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"}],\"name\":\"ExternalSwap\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sourceAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"}],\"name\":\"LoanSwap\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayBorrowingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"interestToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"effectiveInterest\",\"type\":\"uint256\"}],\"name\":\"PayInterestTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayLendingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayTradingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"prevModuleContractAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newModuleContractAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"module\",\"type\":\"bytes32\"}],\"name\":\"ProtocolModuleContractReplaced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"positionSize\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"borrowedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"settlementDate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entryPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entryLeverage\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"currentLeverage\",\"type\":\"uint256\"}],\"name\":\"Trade\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"VaultDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"VaultWithdraw\",\"type\":\"event\"},{\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"constant\":true,\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"affiliateFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliateRewardsHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"affiliateTradingTokenFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliatesReferrerBalances\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliatesUserReferrer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"loanParamsId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"initialMargin\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"manager\",\"type\":\"address\"}],\"internalType\":\"struct MarginTradeStructHelpers.SentAddresses\",\"name\":\"sentAddresses\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestInitialAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"loanTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minEntryPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"loanToCollateralSwapRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"entryLeverage\",\"type\":\"uint256\"}],\"internalType\":\"struct MarginTradeStructHelpers.SentAmounts\",\"name\":\"sentValues\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"loanDataBytes\",\"type\":\"bytes\"}],\"name\":\"borrowOrTradeFromPool\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newCollateral\",\"type\":\"uint256\"}],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowerNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"borrowerOrders\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"lockedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"createdTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expirationTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"borrowingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"delegatedManagers\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feeRebatePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feesController\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"marginAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"}],\"name\":\"getBorrowAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"borrowAmount\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"loanTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"}],\"name\":\"getEstimatedMarginExposure\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"marginAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"}],\"name\":\"getRequiredCollateral\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"collateralAmountRequired\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lenderInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"principalTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"owedPerDay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"owedTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"paidTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"lenderOrders\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"lockedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"createdTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expirationTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"lendingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lendingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lendingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"liquidationIncentivePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loanInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"owedPerDay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"depositTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loanParams\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minInitialMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maintenanceMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"loanPoolToUnderlying\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loans\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"loanParamsId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"pendingTradesId\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"principal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateral\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startRate\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"lockedSOVAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"name\":\"logicTargets\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"maxDisagreement\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"maxSwapSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"minReferralsToPayout\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"pause\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"priceFeeds\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rolloverBaseReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rolloverFlexFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"delegated\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"toggle\",\"type\":\"bool\"}],\"name\":\"setDelegatedManager\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sourceBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sovTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sovrynSwapContractRegistryAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"specialRebates\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"supportedTokens\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"swapsImpl\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"tradingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tradingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tradingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"underlyingToLoanPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"userNotFirstTradeFlag\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"wrbtcToken\",\"outputs\":[{\"internalType\":\"contract IWrbtcERC20\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{\"borrowOrTradeFromPool(bytes32,bytes32,bool,uint256,(address,address,address,address),(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),bytes)\":{\"details\":\"Note: Only callable by loan pools (iTokens). Wrapper to _borrowOrTrade internal function.\",\"params\":{\"initialMargin\":\"The initial amount of margin.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanDataBytes\":\"The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\",\"loanId\":\"The ID of the loan. If 0, start a new loan.\",\"loanParamsId\":\"The ID of the loan parameters.\",\"sentAddresses\":\"The addresses to send tokens: lender, borrower, receiver and manager: lender: must match loan if loanId provided. borrower: must match loan if loanId provided. receiver: receiver of funds (address(0) assumes borrower address). manager: delegated manager of loan unless address(0).\",\"sentValues\":\"The values to send: interestRate: New loan interest rate. newPrincipal: New loan size (borrowAmount + any borrowed interest). interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length). loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans). collateralTokenSent: Total collateralToken deposit. minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\"},\"return\":\"newPrincipal The new loan size.newCollateral The new collateral amount.\"},\"getBorrowAmount(address,address,uint256,uint256,bool)\":{\"details\":\"Basically borrowAmount = collateral / marginAmount * Collateral is something that helps secure a loan. When you borrow money, you agree that your lender can take something and sell it to get their money back if you fail to repay the loan. That's the collateral.\",\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"collateralTokenAmount\":\"The amount of collateral.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanToken\":\"The loan token instance address.\",\"marginAmount\":\"The amount of margin of the trade.\"},\"return\":\"borrowAmount The borrow amount.\"},\"getEstimatedMarginExposure(address,address,uint256,uint256,uint256,uint256)\":{\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"collateralTokenSent\":\"The amount of collateral tokens sent.\",\"interestRate\":\"The interest rate. Percentage w/ 18 decimals.\",\"loanToken\":\"The loan token instance address.\",\"loanTokenSent\":\"The amount of loan tokens sent.\",\"newPrincipal\":\"The updated amount of principal (current debt).\"},\"return\":\"The margin exposure.\"},\"getRequiredCollateral(address,address,uint256,uint256,bool)\":{\"details\":\"Calls internal _getRequiredCollateral and add fees.\",\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanToken\":\"The loan token instance address.\",\"marginAmount\":\"The amount of margin of the trade.\",\"newPrincipal\":\"The updated amount of principal (current debt).\"},\"return\":\"collateralAmountRequired The required collateral.\"},\"initialize(address)\":{\"params\":{\"target\":\"The address of the target contract.\"}},\"isOwner()\":{\"details\":\"Returns true if the caller is the current owner.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"setDelegatedManager(bytes32,address,bool)\":{\"details\":\"Wrapper for _setDelegatedManager internal function.\",\"params\":{\"delegated\":\"The address of the delegated manager.\",\"loanId\":\"The ID of the loan. If 0, start a new loan.\",\"toggle\":\"The flag true/false for the delegated manager.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"Loan Openings contract.\"},\"userdoc\":{\"methods\":{\"borrowOrTradeFromPool(bytes32,bytes32,bool,uint256,(address,address,address,address),(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),bytes)\":{\"notice\":\"Borrow or trade from pool.\"},\"getBorrowAmount(address,address,uint256,uint256,bool)\":{\"notice\":\"Get the borrow amount of a trade loan.\"},\"getEstimatedMarginExposure(address,address,uint256,uint256,uint256,uint256)\":{\"notice\":\"Get the estimated margin exposure. * Margin is the money borrowed from a broker to purchase an investment and is the difference between the total value of investment and the loan amount. Margin trading refers to the practice of using borrowed funds from a broker to trade a financial asset, which forms the collateral for the loan from the broker.\"},\"getRequiredCollateral(address,address,uint256,uint256,bool)\":{\"notice\":\"Get the required collateral.\"},\"initialize(address)\":{\"notice\":\"Set function selectors on target contract.\"},\"setDelegatedManager(bytes32,address,bool)\":{\"notice\":\"Set the delegated manager.\"}},\"notice\":\"This contract code comes from bZx. bZx is a protocol for tokenized margin trading and lending https://bzx.network similar to the dYdX protocol. * This contract contains functions to borrow and trade.\"}},\"settings\":{\"compilationTarget\":{\"contracts/modules/LoanOpenings.sol\":\"LoanOpenings\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nlibrary MarginTradeStructHelpers {\\n struct SentAddresses {\\n address lender;\\n address borrower;\\n address receiver;\\n address manager;\\n }\\n\\n struct SentAmounts {\\n uint256 interestRate;\\n uint256 newPrincipal;\\n uint256 interestInitialAmount;\\n uint256 loanTokenSent;\\n uint256 collateralTokenSent;\\n uint256 minEntryPrice;\\n uint256 loanToCollateralSwapRate;\\n uint256 interestDuration;\\n uint256 entryLeverage;\\n }\\n}\\n\",\"keccak256\":\"0xf0612e2c0d13604a67c3d55efe88810c089f0b84ca63bd3ce82c1e09b0938973\"},\"contracts/core/Objects.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./objects/LoanStruct.sol\\\";\\nimport \\\"./objects/LoanParamsStruct.sol\\\";\\nimport \\\"./objects/OrderStruct.sol\\\";\\nimport \\\"./objects/LenderInterestStruct.sol\\\";\\nimport \\\"./objects/LoanInterestStruct.sol\\\";\\n\\n/**\\n * @title Objects contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract inherints and aggregates several structures needed to handle\\n * loans on the protocol.\\n * */\\ncontract Objects is\\n LoanStruct,\\n LoanParamsStruct,\\n OrderStruct,\\n LenderInterestStruct,\\n LoanInterestStruct\\n{\\n\\n}\\n\",\"keccak256\":\"0xa30b8887af813997ebb480f0aa296245f9f3bd728382060059aa087cd9ee332c\"},\"contracts/core/State.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./Objects.sol\\\";\\nimport \\\"../mixins/EnumerableAddressSet.sol\\\";\\nimport \\\"../mixins/EnumerableBytes32Set.sol\\\";\\nimport \\\"../openzeppelin/ReentrancyGuard.sol\\\";\\nimport \\\"../openzeppelin/Ownable.sol\\\";\\nimport \\\"../openzeppelin/SafeMath.sol\\\";\\nimport \\\"../interfaces/IWrbtcERC20.sol\\\";\\nimport \\\"../reentrancy/SharedReentrancyGuard.sol\\\";\\n\\n/**\\n * @title State contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage values of the Protocol.\\n * */\\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\\n using SafeMath for uint256;\\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\\n\\n /// Handles asset reference price lookups.\\n address public priceFeeds;\\n\\n /// Handles asset swaps using dex liquidity.\\n address public swapsImpl;\\n\\n /// Contract registry address of the Sovryn swap network.\\n address public sovrynSwapContractRegistryAddress;\\n\\n /// Implementations of protocol functions.\\n mapping(bytes4 => address) public logicTargets;\\n\\n /// Loans: loanId => Loan\\n mapping(bytes32 => Loan) public loans;\\n\\n /// Loan parameters: loanParamsId => LoanParams\\n mapping(bytes32 => LoanParams) public loanParams;\\n\\n /// lender => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\\n\\n /// borrower => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\\n\\n /// loanId => delegated => approved\\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\\n\\n /**\\n *** Interest ***\\n **/\\n\\n /// lender => loanToken => LenderInterest object\\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\\n\\n /// loanId => LoanInterest object\\n mapping(bytes32 => LoanInterest) public loanInterest;\\n\\n /**\\n *** Internals ***\\n **/\\n\\n /// Implementations set.\\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\\n\\n /// Active loans set.\\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\\n\\n /// Lender loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\\n\\n /// Borrow loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\\n\\n /// User loan params set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\\n\\n /// Address controlling fee withdrawals.\\n address public feesController;\\n\\n /// 10% fee /// Fee taken from lender interest payments.\\n uint256 public lendingFeePercent = 10**19;\\n\\n /// Total interest fees received and not withdrawn per asset.\\n mapping(address => uint256) public lendingFeeTokensHeld;\\n\\n /// Total interest fees withdraw per asset.\\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\\n mapping(address => uint256) public lendingFeeTokensPaid;\\n\\n /// 0.15% fee /// Fee paid for each trade.\\n uint256 public tradingFeePercent = 15 * 10**16;\\n\\n /// Total trading fees received and not withdrawn per asset.\\n mapping(address => uint256) public tradingFeeTokensHeld;\\n\\n /// Total trading fees withdraw per asset\\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\\n mapping(address => uint256) public tradingFeeTokensPaid;\\n\\n /// 0.09% fee /// Origination fee paid for each loan.\\n uint256 public borrowingFeePercent = 9 * 10**16;\\n\\n /// Total borrowing fees received and not withdrawn per asset.\\n mapping(address => uint256) public borrowingFeeTokensHeld;\\n\\n /// Total borrowing fees withdraw per asset.\\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\\n mapping(address => uint256) public borrowingFeeTokensPaid;\\n\\n /// Current protocol token deposit balance.\\n uint256 public protocolTokenHeld;\\n\\n /// Lifetime total payout of protocol token.\\n uint256 public protocolTokenPaid;\\n\\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\\n uint256 public affiliateFeePercent = 5 * 10**18;\\n\\n /// 5% collateral discount /// Discount on collateral for liquidators.\\n uint256 public liquidationIncentivePercent = 5 * 10**18;\\n\\n /// loanPool => underlying\\n mapping(address => address) public loanPoolToUnderlying;\\n\\n /// underlying => loanPool\\n mapping(address => address) public underlyingToLoanPool;\\n\\n /// Loan pools set.\\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\\n\\n /// Supported tokens for swaps.\\n mapping(address => bool) public supportedTokens;\\n\\n /// % disagreement between swap rate and reference rate.\\n uint256 public maxDisagreement = 5 * 10**18;\\n\\n /// Used as buffer for swap source amount estimations.\\n uint256 public sourceBuffer = 10000;\\n\\n /// Maximum support swap size in rBTC\\n uint256 public maxSwapSize = 50 ether;\\n\\n /// Nonce per borrower. Used for loan id creation.\\n mapping(address => uint256) public borrowerNonce;\\n\\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\\n uint256 public rolloverBaseReward = 16800000000000;\\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\\n\\n IWrbtcERC20 public wrbtcToken;\\n address public protocolTokenAddress;\\n\\n /// 50% fee rebate\\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\\n uint256 public feeRebatePercent = 50 * 10**18;\\n\\n address public admin;\\n\\n /// For modules interaction.\\n address public protocolAddress;\\n\\n /**\\n *** Affiliates ***\\n **/\\n\\n /// The flag is set on the user's first trade.\\n mapping(address => bool) public userNotFirstTradeFlag;\\n\\n /// User => referrer (affiliate).\\n mapping(address => address) public affiliatesUserReferrer;\\n\\n /// List of referral addresses affiliated to the referrer.\\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\\n\\n /// @dev Referral threshold for paying out to the referrer.\\n /// The referrer reward is being accumulated and locked until the threshold is passed.\\n uint256 public minReferralsToPayout = 3;\\n\\n /// @dev Total affiliate SOV rewards that held in the protocol\\n /// (Because the minimum referrals is less than the rule)\\n mapping(address => uint256) public affiliateRewardsHeld;\\n\\n /// @dev For affiliates SOV Bonus proccess.\\n address public sovTokenAddress;\\n address public lockedSOVAddress;\\n\\n /// @dev 20% fee share of trading token fee.\\n /// Fee share of trading token fee for affiliate program.\\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\\n\\n /// @dev Addresses of tokens in which commissions were paid to referrers.\\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\\n\\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\\n\\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\\n bool public pause; //Flag to pause all protocol modules\\n\\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\\n\\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\\n uint256 internal tradingRebateRewardsBasisPoint;\\n\\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\\n /// Will be used in internal swap.\\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\\n\\n address internal pauser;\\n\\n /**\\n * @notice Add signature and target to storage.\\n * @dev Protocol is a proxy and requires a way to add every\\n * module function dynamically during deployment.\\n * */\\n function _setTarget(bytes4 sig, address target) internal {\\n logicTargets[sig] = target;\\n\\n if (target != address(0)) {\\n logicTargetsSet.addBytes32(bytes32(sig));\\n } else {\\n logicTargetsSet.removeBytes32(bytes32(sig));\\n }\\n }\\n\\n modifier onlyAdminOrOwner() {\\n require(isOwner() || admin == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n\\n modifier onlyPauserOrOwner() {\\n require(isOwner() || pauser == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0xf8dfc02f3dc790c73b390a69898d0281c4473487bc91fec1f28fbebceacd3b3c\"},\"contracts/core/objects/LenderInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Lender Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Lender Interest.\\n * */\\ncontract LenderInterestStruct {\\n struct LenderInterest {\\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\\n uint256 paidTotal; /// Total interest paid so far for asset.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0x6583baadddded384836cec469980e7973ec09310ae505b4a2ec67fb7bc19e452\"},\"contracts/core/objects/LoanInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Interest.\\n * */\\ncontract LoanInterestStruct {\\n struct LoanInterest {\\n uint256 owedPerDay; /// Interest owed per day for loan.\\n uint256 depositTotal; /// Total escrowed interest for loan.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0xd9034c6adb1b72e1593589dca024dc4730a1ee8bf6b2dca9d22283f2e7159590\"},\"contracts/core/objects/LoanParamsStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Parameters.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Parameters.\\n * */\\ncontract LoanParamsStruct {\\n struct LoanParams {\\n /// @dev ID of loan params object.\\n bytes32 id;\\n /// @dev If false, this object has been disabled by the owner and can't\\n /// be used for future loans.\\n bool active;\\n /// @dev Owner of this object.\\n address owner;\\n /// @dev The token being loaned.\\n address loanToken;\\n /// @dev The required collateral token.\\n address collateralToken;\\n /// @dev The minimum allowed initial margin.\\n uint256 minInitialMargin;\\n /// @dev An unhealthy loan when current margin is at or below this value.\\n uint256 maintenanceMargin;\\n /// @dev The maximum term for new loans (0 means there's no max term).\\n uint256 maxLoanTerm;\\n }\\n}\\n\",\"keccak256\":\"0xe15aa97713521da7f501e5225af9d92cf34bd68d286dbfed86aa75aabb323945\"},\"contracts/core/objects/LoanStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Object.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Object.\\n * */\\ncontract LoanStruct {\\n struct Loan {\\n bytes32 id; /// ID of the loan.\\n bytes32 loanParamsId; /// The linked loan params ID.\\n bytes32 pendingTradesId; /// The linked pending trades ID.\\n bool active; /// If false, the loan has been fully closed.\\n uint256 principal; /// Total borrowed amount outstanding.\\n uint256 collateral; /// Total collateral escrowed for the loan.\\n uint256 startTimestamp; /// Loan start time.\\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\\n uint256 startMargin; /// Initial margin when the loan opened.\\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\\n address borrower; /// Borrower of this loan.\\n address lender; /// Lender of this loan.\\n }\\n}\\n\",\"keccak256\":\"0x7d05c3096a86d5892e4e72f3a01a5a806f13a5ac90ca6339c611e75c603637b4\"},\"contracts/core/objects/OrderStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Order.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Order.\\n * */\\ncontract OrderStruct {\\n struct Order {\\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\\n uint256 interestRate; /// Interest rate defined by the creator of this order.\\n uint256 minLoanTerm; /// Minimum loan term allowed.\\n uint256 maxLoanTerm; /// Maximum loan term allowed.\\n uint256 createdTimestamp; /// Timestamp when this order was created.\\n uint256 expirationTimestamp; /// Timestamp when this order expires.\\n }\\n}\\n\",\"keccak256\":\"0xcc053c5da34a5927041162259bf856ba913f3524ca03e63ad0c5877777d17e0f\"},\"contracts/events/AffiliatesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\ncontract AffiliatesEvents is ModulesCommonEvents {\\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\\n\\n event SetAffiliatesReferrerFail(\\n address indexed user,\\n address indexed referrer,\\n bool alreadySet,\\n bool userNotFirstTrade\\n );\\n\\n event SetUserNotFirstTradeFlag(address indexed user);\\n\\n event PayTradingFeeToAffiliate(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n bool indexed isHeld,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountPaid\\n );\\n\\n event PayTradingFeeToAffiliateFail(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountTryingToPaid\\n );\\n\\n event WithdrawAffiliatesReferrerTokenFees(\\n address indexed referrer,\\n address indexed receiver,\\n address indexed tokenAddress,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xf72cf23e90db3c49589ddc4e1796680ebfb69a9b146db89f9b61f5fcf6dd95ba\"},\"contracts/events/FeesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Fees Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for fee payments.\\n * */\\ncontract FeesEvents {\\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\\n\\n event PayTradingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event PayBorrowingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event EarnReward(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n\\n event EarnRewardFail(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n}\\n\",\"keccak256\":\"0xe69bf53e15479be5fde1cbaadaf0c004ee038e8a6a37c99f7769bf5d8387015f\"},\"contracts/events/LoanClosingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Closing Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan closing operations.\\n * */\\ncontract LoanClosingsEvents is ModulesCommonEvents {\\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\\n event CloseWithDeposit(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address closer,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\\n event CloseWithSwap(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n address closer,\\n uint256 positionCloseSize,\\n uint256 loanCloseAmount,\\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\\n event Liquidate(\\n address indexed user,\\n address indexed liquidator,\\n bytes32 indexed loanId,\\n address lender,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n event Rollover(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n uint256 principal,\\n uint256 collateral,\\n uint256 endTimestamp,\\n address rewardReceiver,\\n uint256 reward\\n );\\n\\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\\n}\\n\",\"keccak256\":\"0x1ea325b9a213012865a52f38941ce6c1e8c29dce919215b5bdcc63a8a5980be1\"},\"contracts/events/LoanMaintenanceEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Maintenance Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan maintenance operations.\\n * */\\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\\n}\\n\",\"keccak256\":\"0xdee5098b947c22bcef6e38ecaf62bae6941572d1c245d2065ad41ea4f494c61d\"},\"contracts/events/LoanOpeningsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Openings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan openings operations.\\n * */\\ncontract LoanOpeningsEvents is ModulesCommonEvents {\\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\\n event Borrow(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 newCollateral,\\n uint256 interestRate,\\n uint256 interestDuration,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\\n event Trade(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n uint256 positionSize,\\n uint256 borrowedAmount,\\n uint256 interestRate,\\n uint256 settlementDate,\\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\\n uint256 entryLeverage,\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\\n event DelegatedManagerSet(\\n bytes32 indexed loanId,\\n address indexed delegator,\\n address indexed delegated,\\n bool isActive\\n );\\n}\\n\",\"keccak256\":\"0x585710ce6c570c6dbd1b8daf43b63a54b1d60ad01ee1dc3cae407d74d78f3093\"},\"contracts/events/LoanSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan settings operations.\\n * */\\ncontract LoanSettingsEvents is ModulesCommonEvents {\\n event LoanParamsSetup(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\\n\\n event LoanParamsDisabled(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\\n}\\n\",\"keccak256\":\"0xae9c49678a7bc02c2283648939c474c8bfd33781506e05c635c8334c5bf8682f\"},\"contracts/events/ModulesCommonEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\n/**\\n * @title The common events for all modules\\n * @notice This contract contains the events which will be used by all modules\\n **/\\n\\ncontract ModulesCommonEvents {\\n event ProtocolModuleContractReplaced(\\n address indexed prevModuleContractAddress,\\n address indexed newModuleContractAddress,\\n bytes32 indexed module\\n );\\n}\\n\",\"keccak256\":\"0xb07af42d7e6b0fe983889b883691b662a58d2ef8d75b3f32f17faff1871c8b8f\"},\"contracts/events/ProtocolSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title The Protocol Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for protocol settings operations.\\n * */\\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetLoanPool(\\n address indexed sender,\\n address indexed loanPool,\\n address indexed underlying\\n );\\n\\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\\n\\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateTradingTokenFeePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetLiquidationIncentivePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetFeesController(\\n address indexed sender,\\n address indexed oldController,\\n address indexed newController\\n );\\n\\n event SetWrbtcToken(\\n address indexed sender,\\n address indexed oldWethToken,\\n address indexed newWethToken\\n );\\n\\n event SetSovrynSwapContractRegistryAddress(\\n address indexed sender,\\n address indexed oldSovrynSwapContractRegistryAddress,\\n address indexed newSovrynSwapContractRegistryAddress\\n );\\n\\n event SetProtocolTokenAddress(\\n address indexed sender,\\n address indexed oldProtocolToken,\\n address indexed newProtocolToken\\n );\\n\\n event WithdrawFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 lendingAmount,\\n uint256 tradingAmount,\\n uint256 borrowingAmount,\\n uint256 wRBTCConverted\\n );\\n\\n event WithdrawLendingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawTradingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawBorrowingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetRebatePercent(\\n address indexed sender,\\n uint256 oldRebatePercent,\\n uint256 newRebatePercent\\n );\\n\\n event SetSpecialRebates(\\n address indexed sender,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 oldSpecialRebatesPercent,\\n uint256 newSpecialRebatesPercent\\n );\\n\\n event SetProtocolAddress(\\n address indexed sender,\\n address indexed oldProtocol,\\n address indexed newProtocol\\n );\\n\\n event SetMinReferralsToPayoutAffiliates(\\n address indexed sender,\\n uint256 oldMinReferrals,\\n uint256 newMinReferrals\\n );\\n\\n event SetSOVTokenAddress(\\n address indexed sender,\\n address indexed oldTokenAddress,\\n address indexed newTokenAddress\\n );\\n\\n event SetLockedSOVAddress(\\n address indexed sender,\\n address indexed oldAddress,\\n address indexed newAddress\\n );\\n\\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\\n\\n event SetTradingRebateRewardsBasisPoint(\\n address indexed sender,\\n uint256 oldBasisPoint,\\n uint256 newBasisPoint\\n );\\n\\n event SetRolloverFlexFeePercent(\\n address indexed sender,\\n uint256 oldRolloverFlexFeePercent,\\n uint256 newRolloverFlexFeePercent\\n );\\n\\n event SetDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event RemoveDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\\n\\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\\n}\\n\",\"keccak256\":\"0x20ca66a2c53669aa33379bf5233e3bcdddbba3504cd430a0143f0ee3ce1c2641\"},\"contracts/events/SwapsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Swaps Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for swap operations.\\n * */\\ncontract SwapsEvents is ModulesCommonEvents {\\n event LoanSwap(\\n bytes32 indexed loanId,\\n address indexed sourceToken,\\n address indexed destToken,\\n address borrower,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n\\n event ExternalSwap(\\n address indexed user,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n}\\n\",\"keccak256\":\"0x0a1cd289076675980b916941ed923146160d34a8669fc3fb4a06610f285dfbd1\"},\"contracts/feeds/IPriceFeeds.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface IPriceFeeds {\\n function queryRate(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 rate, uint256 precision);\\n\\n function queryPrecision(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 precision);\\n\\n function queryReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount\\n ) external view returns (uint256 destAmount);\\n\\n function checkPriceDisagreement(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount,\\n uint256 destAmount,\\n uint256 maxSlippage\\n ) external view returns (uint256 sourceToDestSwapRate);\\n\\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\\n\\n function getMaxDrawdown(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (uint256);\\n\\n function getCurrentMarginAndCollateralSize(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\\n\\n function getCurrentMargin(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\\n\\n function shouldLiquidate(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (bool);\\n\\n function getFastGasPrice(address payToken) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x2e2c2b393336efedb97659a2fc21c8dfb75b70e15d2422a3bcbf7ebd5fc83c82\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/interfaces/ISovryn.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\npragma experimental ABIEncoderV2;\\n//TODO: stored in ./interfaces only while brownie isn't removed\\n//TODO: move to contracts/interfaces after with brownie is removed\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/ProtocolSettingsEvents.sol\\\";\\nimport \\\"../events/LoanSettingsEvents.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../events/LoanMaintenanceEvents.sol\\\";\\nimport \\\"../events/LoanClosingsEvents.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../events/AffiliatesEvents.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\ncontract ISovryn is\\n State,\\n ProtocolSettingsEvents,\\n LoanSettingsEvents,\\n LoanOpeningsEvents,\\n LoanMaintenanceEvents,\\n LoanClosingsEvents,\\n SwapsEvents,\\n AffiliatesEvents,\\n FeesEvents\\n{\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n ////// Protocol //////\\n\\n function replaceContract(address target) external;\\n\\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\\n\\n function getTarget(string calldata sig) external view returns (address);\\n\\n ////// Protocol Settings //////\\n\\n function setSovrynProtocolAddress(address newProtocolAddress) external;\\n\\n function setSOVTokenAddress(address newSovTokenAddress) external;\\n\\n function setLockedSOVAddress(address newSOVLockedAddress) external;\\n\\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\\n\\n function setPriceFeedContract(address newContract) external;\\n\\n function setSwapsImplContract(address newContract) external;\\n\\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\\n\\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\\n\\n function setLendingFeePercent(uint256 newValue) external;\\n\\n function setTradingFeePercent(uint256 newValue) external;\\n\\n function setBorrowingFeePercent(uint256 newValue) external;\\n\\n function setSwapExternalFeePercent(uint256 newValue) external;\\n\\n function setAffiliateFeePercent(uint256 newValue) external;\\n\\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\\n\\n function setLiquidationIncentivePercent(uint256 newAmount) external;\\n\\n function setMaxDisagreement(uint256 newAmount) external;\\n\\n function setSourceBuffer(uint256 newAmount) external;\\n\\n function setMaxSwapSize(uint256 newAmount) external;\\n\\n function setFeesController(address newController) external;\\n\\n function withdrawFees(address[] calldata tokens, address receiver)\\n external\\n returns (uint256 totalWRBTCWithdrawn);\\n\\n function withdrawLendingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawTradingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawBorrowingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawProtocolToken(address receiver, uint256 amount)\\n external\\n returns (address, bool);\\n\\n function depositProtocolToken(uint256 amount) external;\\n\\n function getLoanPoolsList(uint256 start, uint256 count)\\n external\\n view\\n returns (bytes32[] memory);\\n\\n function isLoanPool(address loanPool) external view returns (bool);\\n\\n function setWrbtcToken(address wrbtcTokenAddress) external;\\n\\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\\n\\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\\n\\n function setRolloverBaseReward(uint256 transactionCost) external;\\n\\n function setRebatePercent(uint256 rebatePercent) external;\\n\\n function setSpecialRebates(\\n address sourceToken,\\n address destToken,\\n uint256 specialRebatesPercent\\n ) external;\\n\\n function getSpecialRebates(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 specialRebatesPercent);\\n\\n function togglePaused(bool paused) external;\\n\\n function isProtocolPaused() external view returns (bool);\\n\\n ////// SwapsImplSovrynSwapModule //////\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (address);\\n\\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\\n\\n function swapsImplExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function swapsImplExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256 expectedReturn);\\n\\n ////// Loan Settings //////\\n\\n function setupLoanParams(LoanParams[] calldata loanParamsList)\\n external\\n returns (bytes32[] memory loanParamsIdList);\\n\\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\\n\\n function getLoanParams(bytes32[] calldata loanParamsIdList)\\n external\\n view\\n returns (LoanParams[] memory loanParamsList);\\n\\n function getLoanParamsList(\\n address owner,\\n uint256 start,\\n uint256 count\\n ) external view returns (bytes32[] memory loanParamsList);\\n\\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\\n\\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\\n\\n ////// Loan Openings //////\\n\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId, // if 0, start a new loan\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n // lender: must match loan if loanId provided\\n // borrower: must match loan if loanId provided\\n // receiver: receiver of funds (address(0) assumes borrower address)\\n // manager: delegated manager of loan unless address(0)\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n // newRate: new loan interest rate\\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\\n // collateralTokenReceived: total collateralToken deposit\\n bytes calldata loanDataBytes\\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\\n\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external;\\n\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256);\\n\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 collateralAmountRequired);\\n\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 borrowAmount);\\n\\n ////// Loan Closings //////\\n\\n function liquidate(\\n bytes32 loanId,\\n address receiver,\\n uint256 closeAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 seizedAmount,\\n address seizedToken\\n );\\n\\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\\n\\n function closeWithDeposit(\\n bytes32 loanId,\\n address receiver,\\n uint256 depositAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n function closeWithSwap(\\n bytes32 loanId,\\n address receiver,\\n uint256 swapAmount, // denominated in collateralToken\\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\\n bytes calldata loanDataBytes\\n )\\n external\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n ////// Loan Maintenance //////\\n\\n function depositCollateral(\\n bytes32 loanId,\\n uint256 depositAmount // must match msg.value if ether is sent\\n ) external payable;\\n\\n function withdrawCollateral(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 actualWithdrawAmount);\\n\\n function withdrawAccruedInterest(address loanToken) external;\\n\\n function getLenderInterestData(address lender, address loanToken)\\n external\\n view\\n returns (\\n uint256 interestPaid,\\n uint256 interestPaidDate,\\n uint256 interestOwedPerDay,\\n uint256 interestUnPaid,\\n uint256 interestFeePercent,\\n uint256 principalTotal\\n );\\n\\n function getLoanInterestData(bytes32 loanId)\\n external\\n view\\n returns (\\n address loanToken,\\n uint256 interestOwedPerDay,\\n uint256 interestDepositTotal,\\n uint256 interestDepositRemaining\\n );\\n\\n struct LoanReturnData {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; // collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n }\\n\\n struct LoanReturnDataV2 {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n address borrower;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; /// collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n uint256 creationTimestamp;\\n }\\n\\n function getUserLoans(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getUserLoansV2(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\\n\\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\\n\\n function getActiveLoans(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getActiveLoansV2(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function extendLoanDuration(\\n bytes32 loanId,\\n uint256 depositAmount,\\n bool useCollateral,\\n bytes calldata /// loanDataBytes, for future use.\\n ) external returns (uint256 secondsExtended);\\n\\n function reduceLoanDuration(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 secondsReduced);\\n\\n ////// Swaps External //////\\n function swapExternal(\\n address sourceToken,\\n address destToken,\\n address receiver,\\n address returnToSender,\\n uint256 sourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n uint256 minReturn,\\n bytes calldata swapData\\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\\n\\n function getSwapExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function checkPriceDivergence(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount,\\n uint256 minReturn\\n ) public view;\\n\\n ////// Affiliates Module //////\\n\\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\\n\\n function setUserNotFirstTradeFlag(address user) external;\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address referrer,\\n address trader,\\n address token,\\n uint256 tradingFeeTokenBaseAmount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n\\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\\n\\n function getReferralsList(address referrer) external view returns (address[] memory refList);\\n\\n function getAffiliatesReferrerBalances(address referrer)\\n external\\n view\\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\\n\\n function getAffiliatesReferrerTokensList(address referrer)\\n external\\n view\\n returns (address[] memory tokensList);\\n\\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\\n external\\n view\\n returns (uint256);\\n\\n function withdrawAffiliatesReferrerTokenFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external;\\n\\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\\n\\n function getProtocolAddress() external view returns (address);\\n\\n function getSovTokenAddress() external view returns (address);\\n\\n function getLockedSOVAddress() external view returns (address);\\n\\n function getFeeRebatePercent() external view returns (uint256);\\n\\n function getMinReferralsToPayout() external view returns (uint256);\\n\\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\\n\\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\\n\\n function getAffiliateTradingTokenFeePercent()\\n external\\n view\\n returns (uint256 affiliateTradingTokenFeePercent);\\n\\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\\n external\\n view\\n returns (uint256 rbtcTotalAmount);\\n\\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\\n\\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\\n\\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\\n\\n function getDedicatedSOVRebate() external view returns (uint256);\\n\\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\\n\\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external\\n view\\n returns (IERC20[] memory);\\n\\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\\n\\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external;\\n\\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\\n external\\n view\\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\\n\\n function setAdmin(address newAdmin) external;\\n\\n function getAdmin() external view returns (address);\\n\\n function setPauser(address newPauser) external;\\n\\n function getPauser() external view returns (address);\\n}\\n\",\"keccak256\":\"0x4e470e1fe1719c2c58b0e44aedce3ee6a21191063b533ccb71c9219a192e8884\"},\"contracts/interfaces/IWrbtc.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ninterface IWrbtc {\\n function deposit() external payable;\\n\\n function withdraw(uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x20fdfe4b5e32fd7f863b3fa128e3c80bd4ccf090a4ffba56186ef3b7f2a80492\"},\"contracts/interfaces/IWrbtcERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./IWrbtc.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\n\\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\\n\",\"keccak256\":\"0x7301a8c8ca7aa016ec94268a16d07366875f2e406442e929968dd745b1ee5be5\"},\"contracts/mixins/EnumerableAddressSet.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Based on Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * As of v2.5.0, only `address` sets are supported.\\n *\\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\\n *\\n * _Available since v2.5.0._\\n */\\nlibrary EnumerableAddressSet {\\n struct AddressSet {\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(address => uint256) index;\\n address[] values;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n * Returns false if the value was already in the set.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n * Returns false if the value was not present in the set.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n // If the element we're deleting is the last one, we can just remove it without doing a swap\\n if (lastIndex != toDeleteIndex) {\\n address lastValue = set.values[lastIndex];\\n\\n // Move the last value to the index where the deleted value is\\n set.values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n // Delete the index entry for the deleted value\\n delete set.index[value];\\n\\n // Delete the old entry for the moved value\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns an array with all values in the set. O(N).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\\n address[] memory output = new address[](set.values.length);\\n for (uint256 i; i < set.values.length; i++) {\\n output[i] = set.values[i];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n \\n * @param start start index of chunk\\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\\n */\\n function enumerateChunk(\\n AddressSet storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (address[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = (set.values.length < end || count == 0) ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new address[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns the number of elements on the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /** @dev Returns the element stored at position `index` in the set. O(1).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xea6fba941ec8502aa11a7ab37e74b917d0dc47bb254e359a2870a87ef97d9872\"},\"contracts/mixins/EnumerableBytes32Set.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title Library for managing loan sets.\\n *\\n * @notice Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\\n * */\\nlibrary EnumerableBytes32Set {\\n struct Bytes32Set {\\n /// Position of the value in the `values` array, plus 1 because index 0\\n /// means a value is not in the set.\\n mapping(bytes32 => uint256) index;\\n bytes32[] values;\\n }\\n\\n /**\\n * @notice Add an address value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return addBytes32(set, value);\\n }\\n\\n /**\\n * @notice Add a value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The new value to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Remove an address value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to remove.\\n *\\n * @return False if the address was not present in the set.\\n */\\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return removeBytes32(set, value);\\n }\\n\\n /**\\n * @notice Remove a value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The value to remove.\\n *\\n * @return False if the value was not present in the set.\\n */\\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n /// If the element we're deleting is the last one,\\n /// we can just remove it without doing a swap.\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set.values[lastIndex];\\n\\n /// Move the last value to the index where the deleted value is.\\n set.values[toDeleteIndex] = lastValue;\\n\\n /// Update the index for the moved value.\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n /// Delete the index entry for the deleted value.\\n delete set.index[value];\\n\\n /// Delete the old entry for the moved value.\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Find out whether a value exists in the set.\\n *\\n * @param set The set of values.\\n * @param value The value to find.\\n *\\n * @return True if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function containsAddress(Bytes32Set storage set, address addrvalue)\\n internal\\n view\\n returns (bool)\\n {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @notice Get all set values.\\n *\\n * @param set The set of values.\\n * @param start The offset of the returning set.\\n * @param count The limit of number of values to return.\\n *\\n * @return An array with all values in the set. O(N).\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(\\n Bytes32Set storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (bytes32[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = set.values.length < end ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new bytes32[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @notice Get the legth of the set.\\n *\\n * @param set The set of values.\\n *\\n * @return the number of elements on the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /**\\n * @notice Get an item from the set by its index.\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n *\\n * @param set The set of values.\\n * @param index The index of the value to return.\\n *\\n * @return the element stored at position `index` in the set. O(1).\\n */\\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xa2801a585c566e07f21c1ebccd0cd0447dd5fd9fe6c1ff2b58d4d979d88a6db0\"},\"contracts/mixins/FeesHelper.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../modules/interfaces/ProtocolAffiliatesInterface.sol\\\";\\nimport \\\"../interfaces/ISovryn.sol\\\";\\nimport \\\"../core/objects/LoanParamsStruct.sol\\\";\\n\\n/**\\n * @title The Fees Helper contract.\\n *\\n * This contract calculates and pays lending/borrow fees and rewards.\\n * */\\ncontract FeesHelper is State, FeesEvents {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Calculate trading fee.\\n * @param feeTokenAmount The amount of tokens to trade.\\n * @return The fee of the trade.\\n * */\\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\\n }\\n\\n /**\\n * @notice Calculate swap external fee.\\n * @param feeTokenAmount The amount of token to swap.\\n * @return The fee of the swap.\\n */\\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\\n }\\n\\n /*\\n\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\\n\\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n\\t\\tuint256 collateralAmountRequired =\\n\\t\\t\\tfeeTokenAmount.mul(10**20).divCeil(\\n\\t\\t\\t\\t10**20 - tradingFeePercent // never will overflow\\n\\t\\t\\t);\\n\\t\\treturn collateralAmountRequired.sub(feeTokenAmount);\\n\\t}*/\\n\\n /**\\n * @notice Calculate the loan origination fee.\\n * @param feeTokenAmount The amount of tokens to borrow.\\n * @return The fee of the loan.\\n * */\\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\\n /*\\n\\t\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t\\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\\n\\t\\tuint256 collateralAmountRequired =\\n\\t\\t\\tfeeTokenAmount.mul(10**20).divCeil(\\n\\t\\t\\t\\t10**20 - borrowingFeePercent // never will overflow\\n\\t\\t\\t);\\n\\t\\treturn collateralAmountRequired.sub(feeTokenAmount);*/\\n }\\n\\n /**\\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\\n *\\n * @param referrer The affiliate referrer address to send the reward to.\\n * @param trader The account that performs this trade.\\n * @param feeToken The address of the token in which the trading fee is paid.\\n * @param tradingFee The amount of tokens accrued as fees on the trading.\\n *\\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\\n * */\\n function _payTradingFeeToAffiliate(\\n address referrer,\\n address trader,\\n address feeToken,\\n uint256 tradingFee\\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\\n address(this)\\n )\\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\\n }\\n\\n /**\\n * @notice Settle the trading fee and pay the token reward to the user.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associated loan - used for logging only.\\n * @param feeToken The address of the token in which the trading fee is paid.\\n * @param tradingFee The amount of tokens accrued as fees on the trading.\\n * */\\n function _payTradingFee(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 tradingFee\\n ) internal {\\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\\n if (tradingFee != 0) {\\n if (affiliatesUserReferrer[user] != address(0)) {\\n _payTradingFeeToAffiliate(\\n affiliatesUserReferrer[user],\\n user,\\n feeToken,\\n protocolTradingFee\\n );\\n protocolTradingFee = (\\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\\n )\\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\\n }\\n\\n /// Increase the storage variable keeping track of the accumulated fees.\\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\\n protocolTradingFee\\n );\\n\\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\\n\\n /// Pay the token reward to the user.\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\\n }\\n }\\n\\n /**\\n * @notice Settle the borrowing fee and pay the token reward to the user.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associated loan - used for logging only.\\n * @param feeToken The address of the token in which the borrowig fee is paid.\\n * @param borrowingFee The height of the fee.\\n * */\\n function _payBorrowingFee(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 borrowingFee\\n ) internal {\\n if (borrowingFee != 0) {\\n /// Increase the storage variable keeping track of the accumulated fees.\\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\\n\\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\\n\\n /// Pay the token reward to the user.\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\\n }\\n }\\n\\n /**\\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\\n * @param user The address to send the reward to.\\n * @param feeToken The address of the token in which the lending fee is paid.\\n * @param lendingFee The height of the fee.\\n * */\\n function _payLendingFee(\\n address user,\\n address feeToken,\\n uint256 lendingFee\\n ) internal {\\n if (lendingFee != 0) {\\n /// Increase the storage variable keeping track of the accumulated fees.\\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\\n\\n emit PayLendingFee(user, feeToken, lendingFee);\\n\\n //// NOTE: Lenders do not receive a fee reward ////\\n }\\n }\\n\\n /// Settle and pay borrowers based on the fees generated by their interest payments.\\n function _settleFeeRewardForInterestExpense(\\n LoanInterest storage loanInterestLocal,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n address user,\\n uint256 interestTime\\n ) internal {\\n /// This represents the fee generated by a borrower's interest payment.\\n uint256 interestExpenseFee =\\n interestTime\\n .sub(loanInterestLocal.updatedTimestamp)\\n .mul(loanInterestLocal.owedPerDay)\\n .mul(lendingFeePercent)\\n .div(1 days * 10**20);\\n\\n loanInterestLocal.updatedTimestamp = interestTime;\\n\\n if (interestExpenseFee != 0) {\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\\n }\\n }\\n\\n /**\\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associeated loan - used for logging only.\\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\\n * @param feeAmount The height of the fee.\\n * */\\n function _payFeeReward(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 feeAmount\\n ) internal {\\n uint256 rewardAmount;\\n uint256 _feeRebatePercent = feeRebatePercent;\\n address _priceFeeds = priceFeeds;\\n\\n if (specialRebates[feeToken][feeTokenPair] > 0) {\\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\\n }\\n\\n /// Note: this should be refactored.\\n /// Calculate the reward amount, querying the price feed.\\n (bool success, bytes memory data) =\\n _priceFeeds.staticcall(\\n abi.encodeWithSelector(\\n IPriceFeeds(_priceFeeds).queryReturn.selector,\\n feeToken,\\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\\n feeAmount.mul(_feeRebatePercent).div(10**20)\\n )\\n );\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n if eq(success, 1) {\\n rewardAmount := mload(add(data, 32))\\n }\\n }\\n\\n // Check the dedicated SOV that is used to pay trading rebate rewards\\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\\n\\n (bool success, ) =\\n lockedSOVAddress.call(\\n abi.encodeWithSignature(\\n \\\"deposit(address,uint256,uint256)\\\",\\n user,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n )\\n );\\n\\n if (success) {\\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\\n\\n emit EarnReward(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n } else {\\n emit EarnRewardFail(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n }\\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\\n emit EarnRewardFail(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0x9094bce5eab7109594a795982a779641c951c2617a618f5eab1f651b3b945077\"},\"contracts/mixins/InterestUser.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../mixins/VaultController.sol\\\";\\nimport \\\"./FeesHelper.sol\\\";\\n\\n/**\\n * @title The Interest User contract.\\n *\\n * This contract pays loan interests.\\n * */\\ncontract InterestUser is VaultController, FeesHelper {\\n using SafeERC20 for IERC20;\\n\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n /**\\n * @notice Internal function to pay interest of a loan.\\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\\n * @param lender The account address of the lender.\\n * @param interestToken The token address to pay interest with.\\n * */\\n function _payInterest(address lender, address interestToken) internal {\\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\\n\\n uint256 interestOwedNow = 0;\\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\\n interestOwedNow = block\\n .timestamp\\n .sub(lenderInterestLocal.updatedTimestamp)\\n .mul(lenderInterestLocal.owedPerDay)\\n .div(1 days);\\n\\n lenderInterestLocal.updatedTimestamp = block.timestamp;\\n\\n if (interestOwedNow > lenderInterestLocal.owedTotal)\\n interestOwedNow = lenderInterestLocal.owedTotal;\\n\\n if (interestOwedNow != 0) {\\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\\n\\n _payInterestTransfer(lender, interestToken, interestOwedNow);\\n }\\n } else {\\n lenderInterestLocal.updatedTimestamp = block.timestamp;\\n }\\n }\\n\\n /**\\n * @notice Internal function to transfer tokens for the interest of a loan.\\n * @param lender The account address of the lender.\\n * @param interestToken The token address to pay interest with.\\n * @param interestOwedNow The amount of interest to pay.\\n * */\\n function _payInterestTransfer(\\n address lender,\\n address interestToken,\\n uint256 interestOwedNow\\n ) internal {\\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\\n /// TODO: refactor: data incapsulation violation and DRY design principles\\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\\n\\n _payLendingFee(lender, interestToken, lendingFee);\\n\\n /// Transfers the interest to the lender, less the interest fee.\\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\\n\\n /// Event Log\\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\\n }\\n}\\n\",\"keccak256\":\"0x870208d1ae2c7adca9478b86fe5e70b4458bf719d49b19f5a8a4441bdaccf866\"},\"contracts/mixins/ModuleCommonFunctionalities.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\n\\ncontract ModuleCommonFunctionalities is State {\\n modifier whenNotPaused() {\\n require(!pause, \\\"Paused\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0x9ed7a6a635ef960b53888b28a2a6bed8b071255cad8cd33f00386a634cbddb74\"},\"contracts/mixins/VaultController.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../core/State.sol\\\";\\n\\n/**\\n * @title The Vault Controller contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\\n * trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract implements functionality to deposit and withdraw wrBTC and\\n * other tokens from the vault.\\n * */\\ncontract VaultController is State {\\n using SafeERC20 for IERC20;\\n\\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\\n\\n /**\\n * @notice Deposit wrBTC into the vault.\\n *\\n * @param from The address of the account paying the deposit.\\n * @param value The amount of wrBTC tokens to transfer.\\n */\\n function vaultEtherDeposit(address from, uint256 value) internal {\\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\\n _wrbtcToken.deposit.value(value)();\\n\\n emit VaultDeposit(address(_wrbtcToken), from, value);\\n }\\n\\n /**\\n * @notice Withdraw wrBTC from the vault.\\n *\\n * @param to The address of the recipient.\\n * @param value The amount of wrBTC tokens to transfer.\\n */\\n function vaultEtherWithdraw(address to, uint256 value) internal {\\n if (value != 0) {\\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\\n uint256 balance = address(this).balance;\\n if (value > balance) {\\n _wrbtcToken.withdraw(value - balance);\\n }\\n Address.sendValue(to, value);\\n\\n emit VaultWithdraw(address(_wrbtcToken), to, value);\\n }\\n }\\n\\n /**\\n * @notice Deposit tokens into the vault.\\n *\\n * @param token The address of the token instance.\\n * @param from The address of the account paying the deposit.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultDeposit(\\n address token,\\n address from,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n IERC20(token).safeTransferFrom(from, address(this), value);\\n\\n emit VaultDeposit(token, from, value);\\n }\\n }\\n\\n /**\\n * @notice Withdraw tokens from the vault.\\n *\\n * @param token The address of the token instance.\\n * @param to The address of the recipient.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultWithdraw(\\n address token,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n IERC20(token).safeTransfer(to, value);\\n\\n emit VaultWithdraw(token, to, value);\\n }\\n }\\n\\n /**\\n * @notice Transfer tokens from an account into another one.\\n *\\n * @param token The address of the token instance.\\n * @param from The address of the account paying.\\n * @param to The address of the recipient.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultTransfer(\\n address token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n if (from == address(this)) {\\n IERC20(token).safeTransfer(to, value);\\n } else {\\n IERC20(token).safeTransferFrom(from, to, value);\\n }\\n }\\n }\\n\\n /**\\n * @notice Approve an allowance of tokens to be spent by an account.\\n *\\n * @param token The address of the token instance.\\n * @param to The address of the spender.\\n * @param value The amount of tokens to allow.\\n */\\n function vaultApprove(\\n address token,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\\n IERC20(token).safeApprove(to, 0);\\n }\\n IERC20(token).safeApprove(to, value);\\n }\\n}\\n\",\"keccak256\":\"0xdcde4eee041b77ec9b73378a4a75b4d20d62f2e76f96f759d55260cf6717d0f3\"},\"contracts/modules/LoanOpenings.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../mixins/VaultController.sol\\\";\\nimport \\\"../mixins/InterestUser.sol\\\";\\nimport \\\"../swaps/SwapsUser.sol\\\";\\nimport \\\"../mixins/ModuleCommonFunctionalities.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\n/**\\n * @title Loan Openings contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains functions to borrow and trade.\\n * */\\ncontract LoanOpenings is\\n LoanOpeningsEvents,\\n VaultController,\\n InterestUser,\\n SwapsUser,\\n ModuleCommonFunctionalities\\n{\\n constructor() public {}\\n\\n /**\\n * @notice Fallback function is to react to receiving value (rBTC).\\n * */\\n function() external {\\n revert(\\\"fallback not allowed\\\");\\n }\\n\\n /**\\n * @notice Set function selectors on target contract.\\n *\\n * @param target The address of the target contract.\\n * */\\n function initialize(address target) external onlyOwner {\\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\\n _setTarget(this.borrowOrTradeFromPool.selector, target);\\n _setTarget(this.setDelegatedManager.selector, target);\\n _setTarget(this.getEstimatedMarginExposure.selector, target);\\n _setTarget(this.getRequiredCollateral.selector, target);\\n _setTarget(this.getBorrowAmount.selector, target);\\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \\\"LoanOpenings\\\");\\n }\\n\\n /**\\n * @notice Borrow or trade from pool.\\n *\\n * @dev Note: Only callable by loan pools (iTokens).\\n * Wrapper to _borrowOrTrade internal function.\\n *\\n * @param loanParamsId The ID of the loan parameters.\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * @param initialMargin The initial amount of margin.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return newPrincipal The new loan size.\\n * @return newCollateral The new collateral amount.\\n * */\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId,\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n bytes calldata loanDataBytes\\n )\\n external\\n payable\\n nonReentrant\\n whenNotPaused\\n returns (uint256 newPrincipal, uint256 newCollateral)\\n {\\n require(msg.value == 0 || loanDataBytes.length != 0, \\\"loanDataBytes required with ether\\\");\\n\\n /// Only callable by loan pools.\\n require(loanPoolToUnderlying[msg.sender] != address(0), \\\"not authorized\\\");\\n\\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\\n require(loanParamsLocal.id != 0, \\\"loanParams not exists\\\");\\n\\n /// Get required collateral.\\n uint256 collateralAmountRequired =\\n _getRequiredCollateral(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n sentValues.newPrincipal,\\n initialMargin,\\n isTorqueLoan\\n );\\n require(collateralAmountRequired != 0, \\\"collateral is 0\\\");\\n\\n return\\n _borrowOrTrade(\\n loanParamsLocal,\\n loanId,\\n isTorqueLoan,\\n collateralAmountRequired,\\n initialMargin,\\n sentAddresses,\\n sentValues,\\n loanDataBytes\\n );\\n }\\n\\n /**\\n * @notice Set the delegated manager.\\n *\\n * @dev Wrapper for _setDelegatedManager internal function.\\n *\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param delegated The address of the delegated manager.\\n * @param toggle The flag true/false for the delegated manager.\\n * */\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external whenNotPaused {\\n require(loans[loanId].borrower == msg.sender, \\\"unauthorized\\\");\\n\\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\\n }\\n\\n /**\\n * @notice Get the estimated margin exposure.\\n *\\n * Margin is the money borrowed from a broker to purchase an investment\\n * and is the difference between the total value of investment and the\\n * loan amount. Margin trading refers to the practice of using borrowed\\n * funds from a broker to trade a financial asset, which forms the\\n * collateral for the loan from the broker.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param loanTokenSent The amount of loan tokens sent.\\n * @param collateralTokenSent The amount of collateral tokens sent.\\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\\n * @param newPrincipal The updated amount of principal (current debt).\\n *\\n * @return The margin exposure.\\n * */\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256) {\\n uint256 maxLoanTerm = 2419200; // 28 days\\n\\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\\n\\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\\n\\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\\n uint256 tradingFee = _getTradingFee(swapAmount);\\n if (tradingFee != 0) {\\n swapAmount = swapAmount.sub(tradingFee);\\n }\\n\\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\\n if (receivedAmount == 0) {\\n return 0;\\n } else {\\n return collateralTokenSent.add(receivedAmount);\\n }\\n }\\n\\n /**\\n * @notice Get the required collateral.\\n *\\n * @dev Calls internal _getRequiredCollateral and add fees.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param newPrincipal The updated amount of principal (current debt).\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return collateralAmountRequired The required collateral.\\n * */\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) public view returns (uint256 collateralAmountRequired) {\\n if (marginAmount != 0) {\\n collateralAmountRequired = _getRequiredCollateral(\\n loanToken,\\n collateralToken,\\n newPrincipal,\\n marginAmount,\\n isTorqueLoan\\n );\\n\\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n // cannot be applied solely as it drives to some other tests failure\\n /*\\n\\t\\t\\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\\n\\t\\t\\tif (collateralAmountRequired != 0 && feePercent != 0) {\\n\\t\\t\\t\\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\\n\\t\\t\\t\\t\\t10**20 - feePercent // never will overflow\\n\\t\\t\\t\\t);\\n\\t\\t\\t}*/\\n\\n uint256 fee =\\n isTorqueLoan\\n ? _getBorrowingFee(collateralAmountRequired)\\n : _getTradingFee(collateralAmountRequired);\\n if (fee != 0) {\\n collateralAmountRequired = collateralAmountRequired.add(fee);\\n }\\n }\\n }\\n\\n /**\\n * @notice Get the borrow amount of a trade loan.\\n *\\n * @dev Basically borrowAmount = collateral / marginAmount\\n *\\n * Collateral is something that helps secure a loan. When you borrow money,\\n * you agree that your lender can take something and sell it to get their\\n * money back if you fail to repay the loan. That's the collateral.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param collateralTokenAmount The amount of collateral.\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return borrowAmount The borrow amount.\\n * */\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) public view returns (uint256 borrowAmount) {\\n if (marginAmount != 0) {\\n if (isTorqueLoan) {\\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\\n }\\n uint256 collateral = collateralTokenAmount;\\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\\n if (fee != 0) {\\n collateral = collateral.sub(fee);\\n }\\n if (loanToken == collateralToken) {\\n borrowAmount = collateral.mul(10**20).div(marginAmount);\\n } else {\\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\\n if (sourceToDestPrecision != 0) {\\n borrowAmount = collateral\\n .mul(10**20)\\n .mul(sourceToDestRate)\\n .div(marginAmount)\\n .div(sourceToDestPrecision);\\n }\\n }\\n /*\\n\\t\\t\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t\\t\\t// cannot be applied solely as it drives to some other tests failure\\n\\t\\t\\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\\n\\t\\t\\tif (borrowAmount != 0 && feePercent != 0) {\\n\\t\\t\\t\\tborrowAmount = borrowAmount\\n\\t\\t\\t\\t\\t.mul(\\n\\t\\t\\t\\t\\t10**20 - feePercent // never will overflow\\n\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t.divCeil(10**20);\\n\\t\\t\\t}*/\\n }\\n }\\n\\n /**\\n * @notice Borrow or trade.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * @param collateralAmountRequired The required amount of collateral.\\n * @param initialMargin The initial amount of margin.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return The new loan size.\\n * @return The new collateral amount.\\n * */\\n function _borrowOrTrade(\\n LoanParams memory loanParamsLocal,\\n bytes32 loanId,\\n bool isTorqueLoan,\\n uint256 collateralAmountRequired,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n bytes memory loanDataBytes\\n ) internal returns (uint256, uint256) {\\n require(\\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\\n \\\"collateral/loan match\\\"\\n );\\n require(initialMargin >= loanParamsLocal.minInitialMargin, \\\"initialMargin too low\\\");\\n\\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\\n require(\\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\\n \\\"invalid interest\\\"\\n );\\n\\n /// Initialize loan.\\n Loan storage loanLocal =\\n loans[\\n _initializeLoan(\\n loanParamsLocal,\\n loanId,\\n initialMargin,\\n sentAddresses,\\n sentValues.newPrincipal\\n )\\n ];\\n\\n // Get required interest.\\n uint256 amount =\\n _initializeInterest(\\n loanParamsLocal,\\n loanLocal,\\n sentValues.interestRate, /// newRate\\n sentValues.newPrincipal, /// newPrincipal,\\n sentValues.interestInitialAmount /// torqueInterest\\n );\\n\\n /// substract out interest from usable loanToken sent.\\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\\n\\n if (isTorqueLoan) {\\n require(sentValues.loanTokenSent == 0, \\\"surplus loan token\\\");\\n\\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\\n // need to temp into local state to avoid\\n address _collateralToken = loanParamsLocal.collateralToken;\\n address _loanToken = loanParamsLocal.loanToken;\\n if (borrowingFee != 0) {\\n _payBorrowingFee(\\n sentAddresses.borrower, /// borrower\\n loanLocal.id,\\n _collateralToken, /// fee token\\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n borrowingFee\\n );\\n\\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\\n }\\n } else {\\n /// Update collateral after trade.\\n uint256 receivedAmount;\\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\\n loanId,\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n sentAddresses.borrower, /// borrower\\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\\n false, /// bypassFee\\n loanDataBytes\\n );\\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\\n\\n /// Check the minEntryPrice with the rate\\n require(\\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\\n \\\"entry price above the minimum\\\"\\n );\\n }\\n\\n /// Settle collateral.\\n require(\\n _isCollateralSatisfied(\\n loanParamsLocal,\\n loanLocal,\\n initialMargin,\\n sentValues.collateralTokenSent,\\n collateralAmountRequired\\n ),\\n \\\"collateral insufficient\\\"\\n );\\n\\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\\n\\n if (isTorqueLoan) {\\n /// reclaiming variable -> interestDuration\\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\\n } else {\\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\\n }\\n\\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\\n\\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\\n }\\n\\n /**\\n * @notice Finalize an open loan.\\n *\\n * @dev Finalize it by updating local parameters of the loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * */\\n function _finalizeOpen(\\n LoanParams memory loanParamsLocal,\\n Loan storage loanLocal,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n bool isTorqueLoan\\n ) internal {\\n /// @dev TODO: here the actual used rate and margin should go.\\n (uint256 initialMargin, uint256 collateralToLoanRate) =\\n IPriceFeeds(priceFeeds).getCurrentMargin(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n loanLocal.principal,\\n loanLocal.collateral\\n );\\n require(initialMargin > loanParamsLocal.maintenanceMargin, \\\"unhealthy position\\\");\\n\\n if (loanLocal.startTimestamp == block.timestamp) {\\n uint256 loanToCollateralPrecision =\\n IPriceFeeds(priceFeeds).queryPrecision(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken\\n );\\n uint256 collateralToLoanPrecision =\\n IPriceFeeds(priceFeeds).queryPrecision(\\n loanParamsLocal.collateralToken,\\n loanParamsLocal.loanToken\\n );\\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\\n loanLocal.startRate = isTorqueLoan\\n ? collateralToLoanRate\\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\\n }\\n\\n _emitOpeningEvents(\\n loanParamsLocal,\\n loanLocal,\\n sentAddresses,\\n sentValues,\\n collateralToLoanRate,\\n initialMargin,\\n isTorqueLoan\\n );\\n }\\n\\n /**\\n * @notice Emit the opening events.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param collateralToLoanRate The exchange rate from collateral to loan\\n * tokens.\\n * @param margin The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * */\\n function _emitOpeningEvents(\\n LoanParams memory loanParamsLocal,\\n Loan memory loanLocal,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n uint256 collateralToLoanRate,\\n uint256 margin,\\n bool isTorqueLoan\\n ) internal {\\n if (isTorqueLoan) {\\n emit Borrow(\\n sentAddresses.borrower, /// user (borrower)\\n sentAddresses.lender, /// lender\\n loanLocal.id, /// loanId\\n loanParamsLocal.loanToken, /// loanToken\\n loanParamsLocal.collateralToken, /// collateralToken\\n sentValues.newPrincipal, /// newPrincipal\\n sentValues.collateralTokenSent, /// newCollateral\\n sentValues.interestRate, /// interestRate\\n sentValues.interestDuration, /// interestDuration\\n collateralToLoanRate, /// collateralToLoanRate,\\n margin /// currentMargin\\n );\\n } else {\\n /// currentLeverage = 100 / currentMargin\\n margin = SafeMath.div(10**38, margin);\\n\\n emit Trade(\\n sentAddresses.borrower, /// user (trader)\\n sentAddresses.lender, /// lender\\n loanLocal.id, /// loanId\\n loanParamsLocal.collateralToken, /// collateralToken\\n loanParamsLocal.loanToken, /// loanToken\\n sentValues.collateralTokenSent, /// positionSize\\n sentValues.newPrincipal, /// borrowedAmount\\n sentValues.interestRate, /// interestRate,\\n loanLocal.endTimestamp, /// settlementDate\\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\\n sentValues.entryLeverage, /// entryLeverage\\n margin /// currentLeverage\\n );\\n }\\n }\\n\\n /**\\n * @notice Set the delegated manager.\\n *\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param delegator The address of previous manager.\\n * @param delegated The address of the delegated manager.\\n * @param toggle The flag true/false for the delegated manager.\\n * */\\n function _setDelegatedManager(\\n bytes32 loanId,\\n address delegator,\\n address delegated,\\n bool toggle\\n ) internal {\\n delegatedManagers[loanId][delegated] = toggle;\\n\\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\\n }\\n\\n /**\\n * @notice Calculate whether the collateral is satisfied.\\n *\\n * @dev Basically check collateral + drawdown >= 98% of required.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param initialMargin The initial amount of margin.\\n * @param newCollateral The amount of new collateral.\\n * @param collateralAmountRequired The amount of required collateral.\\n *\\n * @return Whether the collateral is satisfied.\\n * */\\n function _isCollateralSatisfied(\\n LoanParams memory loanParamsLocal,\\n Loan memory loanLocal,\\n uint256 initialMargin,\\n uint256 newCollateral,\\n uint256 collateralAmountRequired\\n ) internal view returns (bool) {\\n /// Allow at most 2% under-collateralized.\\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\\n\\n if (newCollateral < collateralAmountRequired) {\\n /// Check that existing collateral is sufficient coverage.\\n if (loanLocal.collateral != 0) {\\n uint256 maxDrawdown =\\n IPriceFeeds(priceFeeds).getMaxDrawdown(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n loanLocal.principal,\\n loanLocal.collateral,\\n initialMargin\\n );\\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\\n } else {\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /**\\n * @notice Initialize a loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanId The ID of the loan.\\n * @param initialMargin The amount of margin of the trade.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\\n * @return The loanId.\\n * */\\n function _initializeLoan(\\n LoanParams memory loanParamsLocal,\\n bytes32 loanId,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n uint256 newPrincipal\\n ) internal returns (bytes32) {\\n require(loanParamsLocal.active, \\\"loanParams disabled\\\");\\n\\n address lender = sentAddresses.lender;\\n address borrower = sentAddresses.borrower;\\n address manager = sentAddresses.manager;\\n\\n Loan memory loanLocal;\\n\\n if (loanId == 0) {\\n borrowerNonce[borrower]++;\\n loanId = keccak256(\\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\\n );\\n require(loans[loanId].id == 0, \\\"loan exists\\\");\\n\\n loanLocal = Loan({\\n id: loanId,\\n loanParamsId: loanParamsLocal.id,\\n pendingTradesId: 0,\\n active: true,\\n principal: newPrincipal,\\n collateral: 0, /// calculated later\\n startTimestamp: block.timestamp,\\n endTimestamp: 0, /// calculated later\\n startMargin: initialMargin,\\n startRate: 0, /// queried later\\n borrower: borrower,\\n lender: lender\\n });\\n\\n activeLoansSet.addBytes32(loanId);\\n lenderLoanSets[lender].addBytes32(loanId);\\n borrowerLoanSets[borrower].addBytes32(loanId);\\n } else {\\n loanLocal = loans[loanId];\\n require(\\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\\n \\\"loan has ended\\\"\\n );\\n require(loanLocal.borrower == borrower, \\\"borrower mismatch\\\");\\n require(loanLocal.lender == lender, \\\"lender mismatch\\\");\\n require(loanLocal.loanParamsId == loanParamsLocal.id, \\\"loanParams mismatch\\\");\\n\\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\\n }\\n\\n if (manager != address(0)) {\\n _setDelegatedManager(loanId, borrower, manager, true);\\n }\\n\\n loans[loanId] = loanLocal;\\n\\n return loanId;\\n }\\n\\n /**\\n * @notice Initialize a loan interest.\\n *\\n * @dev A Torque loan is an indefinite-term loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param newRate The new interest rate of the loan.\\n * @param newPrincipal The new principal amount of the loan.\\n * @param torqueInterest The interest rate of the Torque loan.\\n *\\n * @return interestAmountRequired The interest amount required.\\n * */\\n function _initializeInterest(\\n LoanParams memory loanParamsLocal,\\n Loan storage loanLocal,\\n uint256 newRate,\\n uint256 newPrincipal,\\n uint256 torqueInterest /// ignored for fixed-term loans\\n ) internal returns (uint256 interestAmountRequired) {\\n /// Pay outstanding interest to lender.\\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\\n\\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\\n LenderInterest storage lenderInterestLocal =\\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\\n\\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\\n\\n _settleFeeRewardForInterestExpense(\\n loanInterestLocal,\\n loanLocal.id,\\n loanParamsLocal.loanToken, /// fee token\\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n loanLocal.borrower,\\n block.timestamp\\n );\\n\\n uint256 previousDepositRemaining;\\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\\n previousDepositRemaining = loanLocal\\n .endTimestamp\\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\\n .mul(loanInterestLocal.owedPerDay)\\n .div(86400);\\n }\\n\\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\\n\\n /// Update stored owedPerDay\\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\\n\\n if (maxLoanTerm == 0) {\\n /// Indefinite-term (Torque) loan.\\n\\n /// torqueInterest != 0 was confirmed earlier.\\n loanLocal.endTimestamp = torqueInterest\\n .add(previousDepositRemaining)\\n .mul(86400)\\n .div(loanInterestLocal.owedPerDay)\\n .add(block.timestamp);\\n\\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\\n\\n /// Loan term has to at least be greater than one hour.\\n require(maxLoanTerm > 3600, \\\"loan too short\\\");\\n\\n interestAmountRequired = torqueInterest;\\n } else {\\n /// Fixed-term loan.\\n\\n if (loanLocal.endTimestamp == 0) {\\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\\n }\\n\\n interestAmountRequired = loanLocal\\n .endTimestamp\\n .sub(block.timestamp)\\n .mul(owedPerDay)\\n .div(86400);\\n }\\n\\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\\n interestAmountRequired\\n );\\n\\n /// Update remaining lender interest values.\\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\\n }\\n\\n /**\\n * @notice Get the required collateral.\\n *\\n * @dev Basically collateral = newPrincipal * marginAmount\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param newPrincipal The updated amount of principal (current debt).\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return collateralTokenAmount The required collateral.\\n * */\\n function _getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) internal view returns (uint256 collateralTokenAmount) {\\n if (loanToken == collateralToken) {\\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\\n } else {\\n /// Using the price feed instead of the swap expected return\\n /// because we need the rate in the inverse direction\\n /// so the swap is probably farther off than the price feed.\\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\\n if (sourceToDestRate != 0) {\\n collateralTokenAmount = newPrincipal\\n .mul(sourceToDestPrecision)\\n .div(sourceToDestRate)\\n .mul(marginAmount)\\n .div(10**20);\\n /*TODO: review\\n\\t\\t\\t\\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\\n }\\n }\\n // ./tests/loan-token/TradingTestToken.test.js\\n if (isTorqueLoan && collateralTokenAmount != 0) {\\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\\n collateralTokenAmount\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0x99a9332501c69a9991f9e240f614e168323695064d25c002c5d7b348a5d3d7e5\"},\"contracts/modules/interfaces/ProtocolAffiliatesInterface.sol\":{\"content\":\"/**\\n * Copyright 2020, Denis Savelev. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface ProtocolAffiliatesInterface {\\n function setAffiliatesReferrer(address user, address referrer) external;\\n\\n function setUserNotFirstTradeFlag(address user_) external;\\n\\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address affiliate,\\n address trader,\\n address token,\\n uint256 amount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n}\\n\",\"keccak256\":\"0x42f259156db09a06e3dcdf0ab9c6774712616b35e6baff97999a2a534d1c9c64\"},\"contracts/openzeppelin/Address.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n codehash := extcodehash(account)\\n }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x23df48a01dbac9b25e86c9131174fb7752bbc7e741e63f1aa982de22e055ad54\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/openzeppelin/ReentrancyGuard.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @title Helps contracts guard against reentrancy attacks.\\n * @author Remco Bloemen , Eenae \\n * @dev If you mark a function `nonReentrant`, you should also\\n * mark it `external`.\\n */\\ncontract ReentrancyGuard {\\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\\n\\n /// @dev Constant for locked guard state\\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\\n\\n /**\\n * @dev We use a single lock for the whole contract.\\n */\\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * If you mark a function `nonReentrant`, you should also\\n * mark it `external`. Calling one `nonReentrant` function from\\n * another is not supported. Instead, you can implement a\\n * `private` function doing the actual work, and an `external`\\n * wrapper marked as `nonReentrant`.\\n */\\n modifier nonReentrant() {\\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \\\"nonReentrant\\\");\\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\\n _;\\n reentrancyLock = REENTRANCY_GUARD_FREE;\\n }\\n}\\n\",\"keccak256\":\"0xd347de96ad57d1e45b07a2efe3050c1bd4b809236bbf354acb593de56d21a5c9\"},\"contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./Address.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\\n );\\n }\\n\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance =\\n token.allowance(address(this), spender).sub(\\n value,\\n \\\"SafeERC20: decreased allowance below zero\\\"\\n );\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) {\\n // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe99b4d979cb976a6b70e297600242afe38b8cd8f1b1ba6ee373f39f7abb3ca79\"},\"contracts/openzeppelin/SafeMath.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\\n return divCeil(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n\\n if (a == 0) {\\n return 0;\\n }\\n uint256 c = ((a - 1) / b) + 1;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n\\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n return _a < _b ? _a : _b;\\n }\\n}\\n\",\"keccak256\":\"0xbff8d6273e1a6870d1a142c0c23acd63a4dd47760f250390f49ee56333bcb6e8\"},\"contracts/reentrancy/Mutex.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/*\\n * @title Global Mutex contract\\n *\\n * @notice A mutex contract that allows only one function to be called at a time out\\n * of a large set of functions. *Anyone* in the network can freely use any instance\\n * of this contract to add a universal mutex to any function in any contract.\\n */\\ncontract Mutex {\\n /*\\n * We use an uint to store the mutex state.\\n */\\n uint256 public value;\\n\\n /*\\n * @notice Increment the mutex state and return the new value.\\n *\\n * @dev This is the function that will be called by anyone to change the mutex\\n * state. It is purposely not protected by any access control\\n */\\n function incrementAndGetValue() external returns (uint256) {\\n /*\\n * increment value using unsafe math. This is safe because we are\\n * pretty certain no one will ever increment the value 2^256 times\\n * in a single transaction.\\n */\\n return ++value;\\n }\\n}\\n\",\"keccak256\":\"0xd10b0fd07d5fed1ae1237e7c87e6501970fce2a86e2b8862e502258b0d3aeb2c\"},\"contracts/reentrancy/SharedReentrancyGuard.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./Mutex.sol\\\";\\n\\n/*\\n * @title Abstract contract for shared reentrancy guards\\n *\\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\\n * that there's no reentrancy between *any* functions marked with the modifier.\\n *\\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\\n */\\ncontract SharedReentrancyGuard {\\n /*\\n * This is the address of the mutex contract that will be used as the\\n * reentrancy guard.\\n *\\n * The address is hardcoded to avoid changing the memory layout of\\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\\n * because the Mutex contract is always deployed to the same address, with the\\n * same method used in the deployment of ERC1820Registry.\\n */\\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\\n\\n /*\\n * This is the modifier that will be used to protect functions from\\n * reentrancy. It will call the mutex contract to increment the mutex\\n * state and then revert if the mutex state was changed by another\\n * nested call.\\n */\\n modifier globallyNonReentrant() {\\n uint256 previous = MUTEX.incrementAndGetValue();\\n\\n _;\\n\\n /*\\n * If the mutex state was changed by a nested function call, then\\n * the value of the state variable will be different from the previous value.\\n */\\n require(previous == MUTEX.value(), \\\"reentrancy violation\\\");\\n }\\n}\\n\",\"keccak256\":\"0x2d0e61b104b91c1764f20fbeb381ba0f8a8889934ba7f6e8a167ed542ec2c124\"},\"contracts/swaps/SwapsUser.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../mixins/FeesHelper.sol\\\";\\nimport \\\"./connectors/SwapsImplSovrynSwapLib.sol\\\";\\n\\n/**\\n * @title Perform token swaps for loans and trades.\\n * */\\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\\n /**\\n * @notice Internal loan swap.\\n *\\n * @param loanId The ID of the loan.\\n * @param sourceToken The address of the source tokens.\\n * @param destToken The address of destination tokens.\\n * @param user The user address.\\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\\n * @param requiredDestTokenAmount The required amount of destination tokens.\\n * @param bypassFee To bypass or not the fee.\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return destTokenAmountReceived\\n * @return sourceTokenAmountUsed\\n * @return sourceToDestSwapRate\\n * */\\n function _loanSwap(\\n bytes32 loanId,\\n address sourceToken,\\n address destToken,\\n address user,\\n uint256 minSourceTokenAmount,\\n uint256 maxSourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n bool bypassFee,\\n bytes memory loanDataBytes\\n )\\n internal\\n returns (\\n uint256 destTokenAmountReceived,\\n uint256 sourceTokenAmountUsed,\\n uint256 sourceToDestSwapRate\\n )\\n {\\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\\n [\\n sourceToken,\\n destToken,\\n address(this), // receiver\\n address(this), // returnToSender\\n user\\n ],\\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\\n loanId,\\n bypassFee,\\n loanDataBytes,\\n false // swap external flag, set to false so that it will use the tradingFeePercent\\n );\\n\\n /// Will revert if swap size too large.\\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\\n\\n /// Will revert if disagreement found.\\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\\n sourceToken,\\n destToken,\\n sourceTokenAmountUsed,\\n destTokenAmountReceived,\\n maxDisagreement\\n );\\n\\n emit LoanSwap(\\n loanId,\\n sourceToken,\\n destToken,\\n user,\\n sourceTokenAmountUsed,\\n destTokenAmountReceived\\n );\\n }\\n\\n /**\\n * @notice Calculate amount of source and destination tokens.\\n *\\n * @dev Wrapper for _swapsCall_internal function.\\n *\\n * @param addrs The array of addresses.\\n * @param vals The array of values.\\n * @param loanId The Id of the associated loan.\\n * @param miscBool True/false to bypassFee.\\n * @param loanDataBytes Additional loan data (not in use yet).\\n *\\n * @return destTokenAmountReceived The amount of destination tokens received.\\n * @return sourceTokenAmountUsed The amount of source tokens used.\\n * */\\n function _swapsCall(\\n address[5] memory addrs,\\n uint256[3] memory vals,\\n bytes32 loanId,\\n bool miscBool, /// bypassFee\\n bytes memory loanDataBytes,\\n bool isSwapExternal\\n ) internal returns (uint256, uint256) {\\n /// addrs[0]: sourceToken\\n /// addrs[1]: destToken\\n /// addrs[2]: receiver\\n /// addrs[3]: returnToSender\\n /// addrs[4]: user\\n /// vals[0]: minSourceTokenAmount\\n /// vals[1]: maxSourceTokenAmount\\n /// vals[2]: requiredDestTokenAmount\\n\\n require(vals[0] != 0 || vals[1] != 0, \\\"min or max source token amount needs to be set\\\");\\n\\n if (vals[1] == 0) {\\n vals[1] = vals[0];\\n }\\n require(vals[0] <= vals[1], \\\"sourceAmount larger than max\\\");\\n\\n uint256 destTokenAmountReceived;\\n uint256 sourceTokenAmountUsed;\\n\\n uint256 tradingFee;\\n if (!miscBool) {\\n /// bypassFee\\n if (vals[2] == 0) {\\n /// condition: vals[0] will always be used as sourceAmount\\n\\n if (isSwapExternal) {\\n tradingFee = _getSwapExternalFee(vals[0]);\\n } else {\\n tradingFee = _getTradingFee(vals[0]);\\n }\\n\\n if (tradingFee != 0) {\\n _payTradingFee(\\n addrs[4], /// user\\n loanId,\\n addrs[0], /// sourceToken (feeToken)\\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n tradingFee\\n );\\n\\n vals[0] = vals[0].sub(tradingFee);\\n }\\n } else {\\n /// Condition: unknown sourceAmount will be used.\\n\\n if (isSwapExternal) {\\n tradingFee = _getSwapExternalFee(vals[2]);\\n } else {\\n tradingFee = _getTradingFee(vals[2]);\\n }\\n\\n if (tradingFee != 0) {\\n vals[2] = vals[2].add(tradingFee);\\n }\\n }\\n }\\n\\n require(loanDataBytes.length == 0, \\\"invalid state\\\");\\n\\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\\n\\n if (vals[2] == 0) {\\n /// There's no minimum destTokenAmount, but all of vals[0]\\n /// (minSourceTokenAmount) must be spent.\\n require(sourceTokenAmountUsed == vals[0], \\\"swap too large to fill\\\");\\n\\n if (tradingFee != 0) {\\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\\n }\\n } else {\\n /// There's a minimum destTokenAmount required, but\\n /// sourceTokenAmountUsed won't be greater\\n /// than vals[1] (maxSourceTokenAmount)\\n require(sourceTokenAmountUsed <= vals[1], \\\"swap fill too large\\\");\\n require(destTokenAmountReceived >= vals[2], \\\"insufficient swap liquidity\\\");\\n\\n if (tradingFee != 0) {\\n _payTradingFee(\\n addrs[4], /// user\\n loanId, /// loanId,\\n addrs[1], /// destToken (feeToken)\\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n tradingFee\\n );\\n\\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\\n }\\n }\\n\\n return (destTokenAmountReceived, sourceTokenAmountUsed);\\n }\\n\\n /**\\n * @notice Calculate amount of source and destination tokens.\\n *\\n * @dev Calls swapsImpl::internalSwap\\n *\\n * @param addrs The array of addresses.\\n * @param vals The array of values.\\n *\\n * @return destTokenAmountReceived The amount of destination tokens received.\\n * @return sourceTokenAmountUsed The amount of source tokens used.\\n * */\\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\\n internal\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n SwapsImplSovrynSwapLib.SwapParams memory swapParams;\\n\\n swapParams.sourceTokenAddress = addrs[0];\\n swapParams.destTokenAddress = addrs[1];\\n swapParams.receiverAddress = addrs[2];\\n swapParams.returnToSenderAddress = addrs[3];\\n swapParams.minSourceTokenAmount = vals[0];\\n swapParams.maxSourceTokenAmount = vals[1];\\n swapParams.requiredDestTokenAmount = vals[2];\\n\\n (destTokenAmountReceived, sourceTokenAmountUsed) = SwapsImplSovrynSwapLib.swap(swapParams);\\n }\\n\\n /**\\n * @notice Calculate expected amount of destination tokens.\\n *\\n * @dev Calls swapsImpl::internalExpectedReturn\\n *\\n * @param sourceToken The address of the source tokens.\\n * @param destToken The address of the destination tokens.\\n * @param sourceTokenAmount The amount of the source tokens.\\n *\\n * @param destTokenAmount The amount of destination tokens.\\n * */\\n function _swapsExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) internal view returns (uint256 destTokenAmount) {\\n destTokenAmount = SwapsImplSovrynSwapLib.getExpectedReturn(\\n sourceToken,\\n destToken,\\n sourceTokenAmount\\n );\\n }\\n\\n /**\\n * @notice Verify that the amount of tokens are under the swap limit.\\n *\\n * @dev Calls priceFeeds::amountInEth\\n *\\n * @param tokenAddress The address of the token to calculate price.\\n * @param amount The amount of tokens to calculate price.\\n * */\\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\\n uint256 _maxSwapSize = maxSwapSize;\\n if (_maxSwapSize != 0) {\\n uint256 amountInEth;\\n if (tokenAddress == address(wrbtcToken)) {\\n amountInEth = amount;\\n } else {\\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\\n }\\n require(amountInEth <= _maxSwapSize, \\\"swap too large\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x7dfc45e91455458caf886b49c96ad426de06cddffa442c16628eba4974f3d323\"},\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":{\"content\":\"pragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"./interfaces/ISovrynSwapNetwork.sol\\\";\\nimport \\\"./interfaces/IContractRegistry.sol\\\";\\nimport \\\"../../interfaces/ISovryn.sol\\\";\\n\\n/**\\n * @title Swaps Implementation Sovryn contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the implementation of swap process and rate\\n * calculations for Sovryn network.\\n * */\\nlibrary SwapsImplSovrynSwapLib {\\n using SafeMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n struct SwapParams {\\n address sourceTokenAddress;\\n address destTokenAddress;\\n address receiverAddress;\\n address returnToSenderAddress;\\n uint256 minSourceTokenAmount;\\n uint256 maxSourceTokenAmount;\\n uint256 requiredDestTokenAmount;\\n }\\n\\n /// bytes32 contractName = hex\\\"42616e636f724e6574776f726b\\\"; /// \\\"SovrynSwapNetwork\\\"\\n\\n /**\\n * Get the hex name of a contract.\\n * @param source The name of the contract.\\n * */\\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\\n assembly {\\n result := mload(add(source, 32))\\n }\\n }\\n\\n /**\\n * Look up the Sovryn swap network contract registered at the given address.\\n * @param sovrynSwapRegistryAddress The address of the registry.\\n * */\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (ISovrynSwapNetwork)\\n {\\n /// State variable sovrynSwapContractRegistryAddress is part of\\n /// State.sol and set in ProtocolSettings.sol and this function\\n /// needs to work without delegate call as well -> therefore pass it.\\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\\n return\\n ISovrynSwapNetwork(\\n contractRegistry.addressOf(getContractHexName(\\\"SovrynSwapNetwork\\\"))\\n );\\n }\\n\\n /**\\n * Swap the source token for the destination token on the oracle based AMM.\\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\\n * -> swap the minSourceTokenAmount\\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\\n * -> same as on rollover. minimum amount is not considered at all.\\n *\\n * @param params SwapParams struct\\n * sourceTokenAddress The address of the source tokens.\\n * destTokenAddress The address of the destination tokens.\\n * receiverAddress The address who will received the swap token results\\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\\n * requiredDestTokenAmount The required amount of destination tokens.\\n * */\\n function swap(SwapParams memory params)\\n public\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n require(params.sourceTokenAddress != params.destTokenAddress, \\\"source == dest\\\");\\n\\n ISovryn iSovryn = ISovryn(address(this));\\n require(\\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\\n iSovryn.supportedTokens(params.destTokenAddress),\\n \\\"invalid tokens\\\"\\n );\\n\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\\n\\n IERC20[] memory path =\\n _getConversionPath(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n sovrynSwapNetwork\\n );\\n\\n uint256 minReturn = 1;\\n sourceTokenAmountUsed = params.minSourceTokenAmount;\\n\\n /// If the required amount of destination tokens is passed, we need to\\n /// calculate the estimated amount of source tokens regardless of the\\n /// minimum source token amount (name is misleading).\\n if (params.requiredDestTokenAmount > 0) {\\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n params.requiredDestTokenAmount,\\n params.maxSourceTokenAmount\\n );\\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\\n require(\\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\\n params.requiredDestTokenAmount,\\n \\\"insufficient source tokens provided.\\\"\\n );\\n minReturn = params.requiredDestTokenAmount;\\n }\\n\\n require(sourceTokenAmountUsed > 0, \\\"cannot swap 0 tokens\\\");\\n\\n _allowTransfer(\\n sourceTokenAmountUsed,\\n params.sourceTokenAddress,\\n address(sovrynSwapNetwork)\\n );\\n\\n /// @dev Note: the kyber connector uses .call() to interact with kyber\\n /// to avoid bubbling up. here we allow bubbling up.\\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\\n path,\\n sourceTokenAmountUsed,\\n minReturn,\\n params.receiverAddress,\\n address(0),\\n 0\\n );\\n\\n /// If the sender is not the protocol (calling with delegatecall),\\n /// return the remainder to the specified address.\\n /// @dev Note: for the case that the swap is used without the\\n /// protocol. Not sure if it should, though. needs to be discussed.\\n if (params.returnToSenderAddress != address(this)) {\\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\\n /// Send unused source token back.\\n IERC20(params.sourceTokenAddress).safeTransfer(\\n params.returnToSenderAddress,\\n params.maxSourceTokenAmount - sourceTokenAmountUsed\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Check whether the existing allowance suffices to transfer\\n * the needed amount of tokens.\\n * If not, allows the transfer of an arbitrary amount of tokens.\\n *\\n * @param tokenAmount The amount to transfer.\\n * @param tokenAddress The address of the token to transfer.\\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\\n * */\\n function _allowTransfer(\\n uint256 tokenAmount,\\n address tokenAddress,\\n address sovrynSwapNetwork\\n ) internal {\\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\\n if (tempAllowance < tokenAmount) {\\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\\n }\\n }\\n\\n /**\\n * @notice Calculate the number of source tokens to provide in order to\\n * obtain the required destination amount.\\n *\\n * @param sourceTokenAddress The address of the source token address.\\n * @param destTokenAddress The address of the destination token address.\\n * @param requiredDestTokenAmount The number of destination tokens needed.\\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\\n *\\n * @return The estimated amount of source tokens needed.\\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\\n * */\\n function _estimateSourceTokenAmount(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 requiredDestTokenAmount,\\n uint256 maxSourceTokenAmount\\n ) internal view returns (uint256 estimatedSourceAmount) {\\n ISovryn iSovryn = ISovryn(address(this));\\n uint256 sourceToDestPrecision =\\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\\n\\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\\n uint256 expectedRate =\\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\\n\\n /// Compute the source tokens needed to get the required amount with the worst case rate.\\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\\n expectedRate\\n );\\n\\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\\n uint256 buffer = estimatedSourceAmount.div(1000);\\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\\n\\n /// Never spend more than the maximum.\\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\\n return maxSourceTokenAmount;\\n }\\n\\n /**\\n * @notice Get the expected rate for 1 source token when exchanging the\\n * given amount of source tokens.\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\\n * */\\n function getExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n\\n /// Return the rate for 1 token with 18 decimals.\\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\\n }\\n\\n /**\\n * @notice Get the expected return amount when exchanging the given\\n * amount of source tokens.\\n *\\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the return for.\\n * */\\n function getExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256 expectedReturn) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n }\\n\\n function _getConversionPath(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n ISovrynSwapNetwork sovrynSwapNetwork\\n ) private view returns (IERC20[] memory path) {\\n IERC20[] memory _defaultPathConversion =\\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\\n\\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\\n path = _defaultPathConversion.length >= 3\\n ? _defaultPathConversion\\n : sovrynSwapNetwork.conversionPath(\\n IERC20(sourceTokenAddress),\\n IERC20(destTokenAddress)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x058b8d733422a2421f17d1b159aed69f151ea8d5f48ee507bac5b4e86add8b0c\"},\"contracts/swaps/connectors/interfaces/IContractRegistry.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\ncontract IContractRegistry {\\n function addressOf(bytes32 contractName) public view returns (address);\\n}\\n\",\"keccak256\":\"0x793c4eefa2ee04cbf0a1a9da28676ac310ed7bf60a27ec7d86de7d7236ccf45b\"},\"contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol\":{\"content\":\"pragma solidity >=0.5.8 <=0.5.17;\\n\\nimport \\\"../../../interfaces/IERC20.sol\\\";\\n\\ncontract ISovrynSwapNetwork {\\n function convertByPath(\\n IERC20[] calldata _path,\\n uint256 _amount,\\n uint256 _minReturn,\\n address _beneficiary,\\n address _affiliateAccount,\\n uint256 _affiliateFee\\n ) external payable returns (uint256);\\n\\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\\n\\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\\n external\\n view\\n returns (IERC20[] memory);\\n}\\n\",\"keccak256\":\"0xcd28e146b77183bff18f78b511912f7ebe60d437430fdaa72ed145fdda61a5ad\"}},\"version\":1}", - "bytecode": "0x60806040526001600055678ac7230489e80000601555670214e8348c4f000060185567013fbe85edc90000601b55674563918244f40000602055674563918244f40000602155674563918244f400006027556127106028556802b5e3af16b1880000602955650f478e084000602b5567016345785d8a0000602c556802b5e3af16b1880000602f5560036035556801158e460913d00000603955348015620000a657600080fd5b506000620000bc6001600160e01b036200011016565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35062000114565b3390565b61507f80620001246000396000f3fe6080604052600436106103815760003560e01c80638f32d59b116101d1578063cd5d808d11610102578063e8f62764116100a0578063f589a3e71161006f578063f589a3e714610a05578063f6ddc8b314610a1a578063f706b1f214610a2f578063f851a44014610a4457610381565b8063e8f62764146109a6578063edab119f146109bb578063f0e085f5146109d0578063f2fde38b146109e557610381565b8063d485045e116100dc578063d485045e14610925578063d67f707714610945578063d84ca25414610965578063e762319f1461098657610381565b8063cd5d808d146108db578063d288208c146108fb578063d473c2da1461091057610381565b8063b7e152411161016f578063bdee453c11610149578063bdee453c1461082f578063c4a908151461084f578063c4d66de814610887578063cb6eacd1146108a757610381565b8063b7e15241146107e5578063b9cffa3e14610805578063ba4861e91461081a57610381565b8063acc04348116101ab578063acc0434814610779578063ae0a85301461078e578063afe84009146107a3578063b30643d9146107c557610381565b80638f32d59b1461072f57806392d894f814610744578063959083d31461076457610381565b80634203e395116102b65780636e663730116102545780637a8faeb8116102235780637a8faeb8146106d05780638456cb59146106e55780638da5cb5b146106fa5780638dc48ba51461070f57610381565b80636e663730146106715780637420ca3e14610691578063742e6798146106a657806378d849ed146106bb57610381565b8063569fc1fb11610290578063569fc1fb146105dc578063574442cc1461060b57806362fff3f61461062057806368c4ac261461065157610381565b80634203e395146105925780634699f846146105b25780634f28cac2146105c757610381565b80632a324027116103235780633432423c116102fd5780633432423c146105125780633452d2d4146105325780633fca506e146105525780634115a2b61461057257610381565b80632a324027146104c65780632f470764146104db57806333d8991f146104f057610381565b80631b7bde741161035f5780631b7bde741461042c578063218b39c61461045957806324cc57491461047957806325decac0146104a657610381565b8063065d810f146103af5780630676c1b7146103ea57806317548b791461040c575b34801561038d57600080fd5b5060405162461bcd60e51b81526004016103a690614e03565b60405180910390fd5b3480156103bb57600080fd5b506103cf6103ca366004613e77565b610a59565b6040516103e196959493929190614ef6565b60405180910390f35b3480156103f657600080fd5b506103ff610a99565b6040516103e1919061492d565b34801561041857600080fd5b506103ff61042736600461400a565b610aa8565b34801561043857600080fd5b5061044c610447366004613d41565b610ac3565b6040516103e19190614eb1565b34801561046557600080fd5b506103ff610474366004613d23565b610ae0565b34801561048557600080fd5b50610499610494366004613d23565b610afb565b6040516103e19190614b50565b3480156104b257600080fd5b5061044c6104c1366004613d7b565b610b10565b3480156104d257600080fd5b5061044c610b6b565b3480156104e757600080fd5b5061044c610b71565b3480156104fc57600080fd5b5061051061050b366004613f02565b610b77565b005b34801561051e57600080fd5b506103cf61052d366004613e77565b610be4565b34801561053e57600080fd5b5061044c61054d366004613d23565b610c24565b34801561055e57600080fd5b5061044c61056d366004613d23565b610c36565b34801561057e57600080fd5b5061049961058d366004613ee3565b610c48565b34801561059e57600080fd5b5061044c6105ad366004613d23565b610c68565b3480156105be57600080fd5b5061044c610c7a565b3480156105d357600080fd5b5061044c610c80565b3480156105e857600080fd5b506105fc6105f7366004613ec5565b610c86565b6040516103e193929190614ecd565b34801561061757600080fd5b5061044c610ca7565b34801561062c57600080fd5b5061064061063b366004613d41565b610cad565b6040516103e1959493929190614edb565b34801561065d57600080fd5b5061049961066c366004613d23565b610ce7565b34801561067d57600080fd5b506103ff61068c366004613d23565b610cfc565b34801561069d57600080fd5b506103ff610d17565b3480156106b257600080fd5b5061044c610d26565b3480156106c757600080fd5b506103ff610d2c565b3480156106dc57600080fd5b5061044c610d3b565b3480156106f157600080fd5b50610499610d41565b34801561070657600080fd5b506103ff610d4a565b34801561071b57600080fd5b506103ff61072a366004613d23565b610d59565b34801561073b57600080fd5b50610499610d74565b34801561075057600080fd5b5061044c61075f366004613d23565b610d9a565b34801561077057600080fd5b5061044c610dac565b34801561078557600080fd5b5061044c610db2565b34801561079a57600080fd5b5061044c610db8565b3480156107af57600080fd5b506107b8610dbe565b6040516103e19190614c54565b3480156107d157600080fd5b5061044c6107e0366004613d23565b610dcd565b3480156107f157600080fd5b5061044c610800366004613d23565b610ddf565b34801561081157600080fd5b506103ff610df1565b34801561082657600080fd5b506103ff610e00565b34801561083b57600080fd5b5061044c61084a366004613d23565b610e0f565b34801561085b57600080fd5b5061086f61086a366004613ec5565b610e21565b6040516103e19c9b9a99989796959493929190614ba1565b34801561089357600080fd5b506105106108a2366004613d23565b610e93565b3480156108b357600080fd5b506108c76108c2366004613ec5565b610f96565b6040516103e1989796959493929190614b5e565b3480156108e757600080fd5b5061044c6108f6366004613d41565b610fe8565b34801561090757600080fd5b506103ff611005565b34801561091c57600080fd5b5061044c611014565b34801561093157600080fd5b5061044c610940366004613d23565b61101a565b34801561095157600080fd5b5061044c610960366004613df0565b61102c565b610978610973366004613f4f565b6110fa565b6040516103e1929190614ebf565b34801561099257600080fd5b5061044c6109a1366004613d7b565b6112fa565b3480156109b257600080fd5b506103ff61146e565b3480156109c757600080fd5b5061044c61147d565b3480156109dc57600080fd5b5061044c611483565b3480156109f157600080fd5b50610510610a00366004613d23565b611489565b348015610a1157600080fd5b5061044c6114b9565b348015610a2657600080fd5b5061044c6114bf565b348015610a3b57600080fd5b506103ff6114c5565b348015610a5057600080fd5b506103ff6114d4565b6009602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b6031546001600160a01b031681565b6005602052600090815260409020546001600160a01b031681565b603b60209081526000928352604080842090915290825290205481565b6023602052600090815260409020546001600160a01b031681565b60326020526000908152604090205460ff1681565b60008215610b6257610b2586868686866114e3565b9050600082610b3c57610b378261161c565b610b45565b610b4582611652565b90508015610b6057610b5d828263ffffffff61167616565b91505b505b95945050505050565b60185481565b601f5481565b603d5460ff1615610b9a5760405162461bcd60e51b81526004016103a690614c83565b6000838152600660205260409020600a01546001600160a01b03163314610bd35760405162461bcd60e51b81526004016103a690614dc3565b610bdf833384846116a2565b505050565b6008602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b601a6020526000908152604090205481565b602a6020526000908152604090205481565b600a60209081526000928352604080842090915290825290205460ff1681565b60166020526000908152604090205481565b60155481565b60295481565b600c6020526000908152604090208054600182015460029092015490919083565b602b5481565b600b602090815260009283526040808420909152908252902080546001820154600283015460038401546004909401549293919290919085565b60266020526000908152604090205460ff1681565b6033602052600090815260409020546001600160a01b031681565b6003546001600160a01b031681565b60355481565b6002546001600160a01b031681565b601e5481565b603d5460ff1681565b6001546001600160a01b031690565b6022602052600090815260409020546001600160a01b031681565b6001546000906001600160a01b0316610d8b611717565b6001600160a01b031614905090565b60176020526000908152604090205481565b602c5481565b602f5481565b60205481565b602d546001600160a01b031681565b601d6020526000908152604090205481565b601c6020526000908152604090205481565b6037546001600160a01b031681565b6004546001600160a01b031681565b60366020526000908152604090205481565b600660208190526000918252604090912080546001820154600283015460038401546004850154600586015496860154600787015460088801546009890154600a8a0154600b909a0154989a9799969860ff909616979496949593949293919290916001600160a01b0391821691168c565b610e9b610d74565b610eb75760405162461bcd60e51b81526004016103a690614dc3565b633613289560e21b600081905260056020527fd3a886345208a8e3a0f774019653c4e69589e943ba1e46c7fa0ef875651e6e39546001600160a01b031690610eff908361171b565b610f106333d8991f60e01b8361171b565b610f2163d67f707760e01b8361171b565b610f3162977b2b60e61b8361171b565b610f4263e762319f60e01b8361171b565b6b4c6f616e4f70656e696e677360a01b826001600160a01b0316826001600160a01b03167f1420e3a2094d671bc2eb897941fa3d94ffa37f0cb6d530651946250a2151cb7f60405160405180910390a45050565b6007602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949560ff8516956101009095046001600160a01b03908116959481169493169288565b603c60209081526000928352604080842090915290825290205481565b6038546001600160a01b031681565b60275481565b60196020526000908152604090205481565b60006224ea008161105d6907baab4146b63dd00000611051868863ffffffff61179516565b9063ffffffff6117cf16565b9050600061107862015180611051858563ffffffff61179516565b9050600061108c898363ffffffff61181116565b905060006110998261161c565b905080156110b4576110b1828263ffffffff61181116565b91505b60006110c18d8d85611853565b9050806110d757600096505050505050506110f0565b6110e78a8263ffffffff61167616565b96505050505050505b9695505050505050565b60008060016000541461111f5760405162461bcd60e51b81526004016103a690614e33565b6002600055603d5460ff16156111475760405162461bcd60e51b81526004016103a690614c83565b34158061115357508215155b61116f5760405162461bcd60e51b81526004016103a690614e63565b336000908152602260205260409020546001600160a01b03166111a45760405162461bcd60e51b81526004016103a690614da3565b6111ac613a43565b5060008a815260076020908152604091829020825161010080820185528254808352600184015460ff811615159584019590955293046001600160a01b039081169482019490945260028201548416606082015260038201549093166080840152600481015460a0840152600581015460c08401526006015460e08301526112465760405162461bcd60e51b81526004016103a690614df3565b60006112618260600151836080015189602001358c8e6114e3565b9050806112805760405162461bcd60e51b81526004016103a690614d93565b6112e2828c8c848d611297368f90038f018f614028565b6112a6368f90038f018f614046565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118e992505050565b6001600055909d909c509a5050505050505050505050565b60008215610b62578115611324576113218368056bc75e2d6310000063ffffffff61167616565b92505b8360008361133a576113358261161c565b611343565b61134382611652565b9050801561135e5761135b828263ffffffff61181116565b91505b866001600160a01b0316886001600160a01b0316141561139c57611395856110518468056bc75e2d6310000063ffffffff61179516565b9250611463565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c906113d3908c908e9060040161493b565b604080518083038186803b1580156113ea57600080fd5b505afa1580156113fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114229190810190614083565b91509150806000146114605761145d816110518981866114518a68056bc75e2d6310000063ffffffff61179516565b9063ffffffff61179516565b94505b50505b505095945050505050565b6014546001600160a01b031681565b601b5481565b60285481565b611491610d74565b6114ad5760405162461bcd60e51b81526004016103a690614dc3565b6114b681611c22565b50565b60395481565b60215481565b602e546001600160a01b031681565b6030546001600160a01b031681565b6000846001600160a01b0316866001600160a01b031614156115235761151c68056bc75e2d63100000611051868663ffffffff61179516565b90506115de565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c9061155a908a908c9060040161493b565b604080518083038186803b15801561157157600080fd5b505afa158015611585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115a99190810190614083565b91509150816000146115db576115d868056bc75e2d631000006110518761145186838c8863ffffffff61179516565b92505b50505b8180156115ea57508015155b15610b62576110f081611610856110518368056bc75e2d6310000063ffffffff61179516565b9063ffffffff61167616565b600061164c68056bc75e2d631000006116406018548561179590919063ffffffff16565b9063ffffffff611ca416565b92915050565b600061164c68056bc75e2d63100000611640601b548561179590919063ffffffff16565b60008282018381101561169b5760405162461bcd60e51b81526004016103a690614ce3565b9392505050565b6000848152600a602090815260408083206001600160a01b038681168086529190935292819020805460ff1916851515179055519085169086907f0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c9843390611709908690614b50565b60405180910390a450505050565b3390565b6001600160e01b03198216600090815260056020526040902080546001600160a01b0319166001600160a01b0383169081179091551561177657611770600d6001600160e01b0319841663ffffffff611ce616565b50611791565b610bdf600d6001600160e01b0319841663ffffffff611d2e16565b5050565b6000826117a45750600061164c565b828202828482816117b157fe5b041461169b5760405162461bcd60e51b81526004016103a690614db3565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611def565b600061169b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611e26565b604051636dcd64e560e01b815260009073f0F97838B2c80be59118e37436eca8F8edc2d08c90636dcd64e5906118919087908790879060040161498b565b60206040518083038186803b1580156118a957600080fd5b505af41580156118bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118e19190810190614065565b949350505050565b60008089606001516001600160a01b03168a608001516001600160a01b031614156119265760405162461bcd60e51b81526004016103a690614d03565b8960a0015186101561194a5760405162461bcd60e51b81526004016103a690614e83565b60e08a015115158061195f5750604084015115155b61197b5760405162461bcd60e51b81526004016103a690614ca3565b6000600660006119928d8d8b8b8b60200151611e52565b8152602001908152602001600020905060006119bd8c83886000015189602001518a60400151612244565b60608701519091506119d5908263ffffffff61181116565b60608701528915611a5d57606086015115611a025760405162461bcd60e51b81526004016103a690614d63565b6000611a118760800151611652565b60808e015160608f0151919250908215611a5557611a3a8a602001518660000154848487612460565b6080890151611a4f908463ffffffff61181116565b60808a01525b505050611acf565b6000611a828c8e606001518f608001518b602001518b6060015160008060008e6124ff565b60c08a0152506080880151909150611aa0908263ffffffff61167616565b608088015260a087015160c08801511015611acd5760405162461bcd60e51b81526004016103a690614cc3565b505b60408051610180810182528354815260018401546020820152600284015491810191909152600383015460ff16151560608201526004830154608080830191909152600584015460a0830152600684015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b85015416610160830152870151611b78918e918b908d61265d565b611b945760405162461bcd60e51b81526004016103a690614dd3565b60808601516005830154611bad9163ffffffff61167616565b60058301558915611bd7576007820154611bcd904263ffffffff61181116565b60e0870152611bf8565b611bf16f4b3b4ca85a86c47a098a224000000000896117cf565b6101008701525b611c058c8389898e612763565b856020015186608001519350935050509850989650505050505050565b6001600160a01b038116611c485760405162461bcd60e51b81526004016103a690614cb3565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612a36565b6000611cf28383612a80565b611d26575060018083018054808301808355600092835260208084209092018590558483529085905260409091205561164c565b50600061164c565b6000611d3a8383612a80565b15611d265760008281526020849052604090205460018401546000199182019101808214611db2576000856001018281548110611d7357fe5b9060005260206000200154905080866001018481548110611d9057fe5b6000918252602080832090910192909255918252869052604090206001830190555b60008481526020869052604081205560018501805480611dce57fe5b6001900381819060005260206000200160009055905560019250505061164c565b60008183611e105760405162461bcd60e51b81526004016103a69190614c62565b506000838581611e1c57fe5b0495945050505050565b60008184841115611e4a5760405162461bcd60e51b81526004016103a69190614c62565b505050900390565b60008560200151611e755760405162461bcd60e51b81526004016103a690614e23565b825160208401516060850151611e89613a87565b88611fe0576001600160a01b0383166000908152602a60209081526040918290208054600101908190558c519251611ec89392889288929091016148d9565b60408051601f1981840301815291815281516020928301206000818152600690935291205490995015611f0d5760405162461bcd60e51b81526004016103a690614d53565b5060408051610180810182528981528a5160208201526000918101829052600160608201526080810187905260a081018290524260c082015260e0810182905261010081018990526101208101919091526001600160a01b038084166101408301528416610160820152611f88600f8a63ffffffff611ce616565b506001600160a01b0384166000908152601160205260409020611fb1908a63ffffffff611ce616565b506001600160a01b0383166000908152601260205260409020611fda908a63ffffffff611ce616565b50612161565b5060008881526006602081815260409283902083516101808101855281548152600182015492810192909252600281015493820193909352600383015460ff161580156060830181905260048501546080840152600585015460a08401529284015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b909401549093166101608201529161209a57508060e0015142105b6120b65760405162461bcd60e51b81526004016103a690614d73565b826001600160a01b03168161014001516001600160a01b0316146120ec5760405162461bcd60e51b81526004016103a690614cd3565b836001600160a01b03168161016001516001600160a01b0316146121225760405162461bcd60e51b81526004016103a690614d33565b89516020820151146121465760405162461bcd60e51b81526004016103a690614c73565b608081015161215b908763ffffffff61167616565b60808201525b6001600160a01b0382161561217d5761217d89848460016116a2565b60008981526006602081815260409283902084518155908401516001820155918301516002830155606083015160038301805460ff19169115159190911790556080830151600483015560a0830151600583015560c08301519082015560e0820151600782015561010082015160088201556101208201516009820155610140820151600a820180546001600160a01b03199081166001600160a01b039384161790915561016090930151600b909201805490931691161790555095979650505050505050565b600b8401546060860151600091612266916001600160a01b0390911690612a95565b84546000818152600c60209081526040808320600b808b01546001600160a01b03908116865290845282852060608d0180518316875294529190932060e08b0151925160808c0151600a8c0154959692956122c79488949392911642612b73565b6000811580156122da5750600789015415155b1561230857612305620151806110518660000154611451428e6007015461181190919063ffffffff16565b90505b60006123286907baab4146b63dd000006110518a8c63ffffffff61179516565b855490915061233d908263ffffffff61167616565b85556001840154612354908263ffffffff61167616565b6001850155826123c357845461238190429061161090611051620151806114518d8963ffffffff61167616565b60078b01819055612398904263ffffffff61181116565b9250610e1083116123bb5760405162461bcd60e51b81526004016103a690614cf3565b869550612407565b60078a01546123e2576123dc428463ffffffff61167616565b60078b01555b6124046201518061105183611451428f6007015461181190919063ffffffff16565b95505b600185015461241c908763ffffffff61167616565b60018601558354612433908963ffffffff61167616565b8455600284015461244a908763ffffffff61167616565b8460020181905550505050505095945050505050565b80156124f8576001600160a01b0383166000908152601c602052604090205461248f908263ffffffff61167616565b6001600160a01b038085166000818152601c6020526040908190209390935591518692918816907ffb6c38ae4fdd498b3a5003f02ca4ca5340dfedb36b1b100c679eb60633b2c0a7906124e3908690614eb1565b60405180910390a46124f88585858585612bc1565b5050505050565b6040805160a0810182526001600160a01b03808b16825289811660208084019190915230838501819052606080850191909152918a1660808401528351918201845288825281018790529182018590526000918291829161256491908e888886613027565b90935091506125738b8361324c565b600254602754604051631e2c62d360e01b81526001600160a01b0390921691631e2c62d3916125ac918f918f9188918a916004016149db565b60206040518083038186803b1580156125c457600080fd5b505afa1580156125d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125fc9190810190614065565b9050896001600160a01b03168b6001600160a01b03168d7fb4eb3c9b62efcce7021cba5fd9cd0c44df91c2272806ccc5e57df7c912e8d7168c868860405161264693929190614b35565b60405180910390a499509950999650505050505050565b600061268568056bc75e2d631000006110518468055005f0c61448000063ffffffff61179516565b9150818310156127575760a08501511561274f5760025460608701516080808901519088015160a089015160405163f80b25fb60e01b81526000956001600160a01b03169463f80b25fb946126e294919390928c906004016149db565b60206040518083038186803b1580156126fa57600080fd5b505afa15801561270e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127329190810190614065565b905082612745858363ffffffff61167616565b1015915050610b62565b506000610b62565b50600195945050505050565b6002546060860151608087015160048088015460058901546040516317f8680960e11b815260009687966001600160a01b0390911695632ff0d012956127ad9592949193016149b3565b604080518083038186803b1580156127c457600080fd5b505afa1580156127d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127fc9190810190614083565b915091508660c0015182116128235760405162461bcd60e51b81526004016103a690614de3565b4286600601541415612989576002546060880151608089015160405163524efd4b60e01b81526000936001600160a01b03169263524efd4b926128689260040161493b565b60206040518083038186803b15801561288057600080fd5b505afa158015612894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128b89190810190614065565b60025460808a015160608b015160405163524efd4b60e01b81529394506000936001600160a01b039093169263524efd4b926128f892909160040161493b565b60206040518083038186803b15801561291057600080fd5b505afa158015612924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129489190810190614065565b9050600061295c838363ffffffff61179516565b90508561297e5760c087015161297990829063ffffffff6117cf16565b612980565b835b60098a01555050505b60408051610180810182528754815260018801546020820152600288015491810191909152600387015460ff161515606082015260048701546080820152600587015460a0820152600687015460c0820152600787015460e082015260088701546101008201526009870154610120820152600a8701546001600160a01b03908116610140830152600b88015416610160820152612a2d908890878785878961331a565b50505050505050565b60008183612a575760405162461bcd60e51b81526004016103a69190614c62565b5083612a655750600061169b565b6000836001860381612a7357fe5b0460010195945050505050565b60009081526020919091526040902054151590565b6001600160a01b038083166000908152600b602090815260408083209385168352929052908120600181015490919015801590612ad55750600482015415155b15612b6657612b0062015180611051846001015461145186600401544261181190919063ffffffff16565b4260048401556002830154909150811115612b1c575060028101545b8015612b61576003820154612b37908263ffffffff61167616565b60038301556002820154612b51908263ffffffff61181116565b6002830155612b61848483613451565b612b6d565b4260048301555b50505050565b6000612ba96a07259756a8d619980000006110516015546114518b600001546114518d600201548961181190919063ffffffff16565b6002880183905590508015612a2d57612a2d83878787855b602f546002546001600160a01b038581166000908152603c602090815260408083208885168452909152812054909392919091169015612c24576001600160a01b038087166000908152603c602090815260408083209389168352929052205491505b6037546000906060906001600160a01b038085169163d138f9a160e01b918b9116612c6268056bc75e2d631000006110518c8b63ffffffff61179516565b604051602401612c749392919061498b565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612cb29190614921565b600060405180830381855afa9150503d8060008114612ced576040519150601f19603f3d011682016040523d82523d6000602084013e612cf2565b606091505b50915091506001821415612d0857602081015194505b6000306001600160a01b031663c22552f76040518163ffffffff1660e01b815260040160206040518083038186803b158015612d4357600080fd5b505afa158015612d57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d7b9190810190614065565b90508515801590612d8c5750858110155b15612fb45760375460385460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392612dc7929116908a90600401614b1a565b602060405180830381600087803b158015612de157600080fd5b505af1158015612df5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e199190810190613ea7565b50603854603f546040516000926001600160a01b031691612e40918f918b91602401614b35565b60408051601f198184030181529181526020820180516001600160e01b0316630efe6a8b60e01b17905251612e759190614921565b6000604051808303816000865af19150503d8060008114612eb2576040519150601f19603f3d011682016040523d82523d6000602084013e612eb7565b606091505b505090508015612f4657601f54612ed4908863ffffffff61167616565b601f819055508a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167ff41c644671512f1cda76abfe6038e3d7d526c1377a5a8c692f81703901db2150898b603f54604051612f3993929190614ecd565b60405180910390a4612fae565b8a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e710812898b603f54604051612fa593929190614ecd565b60405180910390a45b5061301a565b8515801590612fc257508581105b1561301a57603754603f546040518c926001600160a01b0390811692908f16917f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e71081291613011918b918d91614ecd565b60405180910390a45b5050505050505050505050565b8451600090819015158061303e5750602087015115155b61305a5760405162461bcd60e51b81526004016103a690614e13565b602087015161306b57865160208801525b6020870151875111156130905760405162461bcd60e51b81526004016103a690614d43565b60008060008761314d5760408a015161310c5785156130c1576130ba8a60005b60200201516134f6565b90506130d5565b6130d28a60005b602002015161161c565b90505b80156131075760808b01518b516130f891908b908e60015b60200201518561351a565b89516131049082611811565b8a525b61314d565b85156131245761311d8a60026130b0565b9050613132565b61312f8a60026130c8565b90505b801561314d5760408a01516131479082611676565b60408b01525b86511561316c5760405162461bcd60e51b81526004016103a690614e43565b6131768b8b61366a565b60408c015191945092506131c257895182146131a45760405162461bcd60e51b81526004016103a690614e73565b80156131bd576131ba828263ffffffff61167616565b91505b61323c565b60208a01518211156131e65760405162461bcd60e51b81526004016103a690614d23565b60408a015183101561320a5760405162461bcd60e51b81526004016103a690614c93565b801561323c5760808b015160208c015161322991908b908e60006130ed565b613239838263ffffffff61181116565b92505b5090999098509650505050505050565b6029548015610bdf57602d546000906001600160a01b03858116911614156132755750816132fa565b600254604051635967aa7560e11b81526001600160a01b039091169063b2cf54ea906132a79087908790600401614b1a565b60206040518083038186803b1580156132bf57600080fd5b505afa1580156132d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506132f79190810190614065565b90505b81811115612b6d5760405162461bcd60e51b81526004016103a690614d83565b80156133a357856000015185600001516001600160a01b031686602001516001600160a01b03167f7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f908a606001518b6080015189602001518a608001518b600001518c60e001518c8c604051613396989796959493929190614a1d565b60405180910390a4612a2d565b6133bd6f4b3b4ca85a86c47a098a224000000000836117cf565b9150856000015185600001516001600160a01b031686602001516001600160a01b03167ff640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c8a608001518b6060015189608001518a602001518b600001518e60e001518d60c001518e61010001518d60405161344099989796959493929190614a94565b60405180910390a450505050505050565b600061347568056bc75e2d631000006110516015548561179590919063ffffffff16565b9050613482848483613754565b61349c8385613497858563ffffffff61181116565b6137e2565b6001600160a01b038085169084167f220e66e3e759e1382aa86cd8af5abca05ebf3ad564f223ae62d977678337272a6134db858563ffffffff61181116565b6040516134e89190614eb1565b60405180910390a350505050565b600061164c68056bc75e2d63100000611640603e548561179590919063ffffffff16565b808015613662576001600160a01b0386811660009081526033602052604090205416156135d0576001600160a01b038087166000908152603360205260409020546135689116878684613845565b50506135cd61358f68056bc75e2d631000006110516039548561179590919063ffffffff16565b6135c16135b468056bc75e2d631000006110516020548761179590919063ffffffff16565b849063ffffffff61181116565b9063ffffffff61181116565b90505b6001600160a01b0384166000908152601960205260409020546135f9908263ffffffff61167616565b6001600160a01b03808616600081815260196020526040908190209390935591518792918916907fb23479169712c443e6b00fb0cec3506a5f5926f541df4243d313e11c8c5c71ed9061364d908690614eb1565b60405180910390a46136628686868686612bc1565b505050505050565b600080613675613aeb565b84516001600160a01b039081168252602080870151821683820152604080880151831681850152606080890151909316928401929092528551608084015285015160a08301528481015160c0830152516335aaa79d60e01b815273f0F97838B2c80be59118e37436eca8F8edc2d08c906335aaa79d906136f9908490600401614ea3565b604080518083038186803b15801561371057600080fd5b505af4158015613724573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506137489190810190614083565b90969095509350505050565b8015610bdf576001600160a01b038216600090815260166020526040902054613783908263ffffffff61167616565b6001600160a01b0380841660008181526016602052604090819020939093559151908516907f40a75ae5f7a5336e75f7c7977e12c4b46a9ac0f30de01a2d5b6c1a4f4af63587906137d5908590614eb1565b60405180910390a3505050565b8015610bdf576138026001600160a01b038416838363ffffffff6138d116565b816001600160a01b0316836001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1836040516137d59190614eb1565b6040516306a688ff60e11b815260009081903090630d4d11fe90613873908990899089908990600401614956565b6040805180830381600087803b15801561388c57600080fd5b505af11580156138a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506138c49190810190614083565b9097909650945050505050565b604051610bdf90849063a9059cbb60e01b906138f39086908690602401614b1a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613937826001600160a01b0316613a0a565b6139535760405162461bcd60e51b81526004016103a690614e93565b60006060836001600160a01b03168360405161396f9190614921565b6000604051808303816000865af19150503d80600081146139ac576040519150601f19603f3d011682016040523d82523d6000602084013e6139b1565b606091505b5091509150816139d35760405162461bcd60e51b81526004016103a690614d13565b805115612b6d57808060200190516139ee9190810190613ea7565b612b6d5760405162461bcd60e51b81526004016103a690614e53565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906118e1575050151592915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b803561164c8161500d565b803561164c81615021565b805161164c81615021565b803561164c8161502a565b803561164c81615033565b60008083601f840112613b7057600080fd5b50813567ffffffffffffffff811115613b8857600080fd5b602083019150836001820283011115613ba057600080fd5b9250929050565b600060808284031215613bb957600080fd5b50919050565b600060808284031215613bd157600080fd5b613bdb6080614f50565b90506000613be98484613b27565b8252506020613bfa84848301613b27565b6020830152506040613c0e84828501613b27565b6040830152506060613c2284828501613b27565b60608301525092915050565b60006101208284031215613bb957600080fd5b60006101208284031215613c5457600080fd5b613c5f610120614f50565b90506000613c6d8484613b48565b8252506020613c7e84848301613b48565b6020830152506040613c9284828501613b48565b6040830152506060613ca684828501613b48565b6060830152506080613cba84828501613b48565b60808301525060a0613cce84828501613b48565b60a08301525060c0613ce284828501613b48565b60c08301525060e0613cf684828501613b48565b60e083015250610100613d0b84828501613b48565b6101008301525092915050565b805161164c8161502a565b600060208284031215613d3557600080fd5b60006118e18484613b27565b60008060408385031215613d5457600080fd5b6000613d608585613b27565b9250506020613d7185828601613b27565b9150509250929050565b600080600080600060a08688031215613d9357600080fd5b6000613d9f8888613b27565b9550506020613db088828901613b27565b9450506040613dc188828901613b48565b9350506060613dd288828901613b48565b9250506080613de388828901613b32565b9150509295509295909350565b60008060008060008060c08789031215613e0957600080fd5b6000613e158989613b27565b9650506020613e2689828a01613b27565b9550506040613e3789828a01613b48565b9450506060613e4889828a01613b48565b9350506080613e5989828a01613b48565b92505060a0613e6a89828a01613b48565b9150509295509295509295565b60008060408385031215613e8a57600080fd5b6000613e968585613b27565b9250506020613d7185828601613b48565b600060208284031215613eb957600080fd5b60006118e18484613b3d565b600060208284031215613ed757600080fd5b60006118e18484613b48565b60008060408385031215613ef657600080fd5b6000613d608585613b48565b600080600060608486031215613f1757600080fd5b6000613f238686613b48565b9350506020613f3486828701613b27565b9250506040613f4586828701613b32565b9150509250925092565b600080600080600080600080610240898b031215613f6c57600080fd5b6000613f788b8b613b48565b9850506020613f898b828c01613b48565b9750506040613f9a8b828c01613b32565b9650506060613fab8b828c01613b48565b9550506080613fbc8b828c01613ba7565b945050610100613fce8b828c01613c2e565b93505061022089013567ffffffffffffffff811115613fec57600080fd5b613ff88b828c01613b5e565b92509250509295985092959890939650565b60006020828403121561401c57600080fd5b60006118e18484613b53565b60006080828403121561403a57600080fd5b60006118e18484613bbf565b6000610120828403121561405957600080fd5b60006118e18484613c41565b60006020828403121561407757600080fd5b60006118e18484613d18565b6000806040838503121561409657600080fd5b60006140a28585613d18565b9250506020613d7185828601613d18565b6140bc81614f89565b82525050565b6140bc6140ce82614f89565b614fec565b6140bc81614f94565b6140bc81614f99565b6140bc6140f182614f99565b614f99565b600061410182614f77565b61410b8185614f7b565b935061411b818560208601614fc0565b9290920192915050565b6140bc81614fb5565b600061413982614f77565b6141438185614f80565b9350614153818560208601614fc0565b61415c81614ffd565b9093019392505050565b6000614173601383614f80565b720d8dec2dca0c2e4c2dae640dad2e6dac2e8c6d606b1b815260200192915050565b60006141a2600683614f80565b6514185d5cd95960d21b815260200192915050565b60006141c4601b83614f80565b7f696e73756666696369656e742073776170206c69717569646974790000000000815260200192915050565b60006141fd601083614f80565b6f1a5b9d985b1a59081a5b9d195c995cdd60821b815260200192915050565b6000614229602683614f80565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000614271601d83614f80565b7f656e7472792070726963652061626f766520746865206d696e696d756d000000815260200192915050565b60006142aa601183614f80565b700c4dee4e4deeecae440dad2e6dac2e8c6d607b1b815260200192915050565b60006142d7601b83614f80565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000614310600e83614f80565b6d1b1bd85b881d1bdbc81cda1bdc9d60921b815260200192915050565b600061433a601583614f80565b740c6ded8d8c2e8cae4c2d85ed8dec2dc40dac2e8c6d605b1b815260200192915050565b600061436b602083614f80565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b60006143a4601383614f80565b72737761702066696c6c20746f6f206c6172676560681b815260200192915050565b60006143d3600f83614f80565b6e0d8cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b60006143fe601c83614f80565b7f736f75726365416d6f756e74206c6172676572207468616e206d617800000000815260200192915050565b6000614437600b83614f80565b6a6c6f616e2065786973747360a81b815260200192915050565b600061445e601283614f80565b7139bab938363ab9903637b0b7103a37b5b2b760711b815260200192915050565b600061448c600e83614f80565b6d1b1bd85b881a185cc8195b99195960921b815260200192915050565b60006144b6600e83614f80565b6d7377617020746f6f206c6172676560901b815260200192915050565b60006144e0600f83614f80565b6e0636f6c6c61746572616c206973203608c1b815260200192915050565b600061450b600e83614f80565b6d1b9bdd08185d5d1a1bdc9a5e995960921b815260200192915050565b6000614535602183614f80565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000614578600c83614f80565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006145a0601783614f80565b7f636f6c6c61746572616c20696e73756666696369656e74000000000000000000815260200192915050565b60006145d9601283614f80565b713ab73432b0b63a343c903837b9b4ba34b7b760711b815260200192915050565b6000614607601583614f80565b746c6f616e506172616d73206e6f742065786973747360581b815260200192915050565b6000614638601483614f80565b7319985b1b189858dac81b9bdd08185b1b1bddd95960621b815260200192915050565b6000614668602e83614f80565b7f6d696e206f72206d617820736f7572636520746f6b656e20616d6f756e74206e81526d1959591cc81d1bc81899481cd95d60921b602082015260400192915050565b60006146b8601383614f80565b721b1bd85b94185c985b5cc8191a5cd8589b1959606a1b815260200192915050565b60006146e7600c83614f80565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b600061470f600d83614f80565b6c696e76616c696420737461746560981b815260200192915050565b6000614738602a83614f80565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b6000614784602183614f80565b7f6c6f616e446174614279746573207265717569726564207769746820657468658152603960f91b602082015260400192915050565b60006147c7601683614f80565b751cddd85c081d1bdbc81b185c99d9481d1bc8199a5b1b60521b815260200192915050565b60006147f9601583614f80565b74696e697469616c4d617267696e20746f6f206c6f7760581b815260200192915050565b600061482a601f83614f80565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160e083019061486784826140b3565b50602082015161487a60208501826140b3565b50604082015161488d60408501826140b3565b5060608201516148a060608501826140b3565b5060808201516148b360808501826140dc565b5060a08201516148c660a08501826140dc565b5060c0820151612b6d60c08501826140dc565b60006148e582876140e5565b6020820191506148f582866140c2565b60148201915061490582856140c2565b60148201915061491582846140e5565b50602001949350505050565b600061169b82846140f6565b6020810161164c82846140b3565b6040810161494982856140b3565b61169b60208301846140b3565b6080810161496482876140b3565b61497160208301866140b3565b61497e60408301856140b3565b610b6260608301846140dc565b6060810161499982866140b3565b6149a660208301856140b3565b6118e160408301846140dc565b608081016149c182876140b3565b6149ce60208301866140b3565b61497e60408301856140dc565b60a081016149e982886140b3565b6149f660208301876140b3565b614a0360408301866140dc565b614a1060608301856140dc565b6110f060808301846140dc565b6101008101614a2c828b6140b3565b614a39602083018a6140b3565b614a4660408301896140dc565b614a5360608301886140dc565b614a6060808301876140dc565b614a6d60a08301866140dc565b614a7a60c08301856140dc565b614a8760e08301846140dc565b9998505050505050505050565b6101208101614aa3828c6140b3565b614ab0602083018b6140b3565b614abd604083018a6140dc565b614aca60608301896140dc565b614ad760808301886140dc565b614ae460a08301876140dc565b614af160c08301866140dc565b614afe60e08301856140dc565b614b0c6101008301846140dc565b9a9950505050505050505050565b60408101614b2882856140b3565b61169b60208301846140dc565b60608101614b4382866140b3565b6149a660208301856140dc565b6020810161164c82846140d3565b6101008101614b6d828b6140dc565b614b7a602083018a6140d3565b614b8760408301896140b3565b614b9460608301886140b3565b614a6060808301876140b3565b6101808101614bb0828f6140dc565b614bbd602083018e6140dc565b614bca604083018d6140dc565b614bd7606083018c6140d3565b614be4608083018b6140dc565b614bf160a083018a6140dc565b614bfe60c08301896140dc565b614c0b60e08301886140dc565b614c196101008301876140dc565b614c276101208301866140dc565b614c356101408301856140b3565b614c436101608301846140b3565b9d9c50505050505050505050505050565b6020810161164c8284614125565b6020808252810161169b818461412e565b6020808252810161164c81614166565b6020808252810161164c81614195565b6020808252810161164c816141b7565b6020808252810161164c816141f0565b6020808252810161164c8161421c565b6020808252810161164c81614264565b6020808252810161164c8161429d565b6020808252810161164c816142ca565b6020808252810161164c81614303565b6020808252810161164c8161432d565b6020808252810161164c8161435e565b6020808252810161164c81614397565b6020808252810161164c816143c6565b6020808252810161164c816143f1565b6020808252810161164c8161442a565b6020808252810161164c81614451565b6020808252810161164c8161447f565b6020808252810161164c816144a9565b6020808252810161164c816144d3565b6020808252810161164c816144fe565b6020808252810161164c81614528565b6020808252810161164c8161456b565b6020808252810161164c81614593565b6020808252810161164c816145cc565b6020808252810161164c816145fa565b6020808252810161164c8161462b565b6020808252810161164c8161465b565b6020808252810161164c816146ab565b6020808252810161164c816146da565b6020808252810161164c81614702565b6020808252810161164c8161472b565b6020808252810161164c81614777565b6020808252810161164c816147ba565b6020808252810161164c816147ec565b6020808252810161164c8161481d565b60e0810161164c8284614856565b6020810161164c82846140dc565b60408101614b2882856140dc565b60608101614b4382866140dc565b60a08101614ee982886140dc565b6149f660208301876140dc565b60c08101614f0482896140dc565b614f1160208301886140dc565b614f1e60408301876140dc565b614f2b60608301866140dc565b614f3860808301856140dc565b614f4560a08301846140dc565b979650505050505050565b60405181810167ffffffffffffffff81118282101715614f6f57600080fd5b604052919050565b5190565b919050565b90815260200190565b600061164c82614fa9565b151590565b90565b6001600160e01b03191690565b6001600160a01b031690565b600061164c82614f89565b60005b83811015614fdb578181015183820152602001614fc3565b83811115612b6d5750506000910152565b600061164c82600061164c82615007565b601f01601f191690565b60601b90565b61501681614f89565b81146114b657600080fd5b61501681614f94565b61501681614f99565b61501681614f9c56fea365627a7a723158209a8d12e965f3506c2f6525444e34694cec46e043cf5ecbd237112664c19b0aa96c6578706572696d656e74616cf564736f6c63430005110040", - "deployedBytecode": "0x6080604052600436106103815760003560e01c80638f32d59b116101d1578063cd5d808d11610102578063e8f62764116100a0578063f589a3e71161006f578063f589a3e714610a05578063f6ddc8b314610a1a578063f706b1f214610a2f578063f851a44014610a4457610381565b8063e8f62764146109a6578063edab119f146109bb578063f0e085f5146109d0578063f2fde38b146109e557610381565b8063d485045e116100dc578063d485045e14610925578063d67f707714610945578063d84ca25414610965578063e762319f1461098657610381565b8063cd5d808d146108db578063d288208c146108fb578063d473c2da1461091057610381565b8063b7e152411161016f578063bdee453c11610149578063bdee453c1461082f578063c4a908151461084f578063c4d66de814610887578063cb6eacd1146108a757610381565b8063b7e15241146107e5578063b9cffa3e14610805578063ba4861e91461081a57610381565b8063acc04348116101ab578063acc0434814610779578063ae0a85301461078e578063afe84009146107a3578063b30643d9146107c557610381565b80638f32d59b1461072f57806392d894f814610744578063959083d31461076457610381565b80634203e395116102b65780636e663730116102545780637a8faeb8116102235780637a8faeb8146106d05780638456cb59146106e55780638da5cb5b146106fa5780638dc48ba51461070f57610381565b80636e663730146106715780637420ca3e14610691578063742e6798146106a657806378d849ed146106bb57610381565b8063569fc1fb11610290578063569fc1fb146105dc578063574442cc1461060b57806362fff3f61461062057806368c4ac261461065157610381565b80634203e395146105925780634699f846146105b25780634f28cac2146105c757610381565b80632a324027116103235780633432423c116102fd5780633432423c146105125780633452d2d4146105325780633fca506e146105525780634115a2b61461057257610381565b80632a324027146104c65780632f470764146104db57806333d8991f146104f057610381565b80631b7bde741161035f5780631b7bde741461042c578063218b39c61461045957806324cc57491461047957806325decac0146104a657610381565b8063065d810f146103af5780630676c1b7146103ea57806317548b791461040c575b34801561038d57600080fd5b5060405162461bcd60e51b81526004016103a690614e03565b60405180910390fd5b3480156103bb57600080fd5b506103cf6103ca366004613e77565b610a59565b6040516103e196959493929190614ef6565b60405180910390f35b3480156103f657600080fd5b506103ff610a99565b6040516103e1919061492d565b34801561041857600080fd5b506103ff61042736600461400a565b610aa8565b34801561043857600080fd5b5061044c610447366004613d41565b610ac3565b6040516103e19190614eb1565b34801561046557600080fd5b506103ff610474366004613d23565b610ae0565b34801561048557600080fd5b50610499610494366004613d23565b610afb565b6040516103e19190614b50565b3480156104b257600080fd5b5061044c6104c1366004613d7b565b610b10565b3480156104d257600080fd5b5061044c610b6b565b3480156104e757600080fd5b5061044c610b71565b3480156104fc57600080fd5b5061051061050b366004613f02565b610b77565b005b34801561051e57600080fd5b506103cf61052d366004613e77565b610be4565b34801561053e57600080fd5b5061044c61054d366004613d23565b610c24565b34801561055e57600080fd5b5061044c61056d366004613d23565b610c36565b34801561057e57600080fd5b5061049961058d366004613ee3565b610c48565b34801561059e57600080fd5b5061044c6105ad366004613d23565b610c68565b3480156105be57600080fd5b5061044c610c7a565b3480156105d357600080fd5b5061044c610c80565b3480156105e857600080fd5b506105fc6105f7366004613ec5565b610c86565b6040516103e193929190614ecd565b34801561061757600080fd5b5061044c610ca7565b34801561062c57600080fd5b5061064061063b366004613d41565b610cad565b6040516103e1959493929190614edb565b34801561065d57600080fd5b5061049961066c366004613d23565b610ce7565b34801561067d57600080fd5b506103ff61068c366004613d23565b610cfc565b34801561069d57600080fd5b506103ff610d17565b3480156106b257600080fd5b5061044c610d26565b3480156106c757600080fd5b506103ff610d2c565b3480156106dc57600080fd5b5061044c610d3b565b3480156106f157600080fd5b50610499610d41565b34801561070657600080fd5b506103ff610d4a565b34801561071b57600080fd5b506103ff61072a366004613d23565b610d59565b34801561073b57600080fd5b50610499610d74565b34801561075057600080fd5b5061044c61075f366004613d23565b610d9a565b34801561077057600080fd5b5061044c610dac565b34801561078557600080fd5b5061044c610db2565b34801561079a57600080fd5b5061044c610db8565b3480156107af57600080fd5b506107b8610dbe565b6040516103e19190614c54565b3480156107d157600080fd5b5061044c6107e0366004613d23565b610dcd565b3480156107f157600080fd5b5061044c610800366004613d23565b610ddf565b34801561081157600080fd5b506103ff610df1565b34801561082657600080fd5b506103ff610e00565b34801561083b57600080fd5b5061044c61084a366004613d23565b610e0f565b34801561085b57600080fd5b5061086f61086a366004613ec5565b610e21565b6040516103e19c9b9a99989796959493929190614ba1565b34801561089357600080fd5b506105106108a2366004613d23565b610e93565b3480156108b357600080fd5b506108c76108c2366004613ec5565b610f96565b6040516103e1989796959493929190614b5e565b3480156108e757600080fd5b5061044c6108f6366004613d41565b610fe8565b34801561090757600080fd5b506103ff611005565b34801561091c57600080fd5b5061044c611014565b34801561093157600080fd5b5061044c610940366004613d23565b61101a565b34801561095157600080fd5b5061044c610960366004613df0565b61102c565b610978610973366004613f4f565b6110fa565b6040516103e1929190614ebf565b34801561099257600080fd5b5061044c6109a1366004613d7b565b6112fa565b3480156109b257600080fd5b506103ff61146e565b3480156109c757600080fd5b5061044c61147d565b3480156109dc57600080fd5b5061044c611483565b3480156109f157600080fd5b50610510610a00366004613d23565b611489565b348015610a1157600080fd5b5061044c6114b9565b348015610a2657600080fd5b5061044c6114bf565b348015610a3b57600080fd5b506103ff6114c5565b348015610a5057600080fd5b506103ff6114d4565b6009602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b6031546001600160a01b031681565b6005602052600090815260409020546001600160a01b031681565b603b60209081526000928352604080842090915290825290205481565b6023602052600090815260409020546001600160a01b031681565b60326020526000908152604090205460ff1681565b60008215610b6257610b2586868686866114e3565b9050600082610b3c57610b378261161c565b610b45565b610b4582611652565b90508015610b6057610b5d828263ffffffff61167616565b91505b505b95945050505050565b60185481565b601f5481565b603d5460ff1615610b9a5760405162461bcd60e51b81526004016103a690614c83565b6000838152600660205260409020600a01546001600160a01b03163314610bd35760405162461bcd60e51b81526004016103a690614dc3565b610bdf833384846116a2565b505050565b6008602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b601a6020526000908152604090205481565b602a6020526000908152604090205481565b600a60209081526000928352604080842090915290825290205460ff1681565b60166020526000908152604090205481565b60155481565b60295481565b600c6020526000908152604090208054600182015460029092015490919083565b602b5481565b600b602090815260009283526040808420909152908252902080546001820154600283015460038401546004909401549293919290919085565b60266020526000908152604090205460ff1681565b6033602052600090815260409020546001600160a01b031681565b6003546001600160a01b031681565b60355481565b6002546001600160a01b031681565b601e5481565b603d5460ff1681565b6001546001600160a01b031690565b6022602052600090815260409020546001600160a01b031681565b6001546000906001600160a01b0316610d8b611717565b6001600160a01b031614905090565b60176020526000908152604090205481565b602c5481565b602f5481565b60205481565b602d546001600160a01b031681565b601d6020526000908152604090205481565b601c6020526000908152604090205481565b6037546001600160a01b031681565b6004546001600160a01b031681565b60366020526000908152604090205481565b600660208190526000918252604090912080546001820154600283015460038401546004850154600586015496860154600787015460088801546009890154600a8a0154600b909a0154989a9799969860ff909616979496949593949293919290916001600160a01b0391821691168c565b610e9b610d74565b610eb75760405162461bcd60e51b81526004016103a690614dc3565b633613289560e21b600081905260056020527fd3a886345208a8e3a0f774019653c4e69589e943ba1e46c7fa0ef875651e6e39546001600160a01b031690610eff908361171b565b610f106333d8991f60e01b8361171b565b610f2163d67f707760e01b8361171b565b610f3162977b2b60e61b8361171b565b610f4263e762319f60e01b8361171b565b6b4c6f616e4f70656e696e677360a01b826001600160a01b0316826001600160a01b03167f1420e3a2094d671bc2eb897941fa3d94ffa37f0cb6d530651946250a2151cb7f60405160405180910390a45050565b6007602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949560ff8516956101009095046001600160a01b03908116959481169493169288565b603c60209081526000928352604080842090915290825290205481565b6038546001600160a01b031681565b60275481565b60196020526000908152604090205481565b60006224ea008161105d6907baab4146b63dd00000611051868863ffffffff61179516565b9063ffffffff6117cf16565b9050600061107862015180611051858563ffffffff61179516565b9050600061108c898363ffffffff61181116565b905060006110998261161c565b905080156110b4576110b1828263ffffffff61181116565b91505b60006110c18d8d85611853565b9050806110d757600096505050505050506110f0565b6110e78a8263ffffffff61167616565b96505050505050505b9695505050505050565b60008060016000541461111f5760405162461bcd60e51b81526004016103a690614e33565b6002600055603d5460ff16156111475760405162461bcd60e51b81526004016103a690614c83565b34158061115357508215155b61116f5760405162461bcd60e51b81526004016103a690614e63565b336000908152602260205260409020546001600160a01b03166111a45760405162461bcd60e51b81526004016103a690614da3565b6111ac613a43565b5060008a815260076020908152604091829020825161010080820185528254808352600184015460ff811615159584019590955293046001600160a01b039081169482019490945260028201548416606082015260038201549093166080840152600481015460a0840152600581015460c08401526006015460e08301526112465760405162461bcd60e51b81526004016103a690614df3565b60006112618260600151836080015189602001358c8e6114e3565b9050806112805760405162461bcd60e51b81526004016103a690614d93565b6112e2828c8c848d611297368f90038f018f614028565b6112a6368f90038f018f614046565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118e992505050565b6001600055909d909c509a5050505050505050505050565b60008215610b62578115611324576113218368056bc75e2d6310000063ffffffff61167616565b92505b8360008361133a576113358261161c565b611343565b61134382611652565b9050801561135e5761135b828263ffffffff61181116565b91505b866001600160a01b0316886001600160a01b0316141561139c57611395856110518468056bc75e2d6310000063ffffffff61179516565b9250611463565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c906113d3908c908e9060040161493b565b604080518083038186803b1580156113ea57600080fd5b505afa1580156113fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114229190810190614083565b91509150806000146114605761145d816110518981866114518a68056bc75e2d6310000063ffffffff61179516565b9063ffffffff61179516565b94505b50505b505095945050505050565b6014546001600160a01b031681565b601b5481565b60285481565b611491610d74565b6114ad5760405162461bcd60e51b81526004016103a690614dc3565b6114b681611c22565b50565b60395481565b60215481565b602e546001600160a01b031681565b6030546001600160a01b031681565b6000846001600160a01b0316866001600160a01b031614156115235761151c68056bc75e2d63100000611051868663ffffffff61179516565b90506115de565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c9061155a908a908c9060040161493b565b604080518083038186803b15801561157157600080fd5b505afa158015611585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115a99190810190614083565b91509150816000146115db576115d868056bc75e2d631000006110518761145186838c8863ffffffff61179516565b92505b50505b8180156115ea57508015155b15610b62576110f081611610856110518368056bc75e2d6310000063ffffffff61179516565b9063ffffffff61167616565b600061164c68056bc75e2d631000006116406018548561179590919063ffffffff16565b9063ffffffff611ca416565b92915050565b600061164c68056bc75e2d63100000611640601b548561179590919063ffffffff16565b60008282018381101561169b5760405162461bcd60e51b81526004016103a690614ce3565b9392505050565b6000848152600a602090815260408083206001600160a01b038681168086529190935292819020805460ff1916851515179055519085169086907f0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c9843390611709908690614b50565b60405180910390a450505050565b3390565b6001600160e01b03198216600090815260056020526040902080546001600160a01b0319166001600160a01b0383169081179091551561177657611770600d6001600160e01b0319841663ffffffff611ce616565b50611791565b610bdf600d6001600160e01b0319841663ffffffff611d2e16565b5050565b6000826117a45750600061164c565b828202828482816117b157fe5b041461169b5760405162461bcd60e51b81526004016103a690614db3565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611def565b600061169b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611e26565b604051636dcd64e560e01b815260009073__$6b3065420287e4be5d93089ad806c078e3$__90636dcd64e5906118919087908790879060040161498b565b60206040518083038186803b1580156118a957600080fd5b505af41580156118bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118e19190810190614065565b949350505050565b60008089606001516001600160a01b03168a608001516001600160a01b031614156119265760405162461bcd60e51b81526004016103a690614d03565b8960a0015186101561194a5760405162461bcd60e51b81526004016103a690614e83565b60e08a015115158061195f5750604084015115155b61197b5760405162461bcd60e51b81526004016103a690614ca3565b6000600660006119928d8d8b8b8b60200151611e52565b8152602001908152602001600020905060006119bd8c83886000015189602001518a60400151612244565b60608701519091506119d5908263ffffffff61181116565b60608701528915611a5d57606086015115611a025760405162461bcd60e51b81526004016103a690614d63565b6000611a118760800151611652565b60808e015160608f0151919250908215611a5557611a3a8a602001518660000154848487612460565b6080890151611a4f908463ffffffff61181116565b60808a01525b505050611acf565b6000611a828c8e606001518f608001518b602001518b6060015160008060008e6124ff565b60c08a0152506080880151909150611aa0908263ffffffff61167616565b608088015260a087015160c08801511015611acd5760405162461bcd60e51b81526004016103a690614cc3565b505b60408051610180810182528354815260018401546020820152600284015491810191909152600383015460ff16151560608201526004830154608080830191909152600584015460a0830152600684015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b85015416610160830152870151611b78918e918b908d61265d565b611b945760405162461bcd60e51b81526004016103a690614dd3565b60808601516005830154611bad9163ffffffff61167616565b60058301558915611bd7576007820154611bcd904263ffffffff61181116565b60e0870152611bf8565b611bf16f4b3b4ca85a86c47a098a224000000000896117cf565b6101008701525b611c058c8389898e612763565b856020015186608001519350935050509850989650505050505050565b6001600160a01b038116611c485760405162461bcd60e51b81526004016103a690614cb3565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612a36565b6000611cf28383612a80565b611d26575060018083018054808301808355600092835260208084209092018590558483529085905260409091205561164c565b50600061164c565b6000611d3a8383612a80565b15611d265760008281526020849052604090205460018401546000199182019101808214611db2576000856001018281548110611d7357fe5b9060005260206000200154905080866001018481548110611d9057fe5b6000918252602080832090910192909255918252869052604090206001830190555b60008481526020869052604081205560018501805480611dce57fe5b6001900381819060005260206000200160009055905560019250505061164c565b60008183611e105760405162461bcd60e51b81526004016103a69190614c62565b506000838581611e1c57fe5b0495945050505050565b60008184841115611e4a5760405162461bcd60e51b81526004016103a69190614c62565b505050900390565b60008560200151611e755760405162461bcd60e51b81526004016103a690614e23565b825160208401516060850151611e89613a87565b88611fe0576001600160a01b0383166000908152602a60209081526040918290208054600101908190558c519251611ec89392889288929091016148d9565b60408051601f1981840301815291815281516020928301206000818152600690935291205490995015611f0d5760405162461bcd60e51b81526004016103a690614d53565b5060408051610180810182528981528a5160208201526000918101829052600160608201526080810187905260a081018290524260c082015260e0810182905261010081018990526101208101919091526001600160a01b038084166101408301528416610160820152611f88600f8a63ffffffff611ce616565b506001600160a01b0384166000908152601160205260409020611fb1908a63ffffffff611ce616565b506001600160a01b0383166000908152601260205260409020611fda908a63ffffffff611ce616565b50612161565b5060008881526006602081815260409283902083516101808101855281548152600182015492810192909252600281015493820193909352600383015460ff161580156060830181905260048501546080840152600585015460a08401529284015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b909401549093166101608201529161209a57508060e0015142105b6120b65760405162461bcd60e51b81526004016103a690614d73565b826001600160a01b03168161014001516001600160a01b0316146120ec5760405162461bcd60e51b81526004016103a690614cd3565b836001600160a01b03168161016001516001600160a01b0316146121225760405162461bcd60e51b81526004016103a690614d33565b89516020820151146121465760405162461bcd60e51b81526004016103a690614c73565b608081015161215b908763ffffffff61167616565b60808201525b6001600160a01b0382161561217d5761217d89848460016116a2565b60008981526006602081815260409283902084518155908401516001820155918301516002830155606083015160038301805460ff19169115159190911790556080830151600483015560a0830151600583015560c08301519082015560e0820151600782015561010082015160088201556101208201516009820155610140820151600a820180546001600160a01b03199081166001600160a01b039384161790915561016090930151600b909201805490931691161790555095979650505050505050565b600b8401546060860151600091612266916001600160a01b0390911690612a95565b84546000818152600c60209081526040808320600b808b01546001600160a01b03908116865290845282852060608d0180518316875294529190932060e08b0151925160808c0151600a8c0154959692956122c79488949392911642612b73565b6000811580156122da5750600789015415155b1561230857612305620151806110518660000154611451428e6007015461181190919063ffffffff16565b90505b60006123286907baab4146b63dd000006110518a8c63ffffffff61179516565b855490915061233d908263ffffffff61167616565b85556001840154612354908263ffffffff61167616565b6001850155826123c357845461238190429061161090611051620151806114518d8963ffffffff61167616565b60078b01819055612398904263ffffffff61181116565b9250610e1083116123bb5760405162461bcd60e51b81526004016103a690614cf3565b869550612407565b60078a01546123e2576123dc428463ffffffff61167616565b60078b01555b6124046201518061105183611451428f6007015461181190919063ffffffff16565b95505b600185015461241c908763ffffffff61167616565b60018601558354612433908963ffffffff61167616565b8455600284015461244a908763ffffffff61167616565b8460020181905550505050505095945050505050565b80156124f8576001600160a01b0383166000908152601c602052604090205461248f908263ffffffff61167616565b6001600160a01b038085166000818152601c6020526040908190209390935591518692918816907ffb6c38ae4fdd498b3a5003f02ca4ca5340dfedb36b1b100c679eb60633b2c0a7906124e3908690614eb1565b60405180910390a46124f88585858585612bc1565b5050505050565b6040805160a0810182526001600160a01b03808b16825289811660208084019190915230838501819052606080850191909152918a1660808401528351918201845288825281018790529182018590526000918291829161256491908e888886613027565b90935091506125738b8361324c565b600254602754604051631e2c62d360e01b81526001600160a01b0390921691631e2c62d3916125ac918f918f9188918a916004016149db565b60206040518083038186803b1580156125c457600080fd5b505afa1580156125d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125fc9190810190614065565b9050896001600160a01b03168b6001600160a01b03168d7fb4eb3c9b62efcce7021cba5fd9cd0c44df91c2272806ccc5e57df7c912e8d7168c868860405161264693929190614b35565b60405180910390a499509950999650505050505050565b600061268568056bc75e2d631000006110518468055005f0c61448000063ffffffff61179516565b9150818310156127575760a08501511561274f5760025460608701516080808901519088015160a089015160405163f80b25fb60e01b81526000956001600160a01b03169463f80b25fb946126e294919390928c906004016149db565b60206040518083038186803b1580156126fa57600080fd5b505afa15801561270e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127329190810190614065565b905082612745858363ffffffff61167616565b1015915050610b62565b506000610b62565b50600195945050505050565b6002546060860151608087015160048088015460058901546040516317f8680960e11b815260009687966001600160a01b0390911695632ff0d012956127ad9592949193016149b3565b604080518083038186803b1580156127c457600080fd5b505afa1580156127d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127fc9190810190614083565b915091508660c0015182116128235760405162461bcd60e51b81526004016103a690614de3565b4286600601541415612989576002546060880151608089015160405163524efd4b60e01b81526000936001600160a01b03169263524efd4b926128689260040161493b565b60206040518083038186803b15801561288057600080fd5b505afa158015612894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128b89190810190614065565b60025460808a015160608b015160405163524efd4b60e01b81529394506000936001600160a01b039093169263524efd4b926128f892909160040161493b565b60206040518083038186803b15801561291057600080fd5b505afa158015612924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129489190810190614065565b9050600061295c838363ffffffff61179516565b90508561297e5760c087015161297990829063ffffffff6117cf16565b612980565b835b60098a01555050505b60408051610180810182528754815260018801546020820152600288015491810191909152600387015460ff161515606082015260048701546080820152600587015460a0820152600687015460c0820152600787015460e082015260088701546101008201526009870154610120820152600a8701546001600160a01b03908116610140830152600b88015416610160820152612a2d908890878785878961331a565b50505050505050565b60008183612a575760405162461bcd60e51b81526004016103a69190614c62565b5083612a655750600061169b565b6000836001860381612a7357fe5b0460010195945050505050565b60009081526020919091526040902054151590565b6001600160a01b038083166000908152600b602090815260408083209385168352929052908120600181015490919015801590612ad55750600482015415155b15612b6657612b0062015180611051846001015461145186600401544261181190919063ffffffff16565b4260048401556002830154909150811115612b1c575060028101545b8015612b61576003820154612b37908263ffffffff61167616565b60038301556002820154612b51908263ffffffff61181116565b6002830155612b61848483613451565b612b6d565b4260048301555b50505050565b6000612ba96a07259756a8d619980000006110516015546114518b600001546114518d600201548961181190919063ffffffff16565b6002880183905590508015612a2d57612a2d83878787855b602f546002546001600160a01b038581166000908152603c602090815260408083208885168452909152812054909392919091169015612c24576001600160a01b038087166000908152603c602090815260408083209389168352929052205491505b6037546000906060906001600160a01b038085169163d138f9a160e01b918b9116612c6268056bc75e2d631000006110518c8b63ffffffff61179516565b604051602401612c749392919061498b565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612cb29190614921565b600060405180830381855afa9150503d8060008114612ced576040519150601f19603f3d011682016040523d82523d6000602084013e612cf2565b606091505b50915091506001821415612d0857602081015194505b6000306001600160a01b031663c22552f76040518163ffffffff1660e01b815260040160206040518083038186803b158015612d4357600080fd5b505afa158015612d57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d7b9190810190614065565b90508515801590612d8c5750858110155b15612fb45760375460385460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392612dc7929116908a90600401614b1a565b602060405180830381600087803b158015612de157600080fd5b505af1158015612df5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e199190810190613ea7565b50603854603f546040516000926001600160a01b031691612e40918f918b91602401614b35565b60408051601f198184030181529181526020820180516001600160e01b0316630efe6a8b60e01b17905251612e759190614921565b6000604051808303816000865af19150503d8060008114612eb2576040519150601f19603f3d011682016040523d82523d6000602084013e612eb7565b606091505b505090508015612f4657601f54612ed4908863ffffffff61167616565b601f819055508a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167ff41c644671512f1cda76abfe6038e3d7d526c1377a5a8c692f81703901db2150898b603f54604051612f3993929190614ecd565b60405180910390a4612fae565b8a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e710812898b603f54604051612fa593929190614ecd565b60405180910390a45b5061301a565b8515801590612fc257508581105b1561301a57603754603f546040518c926001600160a01b0390811692908f16917f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e71081291613011918b918d91614ecd565b60405180910390a45b5050505050505050505050565b8451600090819015158061303e5750602087015115155b61305a5760405162461bcd60e51b81526004016103a690614e13565b602087015161306b57865160208801525b6020870151875111156130905760405162461bcd60e51b81526004016103a690614d43565b60008060008761314d5760408a015161310c5785156130c1576130ba8a60005b60200201516134f6565b90506130d5565b6130d28a60005b602002015161161c565b90505b80156131075760808b01518b516130f891908b908e60015b60200201518561351a565b89516131049082611811565b8a525b61314d565b85156131245761311d8a60026130b0565b9050613132565b61312f8a60026130c8565b90505b801561314d5760408a01516131479082611676565b60408b01525b86511561316c5760405162461bcd60e51b81526004016103a690614e43565b6131768b8b61366a565b60408c015191945092506131c257895182146131a45760405162461bcd60e51b81526004016103a690614e73565b80156131bd576131ba828263ffffffff61167616565b91505b61323c565b60208a01518211156131e65760405162461bcd60e51b81526004016103a690614d23565b60408a015183101561320a5760405162461bcd60e51b81526004016103a690614c93565b801561323c5760808b015160208c015161322991908b908e60006130ed565b613239838263ffffffff61181116565b92505b5090999098509650505050505050565b6029548015610bdf57602d546000906001600160a01b03858116911614156132755750816132fa565b600254604051635967aa7560e11b81526001600160a01b039091169063b2cf54ea906132a79087908790600401614b1a565b60206040518083038186803b1580156132bf57600080fd5b505afa1580156132d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506132f79190810190614065565b90505b81811115612b6d5760405162461bcd60e51b81526004016103a690614d83565b80156133a357856000015185600001516001600160a01b031686602001516001600160a01b03167f7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f908a606001518b6080015189602001518a608001518b600001518c60e001518c8c604051613396989796959493929190614a1d565b60405180910390a4612a2d565b6133bd6f4b3b4ca85a86c47a098a224000000000836117cf565b9150856000015185600001516001600160a01b031686602001516001600160a01b03167ff640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c8a608001518b6060015189608001518a602001518b600001518e60e001518d60c001518e61010001518d60405161344099989796959493929190614a94565b60405180910390a450505050505050565b600061347568056bc75e2d631000006110516015548561179590919063ffffffff16565b9050613482848483613754565b61349c8385613497858563ffffffff61181116565b6137e2565b6001600160a01b038085169084167f220e66e3e759e1382aa86cd8af5abca05ebf3ad564f223ae62d977678337272a6134db858563ffffffff61181116565b6040516134e89190614eb1565b60405180910390a350505050565b600061164c68056bc75e2d63100000611640603e548561179590919063ffffffff16565b808015613662576001600160a01b0386811660009081526033602052604090205416156135d0576001600160a01b038087166000908152603360205260409020546135689116878684613845565b50506135cd61358f68056bc75e2d631000006110516039548561179590919063ffffffff16565b6135c16135b468056bc75e2d631000006110516020548761179590919063ffffffff16565b849063ffffffff61181116565b9063ffffffff61181116565b90505b6001600160a01b0384166000908152601960205260409020546135f9908263ffffffff61167616565b6001600160a01b03808616600081815260196020526040908190209390935591518792918916907fb23479169712c443e6b00fb0cec3506a5f5926f541df4243d313e11c8c5c71ed9061364d908690614eb1565b60405180910390a46136628686868686612bc1565b505050505050565b600080613675613aeb565b84516001600160a01b039081168252602080870151821683820152604080880151831681850152606080890151909316928401929092528551608084015285015160a08301528481015160c0830152516335aaa79d60e01b815273__$6b3065420287e4be5d93089ad806c078e3$__906335aaa79d906136f9908490600401614ea3565b604080518083038186803b15801561371057600080fd5b505af4158015613724573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506137489190810190614083565b90969095509350505050565b8015610bdf576001600160a01b038216600090815260166020526040902054613783908263ffffffff61167616565b6001600160a01b0380841660008181526016602052604090819020939093559151908516907f40a75ae5f7a5336e75f7c7977e12c4b46a9ac0f30de01a2d5b6c1a4f4af63587906137d5908590614eb1565b60405180910390a3505050565b8015610bdf576138026001600160a01b038416838363ffffffff6138d116565b816001600160a01b0316836001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1836040516137d59190614eb1565b6040516306a688ff60e11b815260009081903090630d4d11fe90613873908990899089908990600401614956565b6040805180830381600087803b15801561388c57600080fd5b505af11580156138a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506138c49190810190614083565b9097909650945050505050565b604051610bdf90849063a9059cbb60e01b906138f39086908690602401614b1a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613937826001600160a01b0316613a0a565b6139535760405162461bcd60e51b81526004016103a690614e93565b60006060836001600160a01b03168360405161396f9190614921565b6000604051808303816000865af19150503d80600081146139ac576040519150601f19603f3d011682016040523d82523d6000602084013e6139b1565b606091505b5091509150816139d35760405162461bcd60e51b81526004016103a690614d13565b805115612b6d57808060200190516139ee9190810190613ea7565b612b6d5760405162461bcd60e51b81526004016103a690614e53565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906118e1575050151592915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b803561164c8161500d565b803561164c81615021565b805161164c81615021565b803561164c8161502a565b803561164c81615033565b60008083601f840112613b7057600080fd5b50813567ffffffffffffffff811115613b8857600080fd5b602083019150836001820283011115613ba057600080fd5b9250929050565b600060808284031215613bb957600080fd5b50919050565b600060808284031215613bd157600080fd5b613bdb6080614f50565b90506000613be98484613b27565b8252506020613bfa84848301613b27565b6020830152506040613c0e84828501613b27565b6040830152506060613c2284828501613b27565b60608301525092915050565b60006101208284031215613bb957600080fd5b60006101208284031215613c5457600080fd5b613c5f610120614f50565b90506000613c6d8484613b48565b8252506020613c7e84848301613b48565b6020830152506040613c9284828501613b48565b6040830152506060613ca684828501613b48565b6060830152506080613cba84828501613b48565b60808301525060a0613cce84828501613b48565b60a08301525060c0613ce284828501613b48565b60c08301525060e0613cf684828501613b48565b60e083015250610100613d0b84828501613b48565b6101008301525092915050565b805161164c8161502a565b600060208284031215613d3557600080fd5b60006118e18484613b27565b60008060408385031215613d5457600080fd5b6000613d608585613b27565b9250506020613d7185828601613b27565b9150509250929050565b600080600080600060a08688031215613d9357600080fd5b6000613d9f8888613b27565b9550506020613db088828901613b27565b9450506040613dc188828901613b48565b9350506060613dd288828901613b48565b9250506080613de388828901613b32565b9150509295509295909350565b60008060008060008060c08789031215613e0957600080fd5b6000613e158989613b27565b9650506020613e2689828a01613b27565b9550506040613e3789828a01613b48565b9450506060613e4889828a01613b48565b9350506080613e5989828a01613b48565b92505060a0613e6a89828a01613b48565b9150509295509295509295565b60008060408385031215613e8a57600080fd5b6000613e968585613b27565b9250506020613d7185828601613b48565b600060208284031215613eb957600080fd5b60006118e18484613b3d565b600060208284031215613ed757600080fd5b60006118e18484613b48565b60008060408385031215613ef657600080fd5b6000613d608585613b48565b600080600060608486031215613f1757600080fd5b6000613f238686613b48565b9350506020613f3486828701613b27565b9250506040613f4586828701613b32565b9150509250925092565b600080600080600080600080610240898b031215613f6c57600080fd5b6000613f788b8b613b48565b9850506020613f898b828c01613b48565b9750506040613f9a8b828c01613b32565b9650506060613fab8b828c01613b48565b9550506080613fbc8b828c01613ba7565b945050610100613fce8b828c01613c2e565b93505061022089013567ffffffffffffffff811115613fec57600080fd5b613ff88b828c01613b5e565b92509250509295985092959890939650565b60006020828403121561401c57600080fd5b60006118e18484613b53565b60006080828403121561403a57600080fd5b60006118e18484613bbf565b6000610120828403121561405957600080fd5b60006118e18484613c41565b60006020828403121561407757600080fd5b60006118e18484613d18565b6000806040838503121561409657600080fd5b60006140a28585613d18565b9250506020613d7185828601613d18565b6140bc81614f89565b82525050565b6140bc6140ce82614f89565b614fec565b6140bc81614f94565b6140bc81614f99565b6140bc6140f182614f99565b614f99565b600061410182614f77565b61410b8185614f7b565b935061411b818560208601614fc0565b9290920192915050565b6140bc81614fb5565b600061413982614f77565b6141438185614f80565b9350614153818560208601614fc0565b61415c81614ffd565b9093019392505050565b6000614173601383614f80565b720d8dec2dca0c2e4c2dae640dad2e6dac2e8c6d606b1b815260200192915050565b60006141a2600683614f80565b6514185d5cd95960d21b815260200192915050565b60006141c4601b83614f80565b7f696e73756666696369656e742073776170206c69717569646974790000000000815260200192915050565b60006141fd601083614f80565b6f1a5b9d985b1a59081a5b9d195c995cdd60821b815260200192915050565b6000614229602683614f80565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000614271601d83614f80565b7f656e7472792070726963652061626f766520746865206d696e696d756d000000815260200192915050565b60006142aa601183614f80565b700c4dee4e4deeecae440dad2e6dac2e8c6d607b1b815260200192915050565b60006142d7601b83614f80565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000614310600e83614f80565b6d1b1bd85b881d1bdbc81cda1bdc9d60921b815260200192915050565b600061433a601583614f80565b740c6ded8d8c2e8cae4c2d85ed8dec2dc40dac2e8c6d605b1b815260200192915050565b600061436b602083614f80565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b60006143a4601383614f80565b72737761702066696c6c20746f6f206c6172676560681b815260200192915050565b60006143d3600f83614f80565b6e0d8cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b60006143fe601c83614f80565b7f736f75726365416d6f756e74206c6172676572207468616e206d617800000000815260200192915050565b6000614437600b83614f80565b6a6c6f616e2065786973747360a81b815260200192915050565b600061445e601283614f80565b7139bab938363ab9903637b0b7103a37b5b2b760711b815260200192915050565b600061448c600e83614f80565b6d1b1bd85b881a185cc8195b99195960921b815260200192915050565b60006144b6600e83614f80565b6d7377617020746f6f206c6172676560901b815260200192915050565b60006144e0600f83614f80565b6e0636f6c6c61746572616c206973203608c1b815260200192915050565b600061450b600e83614f80565b6d1b9bdd08185d5d1a1bdc9a5e995960921b815260200192915050565b6000614535602183614f80565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000614578600c83614f80565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006145a0601783614f80565b7f636f6c6c61746572616c20696e73756666696369656e74000000000000000000815260200192915050565b60006145d9601283614f80565b713ab73432b0b63a343c903837b9b4ba34b7b760711b815260200192915050565b6000614607601583614f80565b746c6f616e506172616d73206e6f742065786973747360581b815260200192915050565b6000614638601483614f80565b7319985b1b189858dac81b9bdd08185b1b1bddd95960621b815260200192915050565b6000614668602e83614f80565b7f6d696e206f72206d617820736f7572636520746f6b656e20616d6f756e74206e81526d1959591cc81d1bc81899481cd95d60921b602082015260400192915050565b60006146b8601383614f80565b721b1bd85b94185c985b5cc8191a5cd8589b1959606a1b815260200192915050565b60006146e7600c83614f80565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b600061470f600d83614f80565b6c696e76616c696420737461746560981b815260200192915050565b6000614738602a83614f80565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b6000614784602183614f80565b7f6c6f616e446174614279746573207265717569726564207769746820657468658152603960f91b602082015260400192915050565b60006147c7601683614f80565b751cddd85c081d1bdbc81b185c99d9481d1bc8199a5b1b60521b815260200192915050565b60006147f9601583614f80565b74696e697469616c4d617267696e20746f6f206c6f7760581b815260200192915050565b600061482a601f83614f80565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160e083019061486784826140b3565b50602082015161487a60208501826140b3565b50604082015161488d60408501826140b3565b5060608201516148a060608501826140b3565b5060808201516148b360808501826140dc565b5060a08201516148c660a08501826140dc565b5060c0820151612b6d60c08501826140dc565b60006148e582876140e5565b6020820191506148f582866140c2565b60148201915061490582856140c2565b60148201915061491582846140e5565b50602001949350505050565b600061169b82846140f6565b6020810161164c82846140b3565b6040810161494982856140b3565b61169b60208301846140b3565b6080810161496482876140b3565b61497160208301866140b3565b61497e60408301856140b3565b610b6260608301846140dc565b6060810161499982866140b3565b6149a660208301856140b3565b6118e160408301846140dc565b608081016149c182876140b3565b6149ce60208301866140b3565b61497e60408301856140dc565b60a081016149e982886140b3565b6149f660208301876140b3565b614a0360408301866140dc565b614a1060608301856140dc565b6110f060808301846140dc565b6101008101614a2c828b6140b3565b614a39602083018a6140b3565b614a4660408301896140dc565b614a5360608301886140dc565b614a6060808301876140dc565b614a6d60a08301866140dc565b614a7a60c08301856140dc565b614a8760e08301846140dc565b9998505050505050505050565b6101208101614aa3828c6140b3565b614ab0602083018b6140b3565b614abd604083018a6140dc565b614aca60608301896140dc565b614ad760808301886140dc565b614ae460a08301876140dc565b614af160c08301866140dc565b614afe60e08301856140dc565b614b0c6101008301846140dc565b9a9950505050505050505050565b60408101614b2882856140b3565b61169b60208301846140dc565b60608101614b4382866140b3565b6149a660208301856140dc565b6020810161164c82846140d3565b6101008101614b6d828b6140dc565b614b7a602083018a6140d3565b614b8760408301896140b3565b614b9460608301886140b3565b614a6060808301876140b3565b6101808101614bb0828f6140dc565b614bbd602083018e6140dc565b614bca604083018d6140dc565b614bd7606083018c6140d3565b614be4608083018b6140dc565b614bf160a083018a6140dc565b614bfe60c08301896140dc565b614c0b60e08301886140dc565b614c196101008301876140dc565b614c276101208301866140dc565b614c356101408301856140b3565b614c436101608301846140b3565b9d9c50505050505050505050505050565b6020810161164c8284614125565b6020808252810161169b818461412e565b6020808252810161164c81614166565b6020808252810161164c81614195565b6020808252810161164c816141b7565b6020808252810161164c816141f0565b6020808252810161164c8161421c565b6020808252810161164c81614264565b6020808252810161164c8161429d565b6020808252810161164c816142ca565b6020808252810161164c81614303565b6020808252810161164c8161432d565b6020808252810161164c8161435e565b6020808252810161164c81614397565b6020808252810161164c816143c6565b6020808252810161164c816143f1565b6020808252810161164c8161442a565b6020808252810161164c81614451565b6020808252810161164c8161447f565b6020808252810161164c816144a9565b6020808252810161164c816144d3565b6020808252810161164c816144fe565b6020808252810161164c81614528565b6020808252810161164c8161456b565b6020808252810161164c81614593565b6020808252810161164c816145cc565b6020808252810161164c816145fa565b6020808252810161164c8161462b565b6020808252810161164c8161465b565b6020808252810161164c816146ab565b6020808252810161164c816146da565b6020808252810161164c81614702565b6020808252810161164c8161472b565b6020808252810161164c81614777565b6020808252810161164c816147ba565b6020808252810161164c816147ec565b6020808252810161164c8161481d565b60e0810161164c8284614856565b6020810161164c82846140dc565b60408101614b2882856140dc565b60608101614b4382866140dc565b60a08101614ee982886140dc565b6149f660208301876140dc565b60c08101614f0482896140dc565b614f1160208301886140dc565b614f1e60408301876140dc565b614f2b60608301866140dc565b614f3860808301856140dc565b614f4560a08301846140dc565b979650505050505050565b60405181810167ffffffffffffffff81118282101715614f6f57600080fd5b604052919050565b5190565b919050565b90815260200190565b600061164c82614fa9565b151590565b90565b6001600160e01b03191690565b6001600160a01b031690565b600061164c82614f89565b60005b83811015614fdb578181015183820152602001614fc3565b83811115612b6d5750506000910152565b600061164c82600061164c82615007565b601f01601f191690565b60601b90565b61501681614f89565b81146114b657600080fd5b61501681614f94565b61501681614f99565b61501681614f9c56fea365627a7a723158209a8d12e965f3506c2f6525444e34694cec46e043cf5ecbd237112664c19b0aa96c6578706572696d656e74616cf564736f6c63430005110040", + "numDeployments": 2, + "solcInputHash": "444414c40f489390e118f5b65a5947cc", + "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCollateral\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestDuration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"collateralToLoanRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"currentMargin\",\"type\":\"uint256\"}],\"name\":\"Borrow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegated\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isActive\",\"type\":\"bool\"}],\"name\":\"DelegatedManagerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeRebatePercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"basisPoint\",\"type\":\"uint256\"}],\"name\":\"EarnReward\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeRebatePercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"basisPoint\",\"type\":\"uint256\"}],\"name\":\"EarnRewardFail\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sourceAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"}],\"name\":\"ExternalSwap\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sourceAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"}],\"name\":\"LoanSwap\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayBorrowingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"interestToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"effectiveInterest\",\"type\":\"uint256\"}],\"name\":\"PayInterestTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayLendingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayTradingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"prevModuleContractAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newModuleContractAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"module\",\"type\":\"bytes32\"}],\"name\":\"ProtocolModuleContractReplaced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"positionSize\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"borrowedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"settlementDate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entryPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entryLeverage\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"currentLeverage\",\"type\":\"uint256\"}],\"name\":\"Trade\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"VaultDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"VaultWithdraw\",\"type\":\"event\"},{\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"constant\":true,\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"affiliateFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliateRewardsHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"affiliateTradingTokenFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliatesReferrerBalances\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliatesUserReferrer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"loanParamsId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"initialMargin\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"manager\",\"type\":\"address\"}],\"internalType\":\"struct MarginTradeStructHelpers.SentAddresses\",\"name\":\"sentAddresses\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestInitialAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"loanTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minEntryPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"loanToCollateralSwapRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"entryLeverage\",\"type\":\"uint256\"}],\"internalType\":\"struct MarginTradeStructHelpers.SentAmounts\",\"name\":\"sentValues\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"loanDataBytes\",\"type\":\"bytes\"}],\"name\":\"borrowOrTradeFromPool\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newCollateral\",\"type\":\"uint256\"}],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowerNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"borrowerOrders\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"lockedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"createdTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expirationTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"borrowingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"delegatedManagers\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feeRebatePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feesController\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"marginAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"}],\"name\":\"getBorrowAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"borrowAmount\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"loanTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"}],\"name\":\"getEstimatedMarginExposure\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"marginAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"}],\"name\":\"getRequiredCollateral\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"collateralAmountRequired\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lenderInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"principalTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"owedPerDay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"owedTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"paidTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"lenderOrders\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"lockedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"createdTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expirationTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"lendingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lendingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lendingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"liquidationIncentivePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loanInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"owedPerDay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"depositTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loanParams\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minInitialMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maintenanceMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"loanPoolToUnderlying\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loans\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"loanParamsId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"pendingTradesId\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"principal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateral\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startRate\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"lockedSOVAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"name\":\"logicTargets\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"maxDisagreement\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"maxSwapSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"minReferralsToPayout\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"pause\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"priceFeeds\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rolloverBaseReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rolloverFlexFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"delegated\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"toggle\",\"type\":\"bool\"}],\"name\":\"setDelegatedManager\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sourceBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sovTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sovrynSwapContractRegistryAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"specialRebates\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"supportedTokens\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"swapsImpl\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"tradingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tradingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tradingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"underlyingToLoanPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"userNotFirstTradeFlag\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"wrbtcToken\",\"outputs\":[{\"internalType\":\"contract IWrbtcERC20\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{\"borrowOrTradeFromPool(bytes32,bytes32,bool,uint256,(address,address,address,address),(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),bytes)\":{\"details\":\"Note: Only callable by loan pools (iTokens). Wrapper to _borrowOrTrade internal function.\",\"params\":{\"initialMargin\":\"The initial amount of margin.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanDataBytes\":\"The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\",\"loanId\":\"The ID of the loan. If 0, start a new loan.\",\"loanParamsId\":\"The ID of the loan parameters.\",\"sentAddresses\":\"The addresses to send tokens: lender, borrower, receiver and manager: lender: must match loan if loanId provided. borrower: must match loan if loanId provided. receiver: receiver of funds (address(0) assumes borrower address). manager: delegated manager of loan unless address(0).\",\"sentValues\":\"The values to send: interestRate: New loan interest rate. newPrincipal: New loan size (borrowAmount + any borrowed interest). interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length). loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans). collateralTokenSent: Total collateralToken deposit. minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\"},\"return\":\"newPrincipal The new loan size.newCollateral The new collateral amount.\"},\"getBorrowAmount(address,address,uint256,uint256,bool)\":{\"details\":\"Basically borrowAmount = collateral / marginAmount * Collateral is something that helps secure a loan. When you borrow money, you agree that your lender can take something and sell it to get their money back if you fail to repay the loan. That's the collateral.\",\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"collateralTokenAmount\":\"The amount of collateral.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanToken\":\"The loan token instance address.\",\"marginAmount\":\"The amount of margin of the trade.\"},\"return\":\"borrowAmount The borrow amount.\"},\"getEstimatedMarginExposure(address,address,uint256,uint256,uint256,uint256)\":{\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"collateralTokenSent\":\"The amount of collateral tokens sent.\",\"interestRate\":\"The interest rate. Percentage w/ 18 decimals.\",\"loanToken\":\"The loan token instance address.\",\"loanTokenSent\":\"The amount of loan tokens sent.\",\"newPrincipal\":\"The updated amount of principal (current debt).\"},\"return\":\"The margin exposure.\"},\"getRequiredCollateral(address,address,uint256,uint256,bool)\":{\"details\":\"Calls internal _getRequiredCollateral and add fees.\",\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanToken\":\"The loan token instance address.\",\"marginAmount\":\"The amount of margin of the trade.\",\"newPrincipal\":\"The updated amount of principal (current debt).\"},\"return\":\"collateralAmountRequired The required collateral.\"},\"initialize(address)\":{\"params\":{\"target\":\"The address of the target contract.\"}},\"isOwner()\":{\"details\":\"Returns true if the caller is the current owner.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"setDelegatedManager(bytes32,address,bool)\":{\"details\":\"Wrapper for _setDelegatedManager internal function.\",\"params\":{\"delegated\":\"The address of the delegated manager.\",\"loanId\":\"The ID of the loan. If 0, start a new loan.\",\"toggle\":\"The flag true/false for the delegated manager.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"Loan Openings contract.\"},\"userdoc\":{\"methods\":{\"borrowOrTradeFromPool(bytes32,bytes32,bool,uint256,(address,address,address,address),(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),bytes)\":{\"notice\":\"Borrow or trade from pool.\"},\"getBorrowAmount(address,address,uint256,uint256,bool)\":{\"notice\":\"Get the borrow amount of a trade loan.\"},\"getEstimatedMarginExposure(address,address,uint256,uint256,uint256,uint256)\":{\"notice\":\"Get the estimated margin exposure. * Margin is the money borrowed from a broker to purchase an investment and is the difference between the total value of investment and the loan amount. Margin trading refers to the practice of using borrowed funds from a broker to trade a financial asset, which forms the collateral for the loan from the broker.\"},\"getRequiredCollateral(address,address,uint256,uint256,bool)\":{\"notice\":\"Get the required collateral.\"},\"initialize(address)\":{\"notice\":\"Set function selectors on target contract.\"},\"setDelegatedManager(bytes32,address,bool)\":{\"notice\":\"Set the delegated manager.\"}},\"notice\":\"This contract code comes from bZx. bZx is a protocol for tokenized margin trading and lending https://bzx.network similar to the dYdX protocol. * This contract contains functions to borrow and trade.\"}},\"settings\":{\"compilationTarget\":{\"contracts/modules/LoanOpenings.sol\":\"LoanOpenings\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":ds-test/=foundry/lib/forge-std/lib/ds-test/src/\",\":forge-std/=foundry/lib/forge-std/src/\"]},\"sources\":{\"contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nlibrary MarginTradeStructHelpers {\\n struct SentAddresses {\\n address lender;\\n address borrower;\\n address receiver;\\n address manager;\\n }\\n\\n struct SentAmounts {\\n uint256 interestRate;\\n uint256 newPrincipal;\\n uint256 interestInitialAmount;\\n uint256 loanTokenSent;\\n uint256 collateralTokenSent;\\n uint256 minEntryPrice;\\n uint256 loanToCollateralSwapRate;\\n uint256 interestDuration;\\n uint256 entryLeverage;\\n }\\n}\\n\",\"keccak256\":\"0xf0612e2c0d13604a67c3d55efe88810c089f0b84ca63bd3ce82c1e09b0938973\"},\"contracts/core/Objects.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./objects/LoanStruct.sol\\\";\\nimport \\\"./objects/LoanParamsStruct.sol\\\";\\nimport \\\"./objects/OrderStruct.sol\\\";\\nimport \\\"./objects/LenderInterestStruct.sol\\\";\\nimport \\\"./objects/LoanInterestStruct.sol\\\";\\n\\n/**\\n * @title Objects contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract inherints and aggregates several structures needed to handle\\n * loans on the protocol.\\n * */\\ncontract Objects is\\n LoanStruct,\\n LoanParamsStruct,\\n OrderStruct,\\n LenderInterestStruct,\\n LoanInterestStruct\\n{\\n\\n}\\n\",\"keccak256\":\"0xa30b8887af813997ebb480f0aa296245f9f3bd728382060059aa087cd9ee332c\"},\"contracts/core/State.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./Objects.sol\\\";\\nimport \\\"../mixins/EnumerableAddressSet.sol\\\";\\nimport \\\"../mixins/EnumerableBytes32Set.sol\\\";\\nimport \\\"../openzeppelin/ReentrancyGuard.sol\\\";\\nimport \\\"../openzeppelin/Ownable.sol\\\";\\nimport \\\"../openzeppelin/SafeMath.sol\\\";\\nimport \\\"../interfaces/IWrbtcERC20.sol\\\";\\nimport \\\"../reentrancy/SharedReentrancyGuard.sol\\\";\\n\\n/**\\n * @title State contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage values of the Protocol.\\n * */\\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\\n using SafeMath for uint256;\\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\\n\\n /// Handles asset reference price lookups.\\n address public priceFeeds;\\n\\n /// Handles asset swaps using dex liquidity.\\n address public swapsImpl;\\n\\n /// Contract registry address of the Sovryn swap network.\\n address public sovrynSwapContractRegistryAddress;\\n\\n /// Implementations of protocol functions.\\n mapping(bytes4 => address) public logicTargets;\\n\\n /// Loans: loanId => Loan\\n mapping(bytes32 => Loan) public loans;\\n\\n /// Loan parameters: loanParamsId => LoanParams\\n mapping(bytes32 => LoanParams) public loanParams;\\n\\n /// lender => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\\n\\n /// borrower => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\\n\\n /// loanId => delegated => approved\\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\\n\\n /**\\n *** Interest ***\\n **/\\n\\n /// lender => loanToken => LenderInterest object\\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\\n\\n /// loanId => LoanInterest object\\n mapping(bytes32 => LoanInterest) public loanInterest;\\n\\n /**\\n *** Internals ***\\n **/\\n\\n /// Implementations set.\\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\\n\\n /// Active loans set.\\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\\n\\n /// Lender loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\\n\\n /// Borrow loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\\n\\n /// User loan params set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\\n\\n /// Address controlling fee withdrawals.\\n address public feesController;\\n\\n /// 10% fee /// Fee taken from lender interest payments.\\n uint256 public lendingFeePercent = 10**19;\\n\\n /// Total interest fees received and not withdrawn per asset.\\n mapping(address => uint256) public lendingFeeTokensHeld;\\n\\n /// Total interest fees withdraw per asset.\\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\\n mapping(address => uint256) public lendingFeeTokensPaid;\\n\\n /// 0.15% fee /// Fee paid for each trade.\\n uint256 public tradingFeePercent = 15 * 10**16;\\n\\n /// Total trading fees received and not withdrawn per asset.\\n mapping(address => uint256) public tradingFeeTokensHeld;\\n\\n /// Total trading fees withdraw per asset\\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\\n mapping(address => uint256) public tradingFeeTokensPaid;\\n\\n /// 0.09% fee /// Origination fee paid for each loan.\\n uint256 public borrowingFeePercent = 9 * 10**16;\\n\\n /// Total borrowing fees received and not withdrawn per asset.\\n mapping(address => uint256) public borrowingFeeTokensHeld;\\n\\n /// Total borrowing fees withdraw per asset.\\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\\n mapping(address => uint256) public borrowingFeeTokensPaid;\\n\\n /// Current protocol token deposit balance.\\n uint256 public protocolTokenHeld;\\n\\n /// Lifetime total payout of protocol token.\\n uint256 public protocolTokenPaid;\\n\\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\\n uint256 public affiliateFeePercent = 5 * 10**18;\\n\\n /// 5% collateral discount /// Discount on collateral for liquidators.\\n uint256 public liquidationIncentivePercent = 5 * 10**18;\\n\\n /// loanPool => underlying\\n mapping(address => address) public loanPoolToUnderlying;\\n\\n /// underlying => loanPool\\n mapping(address => address) public underlyingToLoanPool;\\n\\n /// Loan pools set.\\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\\n\\n /// Supported tokens for swaps.\\n mapping(address => bool) public supportedTokens;\\n\\n /// % disagreement between swap rate and reference rate.\\n uint256 public maxDisagreement = 5 * 10**18;\\n\\n /// Used as buffer for swap source amount estimations.\\n uint256 public sourceBuffer = 10000;\\n\\n /// Maximum support swap size in rBTC\\n uint256 public maxSwapSize = 50 ether;\\n\\n /// Nonce per borrower. Used for loan id creation.\\n mapping(address => uint256) public borrowerNonce;\\n\\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\\n uint256 public rolloverBaseReward = 16800000000000;\\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\\n\\n IWrbtcERC20 public wrbtcToken;\\n address public protocolTokenAddress;\\n\\n /// 50% fee rebate\\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\\n uint256 public feeRebatePercent = 50 * 10**18;\\n\\n address public admin;\\n\\n /// For modules interaction.\\n address public protocolAddress;\\n\\n /**\\n *** Affiliates ***\\n **/\\n\\n /// The flag is set on the user's first trade.\\n mapping(address => bool) public userNotFirstTradeFlag;\\n\\n /// User => referrer (affiliate).\\n mapping(address => address) public affiliatesUserReferrer;\\n\\n /// List of referral addresses affiliated to the referrer.\\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\\n\\n /// @dev Referral threshold for paying out to the referrer.\\n /// The referrer reward is being accumulated and locked until the threshold is passed.\\n uint256 public minReferralsToPayout = 3;\\n\\n /// @dev Total affiliate SOV rewards that held in the protocol\\n /// (Because the minimum referrals is less than the rule)\\n mapping(address => uint256) public affiliateRewardsHeld;\\n\\n /// @dev For affiliates SOV Bonus proccess.\\n address public sovTokenAddress;\\n address public lockedSOVAddress;\\n\\n /// @dev 20% fee share of trading token fee.\\n /// Fee share of trading token fee for affiliate program.\\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\\n\\n /// @dev Addresses of tokens in which commissions were paid to referrers.\\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\\n\\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\\n\\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\\n bool public pause; //Flag to pause all protocol modules\\n\\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\\n\\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\\n uint256 internal tradingRebateRewardsBasisPoint;\\n\\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\\n /// Will be used in internal swap.\\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\\n\\n address internal pauser;\\n\\n /**\\n * @notice Add signature and target to storage.\\n * @dev Protocol is a proxy and requires a way to add every\\n * module function dynamically during deployment.\\n * */\\n function _setTarget(bytes4 sig, address target) internal {\\n logicTargets[sig] = target;\\n\\n if (target != address(0)) {\\n logicTargetsSet.addBytes32(bytes32(sig));\\n } else {\\n logicTargetsSet.removeBytes32(bytes32(sig));\\n }\\n }\\n\\n modifier onlyAdminOrOwner() {\\n require(isOwner() || admin == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n\\n modifier onlyPauserOrOwner() {\\n require(isOwner() || pauser == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0xf8dfc02f3dc790c73b390a69898d0281c4473487bc91fec1f28fbebceacd3b3c\"},\"contracts/core/objects/LenderInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Lender Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Lender Interest.\\n * */\\ncontract LenderInterestStruct {\\n struct LenderInterest {\\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\\n uint256 paidTotal; /// Total interest paid so far for asset.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0x6583baadddded384836cec469980e7973ec09310ae505b4a2ec67fb7bc19e452\"},\"contracts/core/objects/LoanInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Interest.\\n * */\\ncontract LoanInterestStruct {\\n struct LoanInterest {\\n uint256 owedPerDay; /// Interest owed per day for loan.\\n uint256 depositTotal; /// Total escrowed interest for loan.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0xd9034c6adb1b72e1593589dca024dc4730a1ee8bf6b2dca9d22283f2e7159590\"},\"contracts/core/objects/LoanParamsStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Parameters.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Parameters.\\n * */\\ncontract LoanParamsStruct {\\n struct LoanParams {\\n /// @dev ID of loan params object.\\n bytes32 id;\\n /// @dev If false, this object has been disabled by the owner and can't\\n /// be used for future loans.\\n bool active;\\n /// @dev Owner of this object.\\n address owner;\\n /// @dev The token being loaned.\\n address loanToken;\\n /// @dev The required collateral token.\\n address collateralToken;\\n /// @dev The minimum allowed initial margin.\\n uint256 minInitialMargin;\\n /// @dev An unhealthy loan when current margin is at or below this value.\\n uint256 maintenanceMargin;\\n /// @dev The maximum term for new loans (0 means there's no max term).\\n uint256 maxLoanTerm;\\n }\\n}\\n\",\"keccak256\":\"0xe15aa97713521da7f501e5225af9d92cf34bd68d286dbfed86aa75aabb323945\"},\"contracts/core/objects/LoanStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Object.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Object.\\n * */\\ncontract LoanStruct {\\n struct Loan {\\n bytes32 id; /// ID of the loan.\\n bytes32 loanParamsId; /// The linked loan params ID.\\n bytes32 pendingTradesId; /// The linked pending trades ID.\\n bool active; /// If false, the loan has been fully closed.\\n uint256 principal; /// Total borrowed amount outstanding.\\n uint256 collateral; /// Total collateral escrowed for the loan.\\n uint256 startTimestamp; /// Loan start time.\\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\\n uint256 startMargin; /// Initial margin when the loan opened.\\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\\n address borrower; /// Borrower of this loan.\\n address lender; /// Lender of this loan.\\n }\\n}\\n\",\"keccak256\":\"0x7d05c3096a86d5892e4e72f3a01a5a806f13a5ac90ca6339c611e75c603637b4\"},\"contracts/core/objects/OrderStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Order.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Order.\\n * */\\ncontract OrderStruct {\\n struct Order {\\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\\n uint256 interestRate; /// Interest rate defined by the creator of this order.\\n uint256 minLoanTerm; /// Minimum loan term allowed.\\n uint256 maxLoanTerm; /// Maximum loan term allowed.\\n uint256 createdTimestamp; /// Timestamp when this order was created.\\n uint256 expirationTimestamp; /// Timestamp when this order expires.\\n }\\n}\\n\",\"keccak256\":\"0xcc053c5da34a5927041162259bf856ba913f3524ca03e63ad0c5877777d17e0f\"},\"contracts/events/AffiliatesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\ncontract AffiliatesEvents is ModulesCommonEvents {\\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\\n\\n event SetAffiliatesReferrerFail(\\n address indexed user,\\n address indexed referrer,\\n bool alreadySet,\\n bool userNotFirstTrade\\n );\\n\\n event SetUserNotFirstTradeFlag(address indexed user);\\n\\n event PayTradingFeeToAffiliate(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n bool indexed isHeld,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountPaid\\n );\\n\\n event PayTradingFeeToAffiliateFail(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountTryingToPaid\\n );\\n\\n event WithdrawAffiliatesReferrerTokenFees(\\n address indexed referrer,\\n address indexed receiver,\\n address indexed tokenAddress,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xf72cf23e90db3c49589ddc4e1796680ebfb69a9b146db89f9b61f5fcf6dd95ba\"},\"contracts/events/FeesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Fees Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for fee payments.\\n * */\\ncontract FeesEvents {\\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\\n\\n event PayTradingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event PayBorrowingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event EarnReward(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n\\n event EarnRewardFail(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n}\\n\",\"keccak256\":\"0xe69bf53e15479be5fde1cbaadaf0c004ee038e8a6a37c99f7769bf5d8387015f\"},\"contracts/events/LoanClosingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Closing Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan closing operations.\\n * */\\ncontract LoanClosingsEvents is ModulesCommonEvents {\\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\\n event CloseWithDeposit(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address closer,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\\n event CloseWithSwap(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n address closer,\\n uint256 positionCloseSize,\\n uint256 loanCloseAmount,\\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\\n event Liquidate(\\n address indexed user,\\n address indexed liquidator,\\n bytes32 indexed loanId,\\n address lender,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n event Rollover(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n uint256 principal,\\n uint256 collateral,\\n uint256 endTimestamp,\\n address rewardReceiver,\\n uint256 reward\\n );\\n\\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\\n}\\n\",\"keccak256\":\"0x1ea325b9a213012865a52f38941ce6c1e8c29dce919215b5bdcc63a8a5980be1\"},\"contracts/events/LoanMaintenanceEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Maintenance Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan maintenance operations.\\n * */\\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\\n}\\n\",\"keccak256\":\"0xdee5098b947c22bcef6e38ecaf62bae6941572d1c245d2065ad41ea4f494c61d\"},\"contracts/events/LoanOpeningsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Openings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan openings operations.\\n * */\\ncontract LoanOpeningsEvents is ModulesCommonEvents {\\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\\n event Borrow(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 newCollateral,\\n uint256 interestRate,\\n uint256 interestDuration,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\\n event Trade(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n uint256 positionSize,\\n uint256 borrowedAmount,\\n uint256 interestRate,\\n uint256 settlementDate,\\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\\n uint256 entryLeverage,\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\\n event DelegatedManagerSet(\\n bytes32 indexed loanId,\\n address indexed delegator,\\n address indexed delegated,\\n bool isActive\\n );\\n}\\n\",\"keccak256\":\"0x585710ce6c570c6dbd1b8daf43b63a54b1d60ad01ee1dc3cae407d74d78f3093\"},\"contracts/events/LoanSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan settings operations.\\n * */\\ncontract LoanSettingsEvents is ModulesCommonEvents {\\n event LoanParamsSetup(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\\n\\n event LoanParamsDisabled(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\\n}\\n\",\"keccak256\":\"0xae9c49678a7bc02c2283648939c474c8bfd33781506e05c635c8334c5bf8682f\"},\"contracts/events/ModulesCommonEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\n/**\\n * @title The common events for all modules\\n * @notice This contract contains the events which will be used by all modules\\n **/\\n\\ncontract ModulesCommonEvents {\\n event ProtocolModuleContractReplaced(\\n address indexed prevModuleContractAddress,\\n address indexed newModuleContractAddress,\\n bytes32 indexed module\\n );\\n}\\n\",\"keccak256\":\"0xb07af42d7e6b0fe983889b883691b662a58d2ef8d75b3f32f17faff1871c8b8f\"},\"contracts/events/ProtocolSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title The Protocol Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for protocol settings operations.\\n * */\\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetLoanPool(\\n address indexed sender,\\n address indexed loanPool,\\n address indexed underlying\\n );\\n\\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\\n\\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateTradingTokenFeePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetLiquidationIncentivePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetFeesController(\\n address indexed sender,\\n address indexed oldController,\\n address indexed newController\\n );\\n\\n event SetWrbtcToken(\\n address indexed sender,\\n address indexed oldWethToken,\\n address indexed newWethToken\\n );\\n\\n event SetSovrynSwapContractRegistryAddress(\\n address indexed sender,\\n address indexed oldSovrynSwapContractRegistryAddress,\\n address indexed newSovrynSwapContractRegistryAddress\\n );\\n\\n event SetProtocolTokenAddress(\\n address indexed sender,\\n address indexed oldProtocolToken,\\n address indexed newProtocolToken\\n );\\n\\n event WithdrawFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 lendingAmount,\\n uint256 tradingAmount,\\n uint256 borrowingAmount,\\n uint256 wRBTCConverted\\n );\\n\\n event WithdrawLendingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawTradingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawBorrowingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetRebatePercent(\\n address indexed sender,\\n uint256 oldRebatePercent,\\n uint256 newRebatePercent\\n );\\n\\n event SetSpecialRebates(\\n address indexed sender,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 oldSpecialRebatesPercent,\\n uint256 newSpecialRebatesPercent\\n );\\n\\n event SetProtocolAddress(\\n address indexed sender,\\n address indexed oldProtocol,\\n address indexed newProtocol\\n );\\n\\n event SetMinReferralsToPayoutAffiliates(\\n address indexed sender,\\n uint256 oldMinReferrals,\\n uint256 newMinReferrals\\n );\\n\\n event SetSOVTokenAddress(\\n address indexed sender,\\n address indexed oldTokenAddress,\\n address indexed newTokenAddress\\n );\\n\\n event SetLockedSOVAddress(\\n address indexed sender,\\n address indexed oldAddress,\\n address indexed newAddress\\n );\\n\\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\\n\\n event SetTradingRebateRewardsBasisPoint(\\n address indexed sender,\\n uint256 oldBasisPoint,\\n uint256 newBasisPoint\\n );\\n\\n event SetRolloverFlexFeePercent(\\n address indexed sender,\\n uint256 oldRolloverFlexFeePercent,\\n uint256 newRolloverFlexFeePercent\\n );\\n\\n event SetDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event RemoveDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\\n\\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\\n}\\n\",\"keccak256\":\"0x20ca66a2c53669aa33379bf5233e3bcdddbba3504cd430a0143f0ee3ce1c2641\"},\"contracts/events/SwapsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Swaps Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for swap operations.\\n * */\\ncontract SwapsEvents is ModulesCommonEvents {\\n event LoanSwap(\\n bytes32 indexed loanId,\\n address indexed sourceToken,\\n address indexed destToken,\\n address borrower,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n\\n event ExternalSwap(\\n address indexed user,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n}\\n\",\"keccak256\":\"0x0a1cd289076675980b916941ed923146160d34a8669fc3fb4a06610f285dfbd1\"},\"contracts/feeds/IPriceFeeds.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface IPriceFeeds {\\n function queryRate(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 rate, uint256 precision);\\n\\n function queryPrecision(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 precision);\\n\\n function queryReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount\\n ) external view returns (uint256 destAmount);\\n\\n function checkPriceDisagreement(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount,\\n uint256 destAmount,\\n uint256 maxSlippage\\n ) external view returns (uint256 sourceToDestSwapRate);\\n\\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\\n\\n function getMaxDrawdown(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (uint256);\\n\\n function getCurrentMarginAndCollateralSize(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\\n\\n function getCurrentMargin(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\\n\\n function shouldLiquidate(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (bool);\\n\\n function getFastGasPrice(address payToken) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x2e2c2b393336efedb97659a2fc21c8dfb75b70e15d2422a3bcbf7ebd5fc83c82\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/interfaces/ISovryn.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\npragma experimental ABIEncoderV2;\\n//TODO: stored in ./interfaces only while brownie isn't removed\\n//TODO: move to contracts/interfaces after with brownie is removed\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/ProtocolSettingsEvents.sol\\\";\\nimport \\\"../events/LoanSettingsEvents.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../events/LoanMaintenanceEvents.sol\\\";\\nimport \\\"../events/LoanClosingsEvents.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../events/AffiliatesEvents.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\ncontract ISovryn is\\n State,\\n ProtocolSettingsEvents,\\n LoanSettingsEvents,\\n LoanOpeningsEvents,\\n LoanMaintenanceEvents,\\n LoanClosingsEvents,\\n SwapsEvents,\\n AffiliatesEvents,\\n FeesEvents\\n{\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n ////// Protocol //////\\n\\n function replaceContract(address target) external;\\n\\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\\n\\n function getTarget(string calldata sig) external view returns (address);\\n\\n ////// Protocol Settings //////\\n\\n function setSovrynProtocolAddress(address newProtocolAddress) external;\\n\\n function setSOVTokenAddress(address newSovTokenAddress) external;\\n\\n function setLockedSOVAddress(address newSOVLockedAddress) external;\\n\\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\\n\\n function setPriceFeedContract(address newContract) external;\\n\\n function setSwapsImplContract(address newContract) external;\\n\\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\\n\\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\\n\\n function setLendingFeePercent(uint256 newValue) external;\\n\\n function setTradingFeePercent(uint256 newValue) external;\\n\\n function setBorrowingFeePercent(uint256 newValue) external;\\n\\n function setSwapExternalFeePercent(uint256 newValue) external;\\n\\n function setAffiliateFeePercent(uint256 newValue) external;\\n\\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\\n\\n function setLiquidationIncentivePercent(uint256 newAmount) external;\\n\\n function setMaxDisagreement(uint256 newAmount) external;\\n\\n function setSourceBuffer(uint256 newAmount) external;\\n\\n function setMaxSwapSize(uint256 newAmount) external;\\n\\n function setFeesController(address newController) external;\\n\\n function withdrawFees(address[] calldata tokens, address receiver)\\n external\\n returns (uint256 totalWRBTCWithdrawn);\\n\\n function withdrawLendingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawTradingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawBorrowingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawProtocolToken(address receiver, uint256 amount)\\n external\\n returns (address, bool);\\n\\n function depositProtocolToken(uint256 amount) external;\\n\\n function getLoanPoolsList(uint256 start, uint256 count)\\n external\\n view\\n returns (bytes32[] memory);\\n\\n function isLoanPool(address loanPool) external view returns (bool);\\n\\n function setWrbtcToken(address wrbtcTokenAddress) external;\\n\\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\\n\\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\\n\\n function setRolloverBaseReward(uint256 transactionCost) external;\\n\\n function setRebatePercent(uint256 rebatePercent) external;\\n\\n function setSpecialRebates(\\n address sourceToken,\\n address destToken,\\n uint256 specialRebatesPercent\\n ) external;\\n\\n function getSpecialRebates(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 specialRebatesPercent);\\n\\n function togglePaused(bool paused) external;\\n\\n function isProtocolPaused() external view returns (bool);\\n\\n ////// SwapsImplSovrynSwapModule //////\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (address);\\n\\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\\n\\n function swapsImplExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function swapsImplExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256 expectedReturn);\\n\\n ////// Loan Settings //////\\n\\n function setupLoanParams(LoanParams[] calldata loanParamsList)\\n external\\n returns (bytes32[] memory loanParamsIdList);\\n\\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\\n\\n function getLoanParams(bytes32[] calldata loanParamsIdList)\\n external\\n view\\n returns (LoanParams[] memory loanParamsList);\\n\\n function getLoanParamsList(\\n address owner,\\n uint256 start,\\n uint256 count\\n ) external view returns (bytes32[] memory loanParamsList);\\n\\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\\n\\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\\n\\n ////// Loan Openings //////\\n\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId, // if 0, start a new loan\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n // lender: must match loan if loanId provided\\n // borrower: must match loan if loanId provided\\n // receiver: receiver of funds (address(0) assumes borrower address)\\n // manager: delegated manager of loan unless address(0)\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n // newRate: new loan interest rate\\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\\n // collateralTokenReceived: total collateralToken deposit\\n bytes calldata loanDataBytes\\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\\n\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external;\\n\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256);\\n\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 collateralAmountRequired);\\n\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 borrowAmount);\\n\\n ////// Loan Closings //////\\n\\n function liquidate(\\n bytes32 loanId,\\n address receiver,\\n uint256 closeAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 seizedAmount,\\n address seizedToken\\n );\\n\\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\\n\\n function closeWithDeposit(\\n bytes32 loanId,\\n address receiver,\\n uint256 depositAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n function closeWithSwap(\\n bytes32 loanId,\\n address receiver,\\n uint256 swapAmount, // denominated in collateralToken\\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\\n bytes calldata loanDataBytes\\n )\\n external\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n ////// Loan Maintenance //////\\n\\n function depositCollateral(\\n bytes32 loanId,\\n uint256 depositAmount // must match msg.value if ether is sent\\n ) external payable;\\n\\n function withdrawCollateral(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 actualWithdrawAmount);\\n\\n function withdrawAccruedInterest(address loanToken) external;\\n\\n function getLenderInterestData(address lender, address loanToken)\\n external\\n view\\n returns (\\n uint256 interestPaid,\\n uint256 interestPaidDate,\\n uint256 interestOwedPerDay,\\n uint256 interestUnPaid,\\n uint256 interestFeePercent,\\n uint256 principalTotal\\n );\\n\\n function getLoanInterestData(bytes32 loanId)\\n external\\n view\\n returns (\\n address loanToken,\\n uint256 interestOwedPerDay,\\n uint256 interestDepositTotal,\\n uint256 interestDepositRemaining\\n );\\n\\n struct LoanReturnData {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; // collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n }\\n\\n struct LoanReturnDataV2 {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n address borrower;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; /// collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n uint256 creationTimestamp;\\n }\\n\\n function getUserLoans(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getUserLoansV2(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\\n\\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\\n\\n function getActiveLoans(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getActiveLoansV2(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function extendLoanDuration(\\n bytes32 loanId,\\n uint256 depositAmount,\\n bool useCollateral,\\n bytes calldata /// loanDataBytes, for future use.\\n ) external returns (uint256 secondsExtended);\\n\\n function reduceLoanDuration(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 secondsReduced);\\n\\n ////// Swaps External //////\\n function swapExternal(\\n address sourceToken,\\n address destToken,\\n address receiver,\\n address returnToSender,\\n uint256 sourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n uint256 minReturn,\\n bytes calldata swapData\\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\\n\\n function getSwapExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function checkPriceDivergence(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount,\\n uint256 minReturn\\n ) public view;\\n\\n ////// Affiliates Module //////\\n\\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\\n\\n function setUserNotFirstTradeFlag(address user) external;\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address referrer,\\n address trader,\\n address token,\\n uint256 tradingFeeTokenBaseAmount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n\\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\\n\\n function getReferralsList(address referrer) external view returns (address[] memory refList);\\n\\n function getAffiliatesReferrerBalances(address referrer)\\n external\\n view\\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\\n\\n function getAffiliatesReferrerTokensList(address referrer)\\n external\\n view\\n returns (address[] memory tokensList);\\n\\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\\n external\\n view\\n returns (uint256);\\n\\n function withdrawAffiliatesReferrerTokenFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external;\\n\\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\\n\\n function getProtocolAddress() external view returns (address);\\n\\n function getSovTokenAddress() external view returns (address);\\n\\n function getLockedSOVAddress() external view returns (address);\\n\\n function getFeeRebatePercent() external view returns (uint256);\\n\\n function getMinReferralsToPayout() external view returns (uint256);\\n\\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\\n\\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\\n\\n function getAffiliateTradingTokenFeePercent()\\n external\\n view\\n returns (uint256 affiliateTradingTokenFeePercent);\\n\\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\\n external\\n view\\n returns (uint256 rbtcTotalAmount);\\n\\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\\n\\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\\n\\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\\n\\n function getDedicatedSOVRebate() external view returns (uint256);\\n\\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\\n\\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external\\n view\\n returns (IERC20[] memory);\\n\\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\\n\\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external;\\n\\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\\n external\\n view\\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\\n\\n function setAdmin(address newAdmin) external;\\n\\n function getAdmin() external view returns (address);\\n\\n function setPauser(address newPauser) external;\\n\\n function getPauser() external view returns (address);\\n}\\n\",\"keccak256\":\"0x4e470e1fe1719c2c58b0e44aedce3ee6a21191063b533ccb71c9219a192e8884\"},\"contracts/interfaces/IWrbtc.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ninterface IWrbtc {\\n function deposit() external payable;\\n\\n function withdraw(uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x20fdfe4b5e32fd7f863b3fa128e3c80bd4ccf090a4ffba56186ef3b7f2a80492\"},\"contracts/interfaces/IWrbtcERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./IWrbtc.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\n\\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\\n\",\"keccak256\":\"0x7301a8c8ca7aa016ec94268a16d07366875f2e406442e929968dd745b1ee5be5\"},\"contracts/mixins/EnumerableAddressSet.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Based on Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * As of v2.5.0, only `address` sets are supported.\\n *\\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\\n *\\n * _Available since v2.5.0._\\n */\\nlibrary EnumerableAddressSet {\\n struct AddressSet {\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(address => uint256) index;\\n address[] values;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n * Returns false if the value was already in the set.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n * Returns false if the value was not present in the set.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n // If the element we're deleting is the last one, we can just remove it without doing a swap\\n if (lastIndex != toDeleteIndex) {\\n address lastValue = set.values[lastIndex];\\n\\n // Move the last value to the index where the deleted value is\\n set.values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n // Delete the index entry for the deleted value\\n delete set.index[value];\\n\\n // Delete the old entry for the moved value\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns an array with all values in the set. O(N).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\\n address[] memory output = new address[](set.values.length);\\n for (uint256 i; i < set.values.length; i++) {\\n output[i] = set.values[i];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n \\n * @param start start index of chunk\\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\\n */\\n function enumerateChunk(\\n AddressSet storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (address[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = (set.values.length < end || count == 0) ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new address[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns the number of elements on the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /** @dev Returns the element stored at position `index` in the set. O(1).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xea6fba941ec8502aa11a7ab37e74b917d0dc47bb254e359a2870a87ef97d9872\"},\"contracts/mixins/EnumerableBytes32Set.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title Library for managing loan sets.\\n *\\n * @notice Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\\n * */\\nlibrary EnumerableBytes32Set {\\n struct Bytes32Set {\\n /// Position of the value in the `values` array, plus 1 because index 0\\n /// means a value is not in the set.\\n mapping(bytes32 => uint256) index;\\n bytes32[] values;\\n }\\n\\n /**\\n * @notice Add an address value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return addBytes32(set, value);\\n }\\n\\n /**\\n * @notice Add a value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The new value to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Remove an address value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to remove.\\n *\\n * @return False if the address was not present in the set.\\n */\\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return removeBytes32(set, value);\\n }\\n\\n /**\\n * @notice Remove a value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The value to remove.\\n *\\n * @return False if the value was not present in the set.\\n */\\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n /// If the element we're deleting is the last one,\\n /// we can just remove it without doing a swap.\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set.values[lastIndex];\\n\\n /// Move the last value to the index where the deleted value is.\\n set.values[toDeleteIndex] = lastValue;\\n\\n /// Update the index for the moved value.\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n /// Delete the index entry for the deleted value.\\n delete set.index[value];\\n\\n /// Delete the old entry for the moved value.\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Find out whether a value exists in the set.\\n *\\n * @param set The set of values.\\n * @param value The value to find.\\n *\\n * @return True if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function containsAddress(Bytes32Set storage set, address addrvalue)\\n internal\\n view\\n returns (bool)\\n {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @notice Get all set values.\\n *\\n * @param set The set of values.\\n * @param start The offset of the returning set.\\n * @param count The limit of number of values to return.\\n *\\n * @return An array with all values in the set. O(N).\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(\\n Bytes32Set storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (bytes32[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = set.values.length < end ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new bytes32[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @notice Get the legth of the set.\\n *\\n * @param set The set of values.\\n *\\n * @return the number of elements on the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /**\\n * @notice Get an item from the set by its index.\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n *\\n * @param set The set of values.\\n * @param index The index of the value to return.\\n *\\n * @return the element stored at position `index` in the set. O(1).\\n */\\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xa2801a585c566e07f21c1ebccd0cd0447dd5fd9fe6c1ff2b58d4d979d88a6db0\"},\"contracts/mixins/FeesHelper.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../modules/interfaces/ProtocolAffiliatesInterface.sol\\\";\\nimport \\\"../interfaces/ISovryn.sol\\\";\\nimport \\\"../core/objects/LoanParamsStruct.sol\\\";\\n\\n/**\\n * @title The Fees Helper contract.\\n *\\n * This contract calculates and pays lending/borrow fees and rewards.\\n * */\\ncontract FeesHelper is State, FeesEvents {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Calculate trading fee.\\n * @param feeTokenAmount The amount of tokens to trade.\\n * @return The fee of the trade.\\n * */\\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\\n }\\n\\n /**\\n * @notice Calculate swap external fee.\\n * @param feeTokenAmount The amount of token to swap.\\n * @return The fee of the swap.\\n */\\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\\n }\\n\\n /*\\n\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\\n\\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n\\t\\tuint256 collateralAmountRequired =\\n\\t\\t\\tfeeTokenAmount.mul(10**20).divCeil(\\n\\t\\t\\t\\t10**20 - tradingFeePercent // never will overflow\\n\\t\\t\\t);\\n\\t\\treturn collateralAmountRequired.sub(feeTokenAmount);\\n\\t}*/\\n\\n /**\\n * @notice Calculate the loan origination fee.\\n * @param feeTokenAmount The amount of tokens to borrow.\\n * @return The fee of the loan.\\n * */\\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\\n /*\\n\\t\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t\\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\\n\\t\\tuint256 collateralAmountRequired =\\n\\t\\t\\tfeeTokenAmount.mul(10**20).divCeil(\\n\\t\\t\\t\\t10**20 - borrowingFeePercent // never will overflow\\n\\t\\t\\t);\\n\\t\\treturn collateralAmountRequired.sub(feeTokenAmount);*/\\n }\\n\\n /**\\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\\n *\\n * @param referrer The affiliate referrer address to send the reward to.\\n * @param trader The account that performs this trade.\\n * @param feeToken The address of the token in which the trading fee is paid.\\n * @param tradingFee The amount of tokens accrued as fees on the trading.\\n *\\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\\n * */\\n function _payTradingFeeToAffiliate(\\n address referrer,\\n address trader,\\n address feeToken,\\n uint256 tradingFee\\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\\n address(this)\\n )\\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\\n }\\n\\n /**\\n * @notice Settle the trading fee and pay the token reward to the user.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associated loan - used for logging only.\\n * @param feeToken The address of the token in which the trading fee is paid.\\n * @param tradingFee The amount of tokens accrued as fees on the trading.\\n * */\\n function _payTradingFee(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 tradingFee\\n ) internal {\\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\\n if (tradingFee != 0) {\\n if (affiliatesUserReferrer[user] != address(0)) {\\n _payTradingFeeToAffiliate(\\n affiliatesUserReferrer[user],\\n user,\\n feeToken,\\n protocolTradingFee\\n );\\n protocolTradingFee = (\\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\\n )\\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\\n }\\n\\n /// Increase the storage variable keeping track of the accumulated fees.\\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\\n protocolTradingFee\\n );\\n\\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\\n\\n /// Pay the token reward to the user.\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\\n }\\n }\\n\\n /**\\n * @notice Settle the borrowing fee and pay the token reward to the user.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associated loan - used for logging only.\\n * @param feeToken The address of the token in which the borrowig fee is paid.\\n * @param borrowingFee The height of the fee.\\n * */\\n function _payBorrowingFee(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 borrowingFee\\n ) internal {\\n if (borrowingFee != 0) {\\n /// Increase the storage variable keeping track of the accumulated fees.\\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\\n\\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\\n\\n /// Pay the token reward to the user.\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\\n }\\n }\\n\\n /**\\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\\n * @param user The address to send the reward to.\\n * @param feeToken The address of the token in which the lending fee is paid.\\n * @param lendingFee The height of the fee.\\n * */\\n function _payLendingFee(\\n address user,\\n address feeToken,\\n uint256 lendingFee\\n ) internal {\\n if (lendingFee != 0) {\\n /// Increase the storage variable keeping track of the accumulated fees.\\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\\n\\n emit PayLendingFee(user, feeToken, lendingFee);\\n\\n //// NOTE: Lenders do not receive a fee reward ////\\n }\\n }\\n\\n /// Settle and pay borrowers based on the fees generated by their interest payments.\\n function _settleFeeRewardForInterestExpense(\\n LoanInterest storage loanInterestLocal,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n address user,\\n uint256 interestTime\\n ) internal {\\n /// This represents the fee generated by a borrower's interest payment.\\n uint256 interestExpenseFee =\\n interestTime\\n .sub(loanInterestLocal.updatedTimestamp)\\n .mul(loanInterestLocal.owedPerDay)\\n .mul(lendingFeePercent)\\n .div(1 days * 10**20);\\n\\n loanInterestLocal.updatedTimestamp = interestTime;\\n\\n if (interestExpenseFee != 0) {\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\\n }\\n }\\n\\n /**\\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associeated loan - used for logging only.\\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\\n * @param feeAmount The height of the fee.\\n * */\\n function _payFeeReward(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 feeAmount\\n ) internal {\\n uint256 rewardAmount;\\n uint256 _feeRebatePercent = feeRebatePercent;\\n address _priceFeeds = priceFeeds;\\n\\n if (specialRebates[feeToken][feeTokenPair] > 0) {\\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\\n }\\n\\n /// Note: this should be refactored.\\n /// Calculate the reward amount, querying the price feed.\\n (bool success, bytes memory data) =\\n _priceFeeds.staticcall(\\n abi.encodeWithSelector(\\n IPriceFeeds(_priceFeeds).queryReturn.selector,\\n feeToken,\\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\\n feeAmount.mul(_feeRebatePercent).div(10**20)\\n )\\n );\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n if eq(success, 1) {\\n rewardAmount := mload(add(data, 32))\\n }\\n }\\n\\n // Check the dedicated SOV that is used to pay trading rebate rewards\\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\\n\\n (bool success, ) =\\n lockedSOVAddress.call(\\n abi.encodeWithSignature(\\n \\\"deposit(address,uint256,uint256)\\\",\\n user,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n )\\n );\\n\\n if (success) {\\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\\n\\n emit EarnReward(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n } else {\\n emit EarnRewardFail(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n }\\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\\n emit EarnRewardFail(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0x9094bce5eab7109594a795982a779641c951c2617a618f5eab1f651b3b945077\"},\"contracts/mixins/InterestUser.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../mixins/VaultController.sol\\\";\\nimport \\\"./FeesHelper.sol\\\";\\n\\n/**\\n * @title The Interest User contract.\\n *\\n * This contract pays loan interests.\\n * */\\ncontract InterestUser is VaultController, FeesHelper {\\n using SafeERC20 for IERC20;\\n\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n /**\\n * @notice Internal function to pay interest of a loan.\\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\\n * @param lender The account address of the lender.\\n * @param interestToken The token address to pay interest with.\\n * */\\n function _payInterest(address lender, address interestToken) internal {\\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\\n\\n uint256 interestOwedNow = 0;\\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\\n interestOwedNow = block\\n .timestamp\\n .sub(lenderInterestLocal.updatedTimestamp)\\n .mul(lenderInterestLocal.owedPerDay)\\n .div(1 days);\\n\\n lenderInterestLocal.updatedTimestamp = block.timestamp;\\n\\n if (interestOwedNow > lenderInterestLocal.owedTotal)\\n interestOwedNow = lenderInterestLocal.owedTotal;\\n\\n if (interestOwedNow != 0) {\\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\\n\\n _payInterestTransfer(lender, interestToken, interestOwedNow);\\n }\\n } else {\\n lenderInterestLocal.updatedTimestamp = block.timestamp;\\n }\\n }\\n\\n /**\\n * @notice Internal function to transfer tokens for the interest of a loan.\\n * @param lender The account address of the lender.\\n * @param interestToken The token address to pay interest with.\\n * @param interestOwedNow The amount of interest to pay.\\n * */\\n function _payInterestTransfer(\\n address lender,\\n address interestToken,\\n uint256 interestOwedNow\\n ) internal {\\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\\n /// TODO: refactor: data incapsulation violation and DRY design principles\\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\\n\\n _payLendingFee(lender, interestToken, lendingFee);\\n\\n /// Transfers the interest to the lender, less the interest fee.\\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\\n\\n /// Event Log\\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\\n }\\n}\\n\",\"keccak256\":\"0x870208d1ae2c7adca9478b86fe5e70b4458bf719d49b19f5a8a4441bdaccf866\"},\"contracts/mixins/ModuleCommonFunctionalities.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\n\\ncontract ModuleCommonFunctionalities is State {\\n modifier whenNotPaused() {\\n require(!pause, \\\"Paused\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0x9ed7a6a635ef960b53888b28a2a6bed8b071255cad8cd33f00386a634cbddb74\"},\"contracts/mixins/VaultController.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../core/State.sol\\\";\\n\\n/**\\n * @title The Vault Controller contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\\n * trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract implements functionality to deposit and withdraw wrBTC and\\n * other tokens from the vault.\\n * */\\ncontract VaultController is State {\\n using SafeERC20 for IERC20;\\n\\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\\n\\n /**\\n * @notice Deposit wrBTC into the vault.\\n *\\n * @param from The address of the account paying the deposit.\\n * @param value The amount of wrBTC tokens to transfer.\\n */\\n function vaultEtherDeposit(address from, uint256 value) internal {\\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\\n _wrbtcToken.deposit.value(value)();\\n\\n emit VaultDeposit(address(_wrbtcToken), from, value);\\n }\\n\\n /**\\n * @notice Withdraw wrBTC from the vault.\\n *\\n * @param to The address of the recipient.\\n * @param value The amount of wrBTC tokens to transfer.\\n */\\n function vaultEtherWithdraw(address to, uint256 value) internal {\\n if (value != 0) {\\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\\n uint256 balance = address(this).balance;\\n if (value > balance) {\\n _wrbtcToken.withdraw(value - balance);\\n }\\n Address.sendValue(to, value);\\n\\n emit VaultWithdraw(address(_wrbtcToken), to, value);\\n }\\n }\\n\\n /**\\n * @notice Deposit tokens into the vault.\\n *\\n * @param token The address of the token instance.\\n * @param from The address of the account paying the deposit.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultDeposit(\\n address token,\\n address from,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n IERC20(token).safeTransferFrom(from, address(this), value);\\n\\n emit VaultDeposit(token, from, value);\\n }\\n }\\n\\n /**\\n * @notice Withdraw tokens from the vault.\\n *\\n * @param token The address of the token instance.\\n * @param to The address of the recipient.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultWithdraw(\\n address token,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n IERC20(token).safeTransfer(to, value);\\n\\n emit VaultWithdraw(token, to, value);\\n }\\n }\\n\\n /**\\n * @notice Transfer tokens from an account into another one.\\n *\\n * @param token The address of the token instance.\\n * @param from The address of the account paying.\\n * @param to The address of the recipient.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultTransfer(\\n address token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n if (from == address(this)) {\\n IERC20(token).safeTransfer(to, value);\\n } else {\\n IERC20(token).safeTransferFrom(from, to, value);\\n }\\n }\\n }\\n\\n /**\\n * @notice Approve an allowance of tokens to be spent by an account.\\n *\\n * @param token The address of the token instance.\\n * @param to The address of the spender.\\n * @param value The amount of tokens to allow.\\n */\\n function vaultApprove(\\n address token,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\\n IERC20(token).safeApprove(to, 0);\\n }\\n IERC20(token).safeApprove(to, value);\\n }\\n}\\n\",\"keccak256\":\"0xdcde4eee041b77ec9b73378a4a75b4d20d62f2e76f96f759d55260cf6717d0f3\"},\"contracts/modules/LoanOpenings.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../mixins/VaultController.sol\\\";\\nimport \\\"../mixins/InterestUser.sol\\\";\\nimport \\\"../swaps/SwapsUser.sol\\\";\\nimport \\\"../mixins/ModuleCommonFunctionalities.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\n/**\\n * @title Loan Openings contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains functions to borrow and trade.\\n * */\\ncontract LoanOpenings is\\n LoanOpeningsEvents,\\n VaultController,\\n InterestUser,\\n SwapsUser,\\n ModuleCommonFunctionalities\\n{\\n constructor() public {}\\n\\n /**\\n * @notice Fallback function is to react to receiving value (rBTC).\\n * */\\n function() external {\\n revert(\\\"fallback not allowed\\\");\\n }\\n\\n /**\\n * @notice Set function selectors on target contract.\\n *\\n * @param target The address of the target contract.\\n * */\\n function initialize(address target) external onlyOwner {\\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\\n _setTarget(this.borrowOrTradeFromPool.selector, target);\\n _setTarget(this.setDelegatedManager.selector, target);\\n _setTarget(this.getEstimatedMarginExposure.selector, target);\\n _setTarget(this.getRequiredCollateral.selector, target);\\n _setTarget(this.getBorrowAmount.selector, target);\\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \\\"LoanOpenings\\\");\\n }\\n\\n /**\\n * @notice Borrow or trade from pool.\\n *\\n * @dev Note: Only callable by loan pools (iTokens).\\n * Wrapper to _borrowOrTrade internal function.\\n *\\n * @param loanParamsId The ID of the loan parameters.\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * @param initialMargin The initial amount of margin.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return newPrincipal The new loan size.\\n * @return newCollateral The new collateral amount.\\n * */\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId,\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n bytes calldata loanDataBytes\\n )\\n external\\n payable\\n nonReentrant\\n whenNotPaused\\n returns (uint256 newPrincipal, uint256 newCollateral)\\n {\\n require(msg.value == 0 || loanDataBytes.length != 0, \\\"loanDataBytes required with ether\\\");\\n\\n /// Only callable by loan pools.\\n require(loanPoolToUnderlying[msg.sender] != address(0), \\\"not authorized\\\");\\n\\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\\n require(loanParamsLocal.id != 0, \\\"loanParams not exists\\\");\\n\\n /// Get required collateral.\\n uint256 collateralAmountRequired =\\n _getRequiredCollateral(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n sentValues.newPrincipal,\\n initialMargin,\\n isTorqueLoan\\n );\\n require(collateralAmountRequired != 0, \\\"collateral is 0\\\");\\n\\n return\\n _borrowOrTrade(\\n loanParamsLocal,\\n loanId,\\n isTorqueLoan,\\n collateralAmountRequired,\\n initialMargin,\\n sentAddresses,\\n sentValues,\\n loanDataBytes\\n );\\n }\\n\\n /**\\n * @notice Set the delegated manager.\\n *\\n * @dev Wrapper for _setDelegatedManager internal function.\\n *\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param delegated The address of the delegated manager.\\n * @param toggle The flag true/false for the delegated manager.\\n * */\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external whenNotPaused {\\n require(loans[loanId].borrower == msg.sender, \\\"unauthorized\\\");\\n\\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\\n }\\n\\n /**\\n * @notice Get the estimated margin exposure.\\n *\\n * Margin is the money borrowed from a broker to purchase an investment\\n * and is the difference between the total value of investment and the\\n * loan amount. Margin trading refers to the practice of using borrowed\\n * funds from a broker to trade a financial asset, which forms the\\n * collateral for the loan from the broker.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param loanTokenSent The amount of loan tokens sent.\\n * @param collateralTokenSent The amount of collateral tokens sent.\\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\\n * @param newPrincipal The updated amount of principal (current debt).\\n *\\n * @return The margin exposure.\\n * */\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256) {\\n uint256 maxLoanTerm = 2419200; // 28 days\\n\\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\\n\\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\\n\\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\\n uint256 tradingFee = _getTradingFee(swapAmount);\\n if (tradingFee != 0) {\\n swapAmount = swapAmount.sub(tradingFee);\\n }\\n\\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\\n if (receivedAmount == 0) {\\n return 0;\\n } else {\\n return collateralTokenSent.add(receivedAmount);\\n }\\n }\\n\\n /**\\n * @notice Get the required collateral.\\n *\\n * @dev Calls internal _getRequiredCollateral and add fees.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param newPrincipal The updated amount of principal (current debt).\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return collateralAmountRequired The required collateral.\\n * */\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) public view returns (uint256 collateralAmountRequired) {\\n if (marginAmount != 0) {\\n collateralAmountRequired = _getRequiredCollateral(\\n loanToken,\\n collateralToken,\\n newPrincipal,\\n marginAmount,\\n isTorqueLoan\\n );\\n\\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n // cannot be applied solely as it drives to some other tests failure\\n /*\\n\\t\\t\\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\\n\\t\\t\\tif (collateralAmountRequired != 0 && feePercent != 0) {\\n\\t\\t\\t\\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\\n\\t\\t\\t\\t\\t10**20 - feePercent // never will overflow\\n\\t\\t\\t\\t);\\n\\t\\t\\t}*/\\n\\n uint256 fee =\\n isTorqueLoan\\n ? _getBorrowingFee(collateralAmountRequired)\\n : _getTradingFee(collateralAmountRequired);\\n if (fee != 0) {\\n collateralAmountRequired = collateralAmountRequired.add(fee);\\n }\\n }\\n }\\n\\n /**\\n * @notice Get the borrow amount of a trade loan.\\n *\\n * @dev Basically borrowAmount = collateral / marginAmount\\n *\\n * Collateral is something that helps secure a loan. When you borrow money,\\n * you agree that your lender can take something and sell it to get their\\n * money back if you fail to repay the loan. That's the collateral.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param collateralTokenAmount The amount of collateral.\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return borrowAmount The borrow amount.\\n * */\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) public view returns (uint256 borrowAmount) {\\n if (marginAmount != 0) {\\n if (isTorqueLoan) {\\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\\n }\\n uint256 collateral = collateralTokenAmount;\\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\\n if (fee != 0) {\\n collateral = collateral.sub(fee);\\n }\\n if (loanToken == collateralToken) {\\n borrowAmount = collateral.mul(10**20).div(marginAmount);\\n } else {\\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\\n if (sourceToDestPrecision != 0) {\\n borrowAmount = collateral\\n .mul(10**20)\\n .mul(sourceToDestRate)\\n .div(marginAmount)\\n .div(sourceToDestPrecision);\\n }\\n }\\n /*\\n\\t\\t\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t\\t\\t// cannot be applied solely as it drives to some other tests failure\\n\\t\\t\\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\\n\\t\\t\\tif (borrowAmount != 0 && feePercent != 0) {\\n\\t\\t\\t\\tborrowAmount = borrowAmount\\n\\t\\t\\t\\t\\t.mul(\\n\\t\\t\\t\\t\\t10**20 - feePercent // never will overflow\\n\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t.divCeil(10**20);\\n\\t\\t\\t}*/\\n }\\n }\\n\\n /**\\n * @notice Borrow or trade.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * @param collateralAmountRequired The required amount of collateral.\\n * @param initialMargin The initial amount of margin.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return The new loan size.\\n * @return The new collateral amount.\\n * */\\n function _borrowOrTrade(\\n LoanParams memory loanParamsLocal,\\n bytes32 loanId,\\n bool isTorqueLoan,\\n uint256 collateralAmountRequired,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n bytes memory loanDataBytes\\n ) internal returns (uint256, uint256) {\\n require(\\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\\n \\\"collateral/loan match\\\"\\n );\\n require(initialMargin >= loanParamsLocal.minInitialMargin, \\\"initialMargin too low\\\");\\n\\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\\n require(\\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\\n \\\"invalid interest\\\"\\n );\\n\\n // @note this fix is for borrowing only\\n uint256 sentNewPrincipal = isTorqueLoan ? sentValues.newPrincipal : 0;\\n\\n /// Initialize loan.\\n Loan storage loanLocal =\\n loans[\\n _initializeLoan(\\n loanParamsLocal,\\n loanId,\\n initialMargin,\\n sentAddresses,\\n sentValues.newPrincipal\\n )\\n ];\\n\\n // Get required interest.\\n uint256 amount =\\n _initializeInterest(\\n loanParamsLocal,\\n loanLocal,\\n sentValues.interestRate, /// newRate\\n sentValues.newPrincipal, /// newPrincipal,\\n sentValues.interestInitialAmount /// torqueInterest\\n );\\n\\n /// substract out interest from usable loanToken sent.\\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\\n\\n if (isTorqueLoan) {\\n require(sentValues.loanTokenSent == 0, \\\"surplus loan token\\\");\\n\\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\\n // need to temp into local state to avoid\\n address _collateralToken = loanParamsLocal.collateralToken;\\n address _loanToken = loanParamsLocal.loanToken;\\n if (borrowingFee != 0) {\\n _payBorrowingFee(\\n sentAddresses.borrower, /// borrower\\n loanLocal.id,\\n _collateralToken, /// fee token\\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n borrowingFee\\n );\\n\\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\\n }\\n } else {\\n /// Update collateral after trade.\\n sentValues = _updateCollateralAfterTrade(\\n loanId,\\n loanParamsLocal,\\n sentAddresses,\\n sentValues,\\n loanDataBytes\\n );\\n }\\n\\n /// Settle collateral.\\n require(\\n _isCollateralSatisfied(\\n loanParamsLocal,\\n loanLocal,\\n initialMargin,\\n sentValues.collateralTokenSent,\\n collateralAmountRequired,\\n sentNewPrincipal\\n ),\\n \\\"collateral insufficient\\\"\\n );\\n\\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\\n\\n if (isTorqueLoan) {\\n /// reclaiming variable -> interestDuration\\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\\n } else {\\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\\n }\\n\\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\\n\\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\\n }\\n\\n function _updateCollateralAfterTrade(\\n bytes32 loanId,\\n LoanParams memory loanParamsLocal,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n bytes memory loanDataBytes\\n ) internal returns (MarginTradeStructHelpers.SentAmounts memory) {\\n uint256 receivedAmount;\\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\\n loanId,\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n sentAddresses.borrower, /// borrower\\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\\n false, /// bypassFee\\n loanDataBytes\\n );\\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\\n\\n /// Check the minEntryPrice with the rate\\n require(\\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\\n \\\"entry price above the minimum\\\"\\n );\\n\\n return sentValues;\\n }\\n\\n /**\\n * @notice Finalize an open loan.\\n *\\n * @dev Finalize it by updating local parameters of the loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * */\\n function _finalizeOpen(\\n LoanParams memory loanParamsLocal,\\n Loan storage loanLocal,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n bool isTorqueLoan\\n ) internal {\\n /// @dev TODO: here the actual used rate and margin should go.\\n (uint256 initialMargin, uint256 collateralToLoanRate) =\\n IPriceFeeds(priceFeeds).getCurrentMargin(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n loanLocal.principal,\\n loanLocal.collateral\\n );\\n require(initialMargin > loanParamsLocal.maintenanceMargin, \\\"unhealthy position\\\");\\n\\n if (loanLocal.startTimestamp == block.timestamp) {\\n uint256 loanToCollateralPrecision =\\n IPriceFeeds(priceFeeds).queryPrecision(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken\\n );\\n uint256 collateralToLoanPrecision =\\n IPriceFeeds(priceFeeds).queryPrecision(\\n loanParamsLocal.collateralToken,\\n loanParamsLocal.loanToken\\n );\\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\\n loanLocal.startRate = isTorqueLoan\\n ? collateralToLoanRate\\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\\n }\\n\\n _emitOpeningEvents(\\n loanParamsLocal,\\n loanLocal,\\n sentAddresses,\\n sentValues,\\n collateralToLoanRate,\\n initialMargin,\\n isTorqueLoan\\n );\\n }\\n\\n /**\\n * @notice Emit the opening events.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param collateralToLoanRate The exchange rate from collateral to loan\\n * tokens.\\n * @param margin The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * */\\n function _emitOpeningEvents(\\n LoanParams memory loanParamsLocal,\\n Loan memory loanLocal,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n uint256 collateralToLoanRate,\\n uint256 margin,\\n bool isTorqueLoan\\n ) internal {\\n if (isTorqueLoan) {\\n emit Borrow(\\n sentAddresses.borrower, /// user (borrower)\\n sentAddresses.lender, /// lender\\n loanLocal.id, /// loanId\\n loanParamsLocal.loanToken, /// loanToken\\n loanParamsLocal.collateralToken, /// collateralToken\\n sentValues.newPrincipal, /// newPrincipal\\n sentValues.collateralTokenSent, /// newCollateral\\n sentValues.interestRate, /// interestRate\\n sentValues.interestDuration, /// interestDuration\\n collateralToLoanRate, /// collateralToLoanRate,\\n margin /// currentMargin\\n );\\n } else {\\n /// currentLeverage = 100 / currentMargin\\n margin = SafeMath.div(10**38, margin);\\n\\n emit Trade(\\n sentAddresses.borrower, /// user (trader)\\n sentAddresses.lender, /// lender\\n loanLocal.id, /// loanId\\n loanParamsLocal.collateralToken, /// collateralToken\\n loanParamsLocal.loanToken, /// loanToken\\n sentValues.collateralTokenSent, /// positionSize\\n sentValues.newPrincipal, /// borrowedAmount\\n sentValues.interestRate, /// interestRate,\\n loanLocal.endTimestamp, /// settlementDate\\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\\n sentValues.entryLeverage, /// entryLeverage\\n margin /// currentLeverage\\n );\\n }\\n }\\n\\n /**\\n * @notice Set the delegated manager.\\n *\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param delegator The address of previous manager.\\n * @param delegated The address of the delegated manager.\\n * @param toggle The flag true/false for the delegated manager.\\n * */\\n function _setDelegatedManager(\\n bytes32 loanId,\\n address delegator,\\n address delegated,\\n bool toggle\\n ) internal {\\n delegatedManagers[loanId][delegated] = toggle;\\n\\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\\n }\\n\\n /**\\n * @notice Calculate whether the collateral is satisfied.\\n *\\n * @dev Basically check collateral + drawdown >= 98% of required.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param initialMargin The initial amount of margin.\\n * @param newCollateral The amount of new collateral.\\n * @param collateralAmountRequired The amount of required collateral.\\n * @param newPrincipal The amount to borrow.\\n *\\n * @return Whether the collateral is satisfied.\\n * */\\n function _isCollateralSatisfied(\\n LoanParams memory loanParamsLocal,\\n Loan memory loanLocal,\\n uint256 initialMargin,\\n uint256 newCollateral,\\n uint256 collateralAmountRequired,\\n uint256 newPrincipal\\n ) internal view returns (bool) {\\n /// Allow at most 2% under-collateralized.\\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\\n\\n if (newCollateral < collateralAmountRequired) {\\n /// Check that existing collateral is sufficient coverage.\\n if (loanLocal.collateral != 0) {\\n uint256 maxDrawdown =\\n IPriceFeeds(priceFeeds).getMaxDrawdown(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n loanLocal.principal.sub(newPrincipal), // sub(newPrincipal) to exclude the new borrowed amount from the total principal to calculate maxDrawdown for existing loan\\n loanLocal.collateral,\\n initialMargin\\n );\\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\\n } else {\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /**\\n * @notice Initialize a loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanId The ID of the loan.\\n * @param initialMargin The amount of margin of the trade.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\\n * @return The loanId.\\n * */\\n function _initializeLoan(\\n LoanParams memory loanParamsLocal,\\n bytes32 loanId,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n uint256 newPrincipal\\n ) internal returns (bytes32) {\\n require(loanParamsLocal.active, \\\"loanParams disabled\\\");\\n\\n address lender = sentAddresses.lender;\\n address borrower = sentAddresses.borrower;\\n address manager = sentAddresses.manager;\\n\\n Loan memory loanLocal;\\n\\n if (loanId == 0) {\\n borrowerNonce[borrower]++;\\n loanId = keccak256(\\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\\n );\\n require(loans[loanId].id == 0, \\\"loan exists\\\");\\n\\n loanLocal = Loan({\\n id: loanId,\\n loanParamsId: loanParamsLocal.id,\\n pendingTradesId: 0,\\n active: true,\\n principal: newPrincipal,\\n collateral: 0, /// calculated later\\n startTimestamp: block.timestamp,\\n endTimestamp: 0, /// calculated later\\n startMargin: initialMargin,\\n startRate: 0, /// queried later\\n borrower: borrower,\\n lender: lender\\n });\\n\\n activeLoansSet.addBytes32(loanId);\\n lenderLoanSets[lender].addBytes32(loanId);\\n borrowerLoanSets[borrower].addBytes32(loanId);\\n } else {\\n loanLocal = loans[loanId];\\n require(\\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\\n \\\"loan has ended\\\"\\n );\\n require(loanLocal.borrower == borrower, \\\"borrower mismatch\\\");\\n require(loanLocal.lender == lender, \\\"lender mismatch\\\");\\n require(loanLocal.loanParamsId == loanParamsLocal.id, \\\"loanParams mismatch\\\");\\n\\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\\n }\\n\\n if (manager != address(0)) {\\n _setDelegatedManager(loanId, borrower, manager, true);\\n }\\n\\n loans[loanId] = loanLocal;\\n\\n return loanId;\\n }\\n\\n /**\\n * @notice Initialize a loan interest.\\n *\\n * @dev A Torque loan is an indefinite-term loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param newRate The new interest rate of the loan.\\n * @param newPrincipal The new principal amount of the loan.\\n * @param torqueInterest The interest rate of the Torque loan.\\n *\\n * @return interestAmountRequired The interest amount required.\\n * */\\n function _initializeInterest(\\n LoanParams memory loanParamsLocal,\\n Loan storage loanLocal,\\n uint256 newRate,\\n uint256 newPrincipal,\\n uint256 torqueInterest /// ignored for fixed-term loans\\n ) internal returns (uint256 interestAmountRequired) {\\n /// Pay outstanding interest to lender.\\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\\n\\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\\n LenderInterest storage lenderInterestLocal =\\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\\n\\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\\n\\n _settleFeeRewardForInterestExpense(\\n loanInterestLocal,\\n loanLocal.id,\\n loanParamsLocal.loanToken, /// fee token\\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n loanLocal.borrower,\\n block.timestamp\\n );\\n\\n uint256 previousDepositRemaining;\\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\\n previousDepositRemaining = loanLocal\\n .endTimestamp\\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\\n .mul(loanInterestLocal.owedPerDay)\\n .div(86400);\\n }\\n\\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\\n\\n /// Update stored owedPerDay\\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\\n\\n if (maxLoanTerm == 0) {\\n /// Indefinite-term (Torque) loan.\\n\\n /// torqueInterest != 0 was confirmed earlier.\\n loanLocal.endTimestamp = torqueInterest\\n .add(previousDepositRemaining)\\n .mul(86400)\\n .div(loanInterestLocal.owedPerDay)\\n .add(block.timestamp);\\n\\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\\n\\n /// Loan term has to at least be greater than one hour.\\n require(maxLoanTerm > 3600, \\\"loan too short\\\");\\n\\n interestAmountRequired = torqueInterest;\\n } else {\\n /// Fixed-term loan.\\n\\n if (loanLocal.endTimestamp == 0) {\\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\\n }\\n\\n interestAmountRequired = loanLocal\\n .endTimestamp\\n .sub(block.timestamp)\\n .mul(owedPerDay)\\n .div(86400);\\n }\\n\\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\\n interestAmountRequired\\n );\\n\\n /// Update remaining lender interest values.\\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\\n }\\n\\n /**\\n * @notice Get the required collateral.\\n *\\n * @dev Basically collateral = newPrincipal * marginAmount\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param newPrincipal The updated amount of principal (current debt).\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return collateralTokenAmount The required collateral.\\n * */\\n function _getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) internal view returns (uint256 collateralTokenAmount) {\\n if (loanToken == collateralToken) {\\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\\n } else {\\n /// Using the price feed instead of the swap expected return\\n /// because we need the rate in the inverse direction\\n /// so the swap is probably farther off than the price feed.\\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\\n if (sourceToDestRate != 0) {\\n collateralTokenAmount = newPrincipal\\n .mul(sourceToDestPrecision)\\n .div(sourceToDestRate)\\n .mul(marginAmount)\\n .div(10**20);\\n /*TODO: review\\n\\t\\t\\t\\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\\n }\\n }\\n // ./tests/loan-token/TradingTestToken.test.js\\n if (isTorqueLoan && collateralTokenAmount != 0) {\\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\\n collateralTokenAmount\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0x1c2eb82f702d37c72c7fbc8bd9bf1ded7c880ac643a6b8e0d85b39c0c2b790a9\"},\"contracts/modules/interfaces/ProtocolAffiliatesInterface.sol\":{\"content\":\"/**\\n * Copyright 2020, Denis Savelev. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface ProtocolAffiliatesInterface {\\n function setAffiliatesReferrer(address user, address referrer) external;\\n\\n function setUserNotFirstTradeFlag(address user_) external;\\n\\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address affiliate,\\n address trader,\\n address token,\\n uint256 amount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n}\\n\",\"keccak256\":\"0x42f259156db09a06e3dcdf0ab9c6774712616b35e6baff97999a2a534d1c9c64\"},\"contracts/openzeppelin/Address.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n codehash := extcodehash(account)\\n }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x23df48a01dbac9b25e86c9131174fb7752bbc7e741e63f1aa982de22e055ad54\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/openzeppelin/ReentrancyGuard.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @title Helps contracts guard against reentrancy attacks.\\n * @author Remco Bloemen , Eenae \\n * @dev If you mark a function `nonReentrant`, you should also\\n * mark it `external`.\\n */\\ncontract ReentrancyGuard {\\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\\n\\n /// @dev Constant for locked guard state\\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\\n\\n /**\\n * @dev We use a single lock for the whole contract.\\n */\\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * If you mark a function `nonReentrant`, you should also\\n * mark it `external`. Calling one `nonReentrant` function from\\n * another is not supported. Instead, you can implement a\\n * `private` function doing the actual work, and an `external`\\n * wrapper marked as `nonReentrant`.\\n */\\n modifier nonReentrant() {\\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \\\"nonReentrant\\\");\\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\\n _;\\n reentrancyLock = REENTRANCY_GUARD_FREE;\\n }\\n}\\n\",\"keccak256\":\"0xd347de96ad57d1e45b07a2efe3050c1bd4b809236bbf354acb593de56d21a5c9\"},\"contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./Address.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\\n );\\n }\\n\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance =\\n token.allowance(address(this), spender).sub(\\n value,\\n \\\"SafeERC20: decreased allowance below zero\\\"\\n );\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) {\\n // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe99b4d979cb976a6b70e297600242afe38b8cd8f1b1ba6ee373f39f7abb3ca79\"},\"contracts/openzeppelin/SafeMath.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\\n return divCeil(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n\\n if (a == 0) {\\n return 0;\\n }\\n uint256 c = ((a - 1) / b) + 1;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n\\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n return _a < _b ? _a : _b;\\n }\\n}\\n\",\"keccak256\":\"0xbff8d6273e1a6870d1a142c0c23acd63a4dd47760f250390f49ee56333bcb6e8\"},\"contracts/reentrancy/Mutex.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/*\\n * @title Global Mutex contract\\n *\\n * @notice A mutex contract that allows only one function to be called at a time out\\n * of a large set of functions. *Anyone* in the network can freely use any instance\\n * of this contract to add a universal mutex to any function in any contract.\\n */\\ncontract Mutex {\\n /*\\n * We use an uint to store the mutex state.\\n */\\n uint256 public value;\\n\\n /*\\n * @notice Increment the mutex state and return the new value.\\n *\\n * @dev This is the function that will be called by anyone to change the mutex\\n * state. It is purposely not protected by any access control\\n */\\n function incrementAndGetValue() external returns (uint256) {\\n /*\\n * increment value using unsafe math. This is safe because we are\\n * pretty certain no one will ever increment the value 2^256 times\\n * in a single transaction.\\n */\\n return ++value;\\n }\\n}\\n\",\"keccak256\":\"0xd10b0fd07d5fed1ae1237e7c87e6501970fce2a86e2b8862e502258b0d3aeb2c\"},\"contracts/reentrancy/SharedReentrancyGuard.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./Mutex.sol\\\";\\n\\n/*\\n * @title Abstract contract for shared reentrancy guards\\n *\\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\\n * that there's no reentrancy between *any* functions marked with the modifier.\\n *\\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\\n */\\ncontract SharedReentrancyGuard {\\n /*\\n * This is the address of the mutex contract that will be used as the\\n * reentrancy guard.\\n *\\n * The address is hardcoded to avoid changing the memory layout of\\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\\n * because the Mutex contract is always deployed to the same address, with the\\n * same method used in the deployment of ERC1820Registry.\\n */\\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\\n\\n /*\\n * This is the modifier that will be used to protect functions from\\n * reentrancy. It will call the mutex contract to increment the mutex\\n * state and then revert if the mutex state was changed by another\\n * nested call.\\n */\\n modifier globallyNonReentrant() {\\n uint256 previous = MUTEX.incrementAndGetValue();\\n\\n _;\\n\\n /*\\n * If the mutex state was changed by a nested function call, then\\n * the value of the state variable will be different from the previous value.\\n */\\n require(previous == MUTEX.value(), \\\"reentrancy violation\\\");\\n }\\n}\\n\",\"keccak256\":\"0x2d0e61b104b91c1764f20fbeb381ba0f8a8889934ba7f6e8a167ed542ec2c124\"},\"contracts/swaps/SwapsUser.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../mixins/FeesHelper.sol\\\";\\nimport \\\"./connectors/SwapsImplSovrynSwapLib.sol\\\";\\n\\n/**\\n * @title Perform token swaps for loans and trades.\\n * */\\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\\n /**\\n * @notice Internal loan swap.\\n *\\n * @param loanId The ID of the loan.\\n * @param sourceToken The address of the source tokens.\\n * @param destToken The address of destination tokens.\\n * @param user The user address.\\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\\n * @param requiredDestTokenAmount The required amount of destination tokens.\\n * @param bypassFee To bypass or not the fee.\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return destTokenAmountReceived\\n * @return sourceTokenAmountUsed\\n * @return sourceToDestSwapRate\\n * */\\n function _loanSwap(\\n bytes32 loanId,\\n address sourceToken,\\n address destToken,\\n address user,\\n uint256 minSourceTokenAmount,\\n uint256 maxSourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n bool bypassFee,\\n bytes memory loanDataBytes\\n )\\n internal\\n returns (\\n uint256 destTokenAmountReceived,\\n uint256 sourceTokenAmountUsed,\\n uint256 sourceToDestSwapRate\\n )\\n {\\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\\n [\\n sourceToken,\\n destToken,\\n address(this), // receiver\\n address(this), // returnToSender\\n user\\n ],\\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\\n loanId,\\n bypassFee,\\n loanDataBytes,\\n false // swap external flag, set to false so that it will use the tradingFeePercent\\n );\\n\\n /// Will revert if swap size too large.\\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\\n\\n /// Will revert if disagreement found.\\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\\n sourceToken,\\n destToken,\\n sourceTokenAmountUsed,\\n destTokenAmountReceived,\\n maxDisagreement\\n );\\n\\n emit LoanSwap(\\n loanId,\\n sourceToken,\\n destToken,\\n user,\\n sourceTokenAmountUsed,\\n destTokenAmountReceived\\n );\\n }\\n\\n /**\\n * @notice Calculate amount of source and destination tokens.\\n *\\n * @dev Wrapper for _swapsCall_internal function.\\n *\\n * @param addrs The array of addresses.\\n * @param vals The array of values.\\n * @param loanId The Id of the associated loan.\\n * @param miscBool True/false to bypassFee.\\n * @param loanDataBytes Additional loan data (not in use yet).\\n *\\n * @return destTokenAmountReceived The amount of destination tokens received.\\n * @return sourceTokenAmountUsed The amount of source tokens used.\\n * */\\n function _swapsCall(\\n address[5] memory addrs,\\n uint256[3] memory vals,\\n bytes32 loanId,\\n bool miscBool, /// bypassFee\\n bytes memory loanDataBytes,\\n bool isSwapExternal\\n ) internal returns (uint256, uint256) {\\n /// addrs[0]: sourceToken\\n /// addrs[1]: destToken\\n /// addrs[2]: receiver\\n /// addrs[3]: returnToSender\\n /// addrs[4]: user\\n /// vals[0]: minSourceTokenAmount\\n /// vals[1]: maxSourceTokenAmount\\n /// vals[2]: requiredDestTokenAmount\\n\\n require(vals[0] != 0 || vals[1] != 0, \\\"min or max source token amount needs to be set\\\");\\n\\n if (vals[1] == 0) {\\n vals[1] = vals[0];\\n }\\n require(vals[0] <= vals[1], \\\"sourceAmount larger than max\\\");\\n\\n uint256 destTokenAmountReceived;\\n uint256 sourceTokenAmountUsed;\\n\\n uint256 tradingFee;\\n if (!miscBool) {\\n /// bypassFee\\n if (vals[2] == 0) {\\n /// condition: vals[0] will always be used as sourceAmount\\n\\n if (isSwapExternal) {\\n tradingFee = _getSwapExternalFee(vals[0]);\\n } else {\\n tradingFee = _getTradingFee(vals[0]);\\n }\\n\\n if (tradingFee != 0) {\\n _payTradingFee(\\n addrs[4], /// user\\n loanId,\\n addrs[0], /// sourceToken (feeToken)\\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n tradingFee\\n );\\n\\n vals[0] = vals[0].sub(tradingFee);\\n }\\n } else {\\n /// Condition: unknown sourceAmount will be used.\\n\\n if (isSwapExternal) {\\n tradingFee = _getSwapExternalFee(vals[2]);\\n } else {\\n tradingFee = _getTradingFee(vals[2]);\\n }\\n\\n if (tradingFee != 0) {\\n vals[2] = vals[2].add(tradingFee);\\n }\\n }\\n }\\n\\n require(loanDataBytes.length == 0, \\\"invalid state\\\");\\n\\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\\n\\n if (vals[2] == 0) {\\n /// There's no minimum destTokenAmount, but all of vals[0]\\n /// (minSourceTokenAmount) must be spent.\\n require(sourceTokenAmountUsed == vals[0], \\\"swap too large to fill\\\");\\n\\n if (tradingFee != 0) {\\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\\n }\\n } else {\\n /// There's a minimum destTokenAmount required, but\\n /// sourceTokenAmountUsed won't be greater\\n /// than vals[1] (maxSourceTokenAmount)\\n require(sourceTokenAmountUsed <= vals[1], \\\"swap fill too large\\\");\\n require(destTokenAmountReceived >= vals[2], \\\"insufficient swap liquidity\\\");\\n\\n if (tradingFee != 0) {\\n _payTradingFee(\\n addrs[4], /// user\\n loanId, /// loanId,\\n addrs[1], /// destToken (feeToken)\\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n tradingFee\\n );\\n\\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\\n }\\n }\\n\\n return (destTokenAmountReceived, sourceTokenAmountUsed);\\n }\\n\\n /**\\n * @notice Calculate amount of source and destination tokens.\\n *\\n * @dev Calls swapsImpl::internalSwap\\n *\\n * @param addrs The array of addresses.\\n * @param vals The array of values.\\n *\\n * @return destTokenAmountReceived The amount of destination tokens received.\\n * @return sourceTokenAmountUsed The amount of source tokens used.\\n * */\\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\\n internal\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n SwapsImplSovrynSwapLib.SwapParams memory swapParams;\\n\\n swapParams.sourceTokenAddress = addrs[0];\\n swapParams.destTokenAddress = addrs[1];\\n swapParams.receiverAddress = addrs[2];\\n swapParams.returnToSenderAddress = addrs[3];\\n swapParams.minSourceTokenAmount = vals[0];\\n swapParams.maxSourceTokenAmount = vals[1];\\n swapParams.requiredDestTokenAmount = vals[2];\\n\\n (destTokenAmountReceived, sourceTokenAmountUsed) = SwapsImplSovrynSwapLib.swap(swapParams);\\n }\\n\\n /**\\n * @notice Calculate expected amount of destination tokens.\\n *\\n * @dev Calls swapsImpl::internalExpectedReturn\\n *\\n * @param sourceToken The address of the source tokens.\\n * @param destToken The address of the destination tokens.\\n * @param sourceTokenAmount The amount of the source tokens.\\n *\\n * @param destTokenAmount The amount of destination tokens.\\n * */\\n function _swapsExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) internal view returns (uint256 destTokenAmount) {\\n destTokenAmount = SwapsImplSovrynSwapLib.getExpectedReturn(\\n sourceToken,\\n destToken,\\n sourceTokenAmount\\n );\\n }\\n\\n /**\\n * @notice Verify that the amount of tokens are under the swap limit.\\n *\\n * @dev Calls priceFeeds::amountInEth\\n *\\n * @param tokenAddress The address of the token to calculate price.\\n * @param amount The amount of tokens to calculate price.\\n * */\\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\\n uint256 _maxSwapSize = maxSwapSize;\\n if (_maxSwapSize != 0) {\\n uint256 amountInEth;\\n if (tokenAddress == address(wrbtcToken)) {\\n amountInEth = amount;\\n } else {\\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\\n }\\n require(amountInEth <= _maxSwapSize, \\\"swap too large\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x7dfc45e91455458caf886b49c96ad426de06cddffa442c16628eba4974f3d323\"},\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":{\"content\":\"pragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"./interfaces/ISovrynSwapNetwork.sol\\\";\\nimport \\\"./interfaces/IContractRegistry.sol\\\";\\nimport \\\"../../interfaces/ISovryn.sol\\\";\\n\\n/**\\n * @title Swaps Implementation Sovryn contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the implementation of swap process and rate\\n * calculations for Sovryn network.\\n * */\\nlibrary SwapsImplSovrynSwapLib {\\n using SafeMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n struct SwapParams {\\n address sourceTokenAddress;\\n address destTokenAddress;\\n address receiverAddress;\\n address returnToSenderAddress;\\n uint256 minSourceTokenAmount;\\n uint256 maxSourceTokenAmount;\\n uint256 requiredDestTokenAmount;\\n }\\n\\n /// bytes32 contractName = hex\\\"42616e636f724e6574776f726b\\\"; /// \\\"SovrynSwapNetwork\\\"\\n\\n /**\\n * Get the hex name of a contract.\\n * @param source The name of the contract.\\n * */\\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\\n assembly {\\n result := mload(add(source, 32))\\n }\\n }\\n\\n /**\\n * Look up the Sovryn swap network contract registered at the given address.\\n * @param sovrynSwapRegistryAddress The address of the registry.\\n * */\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (ISovrynSwapNetwork)\\n {\\n /// State variable sovrynSwapContractRegistryAddress is part of\\n /// State.sol and set in ProtocolSettings.sol and this function\\n /// needs to work without delegate call as well -> therefore pass it.\\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\\n return\\n ISovrynSwapNetwork(\\n contractRegistry.addressOf(getContractHexName(\\\"SovrynSwapNetwork\\\"))\\n );\\n }\\n\\n /**\\n * Swap the source token for the destination token on the oracle based AMM.\\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\\n * -> swap the minSourceTokenAmount\\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\\n * -> same as on rollover. minimum amount is not considered at all.\\n *\\n * @param params SwapParams struct\\n * sourceTokenAddress The address of the source tokens.\\n * destTokenAddress The address of the destination tokens.\\n * receiverAddress The address who will received the swap token results\\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\\n * requiredDestTokenAmount The required amount of destination tokens.\\n * */\\n function swap(SwapParams memory params)\\n public\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n require(params.sourceTokenAddress != params.destTokenAddress, \\\"source == dest\\\");\\n\\n ISovryn iSovryn = ISovryn(address(this));\\n require(\\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\\n iSovryn.supportedTokens(params.destTokenAddress),\\n \\\"invalid tokens\\\"\\n );\\n\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\\n\\n IERC20[] memory path =\\n _getConversionPath(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n sovrynSwapNetwork\\n );\\n\\n uint256 minReturn = 1;\\n sourceTokenAmountUsed = params.minSourceTokenAmount;\\n\\n /// If the required amount of destination tokens is passed, we need to\\n /// calculate the estimated amount of source tokens regardless of the\\n /// minimum source token amount (name is misleading).\\n if (params.requiredDestTokenAmount > 0) {\\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n params.requiredDestTokenAmount,\\n params.maxSourceTokenAmount\\n );\\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\\n require(\\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\\n params.requiredDestTokenAmount,\\n \\\"insufficient source tokens provided.\\\"\\n );\\n minReturn = params.requiredDestTokenAmount;\\n }\\n\\n require(sourceTokenAmountUsed > 0, \\\"cannot swap 0 tokens\\\");\\n\\n _allowTransfer(\\n sourceTokenAmountUsed,\\n params.sourceTokenAddress,\\n address(sovrynSwapNetwork)\\n );\\n\\n /// @dev Note: the kyber connector uses .call() to interact with kyber\\n /// to avoid bubbling up. here we allow bubbling up.\\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\\n path,\\n sourceTokenAmountUsed,\\n minReturn,\\n params.receiverAddress,\\n address(0),\\n 0\\n );\\n\\n /// If the sender is not the protocol (calling with delegatecall),\\n /// return the remainder to the specified address.\\n /// @dev Note: for the case that the swap is used without the\\n /// protocol. Not sure if it should, though. needs to be discussed.\\n if (params.returnToSenderAddress != address(this)) {\\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\\n /// Send unused source token back.\\n IERC20(params.sourceTokenAddress).safeTransfer(\\n params.returnToSenderAddress,\\n params.maxSourceTokenAmount - sourceTokenAmountUsed\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Check whether the existing allowance suffices to transfer\\n * the needed amount of tokens.\\n * If not, allows the transfer of an arbitrary amount of tokens.\\n *\\n * @param tokenAmount The amount to transfer.\\n * @param tokenAddress The address of the token to transfer.\\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\\n * */\\n function _allowTransfer(\\n uint256 tokenAmount,\\n address tokenAddress,\\n address sovrynSwapNetwork\\n ) internal {\\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\\n if (tempAllowance < tokenAmount) {\\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\\n }\\n }\\n\\n /**\\n * @notice Calculate the number of source tokens to provide in order to\\n * obtain the required destination amount.\\n *\\n * @param sourceTokenAddress The address of the source token address.\\n * @param destTokenAddress The address of the destination token address.\\n * @param requiredDestTokenAmount The number of destination tokens needed.\\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\\n *\\n * @return The estimated amount of source tokens needed.\\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\\n * */\\n function _estimateSourceTokenAmount(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 requiredDestTokenAmount,\\n uint256 maxSourceTokenAmount\\n ) internal view returns (uint256 estimatedSourceAmount) {\\n ISovryn iSovryn = ISovryn(address(this));\\n uint256 sourceToDestPrecision =\\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\\n\\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\\n uint256 expectedRate =\\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\\n\\n /// Compute the source tokens needed to get the required amount with the worst case rate.\\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\\n expectedRate\\n );\\n\\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\\n uint256 buffer = estimatedSourceAmount.div(1000);\\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\\n\\n /// Never spend more than the maximum.\\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\\n return maxSourceTokenAmount;\\n }\\n\\n /**\\n * @notice Get the expected rate for 1 source token when exchanging the\\n * given amount of source tokens.\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\\n * */\\n function getExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n\\n /// Return the rate for 1 token with 18 decimals.\\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\\n }\\n\\n /**\\n * @notice Get the expected return amount when exchanging the given\\n * amount of source tokens.\\n *\\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the return for.\\n * */\\n function getExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256 expectedReturn) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n }\\n\\n function _getConversionPath(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n ISovrynSwapNetwork sovrynSwapNetwork\\n ) private view returns (IERC20[] memory path) {\\n IERC20[] memory _defaultPathConversion =\\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\\n\\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\\n path = _defaultPathConversion.length >= 3\\n ? _defaultPathConversion\\n : sovrynSwapNetwork.conversionPath(\\n IERC20(sourceTokenAddress),\\n IERC20(destTokenAddress)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x058b8d733422a2421f17d1b159aed69f151ea8d5f48ee507bac5b4e86add8b0c\"},\"contracts/swaps/connectors/interfaces/IContractRegistry.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\ncontract IContractRegistry {\\n function addressOf(bytes32 contractName) public view returns (address);\\n}\\n\",\"keccak256\":\"0x793c4eefa2ee04cbf0a1a9da28676ac310ed7bf60a27ec7d86de7d7236ccf45b\"},\"contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol\":{\"content\":\"pragma solidity >=0.5.8 <=0.5.17;\\n\\nimport \\\"../../../interfaces/IERC20.sol\\\";\\n\\ncontract ISovrynSwapNetwork {\\n function convertByPath(\\n IERC20[] calldata _path,\\n uint256 _amount,\\n uint256 _minReturn,\\n address _beneficiary,\\n address _affiliateAccount,\\n uint256 _affiliateFee\\n ) external payable returns (uint256);\\n\\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\\n\\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\\n external\\n view\\n returns (IERC20[] memory);\\n}\\n\",\"keccak256\":\"0xcd28e146b77183bff18f78b511912f7ebe60d437430fdaa72ed145fdda61a5ad\"}},\"version\":1}", + "bytecode": "0x60806040526001600055678ac7230489e80000601555670214e8348c4f000060185567013fbe85edc90000601b55674563918244f40000602055674563918244f40000602155674563918244f400006027556127106028556802b5e3af16b1880000602955650f478e084000602b5567016345785d8a0000602c556802b5e3af16b1880000602f5560036035556801158e460913d00000603955348015620000a657600080fd5b506000620000bc6001600160e01b036200011016565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35062000114565b3390565b61512680620001246000396000f3fe6080604052600436106103815760003560e01c80638f32d59b116101d1578063cd5d808d11610102578063e8f62764116100a0578063f589a3e71161006f578063f589a3e714610a05578063f6ddc8b314610a1a578063f706b1f214610a2f578063f851a44014610a4457610381565b8063e8f62764146109a6578063edab119f146109bb578063f0e085f5146109d0578063f2fde38b146109e557610381565b8063d485045e116100dc578063d485045e14610925578063d67f707714610945578063d84ca25414610965578063e762319f1461098657610381565b8063cd5d808d146108db578063d288208c146108fb578063d473c2da1461091057610381565b8063b7e152411161016f578063bdee453c11610149578063bdee453c1461082f578063c4a908151461084f578063c4d66de814610887578063cb6eacd1146108a757610381565b8063b7e15241146107e5578063b9cffa3e14610805578063ba4861e91461081a57610381565b8063acc04348116101ab578063acc0434814610779578063ae0a85301461078e578063afe84009146107a3578063b30643d9146107c557610381565b80638f32d59b1461072f57806392d894f814610744578063959083d31461076457610381565b80634203e395116102b65780636e663730116102545780637a8faeb8116102235780637a8faeb8146106d05780638456cb59146106e55780638da5cb5b146106fa5780638dc48ba51461070f57610381565b80636e663730146106715780637420ca3e14610691578063742e6798146106a657806378d849ed146106bb57610381565b8063569fc1fb11610290578063569fc1fb146105dc578063574442cc1461060b57806362fff3f61461062057806368c4ac261461065157610381565b80634203e395146105925780634699f846146105b25780634f28cac2146105c757610381565b80632a324027116103235780633432423c116102fd5780633432423c146105125780633452d2d4146105325780633fca506e146105525780634115a2b61461057257610381565b80632a324027146104c65780632f470764146104db57806333d8991f146104f057610381565b80631b7bde741161035f5780631b7bde741461042c578063218b39c61461045957806324cc57491461047957806325decac0146104a657610381565b8063065d810f146103af5780630676c1b7146103ea57806317548b791461040c575b34801561038d57600080fd5b5060405162461bcd60e51b81526004016103a690614eaa565b60405180910390fd5b3480156103bb57600080fd5b506103cf6103ca366004613f1e565b610a59565b6040516103e196959493929190614f9d565b60405180910390f35b3480156103f657600080fd5b506103ff610a99565b6040516103e191906149d4565b34801561041857600080fd5b506103ff6104273660046140b1565b610aa8565b34801561043857600080fd5b5061044c610447366004613de8565b610ac3565b6040516103e19190614f58565b34801561046557600080fd5b506103ff610474366004613dca565b610ae0565b34801561048557600080fd5b50610499610494366004613dca565b610afb565b6040516103e19190614bf7565b3480156104b257600080fd5b5061044c6104c1366004613e22565b610b10565b3480156104d257600080fd5b5061044c610b6b565b3480156104e757600080fd5b5061044c610b71565b3480156104fc57600080fd5b5061051061050b366004613fa9565b610b77565b005b34801561051e57600080fd5b506103cf61052d366004613f1e565b610be4565b34801561053e57600080fd5b5061044c61054d366004613dca565b610c24565b34801561055e57600080fd5b5061044c61056d366004613dca565b610c36565b34801561057e57600080fd5b5061049961058d366004613f8a565b610c48565b34801561059e57600080fd5b5061044c6105ad366004613dca565b610c68565b3480156105be57600080fd5b5061044c610c7a565b3480156105d357600080fd5b5061044c610c80565b3480156105e857600080fd5b506105fc6105f7366004613f6c565b610c86565b6040516103e193929190614f74565b34801561061757600080fd5b5061044c610ca7565b34801561062c57600080fd5b5061064061063b366004613de8565b610cad565b6040516103e1959493929190614f82565b34801561065d57600080fd5b5061049961066c366004613dca565b610ce7565b34801561067d57600080fd5b506103ff61068c366004613dca565b610cfc565b34801561069d57600080fd5b506103ff610d17565b3480156106b257600080fd5b5061044c610d26565b3480156106c757600080fd5b506103ff610d2c565b3480156106dc57600080fd5b5061044c610d3b565b3480156106f157600080fd5b50610499610d41565b34801561070657600080fd5b506103ff610d4a565b34801561071b57600080fd5b506103ff61072a366004613dca565b610d59565b34801561073b57600080fd5b50610499610d74565b34801561075057600080fd5b5061044c61075f366004613dca565b610d9a565b34801561077057600080fd5b5061044c610dac565b34801561078557600080fd5b5061044c610db2565b34801561079a57600080fd5b5061044c610db8565b3480156107af57600080fd5b506107b8610dbe565b6040516103e19190614cfb565b3480156107d157600080fd5b5061044c6107e0366004613dca565b610dcd565b3480156107f157600080fd5b5061044c610800366004613dca565b610ddf565b34801561081157600080fd5b506103ff610df1565b34801561082657600080fd5b506103ff610e00565b34801561083b57600080fd5b5061044c61084a366004613dca565b610e0f565b34801561085b57600080fd5b5061086f61086a366004613f6c565b610e21565b6040516103e19c9b9a99989796959493929190614c48565b34801561089357600080fd5b506105106108a2366004613dca565b610e93565b3480156108b357600080fd5b506108c76108c2366004613f6c565b610f96565b6040516103e1989796959493929190614c05565b3480156108e757600080fd5b5061044c6108f6366004613de8565b610fe8565b34801561090757600080fd5b506103ff611005565b34801561091c57600080fd5b5061044c611014565b34801561093157600080fd5b5061044c610940366004613dca565b61101a565b34801561095157600080fd5b5061044c610960366004613e97565b61102c565b610978610973366004613ff6565b6110fa565b6040516103e1929190614f66565b34801561099257600080fd5b5061044c6109a1366004613e22565b6112fa565b3480156109b257600080fd5b506103ff61146e565b3480156109c757600080fd5b5061044c61147d565b3480156109dc57600080fd5b5061044c611483565b3480156109f157600080fd5b50610510610a00366004613dca565b611489565b348015610a1157600080fd5b5061044c6114b9565b348015610a2657600080fd5b5061044c6114bf565b348015610a3b57600080fd5b506103ff6114c5565b348015610a5057600080fd5b506103ff6114d4565b6009602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b6031546001600160a01b031681565b6005602052600090815260409020546001600160a01b031681565b603b60209081526000928352604080842090915290825290205481565b6023602052600090815260409020546001600160a01b031681565b60326020526000908152604090205460ff1681565b60008215610b6257610b2586868686866114e3565b9050600082610b3c57610b378261161c565b610b45565b610b4582611652565b90508015610b6057610b5d828263ffffffff61167616565b91505b505b95945050505050565b60185481565b601f5481565b603d5460ff1615610b9a5760405162461bcd60e51b81526004016103a690614d2a565b6000838152600660205260409020600a01546001600160a01b03163314610bd35760405162461bcd60e51b81526004016103a690614e6a565b610bdf833384846116a2565b505050565b6008602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b601a6020526000908152604090205481565b602a6020526000908152604090205481565b600a60209081526000928352604080842090915290825290205460ff1681565b60166020526000908152604090205481565b60155481565b60295481565b600c6020526000908152604090208054600182015460029092015490919083565b602b5481565b600b602090815260009283526040808420909152908252902080546001820154600283015460038401546004909401549293919290919085565b60266020526000908152604090205460ff1681565b6033602052600090815260409020546001600160a01b031681565b6003546001600160a01b031681565b60355481565b6002546001600160a01b031681565b601e5481565b603d5460ff1681565b6001546001600160a01b031690565b6022602052600090815260409020546001600160a01b031681565b6001546000906001600160a01b0316610d8b611717565b6001600160a01b031614905090565b60176020526000908152604090205481565b602c5481565b602f5481565b60205481565b602d546001600160a01b031681565b601d6020526000908152604090205481565b601c6020526000908152604090205481565b6037546001600160a01b031681565b6004546001600160a01b031681565b60366020526000908152604090205481565b600660208190526000918252604090912080546001820154600283015460038401546004850154600586015496860154600787015460088801546009890154600a8a0154600b909a0154989a9799969860ff909616979496949593949293919290916001600160a01b0391821691168c565b610e9b610d74565b610eb75760405162461bcd60e51b81526004016103a690614e6a565b633613289560e21b600081905260056020527fd3a886345208a8e3a0f774019653c4e69589e943ba1e46c7fa0ef875651e6e39546001600160a01b031690610eff908361171b565b610f106333d8991f60e01b8361171b565b610f2163d67f707760e01b8361171b565b610f3162977b2b60e61b8361171b565b610f4263e762319f60e01b8361171b565b6b4c6f616e4f70656e696e677360a01b826001600160a01b0316826001600160a01b03167f1420e3a2094d671bc2eb897941fa3d94ffa37f0cb6d530651946250a2151cb7f60405160405180910390a45050565b6007602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949560ff8516956101009095046001600160a01b03908116959481169493169288565b603c60209081526000928352604080842090915290825290205481565b6038546001600160a01b031681565b60275481565b60196020526000908152604090205481565b60006224ea008161105d6907baab4146b63dd00000611051868863ffffffff61179516565b9063ffffffff6117cf16565b9050600061107862015180611051858563ffffffff61179516565b9050600061108c898363ffffffff61181116565b905060006110998261161c565b905080156110b4576110b1828263ffffffff61181116565b91505b60006110c18d8d85611853565b9050806110d757600096505050505050506110f0565b6110e78a8263ffffffff61167616565b96505050505050505b9695505050505050565b60008060016000541461111f5760405162461bcd60e51b81526004016103a690614eda565b6002600055603d5460ff16156111475760405162461bcd60e51b81526004016103a690614d2a565b34158061115357508215155b61116f5760405162461bcd60e51b81526004016103a690614f0a565b336000908152602260205260409020546001600160a01b03166111a45760405162461bcd60e51b81526004016103a690614e4a565b6111ac613a9e565b5060008a815260076020908152604091829020825161010080820185528254808352600184015460ff811615159584019590955293046001600160a01b039081169482019490945260028201548416606082015260038201549093166080840152600481015460a0840152600581015460c08401526006015460e08301526112465760405162461bcd60e51b81526004016103a690614e9a565b60006112618260600151836080015189602001358c8e6114e3565b9050806112805760405162461bcd60e51b81526004016103a690614e3a565b6112e2828c8c848d611297368f90038f018f6140cf565b6112a6368f90038f018f6140ed565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118e992505050565b6001600055909d909c509a5050505050505050505050565b60008215610b62578115611324576113218368056bc75e2d6310000063ffffffff61167616565b92505b8360008361133a576113358261161c565b611343565b61134382611652565b9050801561135e5761135b828263ffffffff61181116565b91505b866001600160a01b0316886001600160a01b0316141561139c57611395856110518468056bc75e2d6310000063ffffffff61179516565b9250611463565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c906113d3908c908e906004016149e2565b604080518083038186803b1580156113ea57600080fd5b505afa1580156113fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611422919081019061412a565b91509150806000146114605761145d816110518981866114518a68056bc75e2d6310000063ffffffff61179516565b9063ffffffff61179516565b94505b50505b505095945050505050565b6014546001600160a01b031681565b601b5481565b60285481565b611491610d74565b6114ad5760405162461bcd60e51b81526004016103a690614e6a565b6114b681611be0565b50565b60395481565b60215481565b602e546001600160a01b031681565b6030546001600160a01b031681565b6000846001600160a01b0316866001600160a01b031614156115235761151c68056bc75e2d63100000611051868663ffffffff61179516565b90506115de565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c9061155a908a908c906004016149e2565b604080518083038186803b15801561157157600080fd5b505afa158015611585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115a9919081019061412a565b91509150816000146115db576115d868056bc75e2d631000006110518761145186838c8863ffffffff61179516565b92505b50505b8180156115ea57508015155b15610b62576110f081611610856110518368056bc75e2d6310000063ffffffff61179516565b9063ffffffff61167616565b600061164c68056bc75e2d631000006116406018548561179590919063ffffffff16565b9063ffffffff611c6216565b92915050565b600061164c68056bc75e2d63100000611640601b548561179590919063ffffffff16565b60008282018381101561169b5760405162461bcd60e51b81526004016103a690614d8a565b9392505050565b6000848152600a602090815260408083206001600160a01b038681168086529190935292819020805460ff1916851515179055519085169086907f0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c9843390611709908690614bf7565b60405180910390a450505050565b3390565b6001600160e01b03198216600090815260056020526040902080546001600160a01b0319166001600160a01b0383169081179091551561177657611770600d6001600160e01b0319841663ffffffff611ca416565b50611791565b610bdf600d6001600160e01b0319841663ffffffff611cec16565b5050565b6000826117a45750600061164c565b828202828482816117b157fe5b041461169b5760405162461bcd60e51b81526004016103a690614e5a565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611dad565b600061169b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611de4565b604051636dcd64e560e01b81526000907398399051DC17bAFb621269A12a63d70b2D615C6990636dcd64e59061189190879087908790600401614a32565b60206040518083038186803b1580156118a957600080fd5b505af41580156118bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118e1919081019061410c565b949350505050565b60008089606001516001600160a01b03168a608001516001600160a01b031614156119265760405162461bcd60e51b81526004016103a690614daa565b8960a0015186101561194a5760405162461bcd60e51b81526004016103a690614f2a565b60e08a015115158061195f5750604084015115155b61197b5760405162461bcd60e51b81526004016103a690614d4a565b60008861198957600061198f565b84602001515b90506000600660006119a88e8e8c8c8c60200151611e10565b8152602001908152602001600020905060006119d38d8389600001518a602001518b60400151612202565b60608801519091506119eb908263ffffffff61181116565b60608801528a15611a7b57606087015115611a185760405162461bcd60e51b81526004016103a690614e0a565b6000611a278860800151611652565b905060008e60800151905060008f60600151905082600014611a7357611a588b60200151866000015484848761241e565b60808a0151611a6d908463ffffffff61181116565b60808b01525b505050611a8b565b611a888c8e8a8a8a6124bd565b96505b60408051610180810182528354815260018401546020820152600284015491810191909152600383015460ff16151560608201526004830154608080830191909152600584015460a0830152600684015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b85015416610160830152880151611b35918f918c908e88612540565b611b515760405162461bcd60e51b81526004016103a690614e7a565b60808701516005830154611b6a9163ffffffff61167616565b60058301558a15611b94576007820154611b8a904263ffffffff61181116565b60e0880152611bb5565b611bae6f4b3b4ca85a86c47a098a2240000000008a6117cf565b6101008801525b611bc28d838a8a8f61265b565b86602001518760800151945094505050509850989650505050505050565b6001600160a01b038116611c065760405162461bcd60e51b81526004016103a690614d5a565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061292e565b6000611cb08383612978565b611ce4575060018083018054808301808355600092835260208084209092018590558483529085905260409091205561164c565b50600061164c565b6000611cf88383612978565b15611ce45760008281526020849052604090205460018401546000199182019101808214611d70576000856001018281548110611d3157fe5b9060005260206000200154905080866001018481548110611d4e57fe5b6000918252602080832090910192909255918252869052604090206001830190555b60008481526020869052604081205560018501805480611d8c57fe5b6001900381819060005260206000200160009055905560019250505061164c565b60008183611dce5760405162461bcd60e51b81526004016103a69190614d09565b506000838581611dda57fe5b0495945050505050565b60008184841115611e085760405162461bcd60e51b81526004016103a69190614d09565b505050900390565b60008560200151611e335760405162461bcd60e51b81526004016103a690614eca565b825160208401516060850151611e47613ae2565b88611f9e576001600160a01b0383166000908152602a60209081526040918290208054600101908190558c519251611e86939288928892909101614980565b60408051601f1981840301815291815281516020928301206000818152600690935291205490995015611ecb5760405162461bcd60e51b81526004016103a690614dfa565b5060408051610180810182528981528a5160208201526000918101829052600160608201526080810187905260a081018290524260c082015260e0810182905261010081018990526101208101919091526001600160a01b038084166101408301528416610160820152611f46600f8a63ffffffff611ca416565b506001600160a01b0384166000908152601160205260409020611f6f908a63ffffffff611ca416565b506001600160a01b0383166000908152601260205260409020611f98908a63ffffffff611ca416565b5061211f565b5060008881526006602081815260409283902083516101808101855281548152600182015492810192909252600281015493820193909352600383015460ff161580156060830181905260048501546080840152600585015460a08401529284015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b909401549093166101608201529161205857508060e0015142105b6120745760405162461bcd60e51b81526004016103a690614e1a565b826001600160a01b03168161014001516001600160a01b0316146120aa5760405162461bcd60e51b81526004016103a690614d7a565b836001600160a01b03168161016001516001600160a01b0316146120e05760405162461bcd60e51b81526004016103a690614dda565b89516020820151146121045760405162461bcd60e51b81526004016103a690614d1a565b6080810151612119908763ffffffff61167616565b60808201525b6001600160a01b0382161561213b5761213b89848460016116a2565b60008981526006602081815260409283902084518155908401516001820155918301516002830155606083015160038301805460ff19169115159190911790556080830151600483015560a0830151600583015560c08301519082015560e0820151600782015561010082015160088201556101208201516009820155610140820151600a820180546001600160a01b03199081166001600160a01b039384161790915561016090930151600b909201805490931691161790555095979650505050505050565b600b8401546060860151600091612224916001600160a01b039091169061298d565b84546000818152600c60209081526040808320600b808b01546001600160a01b03908116865290845282852060608d0180518316875294529190932060e08b0151925160808c0151600a8c0154959692956122859488949392911642612a6b565b6000811580156122985750600789015415155b156122c6576122c3620151806110518660000154611451428e6007015461181190919063ffffffff16565b90505b60006122e66907baab4146b63dd000006110518a8c63ffffffff61179516565b85549091506122fb908263ffffffff61167616565b85556001840154612312908263ffffffff61167616565b60018501558261238157845461233f90429061161090611051620151806114518d8963ffffffff61167616565b60078b01819055612356904263ffffffff61181116565b9250610e1083116123795760405162461bcd60e51b81526004016103a690614d9a565b8695506123c5565b60078a01546123a05761239a428463ffffffff61167616565b60078b01555b6123c26201518061105183611451428f6007015461181190919063ffffffff16565b95505b60018501546123da908763ffffffff61167616565b600186015583546123f1908963ffffffff61167616565b84556002840154612408908763ffffffff61167616565b8460020181905550505050505095945050505050565b80156124b6576001600160a01b0383166000908152601c602052604090205461244d908263ffffffff61167616565b6001600160a01b038085166000818152601c6020526040908190209390935591518692918816907ffb6c38ae4fdd498b3a5003f02ca4ca5340dfedb36b1b100c679eb60633b2c0a7906124a1908690614f58565b60405180910390a46124b68585858585612ab9565b5050505050565b6124c5613b46565b60006124ea87876060015188608001518860200151886060015160008060008b612f1f565b60c0870152506080850151909150612508908263ffffffff61167616565b608085015260a084015160c085015110156125355760405162461bcd60e51b81526004016103a690614d6a565b509195945050505050565b600061256868056bc75e2d631000006110518568055005f0c61448000063ffffffff61179516565b92508284101561264e5760a0860151156126465760025460608801516080808a0151908901516000936001600160a01b03169263f80b25fb9290916125b3908863ffffffff61181116565b8b60a001518b6040518663ffffffff1660e01b81526004016125d9959493929190614a82565b60206040518083038186803b1580156125f157600080fd5b505afa158015612605573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612629919081019061410c565b90508361263c868363ffffffff61167616565b10159150506110f0565b5060006110f0565b5060019695505050505050565b6002546060860151608087015160048088015460058901546040516317f8680960e11b815260009687966001600160a01b0390911695632ff0d012956126a5959294919301614a5a565b604080518083038186803b1580156126bc57600080fd5b505afa1580156126d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126f4919081019061412a565b915091508660c00151821161271b5760405162461bcd60e51b81526004016103a690614e8a565b4286600601541415612881576002546060880151608089015160405163524efd4b60e01b81526000936001600160a01b03169263524efd4b92612760926004016149e2565b60206040518083038186803b15801561277857600080fd5b505afa15801561278c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127b0919081019061410c565b60025460808a015160608b015160405163524efd4b60e01b81529394506000936001600160a01b039093169263524efd4b926127f09290916004016149e2565b60206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612840919081019061410c565b90506000612854838363ffffffff61179516565b9050856128765760c087015161287190829063ffffffff6117cf16565b612878565b835b60098a01555050505b60408051610180810182528754815260018801546020820152600288015491810191909152600387015460ff161515606082015260048701546080820152600587015460a0820152600687015460c0820152600787015460e082015260088701546101008201526009870154610120820152600a8701546001600160a01b03908116610140830152600b88015416610160820152612925908890878785878961307d565b50505050505050565b6000818361294f5760405162461bcd60e51b81526004016103a69190614d09565b508361295d5750600061169b565b600083600186038161296b57fe5b0460010195945050505050565b60009081526020919091526040902054151590565b6001600160a01b038083166000908152600b6020908152604080832093851683529290529081206001810154909190158015906129cd5750600482015415155b15612a5e576129f862015180611051846001015461145186600401544261181190919063ffffffff16565b4260048401556002830154909150811115612a14575060028101545b8015612a59576003820154612a2f908263ffffffff61167616565b60038301556002820154612a49908263ffffffff61181116565b6002830155612a598484836131b4565b612a65565b4260048301555b50505050565b6000612aa16a07259756a8d619980000006110516015546114518b600001546114518d600201548961181190919063ffffffff16565b60028801839055905080156129255761292583878787855b602f546002546001600160a01b038581166000908152603c602090815260408083208885168452909152812054909392919091169015612b1c576001600160a01b038087166000908152603c602090815260408083209389168352929052205491505b6037546000906060906001600160a01b038085169163d138f9a160e01b918b9116612b5a68056bc75e2d631000006110518c8b63ffffffff61179516565b604051602401612b6c93929190614a32565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612baa91906149c8565b600060405180830381855afa9150503d8060008114612be5576040519150601f19603f3d011682016040523d82523d6000602084013e612bea565b606091505b50915091506001821415612c0057602081015194505b6000306001600160a01b031663c22552f76040518163ffffffff1660e01b815260040160206040518083038186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c73919081019061410c565b90508515801590612c845750858110155b15612eac5760375460385460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392612cbf929116908a90600401614bc1565b602060405180830381600087803b158015612cd957600080fd5b505af1158015612ced573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d119190810190613f4e565b50603854603f546040516000926001600160a01b031691612d38918f918b91602401614bdc565b60408051601f198184030181529181526020820180516001600160e01b0316630efe6a8b60e01b17905251612d6d91906149c8565b6000604051808303816000865af19150503d8060008114612daa576040519150601f19603f3d011682016040523d82523d6000602084013e612daf565b606091505b505090508015612e3e57601f54612dcc908863ffffffff61167616565b601f819055508a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167ff41c644671512f1cda76abfe6038e3d7d526c1377a5a8c692f81703901db2150898b603f54604051612e3193929190614f74565b60405180910390a4612ea6565b8a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e710812898b603f54604051612e9d93929190614f74565b60405180910390a45b50612f12565b8515801590612eba57508581105b15612f1257603754603f546040518c926001600160a01b0390811692908f16917f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e71081291612f09918b918d91614f74565b60405180910390a45b5050505050505050505050565b6040805160a0810182526001600160a01b03808b16825289811660208084019190915230838501819052606080850191909152918a16608084015283519182018452888252810187905291820185905260009182918291612f8491908e888886613259565b9093509150612f938b8361347e565b600254602754604051631e2c62d360e01b81526001600160a01b0390921691631e2c62d391612fcc918f918f9188918a91600401614a82565b60206040518083038186803b158015612fe457600080fd5b505afa158015612ff8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061301c919081019061410c565b9050896001600160a01b03168b6001600160a01b03168d7fb4eb3c9b62efcce7021cba5fd9cd0c44df91c2272806ccc5e57df7c912e8d7168c868860405161306693929190614bdc565b60405180910390a499509950999650505050505050565b801561310657856000015185600001516001600160a01b031686602001516001600160a01b03167f7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f908a606001518b6080015189602001518a608001518b600001518c60e001518c8c6040516130f9989796959493929190614ac4565b60405180910390a4612925565b6131206f4b3b4ca85a86c47a098a224000000000836117cf565b9150856000015185600001516001600160a01b031686602001516001600160a01b03167ff640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c8a608001518b6060015189608001518a602001518b600001518e60e001518d60c001518e61010001518d6040516131a399989796959493929190614b3b565b60405180910390a450505050505050565b60006131d868056bc75e2d631000006110516015548561179590919063ffffffff16565b90506131e584848361354c565b6131ff83856131fa858563ffffffff61181116565b6135da565b6001600160a01b038085169084167f220e66e3e759e1382aa86cd8af5abca05ebf3ad564f223ae62d977678337272a61323e858563ffffffff61181116565b60405161324b9190614f58565b60405180910390a350505050565b845160009081901515806132705750602087015115155b61328c5760405162461bcd60e51b81526004016103a690614eba565b602087015161329d57865160208801525b6020870151875111156132c25760405162461bcd60e51b81526004016103a690614dea565b60008060008761337f5760408a015161333e5785156132f3576132ec8a60005b602002015161363d565b9050613307565b6133048a60005b602002015161161c565b90505b80156133395760808b01518b5161332a91908b908e60015b602002015185613661565b89516133369082611811565b8a525b61337f565b85156133565761334f8a60026132e2565b9050613364565b6133618a60026132fa565b90505b801561337f5760408a01516133799082611676565b60408b01525b86511561339e5760405162461bcd60e51b81526004016103a690614eea565b6133a88b8b6137b1565b60408c015191945092506133f457895182146133d65760405162461bcd60e51b81526004016103a690614f1a565b80156133ef576133ec828263ffffffff61167616565b91505b61346e565b60208a01518211156134185760405162461bcd60e51b81526004016103a690614dca565b60408a015183101561343c5760405162461bcd60e51b81526004016103a690614d3a565b801561346e5760808b015160208c015161345b91908b908e600061331f565b61346b838263ffffffff61181116565b92505b5090999098509650505050505050565b6029548015610bdf57602d546000906001600160a01b03858116911614156134a757508161352c565b600254604051635967aa7560e11b81526001600160a01b039091169063b2cf54ea906134d99087908790600401614bc1565b60206040518083038186803b1580156134f157600080fd5b505afa158015613505573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613529919081019061410c565b90505b81811115612a655760405162461bcd60e51b81526004016103a690614e2a565b8015610bdf576001600160a01b03821660009081526016602052604090205461357b908263ffffffff61167616565b6001600160a01b0380841660008181526016602052604090819020939093559151908516907f40a75ae5f7a5336e75f7c7977e12c4b46a9ac0f30de01a2d5b6c1a4f4af63587906135cd908590614f58565b60405180910390a3505050565b8015610bdf576135fa6001600160a01b038416838363ffffffff61389b16565b816001600160a01b0316836001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1836040516135cd9190614f58565b600061164c68056bc75e2d63100000611640603e548561179590919063ffffffff16565b8080156137a9576001600160a01b038681166000908152603360205260409020541615613717576001600160a01b038087166000908152603360205260409020546136af91168786846138f4565b50506137146136d668056bc75e2d631000006110516039548561179590919063ffffffff16565b6137086136fb68056bc75e2d631000006110516020548761179590919063ffffffff16565b849063ffffffff61181116565b9063ffffffff61181116565b90505b6001600160a01b038416600090815260196020526040902054613740908263ffffffff61167616565b6001600160a01b03808616600081815260196020526040908190209390935591518792918916907fb23479169712c443e6b00fb0cec3506a5f5926f541df4243d313e11c8c5c71ed90613794908690614f58565b60405180910390a46137a98686868686612ab9565b505050505050565b6000806137bc613b92565b84516001600160a01b039081168252602080870151821683820152604080880151831681850152606080890151909316928401929092528551608084015285015160a08301528481015160c0830152516335aaa79d60e01b81527398399051DC17bAFb621269A12a63d70b2D615C69906335aaa79d90613840908490600401614f4a565b604080518083038186803b15801561385757600080fd5b505af415801561386b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061388f919081019061412a565b90969095509350505050565b604051610bdf90849063a9059cbb60e01b906138bd9086908690602401614bc1565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613980565b6040516306a688ff60e11b815260009081903090630d4d11fe906139229089908990899089906004016149fd565b6040805180830381600087803b15801561393b57600080fd5b505af115801561394f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613973919081019061412a565b9097909650945050505050565b613992826001600160a01b0316613a65565b6139ae5760405162461bcd60e51b81526004016103a690614f3a565b60006060836001600160a01b0316836040516139ca91906149c8565b6000604051808303816000865af19150503d8060008114613a07576040519150601f19603f3d011682016040523d82523d6000602084013e613a0c565b606091505b509150915081613a2e5760405162461bcd60e51b81526004016103a690614dba565b805115612a655780806020019051613a499190810190613f4e565b612a655760405162461bcd60e51b81526004016103a690614efa565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906118e1575050151592915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b803561164c816150b4565b803561164c816150c8565b805161164c816150c8565b803561164c816150d1565b803561164c816150da565b60008083601f840112613c1757600080fd5b50813567ffffffffffffffff811115613c2f57600080fd5b602083019150836001820283011115613c4757600080fd5b9250929050565b600060808284031215613c6057600080fd5b50919050565b600060808284031215613c7857600080fd5b613c826080614ff7565b90506000613c908484613bce565b8252506020613ca184848301613bce565b6020830152506040613cb584828501613bce565b6040830152506060613cc984828501613bce565b60608301525092915050565b60006101208284031215613c6057600080fd5b60006101208284031215613cfb57600080fd5b613d06610120614ff7565b90506000613d148484613bef565b8252506020613d2584848301613bef565b6020830152506040613d3984828501613bef565b6040830152506060613d4d84828501613bef565b6060830152506080613d6184828501613bef565b60808301525060a0613d7584828501613bef565b60a08301525060c0613d8984828501613bef565b60c08301525060e0613d9d84828501613bef565b60e083015250610100613db284828501613bef565b6101008301525092915050565b805161164c816150d1565b600060208284031215613ddc57600080fd5b60006118e18484613bce565b60008060408385031215613dfb57600080fd5b6000613e078585613bce565b9250506020613e1885828601613bce565b9150509250929050565b600080600080600060a08688031215613e3a57600080fd5b6000613e468888613bce565b9550506020613e5788828901613bce565b9450506040613e6888828901613bef565b9350506060613e7988828901613bef565b9250506080613e8a88828901613bd9565b9150509295509295909350565b60008060008060008060c08789031215613eb057600080fd5b6000613ebc8989613bce565b9650506020613ecd89828a01613bce565b9550506040613ede89828a01613bef565b9450506060613eef89828a01613bef565b9350506080613f0089828a01613bef565b92505060a0613f1189828a01613bef565b9150509295509295509295565b60008060408385031215613f3157600080fd5b6000613f3d8585613bce565b9250506020613e1885828601613bef565b600060208284031215613f6057600080fd5b60006118e18484613be4565b600060208284031215613f7e57600080fd5b60006118e18484613bef565b60008060408385031215613f9d57600080fd5b6000613e078585613bef565b600080600060608486031215613fbe57600080fd5b6000613fca8686613bef565b9350506020613fdb86828701613bce565b9250506040613fec86828701613bd9565b9150509250925092565b600080600080600080600080610240898b03121561401357600080fd5b600061401f8b8b613bef565b98505060206140308b828c01613bef565b97505060406140418b828c01613bd9565b96505060606140528b828c01613bef565b95505060806140638b828c01613c4e565b9450506101006140758b828c01613cd5565b93505061022089013567ffffffffffffffff81111561409357600080fd5b61409f8b828c01613c05565b92509250509295985092959890939650565b6000602082840312156140c357600080fd5b60006118e18484613bfa565b6000608082840312156140e157600080fd5b60006118e18484613c66565b6000610120828403121561410057600080fd5b60006118e18484613ce8565b60006020828403121561411e57600080fd5b60006118e18484613dbf565b6000806040838503121561413d57600080fd5b60006141498585613dbf565b9250506020613e1885828601613dbf565b61416381615030565b82525050565b61416361417582615030565b615093565b6141638161503b565b61416381615040565b61416361419882615040565b615040565b60006141a88261501e565b6141b28185615022565b93506141c2818560208601615067565b9290920192915050565b6141638161505c565b60006141e08261501e565b6141ea8185615027565b93506141fa818560208601615067565b614203816150a4565b9093019392505050565b600061421a601383615027565b720d8dec2dca0c2e4c2dae640dad2e6dac2e8c6d606b1b815260200192915050565b6000614249600683615027565b6514185d5cd95960d21b815260200192915050565b600061426b601b83615027565b7f696e73756666696369656e742073776170206c69717569646974790000000000815260200192915050565b60006142a4601083615027565b6f1a5b9d985b1a59081a5b9d195c995cdd60821b815260200192915050565b60006142d0602683615027565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000614318601d83615027565b7f656e7472792070726963652061626f766520746865206d696e696d756d000000815260200192915050565b6000614351601183615027565b700c4dee4e4deeecae440dad2e6dac2e8c6d607b1b815260200192915050565b600061437e601b83615027565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006143b7600e83615027565b6d1b1bd85b881d1bdbc81cda1bdc9d60921b815260200192915050565b60006143e1601583615027565b740c6ded8d8c2e8cae4c2d85ed8dec2dc40dac2e8c6d605b1b815260200192915050565b6000614412602083615027565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061444b601383615027565b72737761702066696c6c20746f6f206c6172676560681b815260200192915050565b600061447a600f83615027565b6e0d8cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b60006144a5601c83615027565b7f736f75726365416d6f756e74206c6172676572207468616e206d617800000000815260200192915050565b60006144de600b83615027565b6a6c6f616e2065786973747360a81b815260200192915050565b6000614505601283615027565b7139bab938363ab9903637b0b7103a37b5b2b760711b815260200192915050565b6000614533600e83615027565b6d1b1bd85b881a185cc8195b99195960921b815260200192915050565b600061455d600e83615027565b6d7377617020746f6f206c6172676560901b815260200192915050565b6000614587600f83615027565b6e0636f6c6c61746572616c206973203608c1b815260200192915050565b60006145b2600e83615027565b6d1b9bdd08185d5d1a1bdc9a5e995960921b815260200192915050565b60006145dc602183615027565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b600061461f600c83615027565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6000614647601783615027565b7f636f6c6c61746572616c20696e73756666696369656e74000000000000000000815260200192915050565b6000614680601283615027565b713ab73432b0b63a343c903837b9b4ba34b7b760711b815260200192915050565b60006146ae601583615027565b746c6f616e506172616d73206e6f742065786973747360581b815260200192915050565b60006146df601483615027565b7319985b1b189858dac81b9bdd08185b1b1bddd95960621b815260200192915050565b600061470f602e83615027565b7f6d696e206f72206d617820736f7572636520746f6b656e20616d6f756e74206e81526d1959591cc81d1bc81899481cd95d60921b602082015260400192915050565b600061475f601383615027565b721b1bd85b94185c985b5cc8191a5cd8589b1959606a1b815260200192915050565b600061478e600c83615027565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b60006147b6600d83615027565b6c696e76616c696420737461746560981b815260200192915050565b60006147df602a83615027565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b600061482b602183615027565b7f6c6f616e446174614279746573207265717569726564207769746820657468658152603960f91b602082015260400192915050565b600061486e601683615027565b751cddd85c081d1bdbc81b185c99d9481d1bc8199a5b1b60521b815260200192915050565b60006148a0601583615027565b74696e697469616c4d617267696e20746f6f206c6f7760581b815260200192915050565b60006148d1601f83615027565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160e083019061490e848261415a565b506020820151614921602085018261415a565b506040820151614934604085018261415a565b506060820151614947606085018261415a565b50608082015161495a6080850182614183565b5060a082015161496d60a0850182614183565b5060c0820151612a6560c0850182614183565b600061498c828761418c565b60208201915061499c8286614169565b6014820191506149ac8285614169565b6014820191506149bc828461418c565b50602001949350505050565b600061169b828461419d565b6020810161164c828461415a565b604081016149f0828561415a565b61169b602083018461415a565b60808101614a0b828761415a565b614a18602083018661415a565b614a25604083018561415a565b610b626060830184614183565b60608101614a40828661415a565b614a4d602083018561415a565b6118e16040830184614183565b60808101614a68828761415a565b614a75602083018661415a565b614a256040830185614183565b60a08101614a90828861415a565b614a9d602083018761415a565b614aaa6040830186614183565b614ab76060830185614183565b6110f06080830184614183565b6101008101614ad3828b61415a565b614ae0602083018a61415a565b614aed6040830189614183565b614afa6060830188614183565b614b076080830187614183565b614b1460a0830186614183565b614b2160c0830185614183565b614b2e60e0830184614183565b9998505050505050505050565b6101208101614b4a828c61415a565b614b57602083018b61415a565b614b64604083018a614183565b614b716060830189614183565b614b7e6080830188614183565b614b8b60a0830187614183565b614b9860c0830186614183565b614ba560e0830185614183565b614bb3610100830184614183565b9a9950505050505050505050565b60408101614bcf828561415a565b61169b6020830184614183565b60608101614bea828661415a565b614a4d6020830185614183565b6020810161164c828461417a565b6101008101614c14828b614183565b614c21602083018a61417a565b614c2e604083018961415a565b614c3b606083018861415a565b614b07608083018761415a565b6101808101614c57828f614183565b614c64602083018e614183565b614c71604083018d614183565b614c7e606083018c61417a565b614c8b608083018b614183565b614c9860a083018a614183565b614ca560c0830189614183565b614cb260e0830188614183565b614cc0610100830187614183565b614cce610120830186614183565b614cdc61014083018561415a565b614cea61016083018461415a565b9d9c50505050505050505050505050565b6020810161164c82846141cc565b6020808252810161169b81846141d5565b6020808252810161164c8161420d565b6020808252810161164c8161423c565b6020808252810161164c8161425e565b6020808252810161164c81614297565b6020808252810161164c816142c3565b6020808252810161164c8161430b565b6020808252810161164c81614344565b6020808252810161164c81614371565b6020808252810161164c816143aa565b6020808252810161164c816143d4565b6020808252810161164c81614405565b6020808252810161164c8161443e565b6020808252810161164c8161446d565b6020808252810161164c81614498565b6020808252810161164c816144d1565b6020808252810161164c816144f8565b6020808252810161164c81614526565b6020808252810161164c81614550565b6020808252810161164c8161457a565b6020808252810161164c816145a5565b6020808252810161164c816145cf565b6020808252810161164c81614612565b6020808252810161164c8161463a565b6020808252810161164c81614673565b6020808252810161164c816146a1565b6020808252810161164c816146d2565b6020808252810161164c81614702565b6020808252810161164c81614752565b6020808252810161164c81614781565b6020808252810161164c816147a9565b6020808252810161164c816147d2565b6020808252810161164c8161481e565b6020808252810161164c81614861565b6020808252810161164c81614893565b6020808252810161164c816148c4565b60e0810161164c82846148fd565b6020810161164c8284614183565b60408101614bcf8285614183565b60608101614bea8286614183565b60a08101614f908288614183565b614a9d6020830187614183565b60c08101614fab8289614183565b614fb86020830188614183565b614fc56040830187614183565b614fd26060830186614183565b614fdf6080830185614183565b614fec60a0830184614183565b979650505050505050565b60405181810167ffffffffffffffff8111828210171561501657600080fd5b604052919050565b5190565b919050565b90815260200190565b600061164c82615050565b151590565b90565b6001600160e01b03191690565b6001600160a01b031690565b600061164c82615030565b60005b8381101561508257818101518382015260200161506a565b83811115612a655750506000910152565b600061164c82600061164c826150ae565b601f01601f191690565b60601b90565b6150bd81615030565b81146114b657600080fd5b6150bd8161503b565b6150bd81615040565b6150bd8161504356fea365627a7a7231582006262a07965035f357589c6bb924f7de44a817506b83c56eb712cec5934fdd626c6578706572696d656e74616cf564736f6c63430005110040", + "deployedBytecode": "0x6080604052600436106103815760003560e01c80638f32d59b116101d1578063cd5d808d11610102578063e8f62764116100a0578063f589a3e71161006f578063f589a3e714610a05578063f6ddc8b314610a1a578063f706b1f214610a2f578063f851a44014610a4457610381565b8063e8f62764146109a6578063edab119f146109bb578063f0e085f5146109d0578063f2fde38b146109e557610381565b8063d485045e116100dc578063d485045e14610925578063d67f707714610945578063d84ca25414610965578063e762319f1461098657610381565b8063cd5d808d146108db578063d288208c146108fb578063d473c2da1461091057610381565b8063b7e152411161016f578063bdee453c11610149578063bdee453c1461082f578063c4a908151461084f578063c4d66de814610887578063cb6eacd1146108a757610381565b8063b7e15241146107e5578063b9cffa3e14610805578063ba4861e91461081a57610381565b8063acc04348116101ab578063acc0434814610779578063ae0a85301461078e578063afe84009146107a3578063b30643d9146107c557610381565b80638f32d59b1461072f57806392d894f814610744578063959083d31461076457610381565b80634203e395116102b65780636e663730116102545780637a8faeb8116102235780637a8faeb8146106d05780638456cb59146106e55780638da5cb5b146106fa5780638dc48ba51461070f57610381565b80636e663730146106715780637420ca3e14610691578063742e6798146106a657806378d849ed146106bb57610381565b8063569fc1fb11610290578063569fc1fb146105dc578063574442cc1461060b57806362fff3f61461062057806368c4ac261461065157610381565b80634203e395146105925780634699f846146105b25780634f28cac2146105c757610381565b80632a324027116103235780633432423c116102fd5780633432423c146105125780633452d2d4146105325780633fca506e146105525780634115a2b61461057257610381565b80632a324027146104c65780632f470764146104db57806333d8991f146104f057610381565b80631b7bde741161035f5780631b7bde741461042c578063218b39c61461045957806324cc57491461047957806325decac0146104a657610381565b8063065d810f146103af5780630676c1b7146103ea57806317548b791461040c575b34801561038d57600080fd5b5060405162461bcd60e51b81526004016103a690614eaa565b60405180910390fd5b3480156103bb57600080fd5b506103cf6103ca366004613f1e565b610a59565b6040516103e196959493929190614f9d565b60405180910390f35b3480156103f657600080fd5b506103ff610a99565b6040516103e191906149d4565b34801561041857600080fd5b506103ff6104273660046140b1565b610aa8565b34801561043857600080fd5b5061044c610447366004613de8565b610ac3565b6040516103e19190614f58565b34801561046557600080fd5b506103ff610474366004613dca565b610ae0565b34801561048557600080fd5b50610499610494366004613dca565b610afb565b6040516103e19190614bf7565b3480156104b257600080fd5b5061044c6104c1366004613e22565b610b10565b3480156104d257600080fd5b5061044c610b6b565b3480156104e757600080fd5b5061044c610b71565b3480156104fc57600080fd5b5061051061050b366004613fa9565b610b77565b005b34801561051e57600080fd5b506103cf61052d366004613f1e565b610be4565b34801561053e57600080fd5b5061044c61054d366004613dca565b610c24565b34801561055e57600080fd5b5061044c61056d366004613dca565b610c36565b34801561057e57600080fd5b5061049961058d366004613f8a565b610c48565b34801561059e57600080fd5b5061044c6105ad366004613dca565b610c68565b3480156105be57600080fd5b5061044c610c7a565b3480156105d357600080fd5b5061044c610c80565b3480156105e857600080fd5b506105fc6105f7366004613f6c565b610c86565b6040516103e193929190614f74565b34801561061757600080fd5b5061044c610ca7565b34801561062c57600080fd5b5061064061063b366004613de8565b610cad565b6040516103e1959493929190614f82565b34801561065d57600080fd5b5061049961066c366004613dca565b610ce7565b34801561067d57600080fd5b506103ff61068c366004613dca565b610cfc565b34801561069d57600080fd5b506103ff610d17565b3480156106b257600080fd5b5061044c610d26565b3480156106c757600080fd5b506103ff610d2c565b3480156106dc57600080fd5b5061044c610d3b565b3480156106f157600080fd5b50610499610d41565b34801561070657600080fd5b506103ff610d4a565b34801561071b57600080fd5b506103ff61072a366004613dca565b610d59565b34801561073b57600080fd5b50610499610d74565b34801561075057600080fd5b5061044c61075f366004613dca565b610d9a565b34801561077057600080fd5b5061044c610dac565b34801561078557600080fd5b5061044c610db2565b34801561079a57600080fd5b5061044c610db8565b3480156107af57600080fd5b506107b8610dbe565b6040516103e19190614cfb565b3480156107d157600080fd5b5061044c6107e0366004613dca565b610dcd565b3480156107f157600080fd5b5061044c610800366004613dca565b610ddf565b34801561081157600080fd5b506103ff610df1565b34801561082657600080fd5b506103ff610e00565b34801561083b57600080fd5b5061044c61084a366004613dca565b610e0f565b34801561085b57600080fd5b5061086f61086a366004613f6c565b610e21565b6040516103e19c9b9a99989796959493929190614c48565b34801561089357600080fd5b506105106108a2366004613dca565b610e93565b3480156108b357600080fd5b506108c76108c2366004613f6c565b610f96565b6040516103e1989796959493929190614c05565b3480156108e757600080fd5b5061044c6108f6366004613de8565b610fe8565b34801561090757600080fd5b506103ff611005565b34801561091c57600080fd5b5061044c611014565b34801561093157600080fd5b5061044c610940366004613dca565b61101a565b34801561095157600080fd5b5061044c610960366004613e97565b61102c565b610978610973366004613ff6565b6110fa565b6040516103e1929190614f66565b34801561099257600080fd5b5061044c6109a1366004613e22565b6112fa565b3480156109b257600080fd5b506103ff61146e565b3480156109c757600080fd5b5061044c61147d565b3480156109dc57600080fd5b5061044c611483565b3480156109f157600080fd5b50610510610a00366004613dca565b611489565b348015610a1157600080fd5b5061044c6114b9565b348015610a2657600080fd5b5061044c6114bf565b348015610a3b57600080fd5b506103ff6114c5565b348015610a5057600080fd5b506103ff6114d4565b6009602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b6031546001600160a01b031681565b6005602052600090815260409020546001600160a01b031681565b603b60209081526000928352604080842090915290825290205481565b6023602052600090815260409020546001600160a01b031681565b60326020526000908152604090205460ff1681565b60008215610b6257610b2586868686866114e3565b9050600082610b3c57610b378261161c565b610b45565b610b4582611652565b90508015610b6057610b5d828263ffffffff61167616565b91505b505b95945050505050565b60185481565b601f5481565b603d5460ff1615610b9a5760405162461bcd60e51b81526004016103a690614d2a565b6000838152600660205260409020600a01546001600160a01b03163314610bd35760405162461bcd60e51b81526004016103a690614e6a565b610bdf833384846116a2565b505050565b6008602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b601a6020526000908152604090205481565b602a6020526000908152604090205481565b600a60209081526000928352604080842090915290825290205460ff1681565b60166020526000908152604090205481565b60155481565b60295481565b600c6020526000908152604090208054600182015460029092015490919083565b602b5481565b600b602090815260009283526040808420909152908252902080546001820154600283015460038401546004909401549293919290919085565b60266020526000908152604090205460ff1681565b6033602052600090815260409020546001600160a01b031681565b6003546001600160a01b031681565b60355481565b6002546001600160a01b031681565b601e5481565b603d5460ff1681565b6001546001600160a01b031690565b6022602052600090815260409020546001600160a01b031681565b6001546000906001600160a01b0316610d8b611717565b6001600160a01b031614905090565b60176020526000908152604090205481565b602c5481565b602f5481565b60205481565b602d546001600160a01b031681565b601d6020526000908152604090205481565b601c6020526000908152604090205481565b6037546001600160a01b031681565b6004546001600160a01b031681565b60366020526000908152604090205481565b600660208190526000918252604090912080546001820154600283015460038401546004850154600586015496860154600787015460088801546009890154600a8a0154600b909a0154989a9799969860ff909616979496949593949293919290916001600160a01b0391821691168c565b610e9b610d74565b610eb75760405162461bcd60e51b81526004016103a690614e6a565b633613289560e21b600081905260056020527fd3a886345208a8e3a0f774019653c4e69589e943ba1e46c7fa0ef875651e6e39546001600160a01b031690610eff908361171b565b610f106333d8991f60e01b8361171b565b610f2163d67f707760e01b8361171b565b610f3162977b2b60e61b8361171b565b610f4263e762319f60e01b8361171b565b6b4c6f616e4f70656e696e677360a01b826001600160a01b0316826001600160a01b03167f1420e3a2094d671bc2eb897941fa3d94ffa37f0cb6d530651946250a2151cb7f60405160405180910390a45050565b6007602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949560ff8516956101009095046001600160a01b03908116959481169493169288565b603c60209081526000928352604080842090915290825290205481565b6038546001600160a01b031681565b60275481565b60196020526000908152604090205481565b60006224ea008161105d6907baab4146b63dd00000611051868863ffffffff61179516565b9063ffffffff6117cf16565b9050600061107862015180611051858563ffffffff61179516565b9050600061108c898363ffffffff61181116565b905060006110998261161c565b905080156110b4576110b1828263ffffffff61181116565b91505b60006110c18d8d85611853565b9050806110d757600096505050505050506110f0565b6110e78a8263ffffffff61167616565b96505050505050505b9695505050505050565b60008060016000541461111f5760405162461bcd60e51b81526004016103a690614eda565b6002600055603d5460ff16156111475760405162461bcd60e51b81526004016103a690614d2a565b34158061115357508215155b61116f5760405162461bcd60e51b81526004016103a690614f0a565b336000908152602260205260409020546001600160a01b03166111a45760405162461bcd60e51b81526004016103a690614e4a565b6111ac613a9e565b5060008a815260076020908152604091829020825161010080820185528254808352600184015460ff811615159584019590955293046001600160a01b039081169482019490945260028201548416606082015260038201549093166080840152600481015460a0840152600581015460c08401526006015460e08301526112465760405162461bcd60e51b81526004016103a690614e9a565b60006112618260600151836080015189602001358c8e6114e3565b9050806112805760405162461bcd60e51b81526004016103a690614e3a565b6112e2828c8c848d611297368f90038f018f6140cf565b6112a6368f90038f018f6140ed565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118e992505050565b6001600055909d909c509a5050505050505050505050565b60008215610b62578115611324576113218368056bc75e2d6310000063ffffffff61167616565b92505b8360008361133a576113358261161c565b611343565b61134382611652565b9050801561135e5761135b828263ffffffff61181116565b91505b866001600160a01b0316886001600160a01b0316141561139c57611395856110518468056bc75e2d6310000063ffffffff61179516565b9250611463565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c906113d3908c908e906004016149e2565b604080518083038186803b1580156113ea57600080fd5b505afa1580156113fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611422919081019061412a565b91509150806000146114605761145d816110518981866114518a68056bc75e2d6310000063ffffffff61179516565b9063ffffffff61179516565b94505b50505b505095945050505050565b6014546001600160a01b031681565b601b5481565b60285481565b611491610d74565b6114ad5760405162461bcd60e51b81526004016103a690614e6a565b6114b681611be0565b50565b60395481565b60215481565b602e546001600160a01b031681565b6030546001600160a01b031681565b6000846001600160a01b0316866001600160a01b031614156115235761151c68056bc75e2d63100000611051868663ffffffff61179516565b90506115de565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c9061155a908a908c906004016149e2565b604080518083038186803b15801561157157600080fd5b505afa158015611585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115a9919081019061412a565b91509150816000146115db576115d868056bc75e2d631000006110518761145186838c8863ffffffff61179516565b92505b50505b8180156115ea57508015155b15610b62576110f081611610856110518368056bc75e2d6310000063ffffffff61179516565b9063ffffffff61167616565b600061164c68056bc75e2d631000006116406018548561179590919063ffffffff16565b9063ffffffff611c6216565b92915050565b600061164c68056bc75e2d63100000611640601b548561179590919063ffffffff16565b60008282018381101561169b5760405162461bcd60e51b81526004016103a690614d8a565b9392505050565b6000848152600a602090815260408083206001600160a01b038681168086529190935292819020805460ff1916851515179055519085169086907f0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c9843390611709908690614bf7565b60405180910390a450505050565b3390565b6001600160e01b03198216600090815260056020526040902080546001600160a01b0319166001600160a01b0383169081179091551561177657611770600d6001600160e01b0319841663ffffffff611ca416565b50611791565b610bdf600d6001600160e01b0319841663ffffffff611cec16565b5050565b6000826117a45750600061164c565b828202828482816117b157fe5b041461169b5760405162461bcd60e51b81526004016103a690614e5a565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611dad565b600061169b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611de4565b604051636dcd64e560e01b815260009073__$6b3065420287e4be5d93089ad806c078e3$__90636dcd64e59061189190879087908790600401614a32565b60206040518083038186803b1580156118a957600080fd5b505af41580156118bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118e1919081019061410c565b949350505050565b60008089606001516001600160a01b03168a608001516001600160a01b031614156119265760405162461bcd60e51b81526004016103a690614daa565b8960a0015186101561194a5760405162461bcd60e51b81526004016103a690614f2a565b60e08a015115158061195f5750604084015115155b61197b5760405162461bcd60e51b81526004016103a690614d4a565b60008861198957600061198f565b84602001515b90506000600660006119a88e8e8c8c8c60200151611e10565b8152602001908152602001600020905060006119d38d8389600001518a602001518b60400151612202565b60608801519091506119eb908263ffffffff61181116565b60608801528a15611a7b57606087015115611a185760405162461bcd60e51b81526004016103a690614e0a565b6000611a278860800151611652565b905060008e60800151905060008f60600151905082600014611a7357611a588b60200151866000015484848761241e565b60808a0151611a6d908463ffffffff61181116565b60808b01525b505050611a8b565b611a888c8e8a8a8a6124bd565b96505b60408051610180810182528354815260018401546020820152600284015491810191909152600383015460ff16151560608201526004830154608080830191909152600584015460a0830152600684015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b85015416610160830152880151611b35918f918c908e88612540565b611b515760405162461bcd60e51b81526004016103a690614e7a565b60808701516005830154611b6a9163ffffffff61167616565b60058301558a15611b94576007820154611b8a904263ffffffff61181116565b60e0880152611bb5565b611bae6f4b3b4ca85a86c47a098a2240000000008a6117cf565b6101008801525b611bc28d838a8a8f61265b565b86602001518760800151945094505050509850989650505050505050565b6001600160a01b038116611c065760405162461bcd60e51b81526004016103a690614d5a565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061292e565b6000611cb08383612978565b611ce4575060018083018054808301808355600092835260208084209092018590558483529085905260409091205561164c565b50600061164c565b6000611cf88383612978565b15611ce45760008281526020849052604090205460018401546000199182019101808214611d70576000856001018281548110611d3157fe5b9060005260206000200154905080866001018481548110611d4e57fe5b6000918252602080832090910192909255918252869052604090206001830190555b60008481526020869052604081205560018501805480611d8c57fe5b6001900381819060005260206000200160009055905560019250505061164c565b60008183611dce5760405162461bcd60e51b81526004016103a69190614d09565b506000838581611dda57fe5b0495945050505050565b60008184841115611e085760405162461bcd60e51b81526004016103a69190614d09565b505050900390565b60008560200151611e335760405162461bcd60e51b81526004016103a690614eca565b825160208401516060850151611e47613ae2565b88611f9e576001600160a01b0383166000908152602a60209081526040918290208054600101908190558c519251611e86939288928892909101614980565b60408051601f1981840301815291815281516020928301206000818152600690935291205490995015611ecb5760405162461bcd60e51b81526004016103a690614dfa565b5060408051610180810182528981528a5160208201526000918101829052600160608201526080810187905260a081018290524260c082015260e0810182905261010081018990526101208101919091526001600160a01b038084166101408301528416610160820152611f46600f8a63ffffffff611ca416565b506001600160a01b0384166000908152601160205260409020611f6f908a63ffffffff611ca416565b506001600160a01b0383166000908152601260205260409020611f98908a63ffffffff611ca416565b5061211f565b5060008881526006602081815260409283902083516101808101855281548152600182015492810192909252600281015493820193909352600383015460ff161580156060830181905260048501546080840152600585015460a08401529284015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b909401549093166101608201529161205857508060e0015142105b6120745760405162461bcd60e51b81526004016103a690614e1a565b826001600160a01b03168161014001516001600160a01b0316146120aa5760405162461bcd60e51b81526004016103a690614d7a565b836001600160a01b03168161016001516001600160a01b0316146120e05760405162461bcd60e51b81526004016103a690614dda565b89516020820151146121045760405162461bcd60e51b81526004016103a690614d1a565b6080810151612119908763ffffffff61167616565b60808201525b6001600160a01b0382161561213b5761213b89848460016116a2565b60008981526006602081815260409283902084518155908401516001820155918301516002830155606083015160038301805460ff19169115159190911790556080830151600483015560a0830151600583015560c08301519082015560e0820151600782015561010082015160088201556101208201516009820155610140820151600a820180546001600160a01b03199081166001600160a01b039384161790915561016090930151600b909201805490931691161790555095979650505050505050565b600b8401546060860151600091612224916001600160a01b039091169061298d565b84546000818152600c60209081526040808320600b808b01546001600160a01b03908116865290845282852060608d0180518316875294529190932060e08b0151925160808c0151600a8c0154959692956122859488949392911642612a6b565b6000811580156122985750600789015415155b156122c6576122c3620151806110518660000154611451428e6007015461181190919063ffffffff16565b90505b60006122e66907baab4146b63dd000006110518a8c63ffffffff61179516565b85549091506122fb908263ffffffff61167616565b85556001840154612312908263ffffffff61167616565b60018501558261238157845461233f90429061161090611051620151806114518d8963ffffffff61167616565b60078b01819055612356904263ffffffff61181116565b9250610e1083116123795760405162461bcd60e51b81526004016103a690614d9a565b8695506123c5565b60078a01546123a05761239a428463ffffffff61167616565b60078b01555b6123c26201518061105183611451428f6007015461181190919063ffffffff16565b95505b60018501546123da908763ffffffff61167616565b600186015583546123f1908963ffffffff61167616565b84556002840154612408908763ffffffff61167616565b8460020181905550505050505095945050505050565b80156124b6576001600160a01b0383166000908152601c602052604090205461244d908263ffffffff61167616565b6001600160a01b038085166000818152601c6020526040908190209390935591518692918816907ffb6c38ae4fdd498b3a5003f02ca4ca5340dfedb36b1b100c679eb60633b2c0a7906124a1908690614f58565b60405180910390a46124b68585858585612ab9565b5050505050565b6124c5613b46565b60006124ea87876060015188608001518860200151886060015160008060008b612f1f565b60c0870152506080850151909150612508908263ffffffff61167616565b608085015260a084015160c085015110156125355760405162461bcd60e51b81526004016103a690614d6a565b509195945050505050565b600061256868056bc75e2d631000006110518568055005f0c61448000063ffffffff61179516565b92508284101561264e5760a0860151156126465760025460608801516080808a0151908901516000936001600160a01b03169263f80b25fb9290916125b3908863ffffffff61181116565b8b60a001518b6040518663ffffffff1660e01b81526004016125d9959493929190614a82565b60206040518083038186803b1580156125f157600080fd5b505afa158015612605573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612629919081019061410c565b90508361263c868363ffffffff61167616565b10159150506110f0565b5060006110f0565b5060019695505050505050565b6002546060860151608087015160048088015460058901546040516317f8680960e11b815260009687966001600160a01b0390911695632ff0d012956126a5959294919301614a5a565b604080518083038186803b1580156126bc57600080fd5b505afa1580156126d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126f4919081019061412a565b915091508660c00151821161271b5760405162461bcd60e51b81526004016103a690614e8a565b4286600601541415612881576002546060880151608089015160405163524efd4b60e01b81526000936001600160a01b03169263524efd4b92612760926004016149e2565b60206040518083038186803b15801561277857600080fd5b505afa15801561278c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127b0919081019061410c565b60025460808a015160608b015160405163524efd4b60e01b81529394506000936001600160a01b039093169263524efd4b926127f09290916004016149e2565b60206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612840919081019061410c565b90506000612854838363ffffffff61179516565b9050856128765760c087015161287190829063ffffffff6117cf16565b612878565b835b60098a01555050505b60408051610180810182528754815260018801546020820152600288015491810191909152600387015460ff161515606082015260048701546080820152600587015460a0820152600687015460c0820152600787015460e082015260088701546101008201526009870154610120820152600a8701546001600160a01b03908116610140830152600b88015416610160820152612925908890878785878961307d565b50505050505050565b6000818361294f5760405162461bcd60e51b81526004016103a69190614d09565b508361295d5750600061169b565b600083600186038161296b57fe5b0460010195945050505050565b60009081526020919091526040902054151590565b6001600160a01b038083166000908152600b6020908152604080832093851683529290529081206001810154909190158015906129cd5750600482015415155b15612a5e576129f862015180611051846001015461145186600401544261181190919063ffffffff16565b4260048401556002830154909150811115612a14575060028101545b8015612a59576003820154612a2f908263ffffffff61167616565b60038301556002820154612a49908263ffffffff61181116565b6002830155612a598484836131b4565b612a65565b4260048301555b50505050565b6000612aa16a07259756a8d619980000006110516015546114518b600001546114518d600201548961181190919063ffffffff16565b60028801839055905080156129255761292583878787855b602f546002546001600160a01b038581166000908152603c602090815260408083208885168452909152812054909392919091169015612b1c576001600160a01b038087166000908152603c602090815260408083209389168352929052205491505b6037546000906060906001600160a01b038085169163d138f9a160e01b918b9116612b5a68056bc75e2d631000006110518c8b63ffffffff61179516565b604051602401612b6c93929190614a32565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612baa91906149c8565b600060405180830381855afa9150503d8060008114612be5576040519150601f19603f3d011682016040523d82523d6000602084013e612bea565b606091505b50915091506001821415612c0057602081015194505b6000306001600160a01b031663c22552f76040518163ffffffff1660e01b815260040160206040518083038186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c73919081019061410c565b90508515801590612c845750858110155b15612eac5760375460385460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392612cbf929116908a90600401614bc1565b602060405180830381600087803b158015612cd957600080fd5b505af1158015612ced573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d119190810190613f4e565b50603854603f546040516000926001600160a01b031691612d38918f918b91602401614bdc565b60408051601f198184030181529181526020820180516001600160e01b0316630efe6a8b60e01b17905251612d6d91906149c8565b6000604051808303816000865af19150503d8060008114612daa576040519150601f19603f3d011682016040523d82523d6000602084013e612daf565b606091505b505090508015612e3e57601f54612dcc908863ffffffff61167616565b601f819055508a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167ff41c644671512f1cda76abfe6038e3d7d526c1377a5a8c692f81703901db2150898b603f54604051612e3193929190614f74565b60405180910390a4612ea6565b8a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e710812898b603f54604051612e9d93929190614f74565b60405180910390a45b50612f12565b8515801590612eba57508581105b15612f1257603754603f546040518c926001600160a01b0390811692908f16917f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e71081291612f09918b918d91614f74565b60405180910390a45b5050505050505050505050565b6040805160a0810182526001600160a01b03808b16825289811660208084019190915230838501819052606080850191909152918a16608084015283519182018452888252810187905291820185905260009182918291612f8491908e888886613259565b9093509150612f938b8361347e565b600254602754604051631e2c62d360e01b81526001600160a01b0390921691631e2c62d391612fcc918f918f9188918a91600401614a82565b60206040518083038186803b158015612fe457600080fd5b505afa158015612ff8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061301c919081019061410c565b9050896001600160a01b03168b6001600160a01b03168d7fb4eb3c9b62efcce7021cba5fd9cd0c44df91c2272806ccc5e57df7c912e8d7168c868860405161306693929190614bdc565b60405180910390a499509950999650505050505050565b801561310657856000015185600001516001600160a01b031686602001516001600160a01b03167f7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f908a606001518b6080015189602001518a608001518b600001518c60e001518c8c6040516130f9989796959493929190614ac4565b60405180910390a4612925565b6131206f4b3b4ca85a86c47a098a224000000000836117cf565b9150856000015185600001516001600160a01b031686602001516001600160a01b03167ff640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c8a608001518b6060015189608001518a602001518b600001518e60e001518d60c001518e61010001518d6040516131a399989796959493929190614b3b565b60405180910390a450505050505050565b60006131d868056bc75e2d631000006110516015548561179590919063ffffffff16565b90506131e584848361354c565b6131ff83856131fa858563ffffffff61181116565b6135da565b6001600160a01b038085169084167f220e66e3e759e1382aa86cd8af5abca05ebf3ad564f223ae62d977678337272a61323e858563ffffffff61181116565b60405161324b9190614f58565b60405180910390a350505050565b845160009081901515806132705750602087015115155b61328c5760405162461bcd60e51b81526004016103a690614eba565b602087015161329d57865160208801525b6020870151875111156132c25760405162461bcd60e51b81526004016103a690614dea565b60008060008761337f5760408a015161333e5785156132f3576132ec8a60005b602002015161363d565b9050613307565b6133048a60005b602002015161161c565b90505b80156133395760808b01518b5161332a91908b908e60015b602002015185613661565b89516133369082611811565b8a525b61337f565b85156133565761334f8a60026132e2565b9050613364565b6133618a60026132fa565b90505b801561337f5760408a01516133799082611676565b60408b01525b86511561339e5760405162461bcd60e51b81526004016103a690614eea565b6133a88b8b6137b1565b60408c015191945092506133f457895182146133d65760405162461bcd60e51b81526004016103a690614f1a565b80156133ef576133ec828263ffffffff61167616565b91505b61346e565b60208a01518211156134185760405162461bcd60e51b81526004016103a690614dca565b60408a015183101561343c5760405162461bcd60e51b81526004016103a690614d3a565b801561346e5760808b015160208c015161345b91908b908e600061331f565b61346b838263ffffffff61181116565b92505b5090999098509650505050505050565b6029548015610bdf57602d546000906001600160a01b03858116911614156134a757508161352c565b600254604051635967aa7560e11b81526001600160a01b039091169063b2cf54ea906134d99087908790600401614bc1565b60206040518083038186803b1580156134f157600080fd5b505afa158015613505573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613529919081019061410c565b90505b81811115612a655760405162461bcd60e51b81526004016103a690614e2a565b8015610bdf576001600160a01b03821660009081526016602052604090205461357b908263ffffffff61167616565b6001600160a01b0380841660008181526016602052604090819020939093559151908516907f40a75ae5f7a5336e75f7c7977e12c4b46a9ac0f30de01a2d5b6c1a4f4af63587906135cd908590614f58565b60405180910390a3505050565b8015610bdf576135fa6001600160a01b038416838363ffffffff61389b16565b816001600160a01b0316836001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1836040516135cd9190614f58565b600061164c68056bc75e2d63100000611640603e548561179590919063ffffffff16565b8080156137a9576001600160a01b038681166000908152603360205260409020541615613717576001600160a01b038087166000908152603360205260409020546136af91168786846138f4565b50506137146136d668056bc75e2d631000006110516039548561179590919063ffffffff16565b6137086136fb68056bc75e2d631000006110516020548761179590919063ffffffff16565b849063ffffffff61181116565b9063ffffffff61181116565b90505b6001600160a01b038416600090815260196020526040902054613740908263ffffffff61167616565b6001600160a01b03808616600081815260196020526040908190209390935591518792918916907fb23479169712c443e6b00fb0cec3506a5f5926f541df4243d313e11c8c5c71ed90613794908690614f58565b60405180910390a46137a98686868686612ab9565b505050505050565b6000806137bc613b92565b84516001600160a01b039081168252602080870151821683820152604080880151831681850152606080890151909316928401929092528551608084015285015160a08301528481015160c0830152516335aaa79d60e01b815273__$6b3065420287e4be5d93089ad806c078e3$__906335aaa79d90613840908490600401614f4a565b604080518083038186803b15801561385757600080fd5b505af415801561386b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061388f919081019061412a565b90969095509350505050565b604051610bdf90849063a9059cbb60e01b906138bd9086908690602401614bc1565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613980565b6040516306a688ff60e11b815260009081903090630d4d11fe906139229089908990899089906004016149fd565b6040805180830381600087803b15801561393b57600080fd5b505af115801561394f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613973919081019061412a565b9097909650945050505050565b613992826001600160a01b0316613a65565b6139ae5760405162461bcd60e51b81526004016103a690614f3a565b60006060836001600160a01b0316836040516139ca91906149c8565b6000604051808303816000865af19150503d8060008114613a07576040519150601f19603f3d011682016040523d82523d6000602084013e613a0c565b606091505b509150915081613a2e5760405162461bcd60e51b81526004016103a690614dba565b805115612a655780806020019051613a499190810190613f4e565b612a655760405162461bcd60e51b81526004016103a690614efa565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906118e1575050151592915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b803561164c816150b4565b803561164c816150c8565b805161164c816150c8565b803561164c816150d1565b803561164c816150da565b60008083601f840112613c1757600080fd5b50813567ffffffffffffffff811115613c2f57600080fd5b602083019150836001820283011115613c4757600080fd5b9250929050565b600060808284031215613c6057600080fd5b50919050565b600060808284031215613c7857600080fd5b613c826080614ff7565b90506000613c908484613bce565b8252506020613ca184848301613bce565b6020830152506040613cb584828501613bce565b6040830152506060613cc984828501613bce565b60608301525092915050565b60006101208284031215613c6057600080fd5b60006101208284031215613cfb57600080fd5b613d06610120614ff7565b90506000613d148484613bef565b8252506020613d2584848301613bef565b6020830152506040613d3984828501613bef565b6040830152506060613d4d84828501613bef565b6060830152506080613d6184828501613bef565b60808301525060a0613d7584828501613bef565b60a08301525060c0613d8984828501613bef565b60c08301525060e0613d9d84828501613bef565b60e083015250610100613db284828501613bef565b6101008301525092915050565b805161164c816150d1565b600060208284031215613ddc57600080fd5b60006118e18484613bce565b60008060408385031215613dfb57600080fd5b6000613e078585613bce565b9250506020613e1885828601613bce565b9150509250929050565b600080600080600060a08688031215613e3a57600080fd5b6000613e468888613bce565b9550506020613e5788828901613bce565b9450506040613e6888828901613bef565b9350506060613e7988828901613bef565b9250506080613e8a88828901613bd9565b9150509295509295909350565b60008060008060008060c08789031215613eb057600080fd5b6000613ebc8989613bce565b9650506020613ecd89828a01613bce565b9550506040613ede89828a01613bef565b9450506060613eef89828a01613bef565b9350506080613f0089828a01613bef565b92505060a0613f1189828a01613bef565b9150509295509295509295565b60008060408385031215613f3157600080fd5b6000613f3d8585613bce565b9250506020613e1885828601613bef565b600060208284031215613f6057600080fd5b60006118e18484613be4565b600060208284031215613f7e57600080fd5b60006118e18484613bef565b60008060408385031215613f9d57600080fd5b6000613e078585613bef565b600080600060608486031215613fbe57600080fd5b6000613fca8686613bef565b9350506020613fdb86828701613bce565b9250506040613fec86828701613bd9565b9150509250925092565b600080600080600080600080610240898b03121561401357600080fd5b600061401f8b8b613bef565b98505060206140308b828c01613bef565b97505060406140418b828c01613bd9565b96505060606140528b828c01613bef565b95505060806140638b828c01613c4e565b9450506101006140758b828c01613cd5565b93505061022089013567ffffffffffffffff81111561409357600080fd5b61409f8b828c01613c05565b92509250509295985092959890939650565b6000602082840312156140c357600080fd5b60006118e18484613bfa565b6000608082840312156140e157600080fd5b60006118e18484613c66565b6000610120828403121561410057600080fd5b60006118e18484613ce8565b60006020828403121561411e57600080fd5b60006118e18484613dbf565b6000806040838503121561413d57600080fd5b60006141498585613dbf565b9250506020613e1885828601613dbf565b61416381615030565b82525050565b61416361417582615030565b615093565b6141638161503b565b61416381615040565b61416361419882615040565b615040565b60006141a88261501e565b6141b28185615022565b93506141c2818560208601615067565b9290920192915050565b6141638161505c565b60006141e08261501e565b6141ea8185615027565b93506141fa818560208601615067565b614203816150a4565b9093019392505050565b600061421a601383615027565b720d8dec2dca0c2e4c2dae640dad2e6dac2e8c6d606b1b815260200192915050565b6000614249600683615027565b6514185d5cd95960d21b815260200192915050565b600061426b601b83615027565b7f696e73756666696369656e742073776170206c69717569646974790000000000815260200192915050565b60006142a4601083615027565b6f1a5b9d985b1a59081a5b9d195c995cdd60821b815260200192915050565b60006142d0602683615027565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000614318601d83615027565b7f656e7472792070726963652061626f766520746865206d696e696d756d000000815260200192915050565b6000614351601183615027565b700c4dee4e4deeecae440dad2e6dac2e8c6d607b1b815260200192915050565b600061437e601b83615027565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006143b7600e83615027565b6d1b1bd85b881d1bdbc81cda1bdc9d60921b815260200192915050565b60006143e1601583615027565b740c6ded8d8c2e8cae4c2d85ed8dec2dc40dac2e8c6d605b1b815260200192915050565b6000614412602083615027565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061444b601383615027565b72737761702066696c6c20746f6f206c6172676560681b815260200192915050565b600061447a600f83615027565b6e0d8cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b60006144a5601c83615027565b7f736f75726365416d6f756e74206c6172676572207468616e206d617800000000815260200192915050565b60006144de600b83615027565b6a6c6f616e2065786973747360a81b815260200192915050565b6000614505601283615027565b7139bab938363ab9903637b0b7103a37b5b2b760711b815260200192915050565b6000614533600e83615027565b6d1b1bd85b881a185cc8195b99195960921b815260200192915050565b600061455d600e83615027565b6d7377617020746f6f206c6172676560901b815260200192915050565b6000614587600f83615027565b6e0636f6c6c61746572616c206973203608c1b815260200192915050565b60006145b2600e83615027565b6d1b9bdd08185d5d1a1bdc9a5e995960921b815260200192915050565b60006145dc602183615027565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b600061461f600c83615027565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6000614647601783615027565b7f636f6c6c61746572616c20696e73756666696369656e74000000000000000000815260200192915050565b6000614680601283615027565b713ab73432b0b63a343c903837b9b4ba34b7b760711b815260200192915050565b60006146ae601583615027565b746c6f616e506172616d73206e6f742065786973747360581b815260200192915050565b60006146df601483615027565b7319985b1b189858dac81b9bdd08185b1b1bddd95960621b815260200192915050565b600061470f602e83615027565b7f6d696e206f72206d617820736f7572636520746f6b656e20616d6f756e74206e81526d1959591cc81d1bc81899481cd95d60921b602082015260400192915050565b600061475f601383615027565b721b1bd85b94185c985b5cc8191a5cd8589b1959606a1b815260200192915050565b600061478e600c83615027565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b60006147b6600d83615027565b6c696e76616c696420737461746560981b815260200192915050565b60006147df602a83615027565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b600061482b602183615027565b7f6c6f616e446174614279746573207265717569726564207769746820657468658152603960f91b602082015260400192915050565b600061486e601683615027565b751cddd85c081d1bdbc81b185c99d9481d1bc8199a5b1b60521b815260200192915050565b60006148a0601583615027565b74696e697469616c4d617267696e20746f6f206c6f7760581b815260200192915050565b60006148d1601f83615027565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160e083019061490e848261415a565b506020820151614921602085018261415a565b506040820151614934604085018261415a565b506060820151614947606085018261415a565b50608082015161495a6080850182614183565b5060a082015161496d60a0850182614183565b5060c0820151612a6560c0850182614183565b600061498c828761418c565b60208201915061499c8286614169565b6014820191506149ac8285614169565b6014820191506149bc828461418c565b50602001949350505050565b600061169b828461419d565b6020810161164c828461415a565b604081016149f0828561415a565b61169b602083018461415a565b60808101614a0b828761415a565b614a18602083018661415a565b614a25604083018561415a565b610b626060830184614183565b60608101614a40828661415a565b614a4d602083018561415a565b6118e16040830184614183565b60808101614a68828761415a565b614a75602083018661415a565b614a256040830185614183565b60a08101614a90828861415a565b614a9d602083018761415a565b614aaa6040830186614183565b614ab76060830185614183565b6110f06080830184614183565b6101008101614ad3828b61415a565b614ae0602083018a61415a565b614aed6040830189614183565b614afa6060830188614183565b614b076080830187614183565b614b1460a0830186614183565b614b2160c0830185614183565b614b2e60e0830184614183565b9998505050505050505050565b6101208101614b4a828c61415a565b614b57602083018b61415a565b614b64604083018a614183565b614b716060830189614183565b614b7e6080830188614183565b614b8b60a0830187614183565b614b9860c0830186614183565b614ba560e0830185614183565b614bb3610100830184614183565b9a9950505050505050505050565b60408101614bcf828561415a565b61169b6020830184614183565b60608101614bea828661415a565b614a4d6020830185614183565b6020810161164c828461417a565b6101008101614c14828b614183565b614c21602083018a61417a565b614c2e604083018961415a565b614c3b606083018861415a565b614b07608083018761415a565b6101808101614c57828f614183565b614c64602083018e614183565b614c71604083018d614183565b614c7e606083018c61417a565b614c8b608083018b614183565b614c9860a083018a614183565b614ca560c0830189614183565b614cb260e0830188614183565b614cc0610100830187614183565b614cce610120830186614183565b614cdc61014083018561415a565b614cea61016083018461415a565b9d9c50505050505050505050505050565b6020810161164c82846141cc565b6020808252810161169b81846141d5565b6020808252810161164c8161420d565b6020808252810161164c8161423c565b6020808252810161164c8161425e565b6020808252810161164c81614297565b6020808252810161164c816142c3565b6020808252810161164c8161430b565b6020808252810161164c81614344565b6020808252810161164c81614371565b6020808252810161164c816143aa565b6020808252810161164c816143d4565b6020808252810161164c81614405565b6020808252810161164c8161443e565b6020808252810161164c8161446d565b6020808252810161164c81614498565b6020808252810161164c816144d1565b6020808252810161164c816144f8565b6020808252810161164c81614526565b6020808252810161164c81614550565b6020808252810161164c8161457a565b6020808252810161164c816145a5565b6020808252810161164c816145cf565b6020808252810161164c81614612565b6020808252810161164c8161463a565b6020808252810161164c81614673565b6020808252810161164c816146a1565b6020808252810161164c816146d2565b6020808252810161164c81614702565b6020808252810161164c81614752565b6020808252810161164c81614781565b6020808252810161164c816147a9565b6020808252810161164c816147d2565b6020808252810161164c8161481e565b6020808252810161164c81614861565b6020808252810161164c81614893565b6020808252810161164c816148c4565b60e0810161164c82846148fd565b6020810161164c8284614183565b60408101614bcf8285614183565b60608101614bea8286614183565b60a08101614f908288614183565b614a9d6020830187614183565b60c08101614fab8289614183565b614fb86020830188614183565b614fc56040830187614183565b614fd26060830186614183565b614fdf6080830185614183565b614fec60a0830184614183565b979650505050505050565b60405181810167ffffffffffffffff8111828210171561501657600080fd5b604052919050565b5190565b919050565b90815260200190565b600061164c82615050565b151590565b90565b6001600160e01b03191690565b6001600160a01b031690565b600061164c82615030565b60005b8381101561508257818101518382015260200161506a565b83811115612a655750506000910152565b600061164c82600061164c826150ae565b601f01601f191690565b60601b90565b6150bd81615030565b81146114b657600080fd5b6150bd8161503b565b6150bd81615040565b6150bd8161504356fea365627a7a7231582006262a07965035f357589c6bb924f7de44a817506b83c56eb712cec5934fdd626c6578706572696d656e74616cf564736f6c63430005110040", "libraries": { - "SwapsImplSovrynSwapLib": "0xf0F97838B2c80be59118e37436eca8F8edc2d08c" + "SwapsImplSovrynSwapLib": "0x98399051DC17bAFb621269A12a63d70b2D615C69" }, "devdoc": { "methods": { @@ -2118,7 +2118,7 @@ "storageLayout": { "storage": [ { - "astId": 54790, + "astId": 54832, "contract": "contracts/modules/LoanOpenings.sol:LoanOpenings", "label": "reentrancyLock", "offset": 0, @@ -2126,7 +2126,7 @@ "type": "t_uint256" }, { - "astId": 54606, + "astId": 54648, "contract": "contracts/modules/LoanOpenings.sol:LoanOpenings", "label": "_owner", "offset": 0, diff --git a/deployment/deployments/rskSovrynMainnet/SwapsImplSovrynSwapLib.json b/deployment/deployments/rskSovrynMainnet/SwapsImplSovrynSwapLib.json index 4657a57fb..7d0324aa9 100644 --- a/deployment/deployments/rskSovrynMainnet/SwapsImplSovrynSwapLib.json +++ b/deployment/deployments/rskSovrynMainnet/SwapsImplSovrynSwapLib.json @@ -1,5 +1,5 @@ { - "address": "0xf0F97838B2c80be59118e37436eca8F8edc2d08c", + "address": "0x98399051DC17bAFb621269A12a63d70b2D615C69", "abi": [ { "constant": true, @@ -106,28 +106,28 @@ "type": "function" } ], - "transactionHash": "0x66aa6ac15c49c13dcfc1188191149bae091d77aea1632b6608f8fe6d66399e5f", + "transactionHash": "0x6447bd168f349ec3fdf83a059a501cb8aaeb160e40ea301c678e03a385e9addb", "receipt": { "to": null, - "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", - "contractAddress": "0xf0F97838B2c80be59118e37436eca8F8edc2d08c", + "from": "0xFEe171A152C02F336021fb9E79b4fAc2304a9E7E", + "contractAddress": "0x98399051DC17bAFb621269A12a63d70b2D615C69", "transactionIndex": 0, - "gasUsed": "1722914", + "gasUsed": "1722978", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x563160b9b42b2926d1c41f93de2041bb4cdcd6992dffcb4785d41cb1a04fbaca", - "transactionHash": "0x66aa6ac15c49c13dcfc1188191149bae091d77aea1632b6608f8fe6d66399e5f", + "blockHash": "0xda59f587395abf71cc655bee3b6ff76677f910902af6ba815c5e3fc0932c330c", + "transactionHash": "0x6447bd168f349ec3fdf83a059a501cb8aaeb160e40ea301c678e03a385e9addb", "logs": [], - "blockNumber": 5886008, - "cumulativeGasUsed": "1722914", + "blockNumber": 5996096, + "cumulativeGasUsed": "1722978", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 1, - "solcInputHash": "9310031b42d2950fea7a6220c73f2cc4", - "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[{\"internalType\":\"string\",\"name\":\"source\",\"type\":\"string\"}],\"name\":\"getContractHexName\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"result\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sourceTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceTokenAmount\",\"type\":\"uint256\"}],\"name\":\"getExpectedRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sourceTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceTokenAmount\",\"type\":\"uint256\"}],\"name\":\"getExpectedReturn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"expectedReturn\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sovrynSwapRegistryAddress\",\"type\":\"address\"}],\"name\":\"getSovrynSwapNetworkContract\",\"outputs\":[{\"internalType\":\"contract ISovrynSwapNetwork\",\"name\":\"\",\"type\":\"ISovrynSwapNetwork\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{\"getContractHexName(string)\":{\"params\":{\"source\":\"The name of the contract.\"}},\"getExpectedRate(address,address,uint256)\":{\"params\":{\"destTokenAddress\":\"The address of the destination token contract.\",\"sourceTokenAddress\":\"The address of the source token contract.\",\"sourceTokenAmount\":\"The amount of source tokens to get the rate for.\"}},\"getExpectedReturn(address,address,uint256)\":{\"params\":{\"destTokenAddress\":\"The address of the destination token contract.\",\"sourceTokenAddress\":\"The address of the source token contract.\",\"sourceTokenAmount\":\"The amount of source tokens to get the return for.\"}},\"getSovrynSwapNetworkContract(address)\":{\"params\":{\"sovrynSwapRegistryAddress\":\"The address of the registry.\"}},\"swap(SwapsImplSovrynSwapLib.SwapParams)\":{\"params\":{\"params\":\"SwapParams struct sourceTokenAddress The address of the source tokens. destTokenAddress The address of the destination tokens. receiverAddress The address who will received the swap token results returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract). minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0). maxSourceTokenAmount The maximum amount of source tokens to swapped. requiredDestTokenAmount The required amount of destination tokens.\"}}},\"title\":\"Swaps Implementation Sovryn contract.\"},\"userdoc\":{\"methods\":{\"getContractHexName(string)\":{\"notice\":\"Get the hex name of a contract.\"},\"getExpectedRate(address,address,uint256)\":{\"notice\":\"Get the expected rate for 1 source token when exchanging the given amount of source tokens.\"},\"getExpectedReturn(address,address,uint256)\":{\"notice\":\"Get the expected return amount when exchanging the given amount of source tokens.Right now, this function is being called directly by _swapsExpectedReturn from the protocol So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call. Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\"},\"getSovrynSwapNetworkContract(address)\":{\"notice\":\"Look up the Sovryn swap network contract registered at the given address.\"},\"swap(SwapsImplSovrynSwapLib.SwapParams)\":{\"notice\":\"Swap the source token for the destination token on the oracle based AMM. On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0 -> swap the minSourceTokenAmount On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0 -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded. On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0 -> same as on rollover. minimum amount is not considered at all.\"}},\"notice\":\"This contract code comes from bZx. bZx is a protocol for tokenized margin trading and lending https://bzx.network similar to the dYdX protocol. * This contract contains the implementation of swap process and rate calculations for Sovryn network.\"}},\"settings\":{\"compilationTarget\":{\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":\"SwapsImplSovrynSwapLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nlibrary MarginTradeStructHelpers {\\n struct SentAddresses {\\n address lender;\\n address borrower;\\n address receiver;\\n address manager;\\n }\\n\\n struct SentAmounts {\\n uint256 interestRate;\\n uint256 newPrincipal;\\n uint256 interestInitialAmount;\\n uint256 loanTokenSent;\\n uint256 collateralTokenSent;\\n uint256 minEntryPrice;\\n uint256 loanToCollateralSwapRate;\\n uint256 interestDuration;\\n uint256 entryLeverage;\\n }\\n}\\n\",\"keccak256\":\"0xf0612e2c0d13604a67c3d55efe88810c089f0b84ca63bd3ce82c1e09b0938973\"},\"contracts/core/Objects.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./objects/LoanStruct.sol\\\";\\nimport \\\"./objects/LoanParamsStruct.sol\\\";\\nimport \\\"./objects/OrderStruct.sol\\\";\\nimport \\\"./objects/LenderInterestStruct.sol\\\";\\nimport \\\"./objects/LoanInterestStruct.sol\\\";\\n\\n/**\\n * @title Objects contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract inherints and aggregates several structures needed to handle\\n * loans on the protocol.\\n * */\\ncontract Objects is\\n LoanStruct,\\n LoanParamsStruct,\\n OrderStruct,\\n LenderInterestStruct,\\n LoanInterestStruct\\n{\\n\\n}\\n\",\"keccak256\":\"0xa30b8887af813997ebb480f0aa296245f9f3bd728382060059aa087cd9ee332c\"},\"contracts/core/State.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./Objects.sol\\\";\\nimport \\\"../mixins/EnumerableAddressSet.sol\\\";\\nimport \\\"../mixins/EnumerableBytes32Set.sol\\\";\\nimport \\\"../openzeppelin/ReentrancyGuard.sol\\\";\\nimport \\\"../openzeppelin/Ownable.sol\\\";\\nimport \\\"../openzeppelin/SafeMath.sol\\\";\\nimport \\\"../interfaces/IWrbtcERC20.sol\\\";\\nimport \\\"../reentrancy/SharedReentrancyGuard.sol\\\";\\n\\n/**\\n * @title State contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage values of the Protocol.\\n * */\\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\\n using SafeMath for uint256;\\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\\n\\n /// Handles asset reference price lookups.\\n address public priceFeeds;\\n\\n /// Handles asset swaps using dex liquidity.\\n address public swapsImpl;\\n\\n /// Contract registry address of the Sovryn swap network.\\n address public sovrynSwapContractRegistryAddress;\\n\\n /// Implementations of protocol functions.\\n mapping(bytes4 => address) public logicTargets;\\n\\n /// Loans: loanId => Loan\\n mapping(bytes32 => Loan) public loans;\\n\\n /// Loan parameters: loanParamsId => LoanParams\\n mapping(bytes32 => LoanParams) public loanParams;\\n\\n /// lender => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\\n\\n /// borrower => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\\n\\n /// loanId => delegated => approved\\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\\n\\n /**\\n *** Interest ***\\n **/\\n\\n /// lender => loanToken => LenderInterest object\\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\\n\\n /// loanId => LoanInterest object\\n mapping(bytes32 => LoanInterest) public loanInterest;\\n\\n /**\\n *** Internals ***\\n **/\\n\\n /// Implementations set.\\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\\n\\n /// Active loans set.\\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\\n\\n /// Lender loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\\n\\n /// Borrow loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\\n\\n /// User loan params set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\\n\\n /// Address controlling fee withdrawals.\\n address public feesController;\\n\\n /// 10% fee /// Fee taken from lender interest payments.\\n uint256 public lendingFeePercent = 10**19;\\n\\n /// Total interest fees received and not withdrawn per asset.\\n mapping(address => uint256) public lendingFeeTokensHeld;\\n\\n /// Total interest fees withdraw per asset.\\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\\n mapping(address => uint256) public lendingFeeTokensPaid;\\n\\n /// 0.15% fee /// Fee paid for each trade.\\n uint256 public tradingFeePercent = 15 * 10**16;\\n\\n /// Total trading fees received and not withdrawn per asset.\\n mapping(address => uint256) public tradingFeeTokensHeld;\\n\\n /// Total trading fees withdraw per asset\\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\\n mapping(address => uint256) public tradingFeeTokensPaid;\\n\\n /// 0.09% fee /// Origination fee paid for each loan.\\n uint256 public borrowingFeePercent = 9 * 10**16;\\n\\n /// Total borrowing fees received and not withdrawn per asset.\\n mapping(address => uint256) public borrowingFeeTokensHeld;\\n\\n /// Total borrowing fees withdraw per asset.\\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\\n mapping(address => uint256) public borrowingFeeTokensPaid;\\n\\n /// Current protocol token deposit balance.\\n uint256 public protocolTokenHeld;\\n\\n /// Lifetime total payout of protocol token.\\n uint256 public protocolTokenPaid;\\n\\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\\n uint256 public affiliateFeePercent = 5 * 10**18;\\n\\n /// 5% collateral discount /// Discount on collateral for liquidators.\\n uint256 public liquidationIncentivePercent = 5 * 10**18;\\n\\n /// loanPool => underlying\\n mapping(address => address) public loanPoolToUnderlying;\\n\\n /// underlying => loanPool\\n mapping(address => address) public underlyingToLoanPool;\\n\\n /// Loan pools set.\\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\\n\\n /// Supported tokens for swaps.\\n mapping(address => bool) public supportedTokens;\\n\\n /// % disagreement between swap rate and reference rate.\\n uint256 public maxDisagreement = 5 * 10**18;\\n\\n /// Used as buffer for swap source amount estimations.\\n uint256 public sourceBuffer = 10000;\\n\\n /// Maximum support swap size in rBTC\\n uint256 public maxSwapSize = 50 ether;\\n\\n /// Nonce per borrower. Used for loan id creation.\\n mapping(address => uint256) public borrowerNonce;\\n\\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\\n uint256 public rolloverBaseReward = 16800000000000;\\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\\n\\n IWrbtcERC20 public wrbtcToken;\\n address public protocolTokenAddress;\\n\\n /// 50% fee rebate\\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\\n uint256 public feeRebatePercent = 50 * 10**18;\\n\\n address public admin;\\n\\n /// For modules interaction.\\n address public protocolAddress;\\n\\n /**\\n *** Affiliates ***\\n **/\\n\\n /// The flag is set on the user's first trade.\\n mapping(address => bool) public userNotFirstTradeFlag;\\n\\n /// User => referrer (affiliate).\\n mapping(address => address) public affiliatesUserReferrer;\\n\\n /// List of referral addresses affiliated to the referrer.\\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\\n\\n /// @dev Referral threshold for paying out to the referrer.\\n /// The referrer reward is being accumulated and locked until the threshold is passed.\\n uint256 public minReferralsToPayout = 3;\\n\\n /// @dev Total affiliate SOV rewards that held in the protocol\\n /// (Because the minimum referrals is less than the rule)\\n mapping(address => uint256) public affiliateRewardsHeld;\\n\\n /// @dev For affiliates SOV Bonus proccess.\\n address public sovTokenAddress;\\n address public lockedSOVAddress;\\n\\n /// @dev 20% fee share of trading token fee.\\n /// Fee share of trading token fee for affiliate program.\\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\\n\\n /// @dev Addresses of tokens in which commissions were paid to referrers.\\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\\n\\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\\n\\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\\n bool public pause; //Flag to pause all protocol modules\\n\\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\\n\\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\\n uint256 internal tradingRebateRewardsBasisPoint;\\n\\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\\n /// Will be used in internal swap.\\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\\n\\n address internal pauser;\\n\\n /**\\n * @notice Add signature and target to storage.\\n * @dev Protocol is a proxy and requires a way to add every\\n * module function dynamically during deployment.\\n * */\\n function _setTarget(bytes4 sig, address target) internal {\\n logicTargets[sig] = target;\\n\\n if (target != address(0)) {\\n logicTargetsSet.addBytes32(bytes32(sig));\\n } else {\\n logicTargetsSet.removeBytes32(bytes32(sig));\\n }\\n }\\n\\n modifier onlyAdminOrOwner() {\\n require(isOwner() || admin == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n\\n modifier onlyPauserOrOwner() {\\n require(isOwner() || pauser == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0xf8dfc02f3dc790c73b390a69898d0281c4473487bc91fec1f28fbebceacd3b3c\"},\"contracts/core/objects/LenderInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Lender Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Lender Interest.\\n * */\\ncontract LenderInterestStruct {\\n struct LenderInterest {\\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\\n uint256 paidTotal; /// Total interest paid so far for asset.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0x6583baadddded384836cec469980e7973ec09310ae505b4a2ec67fb7bc19e452\"},\"contracts/core/objects/LoanInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Interest.\\n * */\\ncontract LoanInterestStruct {\\n struct LoanInterest {\\n uint256 owedPerDay; /// Interest owed per day for loan.\\n uint256 depositTotal; /// Total escrowed interest for loan.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0xd9034c6adb1b72e1593589dca024dc4730a1ee8bf6b2dca9d22283f2e7159590\"},\"contracts/core/objects/LoanParamsStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Parameters.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Parameters.\\n * */\\ncontract LoanParamsStruct {\\n struct LoanParams {\\n /// @dev ID of loan params object.\\n bytes32 id;\\n /// @dev If false, this object has been disabled by the owner and can't\\n /// be used for future loans.\\n bool active;\\n /// @dev Owner of this object.\\n address owner;\\n /// @dev The token being loaned.\\n address loanToken;\\n /// @dev The required collateral token.\\n address collateralToken;\\n /// @dev The minimum allowed initial margin.\\n uint256 minInitialMargin;\\n /// @dev An unhealthy loan when current margin is at or below this value.\\n uint256 maintenanceMargin;\\n /// @dev The maximum term for new loans (0 means there's no max term).\\n uint256 maxLoanTerm;\\n }\\n}\\n\",\"keccak256\":\"0xe15aa97713521da7f501e5225af9d92cf34bd68d286dbfed86aa75aabb323945\"},\"contracts/core/objects/LoanStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Object.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Object.\\n * */\\ncontract LoanStruct {\\n struct Loan {\\n bytes32 id; /// ID of the loan.\\n bytes32 loanParamsId; /// The linked loan params ID.\\n bytes32 pendingTradesId; /// The linked pending trades ID.\\n bool active; /// If false, the loan has been fully closed.\\n uint256 principal; /// Total borrowed amount outstanding.\\n uint256 collateral; /// Total collateral escrowed for the loan.\\n uint256 startTimestamp; /// Loan start time.\\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\\n uint256 startMargin; /// Initial margin when the loan opened.\\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\\n address borrower; /// Borrower of this loan.\\n address lender; /// Lender of this loan.\\n }\\n}\\n\",\"keccak256\":\"0x7d05c3096a86d5892e4e72f3a01a5a806f13a5ac90ca6339c611e75c603637b4\"},\"contracts/core/objects/OrderStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Order.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Order.\\n * */\\ncontract OrderStruct {\\n struct Order {\\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\\n uint256 interestRate; /// Interest rate defined by the creator of this order.\\n uint256 minLoanTerm; /// Minimum loan term allowed.\\n uint256 maxLoanTerm; /// Maximum loan term allowed.\\n uint256 createdTimestamp; /// Timestamp when this order was created.\\n uint256 expirationTimestamp; /// Timestamp when this order expires.\\n }\\n}\\n\",\"keccak256\":\"0xcc053c5da34a5927041162259bf856ba913f3524ca03e63ad0c5877777d17e0f\"},\"contracts/events/AffiliatesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\ncontract AffiliatesEvents is ModulesCommonEvents {\\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\\n\\n event SetAffiliatesReferrerFail(\\n address indexed user,\\n address indexed referrer,\\n bool alreadySet,\\n bool userNotFirstTrade\\n );\\n\\n event SetUserNotFirstTradeFlag(address indexed user);\\n\\n event PayTradingFeeToAffiliate(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n bool indexed isHeld,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountPaid\\n );\\n\\n event PayTradingFeeToAffiliateFail(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountTryingToPaid\\n );\\n\\n event WithdrawAffiliatesReferrerTokenFees(\\n address indexed referrer,\\n address indexed receiver,\\n address indexed tokenAddress,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xf72cf23e90db3c49589ddc4e1796680ebfb69a9b146db89f9b61f5fcf6dd95ba\"},\"contracts/events/FeesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Fees Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for fee payments.\\n * */\\ncontract FeesEvents {\\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\\n\\n event PayTradingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event PayBorrowingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event EarnReward(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n\\n event EarnRewardFail(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n}\\n\",\"keccak256\":\"0xe69bf53e15479be5fde1cbaadaf0c004ee038e8a6a37c99f7769bf5d8387015f\"},\"contracts/events/LoanClosingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Closing Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan closing operations.\\n * */\\ncontract LoanClosingsEvents is ModulesCommonEvents {\\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\\n event CloseWithDeposit(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address closer,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\\n event CloseWithSwap(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n address closer,\\n uint256 positionCloseSize,\\n uint256 loanCloseAmount,\\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\\n event Liquidate(\\n address indexed user,\\n address indexed liquidator,\\n bytes32 indexed loanId,\\n address lender,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n event Rollover(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n uint256 principal,\\n uint256 collateral,\\n uint256 endTimestamp,\\n address rewardReceiver,\\n uint256 reward\\n );\\n\\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\\n}\\n\",\"keccak256\":\"0x1ea325b9a213012865a52f38941ce6c1e8c29dce919215b5bdcc63a8a5980be1\"},\"contracts/events/LoanMaintenanceEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Maintenance Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan maintenance operations.\\n * */\\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\\n}\\n\",\"keccak256\":\"0xdee5098b947c22bcef6e38ecaf62bae6941572d1c245d2065ad41ea4f494c61d\"},\"contracts/events/LoanOpeningsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Openings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan openings operations.\\n * */\\ncontract LoanOpeningsEvents is ModulesCommonEvents {\\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\\n event Borrow(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 newCollateral,\\n uint256 interestRate,\\n uint256 interestDuration,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\\n event Trade(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n uint256 positionSize,\\n uint256 borrowedAmount,\\n uint256 interestRate,\\n uint256 settlementDate,\\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\\n uint256 entryLeverage,\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\\n event DelegatedManagerSet(\\n bytes32 indexed loanId,\\n address indexed delegator,\\n address indexed delegated,\\n bool isActive\\n );\\n}\\n\",\"keccak256\":\"0x585710ce6c570c6dbd1b8daf43b63a54b1d60ad01ee1dc3cae407d74d78f3093\"},\"contracts/events/LoanSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan settings operations.\\n * */\\ncontract LoanSettingsEvents is ModulesCommonEvents {\\n event LoanParamsSetup(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\\n\\n event LoanParamsDisabled(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\\n}\\n\",\"keccak256\":\"0xae9c49678a7bc02c2283648939c474c8bfd33781506e05c635c8334c5bf8682f\"},\"contracts/events/ModulesCommonEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\n/**\\n * @title The common events for all modules\\n * @notice This contract contains the events which will be used by all modules\\n **/\\n\\ncontract ModulesCommonEvents {\\n event ProtocolModuleContractReplaced(\\n address indexed prevModuleContractAddress,\\n address indexed newModuleContractAddress,\\n bytes32 indexed module\\n );\\n}\\n\",\"keccak256\":\"0xb07af42d7e6b0fe983889b883691b662a58d2ef8d75b3f32f17faff1871c8b8f\"},\"contracts/events/ProtocolSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title The Protocol Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for protocol settings operations.\\n * */\\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetLoanPool(\\n address indexed sender,\\n address indexed loanPool,\\n address indexed underlying\\n );\\n\\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\\n\\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateTradingTokenFeePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetLiquidationIncentivePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetFeesController(\\n address indexed sender,\\n address indexed oldController,\\n address indexed newController\\n );\\n\\n event SetWrbtcToken(\\n address indexed sender,\\n address indexed oldWethToken,\\n address indexed newWethToken\\n );\\n\\n event SetSovrynSwapContractRegistryAddress(\\n address indexed sender,\\n address indexed oldSovrynSwapContractRegistryAddress,\\n address indexed newSovrynSwapContractRegistryAddress\\n );\\n\\n event SetProtocolTokenAddress(\\n address indexed sender,\\n address indexed oldProtocolToken,\\n address indexed newProtocolToken\\n );\\n\\n event WithdrawFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 lendingAmount,\\n uint256 tradingAmount,\\n uint256 borrowingAmount,\\n uint256 wRBTCConverted\\n );\\n\\n event WithdrawLendingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawTradingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawBorrowingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetRebatePercent(\\n address indexed sender,\\n uint256 oldRebatePercent,\\n uint256 newRebatePercent\\n );\\n\\n event SetSpecialRebates(\\n address indexed sender,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 oldSpecialRebatesPercent,\\n uint256 newSpecialRebatesPercent\\n );\\n\\n event SetProtocolAddress(\\n address indexed sender,\\n address indexed oldProtocol,\\n address indexed newProtocol\\n );\\n\\n event SetMinReferralsToPayoutAffiliates(\\n address indexed sender,\\n uint256 oldMinReferrals,\\n uint256 newMinReferrals\\n );\\n\\n event SetSOVTokenAddress(\\n address indexed sender,\\n address indexed oldTokenAddress,\\n address indexed newTokenAddress\\n );\\n\\n event SetLockedSOVAddress(\\n address indexed sender,\\n address indexed oldAddress,\\n address indexed newAddress\\n );\\n\\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\\n\\n event SetTradingRebateRewardsBasisPoint(\\n address indexed sender,\\n uint256 oldBasisPoint,\\n uint256 newBasisPoint\\n );\\n\\n event SetRolloverFlexFeePercent(\\n address indexed sender,\\n uint256 oldRolloverFlexFeePercent,\\n uint256 newRolloverFlexFeePercent\\n );\\n\\n event SetDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event RemoveDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\\n\\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\\n}\\n\",\"keccak256\":\"0x20ca66a2c53669aa33379bf5233e3bcdddbba3504cd430a0143f0ee3ce1c2641\"},\"contracts/events/SwapsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Swaps Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for swap operations.\\n * */\\ncontract SwapsEvents is ModulesCommonEvents {\\n event LoanSwap(\\n bytes32 indexed loanId,\\n address indexed sourceToken,\\n address indexed destToken,\\n address borrower,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n\\n event ExternalSwap(\\n address indexed user,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n}\\n\",\"keccak256\":\"0x0a1cd289076675980b916941ed923146160d34a8669fc3fb4a06610f285dfbd1\"},\"contracts/feeds/IPriceFeeds.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface IPriceFeeds {\\n function queryRate(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 rate, uint256 precision);\\n\\n function queryPrecision(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 precision);\\n\\n function queryReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount\\n ) external view returns (uint256 destAmount);\\n\\n function checkPriceDisagreement(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount,\\n uint256 destAmount,\\n uint256 maxSlippage\\n ) external view returns (uint256 sourceToDestSwapRate);\\n\\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\\n\\n function getMaxDrawdown(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (uint256);\\n\\n function getCurrentMarginAndCollateralSize(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\\n\\n function getCurrentMargin(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\\n\\n function shouldLiquidate(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (bool);\\n\\n function getFastGasPrice(address payToken) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x2e2c2b393336efedb97659a2fc21c8dfb75b70e15d2422a3bcbf7ebd5fc83c82\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/interfaces/ISovryn.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\npragma experimental ABIEncoderV2;\\n//TODO: stored in ./interfaces only while brownie isn't removed\\n//TODO: move to contracts/interfaces after with brownie is removed\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/ProtocolSettingsEvents.sol\\\";\\nimport \\\"../events/LoanSettingsEvents.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../events/LoanMaintenanceEvents.sol\\\";\\nimport \\\"../events/LoanClosingsEvents.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../events/AffiliatesEvents.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\ncontract ISovryn is\\n State,\\n ProtocolSettingsEvents,\\n LoanSettingsEvents,\\n LoanOpeningsEvents,\\n LoanMaintenanceEvents,\\n LoanClosingsEvents,\\n SwapsEvents,\\n AffiliatesEvents,\\n FeesEvents\\n{\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n ////// Protocol //////\\n\\n function replaceContract(address target) external;\\n\\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\\n\\n function getTarget(string calldata sig) external view returns (address);\\n\\n ////// Protocol Settings //////\\n\\n function setSovrynProtocolAddress(address newProtocolAddress) external;\\n\\n function setSOVTokenAddress(address newSovTokenAddress) external;\\n\\n function setLockedSOVAddress(address newSOVLockedAddress) external;\\n\\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\\n\\n function setPriceFeedContract(address newContract) external;\\n\\n function setSwapsImplContract(address newContract) external;\\n\\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\\n\\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\\n\\n function setLendingFeePercent(uint256 newValue) external;\\n\\n function setTradingFeePercent(uint256 newValue) external;\\n\\n function setBorrowingFeePercent(uint256 newValue) external;\\n\\n function setSwapExternalFeePercent(uint256 newValue) external;\\n\\n function setAffiliateFeePercent(uint256 newValue) external;\\n\\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\\n\\n function setLiquidationIncentivePercent(uint256 newAmount) external;\\n\\n function setMaxDisagreement(uint256 newAmount) external;\\n\\n function setSourceBuffer(uint256 newAmount) external;\\n\\n function setMaxSwapSize(uint256 newAmount) external;\\n\\n function setFeesController(address newController) external;\\n\\n function withdrawFees(address[] calldata tokens, address receiver)\\n external\\n returns (uint256 totalWRBTCWithdrawn);\\n\\n function withdrawLendingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawTradingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawBorrowingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawProtocolToken(address receiver, uint256 amount)\\n external\\n returns (address, bool);\\n\\n function depositProtocolToken(uint256 amount) external;\\n\\n function getLoanPoolsList(uint256 start, uint256 count)\\n external\\n view\\n returns (bytes32[] memory);\\n\\n function isLoanPool(address loanPool) external view returns (bool);\\n\\n function setWrbtcToken(address wrbtcTokenAddress) external;\\n\\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\\n\\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\\n\\n function setRolloverBaseReward(uint256 transactionCost) external;\\n\\n function setRebatePercent(uint256 rebatePercent) external;\\n\\n function setSpecialRebates(\\n address sourceToken,\\n address destToken,\\n uint256 specialRebatesPercent\\n ) external;\\n\\n function getSpecialRebates(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 specialRebatesPercent);\\n\\n function togglePaused(bool paused) external;\\n\\n function isProtocolPaused() external view returns (bool);\\n\\n ////// SwapsImplSovrynSwapModule //////\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (address);\\n\\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\\n\\n function swapsImplExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function swapsImplExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256 expectedReturn);\\n\\n ////// Loan Settings //////\\n\\n function setupLoanParams(LoanParams[] calldata loanParamsList)\\n external\\n returns (bytes32[] memory loanParamsIdList);\\n\\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\\n\\n function getLoanParams(bytes32[] calldata loanParamsIdList)\\n external\\n view\\n returns (LoanParams[] memory loanParamsList);\\n\\n function getLoanParamsList(\\n address owner,\\n uint256 start,\\n uint256 count\\n ) external view returns (bytes32[] memory loanParamsList);\\n\\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\\n\\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\\n\\n ////// Loan Openings //////\\n\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId, // if 0, start a new loan\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n // lender: must match loan if loanId provided\\n // borrower: must match loan if loanId provided\\n // receiver: receiver of funds (address(0) assumes borrower address)\\n // manager: delegated manager of loan unless address(0)\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n // newRate: new loan interest rate\\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\\n // collateralTokenReceived: total collateralToken deposit\\n bytes calldata loanDataBytes\\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\\n\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external;\\n\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256);\\n\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 collateralAmountRequired);\\n\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 borrowAmount);\\n\\n ////// Loan Closings //////\\n\\n function liquidate(\\n bytes32 loanId,\\n address receiver,\\n uint256 closeAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 seizedAmount,\\n address seizedToken\\n );\\n\\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\\n\\n function closeWithDeposit(\\n bytes32 loanId,\\n address receiver,\\n uint256 depositAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n function closeWithSwap(\\n bytes32 loanId,\\n address receiver,\\n uint256 swapAmount, // denominated in collateralToken\\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\\n bytes calldata loanDataBytes\\n )\\n external\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n ////// Loan Maintenance //////\\n\\n function depositCollateral(\\n bytes32 loanId,\\n uint256 depositAmount // must match msg.value if ether is sent\\n ) external payable;\\n\\n function withdrawCollateral(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 actualWithdrawAmount);\\n\\n function withdrawAccruedInterest(address loanToken) external;\\n\\n function getLenderInterestData(address lender, address loanToken)\\n external\\n view\\n returns (\\n uint256 interestPaid,\\n uint256 interestPaidDate,\\n uint256 interestOwedPerDay,\\n uint256 interestUnPaid,\\n uint256 interestFeePercent,\\n uint256 principalTotal\\n );\\n\\n function getLoanInterestData(bytes32 loanId)\\n external\\n view\\n returns (\\n address loanToken,\\n uint256 interestOwedPerDay,\\n uint256 interestDepositTotal,\\n uint256 interestDepositRemaining\\n );\\n\\n struct LoanReturnData {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; // collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n }\\n\\n struct LoanReturnDataV2 {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n address borrower;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; /// collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n uint256 creationTimestamp;\\n }\\n\\n function getUserLoans(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getUserLoansV2(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\\n\\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\\n\\n function getActiveLoans(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getActiveLoansV2(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function extendLoanDuration(\\n bytes32 loanId,\\n uint256 depositAmount,\\n bool useCollateral,\\n bytes calldata /// loanDataBytes, for future use.\\n ) external returns (uint256 secondsExtended);\\n\\n function reduceLoanDuration(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 secondsReduced);\\n\\n ////// Swaps External //////\\n function swapExternal(\\n address sourceToken,\\n address destToken,\\n address receiver,\\n address returnToSender,\\n uint256 sourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n uint256 minReturn,\\n bytes calldata swapData\\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\\n\\n function getSwapExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function checkPriceDivergence(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount,\\n uint256 minReturn\\n ) public view;\\n\\n ////// Affiliates Module //////\\n\\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\\n\\n function setUserNotFirstTradeFlag(address user) external;\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address referrer,\\n address trader,\\n address token,\\n uint256 tradingFeeTokenBaseAmount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n\\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\\n\\n function getReferralsList(address referrer) external view returns (address[] memory refList);\\n\\n function getAffiliatesReferrerBalances(address referrer)\\n external\\n view\\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\\n\\n function getAffiliatesReferrerTokensList(address referrer)\\n external\\n view\\n returns (address[] memory tokensList);\\n\\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\\n external\\n view\\n returns (uint256);\\n\\n function withdrawAffiliatesReferrerTokenFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external;\\n\\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\\n\\n function getProtocolAddress() external view returns (address);\\n\\n function getSovTokenAddress() external view returns (address);\\n\\n function getLockedSOVAddress() external view returns (address);\\n\\n function getFeeRebatePercent() external view returns (uint256);\\n\\n function getMinReferralsToPayout() external view returns (uint256);\\n\\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\\n\\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\\n\\n function getAffiliateTradingTokenFeePercent()\\n external\\n view\\n returns (uint256 affiliateTradingTokenFeePercent);\\n\\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\\n external\\n view\\n returns (uint256 rbtcTotalAmount);\\n\\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\\n\\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\\n\\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\\n\\n function getDedicatedSOVRebate() external view returns (uint256);\\n\\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\\n\\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external\\n view\\n returns (IERC20[] memory);\\n\\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\\n\\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external;\\n\\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\\n external\\n view\\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\\n\\n function setAdmin(address newAdmin) external;\\n\\n function getAdmin() external view returns (address);\\n\\n function setPauser(address newPauser) external;\\n\\n function getPauser() external view returns (address);\\n}\\n\",\"keccak256\":\"0x4e470e1fe1719c2c58b0e44aedce3ee6a21191063b533ccb71c9219a192e8884\"},\"contracts/interfaces/IWrbtc.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ninterface IWrbtc {\\n function deposit() external payable;\\n\\n function withdraw(uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x20fdfe4b5e32fd7f863b3fa128e3c80bd4ccf090a4ffba56186ef3b7f2a80492\"},\"contracts/interfaces/IWrbtcERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./IWrbtc.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\n\\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\\n\",\"keccak256\":\"0x7301a8c8ca7aa016ec94268a16d07366875f2e406442e929968dd745b1ee5be5\"},\"contracts/mixins/EnumerableAddressSet.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Based on Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * As of v2.5.0, only `address` sets are supported.\\n *\\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\\n *\\n * _Available since v2.5.0._\\n */\\nlibrary EnumerableAddressSet {\\n struct AddressSet {\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(address => uint256) index;\\n address[] values;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n * Returns false if the value was already in the set.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n * Returns false if the value was not present in the set.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n // If the element we're deleting is the last one, we can just remove it without doing a swap\\n if (lastIndex != toDeleteIndex) {\\n address lastValue = set.values[lastIndex];\\n\\n // Move the last value to the index where the deleted value is\\n set.values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n // Delete the index entry for the deleted value\\n delete set.index[value];\\n\\n // Delete the old entry for the moved value\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns an array with all values in the set. O(N).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\\n address[] memory output = new address[](set.values.length);\\n for (uint256 i; i < set.values.length; i++) {\\n output[i] = set.values[i];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n \\n * @param start start index of chunk\\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\\n */\\n function enumerateChunk(\\n AddressSet storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (address[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = (set.values.length < end || count == 0) ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new address[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns the number of elements on the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /** @dev Returns the element stored at position `index` in the set. O(1).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xea6fba941ec8502aa11a7ab37e74b917d0dc47bb254e359a2870a87ef97d9872\"},\"contracts/mixins/EnumerableBytes32Set.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title Library for managing loan sets.\\n *\\n * @notice Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\\n * */\\nlibrary EnumerableBytes32Set {\\n struct Bytes32Set {\\n /// Position of the value in the `values` array, plus 1 because index 0\\n /// means a value is not in the set.\\n mapping(bytes32 => uint256) index;\\n bytes32[] values;\\n }\\n\\n /**\\n * @notice Add an address value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return addBytes32(set, value);\\n }\\n\\n /**\\n * @notice Add a value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The new value to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Remove an address value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to remove.\\n *\\n * @return False if the address was not present in the set.\\n */\\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return removeBytes32(set, value);\\n }\\n\\n /**\\n * @notice Remove a value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The value to remove.\\n *\\n * @return False if the value was not present in the set.\\n */\\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n /// If the element we're deleting is the last one,\\n /// we can just remove it without doing a swap.\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set.values[lastIndex];\\n\\n /// Move the last value to the index where the deleted value is.\\n set.values[toDeleteIndex] = lastValue;\\n\\n /// Update the index for the moved value.\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n /// Delete the index entry for the deleted value.\\n delete set.index[value];\\n\\n /// Delete the old entry for the moved value.\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Find out whether a value exists in the set.\\n *\\n * @param set The set of values.\\n * @param value The value to find.\\n *\\n * @return True if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function containsAddress(Bytes32Set storage set, address addrvalue)\\n internal\\n view\\n returns (bool)\\n {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @notice Get all set values.\\n *\\n * @param set The set of values.\\n * @param start The offset of the returning set.\\n * @param count The limit of number of values to return.\\n *\\n * @return An array with all values in the set. O(N).\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(\\n Bytes32Set storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (bytes32[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = set.values.length < end ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new bytes32[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @notice Get the legth of the set.\\n *\\n * @param set The set of values.\\n *\\n * @return the number of elements on the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /**\\n * @notice Get an item from the set by its index.\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n *\\n * @param set The set of values.\\n * @param index The index of the value to return.\\n *\\n * @return the element stored at position `index` in the set. O(1).\\n */\\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xa2801a585c566e07f21c1ebccd0cd0447dd5fd9fe6c1ff2b58d4d979d88a6db0\"},\"contracts/openzeppelin/Address.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n codehash := extcodehash(account)\\n }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x23df48a01dbac9b25e86c9131174fb7752bbc7e741e63f1aa982de22e055ad54\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/openzeppelin/ReentrancyGuard.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @title Helps contracts guard against reentrancy attacks.\\n * @author Remco Bloemen , Eenae \\n * @dev If you mark a function `nonReentrant`, you should also\\n * mark it `external`.\\n */\\ncontract ReentrancyGuard {\\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\\n\\n /// @dev Constant for locked guard state\\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\\n\\n /**\\n * @dev We use a single lock for the whole contract.\\n */\\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * If you mark a function `nonReentrant`, you should also\\n * mark it `external`. Calling one `nonReentrant` function from\\n * another is not supported. Instead, you can implement a\\n * `private` function doing the actual work, and an `external`\\n * wrapper marked as `nonReentrant`.\\n */\\n modifier nonReentrant() {\\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \\\"nonReentrant\\\");\\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\\n _;\\n reentrancyLock = REENTRANCY_GUARD_FREE;\\n }\\n}\\n\",\"keccak256\":\"0xd347de96ad57d1e45b07a2efe3050c1bd4b809236bbf354acb593de56d21a5c9\"},\"contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./Address.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\\n );\\n }\\n\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance =\\n token.allowance(address(this), spender).sub(\\n value,\\n \\\"SafeERC20: decreased allowance below zero\\\"\\n );\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) {\\n // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe99b4d979cb976a6b70e297600242afe38b8cd8f1b1ba6ee373f39f7abb3ca79\"},\"contracts/openzeppelin/SafeMath.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\\n return divCeil(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n\\n if (a == 0) {\\n return 0;\\n }\\n uint256 c = ((a - 1) / b) + 1;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n\\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n return _a < _b ? _a : _b;\\n }\\n}\\n\",\"keccak256\":\"0xbff8d6273e1a6870d1a142c0c23acd63a4dd47760f250390f49ee56333bcb6e8\"},\"contracts/reentrancy/Mutex.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/*\\n * @title Global Mutex contract\\n *\\n * @notice A mutex contract that allows only one function to be called at a time out\\n * of a large set of functions. *Anyone* in the network can freely use any instance\\n * of this contract to add a universal mutex to any function in any contract.\\n */\\ncontract Mutex {\\n /*\\n * We use an uint to store the mutex state.\\n */\\n uint256 public value;\\n\\n /*\\n * @notice Increment the mutex state and return the new value.\\n *\\n * @dev This is the function that will be called by anyone to change the mutex\\n * state. It is purposely not protected by any access control\\n */\\n function incrementAndGetValue() external returns (uint256) {\\n /*\\n * increment value using unsafe math. This is safe because we are\\n * pretty certain no one will ever increment the value 2^256 times\\n * in a single transaction.\\n */\\n return ++value;\\n }\\n}\\n\",\"keccak256\":\"0xd10b0fd07d5fed1ae1237e7c87e6501970fce2a86e2b8862e502258b0d3aeb2c\"},\"contracts/reentrancy/SharedReentrancyGuard.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./Mutex.sol\\\";\\n\\n/*\\n * @title Abstract contract for shared reentrancy guards\\n *\\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\\n * that there's no reentrancy between *any* functions marked with the modifier.\\n *\\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\\n */\\ncontract SharedReentrancyGuard {\\n /*\\n * This is the address of the mutex contract that will be used as the\\n * reentrancy guard.\\n *\\n * The address is hardcoded to avoid changing the memory layout of\\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\\n * because the Mutex contract is always deployed to the same address, with the\\n * same method used in the deployment of ERC1820Registry.\\n */\\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\\n\\n /*\\n * This is the modifier that will be used to protect functions from\\n * reentrancy. It will call the mutex contract to increment the mutex\\n * state and then revert if the mutex state was changed by another\\n * nested call.\\n */\\n modifier globallyNonReentrant() {\\n uint256 previous = MUTEX.incrementAndGetValue();\\n\\n _;\\n\\n /*\\n * If the mutex state was changed by a nested function call, then\\n * the value of the state variable will be different from the previous value.\\n */\\n require(previous == MUTEX.value(), \\\"reentrancy violation\\\");\\n }\\n}\\n\",\"keccak256\":\"0x2d0e61b104b91c1764f20fbeb381ba0f8a8889934ba7f6e8a167ed542ec2c124\"},\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":{\"content\":\"pragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"./interfaces/ISovrynSwapNetwork.sol\\\";\\nimport \\\"./interfaces/IContractRegistry.sol\\\";\\nimport \\\"../../interfaces/ISovryn.sol\\\";\\n\\n/**\\n * @title Swaps Implementation Sovryn contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the implementation of swap process and rate\\n * calculations for Sovryn network.\\n * */\\nlibrary SwapsImplSovrynSwapLib {\\n using SafeMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n struct SwapParams {\\n address sourceTokenAddress;\\n address destTokenAddress;\\n address receiverAddress;\\n address returnToSenderAddress;\\n uint256 minSourceTokenAmount;\\n uint256 maxSourceTokenAmount;\\n uint256 requiredDestTokenAmount;\\n }\\n\\n /// bytes32 contractName = hex\\\"42616e636f724e6574776f726b\\\"; /// \\\"SovrynSwapNetwork\\\"\\n\\n /**\\n * Get the hex name of a contract.\\n * @param source The name of the contract.\\n * */\\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\\n assembly {\\n result := mload(add(source, 32))\\n }\\n }\\n\\n /**\\n * Look up the Sovryn swap network contract registered at the given address.\\n * @param sovrynSwapRegistryAddress The address of the registry.\\n * */\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (ISovrynSwapNetwork)\\n {\\n /// State variable sovrynSwapContractRegistryAddress is part of\\n /// State.sol and set in ProtocolSettings.sol and this function\\n /// needs to work without delegate call as well -> therefore pass it.\\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\\n return\\n ISovrynSwapNetwork(\\n contractRegistry.addressOf(getContractHexName(\\\"SovrynSwapNetwork\\\"))\\n );\\n }\\n\\n /**\\n * Swap the source token for the destination token on the oracle based AMM.\\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\\n * -> swap the minSourceTokenAmount\\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\\n * -> same as on rollover. minimum amount is not considered at all.\\n *\\n * @param params SwapParams struct\\n * sourceTokenAddress The address of the source tokens.\\n * destTokenAddress The address of the destination tokens.\\n * receiverAddress The address who will received the swap token results\\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\\n * requiredDestTokenAmount The required amount of destination tokens.\\n * */\\n function swap(SwapParams memory params)\\n public\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n require(params.sourceTokenAddress != params.destTokenAddress, \\\"source == dest\\\");\\n\\n ISovryn iSovryn = ISovryn(address(this));\\n require(\\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\\n iSovryn.supportedTokens(params.destTokenAddress),\\n \\\"invalid tokens\\\"\\n );\\n\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\\n\\n IERC20[] memory path =\\n _getConversionPath(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n sovrynSwapNetwork\\n );\\n\\n uint256 minReturn = 1;\\n sourceTokenAmountUsed = params.minSourceTokenAmount;\\n\\n /// If the required amount of destination tokens is passed, we need to\\n /// calculate the estimated amount of source tokens regardless of the\\n /// minimum source token amount (name is misleading).\\n if (params.requiredDestTokenAmount > 0) {\\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n params.requiredDestTokenAmount,\\n params.maxSourceTokenAmount\\n );\\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\\n require(\\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\\n params.requiredDestTokenAmount,\\n \\\"insufficient source tokens provided.\\\"\\n );\\n minReturn = params.requiredDestTokenAmount;\\n }\\n\\n require(sourceTokenAmountUsed > 0, \\\"cannot swap 0 tokens\\\");\\n\\n _allowTransfer(\\n sourceTokenAmountUsed,\\n params.sourceTokenAddress,\\n address(sovrynSwapNetwork)\\n );\\n\\n /// @dev Note: the kyber connector uses .call() to interact with kyber\\n /// to avoid bubbling up. here we allow bubbling up.\\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\\n path,\\n sourceTokenAmountUsed,\\n minReturn,\\n params.receiverAddress,\\n address(0),\\n 0\\n );\\n\\n /// If the sender is not the protocol (calling with delegatecall),\\n /// return the remainder to the specified address.\\n /// @dev Note: for the case that the swap is used without the\\n /// protocol. Not sure if it should, though. needs to be discussed.\\n if (params.returnToSenderAddress != address(this)) {\\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\\n /// Send unused source token back.\\n IERC20(params.sourceTokenAddress).safeTransfer(\\n params.returnToSenderAddress,\\n params.maxSourceTokenAmount - sourceTokenAmountUsed\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Check whether the existing allowance suffices to transfer\\n * the needed amount of tokens.\\n * If not, allows the transfer of an arbitrary amount of tokens.\\n *\\n * @param tokenAmount The amount to transfer.\\n * @param tokenAddress The address of the token to transfer.\\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\\n * */\\n function _allowTransfer(\\n uint256 tokenAmount,\\n address tokenAddress,\\n address sovrynSwapNetwork\\n ) internal {\\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\\n if (tempAllowance < tokenAmount) {\\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\\n }\\n }\\n\\n /**\\n * @notice Calculate the number of source tokens to provide in order to\\n * obtain the required destination amount.\\n *\\n * @param sourceTokenAddress The address of the source token address.\\n * @param destTokenAddress The address of the destination token address.\\n * @param requiredDestTokenAmount The number of destination tokens needed.\\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\\n *\\n * @return The estimated amount of source tokens needed.\\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\\n * */\\n function _estimateSourceTokenAmount(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 requiredDestTokenAmount,\\n uint256 maxSourceTokenAmount\\n ) internal view returns (uint256 estimatedSourceAmount) {\\n ISovryn iSovryn = ISovryn(address(this));\\n uint256 sourceToDestPrecision =\\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\\n\\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\\n uint256 expectedRate =\\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\\n\\n /// Compute the source tokens needed to get the required amount with the worst case rate.\\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\\n expectedRate\\n );\\n\\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\\n uint256 buffer = estimatedSourceAmount.div(1000);\\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\\n\\n /// Never spend more than the maximum.\\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\\n return maxSourceTokenAmount;\\n }\\n\\n /**\\n * @notice Get the expected rate for 1 source token when exchanging the\\n * given amount of source tokens.\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\\n * */\\n function getExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n\\n /// Return the rate for 1 token with 18 decimals.\\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\\n }\\n\\n /**\\n * @notice Get the expected return amount when exchanging the given\\n * amount of source tokens.\\n *\\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the return for.\\n * */\\n function getExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256 expectedReturn) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n }\\n\\n function _getConversionPath(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n ISovrynSwapNetwork sovrynSwapNetwork\\n ) private view returns (IERC20[] memory path) {\\n IERC20[] memory _defaultPathConversion =\\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\\n\\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\\n path = _defaultPathConversion.length >= 3\\n ? _defaultPathConversion\\n : sovrynSwapNetwork.conversionPath(\\n IERC20(sourceTokenAddress),\\n IERC20(destTokenAddress)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x058b8d733422a2421f17d1b159aed69f151ea8d5f48ee507bac5b4e86add8b0c\"},\"contracts/swaps/connectors/interfaces/IContractRegistry.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\ncontract IContractRegistry {\\n function addressOf(bytes32 contractName) public view returns (address);\\n}\\n\",\"keccak256\":\"0x793c4eefa2ee04cbf0a1a9da28676ac310ed7bf60a27ec7d86de7d7236ccf45b\"},\"contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol\":{\"content\":\"pragma solidity >=0.5.8 <=0.5.17;\\n\\nimport \\\"../../../interfaces/IERC20.sol\\\";\\n\\ncontract ISovrynSwapNetwork {\\n function convertByPath(\\n IERC20[] calldata _path,\\n uint256 _amount,\\n uint256 _minReturn,\\n address _beneficiary,\\n address _affiliateAccount,\\n uint256 _affiliateFee\\n ) external payable returns (uint256);\\n\\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\\n\\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\\n external\\n view\\n returns (IERC20[] memory);\\n}\\n\",\"keccak256\":\"0xcd28e146b77183bff18f78b511912f7ebe60d437430fdaa72ed145fdda61a5ad\"}},\"version\":1}", - "bytecode": "0x61187c610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100615760003560e01c806335aaa79d146100665780636dcd64e51461009d578063809a9e55146100bd578063b1fb7f56146100d0578063ca83d575146100e3575b600080fd5b81801561007257600080fd5b50610086610081366004611199565b610103565b6040516100949291906116ef565b60405180910390f35b6100b06100ab3660046110c4565b6104dd565b6040516100949190611607565b6100b06100cb3660046110c4565b6105b6565b6100b06100de366004611164565b6106bd565b6100f66100f1366004611088565b6106c4565b6040516100949190611630565b60008082602001516001600160a01b031683600001516001600160a01b031614156101495760405162461bcd60e51b81526004016101409061169f565b60405180910390fd5b8251604051633462561360e11b8152309182916368c4ac269161016e91600401611544565b60206040518083038186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101be9190810190611146565b801561024557506020840151604051633462561360e11b81526001600160a01b038316916368c4ac26916101f59190600401611544565b60206040518083038186803b15801561020d57600080fd5b505afa158015610221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102459190810190611146565b6102615760405162461bcd60e51b81526004016101409061167f565b60006102d7826001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b505afa1580156102b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506100f191908101906110a6565b905060606102ee8660000151876020015184610777565b608087015160c0880151909550909150600190156103cc57610322876000015188602001518960c001518a60a00151610893565b94508660c00151836001600160a01b0316637f9c0ecd84886040518363ffffffff1660e01b8152600401610357929190611588565b60206040518083038186803b15801561036f57600080fd5b505afa158015610383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103a791908101906111b7565b10156103c55760405162461bcd60e51b8152600401610140906116af565b5060c08601515b600085116103ec5760405162461bcd60e51b81526004016101409061164f565b6103fb85886000015185610afd565b604080880151905163b77d239b60e01b81526001600160a01b0385169163b77d239b916104359186918a91879160009081906004016115a8565b602060405180830381600087803b15801561044f57600080fd5b505af1158015610463573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061048791908101906111b7565b60608801519096506001600160a01b031630146104d4578660a001518510156104d457606087015160a088015188516104d4926001600160a01b039091169188900363ffffffff610baa16565b50505050915091565b60008061051c306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b9050606061052b868684610777565b604051637f9c0ecd60e01b81529091506001600160a01b03831690637f9c0ecd9061055c9084908890600401611588565b60206040518083038186803b15801561057457600080fd5b505afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105ac91908101906111b7565b9695505050505050565b6000806105f5306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b90506060610604868684610777565b90506000826001600160a01b0316637f9c0ecd83876040518363ffffffff1660e01b8152600401610636929190611588565b60206040518083038186803b15801561064e57600080fd5b505afa158015610662573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061068691908101906111b7565b90506106b0856106a483670de0b6b3a764000063ffffffff610c0816565b9063ffffffff610c4b16565b93505050505b9392505050565b6020015190565b600080829050806001600160a01b031663bb34534c61070b60405180604001604052806011815260200170536f7672796e537761704e6574776f726b60781b8152506106bd565b6040518263ffffffff1660e01b81526004016107279190611607565b60206040518083038186803b15801561073f57600080fd5b505afa158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106b691908101906110a6565b604051638654042960e01b8152606090819030906386540429906107a19088908890600401611552565b60006040518083038186803b1580156107b957600080fd5b505afa1580156107cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107f59190810190611111565b90506003815110156108885760405163d734fa1960e01b81526001600160a01b0384169063d734fa199061082f9088908890600401611615565b60006040518083038186803b15801561084757600080fd5b505afa15801561085b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108839190810190611111565b61088a565b805b95945050505050565b6000803090506000816001600160a01b03166378d849ed6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108d457600080fd5b505afa1580156108e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061090c91908101906110a6565b6001600160a01b031663524efd4b88886040518363ffffffff1660e01b8152600401610939929190611552565b60206040518083038186803b15801561095157600080fd5b505afa158015610965573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098991908101906111b7565b90508061099a578392505050610af5565b60006109a78888876105b6565b90506109bd816106a4888563ffffffff610c0816565b935060006109d3856103e863ffffffff610c4b16565b9050836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0e57600080fd5b505afa158015610a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a4691908101906111b7565b811115610ac157836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8657600080fd5b505afa158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610abe91908101906111b7565b90505b610ad1858263ffffffff610c8d16565b9450841580610adf57508585115b15610af05785945050505050610af5565b505050505b949350505050565b604051636eb1769f60e11b81526000906001600160a01b0384169063dd62ed3e90610b2e9030908690600401611552565b60206040518083038186803b158015610b4657600080fd5b505afa158015610b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b7e91908101906111b7565b905083811015610ba457610ba46001600160a01b0384168360001963ffffffff610cb216565b50505050565b604051610c0390849063a9059cbb60e01b90610bcc908690869060240161156d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610d78565b505050565b600082610c1757506000610c45565b82820282848281610c2457fe5b0414610c425760405162461bcd60e51b81526004016101409061168f565b90505b92915050565b6000610c4283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250610e5d565b600082820183811015610c425760405162461bcd60e51b81526004016101409061165f565b801580610d3a5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90610ce89030908690600401611552565b60206040518083038186803b158015610d0057600080fd5b505afa158015610d14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d3891908101906111b7565b155b610d565760405162461bcd60e51b8152600401610140906116cf565b604051610c0390849063095ea7b360e01b90610bcc908690869060240161156d565b610d8a826001600160a01b0316610e94565b610da65760405162461bcd60e51b8152600401610140906116df565b60006060836001600160a01b031683604051610dc29190611538565b6000604051808303816000865af19150503d8060008114610dff576040519150601f19603f3d011682016040523d82523d6000602084013e610e04565b606091505b509150915081610e265760405162461bcd60e51b81526004016101409061166f565b805115610ba45780806020019051610e419190810190611146565b610ba45760405162461bcd60e51b8152600401610140906116bf565b60008183610e7e5760405162461bcd60e51b8152600401610140919061163e565b506000838581610e8a57fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610af5575050151592915050565b8035610c4581611807565b8051610c4581611807565b600082601f830112610ef457600080fd5b8151610f07610f0282611724565b6116fd565b91508181835260208401935060208101905083856020840282011115610f2c57600080fd5b60005b83811015610f585781610f428882610f6d565b8452506020928301929190910190600101610f2f565b5050505092915050565b8051610c458161181e565b8051610c4581611827565b600082601f830112610f8957600080fd5b8135610f97610f0282611745565b91508082526020830160208301858383011115610fb357600080fd5b610fbe8382846117c5565b50505092915050565b600060e08284031215610fd957600080fd5b610fe360e06116fd565b90506000610ff18484610ecd565b825250602061100284848301610ecd565b602083015250604061101684828501610ecd565b604083015250606061102a84828501610ecd565b606083015250608061103e84828501611072565b60808301525060a061105284828501611072565b60a08301525060c061106684828501611072565b60c08301525092915050565b8035610c4581611830565b8051610c4581611830565b60006020828403121561109a57600080fd5b6000610af58484610ecd565b6000602082840312156110b857600080fd5b6000610af58484610ed8565b6000806000606084860312156110d957600080fd5b60006110e58686610ecd565b93505060206110f686828701610ecd565b925050604061110786828701611072565b9150509250925092565b60006020828403121561112357600080fd5b815167ffffffffffffffff81111561113a57600080fd5b610af584828501610ee3565b60006020828403121561115857600080fd5b6000610af58484610f62565b60006020828403121561117657600080fd5b813567ffffffffffffffff81111561118d57600080fd5b610af584828501610f78565b600060e082840312156111ab57600080fd5b6000610af58484610fc7565b6000602082840312156111c957600080fd5b6000610af5848461107d565b60006111e18383611292565b505060200190565b6111f2816117af565b82525050565b6111f281611785565b600061120c82611773565b6112168185611777565b93506112218361176d565b8060005b8381101561124f57815161123988826111d5565b97506112448361176d565b925050600101611225565b509495945050505050565b6111f281611795565b600061126e82611773565b6112788185611780565b93506112888185602086016117d1565b9290920192915050565b6111f281611798565b6111f2816117ba565b60006112af82611773565b6112b98185611777565b93506112c98185602086016117d1565b6112d2816117fd565b9093019392505050565b60006112e9601483611777565b7363616e6e6f742073776170203020746f6b656e7360601b815260200192915050565b6000611319601b83611777565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000611352602083611777565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061138b600e83611777565b6d696e76616c696420746f6b656e7360901b815260200192915050565b60006113b5602183611777565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006113f8600e83611777565b6d1cdbdd5c98d9480f4f4819195cdd60921b815260200192915050565b6000611422602483611777565b7f696e73756666696369656e7420736f7572636520746f6b656e732070726f76698152633232b21760e11b602082015260400192915050565b6000611468602a83611777565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006114b4603683611777565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b602082015260400192915050565b600061150c601f83611777565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b60006106b68284611263565b60208101610c4582846111f8565b6040810161156082856111f8565b6106b660208301846111f8565b6040810161157b82856111f8565b6106b6602083018461125a565b604080825281016115998185611201565b90506106b6602083018461125a565b60c080825281016115b98189611201565b90506115c8602083018861125a565b6115d5604083018761125a565b6115e260608301866111f8565b6115ef60808301856111e9565b6115fc60a083018461129b565b979650505050505050565b60208101610c45828461125a565b604081016116238285611292565b6106b66020830184611292565b60208101610c458284611292565b60208082528101610c4281846112a4565b60208082528101610c45816112dc565b60208082528101610c458161130c565b60208082528101610c4581611345565b60208082528101610c458161137e565b60208082528101610c45816113a8565b60208082528101610c45816113eb565b60208082528101610c4581611415565b60208082528101610c458161145b565b60208082528101610c45816114a7565b60208082528101610c45816114ff565b6040810161157b828561125a565b60405181810167ffffffffffffffff8111828210171561171c57600080fd5b604052919050565b600067ffffffffffffffff82111561173b57600080fd5b5060209081020190565b600067ffffffffffffffff82111561175c57600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b919050565b6000610c45826117a3565b151590565b90565b6000610c4582611785565b6001600160a01b031690565b6000610c4582611798565b6000610c4582611795565b82818337506000910152565b60005b838110156117ec5781810151838201526020016117d4565b83811115610ba45750506000910152565b601f01601f191690565b61181081611785565b811461181b57600080fd5b50565b61181081611790565b61181081611798565b6118108161179556fea365627a7a72315820442923cda7d549003cabd4f660a3fb25f1212665bf81032f0ee5dde5e6d2ded46c6578706572696d656e74616cf564736f6c63430005110040", - "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100615760003560e01c806335aaa79d146100665780636dcd64e51461009d578063809a9e55146100bd578063b1fb7f56146100d0578063ca83d575146100e3575b600080fd5b81801561007257600080fd5b50610086610081366004611199565b610103565b6040516100949291906116ef565b60405180910390f35b6100b06100ab3660046110c4565b6104dd565b6040516100949190611607565b6100b06100cb3660046110c4565b6105b6565b6100b06100de366004611164565b6106bd565b6100f66100f1366004611088565b6106c4565b6040516100949190611630565b60008082602001516001600160a01b031683600001516001600160a01b031614156101495760405162461bcd60e51b81526004016101409061169f565b60405180910390fd5b8251604051633462561360e11b8152309182916368c4ac269161016e91600401611544565b60206040518083038186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101be9190810190611146565b801561024557506020840151604051633462561360e11b81526001600160a01b038316916368c4ac26916101f59190600401611544565b60206040518083038186803b15801561020d57600080fd5b505afa158015610221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102459190810190611146565b6102615760405162461bcd60e51b81526004016101409061167f565b60006102d7826001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b505afa1580156102b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506100f191908101906110a6565b905060606102ee8660000151876020015184610777565b608087015160c0880151909550909150600190156103cc57610322876000015188602001518960c001518a60a00151610893565b94508660c00151836001600160a01b0316637f9c0ecd84886040518363ffffffff1660e01b8152600401610357929190611588565b60206040518083038186803b15801561036f57600080fd5b505afa158015610383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103a791908101906111b7565b10156103c55760405162461bcd60e51b8152600401610140906116af565b5060c08601515b600085116103ec5760405162461bcd60e51b81526004016101409061164f565b6103fb85886000015185610afd565b604080880151905163b77d239b60e01b81526001600160a01b0385169163b77d239b916104359186918a91879160009081906004016115a8565b602060405180830381600087803b15801561044f57600080fd5b505af1158015610463573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061048791908101906111b7565b60608801519096506001600160a01b031630146104d4578660a001518510156104d457606087015160a088015188516104d4926001600160a01b039091169188900363ffffffff610baa16565b50505050915091565b60008061051c306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b9050606061052b868684610777565b604051637f9c0ecd60e01b81529091506001600160a01b03831690637f9c0ecd9061055c9084908890600401611588565b60206040518083038186803b15801561057457600080fd5b505afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105ac91908101906111b7565b9695505050505050565b6000806105f5306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b90506060610604868684610777565b90506000826001600160a01b0316637f9c0ecd83876040518363ffffffff1660e01b8152600401610636929190611588565b60206040518083038186803b15801561064e57600080fd5b505afa158015610662573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061068691908101906111b7565b90506106b0856106a483670de0b6b3a764000063ffffffff610c0816565b9063ffffffff610c4b16565b93505050505b9392505050565b6020015190565b600080829050806001600160a01b031663bb34534c61070b60405180604001604052806011815260200170536f7672796e537761704e6574776f726b60781b8152506106bd565b6040518263ffffffff1660e01b81526004016107279190611607565b60206040518083038186803b15801561073f57600080fd5b505afa158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106b691908101906110a6565b604051638654042960e01b8152606090819030906386540429906107a19088908890600401611552565b60006040518083038186803b1580156107b957600080fd5b505afa1580156107cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107f59190810190611111565b90506003815110156108885760405163d734fa1960e01b81526001600160a01b0384169063d734fa199061082f9088908890600401611615565b60006040518083038186803b15801561084757600080fd5b505afa15801561085b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108839190810190611111565b61088a565b805b95945050505050565b6000803090506000816001600160a01b03166378d849ed6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108d457600080fd5b505afa1580156108e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061090c91908101906110a6565b6001600160a01b031663524efd4b88886040518363ffffffff1660e01b8152600401610939929190611552565b60206040518083038186803b15801561095157600080fd5b505afa158015610965573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098991908101906111b7565b90508061099a578392505050610af5565b60006109a78888876105b6565b90506109bd816106a4888563ffffffff610c0816565b935060006109d3856103e863ffffffff610c4b16565b9050836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0e57600080fd5b505afa158015610a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a4691908101906111b7565b811115610ac157836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8657600080fd5b505afa158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610abe91908101906111b7565b90505b610ad1858263ffffffff610c8d16565b9450841580610adf57508585115b15610af05785945050505050610af5565b505050505b949350505050565b604051636eb1769f60e11b81526000906001600160a01b0384169063dd62ed3e90610b2e9030908690600401611552565b60206040518083038186803b158015610b4657600080fd5b505afa158015610b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b7e91908101906111b7565b905083811015610ba457610ba46001600160a01b0384168360001963ffffffff610cb216565b50505050565b604051610c0390849063a9059cbb60e01b90610bcc908690869060240161156d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610d78565b505050565b600082610c1757506000610c45565b82820282848281610c2457fe5b0414610c425760405162461bcd60e51b81526004016101409061168f565b90505b92915050565b6000610c4283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250610e5d565b600082820183811015610c425760405162461bcd60e51b81526004016101409061165f565b801580610d3a5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90610ce89030908690600401611552565b60206040518083038186803b158015610d0057600080fd5b505afa158015610d14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d3891908101906111b7565b155b610d565760405162461bcd60e51b8152600401610140906116cf565b604051610c0390849063095ea7b360e01b90610bcc908690869060240161156d565b610d8a826001600160a01b0316610e94565b610da65760405162461bcd60e51b8152600401610140906116df565b60006060836001600160a01b031683604051610dc29190611538565b6000604051808303816000865af19150503d8060008114610dff576040519150601f19603f3d011682016040523d82523d6000602084013e610e04565b606091505b509150915081610e265760405162461bcd60e51b81526004016101409061166f565b805115610ba45780806020019051610e419190810190611146565b610ba45760405162461bcd60e51b8152600401610140906116bf565b60008183610e7e5760405162461bcd60e51b8152600401610140919061163e565b506000838581610e8a57fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610af5575050151592915050565b8035610c4581611807565b8051610c4581611807565b600082601f830112610ef457600080fd5b8151610f07610f0282611724565b6116fd565b91508181835260208401935060208101905083856020840282011115610f2c57600080fd5b60005b83811015610f585781610f428882610f6d565b8452506020928301929190910190600101610f2f565b5050505092915050565b8051610c458161181e565b8051610c4581611827565b600082601f830112610f8957600080fd5b8135610f97610f0282611745565b91508082526020830160208301858383011115610fb357600080fd5b610fbe8382846117c5565b50505092915050565b600060e08284031215610fd957600080fd5b610fe360e06116fd565b90506000610ff18484610ecd565b825250602061100284848301610ecd565b602083015250604061101684828501610ecd565b604083015250606061102a84828501610ecd565b606083015250608061103e84828501611072565b60808301525060a061105284828501611072565b60a08301525060c061106684828501611072565b60c08301525092915050565b8035610c4581611830565b8051610c4581611830565b60006020828403121561109a57600080fd5b6000610af58484610ecd565b6000602082840312156110b857600080fd5b6000610af58484610ed8565b6000806000606084860312156110d957600080fd5b60006110e58686610ecd565b93505060206110f686828701610ecd565b925050604061110786828701611072565b9150509250925092565b60006020828403121561112357600080fd5b815167ffffffffffffffff81111561113a57600080fd5b610af584828501610ee3565b60006020828403121561115857600080fd5b6000610af58484610f62565b60006020828403121561117657600080fd5b813567ffffffffffffffff81111561118d57600080fd5b610af584828501610f78565b600060e082840312156111ab57600080fd5b6000610af58484610fc7565b6000602082840312156111c957600080fd5b6000610af5848461107d565b60006111e18383611292565b505060200190565b6111f2816117af565b82525050565b6111f281611785565b600061120c82611773565b6112168185611777565b93506112218361176d565b8060005b8381101561124f57815161123988826111d5565b97506112448361176d565b925050600101611225565b509495945050505050565b6111f281611795565b600061126e82611773565b6112788185611780565b93506112888185602086016117d1565b9290920192915050565b6111f281611798565b6111f2816117ba565b60006112af82611773565b6112b98185611777565b93506112c98185602086016117d1565b6112d2816117fd565b9093019392505050565b60006112e9601483611777565b7363616e6e6f742073776170203020746f6b656e7360601b815260200192915050565b6000611319601b83611777565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000611352602083611777565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061138b600e83611777565b6d696e76616c696420746f6b656e7360901b815260200192915050565b60006113b5602183611777565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006113f8600e83611777565b6d1cdbdd5c98d9480f4f4819195cdd60921b815260200192915050565b6000611422602483611777565b7f696e73756666696369656e7420736f7572636520746f6b656e732070726f76698152633232b21760e11b602082015260400192915050565b6000611468602a83611777565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006114b4603683611777565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b602082015260400192915050565b600061150c601f83611777565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b60006106b68284611263565b60208101610c4582846111f8565b6040810161156082856111f8565b6106b660208301846111f8565b6040810161157b82856111f8565b6106b6602083018461125a565b604080825281016115998185611201565b90506106b6602083018461125a565b60c080825281016115b98189611201565b90506115c8602083018861125a565b6115d5604083018761125a565b6115e260608301866111f8565b6115ef60808301856111e9565b6115fc60a083018461129b565b979650505050505050565b60208101610c45828461125a565b604081016116238285611292565b6106b66020830184611292565b60208101610c458284611292565b60208082528101610c4281846112a4565b60208082528101610c45816112dc565b60208082528101610c458161130c565b60208082528101610c4581611345565b60208082528101610c458161137e565b60208082528101610c45816113a8565b60208082528101610c45816113eb565b60208082528101610c4581611415565b60208082528101610c458161145b565b60208082528101610c45816114a7565b60208082528101610c45816114ff565b6040810161157b828561125a565b60405181810167ffffffffffffffff8111828210171561171c57600080fd5b604052919050565b600067ffffffffffffffff82111561173b57600080fd5b5060209081020190565b600067ffffffffffffffff82111561175c57600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b919050565b6000610c45826117a3565b151590565b90565b6000610c4582611785565b6001600160a01b031690565b6000610c4582611798565b6000610c4582611795565b82818337506000910152565b60005b838110156117ec5781810151838201526020016117d4565b83811115610ba45750506000910152565b601f01601f191690565b61181081611785565b811461181b57600080fd5b50565b61181081611790565b61181081611798565b6118108161179556fea365627a7a72315820442923cda7d549003cabd4f660a3fb25f1212665bf81032f0ee5dde5e6d2ded46c6578706572696d656e74616cf564736f6c63430005110040", + "numDeployments": 2, + "solcInputHash": "444414c40f489390e118f5b65a5947cc", + "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[{\"internalType\":\"string\",\"name\":\"source\",\"type\":\"string\"}],\"name\":\"getContractHexName\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"result\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sourceTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceTokenAmount\",\"type\":\"uint256\"}],\"name\":\"getExpectedRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sourceTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceTokenAmount\",\"type\":\"uint256\"}],\"name\":\"getExpectedReturn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"expectedReturn\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sovrynSwapRegistryAddress\",\"type\":\"address\"}],\"name\":\"getSovrynSwapNetworkContract\",\"outputs\":[{\"internalType\":\"contract ISovrynSwapNetwork\",\"name\":\"\",\"type\":\"ISovrynSwapNetwork\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{\"getContractHexName(string)\":{\"params\":{\"source\":\"The name of the contract.\"}},\"getExpectedRate(address,address,uint256)\":{\"params\":{\"destTokenAddress\":\"The address of the destination token contract.\",\"sourceTokenAddress\":\"The address of the source token contract.\",\"sourceTokenAmount\":\"The amount of source tokens to get the rate for.\"}},\"getExpectedReturn(address,address,uint256)\":{\"params\":{\"destTokenAddress\":\"The address of the destination token contract.\",\"sourceTokenAddress\":\"The address of the source token contract.\",\"sourceTokenAmount\":\"The amount of source tokens to get the return for.\"}},\"getSovrynSwapNetworkContract(address)\":{\"params\":{\"sovrynSwapRegistryAddress\":\"The address of the registry.\"}},\"swap(SwapsImplSovrynSwapLib.SwapParams)\":{\"params\":{\"params\":\"SwapParams struct sourceTokenAddress The address of the source tokens. destTokenAddress The address of the destination tokens. receiverAddress The address who will received the swap token results returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract). minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0). maxSourceTokenAmount The maximum amount of source tokens to swapped. requiredDestTokenAmount The required amount of destination tokens.\"}}},\"title\":\"Swaps Implementation Sovryn contract.\"},\"userdoc\":{\"methods\":{\"getContractHexName(string)\":{\"notice\":\"Get the hex name of a contract.\"},\"getExpectedRate(address,address,uint256)\":{\"notice\":\"Get the expected rate for 1 source token when exchanging the given amount of source tokens.\"},\"getExpectedReturn(address,address,uint256)\":{\"notice\":\"Get the expected return amount when exchanging the given amount of source tokens.Right now, this function is being called directly by _swapsExpectedReturn from the protocol So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call. Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\"},\"getSovrynSwapNetworkContract(address)\":{\"notice\":\"Look up the Sovryn swap network contract registered at the given address.\"},\"swap(SwapsImplSovrynSwapLib.SwapParams)\":{\"notice\":\"Swap the source token for the destination token on the oracle based AMM. On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0 -> swap the minSourceTokenAmount On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0 -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded. On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0 -> same as on rollover. minimum amount is not considered at all.\"}},\"notice\":\"This contract code comes from bZx. bZx is a protocol for tokenized margin trading and lending https://bzx.network similar to the dYdX protocol. * This contract contains the implementation of swap process and rate calculations for Sovryn network.\"}},\"settings\":{\"compilationTarget\":{\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":\"SwapsImplSovrynSwapLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":ds-test/=foundry/lib/forge-std/lib/ds-test/src/\",\":forge-std/=foundry/lib/forge-std/src/\"]},\"sources\":{\"contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nlibrary MarginTradeStructHelpers {\\n struct SentAddresses {\\n address lender;\\n address borrower;\\n address receiver;\\n address manager;\\n }\\n\\n struct SentAmounts {\\n uint256 interestRate;\\n uint256 newPrincipal;\\n uint256 interestInitialAmount;\\n uint256 loanTokenSent;\\n uint256 collateralTokenSent;\\n uint256 minEntryPrice;\\n uint256 loanToCollateralSwapRate;\\n uint256 interestDuration;\\n uint256 entryLeverage;\\n }\\n}\\n\",\"keccak256\":\"0xf0612e2c0d13604a67c3d55efe88810c089f0b84ca63bd3ce82c1e09b0938973\"},\"contracts/core/Objects.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./objects/LoanStruct.sol\\\";\\nimport \\\"./objects/LoanParamsStruct.sol\\\";\\nimport \\\"./objects/OrderStruct.sol\\\";\\nimport \\\"./objects/LenderInterestStruct.sol\\\";\\nimport \\\"./objects/LoanInterestStruct.sol\\\";\\n\\n/**\\n * @title Objects contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract inherints and aggregates several structures needed to handle\\n * loans on the protocol.\\n * */\\ncontract Objects is\\n LoanStruct,\\n LoanParamsStruct,\\n OrderStruct,\\n LenderInterestStruct,\\n LoanInterestStruct\\n{\\n\\n}\\n\",\"keccak256\":\"0xa30b8887af813997ebb480f0aa296245f9f3bd728382060059aa087cd9ee332c\"},\"contracts/core/State.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./Objects.sol\\\";\\nimport \\\"../mixins/EnumerableAddressSet.sol\\\";\\nimport \\\"../mixins/EnumerableBytes32Set.sol\\\";\\nimport \\\"../openzeppelin/ReentrancyGuard.sol\\\";\\nimport \\\"../openzeppelin/Ownable.sol\\\";\\nimport \\\"../openzeppelin/SafeMath.sol\\\";\\nimport \\\"../interfaces/IWrbtcERC20.sol\\\";\\nimport \\\"../reentrancy/SharedReentrancyGuard.sol\\\";\\n\\n/**\\n * @title State contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage values of the Protocol.\\n * */\\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\\n using SafeMath for uint256;\\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\\n\\n /// Handles asset reference price lookups.\\n address public priceFeeds;\\n\\n /// Handles asset swaps using dex liquidity.\\n address public swapsImpl;\\n\\n /// Contract registry address of the Sovryn swap network.\\n address public sovrynSwapContractRegistryAddress;\\n\\n /// Implementations of protocol functions.\\n mapping(bytes4 => address) public logicTargets;\\n\\n /// Loans: loanId => Loan\\n mapping(bytes32 => Loan) public loans;\\n\\n /// Loan parameters: loanParamsId => LoanParams\\n mapping(bytes32 => LoanParams) public loanParams;\\n\\n /// lender => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\\n\\n /// borrower => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\\n\\n /// loanId => delegated => approved\\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\\n\\n /**\\n *** Interest ***\\n **/\\n\\n /// lender => loanToken => LenderInterest object\\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\\n\\n /// loanId => LoanInterest object\\n mapping(bytes32 => LoanInterest) public loanInterest;\\n\\n /**\\n *** Internals ***\\n **/\\n\\n /// Implementations set.\\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\\n\\n /// Active loans set.\\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\\n\\n /// Lender loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\\n\\n /// Borrow loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\\n\\n /// User loan params set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\\n\\n /// Address controlling fee withdrawals.\\n address public feesController;\\n\\n /// 10% fee /// Fee taken from lender interest payments.\\n uint256 public lendingFeePercent = 10**19;\\n\\n /// Total interest fees received and not withdrawn per asset.\\n mapping(address => uint256) public lendingFeeTokensHeld;\\n\\n /// Total interest fees withdraw per asset.\\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\\n mapping(address => uint256) public lendingFeeTokensPaid;\\n\\n /// 0.15% fee /// Fee paid for each trade.\\n uint256 public tradingFeePercent = 15 * 10**16;\\n\\n /// Total trading fees received and not withdrawn per asset.\\n mapping(address => uint256) public tradingFeeTokensHeld;\\n\\n /// Total trading fees withdraw per asset\\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\\n mapping(address => uint256) public tradingFeeTokensPaid;\\n\\n /// 0.09% fee /// Origination fee paid for each loan.\\n uint256 public borrowingFeePercent = 9 * 10**16;\\n\\n /// Total borrowing fees received and not withdrawn per asset.\\n mapping(address => uint256) public borrowingFeeTokensHeld;\\n\\n /// Total borrowing fees withdraw per asset.\\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\\n mapping(address => uint256) public borrowingFeeTokensPaid;\\n\\n /// Current protocol token deposit balance.\\n uint256 public protocolTokenHeld;\\n\\n /// Lifetime total payout of protocol token.\\n uint256 public protocolTokenPaid;\\n\\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\\n uint256 public affiliateFeePercent = 5 * 10**18;\\n\\n /// 5% collateral discount /// Discount on collateral for liquidators.\\n uint256 public liquidationIncentivePercent = 5 * 10**18;\\n\\n /// loanPool => underlying\\n mapping(address => address) public loanPoolToUnderlying;\\n\\n /// underlying => loanPool\\n mapping(address => address) public underlyingToLoanPool;\\n\\n /// Loan pools set.\\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\\n\\n /// Supported tokens for swaps.\\n mapping(address => bool) public supportedTokens;\\n\\n /// % disagreement between swap rate and reference rate.\\n uint256 public maxDisagreement = 5 * 10**18;\\n\\n /// Used as buffer for swap source amount estimations.\\n uint256 public sourceBuffer = 10000;\\n\\n /// Maximum support swap size in rBTC\\n uint256 public maxSwapSize = 50 ether;\\n\\n /// Nonce per borrower. Used for loan id creation.\\n mapping(address => uint256) public borrowerNonce;\\n\\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\\n uint256 public rolloverBaseReward = 16800000000000;\\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\\n\\n IWrbtcERC20 public wrbtcToken;\\n address public protocolTokenAddress;\\n\\n /// 50% fee rebate\\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\\n uint256 public feeRebatePercent = 50 * 10**18;\\n\\n address public admin;\\n\\n /// For modules interaction.\\n address public protocolAddress;\\n\\n /**\\n *** Affiliates ***\\n **/\\n\\n /// The flag is set on the user's first trade.\\n mapping(address => bool) public userNotFirstTradeFlag;\\n\\n /// User => referrer (affiliate).\\n mapping(address => address) public affiliatesUserReferrer;\\n\\n /// List of referral addresses affiliated to the referrer.\\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\\n\\n /// @dev Referral threshold for paying out to the referrer.\\n /// The referrer reward is being accumulated and locked until the threshold is passed.\\n uint256 public minReferralsToPayout = 3;\\n\\n /// @dev Total affiliate SOV rewards that held in the protocol\\n /// (Because the minimum referrals is less than the rule)\\n mapping(address => uint256) public affiliateRewardsHeld;\\n\\n /// @dev For affiliates SOV Bonus proccess.\\n address public sovTokenAddress;\\n address public lockedSOVAddress;\\n\\n /// @dev 20% fee share of trading token fee.\\n /// Fee share of trading token fee for affiliate program.\\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\\n\\n /// @dev Addresses of tokens in which commissions were paid to referrers.\\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\\n\\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\\n\\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\\n bool public pause; //Flag to pause all protocol modules\\n\\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\\n\\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\\n uint256 internal tradingRebateRewardsBasisPoint;\\n\\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\\n /// Will be used in internal swap.\\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\\n\\n address internal pauser;\\n\\n /**\\n * @notice Add signature and target to storage.\\n * @dev Protocol is a proxy and requires a way to add every\\n * module function dynamically during deployment.\\n * */\\n function _setTarget(bytes4 sig, address target) internal {\\n logicTargets[sig] = target;\\n\\n if (target != address(0)) {\\n logicTargetsSet.addBytes32(bytes32(sig));\\n } else {\\n logicTargetsSet.removeBytes32(bytes32(sig));\\n }\\n }\\n\\n modifier onlyAdminOrOwner() {\\n require(isOwner() || admin == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n\\n modifier onlyPauserOrOwner() {\\n require(isOwner() || pauser == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0xf8dfc02f3dc790c73b390a69898d0281c4473487bc91fec1f28fbebceacd3b3c\"},\"contracts/core/objects/LenderInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Lender Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Lender Interest.\\n * */\\ncontract LenderInterestStruct {\\n struct LenderInterest {\\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\\n uint256 paidTotal; /// Total interest paid so far for asset.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0x6583baadddded384836cec469980e7973ec09310ae505b4a2ec67fb7bc19e452\"},\"contracts/core/objects/LoanInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Interest.\\n * */\\ncontract LoanInterestStruct {\\n struct LoanInterest {\\n uint256 owedPerDay; /// Interest owed per day for loan.\\n uint256 depositTotal; /// Total escrowed interest for loan.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0xd9034c6adb1b72e1593589dca024dc4730a1ee8bf6b2dca9d22283f2e7159590\"},\"contracts/core/objects/LoanParamsStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Parameters.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Parameters.\\n * */\\ncontract LoanParamsStruct {\\n struct LoanParams {\\n /// @dev ID of loan params object.\\n bytes32 id;\\n /// @dev If false, this object has been disabled by the owner and can't\\n /// be used for future loans.\\n bool active;\\n /// @dev Owner of this object.\\n address owner;\\n /// @dev The token being loaned.\\n address loanToken;\\n /// @dev The required collateral token.\\n address collateralToken;\\n /// @dev The minimum allowed initial margin.\\n uint256 minInitialMargin;\\n /// @dev An unhealthy loan when current margin is at or below this value.\\n uint256 maintenanceMargin;\\n /// @dev The maximum term for new loans (0 means there's no max term).\\n uint256 maxLoanTerm;\\n }\\n}\\n\",\"keccak256\":\"0xe15aa97713521da7f501e5225af9d92cf34bd68d286dbfed86aa75aabb323945\"},\"contracts/core/objects/LoanStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Object.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Object.\\n * */\\ncontract LoanStruct {\\n struct Loan {\\n bytes32 id; /// ID of the loan.\\n bytes32 loanParamsId; /// The linked loan params ID.\\n bytes32 pendingTradesId; /// The linked pending trades ID.\\n bool active; /// If false, the loan has been fully closed.\\n uint256 principal; /// Total borrowed amount outstanding.\\n uint256 collateral; /// Total collateral escrowed for the loan.\\n uint256 startTimestamp; /// Loan start time.\\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\\n uint256 startMargin; /// Initial margin when the loan opened.\\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\\n address borrower; /// Borrower of this loan.\\n address lender; /// Lender of this loan.\\n }\\n}\\n\",\"keccak256\":\"0x7d05c3096a86d5892e4e72f3a01a5a806f13a5ac90ca6339c611e75c603637b4\"},\"contracts/core/objects/OrderStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Order.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Order.\\n * */\\ncontract OrderStruct {\\n struct Order {\\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\\n uint256 interestRate; /// Interest rate defined by the creator of this order.\\n uint256 minLoanTerm; /// Minimum loan term allowed.\\n uint256 maxLoanTerm; /// Maximum loan term allowed.\\n uint256 createdTimestamp; /// Timestamp when this order was created.\\n uint256 expirationTimestamp; /// Timestamp when this order expires.\\n }\\n}\\n\",\"keccak256\":\"0xcc053c5da34a5927041162259bf856ba913f3524ca03e63ad0c5877777d17e0f\"},\"contracts/events/AffiliatesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\ncontract AffiliatesEvents is ModulesCommonEvents {\\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\\n\\n event SetAffiliatesReferrerFail(\\n address indexed user,\\n address indexed referrer,\\n bool alreadySet,\\n bool userNotFirstTrade\\n );\\n\\n event SetUserNotFirstTradeFlag(address indexed user);\\n\\n event PayTradingFeeToAffiliate(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n bool indexed isHeld,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountPaid\\n );\\n\\n event PayTradingFeeToAffiliateFail(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountTryingToPaid\\n );\\n\\n event WithdrawAffiliatesReferrerTokenFees(\\n address indexed referrer,\\n address indexed receiver,\\n address indexed tokenAddress,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xf72cf23e90db3c49589ddc4e1796680ebfb69a9b146db89f9b61f5fcf6dd95ba\"},\"contracts/events/FeesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Fees Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for fee payments.\\n * */\\ncontract FeesEvents {\\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\\n\\n event PayTradingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event PayBorrowingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event EarnReward(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n\\n event EarnRewardFail(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n}\\n\",\"keccak256\":\"0xe69bf53e15479be5fde1cbaadaf0c004ee038e8a6a37c99f7769bf5d8387015f\"},\"contracts/events/LoanClosingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Closing Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan closing operations.\\n * */\\ncontract LoanClosingsEvents is ModulesCommonEvents {\\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\\n event CloseWithDeposit(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address closer,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\\n event CloseWithSwap(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n address closer,\\n uint256 positionCloseSize,\\n uint256 loanCloseAmount,\\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\\n event Liquidate(\\n address indexed user,\\n address indexed liquidator,\\n bytes32 indexed loanId,\\n address lender,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n event Rollover(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n uint256 principal,\\n uint256 collateral,\\n uint256 endTimestamp,\\n address rewardReceiver,\\n uint256 reward\\n );\\n\\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\\n}\\n\",\"keccak256\":\"0x1ea325b9a213012865a52f38941ce6c1e8c29dce919215b5bdcc63a8a5980be1\"},\"contracts/events/LoanMaintenanceEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Maintenance Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan maintenance operations.\\n * */\\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\\n}\\n\",\"keccak256\":\"0xdee5098b947c22bcef6e38ecaf62bae6941572d1c245d2065ad41ea4f494c61d\"},\"contracts/events/LoanOpeningsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Openings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan openings operations.\\n * */\\ncontract LoanOpeningsEvents is ModulesCommonEvents {\\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\\n event Borrow(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 newCollateral,\\n uint256 interestRate,\\n uint256 interestDuration,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\\n event Trade(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n uint256 positionSize,\\n uint256 borrowedAmount,\\n uint256 interestRate,\\n uint256 settlementDate,\\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\\n uint256 entryLeverage,\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\\n event DelegatedManagerSet(\\n bytes32 indexed loanId,\\n address indexed delegator,\\n address indexed delegated,\\n bool isActive\\n );\\n}\\n\",\"keccak256\":\"0x585710ce6c570c6dbd1b8daf43b63a54b1d60ad01ee1dc3cae407d74d78f3093\"},\"contracts/events/LoanSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan settings operations.\\n * */\\ncontract LoanSettingsEvents is ModulesCommonEvents {\\n event LoanParamsSetup(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\\n\\n event LoanParamsDisabled(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\\n}\\n\",\"keccak256\":\"0xae9c49678a7bc02c2283648939c474c8bfd33781506e05c635c8334c5bf8682f\"},\"contracts/events/ModulesCommonEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\n/**\\n * @title The common events for all modules\\n * @notice This contract contains the events which will be used by all modules\\n **/\\n\\ncontract ModulesCommonEvents {\\n event ProtocolModuleContractReplaced(\\n address indexed prevModuleContractAddress,\\n address indexed newModuleContractAddress,\\n bytes32 indexed module\\n );\\n}\\n\",\"keccak256\":\"0xb07af42d7e6b0fe983889b883691b662a58d2ef8d75b3f32f17faff1871c8b8f\"},\"contracts/events/ProtocolSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title The Protocol Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for protocol settings operations.\\n * */\\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetLoanPool(\\n address indexed sender,\\n address indexed loanPool,\\n address indexed underlying\\n );\\n\\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\\n\\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateTradingTokenFeePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetLiquidationIncentivePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetFeesController(\\n address indexed sender,\\n address indexed oldController,\\n address indexed newController\\n );\\n\\n event SetWrbtcToken(\\n address indexed sender,\\n address indexed oldWethToken,\\n address indexed newWethToken\\n );\\n\\n event SetSovrynSwapContractRegistryAddress(\\n address indexed sender,\\n address indexed oldSovrynSwapContractRegistryAddress,\\n address indexed newSovrynSwapContractRegistryAddress\\n );\\n\\n event SetProtocolTokenAddress(\\n address indexed sender,\\n address indexed oldProtocolToken,\\n address indexed newProtocolToken\\n );\\n\\n event WithdrawFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 lendingAmount,\\n uint256 tradingAmount,\\n uint256 borrowingAmount,\\n uint256 wRBTCConverted\\n );\\n\\n event WithdrawLendingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawTradingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawBorrowingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetRebatePercent(\\n address indexed sender,\\n uint256 oldRebatePercent,\\n uint256 newRebatePercent\\n );\\n\\n event SetSpecialRebates(\\n address indexed sender,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 oldSpecialRebatesPercent,\\n uint256 newSpecialRebatesPercent\\n );\\n\\n event SetProtocolAddress(\\n address indexed sender,\\n address indexed oldProtocol,\\n address indexed newProtocol\\n );\\n\\n event SetMinReferralsToPayoutAffiliates(\\n address indexed sender,\\n uint256 oldMinReferrals,\\n uint256 newMinReferrals\\n );\\n\\n event SetSOVTokenAddress(\\n address indexed sender,\\n address indexed oldTokenAddress,\\n address indexed newTokenAddress\\n );\\n\\n event SetLockedSOVAddress(\\n address indexed sender,\\n address indexed oldAddress,\\n address indexed newAddress\\n );\\n\\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\\n\\n event SetTradingRebateRewardsBasisPoint(\\n address indexed sender,\\n uint256 oldBasisPoint,\\n uint256 newBasisPoint\\n );\\n\\n event SetRolloverFlexFeePercent(\\n address indexed sender,\\n uint256 oldRolloverFlexFeePercent,\\n uint256 newRolloverFlexFeePercent\\n );\\n\\n event SetDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event RemoveDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\\n\\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\\n}\\n\",\"keccak256\":\"0x20ca66a2c53669aa33379bf5233e3bcdddbba3504cd430a0143f0ee3ce1c2641\"},\"contracts/events/SwapsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Swaps Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for swap operations.\\n * */\\ncontract SwapsEvents is ModulesCommonEvents {\\n event LoanSwap(\\n bytes32 indexed loanId,\\n address indexed sourceToken,\\n address indexed destToken,\\n address borrower,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n\\n event ExternalSwap(\\n address indexed user,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n}\\n\",\"keccak256\":\"0x0a1cd289076675980b916941ed923146160d34a8669fc3fb4a06610f285dfbd1\"},\"contracts/feeds/IPriceFeeds.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface IPriceFeeds {\\n function queryRate(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 rate, uint256 precision);\\n\\n function queryPrecision(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 precision);\\n\\n function queryReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount\\n ) external view returns (uint256 destAmount);\\n\\n function checkPriceDisagreement(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount,\\n uint256 destAmount,\\n uint256 maxSlippage\\n ) external view returns (uint256 sourceToDestSwapRate);\\n\\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\\n\\n function getMaxDrawdown(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (uint256);\\n\\n function getCurrentMarginAndCollateralSize(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\\n\\n function getCurrentMargin(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\\n\\n function shouldLiquidate(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (bool);\\n\\n function getFastGasPrice(address payToken) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x2e2c2b393336efedb97659a2fc21c8dfb75b70e15d2422a3bcbf7ebd5fc83c82\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/interfaces/ISovryn.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\npragma experimental ABIEncoderV2;\\n//TODO: stored in ./interfaces only while brownie isn't removed\\n//TODO: move to contracts/interfaces after with brownie is removed\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/ProtocolSettingsEvents.sol\\\";\\nimport \\\"../events/LoanSettingsEvents.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../events/LoanMaintenanceEvents.sol\\\";\\nimport \\\"../events/LoanClosingsEvents.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../events/AffiliatesEvents.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\ncontract ISovryn is\\n State,\\n ProtocolSettingsEvents,\\n LoanSettingsEvents,\\n LoanOpeningsEvents,\\n LoanMaintenanceEvents,\\n LoanClosingsEvents,\\n SwapsEvents,\\n AffiliatesEvents,\\n FeesEvents\\n{\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n ////// Protocol //////\\n\\n function replaceContract(address target) external;\\n\\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\\n\\n function getTarget(string calldata sig) external view returns (address);\\n\\n ////// Protocol Settings //////\\n\\n function setSovrynProtocolAddress(address newProtocolAddress) external;\\n\\n function setSOVTokenAddress(address newSovTokenAddress) external;\\n\\n function setLockedSOVAddress(address newSOVLockedAddress) external;\\n\\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\\n\\n function setPriceFeedContract(address newContract) external;\\n\\n function setSwapsImplContract(address newContract) external;\\n\\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\\n\\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\\n\\n function setLendingFeePercent(uint256 newValue) external;\\n\\n function setTradingFeePercent(uint256 newValue) external;\\n\\n function setBorrowingFeePercent(uint256 newValue) external;\\n\\n function setSwapExternalFeePercent(uint256 newValue) external;\\n\\n function setAffiliateFeePercent(uint256 newValue) external;\\n\\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\\n\\n function setLiquidationIncentivePercent(uint256 newAmount) external;\\n\\n function setMaxDisagreement(uint256 newAmount) external;\\n\\n function setSourceBuffer(uint256 newAmount) external;\\n\\n function setMaxSwapSize(uint256 newAmount) external;\\n\\n function setFeesController(address newController) external;\\n\\n function withdrawFees(address[] calldata tokens, address receiver)\\n external\\n returns (uint256 totalWRBTCWithdrawn);\\n\\n function withdrawLendingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawTradingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawBorrowingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawProtocolToken(address receiver, uint256 amount)\\n external\\n returns (address, bool);\\n\\n function depositProtocolToken(uint256 amount) external;\\n\\n function getLoanPoolsList(uint256 start, uint256 count)\\n external\\n view\\n returns (bytes32[] memory);\\n\\n function isLoanPool(address loanPool) external view returns (bool);\\n\\n function setWrbtcToken(address wrbtcTokenAddress) external;\\n\\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\\n\\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\\n\\n function setRolloverBaseReward(uint256 transactionCost) external;\\n\\n function setRebatePercent(uint256 rebatePercent) external;\\n\\n function setSpecialRebates(\\n address sourceToken,\\n address destToken,\\n uint256 specialRebatesPercent\\n ) external;\\n\\n function getSpecialRebates(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 specialRebatesPercent);\\n\\n function togglePaused(bool paused) external;\\n\\n function isProtocolPaused() external view returns (bool);\\n\\n ////// SwapsImplSovrynSwapModule //////\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (address);\\n\\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\\n\\n function swapsImplExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function swapsImplExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256 expectedReturn);\\n\\n ////// Loan Settings //////\\n\\n function setupLoanParams(LoanParams[] calldata loanParamsList)\\n external\\n returns (bytes32[] memory loanParamsIdList);\\n\\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\\n\\n function getLoanParams(bytes32[] calldata loanParamsIdList)\\n external\\n view\\n returns (LoanParams[] memory loanParamsList);\\n\\n function getLoanParamsList(\\n address owner,\\n uint256 start,\\n uint256 count\\n ) external view returns (bytes32[] memory loanParamsList);\\n\\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\\n\\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\\n\\n ////// Loan Openings //////\\n\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId, // if 0, start a new loan\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n // lender: must match loan if loanId provided\\n // borrower: must match loan if loanId provided\\n // receiver: receiver of funds (address(0) assumes borrower address)\\n // manager: delegated manager of loan unless address(0)\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n // newRate: new loan interest rate\\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\\n // collateralTokenReceived: total collateralToken deposit\\n bytes calldata loanDataBytes\\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\\n\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external;\\n\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256);\\n\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 collateralAmountRequired);\\n\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 borrowAmount);\\n\\n ////// Loan Closings //////\\n\\n function liquidate(\\n bytes32 loanId,\\n address receiver,\\n uint256 closeAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 seizedAmount,\\n address seizedToken\\n );\\n\\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\\n\\n function closeWithDeposit(\\n bytes32 loanId,\\n address receiver,\\n uint256 depositAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n function closeWithSwap(\\n bytes32 loanId,\\n address receiver,\\n uint256 swapAmount, // denominated in collateralToken\\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\\n bytes calldata loanDataBytes\\n )\\n external\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n ////// Loan Maintenance //////\\n\\n function depositCollateral(\\n bytes32 loanId,\\n uint256 depositAmount // must match msg.value if ether is sent\\n ) external payable;\\n\\n function withdrawCollateral(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 actualWithdrawAmount);\\n\\n function withdrawAccruedInterest(address loanToken) external;\\n\\n function getLenderInterestData(address lender, address loanToken)\\n external\\n view\\n returns (\\n uint256 interestPaid,\\n uint256 interestPaidDate,\\n uint256 interestOwedPerDay,\\n uint256 interestUnPaid,\\n uint256 interestFeePercent,\\n uint256 principalTotal\\n );\\n\\n function getLoanInterestData(bytes32 loanId)\\n external\\n view\\n returns (\\n address loanToken,\\n uint256 interestOwedPerDay,\\n uint256 interestDepositTotal,\\n uint256 interestDepositRemaining\\n );\\n\\n struct LoanReturnData {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; // collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n }\\n\\n struct LoanReturnDataV2 {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n address borrower;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; /// collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n uint256 creationTimestamp;\\n }\\n\\n function getUserLoans(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getUserLoansV2(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\\n\\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\\n\\n function getActiveLoans(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getActiveLoansV2(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function extendLoanDuration(\\n bytes32 loanId,\\n uint256 depositAmount,\\n bool useCollateral,\\n bytes calldata /// loanDataBytes, for future use.\\n ) external returns (uint256 secondsExtended);\\n\\n function reduceLoanDuration(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 secondsReduced);\\n\\n ////// Swaps External //////\\n function swapExternal(\\n address sourceToken,\\n address destToken,\\n address receiver,\\n address returnToSender,\\n uint256 sourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n uint256 minReturn,\\n bytes calldata swapData\\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\\n\\n function getSwapExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function checkPriceDivergence(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount,\\n uint256 minReturn\\n ) public view;\\n\\n ////// Affiliates Module //////\\n\\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\\n\\n function setUserNotFirstTradeFlag(address user) external;\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address referrer,\\n address trader,\\n address token,\\n uint256 tradingFeeTokenBaseAmount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n\\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\\n\\n function getReferralsList(address referrer) external view returns (address[] memory refList);\\n\\n function getAffiliatesReferrerBalances(address referrer)\\n external\\n view\\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\\n\\n function getAffiliatesReferrerTokensList(address referrer)\\n external\\n view\\n returns (address[] memory tokensList);\\n\\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\\n external\\n view\\n returns (uint256);\\n\\n function withdrawAffiliatesReferrerTokenFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external;\\n\\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\\n\\n function getProtocolAddress() external view returns (address);\\n\\n function getSovTokenAddress() external view returns (address);\\n\\n function getLockedSOVAddress() external view returns (address);\\n\\n function getFeeRebatePercent() external view returns (uint256);\\n\\n function getMinReferralsToPayout() external view returns (uint256);\\n\\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\\n\\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\\n\\n function getAffiliateTradingTokenFeePercent()\\n external\\n view\\n returns (uint256 affiliateTradingTokenFeePercent);\\n\\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\\n external\\n view\\n returns (uint256 rbtcTotalAmount);\\n\\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\\n\\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\\n\\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\\n\\n function getDedicatedSOVRebate() external view returns (uint256);\\n\\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\\n\\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external\\n view\\n returns (IERC20[] memory);\\n\\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\\n\\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external;\\n\\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\\n external\\n view\\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\\n\\n function setAdmin(address newAdmin) external;\\n\\n function getAdmin() external view returns (address);\\n\\n function setPauser(address newPauser) external;\\n\\n function getPauser() external view returns (address);\\n}\\n\",\"keccak256\":\"0x4e470e1fe1719c2c58b0e44aedce3ee6a21191063b533ccb71c9219a192e8884\"},\"contracts/interfaces/IWrbtc.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ninterface IWrbtc {\\n function deposit() external payable;\\n\\n function withdraw(uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x20fdfe4b5e32fd7f863b3fa128e3c80bd4ccf090a4ffba56186ef3b7f2a80492\"},\"contracts/interfaces/IWrbtcERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./IWrbtc.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\n\\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\\n\",\"keccak256\":\"0x7301a8c8ca7aa016ec94268a16d07366875f2e406442e929968dd745b1ee5be5\"},\"contracts/mixins/EnumerableAddressSet.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Based on Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * As of v2.5.0, only `address` sets are supported.\\n *\\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\\n *\\n * _Available since v2.5.0._\\n */\\nlibrary EnumerableAddressSet {\\n struct AddressSet {\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(address => uint256) index;\\n address[] values;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n * Returns false if the value was already in the set.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n * Returns false if the value was not present in the set.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n // If the element we're deleting is the last one, we can just remove it without doing a swap\\n if (lastIndex != toDeleteIndex) {\\n address lastValue = set.values[lastIndex];\\n\\n // Move the last value to the index where the deleted value is\\n set.values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n // Delete the index entry for the deleted value\\n delete set.index[value];\\n\\n // Delete the old entry for the moved value\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns an array with all values in the set. O(N).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\\n address[] memory output = new address[](set.values.length);\\n for (uint256 i; i < set.values.length; i++) {\\n output[i] = set.values[i];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n \\n * @param start start index of chunk\\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\\n */\\n function enumerateChunk(\\n AddressSet storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (address[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = (set.values.length < end || count == 0) ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new address[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns the number of elements on the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /** @dev Returns the element stored at position `index` in the set. O(1).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xea6fba941ec8502aa11a7ab37e74b917d0dc47bb254e359a2870a87ef97d9872\"},\"contracts/mixins/EnumerableBytes32Set.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title Library for managing loan sets.\\n *\\n * @notice Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\\n * */\\nlibrary EnumerableBytes32Set {\\n struct Bytes32Set {\\n /// Position of the value in the `values` array, plus 1 because index 0\\n /// means a value is not in the set.\\n mapping(bytes32 => uint256) index;\\n bytes32[] values;\\n }\\n\\n /**\\n * @notice Add an address value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return addBytes32(set, value);\\n }\\n\\n /**\\n * @notice Add a value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The new value to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Remove an address value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to remove.\\n *\\n * @return False if the address was not present in the set.\\n */\\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return removeBytes32(set, value);\\n }\\n\\n /**\\n * @notice Remove a value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The value to remove.\\n *\\n * @return False if the value was not present in the set.\\n */\\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n /// If the element we're deleting is the last one,\\n /// we can just remove it without doing a swap.\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set.values[lastIndex];\\n\\n /// Move the last value to the index where the deleted value is.\\n set.values[toDeleteIndex] = lastValue;\\n\\n /// Update the index for the moved value.\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n /// Delete the index entry for the deleted value.\\n delete set.index[value];\\n\\n /// Delete the old entry for the moved value.\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Find out whether a value exists in the set.\\n *\\n * @param set The set of values.\\n * @param value The value to find.\\n *\\n * @return True if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function containsAddress(Bytes32Set storage set, address addrvalue)\\n internal\\n view\\n returns (bool)\\n {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @notice Get all set values.\\n *\\n * @param set The set of values.\\n * @param start The offset of the returning set.\\n * @param count The limit of number of values to return.\\n *\\n * @return An array with all values in the set. O(N).\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(\\n Bytes32Set storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (bytes32[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = set.values.length < end ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new bytes32[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @notice Get the legth of the set.\\n *\\n * @param set The set of values.\\n *\\n * @return the number of elements on the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /**\\n * @notice Get an item from the set by its index.\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n *\\n * @param set The set of values.\\n * @param index The index of the value to return.\\n *\\n * @return the element stored at position `index` in the set. O(1).\\n */\\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xa2801a585c566e07f21c1ebccd0cd0447dd5fd9fe6c1ff2b58d4d979d88a6db0\"},\"contracts/openzeppelin/Address.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n codehash := extcodehash(account)\\n }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x23df48a01dbac9b25e86c9131174fb7752bbc7e741e63f1aa982de22e055ad54\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/openzeppelin/ReentrancyGuard.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @title Helps contracts guard against reentrancy attacks.\\n * @author Remco Bloemen , Eenae \\n * @dev If you mark a function `nonReentrant`, you should also\\n * mark it `external`.\\n */\\ncontract ReentrancyGuard {\\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\\n\\n /// @dev Constant for locked guard state\\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\\n\\n /**\\n * @dev We use a single lock for the whole contract.\\n */\\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * If you mark a function `nonReentrant`, you should also\\n * mark it `external`. Calling one `nonReentrant` function from\\n * another is not supported. Instead, you can implement a\\n * `private` function doing the actual work, and an `external`\\n * wrapper marked as `nonReentrant`.\\n */\\n modifier nonReentrant() {\\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \\\"nonReentrant\\\");\\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\\n _;\\n reentrancyLock = REENTRANCY_GUARD_FREE;\\n }\\n}\\n\",\"keccak256\":\"0xd347de96ad57d1e45b07a2efe3050c1bd4b809236bbf354acb593de56d21a5c9\"},\"contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./Address.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\\n );\\n }\\n\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance =\\n token.allowance(address(this), spender).sub(\\n value,\\n \\\"SafeERC20: decreased allowance below zero\\\"\\n );\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) {\\n // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe99b4d979cb976a6b70e297600242afe38b8cd8f1b1ba6ee373f39f7abb3ca79\"},\"contracts/openzeppelin/SafeMath.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\\n return divCeil(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n\\n if (a == 0) {\\n return 0;\\n }\\n uint256 c = ((a - 1) / b) + 1;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n\\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n return _a < _b ? _a : _b;\\n }\\n}\\n\",\"keccak256\":\"0xbff8d6273e1a6870d1a142c0c23acd63a4dd47760f250390f49ee56333bcb6e8\"},\"contracts/reentrancy/Mutex.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/*\\n * @title Global Mutex contract\\n *\\n * @notice A mutex contract that allows only one function to be called at a time out\\n * of a large set of functions. *Anyone* in the network can freely use any instance\\n * of this contract to add a universal mutex to any function in any contract.\\n */\\ncontract Mutex {\\n /*\\n * We use an uint to store the mutex state.\\n */\\n uint256 public value;\\n\\n /*\\n * @notice Increment the mutex state and return the new value.\\n *\\n * @dev This is the function that will be called by anyone to change the mutex\\n * state. It is purposely not protected by any access control\\n */\\n function incrementAndGetValue() external returns (uint256) {\\n /*\\n * increment value using unsafe math. This is safe because we are\\n * pretty certain no one will ever increment the value 2^256 times\\n * in a single transaction.\\n */\\n return ++value;\\n }\\n}\\n\",\"keccak256\":\"0xd10b0fd07d5fed1ae1237e7c87e6501970fce2a86e2b8862e502258b0d3aeb2c\"},\"contracts/reentrancy/SharedReentrancyGuard.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./Mutex.sol\\\";\\n\\n/*\\n * @title Abstract contract for shared reentrancy guards\\n *\\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\\n * that there's no reentrancy between *any* functions marked with the modifier.\\n *\\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\\n */\\ncontract SharedReentrancyGuard {\\n /*\\n * This is the address of the mutex contract that will be used as the\\n * reentrancy guard.\\n *\\n * The address is hardcoded to avoid changing the memory layout of\\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\\n * because the Mutex contract is always deployed to the same address, with the\\n * same method used in the deployment of ERC1820Registry.\\n */\\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\\n\\n /*\\n * This is the modifier that will be used to protect functions from\\n * reentrancy. It will call the mutex contract to increment the mutex\\n * state and then revert if the mutex state was changed by another\\n * nested call.\\n */\\n modifier globallyNonReentrant() {\\n uint256 previous = MUTEX.incrementAndGetValue();\\n\\n _;\\n\\n /*\\n * If the mutex state was changed by a nested function call, then\\n * the value of the state variable will be different from the previous value.\\n */\\n require(previous == MUTEX.value(), \\\"reentrancy violation\\\");\\n }\\n}\\n\",\"keccak256\":\"0x2d0e61b104b91c1764f20fbeb381ba0f8a8889934ba7f6e8a167ed542ec2c124\"},\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":{\"content\":\"pragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"./interfaces/ISovrynSwapNetwork.sol\\\";\\nimport \\\"./interfaces/IContractRegistry.sol\\\";\\nimport \\\"../../interfaces/ISovryn.sol\\\";\\n\\n/**\\n * @title Swaps Implementation Sovryn contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the implementation of swap process and rate\\n * calculations for Sovryn network.\\n * */\\nlibrary SwapsImplSovrynSwapLib {\\n using SafeMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n struct SwapParams {\\n address sourceTokenAddress;\\n address destTokenAddress;\\n address receiverAddress;\\n address returnToSenderAddress;\\n uint256 minSourceTokenAmount;\\n uint256 maxSourceTokenAmount;\\n uint256 requiredDestTokenAmount;\\n }\\n\\n /// bytes32 contractName = hex\\\"42616e636f724e6574776f726b\\\"; /// \\\"SovrynSwapNetwork\\\"\\n\\n /**\\n * Get the hex name of a contract.\\n * @param source The name of the contract.\\n * */\\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\\n assembly {\\n result := mload(add(source, 32))\\n }\\n }\\n\\n /**\\n * Look up the Sovryn swap network contract registered at the given address.\\n * @param sovrynSwapRegistryAddress The address of the registry.\\n * */\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (ISovrynSwapNetwork)\\n {\\n /// State variable sovrynSwapContractRegistryAddress is part of\\n /// State.sol and set in ProtocolSettings.sol and this function\\n /// needs to work without delegate call as well -> therefore pass it.\\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\\n return\\n ISovrynSwapNetwork(\\n contractRegistry.addressOf(getContractHexName(\\\"SovrynSwapNetwork\\\"))\\n );\\n }\\n\\n /**\\n * Swap the source token for the destination token on the oracle based AMM.\\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\\n * -> swap the minSourceTokenAmount\\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\\n * -> same as on rollover. minimum amount is not considered at all.\\n *\\n * @param params SwapParams struct\\n * sourceTokenAddress The address of the source tokens.\\n * destTokenAddress The address of the destination tokens.\\n * receiverAddress The address who will received the swap token results\\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\\n * requiredDestTokenAmount The required amount of destination tokens.\\n * */\\n function swap(SwapParams memory params)\\n public\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n require(params.sourceTokenAddress != params.destTokenAddress, \\\"source == dest\\\");\\n\\n ISovryn iSovryn = ISovryn(address(this));\\n require(\\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\\n iSovryn.supportedTokens(params.destTokenAddress),\\n \\\"invalid tokens\\\"\\n );\\n\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\\n\\n IERC20[] memory path =\\n _getConversionPath(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n sovrynSwapNetwork\\n );\\n\\n uint256 minReturn = 1;\\n sourceTokenAmountUsed = params.minSourceTokenAmount;\\n\\n /// If the required amount of destination tokens is passed, we need to\\n /// calculate the estimated amount of source tokens regardless of the\\n /// minimum source token amount (name is misleading).\\n if (params.requiredDestTokenAmount > 0) {\\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n params.requiredDestTokenAmount,\\n params.maxSourceTokenAmount\\n );\\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\\n require(\\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\\n params.requiredDestTokenAmount,\\n \\\"insufficient source tokens provided.\\\"\\n );\\n minReturn = params.requiredDestTokenAmount;\\n }\\n\\n require(sourceTokenAmountUsed > 0, \\\"cannot swap 0 tokens\\\");\\n\\n _allowTransfer(\\n sourceTokenAmountUsed,\\n params.sourceTokenAddress,\\n address(sovrynSwapNetwork)\\n );\\n\\n /// @dev Note: the kyber connector uses .call() to interact with kyber\\n /// to avoid bubbling up. here we allow bubbling up.\\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\\n path,\\n sourceTokenAmountUsed,\\n minReturn,\\n params.receiverAddress,\\n address(0),\\n 0\\n );\\n\\n /// If the sender is not the protocol (calling with delegatecall),\\n /// return the remainder to the specified address.\\n /// @dev Note: for the case that the swap is used without the\\n /// protocol. Not sure if it should, though. needs to be discussed.\\n if (params.returnToSenderAddress != address(this)) {\\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\\n /// Send unused source token back.\\n IERC20(params.sourceTokenAddress).safeTransfer(\\n params.returnToSenderAddress,\\n params.maxSourceTokenAmount - sourceTokenAmountUsed\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Check whether the existing allowance suffices to transfer\\n * the needed amount of tokens.\\n * If not, allows the transfer of an arbitrary amount of tokens.\\n *\\n * @param tokenAmount The amount to transfer.\\n * @param tokenAddress The address of the token to transfer.\\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\\n * */\\n function _allowTransfer(\\n uint256 tokenAmount,\\n address tokenAddress,\\n address sovrynSwapNetwork\\n ) internal {\\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\\n if (tempAllowance < tokenAmount) {\\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\\n }\\n }\\n\\n /**\\n * @notice Calculate the number of source tokens to provide in order to\\n * obtain the required destination amount.\\n *\\n * @param sourceTokenAddress The address of the source token address.\\n * @param destTokenAddress The address of the destination token address.\\n * @param requiredDestTokenAmount The number of destination tokens needed.\\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\\n *\\n * @return The estimated amount of source tokens needed.\\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\\n * */\\n function _estimateSourceTokenAmount(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 requiredDestTokenAmount,\\n uint256 maxSourceTokenAmount\\n ) internal view returns (uint256 estimatedSourceAmount) {\\n ISovryn iSovryn = ISovryn(address(this));\\n uint256 sourceToDestPrecision =\\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\\n\\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\\n uint256 expectedRate =\\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\\n\\n /// Compute the source tokens needed to get the required amount with the worst case rate.\\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\\n expectedRate\\n );\\n\\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\\n uint256 buffer = estimatedSourceAmount.div(1000);\\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\\n\\n /// Never spend more than the maximum.\\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\\n return maxSourceTokenAmount;\\n }\\n\\n /**\\n * @notice Get the expected rate for 1 source token when exchanging the\\n * given amount of source tokens.\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\\n * */\\n function getExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n\\n /// Return the rate for 1 token with 18 decimals.\\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\\n }\\n\\n /**\\n * @notice Get the expected return amount when exchanging the given\\n * amount of source tokens.\\n *\\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the return for.\\n * */\\n function getExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256 expectedReturn) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n }\\n\\n function _getConversionPath(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n ISovrynSwapNetwork sovrynSwapNetwork\\n ) private view returns (IERC20[] memory path) {\\n IERC20[] memory _defaultPathConversion =\\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\\n\\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\\n path = _defaultPathConversion.length >= 3\\n ? _defaultPathConversion\\n : sovrynSwapNetwork.conversionPath(\\n IERC20(sourceTokenAddress),\\n IERC20(destTokenAddress)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x058b8d733422a2421f17d1b159aed69f151ea8d5f48ee507bac5b4e86add8b0c\"},\"contracts/swaps/connectors/interfaces/IContractRegistry.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\ncontract IContractRegistry {\\n function addressOf(bytes32 contractName) public view returns (address);\\n}\\n\",\"keccak256\":\"0x793c4eefa2ee04cbf0a1a9da28676ac310ed7bf60a27ec7d86de7d7236ccf45b\"},\"contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol\":{\"content\":\"pragma solidity >=0.5.8 <=0.5.17;\\n\\nimport \\\"../../../interfaces/IERC20.sol\\\";\\n\\ncontract ISovrynSwapNetwork {\\n function convertByPath(\\n IERC20[] calldata _path,\\n uint256 _amount,\\n uint256 _minReturn,\\n address _beneficiary,\\n address _affiliateAccount,\\n uint256 _affiliateFee\\n ) external payable returns (uint256);\\n\\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\\n\\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\\n external\\n view\\n returns (IERC20[] memory);\\n}\\n\",\"keccak256\":\"0xcd28e146b77183bff18f78b511912f7ebe60d437430fdaa72ed145fdda61a5ad\"}},\"version\":1}", + "bytecode": "0x61187c610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100615760003560e01c806335aaa79d146100665780636dcd64e51461009d578063809a9e55146100bd578063b1fb7f56146100d0578063ca83d575146100e3575b600080fd5b81801561007257600080fd5b50610086610081366004611199565b610103565b6040516100949291906116ef565b60405180910390f35b6100b06100ab3660046110c4565b6104dd565b6040516100949190611607565b6100b06100cb3660046110c4565b6105b6565b6100b06100de366004611164565b6106bd565b6100f66100f1366004611088565b6106c4565b6040516100949190611630565b60008082602001516001600160a01b031683600001516001600160a01b031614156101495760405162461bcd60e51b81526004016101409061169f565b60405180910390fd5b8251604051633462561360e11b8152309182916368c4ac269161016e91600401611544565b60206040518083038186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101be9190810190611146565b801561024557506020840151604051633462561360e11b81526001600160a01b038316916368c4ac26916101f59190600401611544565b60206040518083038186803b15801561020d57600080fd5b505afa158015610221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102459190810190611146565b6102615760405162461bcd60e51b81526004016101409061167f565b60006102d7826001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b505afa1580156102b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506100f191908101906110a6565b905060606102ee8660000151876020015184610777565b608087015160c0880151909550909150600190156103cc57610322876000015188602001518960c001518a60a00151610893565b94508660c00151836001600160a01b0316637f9c0ecd84886040518363ffffffff1660e01b8152600401610357929190611588565b60206040518083038186803b15801561036f57600080fd5b505afa158015610383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103a791908101906111b7565b10156103c55760405162461bcd60e51b8152600401610140906116af565b5060c08601515b600085116103ec5760405162461bcd60e51b81526004016101409061164f565b6103fb85886000015185610afd565b604080880151905163b77d239b60e01b81526001600160a01b0385169163b77d239b916104359186918a91879160009081906004016115a8565b602060405180830381600087803b15801561044f57600080fd5b505af1158015610463573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061048791908101906111b7565b60608801519096506001600160a01b031630146104d4578660a001518510156104d457606087015160a088015188516104d4926001600160a01b039091169188900363ffffffff610baa16565b50505050915091565b60008061051c306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b9050606061052b868684610777565b604051637f9c0ecd60e01b81529091506001600160a01b03831690637f9c0ecd9061055c9084908890600401611588565b60206040518083038186803b15801561057457600080fd5b505afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105ac91908101906111b7565b9695505050505050565b6000806105f5306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b90506060610604868684610777565b90506000826001600160a01b0316637f9c0ecd83876040518363ffffffff1660e01b8152600401610636929190611588565b60206040518083038186803b15801561064e57600080fd5b505afa158015610662573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061068691908101906111b7565b90506106b0856106a483670de0b6b3a764000063ffffffff610c0816565b9063ffffffff610c4b16565b93505050505b9392505050565b6020015190565b600080829050806001600160a01b031663bb34534c61070b60405180604001604052806011815260200170536f7672796e537761704e6574776f726b60781b8152506106bd565b6040518263ffffffff1660e01b81526004016107279190611607565b60206040518083038186803b15801561073f57600080fd5b505afa158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106b691908101906110a6565b604051638654042960e01b8152606090819030906386540429906107a19088908890600401611552565b60006040518083038186803b1580156107b957600080fd5b505afa1580156107cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107f59190810190611111565b90506003815110156108885760405163d734fa1960e01b81526001600160a01b0384169063d734fa199061082f9088908890600401611615565b60006040518083038186803b15801561084757600080fd5b505afa15801561085b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108839190810190611111565b61088a565b805b95945050505050565b6000803090506000816001600160a01b03166378d849ed6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108d457600080fd5b505afa1580156108e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061090c91908101906110a6565b6001600160a01b031663524efd4b88886040518363ffffffff1660e01b8152600401610939929190611552565b60206040518083038186803b15801561095157600080fd5b505afa158015610965573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098991908101906111b7565b90508061099a578392505050610af5565b60006109a78888876105b6565b90506109bd816106a4888563ffffffff610c0816565b935060006109d3856103e863ffffffff610c4b16565b9050836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0e57600080fd5b505afa158015610a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a4691908101906111b7565b811115610ac157836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8657600080fd5b505afa158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610abe91908101906111b7565b90505b610ad1858263ffffffff610c8d16565b9450841580610adf57508585115b15610af05785945050505050610af5565b505050505b949350505050565b604051636eb1769f60e11b81526000906001600160a01b0384169063dd62ed3e90610b2e9030908690600401611552565b60206040518083038186803b158015610b4657600080fd5b505afa158015610b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b7e91908101906111b7565b905083811015610ba457610ba46001600160a01b0384168360001963ffffffff610cb216565b50505050565b604051610c0390849063a9059cbb60e01b90610bcc908690869060240161156d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610d78565b505050565b600082610c1757506000610c45565b82820282848281610c2457fe5b0414610c425760405162461bcd60e51b81526004016101409061168f565b90505b92915050565b6000610c4283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250610e5d565b600082820183811015610c425760405162461bcd60e51b81526004016101409061165f565b801580610d3a5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90610ce89030908690600401611552565b60206040518083038186803b158015610d0057600080fd5b505afa158015610d14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d3891908101906111b7565b155b610d565760405162461bcd60e51b8152600401610140906116cf565b604051610c0390849063095ea7b360e01b90610bcc908690869060240161156d565b610d8a826001600160a01b0316610e94565b610da65760405162461bcd60e51b8152600401610140906116df565b60006060836001600160a01b031683604051610dc29190611538565b6000604051808303816000865af19150503d8060008114610dff576040519150601f19603f3d011682016040523d82523d6000602084013e610e04565b606091505b509150915081610e265760405162461bcd60e51b81526004016101409061166f565b805115610ba45780806020019051610e419190810190611146565b610ba45760405162461bcd60e51b8152600401610140906116bf565b60008183610e7e5760405162461bcd60e51b8152600401610140919061163e565b506000838581610e8a57fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610af5575050151592915050565b8035610c4581611807565b8051610c4581611807565b600082601f830112610ef457600080fd5b8151610f07610f0282611724565b6116fd565b91508181835260208401935060208101905083856020840282011115610f2c57600080fd5b60005b83811015610f585781610f428882610f6d565b8452506020928301929190910190600101610f2f565b5050505092915050565b8051610c458161181e565b8051610c4581611827565b600082601f830112610f8957600080fd5b8135610f97610f0282611745565b91508082526020830160208301858383011115610fb357600080fd5b610fbe8382846117c5565b50505092915050565b600060e08284031215610fd957600080fd5b610fe360e06116fd565b90506000610ff18484610ecd565b825250602061100284848301610ecd565b602083015250604061101684828501610ecd565b604083015250606061102a84828501610ecd565b606083015250608061103e84828501611072565b60808301525060a061105284828501611072565b60a08301525060c061106684828501611072565b60c08301525092915050565b8035610c4581611830565b8051610c4581611830565b60006020828403121561109a57600080fd5b6000610af58484610ecd565b6000602082840312156110b857600080fd5b6000610af58484610ed8565b6000806000606084860312156110d957600080fd5b60006110e58686610ecd565b93505060206110f686828701610ecd565b925050604061110786828701611072565b9150509250925092565b60006020828403121561112357600080fd5b815167ffffffffffffffff81111561113a57600080fd5b610af584828501610ee3565b60006020828403121561115857600080fd5b6000610af58484610f62565b60006020828403121561117657600080fd5b813567ffffffffffffffff81111561118d57600080fd5b610af584828501610f78565b600060e082840312156111ab57600080fd5b6000610af58484610fc7565b6000602082840312156111c957600080fd5b6000610af5848461107d565b60006111e18383611292565b505060200190565b6111f2816117af565b82525050565b6111f281611785565b600061120c82611773565b6112168185611777565b93506112218361176d565b8060005b8381101561124f57815161123988826111d5565b97506112448361176d565b925050600101611225565b509495945050505050565b6111f281611795565b600061126e82611773565b6112788185611780565b93506112888185602086016117d1565b9290920192915050565b6111f281611798565b6111f2816117ba565b60006112af82611773565b6112b98185611777565b93506112c98185602086016117d1565b6112d2816117fd565b9093019392505050565b60006112e9601483611777565b7363616e6e6f742073776170203020746f6b656e7360601b815260200192915050565b6000611319601b83611777565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000611352602083611777565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061138b600e83611777565b6d696e76616c696420746f6b656e7360901b815260200192915050565b60006113b5602183611777565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006113f8600e83611777565b6d1cdbdd5c98d9480f4f4819195cdd60921b815260200192915050565b6000611422602483611777565b7f696e73756666696369656e7420736f7572636520746f6b656e732070726f76698152633232b21760e11b602082015260400192915050565b6000611468602a83611777565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006114b4603683611777565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b602082015260400192915050565b600061150c601f83611777565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b60006106b68284611263565b60208101610c4582846111f8565b6040810161156082856111f8565b6106b660208301846111f8565b6040810161157b82856111f8565b6106b6602083018461125a565b604080825281016115998185611201565b90506106b6602083018461125a565b60c080825281016115b98189611201565b90506115c8602083018861125a565b6115d5604083018761125a565b6115e260608301866111f8565b6115ef60808301856111e9565b6115fc60a083018461129b565b979650505050505050565b60208101610c45828461125a565b604081016116238285611292565b6106b66020830184611292565b60208101610c458284611292565b60208082528101610c4281846112a4565b60208082528101610c45816112dc565b60208082528101610c458161130c565b60208082528101610c4581611345565b60208082528101610c458161137e565b60208082528101610c45816113a8565b60208082528101610c45816113eb565b60208082528101610c4581611415565b60208082528101610c458161145b565b60208082528101610c45816114a7565b60208082528101610c45816114ff565b6040810161157b828561125a565b60405181810167ffffffffffffffff8111828210171561171c57600080fd5b604052919050565b600067ffffffffffffffff82111561173b57600080fd5b5060209081020190565b600067ffffffffffffffff82111561175c57600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b919050565b6000610c45826117a3565b151590565b90565b6000610c4582611785565b6001600160a01b031690565b6000610c4582611798565b6000610c4582611795565b82818337506000910152565b60005b838110156117ec5781810151838201526020016117d4565b83811115610ba45750506000910152565b601f01601f191690565b61181081611785565b811461181b57600080fd5b50565b61181081611790565b61181081611798565b6118108161179556fea365627a7a72315820ebc5e468d7f9c6318e17879153dc3c0c04f9da7556939114f9f7ba14b6786def6c6578706572696d656e74616cf564736f6c63430005110040", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100615760003560e01c806335aaa79d146100665780636dcd64e51461009d578063809a9e55146100bd578063b1fb7f56146100d0578063ca83d575146100e3575b600080fd5b81801561007257600080fd5b50610086610081366004611199565b610103565b6040516100949291906116ef565b60405180910390f35b6100b06100ab3660046110c4565b6104dd565b6040516100949190611607565b6100b06100cb3660046110c4565b6105b6565b6100b06100de366004611164565b6106bd565b6100f66100f1366004611088565b6106c4565b6040516100949190611630565b60008082602001516001600160a01b031683600001516001600160a01b031614156101495760405162461bcd60e51b81526004016101409061169f565b60405180910390fd5b8251604051633462561360e11b8152309182916368c4ac269161016e91600401611544565b60206040518083038186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101be9190810190611146565b801561024557506020840151604051633462561360e11b81526001600160a01b038316916368c4ac26916101f59190600401611544565b60206040518083038186803b15801561020d57600080fd5b505afa158015610221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102459190810190611146565b6102615760405162461bcd60e51b81526004016101409061167f565b60006102d7826001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b505afa1580156102b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506100f191908101906110a6565b905060606102ee8660000151876020015184610777565b608087015160c0880151909550909150600190156103cc57610322876000015188602001518960c001518a60a00151610893565b94508660c00151836001600160a01b0316637f9c0ecd84886040518363ffffffff1660e01b8152600401610357929190611588565b60206040518083038186803b15801561036f57600080fd5b505afa158015610383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103a791908101906111b7565b10156103c55760405162461bcd60e51b8152600401610140906116af565b5060c08601515b600085116103ec5760405162461bcd60e51b81526004016101409061164f565b6103fb85886000015185610afd565b604080880151905163b77d239b60e01b81526001600160a01b0385169163b77d239b916104359186918a91879160009081906004016115a8565b602060405180830381600087803b15801561044f57600080fd5b505af1158015610463573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061048791908101906111b7565b60608801519096506001600160a01b031630146104d4578660a001518510156104d457606087015160a088015188516104d4926001600160a01b039091169188900363ffffffff610baa16565b50505050915091565b60008061051c306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b9050606061052b868684610777565b604051637f9c0ecd60e01b81529091506001600160a01b03831690637f9c0ecd9061055c9084908890600401611588565b60206040518083038186803b15801561057457600080fd5b505afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105ac91908101906111b7565b9695505050505050565b6000806105f5306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b90506060610604868684610777565b90506000826001600160a01b0316637f9c0ecd83876040518363ffffffff1660e01b8152600401610636929190611588565b60206040518083038186803b15801561064e57600080fd5b505afa158015610662573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061068691908101906111b7565b90506106b0856106a483670de0b6b3a764000063ffffffff610c0816565b9063ffffffff610c4b16565b93505050505b9392505050565b6020015190565b600080829050806001600160a01b031663bb34534c61070b60405180604001604052806011815260200170536f7672796e537761704e6574776f726b60781b8152506106bd565b6040518263ffffffff1660e01b81526004016107279190611607565b60206040518083038186803b15801561073f57600080fd5b505afa158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106b691908101906110a6565b604051638654042960e01b8152606090819030906386540429906107a19088908890600401611552565b60006040518083038186803b1580156107b957600080fd5b505afa1580156107cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107f59190810190611111565b90506003815110156108885760405163d734fa1960e01b81526001600160a01b0384169063d734fa199061082f9088908890600401611615565b60006040518083038186803b15801561084757600080fd5b505afa15801561085b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108839190810190611111565b61088a565b805b95945050505050565b6000803090506000816001600160a01b03166378d849ed6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108d457600080fd5b505afa1580156108e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061090c91908101906110a6565b6001600160a01b031663524efd4b88886040518363ffffffff1660e01b8152600401610939929190611552565b60206040518083038186803b15801561095157600080fd5b505afa158015610965573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098991908101906111b7565b90508061099a578392505050610af5565b60006109a78888876105b6565b90506109bd816106a4888563ffffffff610c0816565b935060006109d3856103e863ffffffff610c4b16565b9050836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0e57600080fd5b505afa158015610a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a4691908101906111b7565b811115610ac157836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8657600080fd5b505afa158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610abe91908101906111b7565b90505b610ad1858263ffffffff610c8d16565b9450841580610adf57508585115b15610af05785945050505050610af5565b505050505b949350505050565b604051636eb1769f60e11b81526000906001600160a01b0384169063dd62ed3e90610b2e9030908690600401611552565b60206040518083038186803b158015610b4657600080fd5b505afa158015610b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b7e91908101906111b7565b905083811015610ba457610ba46001600160a01b0384168360001963ffffffff610cb216565b50505050565b604051610c0390849063a9059cbb60e01b90610bcc908690869060240161156d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610d78565b505050565b600082610c1757506000610c45565b82820282848281610c2457fe5b0414610c425760405162461bcd60e51b81526004016101409061168f565b90505b92915050565b6000610c4283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250610e5d565b600082820183811015610c425760405162461bcd60e51b81526004016101409061165f565b801580610d3a5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90610ce89030908690600401611552565b60206040518083038186803b158015610d0057600080fd5b505afa158015610d14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d3891908101906111b7565b155b610d565760405162461bcd60e51b8152600401610140906116cf565b604051610c0390849063095ea7b360e01b90610bcc908690869060240161156d565b610d8a826001600160a01b0316610e94565b610da65760405162461bcd60e51b8152600401610140906116df565b60006060836001600160a01b031683604051610dc29190611538565b6000604051808303816000865af19150503d8060008114610dff576040519150601f19603f3d011682016040523d82523d6000602084013e610e04565b606091505b509150915081610e265760405162461bcd60e51b81526004016101409061166f565b805115610ba45780806020019051610e419190810190611146565b610ba45760405162461bcd60e51b8152600401610140906116bf565b60008183610e7e5760405162461bcd60e51b8152600401610140919061163e565b506000838581610e8a57fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610af5575050151592915050565b8035610c4581611807565b8051610c4581611807565b600082601f830112610ef457600080fd5b8151610f07610f0282611724565b6116fd565b91508181835260208401935060208101905083856020840282011115610f2c57600080fd5b60005b83811015610f585781610f428882610f6d565b8452506020928301929190910190600101610f2f565b5050505092915050565b8051610c458161181e565b8051610c4581611827565b600082601f830112610f8957600080fd5b8135610f97610f0282611745565b91508082526020830160208301858383011115610fb357600080fd5b610fbe8382846117c5565b50505092915050565b600060e08284031215610fd957600080fd5b610fe360e06116fd565b90506000610ff18484610ecd565b825250602061100284848301610ecd565b602083015250604061101684828501610ecd565b604083015250606061102a84828501610ecd565b606083015250608061103e84828501611072565b60808301525060a061105284828501611072565b60a08301525060c061106684828501611072565b60c08301525092915050565b8035610c4581611830565b8051610c4581611830565b60006020828403121561109a57600080fd5b6000610af58484610ecd565b6000602082840312156110b857600080fd5b6000610af58484610ed8565b6000806000606084860312156110d957600080fd5b60006110e58686610ecd565b93505060206110f686828701610ecd565b925050604061110786828701611072565b9150509250925092565b60006020828403121561112357600080fd5b815167ffffffffffffffff81111561113a57600080fd5b610af584828501610ee3565b60006020828403121561115857600080fd5b6000610af58484610f62565b60006020828403121561117657600080fd5b813567ffffffffffffffff81111561118d57600080fd5b610af584828501610f78565b600060e082840312156111ab57600080fd5b6000610af58484610fc7565b6000602082840312156111c957600080fd5b6000610af5848461107d565b60006111e18383611292565b505060200190565b6111f2816117af565b82525050565b6111f281611785565b600061120c82611773565b6112168185611777565b93506112218361176d565b8060005b8381101561124f57815161123988826111d5565b97506112448361176d565b925050600101611225565b509495945050505050565b6111f281611795565b600061126e82611773565b6112788185611780565b93506112888185602086016117d1565b9290920192915050565b6111f281611798565b6111f2816117ba565b60006112af82611773565b6112b98185611777565b93506112c98185602086016117d1565b6112d2816117fd565b9093019392505050565b60006112e9601483611777565b7363616e6e6f742073776170203020746f6b656e7360601b815260200192915050565b6000611319601b83611777565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000611352602083611777565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061138b600e83611777565b6d696e76616c696420746f6b656e7360901b815260200192915050565b60006113b5602183611777565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006113f8600e83611777565b6d1cdbdd5c98d9480f4f4819195cdd60921b815260200192915050565b6000611422602483611777565b7f696e73756666696369656e7420736f7572636520746f6b656e732070726f76698152633232b21760e11b602082015260400192915050565b6000611468602a83611777565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006114b4603683611777565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b602082015260400192915050565b600061150c601f83611777565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b60006106b68284611263565b60208101610c4582846111f8565b6040810161156082856111f8565b6106b660208301846111f8565b6040810161157b82856111f8565b6106b6602083018461125a565b604080825281016115998185611201565b90506106b6602083018461125a565b60c080825281016115b98189611201565b90506115c8602083018861125a565b6115d5604083018761125a565b6115e260608301866111f8565b6115ef60808301856111e9565b6115fc60a083018461129b565b979650505050505050565b60208101610c45828461125a565b604081016116238285611292565b6106b66020830184611292565b60208101610c458284611292565b60208082528101610c4281846112a4565b60208082528101610c45816112dc565b60208082528101610c458161130c565b60208082528101610c4581611345565b60208082528101610c458161137e565b60208082528101610c45816113a8565b60208082528101610c45816113eb565b60208082528101610c4581611415565b60208082528101610c458161145b565b60208082528101610c45816114a7565b60208082528101610c45816114ff565b6040810161157b828561125a565b60405181810167ffffffffffffffff8111828210171561171c57600080fd5b604052919050565b600067ffffffffffffffff82111561173b57600080fd5b5060209081020190565b600067ffffffffffffffff82111561175c57600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b919050565b6000610c45826117a3565b151590565b90565b6000610c4582611785565b6001600160a01b031690565b6000610c4582611798565b6000610c4582611795565b82818337506000910152565b60005b838110156117ec5781810151838201526020016117d4565b83811115610ba45750506000910152565b601f01601f191690565b61181081611785565b811461181b57600080fd5b50565b61181081611790565b61181081611798565b6118108161179556fea365627a7a72315820ebc5e468d7f9c6318e17879153dc3c0c04f9da7556939114f9f7ba14b6786def6c6578706572696d656e74616cf564736f6c63430005110040", "devdoc": { "methods": { "getContractHexName(string)": { diff --git a/deployment/deployments/rskSovrynMainnet/VestingFactory.json b/deployment/deployments/rskSovrynMainnet/VestingFactory.json new file mode 100644 index 000000000..d71c6d8d9 --- /dev/null +++ b/deployment/deployments/rskSovrynMainnet/VestingFactory.json @@ -0,0 +1,313 @@ +{ + "address": "0x4DfA9759E1Ff3B7F8055a84e3fd76dF6F57BaEf1", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_vestingLogic", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_SOV", + "type": "address" + }, + { + "internalType": "address", + "name": "_staking", + "type": "address" + }, + { + "internalType": "address", + "name": "_tokenOwner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_cliff", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_feeSharing", + "type": "address" + }, + { + "internalType": "address", + "name": "_vestingOwner", + "type": "address" + } + ], + "name": "deployTeamVesting", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_SOV", + "type": "address" + }, + { + "internalType": "address", + "name": "_staking", + "type": "address" + }, + { + "internalType": "address", + "name": "_tokenOwner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_cliff", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_feeSharing", + "type": "address" + }, + { + "internalType": "address", + "name": "_vestingOwner", + "type": "address" + } + ], + "name": "deployVesting", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isOwner", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "vestingLogic", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x4a88cf3a298734ebced882ca34a5495155ff7c785094a6cae152925e94a1fe7a", + "receipt": { + "to": null, + "from": "0xFEe171A152C02F336021fb9E79b4fAc2304a9E7E", + "contractAddress": "0x4DfA9759E1Ff3B7F8055a84e3fd76dF6F57BaEf1", + "transactionIndex": 1, + "gasUsed": "2593687", + "logsBloom": "0x00000000000000000000000000000000000000000000001000800000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000003000080000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020004000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x68a7468d7ddcf05dc40b5e3dc31ce927b7d720358ff5bf3633eca7ceeec1944b", + "transactionHash": "0x4a88cf3a298734ebced882ca34a5495155ff7c785094a6cae152925e94a1fe7a", + "logs": [ + { + "transactionIndex": 1, + "blockNumber": 6042167, + "transactionHash": "0x4a88cf3a298734ebced882ca34a5495155ff7c785094a6cae152925e94a1fe7a", + "address": "0x4DfA9759E1Ff3B7F8055a84e3fd76dF6F57BaEf1", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000fee171a152c02f336021fb9e79b4fac2304a9e7e" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x68a7468d7ddcf05dc40b5e3dc31ce927b7d720358ff5bf3633eca7ceeec1944b" + } + ], + "blockNumber": 6042167, + "cumulativeGasUsed": "2633493", + "status": 1, + "byzantium": true + }, + "args": [ + "0x8bFf9023495ed689f2362CCc45Bfe61ba299e90F" + ], + "numDeployments": 2, + "solcInputHash": "16608baccc4c89e15713f1946c71539a", + "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vestingLogic\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_SOV\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_staking\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_tokenOwner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_cliff\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_duration\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_feeSharing\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vestingOwner\",\"type\":\"address\"}],\"name\":\"deployTeamVesting\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_SOV\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_staking\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_tokenOwner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_cliff\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_duration\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_feeSharing\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vestingOwner\",\"type\":\"address\"}],\"name\":\"deployVesting\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"vestingLogic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{\"deployTeamVesting(address,address,address,uint256,uint256,address,address)\":{\"params\":{\"_SOV\":\"The address of SOV token.\",\"_cliff\":\"The time interval to the first withdraw in seconds.\",\"_duration\":\"The total duration in seconds.\",\"_feeSharing\":\"The address of fee sharing contract.\",\"_staking\":\"The address of staking contract.\",\"_tokenOwner\":\"The owner of the tokens.\",\"_vestingOwner\":\"The address of an owner of vesting contract.\"},\"return\":\"The vesting contract address.\"},\"deployVesting(address,address,address,uint256,uint256,address,address)\":{\"params\":{\"_SOV\":\"the address of SOV token.\",\"_cliff\":\"The time interval to the first withdraw in seconds.\",\"_duration\":\"The total duration in seconds.\",\"_feeSharing\":\"The address of fee sharing contract.\",\"_staking\":\"The address of staking contract.\",\"_tokenOwner\":\"The owner of the tokens.\",\"_vestingOwner\":\"The address of an owner of vesting contract.\"},\"return\":\"The vesting contract address.\"},\"isOwner()\":{\"details\":\"Returns true if the caller is the current owner.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"Vesting Factory: Contract to deploy vesting contracts of two types: vesting (TokenHolder) and team vesting (Multisig).\"},\"userdoc\":{\"methods\":{\"deployTeamVesting(address,address,address,uint256,uint256,address,address)\":{\"notice\":\"Deploys Team Vesting contract.\"},\"deployVesting(address,address,address,uint256,uint256,address,address)\":{\"notice\":\"Deploys Vesting contract.\"}},\"notice\":\"Factory pattern allows to create multiple instances of the same contract and keep track of them easier.\"}},\"settings\":{\"compilationTarget\":{\"contracts/governance/Vesting/VestingFactory.sol\":\"VestingFactory\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":ds-test/=foundry/lib/forge-std/lib/ds-test/src/\",\":forge-std/=foundry/lib/forge-std/src/\"]},\"sources\":{\"contracts/governance/ApprovalReceiver.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./ErrorDecoder.sol\\\";\\nimport \\\"../token/IApproveAndCall.sol\\\";\\n\\n/**\\n * @title Base contract for receiving approval from SOV token.\\n */\\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\\n modifier onlyThisContract() {\\n // Accepts calls only from receiveApproval function.\\n require(msg.sender == address(this), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _data The data will be used for low level call.\\n */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external {\\n // Accepts calls only from SOV token.\\n require(msg.sender == _getToken(), \\\"unauthorized\\\");\\n require(msg.sender == _token, \\\"unauthorized\\\");\\n\\n // Only allowed methods.\\n bool isAllowed = false;\\n bytes4[] memory selectors = _getSelectors();\\n bytes4 sig = _getSig(_data);\\n for (uint256 i = 0; i < selectors.length; i++) {\\n if (sig == selectors[i]) {\\n isAllowed = true;\\n break;\\n }\\n }\\n require(isAllowed, \\\"method is not allowed\\\");\\n\\n // Check sender and amount.\\n address sender;\\n uint256 amount;\\n (, sender, amount) = abi.decode(\\n abi.encodePacked(bytes28(0), _data),\\n (bytes32, address, uint256)\\n );\\n require(sender == _sender, \\\"sender mismatch\\\");\\n require(amount == _amount, \\\"amount mismatch\\\");\\n\\n _call(_data);\\n }\\n\\n /**\\n * @notice Returns token address, only this address can be a sender for receiveApproval.\\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\\n * @return By default, 0x. When overriden, the token address making the call.\\n */\\n function _getToken() internal view returns (address) {\\n return address(0);\\n }\\n\\n /**\\n * @notice Returns list of function selectors allowed to be invoked.\\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\\n * @return By default, empty array. When overriden, allowed selectors.\\n */\\n function _getSelectors() internal pure returns (bytes4[] memory) {\\n return new bytes4[](0);\\n }\\n\\n /**\\n * @notice Makes call and reverts w/ enhanced error message.\\n * @param _data Error message as bytes.\\n */\\n function _call(bytes memory _data) internal {\\n (bool success, bytes memory returnData) = address(this).call(_data);\\n if (!success) {\\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\\n revert(\\\"receiveApproval: Transaction execution reverted.\\\");\\n } else {\\n revert(_addErrorMessage(\\\"receiveApproval: \\\", string(returnData)));\\n }\\n }\\n }\\n\\n /**\\n * @notice Extracts the called function selector, a hash of the signature.\\n * @dev The first four bytes of the call data for a function call specifies\\n * the function to be called. It is the first (left, high-order in big-endian)\\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\\n * Example:\\n * msg.data:\\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\\n * 000450000000000000000000000000000000000000000000000000000000000000001\\n * selector (or method ID): 0xcdcd77c0\\n * signature: baz(uint32,bool)\\n * @param _data The msg.data from the low level call.\\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\\n */\\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\\n assembly {\\n sig := mload(add(_data, 32))\\n }\\n }\\n}\\n\",\"keccak256\":\"0xfec344456774fa83b0885dd71825ccb6780be8db63c394f3ca09107977c65429\"},\"contracts/governance/ErrorDecoder.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Base contract to properly handle returned data on failed calls\\n * @dev On EVM if the return data length of a call is less than 68,\\n * then the transaction fails silently without a revert message!\\n *\\n * As described in the Solidity documentation\\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\\n * the revert reason is an ABI-encoded string consisting of:\\n * 0x08c379a0 // Function selector (method id) for \\\"Error(string)\\\" signature\\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\\n *\\n * Another example, debug data from test:\\n * 0x08c379a0\\n * 0000000000000000000000000000000000000000000000000000000000000020\\n * 0000000000000000000000000000000000000000000000000000000000000034\\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\\n *\\n * Parsed into:\\n * Data offset: 20\\n * Length: 34\\n * Error message:\\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\\n */\\ncontract ErrorDecoder {\\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\\n\\n /**\\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\\n * @param str1 First string, usually a hardcoded context written by dev.\\n * @param str2 Second string, usually the error message from the reverted call.\\n * @return The concatenated error string\\n */\\n function _addErrorMessage(string memory str1, string memory str2)\\n internal\\n pure\\n returns (string memory)\\n {\\n bytes memory bytesStr1 = bytes(str1);\\n bytes memory bytesStr2 = bytes(str2);\\n string memory str12 =\\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\\n bytes memory bytesStr12 = bytes(str12);\\n uint256 j = 0;\\n for (uint256 i = 0; i < bytesStr1.length; i++) {\\n bytesStr12[j++] = bytesStr1[i];\\n }\\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\\n bytesStr12[j++] = bytesStr2[i];\\n }\\n return string(bytesStr12);\\n }\\n}\\n\",\"keccak256\":\"0xa0fa7986924aab574ca9e7c265f8c7bf00671ba1d86dbad143df7c14455f1c6a\"},\"contracts/governance/IFeeSharingCollector.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n * */\\ninterface IFeeSharingCollector {\\n function withdrawFees(address[] calldata _token) external;\\n\\n function transferTokens(address _token, uint96 _amount) external;\\n\\n function withdraw(\\n address _loanPoolToken,\\n uint32 _maxCheckpoints,\\n address _receiver\\n ) external;\\n}\\n\",\"keccak256\":\"0x7794cb434d9395ea983dcf8ded48db5b68897a338429320f60172c4caa47fb40\"},\"contracts/governance/Staking/interfaces/IStaking.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\npragma experimental ABIEncoderV2;\\n\\n/**\\n * @title Interface for Staking modules governance/Staking/modules\\n */\\n\\ninterface IStaking {\\n /*************************** StakingAdminModule ***************************/\\n\\n /**\\n * @notice Add account to Admins ACL.\\n * @param _admin The addresses of the account to grant permissions.\\n * */\\n function addAdmin(address _admin) external;\\n\\n /**\\n * @notice Remove account from Admins ACL.\\n * @param _admin The addresses of the account to revoke permissions.\\n * */\\n function removeAdmin(address _admin) external;\\n\\n /**\\n * @notice Add account to pausers ACL.\\n * @param _pauser The address to grant pauser permissions.\\n * */\\n function addPauser(address _pauser) external;\\n\\n /**\\n * @notice Remove account from pausers ACL.\\n * @param _pauser The address to grant pauser permissions.\\n * */\\n function removePauser(address _pauser) external;\\n\\n /**\\n * @notice Pause/unpause contract\\n * @param _pause true when pausing, false when unpausing\\n * */\\n function pauseUnpause(bool _pause) external;\\n\\n /**\\n * @notice Freeze contract - disable all functions\\n * @param _freeze true when freezing, false when unfreezing\\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\\n * */\\n function freezeUnfreeze(bool _freeze) external;\\n\\n /**\\n * @notice Allows the owner to set a fee sharing proxy contract.\\n * We need it for unstaking with slashing.\\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\\n * */\\n function setFeeSharing(address _feeSharing) external;\\n\\n /**\\n * @notice Allow the owner to set weight scaling.\\n * We need it for unstaking with slashing.\\n * @param _weightScaling The weight scaling.\\n * */\\n function setWeightScaling(uint96 _weightScaling) external;\\n\\n /**\\n * @notice Allow the owner to set a new staking contract.\\n * As a consequence it allows the stakers to migrate their positions\\n * to the new contract.\\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\\n * is not implemented.\\n * @param _newStakingContract The address of the new staking contract.\\n * */\\n function setNewStakingContract(address _newStakingContract) external;\\n\\n /**\\n * @notice Allow a staker to migrate his positions to the new staking contract.\\n * @dev Staking contract needs to be set before by the owner.\\n * Currently not implemented, just needed for the interface.\\n * In case it's needed at some point in the future,\\n * the implementation needs to be changed first.\\n * */\\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\\n\\n /*************************** StakingGovernanceModule ***************************/\\n\\n /**\\n * @notice Compute the total voting power at a given time.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @param time The timestamp for which to calculate the total voting power.\\n * @return The total voting power at the given time.\\n * */\\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Get the current votes balance for a user account.\\n * @param account The address to get votes balance.\\n * @dev This is a wrapper to simplify arguments. The actual computation is\\n * performed on WeightedStaking parent contract.\\n * @return The number of current votes for a user account.\\n * */\\n function getCurrentVotes(address account) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of votes for a delegatee as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will revert\\n * to prevent misinformation.\\n * Used for Voting, not for fee sharing.\\n * @param account The address of the account to check.\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The staking date to compute the power for.\\n * @return The number of votes the delegatee had as of the given block.\\n * */\\n function getPriorVotes(\\n address account,\\n uint256 blockNumber,\\n uint256 date\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of stake for an account as of a block number.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * @param account The address of the account to check.\\n * @param date The staking date to compute the power for.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorStakeByDateForDelegatee(\\n address account,\\n uint256 date,\\n uint256 blockNumber\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\\n * be internal instead of a public function.\\n * @param date The date to check the stakes for.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\\n * @param delegatee The address to delegate votes to.\\n * @param lockDate the date if the position to delegate.\\n * */\\n function delegate(address delegatee, uint256 lockDate) external;\\n\\n /*************************** StakingStakeModule ***************************/\\n\\n event TokensStaked(\\n address indexed staker,\\n uint256 amount,\\n uint256 lockedUntil,\\n uint256 totalStaked\\n );\\n\\n /**\\n * @notice Stake the given amount for the given duration of time.\\n * @param amount The number of tokens to stake.\\n * @param until Timestamp indicating the date until which to stake.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stake(\\n uint96 amount,\\n uint256 until,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Stake the given amount for the given duration of time.\\n * @dev This function will be invoked from receiveApproval\\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\\n * @param sender The sender of SOV.approveAndCall\\n * @param amount The number of tokens to stake.\\n * @param until Timestamp indicating the date until which to stake.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stakeWithApproval(\\n address sender,\\n uint96 amount,\\n uint256 until,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _data The data will be used for low level call.\\n */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @notice Extend the staking duration until the specified date.\\n * @param previousLock The old unlocking timestamp.\\n * @param until The new unlocking timestamp in seconds.\\n * */\\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\\n\\n /**\\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\\n * */\\n function stakesBySchedule(\\n uint256 amount,\\n uint256 cliff,\\n uint256 duration,\\n uint256 intervalLength,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Stake tokens according to the vesting schedule.\\n * @param amount The amount of tokens to stake.\\n * @param cliff The time interval to the first withdraw.\\n * @param duration The staking duration.\\n * @param intervalLength The length of each staking interval when cliff passed.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stakeBySchedule(\\n uint256 amount,\\n uint256 cliff,\\n uint256 duration,\\n uint256 intervalLength,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Get the number of staked tokens held by the user account.\\n * @dev Iterate checkpoints adding up stakes.\\n * @param account The address of the account to get the balance of.\\n * @return The number of tokens held.\\n * */\\n function balanceOf(address account) external view returns (uint96 balance);\\n\\n /**\\n * @notice Get the current number of tokens staked for a day.\\n * @param lockedTS The timestamp to get the staked tokens for.\\n * */\\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\\n\\n /**\\n * @notice Get list of stakes for a user account.\\n * @param account The address to get stakes.\\n * @return The arrays of dates and stakes.\\n * */\\n function getStakes(address account)\\n external\\n view\\n returns (uint256[] memory dates, uint96[] memory stakes);\\n\\n /**\\n * @notice Unstaking is possible every 2 weeks only. This means, to\\n * calculate the key value for the staking checkpoints, we need to\\n * map the intended timestamp to the closest available date.\\n * @param timestamp The unlocking timestamp.\\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\\n * */\\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\\n\\n /*************************** StakingStorageModule ***************************/\\n\\n /// @notice The maximum duration to stake tokens\\n /// @return MAX_DURATION to stake tokens\\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\\n\\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\\n /// @return uint256(MAX_VOTING_WEIGHT);\\n function getStorageMaxVotingWeight() external pure returns (uint256);\\n\\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\\n /// @return uint256(WEIGHT_FACTOR);\\n function getStorageWeightFactor() external pure returns (uint256);\\n\\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\\n function getStorageDefaultWeightScaling() external pure returns (uint256);\\n\\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\\n function getStorageRangeForWeightScaling()\\n external\\n pure\\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\\n\\n /// @notice The EIP-712 typehash for the contract's domain.\\n /// @return uint256(DOMAIN_TYPEHASH);\\n function getStorageDomainTypehash() external pure returns (uint256);\\n\\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\\n /// @return uint256(DELEGATION_TYPEHASH);\\n function getStorageDelegationTypehash() external pure returns (uint256);\\n\\n /// @return name;\\n function getStorageName() external view returns (string memory);\\n\\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\\n\\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\\n function kickoffTS() external view returns (uint256);\\n\\n /// @notice The token to be staked\\n function SOVToken() external view returns (address);\\n\\n /// @notice Stakers delegated voting power\\n /// @param staker - the delegating address\\n /// @param until - delegated voting\\n /// @return _delegate - voting power delegated to address\\n function delegates(address staker, uint256 until) external view returns (address _delegate);\\n\\n /// @notice If this flag is set to true, all tokens are unlocked immediately\\n /// see function unlockAllTokens() for details\\n function allUnlocked() external view returns (bool);\\n\\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\\n function newStakingContract() external view returns (address);\\n\\n /// CHECKPOINTS\\n struct Checkpoint {\\n uint32 fromBlock;\\n uint96 stake;\\n }\\n\\n /// @notice A record of tokens to be unstaked at a given time in total.\\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\\n function totalStakingCheckpoints(uint256 date, uint32 index)\\n external\\n view\\n returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date.\\n /// @dev numTotalStakingCheckpoints[date] is a number.\\n function numTotalStakingCheckpoints(uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\\n function delegateStakingCheckpoints(\\n address delagatee,\\n uint256 date,\\n uint32 index\\n ) external view returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date per delegate.\\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\\n function userStakingCheckpoints(\\n address user,\\n uint256 date,\\n uint32 index\\n ) external view returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date per user.\\n /// @dev numUserStakingCheckpoints[user][date] is a number\\n function numUserStakingCheckpoints(address user, uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of states for signing / validating signatures\\n /// @dev nonces[user] is a number.\\n function nonces(address user) external view returns (uint256 nonce);\\n\\n /// SLASHING ///\\n\\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\\n function feeSharing() external view returns (address);\\n\\n /// @notice used for weight scaling when unstaking with slashing.\\n /// @return uint96 DEFAULT_WEIGHT_SCALING\\n function weightScaling() external view returns (uint96);\\n\\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\\n /// @dev vestingWhitelist[contract] is true/false.\\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\\n\\n /// @dev user => flag whether user has admin role.\\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\\n /// \\tthis function works only with Team Vesting contracts\\n function admins(address isAdmin) external view returns (bool);\\n\\n /// @dev vesting contract code hash => flag whether it's registered code hash\\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\\n\\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\\n function vestingCheckpoints(uint256 date, uint32 index)\\n external\\n view\\n returns (Checkpoint memory);\\n\\n /// @notice The number of total vesting checkpoints for each date.\\n /// @dev numVestingCheckpoints[date] is a number.\\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\\n\\n ///@notice vesting registry contract PROXY address\\n function vestingRegistryLogic() external view returns (address);\\n\\n /// @dev user => flag whether user has pauser role.\\n function pausers(address isPauser) external view returns (bool);\\n\\n /// @dev Staking contract is paused\\n function paused() external view returns (bool);\\n\\n /// @dev Staking contract is frozen\\n function frozen() external view returns (bool);\\n\\n /*************************** StakingVestingModule ***************************/\\n\\n event VestingStakeSet(uint256 lockedTS, uint96 value);\\n\\n /**\\n * @notice Return flag whether the given address is a registered vesting contract.\\n * @param stakerAddress the address to check\\n */\\n function isVestingContract(address stakerAddress) external view returns (bool);\\n\\n /**\\n * @notice Remove vesting contract's code hash to a map of code hashes.\\n * @param vesting The address of Vesting contract.\\n * @dev We need it to use isVestingContract() function instead of isContract()\\n */\\n function removeContractCodeHash(address vesting) external;\\n\\n /**\\n * @notice Add vesting contract's code hash to a map of code hashes.\\n * @param vesting The address of Vesting contract.\\n * @dev We need it to use isVestingContract() function instead of isContract()\\n */\\n function addContractCodeHash(address vesting) external;\\n\\n /**\\n * @notice Determine the prior number of vested stake for an account until a\\n * certain lock date as of a block number.\\n * @dev Block number must be a finalized block or else this function\\n * will revert to prevent misinformation.\\n * @param date The lock date.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Compute the voting power for a specific date.\\n * Power = stake * weight\\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\\n * @param startDate The date for which we need to know the power of the stake.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @return The stacking power.\\n * */\\n function weightedVestingStakeByDate(\\n uint256 date,\\n uint256 startDate,\\n uint256 blockNumber\\n ) external view returns (uint96 power);\\n\\n /**\\n * @notice Determine the prior weighted vested amount for an account as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * Used for fee sharing, not voting.\\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \\\"votes\\\"\\n * to add up token stake, and that could be misleading.\\n *\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The staking date to compute the power for.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\\n external\\n view\\n returns (uint96 votes);\\n\\n /**\\n * @notice Determine the prior number of stake for an account until a\\n * certain lock date as of a block number.\\n * @dev Block number must be a finalized block or else this function\\n * will revert to prevent misinformation.\\n * @param account The address of the account to check.\\n * @param date The lock date.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorUserStakeByDate(\\n address account,\\n uint256 date,\\n uint256 blockNumber\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\\n * @param lockedDates The arrays of lock dates.\\n * @param values The array of values to add to the staked balance.\\n */\\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\\n\\n /**\\n * @notice sets vesting registry\\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\\n * various other functionalities without the necessity of linking it with Vesting Registry\\n */\\n function setVestingRegistry(address _vestingRegistryProxy) external;\\n\\n /*************************** StakingWithdrawModule ***************************/\\n\\n /**\\n * @notice Withdraw the given amount of tokens if they are unlocked.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * */\\n function withdraw(\\n uint96 amount,\\n uint256 until,\\n address receiver\\n ) external;\\n\\n /**\\n * @notice Withdraw the given amount of tokens.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\\n * */\\n function governanceWithdraw(\\n uint96 amount,\\n uint256 until,\\n address receiver\\n ) external;\\n\\n /**\\n * @notice Withdraw tokens for vesting contract.\\n * @param vesting The address of Vesting contract.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\\n * */\\n function governanceWithdrawVesting(address vesting, address receiver) external;\\n\\n /**\\n * @notice Get available and punished amount for withdrawing.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * */\\n function getWithdrawAmounts(uint96 amount, uint256 until)\\n external\\n view\\n returns (uint96, uint96);\\n\\n /**\\n * @notice Allow the owner to unlock all tokens in case the staking contract\\n * is going to be replaced\\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\\n * The owner should not be able to just quickly unlock to withdraw his own\\n * tokens and lock again.\\n * @dev Last resort.\\n * */\\n function unlockAllTokens() external;\\n\\n /*************************** WeightedStakingModule ***************************/\\n\\n /**\\n * @notice Determine the prior weighted stake for an account as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * Used for fee sharing, not voting.\\n *\\n * @param account The address of the account to check.\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The date/timestamp of the unstaking time.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function getPriorWeightedStake(\\n address account,\\n uint256 blockNumber,\\n uint256 date\\n ) external view returns (uint96 priorWeightedStake);\\n\\n /**\\n * @notice Compute the voting power for a specific date.\\n * Power = stake * weight\\n * TODO: WeightedStaking::weightedStakeByDate should probably better\\n * be internal instead of a public function.\\n * @param account The user address.\\n * @param date The staking date to compute the power for.\\n * @param startDate The date for which we need to know the power of the stake.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @return The stacking power.\\n * */\\n function weightedStakeByDate(\\n address account,\\n uint256 date,\\n uint256 startDate,\\n uint256 blockNumber\\n ) external view returns (uint96 power);\\n\\n /**\\n * @notice Compute the weight for a specific date.\\n * @param date The unlocking date.\\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function computeWeightByDate(uint256 date, uint256 startDate)\\n external\\n pure\\n returns (uint96 weight);\\n\\n /**\\n * @notice Returns public constant MAX_DURATION\\n * preserved for backwards compatibility\\n * Use getStorageMaxDurationToStakeTokens()\\n * @return uint96 MAX_DURATION for staking\\n **/\\n function MAX_DURATION() external view returns (uint256);\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() external view returns (address);\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() external view returns (bool);\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) external;\\n\\n /**\\n * @notice Governance withdraw vesting directly through staking contract.\\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\\n * This function only allows cancelling vesting contract of the TeamVesting type.\\n *\\n * @param vesting The vesting address.\\n * @param receiver The receiving address.\\n * @param startFrom The start value for the iterations.\\n */\\n function cancelTeamVesting(\\n address vesting,\\n address receiver,\\n uint256 startFrom\\n ) external;\\n\\n /**\\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\\n *\\n * @return max iteration value.\\n */\\n function getMaxVestingWithdrawIterations() external view returns (uint256);\\n\\n /**\\n * @dev set max withdraw iterations.\\n *\\n * @param maxIterations new max iterations value.\\n */\\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\\n}\\n\",\"keccak256\":\"0x720bd2cc1042cb4abc2bd3a6839131638eafd3d224571ad9ac21cae36625ec2e\"},\"contracts/governance/Vesting/IVesting.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for Vesting contract.\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n * This interface is used by VestingLogic contract to implement stakeTokens function\\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\\n * at a vesting instance.\\n */\\ninterface IVesting {\\n function duration() external returns (uint256);\\n\\n function endDate() external returns (uint256);\\n\\n function stakeTokens(uint256 amount) external;\\n\\n function tokenOwner() external view returns (address);\\n}\\n\",\"keccak256\":\"0x3482a1e27402655f85f5ff2cb06e0876e9bb94e1a63446a09e33babd60274b4b\"},\"contracts/governance/Vesting/IVestingFactory.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for Vesting Factory contract.\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n * This interface is used by VestingFactory contract to override empty\\n * implemention of deployVesting and deployTeamVesting functions\\n * and on VestingRegistry contract to use an instance of VestingFactory.\\n */\\ninterface IVestingFactory {\\n function deployVesting(\\n address _SOV,\\n address _staking,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharing,\\n address _owner\\n ) external returns (address);\\n\\n function deployTeamVesting(\\n address _SOV,\\n address _staking,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharing,\\n address _owner\\n ) external returns (address);\\n}\\n\",\"keccak256\":\"0xc77e276b71ec23ca6d4eead9a842bc01cc37bcfe55a88528190f1f6106773175\"},\"contracts/governance/Vesting/TeamVesting.sol\":{\"content\":\"pragma solidity ^0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../openzeppelin/Ownable.sol\\\";\\nimport \\\"../../interfaces/IERC20.sol\\\";\\n//import \\\"../Staking/interfaces/IStaking.sol\\\";\\nimport \\\"../IFeeSharingCollector.sol\\\";\\nimport \\\"./IVesting.sol\\\";\\nimport \\\"../ApprovalReceiver.sol\\\";\\nimport \\\"./VestingStorage.sol\\\";\\nimport \\\"../../proxy/Proxy.sol\\\";\\n\\n/**\\n * @title Team Vesting Contract.\\n *\\n * @notice A regular vesting contract, but the owner (governance) is able to\\n * withdraw earlier without a slashing.\\n *\\n * @dev Vesting contracts shouldn't be upgradable,\\n * use Proxy instead of UpgradableProxy.\\n * */\\ncontract TeamVesting is VestingStorage, Proxy {\\n /**\\n * @notice Setup the vesting schedule.\\n * @param _logic The address of logic contract.\\n * @param _SOV The SOV token address.\\n * @param _tokenOwner The owner of the tokens.\\n * @param _cliff The time interval to the first withdraw in seconds.\\n * @param _duration The total duration in seconds.\\n * */\\n constructor(\\n address _logic,\\n address _SOV,\\n address _stakingAddress,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharingCollector\\n ) public {\\n require(_SOV != address(0), \\\"SOV address invalid\\\");\\n require(_stakingAddress != address(0), \\\"staking address invalid\\\");\\n require(_tokenOwner != address(0), \\\"token owner address invalid\\\");\\n require(_duration >= _cliff, \\\"duration must be bigger than or equal to the cliff\\\");\\n require(_feeSharingCollector != address(0), \\\"feeSharingCollector address invalid\\\");\\n\\n _setImplementation(_logic);\\n SOV = IERC20(_SOV);\\n staking = IStaking(_stakingAddress);\\n require(_duration <= staking.MAX_DURATION(), \\\"duration may not exceed the max duration\\\");\\n tokenOwner = _tokenOwner;\\n cliff = _cliff;\\n duration = _duration;\\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\\n }\\n}\\n\",\"keccak256\":\"0xba6c95ae79e37dc20ba1c67a48ec227f7b3c210078763b5e8ad20c8b3db0b645\"},\"contracts/governance/Vesting/Vesting.sol\":{\"content\":\"pragma solidity ^0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./TeamVesting.sol\\\";\\n\\n/**\\n * @title Vesting Contract.\\n * @notice Team tokens and investor tokens are vested. Therefore, a smart\\n * contract needs to be developed to enforce the vesting schedule.\\n *\\n * */\\ncontract Vesting is TeamVesting {\\n /**\\n * @notice Setup the vesting schedule.\\n * @param _logic The address of logic contract.\\n * @param _SOV The SOV token address.\\n * @param _tokenOwner The owner of the tokens.\\n * @param _cliff The time interval to the first withdraw in seconds.\\n * @param _duration The total duration in seconds.\\n * */\\n constructor(\\n address _logic,\\n address _SOV,\\n address _stakingAddress,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharingCollectorProxy\\n )\\n public\\n TeamVesting(\\n _logic,\\n _SOV,\\n _stakingAddress,\\n _tokenOwner,\\n _cliff,\\n _duration,\\n _feeSharingCollectorProxy\\n )\\n {}\\n\\n /**\\n * @dev We need to add this implementation to prevent proxy call VestingLogic.governanceWithdrawTokens\\n * @param receiver The receiver of the token withdrawal.\\n * */\\n function governanceWithdrawTokens(address receiver) public {\\n revert(\\\"operation not supported\\\");\\n }\\n}\\n\",\"keccak256\":\"0xa042b910acc3bec9c75213160bc5257c3acade8ce56b4dd0777caab903d0ab23\"},\"contracts/governance/Vesting/VestingFactory.sol\":{\"content\":\"pragma solidity ^0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../openzeppelin/Ownable.sol\\\";\\nimport \\\"./Vesting.sol\\\";\\nimport \\\"./TeamVesting.sol\\\";\\nimport \\\"./IVestingFactory.sol\\\";\\n\\n/**\\n * @title Vesting Factory: Contract to deploy vesting contracts\\n * of two types: vesting (TokenHolder) and team vesting (Multisig).\\n * @notice Factory pattern allows to create multiple instances\\n * of the same contract and keep track of them easier.\\n * */\\ncontract VestingFactory is IVestingFactory, Ownable {\\n address public vestingLogic;\\n\\n constructor(address _vestingLogic) public {\\n require(_vestingLogic != address(0), \\\"invalid vesting logic address\\\");\\n vestingLogic = _vestingLogic;\\n }\\n\\n /**\\n * @notice Deploys Vesting contract.\\n * @param _SOV the address of SOV token.\\n * @param _staking The address of staking contract.\\n * @param _tokenOwner The owner of the tokens.\\n * @param _cliff The time interval to the first withdraw in seconds.\\n * @param _duration The total duration in seconds.\\n * @param _feeSharing The address of fee sharing contract.\\n * @param _vestingOwner The address of an owner of vesting contract.\\n * @return The vesting contract address.\\n * */\\n function deployVesting(\\n address _SOV,\\n address _staking,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharing,\\n address _vestingOwner\\n )\\n external\\n onlyOwner /// @dev owner - VestingRegistry\\n returns (address)\\n {\\n address vesting =\\n address(\\n new Vesting(\\n vestingLogic,\\n _SOV,\\n _staking,\\n _tokenOwner,\\n _cliff,\\n _duration,\\n _feeSharing\\n )\\n );\\n Ownable(vesting).transferOwnership(_vestingOwner);\\n return vesting;\\n }\\n\\n /**\\n * @notice Deploys Team Vesting contract.\\n * @param _SOV The address of SOV token.\\n * @param _staking The address of staking contract.\\n * @param _tokenOwner The owner of the tokens.\\n * @param _cliff The time interval to the first withdraw in seconds.\\n * @param _duration The total duration in seconds.\\n * @param _feeSharing The address of fee sharing contract.\\n * @param _vestingOwner The address of an owner of vesting contract.\\n * @return The vesting contract address.\\n * */\\n function deployTeamVesting(\\n address _SOV,\\n address _staking,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharing,\\n address _vestingOwner\\n )\\n external\\n onlyOwner //owner - VestingRegistry\\n returns (address)\\n {\\n address vesting =\\n address(\\n new TeamVesting(\\n vestingLogic,\\n _SOV,\\n _staking,\\n _tokenOwner,\\n _cliff,\\n _duration,\\n _feeSharing\\n )\\n );\\n Ownable(vesting).transferOwnership(_vestingOwner);\\n return vesting;\\n }\\n}\\n\",\"keccak256\":\"0x50ea6d6fc9ab0522c442bbf14be6a7fd0808fd96141d2d198c818b300e04298c\"},\"contracts/governance/Vesting/VestingStorage.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"../../openzeppelin/Ownable.sol\\\";\\nimport \\\"../../interfaces/IERC20.sol\\\";\\nimport \\\"../Staking/interfaces/IStaking.sol\\\";\\nimport \\\"../IFeeSharingCollector.sol\\\";\\n\\n/**\\n * @title Vesting Storage Contract.\\n *\\n * @notice This contract is just the storage required for vesting.\\n * It is parent of VestingLogic and TeamVesting.\\n *\\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\\n * */\\ncontract VestingStorage is Ownable {\\n /// @notice The SOV token contract.\\n IERC20 public SOV;\\n\\n /// @notice The staking contract address.\\n IStaking public staking;\\n\\n /// @notice The owner of the vested tokens.\\n address public tokenOwner;\\n\\n /// @notice Fee sharing Proxy.\\n IFeeSharingCollector public feeSharingCollector;\\n\\n /// @notice The cliff. After this time period the tokens begin to unlock.\\n uint256 public cliff;\\n\\n /// @notice The duration. After this period all tokens will have been unlocked.\\n uint256 public duration;\\n\\n /// @notice The start date of the vesting.\\n uint256 public startDate;\\n\\n /// @notice The end date of the vesting.\\n uint256 public endDate;\\n\\n /// @notice Constant used for computing the vesting dates.\\n uint256 constant FOUR_WEEKS = 4 weeks;\\n}\\n\",\"keccak256\":\"0xf70f579d357d8f0aa0839824c1a1d66713c3cd42a58118d2893a35b52baaa140\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/proxy/Proxy.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Base Proxy contract.\\n * @notice The proxy performs delegated calls to the contract implementation\\n * it is pointing to. This way upgradable contracts are possible on blockchain.\\n *\\n * Delegating proxy contracts are widely used for both upgradeability and gas\\n * savings. These proxies rely on a logic contract (also known as implementation\\n * contract or master copy) that is called using delegatecall. This allows\\n * proxies to keep a persistent state (storage and balance) while the code is\\n * delegated to the logic contract.\\n *\\n * Proxy contract is meant to be inherited and its internal functions\\n * _setImplementation and _setProxyOwner to be called when upgrades become\\n * neccessary.\\n *\\n * The loan token (iToken) contract as well as the protocol contract act as\\n * proxies, delegating all calls to underlying contracts. Therefore, if you\\n * want to interact with them using web3, you need to use the ABIs from the\\n * contracts containing the actual logic or the interface contract.\\n * ABI for LoanToken contracts: LoanTokenLogicStandard\\n * ABI for Protocol contract: ISovryn\\n *\\n * @dev UpgradableProxy is the contract that inherits Proxy and wraps these\\n * functions.\\n * */\\ncontract Proxy {\\n bytes32 private constant KEY_IMPLEMENTATION = keccak256(\\\"key.implementation\\\");\\n bytes32 private constant KEY_OWNER = keccak256(\\\"key.proxy.owner\\\");\\n\\n event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);\\n event ImplementationChanged(\\n address indexed _oldImplementation,\\n address indexed _newImplementation\\n );\\n\\n /**\\n * @notice Set sender as an owner.\\n * */\\n constructor() public {\\n _setProxyOwner(msg.sender);\\n }\\n\\n /**\\n * @notice Throw error if called not by an owner.\\n * */\\n modifier onlyProxyOwner() {\\n require(msg.sender == getProxyOwner(), \\\"Proxy:: access denied\\\");\\n _;\\n }\\n\\n /**\\n * @notice Set address of the implementation.\\n * @param _implementation Address of the implementation.\\n * */\\n function _setImplementation(address _implementation) internal {\\n require(_implementation != address(0), \\\"Proxy::setImplementation: invalid address\\\");\\n emit ImplementationChanged(getImplementation(), _implementation);\\n\\n bytes32 key = KEY_IMPLEMENTATION;\\n assembly {\\n sstore(key, _implementation)\\n }\\n }\\n\\n /**\\n * @notice Return address of the implementation.\\n * @return Address of the implementation.\\n * */\\n function getImplementation() public view returns (address _implementation) {\\n bytes32 key = KEY_IMPLEMENTATION;\\n assembly {\\n _implementation := sload(key)\\n }\\n }\\n\\n /**\\n * @notice Set address of the owner.\\n * @param _owner Address of the owner.\\n * */\\n function _setProxyOwner(address _owner) internal {\\n require(_owner != address(0), \\\"Proxy::setProxyOwner: invalid address\\\");\\n emit OwnershipTransferred(getProxyOwner(), _owner);\\n\\n bytes32 key = KEY_OWNER;\\n assembly {\\n sstore(key, _owner)\\n }\\n }\\n\\n /**\\n * @notice Return address of the owner.\\n * @return Address of the owner.\\n * */\\n function getProxyOwner() public view returns (address _owner) {\\n bytes32 key = KEY_OWNER;\\n assembly {\\n _owner := sload(key)\\n }\\n }\\n\\n /**\\n * @notice Fallback function performs a delegate call\\n * to the actual implementation address is pointing this proxy.\\n * Returns whatever the implementation call returns.\\n * */\\n function() external payable {\\n address implementation = getImplementation();\\n require(implementation != address(0), \\\"Proxy::(): implementation not found\\\");\\n\\n assembly {\\n let pointer := mload(0x40)\\n calldatacopy(pointer, 0, calldatasize)\\n let result := delegatecall(gas, implementation, pointer, calldatasize, 0, 0)\\n let size := returndatasize\\n returndatacopy(pointer, 0, size)\\n\\n switch result\\n case 0 {\\n revert(pointer, size)\\n }\\n default {\\n return(pointer, size)\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x8574814d1ea5b04efc8ef1e629e04e5783d4c106ff73a47c72e279c027a6a403\"},\"contracts/token/IApproveAndCall.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for contract governance/ApprovalReceiver.sol\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n */\\ninterface IApproveAndCall {\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _sender The sender of SOV.approveAndCall function.\\n * @param _amount The amount was approved.\\n * @param _token The address of token.\\n * @param _data The data will be used for low level call.\\n * */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x0ca93f8436a4d81d80de5ea9214139b490d96f708f09c975a0869ce9abc61635\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5060405161264338038061264383398101604081905261002f916100f5565b60006100426001600160e01b036100e016565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b0381166100bb5760405162461bcd60e51b81526004016100b290610154565b60405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055610195565b3390565b80516100ef8161017e565b92915050565b60006020828403121561010757600080fd5b600061011384846100e4565b949350505050565b6000610128601d83610164565b7f696e76616c69642076657374696e67206c6f6769632061646472657373000000815260200192915050565b602080825281016100ef8161011b565b90815260200190565b60006001600160a01b0382166100ef565b6101878161016d565b811461019257600080fd5b50565b61249f806101a46000396000f3fe60806040523480156200001157600080fd5b50600436106200006a5760003560e01c8063546344f0146200006f5780638da5cb5b146200009e5780638f32d59b14620000a8578063c0cad24e14620000c1578063f2fde38b14620000cb578063fa5f771e14620000e4575b600080fd5b6200008662000080366004620003bc565b620000fb565b60405162000095919062000502565b60405180910390f35b62000086620001fd565b620000b26200020c565b60405162000095919062000588565b6200008662000232565b620000e2620000dc36600462000393565b62000241565b005b62000086620000f5366004620003bc565b62000278565b6000620001076200020c565b6200012f5760405162461bcd60e51b81526004016200012690620005aa565b60405180910390fd5b6000600160009054906101000a90046001600160a01b03168989898989896040516200015b9062000357565b6200016d979695949392919062000512565b604051809103906000f0801580156200018a573d6000803e3d6000fd5b5060405163f2fde38b60e01b81529091506001600160a01b0382169063f2fde38b90620001bc90869060040162000502565b600060405180830381600087803b158015620001d757600080fd5b505af1158015620001ec573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6000546001600160a01b031690565b600080546001600160a01b031662000223620002cf565b6001600160a01b031614905090565b6001546001600160a01b031681565b6200024b6200020c565b6200026a5760405162461bcd60e51b81526004016200012690620005aa565b6200027581620002d3565b50565b6000620002846200020c565b620002a35760405162461bcd60e51b81526004016200012690620005aa565b6000600160009054906101000a90046001600160a01b03168989898989896040516200015b9062000365565b3390565b6001600160a01b038116620002fc5760405162461bcd60e51b8152600401620001269062000598565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b610ed5806200060983390190565b610f7f80620014de83390190565b80356200038081620005e6565b92915050565b80356200038081620005fd565b600060208284031215620003a657600080fd5b6000620003b4848462000373565b949350505050565b600080600080600080600060e0888a031215620003d857600080fd5b6000620003e68a8a62000373565b9750506020620003f98a828b0162000373565b96505060406200040c8a828b0162000373565b95505060606200041f8a828b0162000386565b9450506080620004328a828b0162000386565b93505060a0620004458a828b0162000373565b92505060c0620004588a828b0162000373565b91505092959891949750929550565b6200047281620005c5565b82525050565b6200047281620005d2565b600062000492602683620005bc565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000620004dc600c83620005bc565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6200047281620005e3565b6020810162000380828462000467565b60e0810162000522828a62000467565b62000531602083018962000467565b62000540604083018862000467565b6200054f606083018762000467565b6200055e6080830186620004f7565b6200056d60a0830185620004f7565b6200057c60c083018462000467565b98975050505050505050565b6020810162000380828462000478565b60208082528101620003808162000483565b602080825281016200038081620004cd565b90815260200190565b60006200038082620005d7565b151590565b6001600160a01b031690565b90565b620005f181620005c5565b81146200027557600080fd5b620005f181620005e356fe60806040523480156200001157600080fd5b5060405162000ed538038062000ed58339810160408190526200003491620003ef565b6000620000496001600160e01b036200028416565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062000eb5833981519152908290a35062000096336001600160e01b036200028816565b6001600160a01b038616620000c85760405162461bcd60e51b8152600401620000bf90620007e8565b60405180910390fd5b6001600160a01b038516620000f15760405162461bcd60e51b8152600401620000bf90620007d6565b6001600160a01b0384166200011a5760405162461bcd60e51b8152600401620000bf906200078e565b828210156200013d5760405162461bcd60e51b8152600401620000bf906200077c565b6001600160a01b038116620001665760405162461bcd60e51b8152600401620000bf90620007b2565b6200017a876001600160e01b036200031216565b600180546001600160a01b038089166001600160a01b0319928316179092556002805488841692169190911790819055604080516358b925a360e11b81529051919092169163b1724b46916004808301926020929190829003018186803b158015620001e557600080fd5b505afa158015620001fa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200022091908101906200049a565b821115620002425760405162461bcd60e51b8152600401620000bf906200076a565b600380546001600160a01b039586166001600160a01b031991821617909155600593909355600691909155600480549190931691161790555062000842915050565b3390565b6001600160a01b038116620002b15760405162461bcd60e51b8152600401620000bf90620007c4565b6001600160a01b038116620002ce6001600160e01b036200039d16565b6001600160a01b031660008051602062000eb583398151915260405160405180910390a3600060405162000302906200075d565b6040519081900390209190915550565b6001600160a01b0381166200033b5760405162461bcd60e51b8152600401620000bf90620007a0565b6001600160a01b038116620003586001600160e01b03620003be16565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a36000604051620003029062000750565b600080604051620003ae906200075d565b6040519081900390205492915050565b600080604051620003ae9062000750565b8051620003dc816200081d565b92915050565b8051620003dc8162000837565b600080600080600080600060e0888a0312156200040b57600080fd5b6000620004198a8a620003cf565b97505060206200042c8a828b01620003cf565b96505060406200043f8a828b01620003cf565b9550506060620004528a828b01620003cf565b9450506080620004658a828b01620003e2565b93505060a0620004788a828b01620003e2565b92505060c06200048b8a828b01620003cf565b91505092959891949750929550565b600060208284031215620004ad57600080fd5b6000620004bb8484620003e2565b949350505050565b6000620004d2602883620007fa565b7f6475726174696f6e206d6179206e6f742065786365656420746865206d617820815267323ab930ba34b7b760c11b602082015260400192915050565b60006200051e603283620007fa565b7f6475726174696f6e206d75737420626520626967676572207468616e206f722081527132b8bab0b6103a37903a34329031b634b33360711b602082015260400192915050565b600062000574601b83620007fa565b7f746f6b656e206f776e6572206164647265737320696e76616c69640000000000815260200192915050565b6000620005af602983620007fa565b7f50726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6981526864206164647265737360b81b602082015260400192915050565b6000620005fc60128362000803565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006200062c602383620007fa565b7f66656553686172696e67436f6c6c6563746f72206164647265737320696e76618152621b1a5960ea1b602082015260400192915050565b600062000673600f8362000803565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000620006a0602583620007fa565b7f50726f78793a3a73657450726f78794f776e65723a20696e76616c6964206164815264647265737360d81b602082015260400192915050565b6000620006e9601783620007fa565b7f7374616b696e67206164647265737320696e76616c6964000000000000000000815260200192915050565b600062000724601383620007fa565b7f534f56206164647265737320696e76616c696400000000000000000000000000815260200192915050565b6000620003dc82620005ed565b6000620003dc8262000664565b60208082528101620003dc81620004c3565b60208082528101620003dc816200050f565b60208082528101620003dc8162000565565b60208082528101620003dc81620005a0565b60208082528101620003dc816200061d565b60208082528101620003dc8162000691565b60208082528101620003dc81620006da565b60208082528101620003dc8162000715565b90815260200190565b919050565b60006001600160a01b038216620003dc565b90565b620008288162000808565b81146200083457600080fd5b50565b62000828816200081a565b61066380620008526000396000f3fe6080604052600436106100c25760003560e01c80636b7dbb2d1161007f578063a3e6761011610059578063a3e676101461021c578063aaf10f4214610231578063c24a0f8b14610246578063f2fde38b1461025b576100c2565b80636b7dbb2d146101d05780638da5cb5b146101e55780638f32d59b146101fa576100c2565b806308dcb360146101225780630b97bc861461014d5780630fb5a6b41461016f57806313d033c0146101845780631ab7710d146101995780634cf088d9146101bb575b60006100cc61027d565b90506001600160a01b0381166100fd5760405162461bcd60e51b81526004016100f4906105b6565b60405180910390fd5b60405136600082376000803683855af43d806000843e81801561011e578184f35b8184fd5b34801561012e57600080fd5b5061013761029c565b6040516101449190610588565b60405180910390f35b34801561015957600080fd5b506101626102ab565b60405161014491906105c6565b34801561017b57600080fd5b506101626102b1565b34801561019057600080fd5b506101626102b7565b3480156101a557600080fd5b506101ae6102bd565b604051610144919061056c565b3480156101c757600080fd5b506101376102cc565b3480156101dc57600080fd5b506101376102db565b3480156101f157600080fd5b506101ae6102ea565b34801561020657600080fd5b5061020f6102f9565b604051610144919061057a565b34801561022857600080fd5b506101ae61031d565b34801561023d57600080fd5b506101ae61027d565b34801561025257600080fd5b5061016261032c565b34801561026757600080fd5b5061027b6102763660046103f8565b610332565b005b60008060405161028c90610556565b6040519081900390205492915050565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b60008060405161028c90610561565b6002546001600160a01b031681565b6004546001600160a01b031681565b6000546001600160a01b031690565b600080546001600160a01b031661030e610362565b6001600160a01b031614905090565b6003546001600160a01b031681565b60085481565b61033a6102f9565b6103565760405162461bcd60e51b81526004016100f4906105a6565b61035f81610366565b50565b3390565b6001600160a01b03811661038c5760405162461bcd60e51b81526004016100f490610596565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b80356103f28161060c565b92915050565b60006020828403121561040a57600080fd5b600061041684846103e7565b949350505050565b610427816105e2565b82525050565b610427816105ed565b61042781610601565b600061044c6026836105d4565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000610494600c836105d4565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006104bc6012836105dd565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006104ea600f836105dd565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b60006105156023836105d4565b7f50726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f8152621d5b9960ea1b602082015260400192915050565b610427816105fe565b60006103f2826104af565b60006103f2826104dd565b602081016103f2828461041e565b602081016103f2828461042d565b602081016103f28284610436565b602080825281016103f28161043f565b602080825281016103f281610487565b602080825281016103f281610508565b602081016103f2828461054d565b90815260200190565b919050565b60006103f2826105f2565b151590565b6001600160a01b031690565b90565b60006103f2826105e2565b610615816105e2565b811461035f57600080fdfea365627a7a723158201d6e026074210469b30e9859d585cf2e6aac18794965c91da6b1abb8718c7ed16c6578706572696d656e74616cf564736f6c634300051100408be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060806040523480156200001157600080fd5b5060405162000f7f38038062000f7f8339810160408190526200003491620003fd565b868686868686866000620000506001600160e01b036200029216565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062000f5f833981519152908290a3506200009d336001600160e01b036200029616565b6001600160a01b038616620000cf5760405162461bcd60e51b8152600401620000c690620007f6565b60405180910390fd5b6001600160a01b038516620000f85760405162461bcd60e51b8152600401620000c690620007e4565b6001600160a01b038416620001215760405162461bcd60e51b8152600401620000c6906200079c565b82821015620001445760405162461bcd60e51b8152600401620000c6906200078a565b6001600160a01b0381166200016d5760405162461bcd60e51b8152600401620000c690620007c0565b62000181876001600160e01b036200032016565b600180546001600160a01b038089166001600160a01b0319928316179092556002805488841692169190911790819055604080516358b925a360e11b81529051919092169163b1724b46916004808301926020929190829003018186803b158015620001ec57600080fd5b505afa15801562000201573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002279190810190620004a8565b821115620002495760405162461bcd60e51b8152600401620000c69062000778565b600380546001600160a01b039586166001600160a01b03199182161790915560059390935560069190915560048054919093169116179055506200085098505050505050505050565b3390565b6001600160a01b038116620002bf5760405162461bcd60e51b8152600401620000c690620007d2565b6001600160a01b038116620002dc6001600160e01b03620003ab16565b6001600160a01b031660008051602062000f5f83398151915260405160405180910390a3600060405162000310906200076b565b6040519081900390209190915550565b6001600160a01b038116620003495760405162461bcd60e51b8152600401620000c690620007ae565b6001600160a01b038116620003666001600160e01b03620003cc16565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3600060405162000310906200075e565b600080604051620003bc906200076b565b6040519081900390205492915050565b600080604051620003bc906200075e565b8051620003ea816200082b565b92915050565b8051620003ea8162000845565b600080600080600080600060e0888a0312156200041957600080fd5b6000620004278a8a620003dd565b97505060206200043a8a828b01620003dd565b96505060406200044d8a828b01620003dd565b9550506060620004608a828b01620003dd565b9450506080620004738a828b01620003f0565b93505060a0620004868a828b01620003f0565b92505060c0620004998a828b01620003dd565b91505092959891949750929550565b600060208284031215620004bb57600080fd5b6000620004c98484620003f0565b949350505050565b6000620004e060288362000808565b7f6475726174696f6e206d6179206e6f742065786365656420746865206d617820815267323ab930ba34b7b760c11b602082015260400192915050565b60006200052c60328362000808565b7f6475726174696f6e206d75737420626520626967676572207468616e206f722081527132b8bab0b6103a37903a34329031b634b33360711b602082015260400192915050565b600062000582601b8362000808565b7f746f6b656e206f776e6572206164647265737320696e76616c69640000000000815260200192915050565b6000620005bd60298362000808565b7f50726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6981526864206164647265737360b81b602082015260400192915050565b60006200060a60128362000811565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006200063a60238362000808565b7f66656553686172696e67436f6c6c6563746f72206164647265737320696e76618152621b1a5960ea1b602082015260400192915050565b600062000681600f8362000811565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000620006ae60258362000808565b7f50726f78793a3a73657450726f78794f776e65723a20696e76616c6964206164815264647265737360d81b602082015260400192915050565b6000620006f760178362000808565b7f7374616b696e67206164647265737320696e76616c6964000000000000000000815260200192915050565b60006200073260138362000808565b7f534f56206164647265737320696e76616c696400000000000000000000000000815260200192915050565b6000620003ea82620005fb565b6000620003ea8262000672565b60208082528101620003ea81620004d1565b60208082528101620003ea816200051d565b60208082528101620003ea8162000573565b60208082528101620003ea81620005ae565b60208082528101620003ea816200062b565b60208082528101620003ea816200069f565b60208082528101620003ea81620006e8565b60208082528101620003ea8162000723565b90815260200190565b919050565b60006001600160a01b038216620003ea565b90565b620008368162000816565b81146200084257600080fd5b50565b620008368162000828565b6106ff80620008606000396000f3fe6080604052600436106100dd5760003560e01c806378f24bc61161007f578063a3e6761011610059578063a3e6761014610259578063aaf10f421461026e578063c24a0f8b14610283578063f2fde38b14610298576100dd565b806378f24bc6146102005780638da5cb5b146102225780638f32d59b14610237576100dd565b806313d033c0116100bb57806313d033c01461019f5780631ab7710d146101b45780634cf088d9146101d65780636b7dbb2d146101eb576100dd565b806308dcb3601461013d5780630b97bc86146101685780630fb5a6b41461018a575b60006100e76102b8565b90506001600160a01b0381166101185760405162461bcd60e51b815260040161010f90610652565b60405180910390fd5b60405136600082376000803683855af43d806000843e818015610139578184f35b8184fd5b34801561014957600080fd5b506101526102d7565b60405161015f9190610614565b60405180910390f35b34801561017457600080fd5b5061017d6102e6565b60405161015f9190610662565b34801561019657600080fd5b5061017d6102ec565b3480156101ab57600080fd5b5061017d6102f2565b3480156101c057600080fd5b506101c96102f8565b60405161015f91906105f8565b3480156101e257600080fd5b50610152610307565b3480156101f757600080fd5b50610152610316565b34801561020c57600080fd5b5061022061021b36600461044b565b610325565b005b34801561022e57600080fd5b506101c961033d565b34801561024357600080fd5b5061024c61034c565b60405161015f9190610606565b34801561026557600080fd5b506101c9610370565b34801561027a57600080fd5b506101c96102b8565b34801561028f57600080fd5b5061017d61037f565b3480156102a457600080fd5b506102206102b336600461044b565b610385565b6000806040516102c7906105e2565b6040519081900390205492915050565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b6000806040516102c7906105ed565b6002546001600160a01b031681565b6004546001600160a01b031681565b60405162461bcd60e51b815260040161010f90610642565b6000546001600160a01b031690565b600080546001600160a01b03166103616103b5565b6001600160a01b031614905090565b6003546001600160a01b031681565b60085481565b61038d61034c565b6103a95760405162461bcd60e51b815260040161010f90610632565b6103b2816103b9565b50565b3390565b6001600160a01b0381166103df5760405162461bcd60e51b815260040161010f90610622565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b8035610445816106a8565b92915050565b60006020828403121561045d57600080fd5b6000610469848461043a565b949350505050565b61047a8161067e565b82525050565b61047a81610689565b61047a8161069d565b600061049f602683610670565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b60006104e7600c83610670565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b600061050f601283610679565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b600061053d600f83610679565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000610568601783610670565b7f6f7065726174696f6e206e6f7420737570706f72746564000000000000000000815260200192915050565b60006105a1602383610670565b7f50726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f8152621d5b9960ea1b602082015260400192915050565b61047a8161069a565b600061044582610502565b600061044582610530565b602081016104458284610471565b602081016104458284610480565b602081016104458284610489565b6020808252810161044581610492565b60208082528101610445816104da565b602080825281016104458161055b565b6020808252810161044581610594565b6020810161044582846105d9565b90815260200190565b919050565b60006104458261068e565b151590565b6001600160a01b031690565b90565b60006104458261067e565b6106b18161067e565b81146103b257600080fdfea365627a7a723158209dea2ce74a9a4fb291e16464a9428aa1695111bdcdc3225dd7ee11b2e5b73e106c6578706572696d656e74616cf564736f6c634300051100408be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0a365627a7a7231582083a2f6860b79759e25565940e943e2b22a620d6c707c487b68e8c46a96e2ca826c6578706572696d656e74616cf564736f6c63430005110040", + "deployedBytecode": "0x60806040523480156200001157600080fd5b50600436106200006a5760003560e01c8063546344f0146200006f5780638da5cb5b146200009e5780638f32d59b14620000a8578063c0cad24e14620000c1578063f2fde38b14620000cb578063fa5f771e14620000e4575b600080fd5b6200008662000080366004620003bc565b620000fb565b60405162000095919062000502565b60405180910390f35b62000086620001fd565b620000b26200020c565b60405162000095919062000588565b6200008662000232565b620000e2620000dc36600462000393565b62000241565b005b62000086620000f5366004620003bc565b62000278565b6000620001076200020c565b6200012f5760405162461bcd60e51b81526004016200012690620005aa565b60405180910390fd5b6000600160009054906101000a90046001600160a01b03168989898989896040516200015b9062000357565b6200016d979695949392919062000512565b604051809103906000f0801580156200018a573d6000803e3d6000fd5b5060405163f2fde38b60e01b81529091506001600160a01b0382169063f2fde38b90620001bc90869060040162000502565b600060405180830381600087803b158015620001d757600080fd5b505af1158015620001ec573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6000546001600160a01b031690565b600080546001600160a01b031662000223620002cf565b6001600160a01b031614905090565b6001546001600160a01b031681565b6200024b6200020c565b6200026a5760405162461bcd60e51b81526004016200012690620005aa565b6200027581620002d3565b50565b6000620002846200020c565b620002a35760405162461bcd60e51b81526004016200012690620005aa565b6000600160009054906101000a90046001600160a01b03168989898989896040516200015b9062000365565b3390565b6001600160a01b038116620002fc5760405162461bcd60e51b8152600401620001269062000598565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b610ed5806200060983390190565b610f7f80620014de83390190565b80356200038081620005e6565b92915050565b80356200038081620005fd565b600060208284031215620003a657600080fd5b6000620003b4848462000373565b949350505050565b600080600080600080600060e0888a031215620003d857600080fd5b6000620003e68a8a62000373565b9750506020620003f98a828b0162000373565b96505060406200040c8a828b0162000373565b95505060606200041f8a828b0162000386565b9450506080620004328a828b0162000386565b93505060a0620004458a828b0162000373565b92505060c0620004588a828b0162000373565b91505092959891949750929550565b6200047281620005c5565b82525050565b6200047281620005d2565b600062000492602683620005bc565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000620004dc600c83620005bc565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6200047281620005e3565b6020810162000380828462000467565b60e0810162000522828a62000467565b62000531602083018962000467565b62000540604083018862000467565b6200054f606083018762000467565b6200055e6080830186620004f7565b6200056d60a0830185620004f7565b6200057c60c083018462000467565b98975050505050505050565b6020810162000380828462000478565b60208082528101620003808162000483565b602080825281016200038081620004cd565b90815260200190565b60006200038082620005d7565b151590565b6001600160a01b031690565b90565b620005f181620005c5565b81146200027557600080fd5b620005f181620005e356fe60806040523480156200001157600080fd5b5060405162000ed538038062000ed58339810160408190526200003491620003ef565b6000620000496001600160e01b036200028416565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062000eb5833981519152908290a35062000096336001600160e01b036200028816565b6001600160a01b038616620000c85760405162461bcd60e51b8152600401620000bf90620007e8565b60405180910390fd5b6001600160a01b038516620000f15760405162461bcd60e51b8152600401620000bf90620007d6565b6001600160a01b0384166200011a5760405162461bcd60e51b8152600401620000bf906200078e565b828210156200013d5760405162461bcd60e51b8152600401620000bf906200077c565b6001600160a01b038116620001665760405162461bcd60e51b8152600401620000bf90620007b2565b6200017a876001600160e01b036200031216565b600180546001600160a01b038089166001600160a01b0319928316179092556002805488841692169190911790819055604080516358b925a360e11b81529051919092169163b1724b46916004808301926020929190829003018186803b158015620001e557600080fd5b505afa158015620001fa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200022091908101906200049a565b821115620002425760405162461bcd60e51b8152600401620000bf906200076a565b600380546001600160a01b039586166001600160a01b031991821617909155600593909355600691909155600480549190931691161790555062000842915050565b3390565b6001600160a01b038116620002b15760405162461bcd60e51b8152600401620000bf90620007c4565b6001600160a01b038116620002ce6001600160e01b036200039d16565b6001600160a01b031660008051602062000eb583398151915260405160405180910390a3600060405162000302906200075d565b6040519081900390209190915550565b6001600160a01b0381166200033b5760405162461bcd60e51b8152600401620000bf90620007a0565b6001600160a01b038116620003586001600160e01b03620003be16565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a36000604051620003029062000750565b600080604051620003ae906200075d565b6040519081900390205492915050565b600080604051620003ae9062000750565b8051620003dc816200081d565b92915050565b8051620003dc8162000837565b600080600080600080600060e0888a0312156200040b57600080fd5b6000620004198a8a620003cf565b97505060206200042c8a828b01620003cf565b96505060406200043f8a828b01620003cf565b9550506060620004528a828b01620003cf565b9450506080620004658a828b01620003e2565b93505060a0620004788a828b01620003e2565b92505060c06200048b8a828b01620003cf565b91505092959891949750929550565b600060208284031215620004ad57600080fd5b6000620004bb8484620003e2565b949350505050565b6000620004d2602883620007fa565b7f6475726174696f6e206d6179206e6f742065786365656420746865206d617820815267323ab930ba34b7b760c11b602082015260400192915050565b60006200051e603283620007fa565b7f6475726174696f6e206d75737420626520626967676572207468616e206f722081527132b8bab0b6103a37903a34329031b634b33360711b602082015260400192915050565b600062000574601b83620007fa565b7f746f6b656e206f776e6572206164647265737320696e76616c69640000000000815260200192915050565b6000620005af602983620007fa565b7f50726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6981526864206164647265737360b81b602082015260400192915050565b6000620005fc60128362000803565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006200062c602383620007fa565b7f66656553686172696e67436f6c6c6563746f72206164647265737320696e76618152621b1a5960ea1b602082015260400192915050565b600062000673600f8362000803565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000620006a0602583620007fa565b7f50726f78793a3a73657450726f78794f776e65723a20696e76616c6964206164815264647265737360d81b602082015260400192915050565b6000620006e9601783620007fa565b7f7374616b696e67206164647265737320696e76616c6964000000000000000000815260200192915050565b600062000724601383620007fa565b7f534f56206164647265737320696e76616c696400000000000000000000000000815260200192915050565b6000620003dc82620005ed565b6000620003dc8262000664565b60208082528101620003dc81620004c3565b60208082528101620003dc816200050f565b60208082528101620003dc8162000565565b60208082528101620003dc81620005a0565b60208082528101620003dc816200061d565b60208082528101620003dc8162000691565b60208082528101620003dc81620006da565b60208082528101620003dc8162000715565b90815260200190565b919050565b60006001600160a01b038216620003dc565b90565b620008288162000808565b81146200083457600080fd5b50565b62000828816200081a565b61066380620008526000396000f3fe6080604052600436106100c25760003560e01c80636b7dbb2d1161007f578063a3e6761011610059578063a3e676101461021c578063aaf10f4214610231578063c24a0f8b14610246578063f2fde38b1461025b576100c2565b80636b7dbb2d146101d05780638da5cb5b146101e55780638f32d59b146101fa576100c2565b806308dcb360146101225780630b97bc861461014d5780630fb5a6b41461016f57806313d033c0146101845780631ab7710d146101995780634cf088d9146101bb575b60006100cc61027d565b90506001600160a01b0381166100fd5760405162461bcd60e51b81526004016100f4906105b6565b60405180910390fd5b60405136600082376000803683855af43d806000843e81801561011e578184f35b8184fd5b34801561012e57600080fd5b5061013761029c565b6040516101449190610588565b60405180910390f35b34801561015957600080fd5b506101626102ab565b60405161014491906105c6565b34801561017b57600080fd5b506101626102b1565b34801561019057600080fd5b506101626102b7565b3480156101a557600080fd5b506101ae6102bd565b604051610144919061056c565b3480156101c757600080fd5b506101376102cc565b3480156101dc57600080fd5b506101376102db565b3480156101f157600080fd5b506101ae6102ea565b34801561020657600080fd5b5061020f6102f9565b604051610144919061057a565b34801561022857600080fd5b506101ae61031d565b34801561023d57600080fd5b506101ae61027d565b34801561025257600080fd5b5061016261032c565b34801561026757600080fd5b5061027b6102763660046103f8565b610332565b005b60008060405161028c90610556565b6040519081900390205492915050565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b60008060405161028c90610561565b6002546001600160a01b031681565b6004546001600160a01b031681565b6000546001600160a01b031690565b600080546001600160a01b031661030e610362565b6001600160a01b031614905090565b6003546001600160a01b031681565b60085481565b61033a6102f9565b6103565760405162461bcd60e51b81526004016100f4906105a6565b61035f81610366565b50565b3390565b6001600160a01b03811661038c5760405162461bcd60e51b81526004016100f490610596565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b80356103f28161060c565b92915050565b60006020828403121561040a57600080fd5b600061041684846103e7565b949350505050565b610427816105e2565b82525050565b610427816105ed565b61042781610601565b600061044c6026836105d4565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000610494600c836105d4565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006104bc6012836105dd565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006104ea600f836105dd565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b60006105156023836105d4565b7f50726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f8152621d5b9960ea1b602082015260400192915050565b610427816105fe565b60006103f2826104af565b60006103f2826104dd565b602081016103f2828461041e565b602081016103f2828461042d565b602081016103f28284610436565b602080825281016103f28161043f565b602080825281016103f281610487565b602080825281016103f281610508565b602081016103f2828461054d565b90815260200190565b919050565b60006103f2826105f2565b151590565b6001600160a01b031690565b90565b60006103f2826105e2565b610615816105e2565b811461035f57600080fdfea365627a7a723158201d6e026074210469b30e9859d585cf2e6aac18794965c91da6b1abb8718c7ed16c6578706572696d656e74616cf564736f6c634300051100408be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060806040523480156200001157600080fd5b5060405162000f7f38038062000f7f8339810160408190526200003491620003fd565b868686868686866000620000506001600160e01b036200029216565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062000f5f833981519152908290a3506200009d336001600160e01b036200029616565b6001600160a01b038616620000cf5760405162461bcd60e51b8152600401620000c690620007f6565b60405180910390fd5b6001600160a01b038516620000f85760405162461bcd60e51b8152600401620000c690620007e4565b6001600160a01b038416620001215760405162461bcd60e51b8152600401620000c6906200079c565b82821015620001445760405162461bcd60e51b8152600401620000c6906200078a565b6001600160a01b0381166200016d5760405162461bcd60e51b8152600401620000c690620007c0565b62000181876001600160e01b036200032016565b600180546001600160a01b038089166001600160a01b0319928316179092556002805488841692169190911790819055604080516358b925a360e11b81529051919092169163b1724b46916004808301926020929190829003018186803b158015620001ec57600080fd5b505afa15801562000201573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002279190810190620004a8565b821115620002495760405162461bcd60e51b8152600401620000c69062000778565b600380546001600160a01b039586166001600160a01b03199182161790915560059390935560069190915560048054919093169116179055506200085098505050505050505050565b3390565b6001600160a01b038116620002bf5760405162461bcd60e51b8152600401620000c690620007d2565b6001600160a01b038116620002dc6001600160e01b03620003ab16565b6001600160a01b031660008051602062000f5f83398151915260405160405180910390a3600060405162000310906200076b565b6040519081900390209190915550565b6001600160a01b038116620003495760405162461bcd60e51b8152600401620000c690620007ae565b6001600160a01b038116620003666001600160e01b03620003cc16565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3600060405162000310906200075e565b600080604051620003bc906200076b565b6040519081900390205492915050565b600080604051620003bc906200075e565b8051620003ea816200082b565b92915050565b8051620003ea8162000845565b600080600080600080600060e0888a0312156200041957600080fd5b6000620004278a8a620003dd565b97505060206200043a8a828b01620003dd565b96505060406200044d8a828b01620003dd565b9550506060620004608a828b01620003dd565b9450506080620004738a828b01620003f0565b93505060a0620004868a828b01620003f0565b92505060c0620004998a828b01620003dd565b91505092959891949750929550565b600060208284031215620004bb57600080fd5b6000620004c98484620003f0565b949350505050565b6000620004e060288362000808565b7f6475726174696f6e206d6179206e6f742065786365656420746865206d617820815267323ab930ba34b7b760c11b602082015260400192915050565b60006200052c60328362000808565b7f6475726174696f6e206d75737420626520626967676572207468616e206f722081527132b8bab0b6103a37903a34329031b634b33360711b602082015260400192915050565b600062000582601b8362000808565b7f746f6b656e206f776e6572206164647265737320696e76616c69640000000000815260200192915050565b6000620005bd60298362000808565b7f50726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6981526864206164647265737360b81b602082015260400192915050565b60006200060a60128362000811565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006200063a60238362000808565b7f66656553686172696e67436f6c6c6563746f72206164647265737320696e76618152621b1a5960ea1b602082015260400192915050565b600062000681600f8362000811565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000620006ae60258362000808565b7f50726f78793a3a73657450726f78794f776e65723a20696e76616c6964206164815264647265737360d81b602082015260400192915050565b6000620006f760178362000808565b7f7374616b696e67206164647265737320696e76616c6964000000000000000000815260200192915050565b60006200073260138362000808565b7f534f56206164647265737320696e76616c696400000000000000000000000000815260200192915050565b6000620003ea82620005fb565b6000620003ea8262000672565b60208082528101620003ea81620004d1565b60208082528101620003ea816200051d565b60208082528101620003ea8162000573565b60208082528101620003ea81620005ae565b60208082528101620003ea816200062b565b60208082528101620003ea816200069f565b60208082528101620003ea81620006e8565b60208082528101620003ea8162000723565b90815260200190565b919050565b60006001600160a01b038216620003ea565b90565b620008368162000816565b81146200084257600080fd5b50565b620008368162000828565b6106ff80620008606000396000f3fe6080604052600436106100dd5760003560e01c806378f24bc61161007f578063a3e6761011610059578063a3e6761014610259578063aaf10f421461026e578063c24a0f8b14610283578063f2fde38b14610298576100dd565b806378f24bc6146102005780638da5cb5b146102225780638f32d59b14610237576100dd565b806313d033c0116100bb57806313d033c01461019f5780631ab7710d146101b45780634cf088d9146101d65780636b7dbb2d146101eb576100dd565b806308dcb3601461013d5780630b97bc86146101685780630fb5a6b41461018a575b60006100e76102b8565b90506001600160a01b0381166101185760405162461bcd60e51b815260040161010f90610652565b60405180910390fd5b60405136600082376000803683855af43d806000843e818015610139578184f35b8184fd5b34801561014957600080fd5b506101526102d7565b60405161015f9190610614565b60405180910390f35b34801561017457600080fd5b5061017d6102e6565b60405161015f9190610662565b34801561019657600080fd5b5061017d6102ec565b3480156101ab57600080fd5b5061017d6102f2565b3480156101c057600080fd5b506101c96102f8565b60405161015f91906105f8565b3480156101e257600080fd5b50610152610307565b3480156101f757600080fd5b50610152610316565b34801561020c57600080fd5b5061022061021b36600461044b565b610325565b005b34801561022e57600080fd5b506101c961033d565b34801561024357600080fd5b5061024c61034c565b60405161015f9190610606565b34801561026557600080fd5b506101c9610370565b34801561027a57600080fd5b506101c96102b8565b34801561028f57600080fd5b5061017d61037f565b3480156102a457600080fd5b506102206102b336600461044b565b610385565b6000806040516102c7906105e2565b6040519081900390205492915050565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b6000806040516102c7906105ed565b6002546001600160a01b031681565b6004546001600160a01b031681565b60405162461bcd60e51b815260040161010f90610642565b6000546001600160a01b031690565b600080546001600160a01b03166103616103b5565b6001600160a01b031614905090565b6003546001600160a01b031681565b60085481565b61038d61034c565b6103a95760405162461bcd60e51b815260040161010f90610632565b6103b2816103b9565b50565b3390565b6001600160a01b0381166103df5760405162461bcd60e51b815260040161010f90610622565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b8035610445816106a8565b92915050565b60006020828403121561045d57600080fd5b6000610469848461043a565b949350505050565b61047a8161067e565b82525050565b61047a81610689565b61047a8161069d565b600061049f602683610670565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b60006104e7600c83610670565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b600061050f601283610679565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b600061053d600f83610679565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000610568601783610670565b7f6f7065726174696f6e206e6f7420737570706f72746564000000000000000000815260200192915050565b60006105a1602383610670565b7f50726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f8152621d5b9960ea1b602082015260400192915050565b61047a8161069a565b600061044582610502565b600061044582610530565b602081016104458284610471565b602081016104458284610480565b602081016104458284610489565b6020808252810161044581610492565b60208082528101610445816104da565b602080825281016104458161055b565b6020808252810161044581610594565b6020810161044582846105d9565b90815260200190565b919050565b60006104458261068e565b151590565b6001600160a01b031690565b90565b60006104458261067e565b6106b18161067e565b81146103b257600080fdfea365627a7a723158209dea2ce74a9a4fb291e16464a9428aa1695111bdcdc3225dd7ee11b2e5b73e106c6578706572696d656e74616cf564736f6c634300051100408be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0a365627a7a7231582083a2f6860b79759e25565940e943e2b22a620d6c707c487b68e8c46a96e2ca826c6578706572696d656e74616cf564736f6c63430005110040", + "devdoc": { + "methods": { + "deployTeamVesting(address,address,address,uint256,uint256,address,address)": { + "params": { + "_SOV": "The address of SOV token.", + "_cliff": "The time interval to the first withdraw in seconds.", + "_duration": "The total duration in seconds.", + "_feeSharing": "The address of fee sharing contract.", + "_staking": "The address of staking contract.", + "_tokenOwner": "The owner of the tokens.", + "_vestingOwner": "The address of an owner of vesting contract." + }, + "return": "The vesting contract address." + }, + "deployVesting(address,address,address,uint256,uint256,address,address)": { + "params": { + "_SOV": "the address of SOV token.", + "_cliff": "The time interval to the first withdraw in seconds.", + "_duration": "The total duration in seconds.", + "_feeSharing": "The address of fee sharing contract.", + "_staking": "The address of staking contract.", + "_tokenOwner": "The owner of the tokens.", + "_vestingOwner": "The address of an owner of vesting contract." + }, + "return": "The vesting contract address." + }, + "isOwner()": { + "details": "Returns true if the caller is the current owner." + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "title": "Vesting Factory: Contract to deploy vesting contracts of two types: vesting (TokenHolder) and team vesting (Multisig)." + }, + "userdoc": { + "methods": { + "deployTeamVesting(address,address,address,uint256,uint256,address,address)": { + "notice": "Deploys Team Vesting contract." + }, + "deployVesting(address,address,address,uint256,uint256,address,address)": { + "notice": "Deploys Vesting contract." + } + }, + "notice": "Factory pattern allows to create multiple instances of the same contract and keep track of them easier." + }, + "storageLayout": { + "storage": [ + { + "astId": 54807, + "contract": "contracts/governance/Vesting/VestingFactory.sol:VestingFactory", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 27890, + "contract": "contracts/governance/Vesting/VestingFactory.sol:VestingFactory", + "label": "vestingLogic", + "offset": 0, + "slot": "1", + "type": "t_address" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + } + } + } +} \ No newline at end of file diff --git a/deployment/deployments/rskSovrynMainnet/VestingLogic.json b/deployment/deployments/rskSovrynMainnet/VestingLogic.json new file mode 100644 index 000000000..f0201676d --- /dev/null +++ b/deployment/deployments/rskSovrynMainnet/VestingLogic.json @@ -0,0 +1,687 @@ +{ + "address": "0x8bFf9023495ed689f2362CCc45Bfe61ba299e90F", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "loanPoolToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "maxCheckpoints", + "type": "uint32" + } + ], + "name": "DividendsCollected", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newStakingContract", + "type": "address" + } + ], + "name": "MigratedToNewStakingContract", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensStaked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "startFrom", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "end", + "type": "uint256" + } + ], + "name": "TokensWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "delegatee", + "type": "address" + } + ], + "name": "VotesDelegated", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "SOV", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "cliff", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_loanPoolToken", + "type": "address" + }, + { + "internalType": "uint32", + "name": "_maxCheckpoints", + "type": "uint32" + }, + { + "internalType": "address", + "name": "_receiver", + "type": "address" + } + ], + "name": "collectDividends", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_delegatee", + "type": "address" + } + ], + "name": "delegate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "duration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "endDate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "feeSharingCollector", + "outputs": [ + { + "internalType": "contract IFeeSharingCollector", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isOwner", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "migrateToNewStakingContract", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "receiveApproval", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "stakeTokens", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "stakeTokensWithApproval", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "staking", + "outputs": [ + { + "internalType": "contract IStaking", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "startDate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "tokenOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "withdrawTokens", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "startFrom", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxWithdrawIterations", + "type": "uint256" + } + ], + "name": "withdrawTokensStartingFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x8cef0f99e5a6f5cc4bfbc7fe2474d5d8bc682f76b783dbb1f19d1fb9211b8cb2", + "receipt": { + "to": null, + "from": "0xFEe171A152C02F336021fb9E79b4fAc2304a9E7E", + "contractAddress": "0x8bFf9023495ed689f2362CCc45Bfe61ba299e90F", + "transactionIndex": 0, + "gasUsed": "1958750", + "logsBloom": "0x00000000000000200000000000000000000000000000000000800000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000080000000000000000000000000000000020000000000000000000800000000000000000000000000100000400000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x962a46485bfd1ff601c25de2301085cb0f18c39469e3be07538d7730c455f4ec", + "transactionHash": "0x8cef0f99e5a6f5cc4bfbc7fe2474d5d8bc682f76b783dbb1f19d1fb9211b8cb2", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 6042166, + "transactionHash": "0x8cef0f99e5a6f5cc4bfbc7fe2474d5d8bc682f76b783dbb1f19d1fb9211b8cb2", + "address": "0x8bFf9023495ed689f2362CCc45Bfe61ba299e90F", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000fee171a152c02f336021fb9e79b4fac2304a9e7e" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x962a46485bfd1ff601c25de2301085cb0f18c39469e3be07538d7730c455f4ec" + } + ], + "blockNumber": 6042166, + "cumulativeGasUsed": "1958750", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 2, + "solcInputHash": "16608baccc4c89e15713f1946c71539a", + "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"loanPoolToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxCheckpoints\",\"type\":\"uint32\"}],\"name\":\"DividendsCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newStakingContract\",\"type\":\"address\"}],\"name\":\"MigratedToNewStakingContract\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TokensStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startFrom\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"TokensWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"delegatee\",\"type\":\"address\"}],\"name\":\"VotesDelegated\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[],\"name\":\"SOV\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"cliff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_loanPoolToken\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"_maxCheckpoints\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"_receiver\",\"type\":\"address\"}],\"name\":\"collectDividends\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_delegatee\",\"type\":\"address\"}],\"name\":\"delegate\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"duration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"endDate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feeSharingCollector\",\"outputs\":[{\"internalType\":\"contract IFeeSharingCollector\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"migrateToNewStakingContract\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"receiveApproval\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"stakeTokens\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"stakeTokensWithApproval\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"staking\",\"outputs\":[{\"internalType\":\"contract IStaking\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"startDate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"tokenOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"withdrawTokens\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"startFrom\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxWithdrawIterations\",\"type\":\"uint256\"}],\"name\":\"withdrawTokensStartingFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Deployed by a VestingFactory contract.\",\"methods\":{\"collectDividends(address,uint32,address)\":{\"params\":{\"_loanPoolToken\":\"The loan pool token address.\",\"_maxCheckpoints\":\"Maximum number of checkpoints to be processed.\",\"_receiver\":\"The receiver of tokens or msg.sender\"}},\"delegate(address)\":{\"params\":{\"_delegatee\":\"The address to delegate votes to.\"}},\"isOwner()\":{\"details\":\"Returns true if the caller is the current owner.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"receiveApproval(address,uint256,address,bytes)\":{\"params\":{\"_data\":\"The data will be used for low level call.\"}},\"stakeTokens(uint256)\":{\"params\":{\"_amount\":\"The amount of tokens to stake.\"}},\"stakeTokensWithApproval(address,uint256)\":{\"details\":\"This function will be invoked from receiveApproval.SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\",\"params\":{\"_amount\":\"The amount of tokens to stake.\",\"_sender\":\"The sender of SOV.approveAndCall\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"withdrawTokens(address)\":{\"params\":{\"receiver\":\"The receiving address.\"}},\"withdrawTokensStartingFrom(address,uint256,uint256)\":{\"params\":{\"maxWithdrawIterations\":\"max withdrawal iteration to work around block gas limit issue.\",\"receiver\":\"The receiving address.\",\"startFrom\":\"The start value for the iterations.\"}}},\"title\":\"Vesting Logic contract.\"},\"userdoc\":{\"methods\":{\"collectDividends(address,uint32,address)\":{\"notice\":\"Collect dividends from fee sharing proxy.\"},\"delegate(address)\":{\"notice\":\"Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\"},\"migrateToNewStakingContract()\":{\"notice\":\"Allows the owners to migrate the positions to a new staking contract.\"},\"receiveApproval(address,uint256,address,bytes)\":{\"notice\":\"Receives approval from SOV token.\"},\"stakeTokens(uint256)\":{\"notice\":\"Stakes tokens according to the vesting schedule.\"},\"stakeTokensWithApproval(address,uint256)\":{\"notice\":\"Stakes tokens according to the vesting schedule.\"},\"withdrawTokens(address)\":{\"notice\":\"Withdraws unlocked tokens from the staking contract and forwards them to an address specified by the token owner.\"},\"withdrawTokensStartingFrom(address,uint256,uint256)\":{\"notice\":\"Withdraws unlocked tokens partially (based on the max withdraw iteration that has been set) from the staking contract and forwards them to an address specified by the token owner.\"}},\"notice\":\"Staking, delegating and withdrawal functionality.\"}},\"settings\":{\"compilationTarget\":{\"contracts/governance/Vesting/VestingLogic.sol\":\"VestingLogic\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":ds-test/=foundry/lib/forge-std/lib/ds-test/src/\",\":forge-std/=foundry/lib/forge-std/src/\"]},\"sources\":{\"contracts/governance/ApprovalReceiver.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./ErrorDecoder.sol\\\";\\nimport \\\"../token/IApproveAndCall.sol\\\";\\n\\n/**\\n * @title Base contract for receiving approval from SOV token.\\n */\\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\\n modifier onlyThisContract() {\\n // Accepts calls only from receiveApproval function.\\n require(msg.sender == address(this), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _data The data will be used for low level call.\\n */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external {\\n // Accepts calls only from SOV token.\\n require(msg.sender == _getToken(), \\\"unauthorized\\\");\\n require(msg.sender == _token, \\\"unauthorized\\\");\\n\\n // Only allowed methods.\\n bool isAllowed = false;\\n bytes4[] memory selectors = _getSelectors();\\n bytes4 sig = _getSig(_data);\\n for (uint256 i = 0; i < selectors.length; i++) {\\n if (sig == selectors[i]) {\\n isAllowed = true;\\n break;\\n }\\n }\\n require(isAllowed, \\\"method is not allowed\\\");\\n\\n // Check sender and amount.\\n address sender;\\n uint256 amount;\\n (, sender, amount) = abi.decode(\\n abi.encodePacked(bytes28(0), _data),\\n (bytes32, address, uint256)\\n );\\n require(sender == _sender, \\\"sender mismatch\\\");\\n require(amount == _amount, \\\"amount mismatch\\\");\\n\\n _call(_data);\\n }\\n\\n /**\\n * @notice Returns token address, only this address can be a sender for receiveApproval.\\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\\n * @return By default, 0x. When overriden, the token address making the call.\\n */\\n function _getToken() internal view returns (address) {\\n return address(0);\\n }\\n\\n /**\\n * @notice Returns list of function selectors allowed to be invoked.\\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\\n * @return By default, empty array. When overriden, allowed selectors.\\n */\\n function _getSelectors() internal pure returns (bytes4[] memory) {\\n return new bytes4[](0);\\n }\\n\\n /**\\n * @notice Makes call and reverts w/ enhanced error message.\\n * @param _data Error message as bytes.\\n */\\n function _call(bytes memory _data) internal {\\n (bool success, bytes memory returnData) = address(this).call(_data);\\n if (!success) {\\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\\n revert(\\\"receiveApproval: Transaction execution reverted.\\\");\\n } else {\\n revert(_addErrorMessage(\\\"receiveApproval: \\\", string(returnData)));\\n }\\n }\\n }\\n\\n /**\\n * @notice Extracts the called function selector, a hash of the signature.\\n * @dev The first four bytes of the call data for a function call specifies\\n * the function to be called. It is the first (left, high-order in big-endian)\\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\\n * Example:\\n * msg.data:\\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\\n * 000450000000000000000000000000000000000000000000000000000000000000001\\n * selector (or method ID): 0xcdcd77c0\\n * signature: baz(uint32,bool)\\n * @param _data The msg.data from the low level call.\\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\\n */\\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\\n assembly {\\n sig := mload(add(_data, 32))\\n }\\n }\\n}\\n\",\"keccak256\":\"0xfec344456774fa83b0885dd71825ccb6780be8db63c394f3ca09107977c65429\"},\"contracts/governance/ErrorDecoder.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Base contract to properly handle returned data on failed calls\\n * @dev On EVM if the return data length of a call is less than 68,\\n * then the transaction fails silently without a revert message!\\n *\\n * As described in the Solidity documentation\\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\\n * the revert reason is an ABI-encoded string consisting of:\\n * 0x08c379a0 // Function selector (method id) for \\\"Error(string)\\\" signature\\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\\n *\\n * Another example, debug data from test:\\n * 0x08c379a0\\n * 0000000000000000000000000000000000000000000000000000000000000020\\n * 0000000000000000000000000000000000000000000000000000000000000034\\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\\n *\\n * Parsed into:\\n * Data offset: 20\\n * Length: 34\\n * Error message:\\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\\n */\\ncontract ErrorDecoder {\\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\\n\\n /**\\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\\n * @param str1 First string, usually a hardcoded context written by dev.\\n * @param str2 Second string, usually the error message from the reverted call.\\n * @return The concatenated error string\\n */\\n function _addErrorMessage(string memory str1, string memory str2)\\n internal\\n pure\\n returns (string memory)\\n {\\n bytes memory bytesStr1 = bytes(str1);\\n bytes memory bytesStr2 = bytes(str2);\\n string memory str12 =\\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\\n bytes memory bytesStr12 = bytes(str12);\\n uint256 j = 0;\\n for (uint256 i = 0; i < bytesStr1.length; i++) {\\n bytesStr12[j++] = bytesStr1[i];\\n }\\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\\n bytesStr12[j++] = bytesStr2[i];\\n }\\n return string(bytesStr12);\\n }\\n}\\n\",\"keccak256\":\"0xa0fa7986924aab574ca9e7c265f8c7bf00671ba1d86dbad143df7c14455f1c6a\"},\"contracts/governance/IFeeSharingCollector.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n * */\\ninterface IFeeSharingCollector {\\n function withdrawFees(address[] calldata _token) external;\\n\\n function transferTokens(address _token, uint96 _amount) external;\\n\\n function withdraw(\\n address _loanPoolToken,\\n uint32 _maxCheckpoints,\\n address _receiver\\n ) external;\\n}\\n\",\"keccak256\":\"0x7794cb434d9395ea983dcf8ded48db5b68897a338429320f60172c4caa47fb40\"},\"contracts/governance/Staking/interfaces/IStaking.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\npragma experimental ABIEncoderV2;\\n\\n/**\\n * @title Interface for Staking modules governance/Staking/modules\\n */\\n\\ninterface IStaking {\\n /*************************** StakingAdminModule ***************************/\\n\\n /**\\n * @notice Add account to Admins ACL.\\n * @param _admin The addresses of the account to grant permissions.\\n * */\\n function addAdmin(address _admin) external;\\n\\n /**\\n * @notice Remove account from Admins ACL.\\n * @param _admin The addresses of the account to revoke permissions.\\n * */\\n function removeAdmin(address _admin) external;\\n\\n /**\\n * @notice Add account to pausers ACL.\\n * @param _pauser The address to grant pauser permissions.\\n * */\\n function addPauser(address _pauser) external;\\n\\n /**\\n * @notice Remove account from pausers ACL.\\n * @param _pauser The address to grant pauser permissions.\\n * */\\n function removePauser(address _pauser) external;\\n\\n /**\\n * @notice Pause/unpause contract\\n * @param _pause true when pausing, false when unpausing\\n * */\\n function pauseUnpause(bool _pause) external;\\n\\n /**\\n * @notice Freeze contract - disable all functions\\n * @param _freeze true when freezing, false when unfreezing\\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\\n * */\\n function freezeUnfreeze(bool _freeze) external;\\n\\n /**\\n * @notice Allows the owner to set a fee sharing proxy contract.\\n * We need it for unstaking with slashing.\\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\\n * */\\n function setFeeSharing(address _feeSharing) external;\\n\\n /**\\n * @notice Allow the owner to set weight scaling.\\n * We need it for unstaking with slashing.\\n * @param _weightScaling The weight scaling.\\n * */\\n function setWeightScaling(uint96 _weightScaling) external;\\n\\n /**\\n * @notice Allow the owner to set a new staking contract.\\n * As a consequence it allows the stakers to migrate their positions\\n * to the new contract.\\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\\n * is not implemented.\\n * @param _newStakingContract The address of the new staking contract.\\n * */\\n function setNewStakingContract(address _newStakingContract) external;\\n\\n /**\\n * @notice Allow a staker to migrate his positions to the new staking contract.\\n * @dev Staking contract needs to be set before by the owner.\\n * Currently not implemented, just needed for the interface.\\n * In case it's needed at some point in the future,\\n * the implementation needs to be changed first.\\n * */\\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\\n\\n /*************************** StakingGovernanceModule ***************************/\\n\\n /**\\n * @notice Compute the total voting power at a given time.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @param time The timestamp for which to calculate the total voting power.\\n * @return The total voting power at the given time.\\n * */\\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Get the current votes balance for a user account.\\n * @param account The address to get votes balance.\\n * @dev This is a wrapper to simplify arguments. The actual computation is\\n * performed on WeightedStaking parent contract.\\n * @return The number of current votes for a user account.\\n * */\\n function getCurrentVotes(address account) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of votes for a delegatee as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will revert\\n * to prevent misinformation.\\n * Used for Voting, not for fee sharing.\\n * @param account The address of the account to check.\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The staking date to compute the power for.\\n * @return The number of votes the delegatee had as of the given block.\\n * */\\n function getPriorVotes(\\n address account,\\n uint256 blockNumber,\\n uint256 date\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of stake for an account as of a block number.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * @param account The address of the account to check.\\n * @param date The staking date to compute the power for.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorStakeByDateForDelegatee(\\n address account,\\n uint256 date,\\n uint256 blockNumber\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\\n * be internal instead of a public function.\\n * @param date The date to check the stakes for.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\\n * @param delegatee The address to delegate votes to.\\n * @param lockDate the date if the position to delegate.\\n * */\\n function delegate(address delegatee, uint256 lockDate) external;\\n\\n /*************************** StakingStakeModule ***************************/\\n\\n event TokensStaked(\\n address indexed staker,\\n uint256 amount,\\n uint256 lockedUntil,\\n uint256 totalStaked\\n );\\n\\n /**\\n * @notice Stake the given amount for the given duration of time.\\n * @param amount The number of tokens to stake.\\n * @param until Timestamp indicating the date until which to stake.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stake(\\n uint96 amount,\\n uint256 until,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Stake the given amount for the given duration of time.\\n * @dev This function will be invoked from receiveApproval\\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\\n * @param sender The sender of SOV.approveAndCall\\n * @param amount The number of tokens to stake.\\n * @param until Timestamp indicating the date until which to stake.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stakeWithApproval(\\n address sender,\\n uint96 amount,\\n uint256 until,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _data The data will be used for low level call.\\n */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @notice Extend the staking duration until the specified date.\\n * @param previousLock The old unlocking timestamp.\\n * @param until The new unlocking timestamp in seconds.\\n * */\\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\\n\\n /**\\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\\n * */\\n function stakesBySchedule(\\n uint256 amount,\\n uint256 cliff,\\n uint256 duration,\\n uint256 intervalLength,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Stake tokens according to the vesting schedule.\\n * @param amount The amount of tokens to stake.\\n * @param cliff The time interval to the first withdraw.\\n * @param duration The staking duration.\\n * @param intervalLength The length of each staking interval when cliff passed.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stakeBySchedule(\\n uint256 amount,\\n uint256 cliff,\\n uint256 duration,\\n uint256 intervalLength,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Get the number of staked tokens held by the user account.\\n * @dev Iterate checkpoints adding up stakes.\\n * @param account The address of the account to get the balance of.\\n * @return The number of tokens held.\\n * */\\n function balanceOf(address account) external view returns (uint96 balance);\\n\\n /**\\n * @notice Get the current number of tokens staked for a day.\\n * @param lockedTS The timestamp to get the staked tokens for.\\n * */\\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\\n\\n /**\\n * @notice Get list of stakes for a user account.\\n * @param account The address to get stakes.\\n * @return The arrays of dates and stakes.\\n * */\\n function getStakes(address account)\\n external\\n view\\n returns (uint256[] memory dates, uint96[] memory stakes);\\n\\n /**\\n * @notice Unstaking is possible every 2 weeks only. This means, to\\n * calculate the key value for the staking checkpoints, we need to\\n * map the intended timestamp to the closest available date.\\n * @param timestamp The unlocking timestamp.\\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\\n * */\\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\\n\\n /*************************** StakingStorageModule ***************************/\\n\\n /// @notice The maximum duration to stake tokens\\n /// @return MAX_DURATION to stake tokens\\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\\n\\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\\n /// @return uint256(MAX_VOTING_WEIGHT);\\n function getStorageMaxVotingWeight() external pure returns (uint256);\\n\\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\\n /// @return uint256(WEIGHT_FACTOR);\\n function getStorageWeightFactor() external pure returns (uint256);\\n\\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\\n function getStorageDefaultWeightScaling() external pure returns (uint256);\\n\\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\\n function getStorageRangeForWeightScaling()\\n external\\n pure\\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\\n\\n /// @notice The EIP-712 typehash for the contract's domain.\\n /// @return uint256(DOMAIN_TYPEHASH);\\n function getStorageDomainTypehash() external pure returns (uint256);\\n\\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\\n /// @return uint256(DELEGATION_TYPEHASH);\\n function getStorageDelegationTypehash() external pure returns (uint256);\\n\\n /// @return name;\\n function getStorageName() external view returns (string memory);\\n\\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\\n\\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\\n function kickoffTS() external view returns (uint256);\\n\\n /// @notice The token to be staked\\n function SOVToken() external view returns (address);\\n\\n /// @notice Stakers delegated voting power\\n /// @param staker - the delegating address\\n /// @param until - delegated voting\\n /// @return _delegate - voting power delegated to address\\n function delegates(address staker, uint256 until) external view returns (address _delegate);\\n\\n /// @notice If this flag is set to true, all tokens are unlocked immediately\\n /// see function unlockAllTokens() for details\\n function allUnlocked() external view returns (bool);\\n\\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\\n function newStakingContract() external view returns (address);\\n\\n /// CHECKPOINTS\\n struct Checkpoint {\\n uint32 fromBlock;\\n uint96 stake;\\n }\\n\\n /// @notice A record of tokens to be unstaked at a given time in total.\\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\\n function totalStakingCheckpoints(uint256 date, uint32 index)\\n external\\n view\\n returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date.\\n /// @dev numTotalStakingCheckpoints[date] is a number.\\n function numTotalStakingCheckpoints(uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\\n function delegateStakingCheckpoints(\\n address delagatee,\\n uint256 date,\\n uint32 index\\n ) external view returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date per delegate.\\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\\n function userStakingCheckpoints(\\n address user,\\n uint256 date,\\n uint32 index\\n ) external view returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date per user.\\n /// @dev numUserStakingCheckpoints[user][date] is a number\\n function numUserStakingCheckpoints(address user, uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of states for signing / validating signatures\\n /// @dev nonces[user] is a number.\\n function nonces(address user) external view returns (uint256 nonce);\\n\\n /// SLASHING ///\\n\\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\\n function feeSharing() external view returns (address);\\n\\n /// @notice used for weight scaling when unstaking with slashing.\\n /// @return uint96 DEFAULT_WEIGHT_SCALING\\n function weightScaling() external view returns (uint96);\\n\\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\\n /// @dev vestingWhitelist[contract] is true/false.\\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\\n\\n /// @dev user => flag whether user has admin role.\\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\\n /// \\tthis function works only with Team Vesting contracts\\n function admins(address isAdmin) external view returns (bool);\\n\\n /// @dev vesting contract code hash => flag whether it's registered code hash\\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\\n\\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\\n function vestingCheckpoints(uint256 date, uint32 index)\\n external\\n view\\n returns (Checkpoint memory);\\n\\n /// @notice The number of total vesting checkpoints for each date.\\n /// @dev numVestingCheckpoints[date] is a number.\\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\\n\\n ///@notice vesting registry contract PROXY address\\n function vestingRegistryLogic() external view returns (address);\\n\\n /// @dev user => flag whether user has pauser role.\\n function pausers(address isPauser) external view returns (bool);\\n\\n /// @dev Staking contract is paused\\n function paused() external view returns (bool);\\n\\n /// @dev Staking contract is frozen\\n function frozen() external view returns (bool);\\n\\n /*************************** StakingVestingModule ***************************/\\n\\n event VestingStakeSet(uint256 lockedTS, uint96 value);\\n\\n /**\\n * @notice Return flag whether the given address is a registered vesting contract.\\n * @param stakerAddress the address to check\\n */\\n function isVestingContract(address stakerAddress) external view returns (bool);\\n\\n /**\\n * @notice Remove vesting contract's code hash to a map of code hashes.\\n * @param vesting The address of Vesting contract.\\n * @dev We need it to use isVestingContract() function instead of isContract()\\n */\\n function removeContractCodeHash(address vesting) external;\\n\\n /**\\n * @notice Add vesting contract's code hash to a map of code hashes.\\n * @param vesting The address of Vesting contract.\\n * @dev We need it to use isVestingContract() function instead of isContract()\\n */\\n function addContractCodeHash(address vesting) external;\\n\\n /**\\n * @notice Determine the prior number of vested stake for an account until a\\n * certain lock date as of a block number.\\n * @dev Block number must be a finalized block or else this function\\n * will revert to prevent misinformation.\\n * @param date The lock date.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Compute the voting power for a specific date.\\n * Power = stake * weight\\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\\n * @param startDate The date for which we need to know the power of the stake.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @return The stacking power.\\n * */\\n function weightedVestingStakeByDate(\\n uint256 date,\\n uint256 startDate,\\n uint256 blockNumber\\n ) external view returns (uint96 power);\\n\\n /**\\n * @notice Determine the prior weighted vested amount for an account as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * Used for fee sharing, not voting.\\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \\\"votes\\\"\\n * to add up token stake, and that could be misleading.\\n *\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The staking date to compute the power for.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\\n external\\n view\\n returns (uint96 votes);\\n\\n /**\\n * @notice Determine the prior number of stake for an account until a\\n * certain lock date as of a block number.\\n * @dev Block number must be a finalized block or else this function\\n * will revert to prevent misinformation.\\n * @param account The address of the account to check.\\n * @param date The lock date.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorUserStakeByDate(\\n address account,\\n uint256 date,\\n uint256 blockNumber\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\\n * @param lockedDates The arrays of lock dates.\\n * @param values The array of values to add to the staked balance.\\n */\\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\\n\\n /**\\n * @notice sets vesting registry\\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\\n * various other functionalities without the necessity of linking it with Vesting Registry\\n */\\n function setVestingRegistry(address _vestingRegistryProxy) external;\\n\\n /*************************** StakingWithdrawModule ***************************/\\n\\n /**\\n * @notice Withdraw the given amount of tokens if they are unlocked.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * */\\n function withdraw(\\n uint96 amount,\\n uint256 until,\\n address receiver\\n ) external;\\n\\n /**\\n * @notice Withdraw the given amount of tokens.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\\n * */\\n function governanceWithdraw(\\n uint96 amount,\\n uint256 until,\\n address receiver\\n ) external;\\n\\n /**\\n * @notice Withdraw tokens for vesting contract.\\n * @param vesting The address of Vesting contract.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\\n * */\\n function governanceWithdrawVesting(address vesting, address receiver) external;\\n\\n /**\\n * @notice Get available and punished amount for withdrawing.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * */\\n function getWithdrawAmounts(uint96 amount, uint256 until)\\n external\\n view\\n returns (uint96, uint96);\\n\\n /**\\n * @notice Allow the owner to unlock all tokens in case the staking contract\\n * is going to be replaced\\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\\n * The owner should not be able to just quickly unlock to withdraw his own\\n * tokens and lock again.\\n * @dev Last resort.\\n * */\\n function unlockAllTokens() external;\\n\\n /*************************** WeightedStakingModule ***************************/\\n\\n /**\\n * @notice Determine the prior weighted stake for an account as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * Used for fee sharing, not voting.\\n *\\n * @param account The address of the account to check.\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The date/timestamp of the unstaking time.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function getPriorWeightedStake(\\n address account,\\n uint256 blockNumber,\\n uint256 date\\n ) external view returns (uint96 priorWeightedStake);\\n\\n /**\\n * @notice Compute the voting power for a specific date.\\n * Power = stake * weight\\n * TODO: WeightedStaking::weightedStakeByDate should probably better\\n * be internal instead of a public function.\\n * @param account The user address.\\n * @param date The staking date to compute the power for.\\n * @param startDate The date for which we need to know the power of the stake.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @return The stacking power.\\n * */\\n function weightedStakeByDate(\\n address account,\\n uint256 date,\\n uint256 startDate,\\n uint256 blockNumber\\n ) external view returns (uint96 power);\\n\\n /**\\n * @notice Compute the weight for a specific date.\\n * @param date The unlocking date.\\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function computeWeightByDate(uint256 date, uint256 startDate)\\n external\\n pure\\n returns (uint96 weight);\\n\\n /**\\n * @notice Returns public constant MAX_DURATION\\n * preserved for backwards compatibility\\n * Use getStorageMaxDurationToStakeTokens()\\n * @return uint96 MAX_DURATION for staking\\n **/\\n function MAX_DURATION() external view returns (uint256);\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() external view returns (address);\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() external view returns (bool);\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) external;\\n\\n /**\\n * @notice Governance withdraw vesting directly through staking contract.\\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\\n * This function only allows cancelling vesting contract of the TeamVesting type.\\n *\\n * @param vesting The vesting address.\\n * @param receiver The receiving address.\\n * @param startFrom The start value for the iterations.\\n */\\n function cancelTeamVesting(\\n address vesting,\\n address receiver,\\n uint256 startFrom\\n ) external;\\n\\n /**\\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\\n *\\n * @return max iteration value.\\n */\\n function getMaxVestingWithdrawIterations() external view returns (uint256);\\n\\n /**\\n * @dev set max withdraw iterations.\\n *\\n * @param maxIterations new max iterations value.\\n */\\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\\n}\\n\",\"keccak256\":\"0x720bd2cc1042cb4abc2bd3a6839131638eafd3d224571ad9ac21cae36625ec2e\"},\"contracts/governance/Vesting/IVesting.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for Vesting contract.\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n * This interface is used by VestingLogic contract to implement stakeTokens function\\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\\n * at a vesting instance.\\n */\\ninterface IVesting {\\n function duration() external returns (uint256);\\n\\n function endDate() external returns (uint256);\\n\\n function stakeTokens(uint256 amount) external;\\n\\n function tokenOwner() external view returns (address);\\n}\\n\",\"keccak256\":\"0x3482a1e27402655f85f5ff2cb06e0876e9bb94e1a63446a09e33babd60274b4b\"},\"contracts/governance/Vesting/VestingLogic.sol\":{\"content\":\"pragma solidity ^0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../openzeppelin/Ownable.sol\\\";\\nimport \\\"../../interfaces/IERC20.sol\\\";\\nimport \\\"../Staking/interfaces/IStaking.sol\\\";\\nimport \\\"../IFeeSharingCollector.sol\\\";\\nimport \\\"./IVesting.sol\\\";\\nimport \\\"../ApprovalReceiver.sol\\\";\\nimport \\\"./VestingStorage.sol\\\";\\nimport \\\"../../openzeppelin/SafeMath.sol\\\";\\n\\n/**\\n * @title Vesting Logic contract.\\n * @notice Staking, delegating and withdrawal functionality.\\n * @dev Deployed by a VestingFactory contract.\\n * */\\ncontract VestingLogic is IVesting, VestingStorage, ApprovalReceiver {\\n using SafeMath for uint256;\\n /* Events */\\n\\n event TokensStaked(address indexed caller, uint256 amount);\\n event VotesDelegated(address indexed caller, address delegatee);\\n event TokensWithdrawn(\\n address indexed caller,\\n address receiver,\\n uint256 startFrom,\\n uint256 end\\n );\\n event DividendsCollected(\\n address indexed caller,\\n address loanPoolToken,\\n address receiver,\\n uint32 maxCheckpoints\\n );\\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\\n\\n /* Modifiers */\\n\\n /**\\n * @dev Throws if called by any account other than the token owner or the contract owner.\\n */\\n modifier onlyOwners() {\\n require(msg.sender == tokenOwner || isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the token owner.\\n */\\n modifier onlyTokenOwner() {\\n require(msg.sender == tokenOwner, \\\"unauthorized\\\");\\n _;\\n }\\n\\n /* Functions */\\n\\n /**\\n * @notice Stakes tokens according to the vesting schedule.\\n * @param _amount The amount of tokens to stake.\\n * */\\n function stakeTokens(uint256 _amount) public {\\n _stakeTokens(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Stakes tokens according to the vesting schedule.\\n * @dev This function will be invoked from receiveApproval.\\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\\n * @param _sender The sender of SOV.approveAndCall\\n * @param _amount The amount of tokens to stake.\\n * */\\n function stakeTokensWithApproval(address _sender, uint256 _amount) public onlyThisContract {\\n _stakeTokens(_sender, _amount);\\n }\\n\\n /**\\n * @notice Stakes tokens according to the vesting schedule. Low level function.\\n * @dev Once here the allowance of tokens is taken for granted.\\n * @param _sender The sender of tokens to stake.\\n * @param _amount The amount of tokens to stake.\\n * */\\n function _stakeTokens(address _sender, uint256 _amount) internal {\\n /// @dev Maybe better to allow staking unil the cliff was reached.\\n if (startDate == 0) {\\n startDate = staking.timestampToLockDate(block.timestamp);\\n }\\n endDate = staking.timestampToLockDate(block.timestamp + duration);\\n\\n /// @dev Transfer the tokens to this contract.\\n bool success = SOV.transferFrom(_sender, address(this), _amount);\\n require(success);\\n\\n /// @dev Allow the staking contract to access them.\\n SOV.approve(address(staking), _amount);\\n\\n staking.stakeBySchedule(_amount, cliff, duration, FOUR_WEEKS, address(this), tokenOwner);\\n\\n emit TokensStaked(_sender, _amount);\\n }\\n\\n /**\\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\\n * to `delegatee`.\\n * @param _delegatee The address to delegate votes to.\\n * */\\n function delegate(address _delegatee) public onlyTokenOwner {\\n require(_delegatee != address(0), \\\"delegatee address invalid\\\");\\n\\n /// @dev Withdraw for each unlocked position.\\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\\n ///\\t\\tworkaround found, but it doesn't work with TWO_WEEKS\\n for (uint256 i = startDate + cliff; i <= endDate; i += FOUR_WEEKS) {\\n staking.delegate(_delegatee, i);\\n }\\n emit VotesDelegated(msg.sender, _delegatee);\\n }\\n\\n /**\\n * @notice Withdraws unlocked tokens from the staking contract and\\n * forwards them to an address specified by the token owner.\\n * @param receiver The receiving address.\\n * */\\n function withdrawTokens(address receiver) public onlyOwners {\\n uint256 startFrom = startDate + cliff;\\n _withdrawTokens(receiver, startFrom, block.timestamp);\\n }\\n\\n /**\\n * @notice Withdraws unlocked tokens partially (based on the max withdraw iteration that has been set) from the staking contract and\\n * forwards them to an address specified by the token owner.\\n * @param receiver The receiving address.\\n * @param startFrom The start value for the iterations.\\n * @param maxWithdrawIterations max withdrawal iteration to work around block gas limit issue.\\n * */\\n function withdrawTokensStartingFrom(\\n address receiver,\\n uint256 startFrom,\\n uint256 maxWithdrawIterations\\n ) public onlyOwners {\\n uint256 defaultStartFrom = startDate + cliff;\\n\\n startFrom = _timestampToLockDate(startFrom);\\n startFrom = startFrom < defaultStartFrom ? defaultStartFrom : startFrom;\\n\\n // @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\\n uint256 maxWithdrawDate = (startFrom + (FOUR_WEEKS * (maxWithdrawIterations.sub(1))));\\n uint256 endAt = endDate < maxWithdrawDate ? endDate : maxWithdrawDate;\\n _withdrawTokens(receiver, startFrom, endAt);\\n }\\n\\n /**\\n * @notice Withdraws tokens from the staking contract and forwards them\\n * to an address specified by the token owner. Low level function.\\n * @dev Once here the caller permission is taken for granted.\\n * @param receiver The receiving address.\\n * @param startFrom start withdrawal from date.\\n * @param endAt end time for regular withdrawal\\n * or just unlocked tokens (false).\\n * */\\n function _withdrawTokens(\\n address receiver,\\n uint256 startFrom,\\n uint256 endAt\\n ) internal {\\n require(receiver != address(0), \\\"receiver address invalid\\\");\\n\\n uint96 stake;\\n\\n /// @dev Usually we just need to iterate over the possible dates until now.\\n uint256 end;\\n\\n if (staking.allUnlocked()) {\\n end = endAt < endDate ? endAt : endDate;\\n } else {\\n end = endAt < block.timestamp ? endAt : block.timestamp;\\n if (end > endDate) end = endDate;\\n }\\n\\n /// @dev Withdraw for each unlocked position.\\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\\n ///\\t\\tworkaround found, but it doesn't work with TWO_WEEKS\\n for (uint256 i = startFrom; i <= end; i += FOUR_WEEKS) {\\n /// @dev Read amount to withdraw.\\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number - 1);\\n\\n /// @dev Withdraw if > 0\\n if (stake > 0) {\\n staking.withdraw(stake, i, receiver);\\n }\\n }\\n\\n emit TokensWithdrawn(msg.sender, receiver, startFrom, end);\\n }\\n\\n /**\\n * @notice Collect dividends from fee sharing proxy.\\n * @param _loanPoolToken The loan pool token address.\\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\\n * @param _receiver The receiver of tokens or msg.sender\\n * */\\n function collectDividends(\\n address _loanPoolToken,\\n uint32 _maxCheckpoints,\\n address _receiver\\n ) public onlyOwners {\\n require(_receiver != address(0), \\\"receiver address invalid\\\");\\n\\n /// @dev Invokes the fee sharing proxy.\\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\\n\\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\\n }\\n\\n /**\\n * @notice Allows the owners to migrate the positions\\n * to a new staking contract.\\n * */\\n function migrateToNewStakingContract() public onlyOwners {\\n staking.migrateToNewStakingContract();\\n staking = IStaking(staking.newStakingContract());\\n emit MigratedToNewStakingContract(msg.sender, address(staking));\\n }\\n\\n /**\\n * @notice Overrides default ApprovalReceiver._getToken function to\\n * register SOV token on this contract.\\n * @return The address of SOV token.\\n * */\\n function _getToken() internal view returns (address) {\\n return address(SOV);\\n }\\n\\n /**\\n * @notice Overrides default ApprovalReceiver._getSelectors function to\\n * register stakeTokensWithApproval selector on this contract.\\n * @return The array of registered selectors on this contract.\\n * */\\n function _getSelectors() internal pure returns (bytes4[] memory) {\\n bytes4[] memory selectors = new bytes4[](1);\\n selectors[0] = this.stakeTokensWithApproval.selector;\\n return selectors;\\n }\\n\\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\\n // Optimize gas costs by reading kickoffTS from storage only once.\\n uint256 start = startDate + cliff;\\n require(timestamp >= start, \\\"timestamp < contract creation\\\"); // WS23\\n /**\\n * @dev If staking timestamp does not match any of the unstaking dates\\n * , set the lockDate to the closest one before the timestamp.\\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\\n * */\\n uint256 periodFromKickoff = (timestamp - start) / FOUR_WEEKS;\\n lockDate = periodFromKickoff * FOUR_WEEKS + start;\\n }\\n}\\n\",\"keccak256\":\"0x991b246a9930d8f2605d3088965159f15fd8a0e4ddbb64b9f21d4706d89a8ef8\"},\"contracts/governance/Vesting/VestingStorage.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"../../openzeppelin/Ownable.sol\\\";\\nimport \\\"../../interfaces/IERC20.sol\\\";\\nimport \\\"../Staking/interfaces/IStaking.sol\\\";\\nimport \\\"../IFeeSharingCollector.sol\\\";\\n\\n/**\\n * @title Vesting Storage Contract.\\n *\\n * @notice This contract is just the storage required for vesting.\\n * It is parent of VestingLogic and TeamVesting.\\n *\\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\\n * */\\ncontract VestingStorage is Ownable {\\n /// @notice The SOV token contract.\\n IERC20 public SOV;\\n\\n /// @notice The staking contract address.\\n IStaking public staking;\\n\\n /// @notice The owner of the vested tokens.\\n address public tokenOwner;\\n\\n /// @notice Fee sharing Proxy.\\n IFeeSharingCollector public feeSharingCollector;\\n\\n /// @notice The cliff. After this time period the tokens begin to unlock.\\n uint256 public cliff;\\n\\n /// @notice The duration. After this period all tokens will have been unlocked.\\n uint256 public duration;\\n\\n /// @notice The start date of the vesting.\\n uint256 public startDate;\\n\\n /// @notice The end date of the vesting.\\n uint256 public endDate;\\n\\n /// @notice Constant used for computing the vesting dates.\\n uint256 constant FOUR_WEEKS = 4 weeks;\\n}\\n\",\"keccak256\":\"0xf70f579d357d8f0aa0839824c1a1d66713c3cd42a58118d2893a35b52baaa140\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/openzeppelin/SafeMath.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\\n return divCeil(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n\\n if (a == 0) {\\n return 0;\\n }\\n uint256 c = ((a - 1) / b) + 1;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n\\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n return _a < _b ? _a : _b;\\n }\\n}\\n\",\"keccak256\":\"0xbff8d6273e1a6870d1a142c0c23acd63a4dd47760f250390f49ee56333bcb6e8\"},\"contracts/token/IApproveAndCall.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for contract governance/ApprovalReceiver.sol\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n */\\ninterface IApproveAndCall {\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _sender The sender of SOV.approveAndCall function.\\n * @param _amount The amount was approved.\\n * @param _token The address of token.\\n * @param _data The data will be used for low level call.\\n * */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x0ca93f8436a4d81d80de5ea9214139b490d96f708f09c975a0869ce9abc61635\"}},\"version\":1}", + "bytecode": "0x608060405260006100176001600160e01b0361006616565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35061006a565b3390565b611b7f806100796000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806362dc2f35116100ad5780638f32d59b116100715780638f32d59b1461020a5780638f4ffcb11461021f578063a3e6761014610232578063c24a0f8b1461023a578063f2fde38b1461024257610121565b806362dc2f35146101b45780636b7dbb2d146101c75780637547c7a3146101cf57806381e45268146101e25780638da5cb5b146101f557610121565b80634552a7ae116100f45780634552a7ae1461016957806349df728c1461017e5780634cf088d9146101915780635419675f146101995780635c19a95c146101a157610121565b806308dcb360146101265780630b97bc86146101445780630fb5a6b41461015957806313d033c014610161575b600080fd5b61012e610255565b60405161013b919061192c565b60405180910390f35b61014c610264565b60405161013b91906119db565b61014c61026a565b61014c610270565b61017c61017736600461141e565b610276565b005b61017c61018c366004611322565b610320565b61012e61036e565b61017c61037d565b61017c6101af366004611322565b6104fe565b61017c6101c236600461146b565b610615565b61012e610722565b61017c6101dd36600461150f565b610731565b61017c6101f0366004611366565b61073e565b6101fd610767565b60405161013b9190611862565b610212610776565b60405161013b919061191e565b61017c61022d3660046113a0565b61079a565b6101fd61098e565b61014c61099d565b61017c610250366004611322565b6109a3565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b6003546001600160a01b03163314806102925750610292610776565b6102b75760405162461bcd60e51b81526004016102ae9061199b565b60405180910390fd5b600554600754016102c7836109d0565b92508083106102d657826102d8565b805b925060006102ed83600163ffffffff610a1416565b6224ea00028401905060008160085410610307578161030b565b6008545b9050610318868683610a5f565b505050505050565b6003546001600160a01b031633148061033c575061033c610776565b6103585760405162461bcd60e51b81526004016102ae9061199b565b6005546007540161036a828242610a5f565b5050565b6002546001600160a01b031681565b6003546001600160a01b03163314806103995750610399610776565b6103b55760405162461bcd60e51b81526004016102ae9061199b565b600260009054906101000a90046001600160a01b03166001600160a01b0316635419675f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561040557600080fd5b505af1158015610419573d6000803e3d6000fd5b50505050600260009054906101000a90046001600160a01b03166001600160a01b031663ae81dfe46040518163ffffffff1660e01b815260040160206040518083038186803b15801561046b57600080fd5b505afa15801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506104a39190810190611348565b600280546001600160a01b0319166001600160a01b03928316179081905560405133927f9613f431247983a83a2b3667aa63a5174194ac89328dfadc69be44409521b3c1926104f492911690611862565b60405180910390a2565b6003546001600160a01b031633146105285760405162461bcd60e51b81526004016102ae9061199b565b6001600160a01b03811661054e5760405162461bcd60e51b81526004016102ae906119ab565b600554600754015b60085481116105d05760025460405163026e402b60e01b81526001600160a01b039091169063026e402b9061059190859085906004016118c0565b600060405180830381600087803b1580156105ab57600080fd5b505af11580156105bf573d6000803e3d6000fd5b505050506224ea0081019050610556565b50336001600160a01b03167f734a802cc194e2139bfcc08e10336f24dfa14fd2c5ab70268d8706c0558670668260405161060a9190611862565b60405180910390a250565b6003546001600160a01b03163314806106315750610631610776565b61064d5760405162461bcd60e51b81526004016102ae9061199b565b6001600160a01b0381166106735760405162461bcd60e51b81526004016102ae906119bb565b6004805460405163a965b3a960e01b81526001600160a01b039091169163a965b3a9916106a691879187918791016118f6565b600060405180830381600087803b1580156106c057600080fd5b505af11580156106d4573d6000803e3d6000fd5b50505050336001600160a01b03167f5fa0b381cb4bdbc7063d1e5c78b90a634a6d6a12d6cb6fabe450fd4b8d1eab0184838560405161071593929190611898565b60405180910390a2505050565b6004546001600160a01b031681565b61073b3382610cb2565b50565b33301461075d5760405162461bcd60e51b81526004016102ae9061199b565b61036a8282610cb2565b6000546001600160a01b031690565b600080546001600160a01b031661078b610f94565b6001600160a01b031614905090565b6107a2610f98565b6001600160a01b0316336001600160a01b0316146107d25760405162461bcd60e51b81526004016102ae9061199b565b336001600160a01b038416146107fa5760405162461bcd60e51b81526004016102ae9061199b565b60006060610806610fa7565b9050600061084985858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fff92505050565b905060005b82518110156108975782818151811061086357fe5b60200260200101516001600160e01b031916826001600160e01b031916141561088f5760019350610897565b60010161084e565b50826108b55760405162461bcd60e51b81526004016102ae9061197b565b600080600060201b87876040516020016108d193929190611830565b6040516020818303038152906040528060200190516108f391908101906114cc565b9093509150506001600160a01b03808316908b16146109245760405162461bcd60e51b81526004016102ae9061198b565b8881146109435760405162461bcd60e51b81526004016102ae906119cb565b61098287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061100692505050565b50505050505050505050565b6003546001600160a01b031681565b60085481565b6109ab610776565b6109c75760405162461bcd60e51b81526004016102ae9061199b565b61073b816110e0565b60055460075460009101808310156109fa5760405162461bcd60e51b81526004016102ae9061194b565b60006224ea00828503046224ea0002919091019392505050565b6000610a5683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611161565b90505b92915050565b6001600160a01b038316610a855760405162461bcd60e51b81526004016102ae906119bb565b600080600260009054906101000a90046001600160a01b03166001600160a01b0316639929e8866040518163ffffffff1660e01b815260040160206040518083038186803b158015610ad657600080fd5b505afa158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b0e91908101906114ae565b15610b2d576008548310610b2457600854610b26565b825b9050610b4d565b428310610b3a5742610b3c565b825b9050600854811115610b4d57506008545b835b818111610c65576002546040516367bdb42560e11b81526001600160a01b039091169063cf7b684a90610b8e90309085906000194301906004016118db565b60206040518083038186803b158015610ba657600080fd5b505afa158015610bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bde919081019061154b565b92506bffffffffffffffffffffffff831615610c5b576002546040516336adb29160e21b81526001600160a01b039091169063dab6ca4490610c2890869085908b90600401611a43565b600060405180830381600087803b158015610c4257600080fd5b505af1158015610c56573d6000803e3d6000fd5b505050505b6224ea0001610b4f565b50336001600160a01b03167f6b83b455c317523498e4e86849438d4356ad79ba6b355a5e6d5bc05eca6c780f868684604051610ca3939291906118db565b60405180910390a25050505050565b600754610d3d576002546040516372ec979560e01b81526001600160a01b03909116906372ec979590610ce99042906004016119db565b60206040518083038186803b158015610d0157600080fd5b505afa158015610d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d39919081019061152d565b6007555b6002546006546040516372ec979560e01b81526001600160a01b03909216916372ec979591610d739142909101906004016119db565b60206040518083038186803b158015610d8b57600080fd5b505afa158015610d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610dc3919081019061152d565b6008556001546040516323b872dd60e01b81526000916001600160a01b0316906323b872dd90610dfb90869030908790600401611870565b602060405180830381600087803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e4d91908101906114ae565b905080610e5957600080fd5b60015460025460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392610e8f9291169086906004016118c0565b602060405180830381600087803b158015610ea957600080fd5b505af1158015610ebd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ee191908101906114ae565b5060025460055460065460035460405163c1b79b0560e01b81526001600160a01b039485169463c1b79b0594610f29948994919390926224ea009230929116906004016119e9565b600060405180830381600087803b158015610f4357600080fd5b505af1158015610f57573d6000803e3d6000fd5b50505050826001600160a01b03167fb539ca1e5c8d398ddf1c41c30166f33404941683be4683319b57669a93dad4ef8360405161071591906119db565b3390565b6001546001600160a01b031690565b604080516001808252818301909252606091829190602080830190803883390190505090506381e4526860e01b81600081518110610fe157fe5b6001600160e01b031990921660209283029190910190910152905090565b6020015190565b60006060306001600160a01b0316836040516110229190611856565b6000604051808303816000865af19150503d806000811461105f576040519150601f19603f3d011682016040523d82523d6000602084013e611064565b606091505b5091509150816110db57604481511161108f5760405162461bcd60e51b81526004016102ae9061195b565b6110c26040518060400160405280601181526020017003932b1b2b4bb32a0b8383937bb30b61d1607d1b81525082611192565b60405162461bcd60e51b81526004016102ae919061193a565b505050565b6001600160a01b0381166111065760405162461bcd60e51b81526004016102ae9061196b565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b600081848411156111855760405162461bcd60e51b81526004016102ae919061193a565b50508183035b9392505050565b6060808390506060839050606060448251845101036040519080825280601f01601f1916602001820160405280156111d1576020820181803883390190505b509050806000805b855181101561122a578581815181106111ee57fe5b602001015160f81c60f81b83838060010194508151811061120b57fe5b60200101906001600160f81b031916908160001a9053506001016111d9565b5060445b845181101561127f5784818151811061124357fe5b602001015160f81c60f81b83838060010194508151811061126057fe5b60200101906001600160f81b031916908160001a90535060010161122e565b5090979650505050505050565b8035610a5981611b04565b8051610a5981611b04565b8051610a5981611b18565b8051610a5981611b21565b60008083601f8401126112ca57600080fd5b50813567ffffffffffffffff8111156112e257600080fd5b6020830191508360018202830111156112fa57600080fd5b9250929050565b8035610a5981611b21565b8035610a5981611b2a565b8051610a5981611b33565b60006020828403121561133457600080fd5b6000611340848461128c565b949350505050565b60006020828403121561135a57600080fd5b60006113408484611297565b6000806040838503121561137957600080fd5b6000611385858561128c565b925050602061139685828601611301565b9150509250929050565b6000806000806000608086880312156113b857600080fd5b60006113c4888861128c565b95505060206113d588828901611301565b94505060406113e68882890161128c565b935050606086013567ffffffffffffffff81111561140357600080fd5b61140f888289016112b8565b92509250509295509295909350565b60008060006060848603121561143357600080fd5b600061143f868661128c565b935050602061145086828701611301565b925050604061146186828701611301565b9150509250925092565b60008060006060848603121561148057600080fd5b600061148c868661128c565b935050602061149d8682870161130c565b92505060406114618682870161128c565b6000602082840312156114c057600080fd5b600061134084846112a2565b6000806000606084860312156114e157600080fd5b60006114ed86866112ad565b93505060206114fe86828701611297565b9250506040611461868287016112ad565b60006020828403121561152157600080fd5b60006113408484611301565b60006020828403121561153f57600080fd5b600061134084846112ad565b60006020828403121561155d57600080fd5b60006113408484611317565b61157281611a70565b82525050565b61157281611a7b565b61157261158d82611a80565b611a8a565b600061159e8385611a62565b93506115ab838584611abe565b50500190565b60006115bc82611a5e565b6115c68185611a62565b93506115d6818560208601611aca565b9290920192915050565b61157281611ab3565b60006115f482611a5e565b6115fe8185611a67565b935061160e818560208601611aca565b61161781611afa565b9093019392505050565b600061162e601d83611a67565b7f74696d657374616d70203c20636f6e7472616374206372656174696f6e000000815260200192915050565b6000611667603083611a67565b7f72656365697665417070726f76616c3a205472616e73616374696f6e2065786581526f31baba34b7b7103932bb32b93a32b21760811b602082015260400192915050565b60006116b9602683611a67565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000611701601583611a67565b741b595d1a1bd9081a5cc81b9bdd08185b1b1bddd959605a1b815260200192915050565b6000611732600f83611a67565b6e0e6cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b600061175d600c83611a67565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6000611785601983611a67565b7f64656c656761746565206164647265737320696e76616c696400000000000000815260200192915050565b60006117be601883611a67565b7f7265636569766572206164647265737320696e76616c69640000000000000000815260200192915050565b60006117f7600f83611a67565b6e0c2dadeeadce840dad2e6dac2e8c6d608b1b815260200192915050565b61157281611a8a565b61157281611a99565b61157281611aa2565b600061183c8286611581565b601c8201915061184d828486611592565b95945050505050565b600061118b82846115b1565b60208101610a598284611569565b6060810161187e8286611569565b61188b6020830185611569565b6113406040830184611815565b606081016118a68286611569565b6118b36020830185611569565b611340604083018461181e565b604081016118ce8285611569565b61118b6020830184611815565b606081016118e98286611569565b61188b6020830185611815565b606081016119048286611569565b611911602083018561181e565b6113406040830184611569565b60208101610a598284611578565b60208101610a5982846115e0565b60208082528101610a5681846115e9565b60208082528101610a5981611621565b60208082528101610a598161165a565b60208082528101610a59816116ac565b60208082528101610a59816116f4565b60208082528101610a5981611725565b60208082528101610a5981611750565b60208082528101610a5981611778565b60208082528101610a59816117b1565b60208082528101610a59816117ea565b60208101610a598284611815565b60c081016119f78289611815565b611a046020830188611815565b611a116040830187611815565b611a1e6060830186611815565b611a2b6080830185611569565b611a3860a0830184611569565b979650505050505050565b60608101611a518286611827565b6119116020830185611815565b5190565b919050565b90815260200190565b6000610a5982611a8d565b151590565b63ffffffff191690565b90565b6001600160a01b031690565b63ffffffff1690565b6bffffffffffffffffffffffff1690565b6000610a5982611a70565b82818337506000910152565b60005b83811015611ae5578181015183820152602001611acd565b83811115611af4576000848401525b50505050565b601f01601f191690565b611b0d81611a70565b811461073b57600080fd5b611b0d81611a7b565b611b0d81611a8a565b611b0d81611a99565b611b0d81611aa256fea365627a7a72315820715beca3e78a6789e69c27f7c8038b85beaa0593614c96f7d7fe21c13c6ec4776c6578706572696d656e74616cf564736f6c63430005110040", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101215760003560e01c806362dc2f35116100ad5780638f32d59b116100715780638f32d59b1461020a5780638f4ffcb11461021f578063a3e6761014610232578063c24a0f8b1461023a578063f2fde38b1461024257610121565b806362dc2f35146101b45780636b7dbb2d146101c75780637547c7a3146101cf57806381e45268146101e25780638da5cb5b146101f557610121565b80634552a7ae116100f45780634552a7ae1461016957806349df728c1461017e5780634cf088d9146101915780635419675f146101995780635c19a95c146101a157610121565b806308dcb360146101265780630b97bc86146101445780630fb5a6b41461015957806313d033c014610161575b600080fd5b61012e610255565b60405161013b919061192c565b60405180910390f35b61014c610264565b60405161013b91906119db565b61014c61026a565b61014c610270565b61017c61017736600461141e565b610276565b005b61017c61018c366004611322565b610320565b61012e61036e565b61017c61037d565b61017c6101af366004611322565b6104fe565b61017c6101c236600461146b565b610615565b61012e610722565b61017c6101dd36600461150f565b610731565b61017c6101f0366004611366565b61073e565b6101fd610767565b60405161013b9190611862565b610212610776565b60405161013b919061191e565b61017c61022d3660046113a0565b61079a565b6101fd61098e565b61014c61099d565b61017c610250366004611322565b6109a3565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b6003546001600160a01b03163314806102925750610292610776565b6102b75760405162461bcd60e51b81526004016102ae9061199b565b60405180910390fd5b600554600754016102c7836109d0565b92508083106102d657826102d8565b805b925060006102ed83600163ffffffff610a1416565b6224ea00028401905060008160085410610307578161030b565b6008545b9050610318868683610a5f565b505050505050565b6003546001600160a01b031633148061033c575061033c610776565b6103585760405162461bcd60e51b81526004016102ae9061199b565b6005546007540161036a828242610a5f565b5050565b6002546001600160a01b031681565b6003546001600160a01b03163314806103995750610399610776565b6103b55760405162461bcd60e51b81526004016102ae9061199b565b600260009054906101000a90046001600160a01b03166001600160a01b0316635419675f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561040557600080fd5b505af1158015610419573d6000803e3d6000fd5b50505050600260009054906101000a90046001600160a01b03166001600160a01b031663ae81dfe46040518163ffffffff1660e01b815260040160206040518083038186803b15801561046b57600080fd5b505afa15801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506104a39190810190611348565b600280546001600160a01b0319166001600160a01b03928316179081905560405133927f9613f431247983a83a2b3667aa63a5174194ac89328dfadc69be44409521b3c1926104f492911690611862565b60405180910390a2565b6003546001600160a01b031633146105285760405162461bcd60e51b81526004016102ae9061199b565b6001600160a01b03811661054e5760405162461bcd60e51b81526004016102ae906119ab565b600554600754015b60085481116105d05760025460405163026e402b60e01b81526001600160a01b039091169063026e402b9061059190859085906004016118c0565b600060405180830381600087803b1580156105ab57600080fd5b505af11580156105bf573d6000803e3d6000fd5b505050506224ea0081019050610556565b50336001600160a01b03167f734a802cc194e2139bfcc08e10336f24dfa14fd2c5ab70268d8706c0558670668260405161060a9190611862565b60405180910390a250565b6003546001600160a01b03163314806106315750610631610776565b61064d5760405162461bcd60e51b81526004016102ae9061199b565b6001600160a01b0381166106735760405162461bcd60e51b81526004016102ae906119bb565b6004805460405163a965b3a960e01b81526001600160a01b039091169163a965b3a9916106a691879187918791016118f6565b600060405180830381600087803b1580156106c057600080fd5b505af11580156106d4573d6000803e3d6000fd5b50505050336001600160a01b03167f5fa0b381cb4bdbc7063d1e5c78b90a634a6d6a12d6cb6fabe450fd4b8d1eab0184838560405161071593929190611898565b60405180910390a2505050565b6004546001600160a01b031681565b61073b3382610cb2565b50565b33301461075d5760405162461bcd60e51b81526004016102ae9061199b565b61036a8282610cb2565b6000546001600160a01b031690565b600080546001600160a01b031661078b610f94565b6001600160a01b031614905090565b6107a2610f98565b6001600160a01b0316336001600160a01b0316146107d25760405162461bcd60e51b81526004016102ae9061199b565b336001600160a01b038416146107fa5760405162461bcd60e51b81526004016102ae9061199b565b60006060610806610fa7565b9050600061084985858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fff92505050565b905060005b82518110156108975782818151811061086357fe5b60200260200101516001600160e01b031916826001600160e01b031916141561088f5760019350610897565b60010161084e565b50826108b55760405162461bcd60e51b81526004016102ae9061197b565b600080600060201b87876040516020016108d193929190611830565b6040516020818303038152906040528060200190516108f391908101906114cc565b9093509150506001600160a01b03808316908b16146109245760405162461bcd60e51b81526004016102ae9061198b565b8881146109435760405162461bcd60e51b81526004016102ae906119cb565b61098287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061100692505050565b50505050505050505050565b6003546001600160a01b031681565b60085481565b6109ab610776565b6109c75760405162461bcd60e51b81526004016102ae9061199b565b61073b816110e0565b60055460075460009101808310156109fa5760405162461bcd60e51b81526004016102ae9061194b565b60006224ea00828503046224ea0002919091019392505050565b6000610a5683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611161565b90505b92915050565b6001600160a01b038316610a855760405162461bcd60e51b81526004016102ae906119bb565b600080600260009054906101000a90046001600160a01b03166001600160a01b0316639929e8866040518163ffffffff1660e01b815260040160206040518083038186803b158015610ad657600080fd5b505afa158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b0e91908101906114ae565b15610b2d576008548310610b2457600854610b26565b825b9050610b4d565b428310610b3a5742610b3c565b825b9050600854811115610b4d57506008545b835b818111610c65576002546040516367bdb42560e11b81526001600160a01b039091169063cf7b684a90610b8e90309085906000194301906004016118db565b60206040518083038186803b158015610ba657600080fd5b505afa158015610bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bde919081019061154b565b92506bffffffffffffffffffffffff831615610c5b576002546040516336adb29160e21b81526001600160a01b039091169063dab6ca4490610c2890869085908b90600401611a43565b600060405180830381600087803b158015610c4257600080fd5b505af1158015610c56573d6000803e3d6000fd5b505050505b6224ea0001610b4f565b50336001600160a01b03167f6b83b455c317523498e4e86849438d4356ad79ba6b355a5e6d5bc05eca6c780f868684604051610ca3939291906118db565b60405180910390a25050505050565b600754610d3d576002546040516372ec979560e01b81526001600160a01b03909116906372ec979590610ce99042906004016119db565b60206040518083038186803b158015610d0157600080fd5b505afa158015610d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d39919081019061152d565b6007555b6002546006546040516372ec979560e01b81526001600160a01b03909216916372ec979591610d739142909101906004016119db565b60206040518083038186803b158015610d8b57600080fd5b505afa158015610d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610dc3919081019061152d565b6008556001546040516323b872dd60e01b81526000916001600160a01b0316906323b872dd90610dfb90869030908790600401611870565b602060405180830381600087803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e4d91908101906114ae565b905080610e5957600080fd5b60015460025460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392610e8f9291169086906004016118c0565b602060405180830381600087803b158015610ea957600080fd5b505af1158015610ebd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ee191908101906114ae565b5060025460055460065460035460405163c1b79b0560e01b81526001600160a01b039485169463c1b79b0594610f29948994919390926224ea009230929116906004016119e9565b600060405180830381600087803b158015610f4357600080fd5b505af1158015610f57573d6000803e3d6000fd5b50505050826001600160a01b03167fb539ca1e5c8d398ddf1c41c30166f33404941683be4683319b57669a93dad4ef8360405161071591906119db565b3390565b6001546001600160a01b031690565b604080516001808252818301909252606091829190602080830190803883390190505090506381e4526860e01b81600081518110610fe157fe5b6001600160e01b031990921660209283029190910190910152905090565b6020015190565b60006060306001600160a01b0316836040516110229190611856565b6000604051808303816000865af19150503d806000811461105f576040519150601f19603f3d011682016040523d82523d6000602084013e611064565b606091505b5091509150816110db57604481511161108f5760405162461bcd60e51b81526004016102ae9061195b565b6110c26040518060400160405280601181526020017003932b1b2b4bb32a0b8383937bb30b61d1607d1b81525082611192565b60405162461bcd60e51b81526004016102ae919061193a565b505050565b6001600160a01b0381166111065760405162461bcd60e51b81526004016102ae9061196b565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b600081848411156111855760405162461bcd60e51b81526004016102ae919061193a565b50508183035b9392505050565b6060808390506060839050606060448251845101036040519080825280601f01601f1916602001820160405280156111d1576020820181803883390190505b509050806000805b855181101561122a578581815181106111ee57fe5b602001015160f81c60f81b83838060010194508151811061120b57fe5b60200101906001600160f81b031916908160001a9053506001016111d9565b5060445b845181101561127f5784818151811061124357fe5b602001015160f81c60f81b83838060010194508151811061126057fe5b60200101906001600160f81b031916908160001a90535060010161122e565b5090979650505050505050565b8035610a5981611b04565b8051610a5981611b04565b8051610a5981611b18565b8051610a5981611b21565b60008083601f8401126112ca57600080fd5b50813567ffffffffffffffff8111156112e257600080fd5b6020830191508360018202830111156112fa57600080fd5b9250929050565b8035610a5981611b21565b8035610a5981611b2a565b8051610a5981611b33565b60006020828403121561133457600080fd5b6000611340848461128c565b949350505050565b60006020828403121561135a57600080fd5b60006113408484611297565b6000806040838503121561137957600080fd5b6000611385858561128c565b925050602061139685828601611301565b9150509250929050565b6000806000806000608086880312156113b857600080fd5b60006113c4888861128c565b95505060206113d588828901611301565b94505060406113e68882890161128c565b935050606086013567ffffffffffffffff81111561140357600080fd5b61140f888289016112b8565b92509250509295509295909350565b60008060006060848603121561143357600080fd5b600061143f868661128c565b935050602061145086828701611301565b925050604061146186828701611301565b9150509250925092565b60008060006060848603121561148057600080fd5b600061148c868661128c565b935050602061149d8682870161130c565b92505060406114618682870161128c565b6000602082840312156114c057600080fd5b600061134084846112a2565b6000806000606084860312156114e157600080fd5b60006114ed86866112ad565b93505060206114fe86828701611297565b9250506040611461868287016112ad565b60006020828403121561152157600080fd5b60006113408484611301565b60006020828403121561153f57600080fd5b600061134084846112ad565b60006020828403121561155d57600080fd5b60006113408484611317565b61157281611a70565b82525050565b61157281611a7b565b61157261158d82611a80565b611a8a565b600061159e8385611a62565b93506115ab838584611abe565b50500190565b60006115bc82611a5e565b6115c68185611a62565b93506115d6818560208601611aca565b9290920192915050565b61157281611ab3565b60006115f482611a5e565b6115fe8185611a67565b935061160e818560208601611aca565b61161781611afa565b9093019392505050565b600061162e601d83611a67565b7f74696d657374616d70203c20636f6e7472616374206372656174696f6e000000815260200192915050565b6000611667603083611a67565b7f72656365697665417070726f76616c3a205472616e73616374696f6e2065786581526f31baba34b7b7103932bb32b93a32b21760811b602082015260400192915050565b60006116b9602683611a67565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000611701601583611a67565b741b595d1a1bd9081a5cc81b9bdd08185b1b1bddd959605a1b815260200192915050565b6000611732600f83611a67565b6e0e6cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b600061175d600c83611a67565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6000611785601983611a67565b7f64656c656761746565206164647265737320696e76616c696400000000000000815260200192915050565b60006117be601883611a67565b7f7265636569766572206164647265737320696e76616c69640000000000000000815260200192915050565b60006117f7600f83611a67565b6e0c2dadeeadce840dad2e6dac2e8c6d608b1b815260200192915050565b61157281611a8a565b61157281611a99565b61157281611aa2565b600061183c8286611581565b601c8201915061184d828486611592565b95945050505050565b600061118b82846115b1565b60208101610a598284611569565b6060810161187e8286611569565b61188b6020830185611569565b6113406040830184611815565b606081016118a68286611569565b6118b36020830185611569565b611340604083018461181e565b604081016118ce8285611569565b61118b6020830184611815565b606081016118e98286611569565b61188b6020830185611815565b606081016119048286611569565b611911602083018561181e565b6113406040830184611569565b60208101610a598284611578565b60208101610a5982846115e0565b60208082528101610a5681846115e9565b60208082528101610a5981611621565b60208082528101610a598161165a565b60208082528101610a59816116ac565b60208082528101610a59816116f4565b60208082528101610a5981611725565b60208082528101610a5981611750565b60208082528101610a5981611778565b60208082528101610a59816117b1565b60208082528101610a59816117ea565b60208101610a598284611815565b60c081016119f78289611815565b611a046020830188611815565b611a116040830187611815565b611a1e6060830186611815565b611a2b6080830185611569565b611a3860a0830184611569565b979650505050505050565b60608101611a518286611827565b6119116020830185611815565b5190565b919050565b90815260200190565b6000610a5982611a8d565b151590565b63ffffffff191690565b90565b6001600160a01b031690565b63ffffffff1690565b6bffffffffffffffffffffffff1690565b6000610a5982611a70565b82818337506000910152565b60005b83811015611ae5578181015183820152602001611acd565b83811115611af4576000848401525b50505050565b601f01601f191690565b611b0d81611a70565b811461073b57600080fd5b611b0d81611a7b565b611b0d81611a8a565b611b0d81611a99565b611b0d81611aa256fea365627a7a72315820715beca3e78a6789e69c27f7c8038b85beaa0593614c96f7d7fe21c13c6ec4776c6578706572696d656e74616cf564736f6c63430005110040", + "devdoc": { + "details": "Deployed by a VestingFactory contract.", + "methods": { + "collectDividends(address,uint32,address)": { + "params": { + "_loanPoolToken": "The loan pool token address.", + "_maxCheckpoints": "Maximum number of checkpoints to be processed.", + "_receiver": "The receiver of tokens or msg.sender" + } + }, + "delegate(address)": { + "params": { + "_delegatee": "The address to delegate votes to." + } + }, + "isOwner()": { + "details": "Returns true if the caller is the current owner." + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "receiveApproval(address,uint256,address,bytes)": { + "params": { + "_data": "The data will be used for low level call." + } + }, + "stakeTokens(uint256)": { + "params": { + "_amount": "The amount of tokens to stake." + } + }, + "stakeTokensWithApproval(address,uint256)": { + "details": "This function will be invoked from receiveApproval.SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval", + "params": { + "_amount": "The amount of tokens to stake.", + "_sender": "The sender of SOV.approveAndCall" + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + }, + "withdrawTokens(address)": { + "params": { + "receiver": "The receiving address." + } + }, + "withdrawTokensStartingFrom(address,uint256,uint256)": { + "params": { + "maxWithdrawIterations": "max withdrawal iteration to work around block gas limit issue.", + "receiver": "The receiving address.", + "startFrom": "The start value for the iterations." + } + } + }, + "title": "Vesting Logic contract." + }, + "userdoc": { + "methods": { + "collectDividends(address,uint32,address)": { + "notice": "Collect dividends from fee sharing proxy." + }, + "delegate(address)": { + "notice": "Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`." + }, + "migrateToNewStakingContract()": { + "notice": "Allows the owners to migrate the positions to a new staking contract." + }, + "receiveApproval(address,uint256,address,bytes)": { + "notice": "Receives approval from SOV token." + }, + "stakeTokens(uint256)": { + "notice": "Stakes tokens according to the vesting schedule." + }, + "stakeTokensWithApproval(address,uint256)": { + "notice": "Stakes tokens according to the vesting schedule." + }, + "withdrawTokens(address)": { + "notice": "Withdraws unlocked tokens from the staking contract and forwards them to an address specified by the token owner." + }, + "withdrawTokensStartingFrom(address,uint256,uint256)": { + "notice": "Withdraws unlocked tokens partially (based on the max withdraw iteration that has been set) from the staking contract and forwards them to an address specified by the token owner." + } + }, + "notice": "Staking, delegating and withdrawal functionality." + }, + "storageLayout": { + "storage": [ + { + "astId": 54807, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 32151, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "SOV", + "offset": 0, + "slot": "1", + "type": "t_contract(IERC20)33453" + }, + { + "astId": 32153, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "staking", + "offset": 0, + "slot": "2", + "type": "t_contract(IStaking)17840" + }, + { + "astId": 32155, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "tokenOwner", + "offset": 0, + "slot": "3", + "type": "t_address" + }, + { + "astId": 32157, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "feeSharingCollector", + "offset": 0, + "slot": "4", + "type": "t_contract(IFeeSharingCollector)17012" + }, + { + "astId": 32159, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "cliff", + "offset": 0, + "slot": "5", + "type": "t_uint256" + }, + { + "astId": 32161, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "duration", + "offset": 0, + "slot": "6", + "type": "t_uint256" + }, + { + "astId": 32163, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "startDate", + "offset": 0, + "slot": "7", + "type": "t_uint256" + }, + { + "astId": 32165, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "endDate", + "offset": 0, + "slot": "8", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_contract(IERC20)33453": { + "encoding": "inplace", + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IFeeSharingCollector)17012": { + "encoding": "inplace", + "label": "contract IFeeSharingCollector", + "numberOfBytes": "20" + }, + "t_contract(IStaking)17840": { + "encoding": "inplace", + "label": "contract IStaking", + "numberOfBytes": "20" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/deployment/deployments/rskSovrynMainnet/solcInputs/16608baccc4c89e15713f1946c71539a.json b/deployment/deployments/rskSovrynMainnet/solcInputs/16608baccc4c89e15713f1946c71539a.json new file mode 100644 index 000000000..10b7a1252 --- /dev/null +++ b/deployment/deployments/rskSovrynMainnet/solcInputs/16608baccc4c89e15713f1946c71539a.json @@ -0,0 +1,711 @@ +{ + "language": "Solidity", + "sources": { + "contracts/connectors/loantoken/AdvancedToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Advanced Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedToken implements standard ERC-20 approval, mint and burn token functionality.\n * Logic (AdvancedToken) is kept aside from storage (AdvancedTokenStorage).\n *\n * For example, LoanTokenLogicDai contract uses AdvancedToken::_mint() to mint\n * its Loan Dai iTokens.\n * */\ncontract AdvancedToken is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n /**\n * @notice Set an amount as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n *\n * @param _spender The account address that will be able to spend the tokens.\n * @param _value The amount of tokens allowed to spend.\n * */\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @notice The iToken minting process. Meant to issue Loan iTokens.\n * Lenders are able to open an iToken position, by minting them.\n * This function is called by LoanTokenLogicStandard::_mintToken\n * @param _to The recipient of the minted tTokens.\n * @param _tokenAmount The amount of iTokens to be minted.\n * @param _assetAmount The amount of lended tokens (asset to lend).\n * @param _price The price of the lended tokens.\n * @return The updated balance of the recipient.\n * */\n function _mint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n require(_to != address(0), \"15\");\n\n uint256 _balance = balances[_to].add(_tokenAmount);\n balances[_to] = _balance;\n\n totalSupply_ = totalSupply_.add(_tokenAmount);\n\n emit Mint(_to, _tokenAmount, _assetAmount, _price);\n emit Transfer(address(0), _to, _tokenAmount);\n\n return _balance;\n }\n\n /**\n * @notice The iToken burning process. Meant to destroy Loan iTokens.\n * Lenders are able to close an iToken position, by burning them.\n * This function is called by LoanTokenLogicStandard::_burnToken\n * @param _who The owner of the iTokens to burn.\n * @param _tokenAmount The amount of iTokens to burn.\n * @param _assetAmount The amount of lended tokens.\n * @param _price The price of the lended tokens.\n * @return The updated balance of the iTokens owner.\n * */\n function _burn(\n address _who,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n //bzx compare\n //TODO: Unit test\n uint256 _balance = balances[_who].sub(_tokenAmount, \"16\");\n\n // a rounding error may leave dust behind, so we clear this out\n if (_balance <= 10) {\n // We can't leave such small balance quantities.\n _tokenAmount = _tokenAmount.add(_balance);\n _balance = 0;\n }\n balances[_who] = _balance;\n\n totalSupply_ = totalSupply_.sub(_tokenAmount);\n\n emit Burn(_who, _tokenAmount, _assetAmount, _price);\n emit Transfer(_who, address(0), _tokenAmount);\n return _balance;\n }\n}\n" + }, + "contracts/connectors/loantoken/AdvancedTokenStorage.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./LoanTokenBase.sol\";\n\n/**\n * @title Advanced Token Storage contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedTokenStorage implements standard ERC-20 getters functionality:\n * totalSupply, balanceOf, allowance and some events.\n * iToken logic is divided into several contracts AdvancedToken,\n * AdvancedTokenStorage and LoanTokenBase.\n * */\ncontract AdvancedTokenStorage is LoanTokenBase {\n using SafeMath for uint256;\n\n /* Events */\n\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /* Storage */\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n /* Functions */\n\n /**\n * @notice Get the total supply of iTokens.\n * @return The total number of iTokens in existence as of now.\n * */\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n /**\n * @notice Get the amount of iTokens owned by an account.\n * @param _owner The account owner of the iTokens.\n * @return The number of iTokens an account owns.\n * */\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n /**\n * @notice Get the amount of iTokens allowed to be spent by a\n * given account on behalf of the owner.\n * @param _owner The account owner of the iTokens.\n * @param _spender The account allowed to send the iTokens.\n * @return The number of iTokens an account is allowing the spender\n * to send on its behalf.\n * */\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/connectors/loantoken/interfaces/FeedsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface FeedsLike {\n function queryRate(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 rate, uint256 precision);\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../lib/MarginTradeStructHelpers.sol\";\n\ninterface ProtocolLike {\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function priceFeeds() external view returns (address);\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function lendingFeePercent() external view returns (uint256);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function borrowerNonce(address) external view returns (uint256);\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata // for future use /*loanDataBytes*/\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolSettingsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../core/objects/LoanParamsStruct.sol\";\n\ninterface ProtocolSettingsLike {\n function setupLoanParams(LoanParamsStruct.LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n}\n" + }, + "contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol": { + "content": "pragma solidity 0.5.17;\n\nlibrary MarginTradeStructHelpers {\n struct SentAddresses {\n address lender;\n address borrower;\n address receiver;\n address manager;\n }\n\n struct SentAmounts {\n uint256 interestRate;\n uint256 newPrincipal;\n uint256 interestInitialAmount;\n uint256 loanTokenSent;\n uint256 collateralTokenSent;\n uint256 minEntryPrice;\n uint256 loanToCollateralSwapRate;\n uint256 interestDuration;\n uint256 entryLeverage;\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Loan Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * A loan token (iToken) is created as a proxy to an upgradable token contract.\n *\n * Examples of loan tokens on Sovryn are iRBTC, iDOC, iUSDT, iBPro,\n * iSOV (near future).\n *\n * Lenders receive iTokens that collect interest from the lending pool\n * which they can redeem by withdrawing them. The i in iToken stands for interest.\n *\n * Do not confuse iTokens with underlying tokens. iDOC is an iToken (loan token)\n * whilest DOC is the underlying token (currency).\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\n * */\ncontract LoanToken is AdvancedTokenStorage {\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n address public admin;\n\n /**\n * @notice Deploy loan token proxy.\n * Sets ERC20 parameters of the token.\n *\n * @param _newOwner The address of the new owner.\n * @param _newTarget The address of the new target contract instance.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice Public owner setter for target address.\n * @dev Calls internal setter.\n * @param _newTarget The address of the new target contract instance.\n * */\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n /**\n * @notice Internal setter for target address.\n * @param _newTarget The address of the new target contract instance.\n * */\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n /**\n * @notice Internal setter for sovrynContract address.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * */\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n /**\n * @notice Internal setter for wrBTC address.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n /**\n * @notice Public owner cloner for pointed loan token.\n * Sets ERC20 parameters of the token.\n *\n * @dev TODO: add check for double init.\n * idk but init usually can be called only once.\n *\n * @param _loanTokenAddress The address of the pointed loan token instance.\n * @param _name The ERC20 token name.\n * @param _symbol The ERC20 token symbol.\n * */\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; /// starting price of 1\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenBase.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SignedSafeMath.sol\";\nimport \"../../openzeppelin/ReentrancyGuard.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\nimport \"./Pausable.sol\";\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title Loan Token Base contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Specific loan related storage for iTokens.\n *\n * An loan token or iToken is a representation of a user funds in the pool and the\n * interest they've earned. The redemption value of iTokens continually increase\n * from the accretion of interest paid into the lending pool by borrowers. The user\n * can sell iTokens to exit its position. The user might potentially use them as\n * collateral wherever applicable.\n *\n * There are three main tokens in the bZx system, iTokens, pTokens, and BZRX tokens.\n * The bZx system of lending and borrowing depends on iTokens and pTokens, and when\n * users lend or borrow money on bZx, their crypto assets go into or come out of\n * global liquidity pools, which are pools of funds shared between many different\n * exchanges. When lenders supply funds into the global liquidity pools, they\n * automatically receive iTokens; When users borrow money to open margin trading\n * positions, they automatically receive pTokens. The system is also designed to\n * use the BZRX tokens, which are only used to pay fees on the network currently.\n * */\ncontract LoanTokenBase is ReentrancyGuard, SharedReentrancyGuard, Ownable, Pausable {\n uint256 internal constant WEI_PRECISION = 10**18;\n uint256 internal constant WEI_PERCENT_PRECISION = 10**20;\n\n int256 internal constant sWEI_PRECISION = 10**18;\n\n /// @notice Standard ERC-20 properties\n string public name;\n string public symbol;\n uint8 public decimals;\n\n /// @notice The address of the loan token (asset to lend) instance.\n address public loanTokenAddress;\n\n uint256 public baseRate;\n uint256 public rateMultiplier;\n uint256 public lowUtilBaseRate;\n uint256 public lowUtilRateMultiplier;\n\n uint256 public targetLevel;\n uint256 public kinkLevel;\n uint256 public maxScaleRate;\n\n uint256 internal _flTotalAssetSupply;\n uint256 public checkpointSupply;\n uint256 public initialPrice;\n\n /// uint88 for tight packing -> 8 + 88 + 160 = 256\n uint88 internal lastSettleTime_;\n\n /// Mapping of keccak256(collateralToken, isTorqueLoan) to loanParamsId.\n mapping(uint256 => bytes32) public loanParamsIds;\n\n /// Price of token at last user checkpoint.\n mapping(address => uint256) internal checkpointPrices_;\n\n // the maximum trading/borrowing/lending limit per token address\n mapping(address => uint256) public transactionLimit;\n // 0 -> no limit\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicBeacon.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../mixins/EnumerableBytes32Set.sol\";\nimport \"../../mixins/EnumerableBytes4Set.sol\";\nimport \"../../utils/PausableRole.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Loan Token Logic Beacon contract.\n *\n * @notice This contract stored the target logic implementation of LoanTokens which has the same logic implementation (LoanTokenLogicLM / LoanTokenLogicWrbtc)\n * Apart from storing the target logic implementation, this contract also has a pause functionality.\n * By implementing pause/unpause functionality in this beacon contract, we can pause the loan token that has the same Logic (LoanTokenLogicLM / LoanTokenLogicWrbtc) at one call.\n * Meanwhile the pause/unpause function in the LoanTokenLogicProxy is used to pause/unpause specific LoanToken\n */\n\ncontract LoanTokenLogicBeacon is PausableRole {\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; // enumerable map of bytes4 or addresses\n\n mapping(bytes4 => address) private logicTargets;\n\n struct LoanTokenLogicModuleUpdate {\n address implementation; // address implementaion of the module\n uint256 updateTimestamp; // time of update\n }\n\n mapping(bytes32 => LoanTokenLogicModuleUpdate[]) public moduleUpgradeLog; /** the module name as the key */\n\n mapping(bytes32 => uint256) public activeModuleIndex; /** To store the current active index log for module */\n\n mapping(bytes32 => EnumerableBytes4Set.Bytes4Set) private activeFuncSignatureList; /** Store the current active function signature */\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n * This is the overriden function from the pausable contract, so that we can use custom error message.\n */\n modifier whenNotPaused() {\n require(!_paused, \"LoanTokenLogicBeacon:paused mode\");\n _;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This function will store the updated protocol module to the storage (For rollback purposes)\n *\n * @param loanTokenModuleAddress The module target address\n */\n function registerLoanTokenModule(address loanTokenModuleAddress) external onlyOwner {\n bytes32 moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n\n // Store the upgrade to the log\n moduleUpgradeLog[moduleName].push(\n LoanTokenLogicModuleUpdate(loanTokenModuleAddress, block.timestamp)\n );\n activeModuleIndex[moduleName] = moduleUpgradeLog[moduleName].length - 1;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This registration will require target contract to have the exact function getListFunctionSignatures() which will return functionSignatureList and the moduleName in bytes32\n *\n * @param loanTokenModuleAddress the target logic of the loan token module\n *\n * @return the module name\n */\n function _registerLoanTokenModule(address loanTokenModuleAddress) private returns (bytes32) {\n require(\n Address.isContract(loanTokenModuleAddress),\n \"LoanTokenModuleAddress is not a contract\"\n );\n\n // Get the list of function signature on this loanTokenModulesAddress\n (bytes4[] memory functionSignatureList, bytes32 moduleName) =\n ILoanTokenLogicModules(loanTokenModuleAddress).getListFunctionSignatures();\n\n /// register / update the module function signature address implementation\n for (uint256 i; i < functionSignatureList.length; i++) {\n require(functionSignatureList[i] != bytes4(0x0), \"ERR_EMPTY_FUNC_SIGNATURE\");\n logicTargets[functionSignatureList[i]] = loanTokenModuleAddress;\n if (!activeFuncSignatureList[moduleName].contains(functionSignatureList[i]))\n activeFuncSignatureList[moduleName].addBytes4(functionSignatureList[i]);\n }\n\n /// delete the \"removed\" module function signature in the current implementation\n bytes4[] memory activeSignatureListEnum =\n activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n for (uint256 i; i < activeSignatureListEnum.length; i++) {\n bytes4 activeSigBytes = activeSignatureListEnum[i];\n if (logicTargets[activeSigBytes] != loanTokenModuleAddress) {\n logicTargets[activeSigBytes] = address(0);\n activeFuncSignatureList[moduleName].removeBytes4(activeSigBytes);\n }\n }\n\n return moduleName;\n }\n\n /**\n * @dev get all active function signature list based on the module name.\n *\n * @param moduleName in bytes32.\n *\n * @return the array of function signature.\n */\n function getActiveFuncSignatureList(bytes32 moduleName)\n public\n view\n returns (bytes4[] memory signatureList)\n {\n signatureList = activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n return signatureList;\n }\n\n /**\n * @dev Get total length of the module upgrade log.\n *\n * @param moduleName in bytes32.\n *\n * @return length of module upgrade log.\n */\n function getModuleUpgradeLogLength(bytes32 moduleName) external view returns (uint256) {\n return moduleUpgradeLog[moduleName].length;\n }\n\n /**\n * @notice This function will rollback particular module to the spesific index / version of deployment\n *\n * @param moduleName Name of module in bytes32 format\n * @param index index / version of previous deployment\n */\n function rollback(bytes32 moduleName, uint256 index) external onlyOwner {\n address loanTokenModuleAddress = moduleUpgradeLog[moduleName][index].implementation;\n moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n activeModuleIndex[moduleName] = index;\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(bytes4 sig) external view whenNotPaused returns (address) {\n return logicTargets[sig];\n }\n}\n\ninterface ILoanTokenLogicModules {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory, bytes32 moduleName);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicProxy.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./AdvancedTokenStorage.sol\";\nimport \"../../openzeppelin/Initializable.sol\";\n\n/**\n * @title Loan Token Logic Proxy contract.\n *\n * @notice This contract contains the proxy functionality and it will query the logic target from LoanTokenLogicBeacon\n * This contract will also has the pause/unpause functionality. The purpose of this pausability is so that we can pause/unpause from the loan token level.\n *\n */\ncontract LoanTokenLogicProxy is AdvancedTokenStorage {\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT\n */\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT (CONSTANT / IMMUTABLE)\n */\n\n bytes32 internal constant LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT =\n keccak256(\"LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT\");\n\n modifier onlyAdmin() {\n require(isOwner(), \"LoanTokenLogicProxy:unauthorized\");\n _;\n }\n\n /**\n * @notice Fallback function performs a logic implementation address query to LoanTokenLogicBeacon and then do delegate call to that query result address.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n // query the logic target implementation address from the LoanTokenLogicBeacon\n address target = ILoanTokenLogicBeacon(_beaconAddress()).getTarget(msg.sig);\n require(target != address(0), \"LoanTokenLogicProxy:target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @dev Returns the current Loan Token logic Beacon.\n * @return Address of the current LoanTokenLogicBeacon.\n */\n function _beaconAddress() internal view returns (address beaconAddress) {\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n assembly {\n beaconAddress := sload(slot)\n }\n }\n\n /**\n * @return The address of the current LoanTokenLogicBeacon.\n */\n function beaconAddress() external view returns (address) {\n return _beaconAddress();\n }\n\n /**\n * @dev Set/update the new beacon address.\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon.\n */\n function _setBeaconAddress(address _newBeaconAddress) private {\n require(\n Address.isContract(_newBeaconAddress),\n \"Cannot set beacon address to a non-contract address\"\n );\n\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n\n assembly {\n sstore(slot, _newBeaconAddress)\n }\n }\n\n /**\n * @dev External function to set the new LoanTokenLogicBeacon Address\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon\n */\n function setBeaconAddress(address _newBeaconAddress) external onlyAdmin {\n _setBeaconAddress(_newBeaconAddress);\n }\n\n /**\n * @dev External function to return the LoanTokenLogicProxy of loan token (target of LoanToken contract).\n * Ideally this getter should be added in the LoanToken contract\n * but since LoanToken contract can't be changed, adding the getter in this contract will do\n * because it will use the context of LoanToken contract.\n *\n * @return target address of LoanToken contract\n */\n function getTarget() external view returns (address) {\n return target_;\n }\n}\n\ninterface ILoanTokenLogicBeacon {\n function getTarget(bytes4 functionSignature)\n external\n view\n returns (address logicTargetAddress);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicShared.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicStorage.sol\";\nimport \"./interfaces/ProtocolLike.sol\";\nimport \"./interfaces/FeedsLike.sol\";\nimport \"./interfaces/ProtocolSettingsLike.sol\";\nimport \"../../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../../farm/ILiquidityMining.sol\";\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../governance/Vesting/IVesting.sol\";\n\n/**\n * @dev This contract shares functions used by both LoanTokenLogicSplit and LoanTokenLogicStandard\n */\ncontract LoanTokenLogicShared is LoanTokenLogicStorage {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /**\n * @notice Update the user's checkpoint price and profit so far.\n * In this loan token contract, whenever some tokens are minted or burned,\n * the _updateCheckpoints() function is invoked to update the stats to\n * reflect the balance changes.\n *\n * @param _user The user address.\n * @param _oldBalance The user's previous balance.\n * @param _newBalance The user's updated balance.\n * @param _currentPrice The current loan token price.\n * */\n function _updateCheckpoints(\n address _user,\n uint256 _oldBalance,\n uint256 _newBalance,\n uint256 _currentPrice\n ) internal {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(_user, iToken_ProfitSoFar));\n\n int256 _currentProfit;\n if (_newBalance == 0) {\n _currentPrice = 0;\n } else if (_oldBalance != 0) {\n _currentProfit = _profitOf(slot, _oldBalance, _currentPrice, checkpointPrices_[_user]);\n }\n\n assembly {\n sstore(slot, _currentProfit)\n }\n\n checkpointPrices_[_user] = _currentPrice;\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice Transfer tokens, low level.\n * Checks allowance, updates sender and recipient balances\n * and updates checkpoints too.\n *\n * @param _from The tokens' owner.\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @param _allowanceAmount The amount of tokens allowed to transfer.\n *\n * @return Success true/false.\n * */\n function _internalTransferFrom(\n address _from,\n address _to,\n uint256 _value,\n uint256 _allowanceAmount\n ) internal returns (bool) {\n if (_allowanceAmount != uint256(-1)) {\n allowed[_from][msg.sender] = _allowanceAmount.sub(_value, \"14\");\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, _allowanceAmount, allowed[_from][msg.sender]);\n }\n\n require(_to != address(0), \"15\");\n\n uint256 _balancesFrom = balances[_from];\n uint256 _balancesFromNew = _balancesFrom.sub(_value, \"16\");\n balances[_from] = _balancesFromNew;\n\n uint256 _balancesTo = balances[_to];\n uint256 _balancesToNew = _balancesTo.add(_value);\n balances[_to] = _balancesToNew;\n\n /// @dev Handle checkpoint update.\n uint256 _currentPrice = tokenPrice();\n\n //checkpoints are not being used by the smart contract logic itself, but just for external use (query the profit)\n //only update the checkpoints of a user if he's not depositing to / withdrawing from the lending pool\n if (_from != liquidityMiningAddress && _to != liquidityMiningAddress) {\n _updateCheckpoints(_from, _balancesFrom, _balancesFromNew, _currentPrice);\n _updateCheckpoints(_to, _balancesTo, _balancesToNew, _currentPrice);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n /**\n * @notice Profit calculation based on checkpoints of price.\n * @param slot The user slot.\n * @param _balance The user balance.\n * @param _currentPrice The current price of the loan token.\n * @param _checkpointPrice The price of the loan token on checkpoint.\n * @return The profit of a user.\n * */\n function _profitOf(\n bytes32 slot,\n uint256 _balance,\n uint256 _currentPrice,\n uint256 _checkpointPrice\n ) internal view returns (int256 profitSoFar) {\n if (_checkpointPrice == 0) {\n return 0;\n }\n\n assembly {\n profitSoFar := sload(slot)\n }\n\n profitSoFar = int256(_currentPrice)\n .sub(int256(_checkpointPrice))\n .mul(int256(_balance))\n .div(sWEI_PRECISION)\n .add(profitSoFar);\n }\n\n /**\n * @notice Loan token price calculation considering unpaid interests.\n * @return The loan token price.\n * */\n function tokenPrice() public view returns (uint256 price) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _tokenPrice(_totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Get the total amount of loan tokens on debt.\n * Calls protocol getTotalPrincipal function.\n * In the context of borrowing, principal is the initial size of a loan.\n * It can also be the amount still owed on a loan. If you take out a\n * $50,000 mortgage, for example, the principal is $50,000. If you pay off\n * $30,000, the principal balance now consists of the remaining $20,000.\n *\n * @return The total amount of loan tokens on debt.\n * */\n function totalAssetBorrow() public view returns (uint256) {\n return\n ProtocolLike(sovrynContractAddress).getTotalPrincipal(address(this), loanTokenAddress);\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice .\n *\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param withdrawalAmount The amount of tokens to withdraw.\n *\n * @return msgValue The amount of rBTC sent minus the collateral on tokens.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = loanTokenAddress;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n _safeTransfer(_loanTokenAddress, sentAddresses.receiver, withdrawalAmount, \"\");\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n /**\n * This is a critical piece of code!\n * rBTC are supposed to be held by the contract itself, while other tokens are being transfered from the sender directly.\n * */\n if (collateralTokenSent != 0) {\n if (\n collateralTokenAddress == _wrbtcToken &&\n msgValue != 0 &&\n msgValue >= collateralTokenSent\n ) {\n IWrbtc(_wrbtcToken).deposit.value(collateralTokenSent)();\n _safeTransfer(\n collateralTokenAddress,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-a\"\n );\n msgValue -= collateralTokenSent;\n } else {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-b\"\n );\n }\n }\n\n if (loanTokenSent != 0) {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n\n /**\n * @notice Withdraw loan token interests from protocol.\n * This function only operates once per block.\n * It asks protocol to withdraw accrued interests for the loan token.\n *\n * @dev Internal sync required on every loan trade before starting.\n * */\n function _settleInterest() internal {\n uint88 ts = uint88(block.timestamp);\n if (lastSettleTime_ != ts) {\n ProtocolLike(sovrynContractAddress).withdrawAccruedInterest(loanTokenAddress);\n\n lastSettleTime_ = ts;\n }\n }\n\n /**\n * @notice Imitate a Solidity high-level call (i.e. a regular function\n * call to a contract), relaxing the requirement on the return value:\n * the return value is optional (but if data is returned, it must not be\n * false).\n *\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n * @param errorMsg The error message on failure.\n * */\n function _callOptionalReturn(\n address token,\n bytes memory data,\n string memory errorMsg\n ) internal {\n require(Address.isContract(token), \"call to a non-contract address\");\n (bool success, bytes memory returndata) = token.call(data);\n require(success, errorMsg);\n\n if (returndata.length != 0) {\n require(abi.decode(returndata, (bool)), errorMsg);\n }\n }\n\n /**\n * @notice Execute the ERC20 token's `transfer` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransfer(\n address token,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transfer.selector, to, amount),\n errorMsg\n );\n }\n\n /**\n * @notice Execute the ERC20 token's `transferFrom` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param from The source address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransferFrom(\n address token,\n address from,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transferFrom.selector, from, to, amount),\n errorMsg\n );\n }\n\n /** Internal view function */\n /**\n * @notice Compute the token price.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The token price.\n * */\n function _tokenPrice(uint256 assetSupply) internal view returns (uint256) {\n uint256 totalTokenSupply = totalSupply_;\n\n return\n totalTokenSupply != 0 ? assetSupply.mul(10**18).div(totalTokenSupply) : initialPrice;\n }\n\n /**\n * @notice Get two kind of interests: owed per day and yet to be paid.\n * @return interestOwedPerDay The interest per day.\n * @return interestUnPaid The interest not yet paid.\n * */\n function _getAllInterest()\n internal\n view\n returns (uint256 interestOwedPerDay, uint256 interestUnPaid)\n {\n /// interestPaid, interestPaidDate, interestOwedPerDay, interestUnPaid, interestFeePercent, principalTotal\n uint256 interestFeePercent;\n (, , interestOwedPerDay, interestUnPaid, interestFeePercent, ) = ProtocolLike(\n sovrynContractAddress\n )\n .getLenderInterestData(address(this), loanTokenAddress);\n\n interestUnPaid = interestUnPaid.mul(SafeMath.sub(10**20, interestFeePercent)).div(10**20);\n }\n\n /**\n * @notice Compute the total amount of loan tokens on supply.\n * @param interestUnPaid The interest not yet paid.\n * @return assetSupply The total amount of loan tokens on supply.\n * */\n function _totalAssetSupply(uint256 interestUnPaid)\n internal\n view\n returns (uint256 assetSupply)\n {\n if (totalSupply_ != 0) {\n uint256 assetsBalance = _flTotalAssetSupply; /// Temporary locked totalAssetSupply during a flash loan transaction.\n if (assetsBalance == 0) {\n assetsBalance = _underlyingBalance().add(totalAssetBorrow());\n }\n\n return assetsBalance.add(interestUnPaid);\n }\n }\n\n /**\n * @notice Get the loan contract balance.\n * @return The balance of the loan token for this contract.\n * */\n function _underlyingBalance() internal view returns (uint256) {\n return IERC20(loanTokenAddress).balanceOf(address(this));\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicSplit.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\n/**\n * @title Loan Token Logic Standard contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Logic around loan tokens (iTokens) required to operate borrowing,\n * and margin trading financial processes.\n *\n * The user provides funds to the lending pool using the mint function and\n * withdraws funds from the lending pool using the burn function. Mint and\n * burn refer to minting and burning loan tokens. Loan tokens represent a\n * share of the pool and gather interest over time.\n *\n * Interest rates are determined by supply and demand. When a lender deposits\n * funds, the interest rates go down. When a trader borrows funds, the\n * interest rates go up. Fulcrum uses a simple linear interest rate formula\n * of the form y = mx + b. The interest rate starts at 1% when loans aren't\n * being utilized and scales up to 40% when all the funds in the loan pool\n * are being borrowed.\n *\n * The borrow rate is determined at the time of the loan and represents the\n * net contribution of each borrower. Each borrower's interest contribution\n * is determined by the utilization rate of the pool and is netted against\n * all prior borrows. This means that the total amount of interest flowing\n * into the lending pool is not directly changed by lenders entering or\n * exiting the pool. The entrance or exit of lenders only impacts how the\n * interest payments are split up.\n *\n * For example, if there are 2 lenders with equal holdings each earning\n * 5% APR, but one of the lenders leave, then the remaining lender will earn\n * 10% APR since the interest payments don't have to be split between two\n * individuals.\n * */\ncontract LoanTokenLogicSplit is LoanTokenLogicShared {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /* Public functions */\n\n /**\n * @notice Mint loan token wrapper.\n * Adds a check before calling low level _mintToken function.\n * The function retrieves the tokens from the message sender, so make sure\n * to first approve the loan token contract to access your funds. This is\n * done by calling approve(address spender, uint amount) on the ERC20\n * token contract, where spender is the loan token contract address and\n * amount is the amount to be deposited.\n *\n * @param receiver The account getting the minted tokens.\n * @param depositAmount The amount of underlying tokens provided on the\n * loan. (Not the number of loan tokens to mint).\n *\n * @return The amount of loan tokens minted.\n * */\n function mint(address receiver, uint256 depositAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice Burn loan token wrapper.\n * Adds a pay-out transfer after calling low level _burnToken function.\n * In order to withdraw funds to the pool, call burn on the respective\n * loan token contract. This will burn your loan tokens and send you the\n * underlying token in exchange.\n *\n * @param receiver The account getting the minted tokens.\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 loanAmountPaid)\n {\n loanAmountPaid = _burnToken(burnAmount);\n\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (loanAmountPaid != 0) {\n _safeTransfer(loanTokenAddress, receiver, loanAmountPaid, \"5\");\n }\n }\n\n /**\n * @notice transfers the underlying asset from the msg.sender and mints tokens for the receiver\n * @param receiver the address of the iToken receiver\n * @param depositAmount the amount of underlying assets to be deposited\n * @return the amount of iTokens issued\n */\n function _mintToken(address receiver, uint256 depositAmount)\n internal\n returns (uint256 mintAmount)\n {\n uint256 currentPrice;\n\n //calculate amount to mint and transfer the underlying asset\n (mintAmount, currentPrice) = _prepareMinting(depositAmount);\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n receiver\n );\n uint256 oldBalance = balances[receiver].add(balanceOnLM);\n uint256 newBalance = oldBalance.add(mintAmount);\n\n //mint the tokens to the receiver\n _mint(receiver, mintAmount, depositAmount, currentPrice);\n\n //update the checkpoint of the receiver\n _updateCheckpoints(receiver, oldBalance, newBalance, currentPrice);\n }\n\n /**\n * calculates the amount of tokens to mint and transfers the underlying asset to this contract\n * @param depositAmount the amount of the underyling asset deposited\n * @return the amount to be minted\n */\n function _prepareMinting(uint256 depositAmount)\n internal\n returns (uint256 mintAmount, uint256 currentPrice)\n {\n require(depositAmount != 0, \"17\");\n\n _settleInterest();\n\n currentPrice = _tokenPrice(_totalAssetSupply(0));\n mintAmount = depositAmount.mul(10**18).div(currentPrice);\n\n if (msg.value == 0) {\n _safeTransferFrom(loanTokenAddress, msg.sender, address(this), depositAmount, \"18\");\n } else {\n IWrbtc(wrbtcTokenAddress).deposit.value(depositAmount)();\n }\n }\n\n /**\n * @notice A wrapper for AdvancedToken::_burn\n *\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function _burnToken(uint256 burnAmount) internal returns (uint256 loanAmountPaid) {\n require(burnAmount != 0, \"19\");\n\n if (burnAmount > balanceOf(msg.sender)) {\n require(burnAmount == uint256(-1), \"32\");\n burnAmount = balanceOf(msg.sender);\n }\n\n _settleInterest();\n\n uint256 currentPrice = _tokenPrice(_totalAssetSupply(0));\n\n uint256 loanAmountOwed = burnAmount.mul(currentPrice).div(10**18);\n uint256 loanAmountAvailableInContract = _underlyingBalance();\n\n loanAmountPaid = loanAmountOwed;\n require(loanAmountPaid <= loanAmountAvailableInContract, \"37\");\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n uint256 oldBalance = balances[msg.sender].add(balanceOnLM);\n uint256 newBalance = oldBalance.sub(burnAmount);\n\n _burn(msg.sender, burnAmount, loanAmountPaid, currentPrice);\n\n //this function does not only update the checkpoints but also the current profit of the user\n //all for external use only\n _updateCheckpoints(msg.sender, oldBalance, newBalance, currentPrice);\n }\n\n function _mintWithLM(address receiver, uint256 depositAmount)\n internal\n returns (uint256 minted)\n {\n //mint the tokens for the receiver\n minted = _mintToken(receiver, depositAmount);\n\n //transfer the tokens from the receiver to the LM address\n _internalTransferFrom(receiver, liquidityMiningAddress, minted, minted);\n\n //inform the LM mining contract\n ILiquidityMining(liquidityMiningAddress).onTokensDeposited(receiver, minted);\n }\n\n function _burnFromLM(uint256 burnAmount) internal returns (uint256) {\n uint256 balanceOnLM =\n ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n require(balanceOnLM.add(balanceOf(msg.sender)) >= burnAmount, \"not enough balance\");\n\n if (balanceOnLM > 0) {\n //withdraw pool tokens and LM rewards to the passed address\n if (balanceOnLM < burnAmount) {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n balanceOnLM,\n msg.sender\n );\n } else {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n burnAmount,\n msg.sender\n );\n }\n }\n //burn the tokens of the msg.sender\n return _burnToken(burnAmount);\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStandard.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\ncontract LoanTokenLogicStandard is LoanTokenLogicShared {\n /**\n * @notice Transfer tokens wrapper.\n * Sets token owner the msg.sender.\n * Sets maximun allowance uint256(-1) to ensure tokens are always transferred.\n *\n * If the recipient (_to) is a vesting contract address, transfer the token to the tokenOwner of the vesting contract itself.\n *\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @return Success true/false.\n * */\n function transfer(address _to, uint256 _value) external returns (bool) {\n /** need additional check address(0) here to support backward compatibility\n * in case we don't want to activate this check, just need to set the stakingContractAddress to 0 address\n */\n if (\n stakingContractAddress != address(0) &&\n IStaking(stakingContractAddress).isVestingContract(_to)\n ) {\n (bool success, bytes memory data) =\n _to.staticcall(abi.encodeWithSelector(IVesting(_to).tokenOwner.selector));\n\n if (success) _to = abi.decode(data, (address));\n }\n\n return _internalTransferFrom(msg.sender, _to, _value, uint256(-1));\n }\n\n /**\n * @notice Moves `_value` loan tokens from `_from` to `_to` using the\n * allowance mechanism. Calls internal _internalTransferFrom function.\n *\n * @return A boolean value indicating whether the operation succeeded.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool) {\n return\n _internalTransferFrom(\n _from,\n _to,\n _value,\n //allowed[_from][msg.sender]\n ProtocolLike(sovrynContractAddress).isLoanPool(msg.sender)\n ? uint256(-1)\n : allowed[_from][msg.sender]\n );\n }\n\n /**\n * @notice Borrow funds from the pool.\n * The underlying loan token may not be used as collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * (150% of the withdrawn amount worth in collateral tokens).\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param borrower The one paying for the collateral.\n * @param receiver The one receiving the withdrawn amount.\n *\n * @return New principal and new collateral added to loan.\n * */\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes memory /// loanDataBytes: arbitrary order data (for future use).\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n )\n {\n require(withdrawAmount != 0, \"6\");\n\n _checkPause();\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n\n require(\n (msg.value == 0 || msg.value == collateralTokenSent) &&\n (collateralTokenSent != 0 || loanId != 0) &&\n (collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0) &&\n (loanId == 0 || msg.sender == borrower),\n \"7\"\n );\n\n /// @dev We have an issue regarding contract size code is too big. 1 of the solution is need to keep the error message 32 bytes length\n // Temporarily, we combine this require to the above, so can save the contract size code\n // require(collateralTokenSent != 0 || loanId != 0, \"8\");\n // require(collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0, \"9\");\n\n /// @dev Ensure authorized use of existing loan.\n // require(loanId == 0 || msg.sender == borrower, \"401 use of existing loan\");\n\n /// @dev The condition is never met.\n /// Address zero is not allowed by previous require validation.\n /// This check is unneeded and was lowering the test coverage index.\n // if (collateralTokenAddress == address(0)) {\n // \tcollateralTokenAddress = wrbtcTokenAddress;\n // }\n\n require(collateralTokenAddress != loanTokenAddress, \"10\");\n\n _settleInterest();\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this); /// The lender.\n sentAddresses.borrower = borrower;\n sentAddresses.receiver = receiver;\n /// sentAddresses.manager = address(0); /// The manager.\n\n sentAmounts.newPrincipal = withdrawAmount;\n\n /// interestRate, interestInitialAmount, borrowAmount (newBorrowAmount).\n (\n sentAmounts.interestRate,\n sentAmounts.interestInitialAmount,\n sentAmounts.newPrincipal\n ) = _getInterestRateAndBorrowAmount(\n sentAmounts.newPrincipal,\n _totalAssetSupply(0), /// Interest is settled above.\n initialLoanDuration\n );\n\n /// sentAmounts.loanTokenSent = 0; /// loanTokenSent\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n return\n _borrowOrTrade(\n loanId,\n withdrawAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ]\n ),\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Borrow and immediately get into a position.\n *\n * Trading on margin is used to increase an investor's buying power.\n * Margin is the amount of money required to open a position, while\n * leverage is the multiple of exposure to account equity.\n *\n * Leverage allows you to trade positions LARGER than the amount\n * of money in your trading account. Leverage is expressed as a ratio.\n *\n * When trading on margin, investors first deposit some token that then\n * serves as collateral for the loan, and then pay ongoing interest\n * payments on the money they borrow.\n *\n * Margin trading = taking a loan and swapping it:\n * In order to open a margin trade position,\n * 1.- The user calls marginTrade on the loan token contract.\n * 2.- The loan token contract provides the loan and sends it for processing\n * to the protocol proxy contract.\n * 3.- The protocol proxy contract uses the module LoanOpening to create a\n * position and swaps the loan tokens to collateral tokens.\n * 4.- The Sovryn Swap network looks up the correct converter and swaps the\n * tokens.\n * If successful, the position is being held by the protocol proxy contract,\n * which is why positions need to be closed at the protocol proxy contract.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n * */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // value of loan token in collateral\n bytes memory loanDataBytes /// Arbitrary order data.\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n _checkPause();\n\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n require(collateralTokenAddress != loanTokenAddress, \"11\");\n\n /// @dev Ensure authorized use of existing loan.\n require(loanId == 0 || msg.sender == trader, \"401 use of existing loan\");\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n if (transactionLimit[loanTokenAddress] > 0)\n require(loanTokenSent <= transactionLimit[loanTokenAddress]);\n\n /// @dev Compute the worth of the total deposit in loan tokens.\n /// (loanTokenSent + convert(collateralTokenSent))\n /// No actual swap happening here.\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n require(totalDeposit != 0, \"12\");\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this);\n sentAddresses.borrower = trader;\n sentAddresses.receiver = trader;\n /// sentAddresses.manager = address(0); /// The manager.\n\n /// sentAmounts.interestRate = 0; /// interestRate (found later).\n sentAmounts.newPrincipal = totalDeposit;\n /// sentAmounts.interestInitialAmount = 0; /// interestInitialAmount (interest is calculated based on fixed-term loan).\n sentAmounts.loanTokenSent = loanTokenSent;\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n _settleInterest();\n\n (sentAmounts.newPrincipal, sentAmounts.interestRate) = _getMarginBorrowAmountAndRate( /// borrowAmount, interestRate\n leverageAmount,\n sentAmounts.newPrincipal /// depositAmount\n );\n\n require(\n _getAmountInRbtc(loanTokenAddress, sentAmounts.newPrincipal) > TINY_AMOUNT,\n \"principal too small\"\n );\n\n /// @dev Converting to initialMargin\n leverageAmount = SafeMath.div(10**38, leverageAmount);\n sentAmounts.minEntryPrice = minEntryPrice;\n return\n _borrowOrTrade(\n loanId,\n 0, /// withdrawAmount\n leverageAmount, //initial margin\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n );\n }\n\n /**\n * @notice Wrapper for marginTrade invoking setAffiliatesReferrer to track\n * referral trade by affiliates program.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param affiliateReferrer The address of the referrer from affiliates program.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n */\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, /// Value of loan token in collateral\n address affiliateReferrer, /// The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n if (affiliateReferrer != address(0))\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(\n trader,\n affiliateReferrer\n );\n return\n marginTrade(\n loanId,\n leverageAmount,\n loanTokenSent,\n collateralTokenSent,\n collateralTokenAddress,\n trader,\n minEntryPrice,\n loanDataBytes\n );\n }\n\n /* Public View functions */\n\n /**\n * @notice Wrapper for internal _profitOf low level function.\n * @param user The user address.\n * @return The profit of a user.\n * */\n function profitOf(address user) external view returns (int256) {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(user, iToken_ProfitSoFar));\n //TODO + LM balance\n return _profitOf(slot, balances[user], tokenPrice(), checkpointPrices_[user]);\n }\n\n /**\n * @notice Getter for the price checkpoint mapping.\n * @param _user The user account as the mapping index.\n * @return The price on the checkpoint for this user.\n * */\n function checkpointPrice(address _user) public view returns (uint256 price) {\n return checkpointPrices_[_user];\n }\n\n /**\n * @notice Get current liquidity.\n * A part of total funds supplied are borrowed. Liquidity = supply - borrow\n * @return The market liquidity.\n * */\n function marketLiquidity() public view returns (uint256) {\n uint256 totalSupply = _totalAssetSupply(0);\n uint256 totalBorrow = totalAssetBorrow();\n if (totalSupply > totalBorrow) {\n return totalSupply - totalBorrow;\n }\n }\n\n /**\n * @notice Wrapper for average borrow interest.\n * @return The average borrow interest.\n * */\n function avgBorrowInterestRate() public view returns (uint256) {\n return _avgBorrowInterestRate(totalAssetBorrow());\n }\n\n /**\n * @notice Get borrow interest rate.\n * The minimum rate the next base protocol borrower will receive\n * for variable-rate loans.\n * @return The borrow interest rate.\n * */\n function borrowInterestRate() public view returns (uint256) {\n return _nextBorrowInterestRate(0);\n }\n\n /**\n * @notice Public wrapper for internal call.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest rate.\n * */\n function nextBorrowInterestRate(uint256 borrowAmount) public view returns (uint256) {\n return _nextBorrowInterestRate(borrowAmount);\n }\n\n /**\n * @notice Get interest rate.\n *\n * @return Interest that lenders are currently receiving when supplying to\n * the pool.\n * */\n function supplyInterestRate() public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0));\n }\n\n /**\n * @notice Get interest rate w/ added supply.\n * @param supplyAmount The amount of tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of tokens to the pool.\n * */\n function nextSupplyInterestRate(uint256 supplyAmount) public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0).add(supplyAmount));\n }\n\n /**\n * @notice Get interest rate w/ added supply assets.\n * @param assetSupply The amount of loan tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of loan tokens to the pool.\n * */\n function totalSupplyInterestRate(uint256 assetSupply) public view returns (uint256) {\n uint256 assetBorrow = totalAssetBorrow();\n if (assetBorrow != 0) {\n return calculateSupplyInterestRate(assetBorrow, assetSupply);\n }\n }\n\n /**\n * @notice Get the total amount of loan tokens on supply.\n * @dev Wrapper for internal _totalAssetSupply function.\n * @return The total amount of loan tokens on supply.\n * */\n function totalAssetSupply() public view returns (uint256) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _totalAssetSupply(interestUnPaid);\n }\n\n /**\n * @notice Compute the maximum deposit amount under current market conditions.\n * @dev maxEscrowAmount = liquidity * (100 - interestForDuration) / 100\n * @param leverageAmount The chosen multiplier with 18 decimals.\n * */\n function getMaxEscrowAmount(uint256 leverageAmount)\n public\n view\n returns (uint256 maxEscrowAmount)\n {\n /**\n * @dev Mathematical imperfection: depending on liquidity we might be able\n * to borrow more if utilization is below the kink level.\n * */\n uint256 interestForDuration = maxScaleRate.mul(28).div(365);\n uint256 factor = uint256(10**20).sub(interestForDuration);\n uint256 maxLoanSize = marketLiquidity().mul(factor).div(10**20);\n maxEscrowAmount = maxLoanSize.mul(10**18).div(leverageAmount);\n }\n\n /**\n * @notice Get loan token balance.\n * @return The user's balance of underlying token.\n * */\n function assetBalanceOf(address _owner) public view returns (uint256) {\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0)) {\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n _owner\n );\n }\n return balanceOf(_owner).add(balanceOnLM).mul(tokenPrice()).div(10**18);\n }\n\n /**\n * @notice Get margin information on a trade.\n *\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The principal, the collateral and the interestRate.\n * */\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n public\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n )\n {\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n\n (principal, interestRate) = _getMarginBorrowAmountAndRate(leverageAmount, totalDeposit);\n if (principal > _underlyingBalance()) {\n return (0, 0, 0);\n }\n\n loanTokenSent = loanTokenSent.add(principal);\n\n collateral = ProtocolLike(sovrynContractAddress).getEstimatedMarginExposure(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent,\n collateralTokenSent,\n interestRate,\n principal\n );\n }\n\n /**\n * @notice Calculate the deposit required to a given borrow.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param borrowAmount The amount of borrow.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of deposit required.\n * */\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 depositAmount) {\n if (borrowAmount != 0) {\n (, , uint256 newBorrowAmount) =\n _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (newBorrowAmount <= _underlyingBalance()) {\n if (collateralTokenAddress == address(0))\n collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ];\n return\n ProtocolLike(sovrynContractAddress)\n .getRequiredCollateral(\n loanTokenAddress,\n collateralTokenAddress,\n newBorrowAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin\n true /// isTorqueLoan\n )\n .add(10); /// Some dust to compensate for rounding errors.\n }\n }\n }\n\n /**\n * @notice Calculate the borrow allowed for a given deposit.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param depositAmount The amount of deposit.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of borrow allowed.\n * */\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 borrowAmount) {\n if (depositAmount != 0) {\n if (collateralTokenAddress == address(0)) collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))];\n borrowAmount = ProtocolLike(sovrynContractAddress).getBorrowAmount(\n loanTokenAddress,\n collateralTokenAddress,\n depositAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin,\n true /// isTorqueLoan\n );\n\n (, , borrowAmount) = _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (borrowAmount > _underlyingBalance()) {\n borrowAmount = 0;\n }\n }\n }\n\n /**\n * @notice Check if entry price lies above a minimum\n *\n * @param loanTokenSent The amount of deposit.\n * @param collateralTokenAddress The token address of collateral.\n * @param minEntryPrice Value of loan token in collateral\n * */\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) public view {\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokensReceived =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent\n );\n uint256 collateralTokenPrice =\n (collateralTokensReceived.mul(WEI_PRECISION)).div(loanTokenSent);\n require(collateralTokenPrice >= minEntryPrice, \"entry price above the minimum\");\n }\n\n /**\n * @notice Compute the next supply interest adjustment.\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next supply interest adjustment.\n * */\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n public\n view\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply >= assetBorrow) {\n return\n _avgBorrowInterestRate(assetBorrow)\n .mul(_utilizationRate(assetBorrow, assetSupply))\n .mul(\n SafeMath.sub(10**20, ProtocolLike(sovrynContractAddress).lendingFeePercent())\n )\n .div(10**40);\n }\n }\n\n /* Internal functions */\n\n /**\n * @notice Compute what the deposit is worth in loan tokens using the swap rate\n * used for loan size computation.\n *\n * @param collateralTokenAddress The token address of the collateral.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param loanTokenSent The number of loan tokens provided by the user.\n *\n * @return The value of the deposit in loan tokens.\n * */\n function _totalDeposit(\n address collateralTokenAddress,\n uint256 collateralTokenSent,\n uint256 loanTokenSent\n ) internal view returns (uint256 totalDeposit) {\n totalDeposit = loanTokenSent;\n\n if (collateralTokenSent != 0) {\n /// @dev Get the oracle rate from collateral -> loan\n (uint256 collateralToLoanRate, uint256 collateralToLoanPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n collateralTokenAddress,\n loanTokenAddress\n );\n require(\n (collateralToLoanRate != 0) && (collateralToLoanPrecision != 0),\n \"invalid rate collateral token\"\n );\n\n /// @dev Compute the loan token amount with the oracle rate.\n uint256 loanTokenAmount =\n collateralTokenSent.mul(collateralToLoanRate).div(collateralToLoanPrecision);\n\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokenAmount =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenAmount\n );\n\n /// @dev Probably not the same due to the price difference.\n if (collateralTokenAmount != collateralTokenSent) {\n //scale the loan token amount accordingly, so we'll get the expected position size in the end\n loanTokenAmount = loanTokenAmount.mul(collateralTokenAmount).div(\n collateralTokenSent\n );\n }\n\n totalDeposit = loanTokenAmount.add(totalDeposit);\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n asset,\n wrbtcTokenAddress\n );\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /*\n * @notice Compute interest rate and other loan parameters.\n *\n * @param borrowAmount The amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n *\n * @return The interest rate, the interest calculated based on fixed-term\n * loan, and the new borrow amount.\n * */\n function _getInterestRateAndBorrowAmount(\n uint256 borrowAmount,\n uint256 assetSupply,\n uint256 initialLoanDuration /// Duration in seconds.\n )\n internal\n view\n returns (\n uint256 interestRate,\n uint256 interestInitialAmount,\n uint256 newBorrowAmount\n )\n {\n interestRate = _nextBorrowInterestRate2(borrowAmount, assetSupply);\n\n /// newBorrowAmount = borrowAmount * 10^18 / (10^18 - interestRate * 7884000 * 10^18 / 31536000 / 10^20)\n newBorrowAmount = borrowAmount.mul(10**18).div(\n SafeMath.sub(\n 10**18,\n interestRate.mul(initialLoanDuration).mul(10**18).div(31536000 * 10**20) /// 365 * 86400 * 10**20\n )\n );\n\n interestInitialAmount = newBorrowAmount.sub(borrowAmount);\n }\n\n /**\n * @notice Compute principal and collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialMargin The initial margin with 18 decimals\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return The new principal and the new collateral. Principal is the\n * complete borrowed amount (in loan tokens). Collateral is the complete\n * position size (loan + margin) (in collateral tokens).\n * */\n function _borrowOrTrade(\n bytes32 loanId,\n uint256 withdrawAmount,\n uint256 initialMargin,\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n _checkPause();\n require(\n sentAmounts.newPrincipal <= _underlyingBalance() && /// newPrincipal (borrowed amount + fees)\n sentAddresses.borrower != address(0), /// The borrower.\n \"24\"\n );\n\n if (sentAddresses.receiver == address(0)) {\n sentAddresses.receiver = sentAddresses.borrower; /// The receiver = the borrower.\n }\n\n /// @dev Handle transfers prior to adding newPrincipal to loanTokenSent\n uint256 msgValue =\n _verifyTransfers(collateralTokenAddress, sentAddresses, sentAmounts, withdrawAmount);\n\n /**\n * @dev Adding the loan token portion from the lender to loanTokenSent\n * (add the loan to the loan tokens sent from the user).\n * */\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.add(sentAmounts.newPrincipal); /// newPrincipal\n\n if (withdrawAmount != 0) {\n /// @dev withdrawAmount already sent to the borrower, so we aren't sending it to the protocol.\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.sub(withdrawAmount);\n }\n\n bool withdrawAmountExist = false; /// Default is false, but added just as to make sure.\n\n if (withdrawAmount != 0) {\n withdrawAmountExist = true;\n }\n\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, withdrawAmountExist)))\n ];\n\n (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent) = ProtocolLike(\n sovrynContractAddress\n )\n .borrowOrTradeFromPool\n .value(msgValue)(\n loanParamsId,\n loanId,\n withdrawAmountExist,\n initialMargin,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n ); /// newPrincipal, newCollateral\n require(sentAmounts.newPrincipal != 0, \"25\");\n\n /// @dev Setting not-first-trade flag to prevent binding to an affiliate existing users post factum.\n /// @dev REFACTOR: move to a general interface: ProtocolSettingsLike?\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(\n sentAddresses.borrower\n );\n\n return (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent); // newPrincipal, newCollateral\n }\n\n /* Internal View functions */\n\n /**\n * @notice Compute the average borrow interest rate.\n * @param assetBorrow The amount of loan tokens on debt.\n * @return The average borrow interest rate.\n * */\n function _avgBorrowInterestRate(uint256 assetBorrow) internal view returns (uint256) {\n if (assetBorrow != 0) {\n (uint256 interestOwedPerDay, ) = _getAllInterest();\n return interestOwedPerDay.mul(10**20).mul(365).div(assetBorrow);\n }\n }\n\n /**\n * @notice Compute the next borrow interest adjustment.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate(uint256 borrowAmount) internal view returns (uint256) {\n uint256 interestUnPaid;\n if (borrowAmount != 0) {\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n uint256 balance = _underlyingBalance().add(interestUnPaid);\n if (borrowAmount > balance) {\n borrowAmount = balance;\n }\n }\n\n return _nextBorrowInterestRate2(borrowAmount, _totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Compute the next borrow interest adjustment under target-kink\n * level analysis.\n *\n * The \"kink\" in the cDAI interest rate model reflects the utilization rate\n * at which the slope of the interest rate goes from \"gradual\" to \"steep\".\n * That is, below this utilization rate, the slope of the interest rate\n * curve is gradual. Above this utilization rate, it is steep.\n *\n * Because of this dynamic between the interest rate curves before and\n * after the \"kink\", the \"kink\" can be thought of as the target utilization\n * rate. Above that rate, it quickly becomes expensive to borrow (and\n * commensurately lucrative for suppliers).\n *\n * @param newBorrowAmount The new amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate2(uint256 newBorrowAmount, uint256 assetSupply)\n internal\n view\n returns (uint256 nextRate)\n {\n uint256 utilRate = _utilizationRate(totalAssetBorrow().add(newBorrowAmount), assetSupply);\n\n uint256 thisMinRate;\n uint256 thisRateAtKink;\n uint256 thisBaseRate = baseRate;\n uint256 thisRateMultiplier = rateMultiplier;\n uint256 thisTargetLevel = targetLevel;\n uint256 thisKinkLevel = kinkLevel;\n uint256 thisMaxScaleRate = maxScaleRate;\n\n if (utilRate < thisTargetLevel) {\n // target targetLevel utilization when utilization is under targetLevel\n utilRate = thisTargetLevel;\n }\n\n if (utilRate > thisKinkLevel) {\n /// @dev Scale rate proportionally up to 100%\n uint256 thisMaxRange = WEI_PERCENT_PRECISION - thisKinkLevel; /// Will not overflow.\n\n utilRate -= thisKinkLevel;\n if (utilRate > thisMaxRange) utilRate = thisMaxRange;\n\n // Modified the rate calculation as it is slightly exaggerated around kink level\n // thisRateAtKink = thisRateMultiplier.add(thisBaseRate).mul(thisKinkLevel).div(WEI_PERCENT_PRECISION);\n thisRateAtKink = thisKinkLevel.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n nextRate = utilRate\n .mul(SafeMath.sub(thisMaxScaleRate, thisRateAtKink))\n .div(thisMaxRange)\n .add(thisRateAtKink);\n } else {\n nextRate = utilRate.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n thisMinRate = thisBaseRate;\n thisRateAtKink = thisRateMultiplier.add(thisBaseRate);\n\n if (nextRate < thisMinRate) nextRate = thisMinRate;\n else if (nextRate > thisRateAtKink) nextRate = thisRateAtKink;\n }\n }\n\n /**\n * @notice Compute the loan size and interest rate.\n * @param leverageAmount The leverage with 18 decimals.\n * @param depositAmount The amount the user deposited in underlying loan tokens.\n * @return borrowAmount The amount of tokens to borrow.\n * @return interestRate The interest rate to pay on the position.\n * */\n function _getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n internal\n view\n returns (uint256 borrowAmount, uint256 interestRate)\n {\n uint256 loanSizeBeforeInterest = depositAmount.mul(leverageAmount).div(10**18);\n /**\n * @dev Mathematical imperfection. we calculate the interest rate based on\n * the loanSizeBeforeInterest, but the actual borrowed amount will be bigger.\n * */\n interestRate = _nextBorrowInterestRate2(loanSizeBeforeInterest, _totalAssetSupply(0));\n /// @dev Assumes that loan, collateral, and interest token are the same.\n borrowAmount = _adjustLoanSize(interestRate, 28 days, loanSizeBeforeInterest);\n }\n\n /**\n * @notice Make sure call is not paused.\n * @dev Used for internal verification if the called function is paused.\n * It throws an exception in case it's not.\n * */\n function _checkPause() internal view {\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n msg.sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n bool isPaused;\n assembly {\n isPaused := sload(slot)\n }\n require(!isPaused, \"unauthorized\");\n }\n\n /**\n * @notice Adjusts the loan size to make sure the expected exposure remains after prepaying the interest.\n * @dev loanSizeWithInterest = loanSizeBeforeInterest * 100 / (100 - interestForDuration)\n * @param interestRate The interest rate to pay on the position.\n * @param maxDuration The maximum duration of the position (until rollover).\n * @param loanSizeBeforeInterest The loan size before interest is added.\n * */\n function _adjustLoanSize(\n uint256 interestRate,\n uint256 maxDuration,\n uint256 loanSizeBeforeInterest\n ) internal pure returns (uint256 loanSizeWithInterest) {\n uint256 interestForDuration = interestRate.mul(maxDuration).div(365 days);\n uint256 divisor = uint256(10**20).sub(interestForDuration);\n loanSizeWithInterest = loanSizeBeforeInterest.mul(10**20).div(divisor);\n }\n\n /**\n * @notice Calculate the utilization rate.\n * @dev Utilization rate = assetBorrow / assetSupply\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The utilization rate.\n * */\n function _utilizationRate(uint256 assetBorrow, uint256 assetSupply)\n internal\n pure\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply != 0) {\n /// U = total_borrow / total_supply\n return assetBorrow.mul(10**20).div(assetSupply);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./AdvancedToken.sol\";\n\ncontract LoanTokenLogicStorage is AdvancedToken {\n /// DO NOT ADD VARIABLES HERE - SEE BELOW\n\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /// @dev Add new variables here on the bottom.\n address public earlyAccessToken; //not used anymore, but staying for upgradability\n address public pauser;\n /** The address of the liquidity mining contract */\n address public liquidityMiningAddress;\n\n /** The address of the staking contract */\n address public stakingContractAddress;\n\n /// @dev Used by flashBorrow function.\n uint256 public constant VERSION = 6;\n /// @dev Used by flashBorrow function.\n address internal constant arbitraryCaller = 0x000F400e6818158D541C3EBE45FE3AA0d47372FF;\n bytes32 internal constant iToken_ProfitSoFar =\n 0x37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb6; // keccak256(\"iToken_ProfitSoFar\")\n uint256 public constant TINY_AMOUNT = 25e13;\n\n function stringToBytes32(string memory source) public pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"unauthorized\"); // SS02\n _;\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogic is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenMintAndBurn also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenLogicStandard also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\")); /// LoanTokenLogicStandard\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\")); /// LoanTokenLogicLM\n res[2] = bytes4(keccak256(\"burn(address,uint256)\")); /// LoanTokenLogicStandard\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\")); /// LoanTokenLogicLM\n\n return (res, stringToBytes32(\"LoanTokenLogicLM\"));\n }\n\n /**\n * @notice deposit into the lending pool and optionally participate at the Liquidity Mining Program\n * @param receiver the receiver of the tokens\n * @param depositAmount The amount of underlying tokens provided on the loan.\n *\t\t\t\t\t\t(Not the number of loan tokens to mint).\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 minted) {\n if (useLM) return _mintWithLM(receiver, depositAmount);\n else return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice withdraws from the lending pool and optionally retrieves the pool tokens from the\n * Liquidity Mining Contract\n * @param receiver the receiver of the underlying tokens. note: potetial LM rewards are always sent to the msg.sender\n * @param burnAmount The amount of pool tokens to redeem.\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 redeemed) {\n if (useLM) redeemed = _burnFromLM(burnAmount);\n else redeemed = _burnToken(burnAmount);\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (redeemed != 0) {\n _safeTransfer(loanTokenAddress, receiver, redeemed, \"asset transfer failed\");\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtc.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogicWrbtc is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtc\"));\n }\n\n /**\n * @dev internal override functions\n * @dev Put all of internal override function dedicated to the loanTokenWrtbc module here\n * e.g: _verifyTransfers will override the implementation of _verifyTransfers in loanTokenLogicSplit\n */\n\n /**\n * @notice Handle transfers prior to adding newPrincipal to loanTokenSent.\n *\n * @param collateralTokenAddress The address of the collateral token.\n * @param sentAddresses The struct which contains addresses of\n * - lender\n * - borrower\n * - receiver\n * - manager\n *\n * @param sentAmounts The struct which contains uint256 of:\n * - interestRate\n * - newPrincipal\n * - interestInitialAmount\n * - loanTokenSent\n * - collateralTokenSent\n *\n * @param withdrawalAmount The amount to withdraw.\n *\n * @return msgValue The amount of value sent.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = _wrbtcToken;\n address receiver = sentAddresses.receiver;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n IWrbtcERC20(_wrbtcToken).withdraw(withdrawalAmount);\n Address.sendValue(receiver, withdrawalAmount);\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n\n if (collateralTokenSent != 0) {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28\"\n );\n }\n\n if (loanTokenSent != 0) {\n if (msgValue != 0 && msgValue >= loanTokenSent) {\n IWrbtc(_wrbtcToken).deposit.value(loanTokenSent)();\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, loanTokenSent, \"29\");\n msgValue -= loanTokenSent;\n } else {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtcLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicWrbtcLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token Mint and Burn.\n res[0] = this.mint.selector;\n res[1] = this.burn.selector;\n\n // Loan Token WRBTC\n res[2] = this.mintWithBTC.selector;\n res[3] = this.burnToBTC.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtcLM\"));\n }\n\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n if (useLM) return _mintWithLM(receiver, msg.value);\n else return _mintToken(receiver, msg.value);\n }\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 loanAmountPaid) {\n loanAmountPaid = useLM ? _burnFromLM(burnAmount) : _burnToken(burnAmount);\n\n if (loanAmountPaid != 0) {\n IWrbtcERC20(wrbtcTokenAddress).withdraw(loanAmountPaid);\n Address.sendValue(receiver, loanAmountPaid);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/shared/LoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../AdvancedToken.sol\";\nimport \"../../interfaces/ProtocolSettingsLike.sol\";\nimport \"../../LoanTokenLogicStorage.sol\";\n\ncontract LoanTokenSettingsLowerAdmin is LoanTokenLogicStorage {\n using SafeMath for uint256;\n\n /// @dev TODO: Check for restrictions in this contract.\n modifier onlyAdmin() {\n require(isOwner() || msg.sender == admin, \"unauthorized\");\n _;\n }\n\n /* Events */\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](15);\n res[0] = this.setAdmin.selector;\n res[1] = this.setPauser.selector;\n res[2] = this.setupLoanParams.selector;\n res[3] = this.disableLoanParams.selector;\n res[4] = this.setDemandCurve.selector;\n res[5] = this.toggleFunctionPause.selector;\n res[6] = this.setTransactionLimits.selector;\n res[7] = this.changeLoanTokenNameAndSymbol.selector;\n res[8] = this.pauser.selector;\n res[9] = this.setLiquidityMiningAddress.selector;\n res[10] = this.withdrawRBTCTo.selector;\n res[11] = this.getLiquidityMiningAddress.selector;\n res[12] = this.checkPause.selector;\n res[13] = this.setStakingContractAddress.selector;\n res[14] = this.getStakingContractAddress.selector;\n return (res, stringToBytes32(\"LoanTokenSettingsLowerAdmin\"));\n }\n\n /**\n * @notice Set admin account.\n * @param _admin The address of the account to grant admin permissions.\n * */\n function setAdmin(address _admin) public onlyOwner {\n admin = _admin;\n }\n\n /**\n * @notice Set pauser account.\n * @param _pauser The address of the account to grant pause permissions.\n * */\n function setPauser(address _pauser) public onlyOwner {\n pauser = _pauser;\n }\n\n /**\n * @notice Fallback function not allowed\n * */\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n /**\n * @notice Set loan token parameters.\n *\n * @param loanParamsList The array of loan parameters.\n * @param areTorqueLoans Whether the loan is a torque loan.\n * */\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans /// isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n /**\n * @notice Disable loan token parameters.\n *\n * @param collateralTokens The array of collateral tokens.\n * @param isTorqueLoans Whether the loan is a torque loan.\n * */\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n /**\n * @notice Set loan token parameters about the demand curve.\n *\n * @dev These params should be percentages represented\n * like so: 5% = 5000000000000000000 /// 18 digits precision.\n * rateMultiplier + baseRate can't exceed 100%\n *\n * To maintain a healthy credit score, it's important to keep your\n * credit utilization rate (CUR) low (_lowUtilBaseRate). In general\n * you don't want your CUR to exceed 30%, but increasingly financial\n * experts are recommending that you don't want to go above 10% if you\n * really want an excellent credit score.\n *\n * Interest rates tend to cluster around the kink level of a kinked\n * interest rate model. More info at https://arxiv.org/pdf/2006.13922.pdf\n * and https://compound.finance/governance/proposals/12\n *\n * @param _baseRate The interest rate.\n * @param _rateMultiplier The precision multiplier for base rate.\n * @param _lowUtilBaseRate The credit utilization rate (CUR) low value.\n * @param _lowUtilRateMultiplier The precision multiplier for low util base rate.\n * @param _targetLevel The target level.\n * @param _kinkLevel The level that interest rates cluster on kinked model.\n * @param _maxScaleRate The maximum rate of the scale.\n * */\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; /// 80 ether\n kinkLevel = _kinkLevel; /// 90 ether\n maxScaleRate = _maxScaleRate; /// 100 ether\n }\n\n /**\n * @notice Set the pause flag for a function to true or false.\n *\n * @dev Combining the hash of \"iToken_FunctionPause\" string and a function\n * selector gets a slot to write a flag for pause state.\n *\n * @param funcId The ID of a function, the selector.\n * @param isPaused true/false value of the flag.\n * */\n function toggleFunctionPause(\n string memory funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyPauserOrOwner {\n bool paused;\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n paused := sload(slot)\n }\n require(paused != isPaused, \"isPaused is already set to that value\");\n assembly {\n sstore(slot, isPaused)\n }\n emit ToggledFunctionPaused(funcId, !isPaused, isPaused);\n }\n\n /**\n * Set the transaction limit per token address.\n * @param addresses The token addresses.\n * @param limits The limit denominated in the currency of the token address.\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyAdmin\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n\n /**\n *\t@notice Update the loan token parameters.\n *\t@param _name The new name of the loan token.\n *\t@param _symbol The new symbol of the loan token.\n * */\n function changeLoanTokenNameAndSymbol(string memory _name, string memory _symbol)\n public\n onlyAdmin\n {\n name = _name;\n symbol = _symbol;\n }\n\n /**\n * @notice Withdraws RBTC from the contract by Multisig.\n * @param _receiverAddress The address where the rBTC has to be transferred.\n * @param _amount The amount of rBTC to be transferred.\n */\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external onlyOwner {\n require(_receiverAddress != address(0), \"receiver address invalid\");\n require(_amount > 0, \"non-zero withdraw amount expected\");\n require(_amount <= address(this).balance, \"withdraw amount cannot exceed balance\");\n _receiverAddress.transfer(_amount);\n emit WithdrawRBTCTo(_receiverAddress, _amount);\n }\n\n /**\n * @notice sets the liquidity mining contract address\n * @param LMAddress the address of the liquidity mining contract\n */\n function setLiquidityMiningAddress(address LMAddress) external onlyOwner {\n liquidityMiningAddress = LMAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for liquidityMiningAddress\n\n\t * @return liquidityMiningAddress\n\t */\n function getLiquidityMiningAddress() public view returns (address) {\n return liquidityMiningAddress;\n }\n\n /**\n * @notice sets the staking contract address\n * @param _stakingContractAddress the address of the staking contract\n */\n function setStakingContractAddress(address _stakingContractAddress) external onlyOwner {\n stakingContractAddress = _stakingContractAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for stakingContractAddress\n\n\t * @return stakingContractAddress\n\t */\n function getStakingContractAddress() public view returns (address) {\n return stakingContractAddress;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param funcId The function ID, the selector.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function checkPause(string memory funcId) public view returns (bool isPaused) {\n bytes4 sig = bytes4(keccak256(abi.encodePacked(funcId)));\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n isPaused := sload(slot)\n }\n return isPaused;\n }\n}\n" + }, + "contracts/connectors/loantoken/Pausable.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Pausable contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * The contract implements pausable functionality by reading on slots the\n * pause state of contract functions.\n * */\ncontract Pausable {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 internal constant Pausable_FunctionPause =\n 0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047;\n\n modifier pausable(bytes4 sig) {\n require(!_isPaused(sig), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param sig The function ID, the selector on bytes4.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function _isPaused(bytes4 sig) internal view returns (bool isPaused) {\n bytes32 slot = keccak256(abi.encodePacked(sig, Pausable_FunctionPause));\n assembly {\n isPaused := sload(slot)\n }\n }\n}\n" + }, + "contracts/core/Objects.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./objects/LoanStruct.sol\";\nimport \"./objects/LoanParamsStruct.sol\";\nimport \"./objects/OrderStruct.sol\";\nimport \"./objects/LenderInterestStruct.sol\";\nimport \"./objects/LoanInterestStruct.sol\";\n\n/**\n * @title Objects contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract inherints and aggregates several structures needed to handle\n * loans on the protocol.\n * */\ncontract Objects is\n LoanStruct,\n LoanParamsStruct,\n OrderStruct,\n LenderInterestStruct,\n LoanInterestStruct\n{\n\n}\n" + }, + "contracts/core/objects/LenderInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Lender Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Lender Interest.\n * */\ncontract LenderInterestStruct {\n struct LenderInterest {\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\n uint256 paidTotal; /// Total interest paid so far for asset.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Interest.\n * */\ncontract LoanInterestStruct {\n struct LoanInterest {\n uint256 owedPerDay; /// Interest owed per day for loan.\n uint256 depositTotal; /// Total escrowed interest for loan.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanParamsStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Parameters.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Parameters.\n * */\ncontract LoanParamsStruct {\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n}\n" + }, + "contracts/core/objects/LoanStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Object.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Object.\n * */\ncontract LoanStruct {\n struct Loan {\n bytes32 id; /// ID of the loan.\n bytes32 loanParamsId; /// The linked loan params ID.\n bytes32 pendingTradesId; /// The linked pending trades ID.\n bool active; /// If false, the loan has been fully closed.\n uint256 principal; /// Total borrowed amount outstanding.\n uint256 collateral; /// Total collateral escrowed for the loan.\n uint256 startTimestamp; /// Loan start time.\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\n uint256 startMargin; /// Initial margin when the loan opened.\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\n address borrower; /// Borrower of this loan.\n address lender; /// Lender of this loan.\n }\n}\n" + }, + "contracts/core/objects/OrderStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Order.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Order.\n * */\ncontract OrderStruct {\n struct Order {\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\n uint256 interestRate; /// Interest rate defined by the creator of this order.\n uint256 minLoanTerm; /// Minimum loan term allowed.\n uint256 maxLoanTerm; /// Maximum loan term allowed.\n uint256 createdTimestamp; /// Timestamp when this order was created.\n uint256 expirationTimestamp; /// Timestamp when this order expires.\n }\n}\n" + }, + "contracts/core/Protocol.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./State.sol\";\n\n/**\n * @title Sovryn Protocol contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the proxy functionality to deploy Protocol anchor\n * and logic apart, turning it upgradable.\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822\n * */\ncontract sovrynProtocol is State {\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = logicTargets[msg.sig];\n require(target != address(0), \"target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice External owner target initializer.\n * @param target The target addresses.\n * */\n function replaceContract(address target) external onlyOwner {\n (bool success, ) =\n target.delegatecall(abi.encodeWithSignature(\"initialize(address)\", target));\n require(success, \"setup failed\");\n }\n\n /**\n * @notice External owner setter for target addresses.\n * @param sigsArr The array of signatures.\n * @param targetsArr The array of addresses.\n * */\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr)\n external\n onlyOwner\n {\n require(sigsArr.length == targetsArr.length, \"count mismatch\");\n\n for (uint256 i = 0; i < sigsArr.length; i++) {\n _setTarget(bytes4(keccak256(abi.encodePacked(sigsArr[i]))), targetsArr[i]);\n }\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(string calldata sig) external view returns (address) {\n return logicTargets[bytes4(keccak256(abi.encodePacked(sig)))];\n }\n}\n" + }, + "contracts/core/State.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./Objects.sol\";\nimport \"../mixins/EnumerableAddressSet.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/ReentrancyGuard.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title State contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage values of the Protocol.\n * */\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\n using SafeMath for uint256;\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n\n /// Handles asset reference price lookups.\n address public priceFeeds;\n\n /// Handles asset swaps using dex liquidity.\n address public swapsImpl;\n\n /// Contract registry address of the Sovryn swap network.\n address public sovrynSwapContractRegistryAddress;\n\n /// Implementations of protocol functions.\n mapping(bytes4 => address) public logicTargets;\n\n /// Loans: loanId => Loan\n mapping(bytes32 => Loan) public loans;\n\n /// Loan parameters: loanParamsId => LoanParams\n mapping(bytes32 => LoanParams) public loanParams;\n\n /// lender => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\n\n /// borrower => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\n\n /// loanId => delegated => approved\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\n\n /**\n *** Interest ***\n **/\n\n /// lender => loanToken => LenderInterest object\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\n\n /// loanId => LoanInterest object\n mapping(bytes32 => LoanInterest) public loanInterest;\n\n /**\n *** Internals ***\n **/\n\n /// Implementations set.\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\n\n /// Active loans set.\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\n\n /// Lender loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\n\n /// Borrow loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\n\n /// User loan params set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\n\n /// Address controlling fee withdrawals.\n address public feesController;\n\n /// 10% fee /// Fee taken from lender interest payments.\n uint256 public lendingFeePercent = 10**19;\n\n /// Total interest fees received and not withdrawn per asset.\n mapping(address => uint256) public lendingFeeTokensHeld;\n\n /// Total interest fees withdraw per asset.\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\n mapping(address => uint256) public lendingFeeTokensPaid;\n\n /// 0.15% fee /// Fee paid for each trade.\n uint256 public tradingFeePercent = 15 * 10**16;\n\n /// Total trading fees received and not withdrawn per asset.\n mapping(address => uint256) public tradingFeeTokensHeld;\n\n /// Total trading fees withdraw per asset\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\n mapping(address => uint256) public tradingFeeTokensPaid;\n\n /// 0.09% fee /// Origination fee paid for each loan.\n uint256 public borrowingFeePercent = 9 * 10**16;\n\n /// Total borrowing fees received and not withdrawn per asset.\n mapping(address => uint256) public borrowingFeeTokensHeld;\n\n /// Total borrowing fees withdraw per asset.\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\n mapping(address => uint256) public borrowingFeeTokensPaid;\n\n /// Current protocol token deposit balance.\n uint256 public protocolTokenHeld;\n\n /// Lifetime total payout of protocol token.\n uint256 public protocolTokenPaid;\n\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\n uint256 public affiliateFeePercent = 5 * 10**18;\n\n /// 5% collateral discount /// Discount on collateral for liquidators.\n uint256 public liquidationIncentivePercent = 5 * 10**18;\n\n /// loanPool => underlying\n mapping(address => address) public loanPoolToUnderlying;\n\n /// underlying => loanPool\n mapping(address => address) public underlyingToLoanPool;\n\n /// Loan pools set.\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\n\n /// Supported tokens for swaps.\n mapping(address => bool) public supportedTokens;\n\n /// % disagreement between swap rate and reference rate.\n uint256 public maxDisagreement = 5 * 10**18;\n\n /// Used as buffer for swap source amount estimations.\n uint256 public sourceBuffer = 10000;\n\n /// Maximum support swap size in rBTC\n uint256 public maxSwapSize = 50 ether;\n\n /// Nonce per borrower. Used for loan id creation.\n mapping(address => uint256) public borrowerNonce;\n\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\n uint256 public rolloverBaseReward = 16800000000000;\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\n\n IWrbtcERC20 public wrbtcToken;\n address public protocolTokenAddress;\n\n /// 50% fee rebate\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\n uint256 public feeRebatePercent = 50 * 10**18;\n\n address public admin;\n\n /// For modules interaction.\n address public protocolAddress;\n\n /**\n *** Affiliates ***\n **/\n\n /// The flag is set on the user's first trade.\n mapping(address => bool) public userNotFirstTradeFlag;\n\n /// User => referrer (affiliate).\n mapping(address => address) public affiliatesUserReferrer;\n\n /// List of referral addresses affiliated to the referrer.\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\n\n /// @dev Referral threshold for paying out to the referrer.\n /// The referrer reward is being accumulated and locked until the threshold is passed.\n uint256 public minReferralsToPayout = 3;\n\n /// @dev Total affiliate SOV rewards that held in the protocol\n /// (Because the minimum referrals is less than the rule)\n mapping(address => uint256) public affiliateRewardsHeld;\n\n /// @dev For affiliates SOV Bonus proccess.\n address public sovTokenAddress;\n address public lockedSOVAddress;\n\n /// @dev 20% fee share of trading token fee.\n /// Fee share of trading token fee for affiliate program.\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\n\n /// @dev Addresses of tokens in which commissions were paid to referrers.\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\n\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\n\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\n bool public pause; //Flag to pause all protocol modules\n\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\n\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\n uint256 internal tradingRebateRewardsBasisPoint;\n\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\n /// Will be used in internal swap.\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\n\n address internal pauser;\n\n /**\n * @notice Add signature and target to storage.\n * @dev Protocol is a proxy and requires a way to add every\n * module function dynamically during deployment.\n * */\n function _setTarget(bytes4 sig, address target) internal {\n logicTargets[sig] = target;\n\n if (target != address(0)) {\n logicTargetsSet.addBytes32(bytes32(sig));\n } else {\n logicTargetsSet.removeBytes32(bytes32(sig));\n }\n }\n\n modifier onlyAdminOrOwner() {\n require(isOwner() || admin == (msg.sender), \"unauthorized\");\n _;\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || pauser == (msg.sender), \"unauthorized\");\n _;\n }\n}\n" + }, + "contracts/escrow/Escrow.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Ethereum Pool to accept SOV Token.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice You can use this contract for deposit of SOV tokens for some time and withdraw later.\n */\ncontract Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalDeposit;\n /// @notice The release timestamp for the tokens deposited.\n uint256 public releaseTime;\n /// @notice The amount of token we would be accepting as deposit at max.\n uint256 public depositLimit;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The multisig contract which handles the fund.\n address public multisig;\n\n /// @notice The user balances.\n mapping(address => uint256) userBalances;\n\n /// @notice The current contract status.\n /// @notice Deployed - Deployed the contract.\n /// @notice Deposit - Time to deposit in the contract by the users.\n /// @notice Holding - Deposit is closed and now the holding period starts.\n /// @notice Withdraw - Time to withdraw in the contract by the users.\n /// @notice Expired - The contract is now closed completely.\n enum Status { Deployed, Deposit, Holding, Withdraw, Expired }\n Status public status;\n\n /* Events */\n\n /// @notice Emitted when the contract deposit starts.\n event EscrowActivated();\n\n /// @notice Emitted when the contract is put in holding state. No new token deposit accepted by User.\n event EscrowInHoldingState();\n\n /// @notice Emitted when the contract is put in withdraw state. Users can now withdraw tokens.\n event EscrowInWithdrawState();\n\n /// @notice Emitted when the contract is expired after withdraws are made/total token transfer.\n event EscrowFundExpired();\n\n /// @notice Emitted when a new multisig is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newMultisig The address which is added as the new multisig.\n /// @dev Can only be initiated by the current multisig.\n event NewMultisig(address indexed _initiator, address indexed _newMultisig);\n\n /// @notice Emitted when the release timestamp is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseTimestamp The updated release timestamp for the withdraw.\n event TokenReleaseUpdated(address indexed _initiator, uint256 _releaseTimestamp);\n\n /// @notice Emitted when the deposit limit is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _depositLimit The updated deposit limit.\n event TokenDepositLimitUpdated(address indexed _initiator, uint256 _depositLimit);\n\n /// @notice Emitted when a new token deposit is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when we reach the token deposit limit.\n event DepositLimitReached();\n\n /// @notice Emitted when a token withdraw is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdrawByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyMultisig() {\n require(msg.sender == multisig, \"Only Multisig can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n modifier checkRelease() {\n require(\n releaseTime != 0 && releaseTime <= block.timestamp,\n \"The release time has not started yet.\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_multisig != address(0), \"Invalid Multisig Address.\");\n\n SOV = IERC20(_SOV);\n multisig = _multisig;\n\n emit NewMultisig(msg.sender, _multisig);\n\n releaseTime = _releaseTime;\n depositLimit = _depositLimit;\n\n status = Status.Deployed;\n }\n\n /**\n * @notice This function is called once after deployment for starting the deposit action.\n * @dev Without calling this function, the contract will not start accepting tokens.\n */\n function init() external onlyMultisig checkStatus(Status.Deployed) {\n status = Status.Deposit;\n\n emit EscrowActivated();\n }\n\n /**\n * @notice Update Multisig.\n * @param _newMultisig The new owner of the tokens & contract.\n */\n function updateMultisig(address _newMultisig) external onlyMultisig {\n require(_newMultisig != address(0), \"New Multisig address invalid.\");\n\n multisig = _newMultisig;\n\n emit NewMultisig(msg.sender, _newMultisig);\n }\n\n /**\n * @notice Update Release Timestamp.\n * @param _newReleaseTime The new release timestamp for token release.\n * @dev Zero is also a valid timestamp, if the release time is not scheduled yet.\n */\n function updateReleaseTimestamp(uint256 _newReleaseTime) external onlyMultisig {\n releaseTime = _newReleaseTime;\n\n emit TokenReleaseUpdated(msg.sender, _newReleaseTime);\n }\n\n /**\n * @notice Update Deposit Limit.\n * @param _newDepositLimit The new deposit limit.\n * @dev IMPORTANT: Should not decrease than already deposited.\n */\n function updateDepositLimit(uint256 _newDepositLimit) external onlyMultisig {\n require(\n _newDepositLimit >= totalDeposit,\n \"Deposit already higher than the limit trying to be set.\"\n );\n depositLimit = _newDepositLimit;\n\n emit TokenDepositLimitUpdated(msg.sender, _newDepositLimit);\n }\n\n /**\n * @notice Deposit tokens to this contract by User.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the user inorder for this function to work.\n * These tokens can be withdrawn/transferred during Holding State by the Multisig.\n */\n function depositTokens(uint256 _amount) external checkStatus(Status.Deposit) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n uint256 amount = _amount;\n\n if (totalDeposit.add(_amount) >= depositLimit) {\n amount = depositLimit.sub(totalDeposit);\n emit DepositLimitReached();\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n userBalances[msg.sender] = userBalances[msg.sender].add(amount);\n totalDeposit = totalDeposit.add(amount);\n\n emit TokenDeposit(msg.sender, amount);\n }\n\n /**\n * @notice Update contract state to Holding.\n * @dev Once called, the contract no longer accepts any more deposits.\n * The multisig can now withdraw tokens from the contract after the contract is in Holding State.\n */\n function changeStateToHolding() external onlyMultisig checkStatus(Status.Deposit) {\n status = Status.Holding;\n\n emit EscrowInHoldingState();\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred. Zero address if the withdraw is to be done in Multisig.\n * @dev Can only be called after the token state is changed to Holding.\n */\n function withdrawTokensByMultisig(address _receiverAddress)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n address receiverAddress = msg.sender;\n if (_receiverAddress != address(0)) {\n receiverAddress = _receiverAddress;\n }\n\n uint256 value = SOV.balanceOf(address(this));\n /// Sending the amount to multisig.\n bool txStatus = SOV.transfer(receiverAddress, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdrawByMultisig(msg.sender, value);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n * Once the token deposit is higher than the total deposits done, the contract state is changed to Withdraw.\n */\n function depositTokensByMultisig(uint256 _amount)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDepositByMultisig(msg.sender, _amount);\n\n if (SOV.balanceOf(address(this)) >= totalDeposit) {\n status = Status.Withdraw;\n emit EscrowInWithdrawState();\n }\n }\n\n /**\n * @notice Withdraws token from the contract by User.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokens() public checkRelease checkStatus(Status.Withdraw) {\n uint256 amount = userBalances[msg.sender];\n userBalances[msg.sender] = 0;\n bool txStatus = SOV.transfer(msg.sender, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdraw(msg.sender, amount);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token balance of a particular user.\n * @return _addr The user address whose balance has to be checked.\n */\n function getUserBalance(address _addr) external view returns (uint256 balance) {\n return userBalances[_addr];\n }\n}\n" + }, + "contracts/escrow/EscrowReward.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Escrow.sol\";\nimport \"../locked/ILockedSOV.sol\";\n\n/**\n * @title A reward distribution contract for Sovryn Ethereum Pool Escrow Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice Multisig can use this contract for depositing of Reward tokens based on the total token deposit.\n */\ncontract EscrowReward is Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total reward tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalRewardDeposit;\n\n /// @notice The Locked SOV contract.\n ILockedSOV public lockedSOV;\n\n /* Events */\n\n /// @notice Emitted when the Locked SOV Contract address is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _lockedSOV The address of the Locked SOV Contract.\n event LockedSOVUpdated(address indexed _initiator, address indexed _lockedSOV);\n\n /// @notice Emitted when a new reward token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event RewardDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a Reward token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event RewardTokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _lockedSOV The Locked SOV Contract address.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _lockedSOV,\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public Escrow(_SOV, _multisig, _releaseTime, _depositLimit) {\n if (_lockedSOV != address(0)) {\n lockedSOV = ILockedSOV(_lockedSOV);\n }\n }\n\n /**\n * @notice Set the Locked SOV Contract Address if not already done.\n * @param _lockedSOV The Locked SOV Contract address.\n */\n function updateLockedSOV(address _lockedSOV) external onlyMultisig {\n require(_lockedSOV != address(0), \"Invalid Reward Token Address.\");\n\n lockedSOV = ILockedSOV(_lockedSOV);\n\n emit LockedSOVUpdated(msg.sender, _lockedSOV);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n */\n function depositRewardByMultisig(uint256 _amount) external onlyMultisig {\n require(\n status != Status.Withdraw,\n \"Reward Token deposit is only allowed before User Withdraw starts.\"\n );\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n totalRewardDeposit = totalRewardDeposit.add(_amount);\n txStatus = SOV.approve(address(lockedSOV), totalRewardDeposit);\n require(txStatus, \"Token Approval was not successful.\");\n\n emit RewardDepositByMultisig(msg.sender, _amount);\n }\n\n /**\n * @notice Withdraws token and reward from the contract by User. Reward is gone to lockedSOV contract for future vesting.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokensAndReward() external checkRelease checkStatus(Status.Withdraw) {\n // Reward calculation have to be done initially as the User Balance is zeroed out .\n uint256 reward = userBalances[msg.sender].mul(totalRewardDeposit).div(totalDeposit);\n withdrawTokens();\n\n lockedSOV.depositSOV(msg.sender, reward);\n\n emit RewardTokenWithdraw(msg.sender, reward);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the reward a particular user can get.\n * @param _addr The address of the user whose reward is to be read.\n * @return reward The reward received by the user.\n */\n function getReward(address _addr) external view returns (uint256 reward) {\n if (userBalances[_addr].mul(totalRewardDeposit) == 0) {\n return 0;\n }\n return userBalances[_addr].mul(totalRewardDeposit).div(totalDeposit);\n }\n}\n" + }, + "contracts/events/AffiliatesEvents.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\ncontract AffiliatesEvents is ModulesCommonEvents {\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\n\n event SetAffiliatesReferrerFail(\n address indexed user,\n address indexed referrer,\n bool alreadySet,\n bool userNotFirstTrade\n );\n\n event SetUserNotFirstTradeFlag(address indexed user);\n\n event PayTradingFeeToAffiliate(\n address indexed referrer,\n address trader,\n address indexed token,\n bool indexed isHeld,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountPaid\n );\n\n event PayTradingFeeToAffiliateFail(\n address indexed referrer,\n address trader,\n address indexed token,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountTryingToPaid\n );\n\n event WithdrawAffiliatesReferrerTokenFees(\n address indexed referrer,\n address indexed receiver,\n address indexed tokenAddress,\n uint256 amount\n );\n}\n" + }, + "contracts/events/FeesEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Fees Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for fee payments.\n * */\ncontract FeesEvents {\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\n\n event PayTradingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event PayBorrowingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event EarnReward(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n\n event EarnRewardFail(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n}\n" + }, + "contracts/events/LoanClosingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Closing Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan closing operations.\n * */\ncontract LoanClosingsEvents is ModulesCommonEvents {\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\n event CloseWithDeposit(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address closer,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\n event CloseWithSwap(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n address closer,\n uint256 positionCloseSize,\n uint256 loanCloseAmount,\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\n uint256 currentLeverage\n );\n\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\n event Liquidate(\n address indexed user,\n address indexed liquidator,\n bytes32 indexed loanId,\n address lender,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n event Rollover(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n uint256 principal,\n uint256 collateral,\n uint256 endTimestamp,\n address rewardReceiver,\n uint256 reward\n );\n\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\n}\n" + }, + "contracts/events/LoanMaintenanceEvents.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Maintenance Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan maintenance operations.\n * */\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\n}\n" + }, + "contracts/events/LoanOpeningsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Openings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan openings operations.\n * */\ncontract LoanOpeningsEvents is ModulesCommonEvents {\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\n event Borrow(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 newCollateral,\n uint256 interestRate,\n uint256 interestDuration,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\n event Trade(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n uint256 positionSize,\n uint256 borrowedAmount,\n uint256 interestRate,\n uint256 settlementDate,\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\n uint256 entryLeverage,\n uint256 currentLeverage\n );\n\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\n event DelegatedManagerSet(\n bytes32 indexed loanId,\n address indexed delegator,\n address indexed delegated,\n bool isActive\n );\n}\n" + }, + "contracts/events/LoanSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan settings operations.\n * */\ncontract LoanSettingsEvents is ModulesCommonEvents {\n event LoanParamsSetup(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\n\n event LoanParamsDisabled(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\n}\n" + }, + "contracts/events/ModulesCommonEvents.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title The common events for all modules\n * @notice This contract contains the events which will be used by all modules\n **/\n\ncontract ModulesCommonEvents {\n event ProtocolModuleContractReplaced(\n address indexed prevModuleContractAddress,\n address indexed newModuleContractAddress,\n bytes32 indexed module\n );\n}\n" + }, + "contracts/events/ProtocolSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title The Protocol Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for protocol settings operations.\n * */\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\n\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\n\n event SetLoanPool(\n address indexed sender,\n address indexed loanPool,\n address indexed underlying\n );\n\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\n\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateTradingTokenFeePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetLiquidationIncentivePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetFeesController(\n address indexed sender,\n address indexed oldController,\n address indexed newController\n );\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWethToken,\n address indexed newWethToken\n );\n\n event SetSovrynSwapContractRegistryAddress(\n address indexed sender,\n address indexed oldSovrynSwapContractRegistryAddress,\n address indexed newSovrynSwapContractRegistryAddress\n );\n\n event SetProtocolTokenAddress(\n address indexed sender,\n address indexed oldProtocolToken,\n address indexed newProtocolToken\n );\n\n event WithdrawFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 lendingAmount,\n uint256 tradingAmount,\n uint256 borrowingAmount,\n uint256 wRBTCConverted\n );\n\n event WithdrawLendingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawTradingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawBorrowingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetRebatePercent(\n address indexed sender,\n uint256 oldRebatePercent,\n uint256 newRebatePercent\n );\n\n event SetSpecialRebates(\n address indexed sender,\n address indexed sourceToken,\n address indexed destToken,\n uint256 oldSpecialRebatesPercent,\n uint256 newSpecialRebatesPercent\n );\n\n event SetProtocolAddress(\n address indexed sender,\n address indexed oldProtocol,\n address indexed newProtocol\n );\n\n event SetMinReferralsToPayoutAffiliates(\n address indexed sender,\n uint256 oldMinReferrals,\n uint256 newMinReferrals\n );\n\n event SetSOVTokenAddress(\n address indexed sender,\n address indexed oldTokenAddress,\n address indexed newTokenAddress\n );\n\n event SetLockedSOVAddress(\n address indexed sender,\n address indexed oldAddress,\n address indexed newAddress\n );\n\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\n\n event SetTradingRebateRewardsBasisPoint(\n address indexed sender,\n uint256 oldBasisPoint,\n uint256 newBasisPoint\n );\n\n event SetRolloverFlexFeePercent(\n address indexed sender,\n uint256 oldRolloverFlexFeePercent,\n uint256 newRolloverFlexFeePercent\n );\n\n event SetDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event RemoveDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n}\n" + }, + "contracts/events/SwapsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Swaps Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for swap operations.\n * */\ncontract SwapsEvents is ModulesCommonEvents {\n event LoanSwap(\n bytes32 indexed loanId,\n address indexed sourceToken,\n address indexed destToken,\n address borrower,\n uint256 sourceAmount,\n uint256 destAmount\n );\n\n event ExternalSwap(\n address indexed user,\n address indexed sourceToken,\n address indexed destToken,\n uint256 sourceAmount,\n uint256 destAmount\n );\n}\n" + }, + "contracts/farm/ILiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\n\ninterface ILiquidityMining {\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external;\n\n function onTokensDeposited(address _user, uint256 _amount) external;\n\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/farm/LiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./LiquidityMiningStorage.sol\";\nimport \"./ILiquidityMining.sol\";\n\ncontract LiquidityMining is ILiquidityMining, LiquidityMiningStorage {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n /* Constants */\n\n uint256 public constant PRECISION = 1e12;\n // Bonus multiplier for early liquidity providers.\n // During bonus period each passed block will be calculated like N passed blocks, where N = BONUS_MULTIPLIER\n uint256 public constant BONUS_BLOCK_MULTIPLIER = 10;\n\n uint256 public constant SECONDS_PER_BLOCK = 30;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event PoolTokenAdded(address indexed user, address indexed poolToken, uint256 allocationPoint);\n event PoolTokenUpdated(\n address indexed user,\n address indexed poolToken,\n uint256 newAllocationPoint,\n uint256 oldAllocationPoint\n );\n event Deposit(address indexed user, address indexed poolToken, uint256 amount);\n event RewardClaimed(address indexed user, address indexed poolToken, uint256 amount);\n event Withdraw(address indexed user, address indexed poolToken, uint256 amount);\n event EmergencyWithdraw(\n address indexed user,\n address indexed poolToken,\n uint256 amount,\n uint256 accumulatedReward\n );\n\n /* Functions */\n\n /**\n * @notice Initialize mining.\n *\n * @param _SOV The SOV token.\n * @param _rewardTokensPerBlock The number of reward tokens per block.\n * @param _startDelayBlocks The number of blocks should be passed to start\n * mining.\n * @param _numberOfBonusBlocks The number of blocks when each block will\n * be calculated as N blocks (BONUS_BLOCK_MULTIPLIER).\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n * SOV rewards are not paid directly to liquidity providers. Instead they\n * are deposited into a lockedSOV vault contract.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n */\n function initialize(\n IERC20 _SOV,\n uint256 _rewardTokensPerBlock,\n uint256 _startDelayBlocks,\n uint256 _numberOfBonusBlocks,\n address _wrapper,\n ILockedSOV _lockedSOV,\n uint256 _unlockedImmediatelyPercent\n ) external onlyAuthorized {\n /// @dev Non-idempotent function. Must be called just once.\n require(address(SOV) == address(0), \"Already initialized\");\n require(address(_SOV) != address(0), \"Invalid token address\");\n require(_startDelayBlocks > 0, \"Invalid start block\");\n require(\n _unlockedImmediatelyPercent < 10000,\n \"Unlocked immediately percent has to be less than 10000.\"\n );\n\n SOV = _SOV;\n rewardTokensPerBlock = _rewardTokensPerBlock;\n startBlock = block.number + _startDelayBlocks;\n bonusEndBlock = startBlock + _numberOfBonusBlocks;\n wrapper = _wrapper;\n lockedSOV = _lockedSOV;\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets lockedSOV contract.\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n */\n function setLockedSOV(ILockedSOV _lockedSOV) external onlyAuthorized {\n require(address(_lockedSOV) != address(0), \"Invalid lockedSOV Address.\");\n lockedSOV = _lockedSOV;\n }\n\n /**\n * @notice Sets unlocked immediately percent.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setUnlockedImmediatelyPercent(uint256 _unlockedImmediatelyPercent)\n external\n onlyAuthorized\n {\n require(\n _unlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets unlocked immediately percent overwrite for specific pool token.\n * @param _poolToken the address of pool token\n * @param _poolTokenUnlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setPoolTokenUnlockedImmediatelyPercent(\n address _poolToken,\n uint256 _poolTokenUnlockedImmediatelyPercent\n ) external onlyAuthorized {\n require(\n _poolTokenUnlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n poolTokensUnlockedImmediatelyPercent[_poolToken] = _poolTokenUnlockedImmediatelyPercent;\n }\n\n /**\n * @notice sets wrapper proxy contract\n * @dev can be set to zero address to remove wrapper\n */\n function setWrapper(address _wrapper) external onlyAuthorized {\n wrapper = _wrapper;\n }\n\n /**\n * @notice stops mining by setting end block\n */\n function stopMining() external onlyAuthorized {\n require(endBlock == 0, \"Already stopped\");\n\n endBlock = block.number;\n }\n\n /**\n * @notice Transfers SOV tokens to given address.\n * Owner use this function to withdraw SOV from LM contract\n * into another account.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) external onlyAuthorized {\n require(_receiver != address(0), \"Receiver address invalid\");\n require(_amount != 0, \"Amount invalid\");\n\n /// @dev Do not transfer more SOV than available.\n uint256 SOVBal = SOV.balanceOf(address(this));\n if (_amount > SOVBal) {\n _amount = SOVBal;\n }\n\n /// @dev The actual transfer.\n require(SOV.transfer(_receiver, _amount), \"Transfer failed\");\n\n /// @dev Event log.\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Get the missed SOV balance of LM contract.\n *\n * @return The amount of SOV tokens according to totalUsersBalance\n * in excess of actual SOV balance of the LM contract.\n * */\n function getMissedBalance() external view returns (uint256) {\n uint256 balance = SOV.balanceOf(address(this));\n return balance >= totalUsersBalance ? 0 : totalUsersBalance.sub(balance);\n }\n\n /**\n * @notice adds a new lp to the pool. Can only be called by the owner or an admin\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _withUpdate the flag whether we need to update all pools\n */\n function add(\n address _poolToken,\n uint96 _allocationPoint,\n bool _withUpdate\n ) external onlyAuthorized {\n require(_allocationPoint > 0, \"Invalid allocation point\");\n require(_poolToken != address(0), \"Invalid token address\");\n require(poolIdList[_poolToken] == 0, \"Token already added\");\n\n if (_withUpdate) {\n updateAllPools();\n }\n\n uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;\n totalAllocationPoint = totalAllocationPoint.add(_allocationPoint);\n\n poolInfoList.push(\n PoolInfo({\n poolToken: IERC20(_poolToken),\n allocationPoint: _allocationPoint,\n lastRewardBlock: lastRewardBlock,\n accumulatedRewardPerShare: 0\n })\n );\n //indexing starts from 1 in order to check whether token was already added\n poolIdList[_poolToken] = poolInfoList.length;\n\n emit PoolTokenAdded(msg.sender, _poolToken, _allocationPoint);\n }\n\n /**\n * @notice updates the given pool's reward tokens allocation point\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function update(\n address _poolToken,\n uint96 _allocationPoint,\n bool _updateAllFlag\n ) external onlyAuthorized {\n if (_updateAllFlag) {\n updateAllPools();\n } else {\n updatePool(_poolToken);\n }\n _updateToken(_poolToken, _allocationPoint);\n }\n\n function _updateToken(address _poolToken, uint96 _allocationPoint) internal {\n uint256 poolId = _getPoolId(_poolToken);\n\n uint256 previousAllocationPoint = poolInfoList[poolId].allocationPoint;\n totalAllocationPoint = totalAllocationPoint.sub(previousAllocationPoint).add(\n _allocationPoint\n );\n poolInfoList[poolId].allocationPoint = _allocationPoint;\n\n emit PoolTokenUpdated(msg.sender, _poolToken, _allocationPoint, previousAllocationPoint);\n }\n\n /**\n * @notice updates the given pools' reward tokens allocation points\n * @param _poolTokens array of addresses of pool tokens\n * @param _allocationPoints array of allocation points (weight) for the given pools\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function updateTokens(\n address[] calldata _poolTokens,\n uint96[] calldata _allocationPoints,\n bool _updateAllFlag\n ) external onlyAuthorized {\n require(_poolTokens.length == _allocationPoints.length, \"Arrays mismatch\");\n\n if (_updateAllFlag) {\n updateAllPools();\n }\n uint256 length = _poolTokens.length;\n for (uint256 i = 0; i < length; i++) {\n if (!_updateAllFlag) {\n updatePool(_poolTokens[i]);\n }\n _updateToken(_poolTokens[i], _allocationPoints[i]);\n }\n }\n\n /**\n * @notice returns reward multiplier over the given _from to _to block\n * @param _from the first block for a calculation\n * @param _to the last block for a calculation\n */\n function _getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n internal\n view\n returns (uint256)\n {\n if (_from < startBlock) {\n _from = startBlock;\n }\n if (endBlock > 0 && _to > endBlock) {\n _to = endBlock;\n }\n if (_to <= bonusEndBlock) {\n return _to.sub(_from).mul(BONUS_BLOCK_MULTIPLIER);\n } else if (_from >= bonusEndBlock) {\n return _to.sub(_from);\n } else {\n return\n bonusEndBlock.sub(_from).mul(BONUS_BLOCK_MULTIPLIER).add(_to.sub(bonusEndBlock));\n }\n }\n\n function _getUserAccumulatedReward(uint256 _poolId, address _user)\n internal\n view\n returns (uint256)\n {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_user];\n\n uint256 accumulatedRewardPerShare = pool.accumulatedRewardPerShare;\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (block.number > pool.lastRewardBlock && poolTokenBalance != 0) {\n (, uint256 accumulatedRewardPerShare_) = _getPoolAccumulatedReward(pool);\n accumulatedRewardPerShare = accumulatedRewardPerShare.add(accumulatedRewardPerShare_);\n }\n\n return\n user.accumulatedReward.add(\n user.amount.mul(accumulatedRewardPerShare).div(PRECISION).sub(user.rewardDebt)\n );\n }\n\n /**\n * @notice returns accumulated reward\n * @param _poolToken the address of pool token\n * @param _user the user address\n */\n function getUserAccumulatedReward(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n uint256 poolId = _getPoolId(_poolToken);\n return _getUserAccumulatedReward(poolId, _user);\n }\n\n /**\n * @notice returns estimated reward\n * @param _poolToken the address of pool token\n * @param _amount the amount of tokens to be deposited\n * @param _duration the duration of liquidity providing in seconds\n */\n function getEstimatedReward(\n address _poolToken,\n uint256 _amount,\n uint256 _duration\n ) external view returns (uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n uint256 start = block.number;\n uint256 end = start.add(_duration.div(SECONDS_PER_BLOCK));\n (, uint256 accumulatedRewardPerShare) =\n _getPoolAccumulatedReward(pool, _amount, start, end);\n return _amount.mul(accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Updates reward variables for all pools.\n * @dev Be careful of gas spending!\n */\n function updateAllPools() public {\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n _updatePool(i);\n }\n }\n\n /**\n * @notice Updates reward variables of the given pool to be up-to-date\n * @param _poolToken the address of pool token\n */\n function updatePool(address _poolToken) public {\n uint256 poolId = _getPoolId(_poolToken);\n _updatePool(poolId);\n }\n\n function _updatePool(uint256 _poolId) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n\n //this pool has been updated recently\n if (block.number <= pool.lastRewardBlock) {\n return;\n }\n\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (poolTokenBalance == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n (uint256 accumulatedReward_, uint256 accumulatedRewardPerShare_) =\n _getPoolAccumulatedReward(pool);\n pool.accumulatedRewardPerShare = pool.accumulatedRewardPerShare.add(\n accumulatedRewardPerShare_\n );\n pool.lastRewardBlock = block.number;\n\n totalUsersBalance = totalUsersBalance.add(accumulatedReward_);\n }\n\n function _getPoolAccumulatedReward(PoolInfo storage _pool)\n internal\n view\n returns (uint256, uint256)\n {\n return _getPoolAccumulatedReward(_pool, 0, _pool.lastRewardBlock, block.number);\n }\n\n function _getPoolAccumulatedReward(\n PoolInfo storage _pool,\n uint256 _additionalAmount,\n uint256 _startBlock,\n uint256 _endBlock\n ) internal view returns (uint256, uint256) {\n uint256 passedBlocks = _getPassedBlocksWithBonusMultiplier(_startBlock, _endBlock);\n uint256 accumulatedReward =\n passedBlocks.mul(rewardTokensPerBlock).mul(_pool.allocationPoint).div(\n totalAllocationPoint\n );\n\n uint256 poolTokenBalance = _pool.poolToken.balanceOf(address(this));\n poolTokenBalance = poolTokenBalance.add(_additionalAmount);\n uint256 accumulatedRewardPerShare = accumulatedReward.mul(PRECISION).div(poolTokenBalance);\n return (accumulatedReward, accumulatedRewardPerShare);\n }\n\n /**\n * @notice deposits pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it or to msg.sender\n */\n function deposit(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n _deposit(_poolToken, _amount, _user, false);\n }\n\n /**\n * @notice if the lending pools directly mint/transfer tokens to this address, process it like a user deposit\n * @dev only callable by the pool which issues the tokens\n * @param _user the user address\n * @param _amount the minted amount\n */\n function onTokensDeposited(address _user, uint256 _amount) external {\n //the msg.sender is the pool token. if the msg.sender is not a valid pool token, _deposit will revert\n _deposit(msg.sender, _amount, _user, true);\n }\n\n /**\n * @notice internal function for depositing pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it\n * @param alreadyTransferred true if the pool tokens have already been transferred\n */\n function _deposit(\n address _poolToken,\n uint256 _amount,\n address _user,\n bool alreadyTransferred\n ) internal {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _user != address(0) ? _user : msg.sender;\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n\n _updatePool(poolId);\n //sends reward directly to the user\n _updateReward(pool, user);\n\n if (_amount > 0) {\n //receives pool tokens from msg.sender, it can be user or WrapperProxy contract\n if (!alreadyTransferred)\n pool.poolToken.safeTransferFrom(address(msg.sender), address(this), _amount);\n user.amount = user.amount.add(_amount);\n }\n _updateRewardDebt(pool, user);\n emit Deposit(userAddress, _poolToken, _amount);\n }\n\n /**\n * @notice transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimReward(address _poolToken, address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n _claimReward(poolId, userAddress, true);\n }\n\n function _claimReward(\n uint256 _poolId,\n address _userAddress,\n bool _isStakingTokens\n ) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_userAddress];\n\n _updatePool(_poolId);\n _updateReward(pool, user);\n _transferReward(address(pool.poolToken), user, _userAddress, _isStakingTokens, true);\n _updateRewardDebt(pool, user);\n }\n\n /**\n * @notice transfers reward tokens from all pools\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimRewardFromAllPools(address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n uint256 poolId = i;\n _claimReward(poolId, userAddress, false);\n }\n\n if (\n lockedSOV.getLockedBalance(userAddress) > 0 ||\n lockedSOV.getUnlockedBalance(userAddress) > 0\n ) {\n lockedSOV.withdrawAndStakeTokensFrom(userAddress);\n }\n }\n\n /**\n * @notice withdraws pool tokens and transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the user address will be used to process a withdrawal (can be passed only by wrapper contract)\n */\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n require(user.amount >= _amount, \"Not enough balance\");\n\n _updatePool(poolId);\n _updateReward(pool, user);\n _transferReward(_poolToken, user, userAddress, false, false);\n\n user.amount = user.amount.sub(_amount);\n\n //msg.sender is wrapper -> send to wrapper\n if (msg.sender == wrapper) {\n pool.poolToken.safeTransfer(address(msg.sender), _amount);\n }\n //msg.sender is user or pool token (lending pool) -> send to user\n else {\n pool.poolToken.safeTransfer(userAddress, _amount);\n }\n\n _updateRewardDebt(pool, user);\n emit Withdraw(userAddress, _poolToken, _amount);\n }\n\n function _getUserAddress(address _user) internal view returns (address) {\n address userAddress = msg.sender;\n if (_user != address(0)) {\n //only wrapper can pass _user parameter\n require(\n msg.sender == wrapper || poolIdList[msg.sender] != 0,\n \"only wrapper or pools may withdraw for a user\"\n );\n userAddress = _user;\n }\n return userAddress;\n }\n\n function _updateReward(PoolInfo storage pool, UserInfo storage user) internal {\n //update user accumulated reward\n if (user.amount > 0) {\n //add reward for the previous amount of deposited tokens\n uint256 accumulatedReward =\n user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION).sub(\n user.rewardDebt\n );\n user.accumulatedReward = user.accumulatedReward.add(accumulatedReward);\n }\n }\n\n function _updateRewardDebt(PoolInfo storage pool, UserInfo storage user) internal {\n //reward accumulated before amount update (should be subtracted during next reward calculation)\n user.rewardDebt = user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Send reward in SOV to the lockedSOV vault.\n * @param _user The user info, to get its reward share.\n * @param _userAddress The address of the user, to send SOV in its behalf.\n * @param _isStakingTokens The flag whether we need to stake tokens\n * @param _isCheckingBalance The flag whether we need to throw error or don't process reward if SOV balance isn't enough\n */\n function _transferReward(\n address _poolToken,\n UserInfo storage _user,\n address _userAddress,\n bool _isStakingTokens,\n bool _isCheckingBalance\n ) internal {\n uint256 userAccumulatedReward = _user.accumulatedReward;\n /// @dev get unlock immediate percent of the pool token.\n uint256 calculatedUnlockedImmediatelyPercent = calcUnlockedImmediatelyPercent(_poolToken);\n\n /// @dev Transfer if enough SOV balance on this LM contract.\n uint256 balance = SOV.balanceOf(address(this));\n if (balance >= userAccumulatedReward) {\n totalUsersBalance = totalUsersBalance.sub(userAccumulatedReward);\n _user.accumulatedReward = 0;\n\n /// @dev If calculatedUnlockedImmediatelyPercent is 100%, transfer the reward to the LP (user).\n /// else, deposit it into lockedSOV vault contract, but first\n /// SOV deposit must be approved to move the SOV tokens\n /// from this LM contract into the lockedSOV vault.\n if (calculatedUnlockedImmediatelyPercent == 10000) {\n SOV.transfer(_userAddress, userAccumulatedReward);\n } else {\n require(SOV.approve(address(lockedSOV), userAccumulatedReward), \"Approve failed\");\n lockedSOV.deposit(\n _userAddress,\n userAccumulatedReward,\n calculatedUnlockedImmediatelyPercent\n );\n\n if (_isStakingTokens) {\n lockedSOV.withdrawAndStakeTokensFrom(_userAddress);\n }\n }\n\n /// @dev Event log.\n emit RewardClaimed(_userAddress, _poolToken, userAccumulatedReward);\n } else {\n require(!_isCheckingBalance, \"Claiming reward failed\");\n }\n }\n\n /**\n * @notice withdraws pool tokens without transferring reward tokens\n * @param _poolToken the address of pool token\n * @dev EMERGENCY ONLY\n */\n function emergencyWithdraw(address _poolToken) external {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][msg.sender];\n\n _updatePool(poolId);\n _updateReward(pool, user);\n\n totalUsersBalance = totalUsersBalance.sub(user.accumulatedReward);\n uint256 userAmount = user.amount;\n uint256 userAccumulatedReward = user.accumulatedReward;\n user.amount = 0;\n user.rewardDebt = 0;\n user.accumulatedReward = 0;\n pool.poolToken.safeTransfer(address(msg.sender), userAmount);\n\n emit EmergencyWithdraw(msg.sender, _poolToken, userAmount, userAccumulatedReward);\n }\n\n /**\n * @notice returns pool id\n * @param _poolToken the address of pool token\n */\n function getPoolId(address _poolToken) external view returns (uint256) {\n return _getPoolId(_poolToken);\n }\n\n function _getPoolId(address _poolToken) internal view returns (uint256) {\n uint256 poolId = poolIdList[_poolToken];\n require(poolId > 0, \"Pool token not found\");\n return poolId - 1;\n }\n\n /**\n * @notice returns count of pool tokens\n */\n function getPoolLength() external view returns (uint256) {\n return poolInfoList.length;\n }\n\n /**\n * @notice returns list of pool token's info\n */\n function getPoolInfoList() external view returns (PoolInfo[] memory) {\n return poolInfoList;\n }\n\n /**\n * @notice returns pool info for the given token\n * @param _poolToken the address of pool token\n */\n function getPoolInfo(address _poolToken) external view returns (PoolInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return poolInfoList[poolId];\n }\n\n /**\n * @notice returns list of [amount, accumulatedReward] for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserBalanceList(address _user) external view returns (uint256[2][] memory) {\n uint256 length = poolInfoList.length;\n uint256[2][] memory userBalanceList = new uint256[2][](length);\n for (uint256 i = 0; i < length; i++) {\n userBalanceList[i][0] = userInfoMap[i][_user].amount;\n userBalanceList[i][1] = _getUserAccumulatedReward(i, _user);\n }\n return userBalanceList;\n }\n\n /**\n * @notice returns UserInfo for the given pool and user\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserInfo(address _poolToken, address _user) public view returns (UserInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return userInfoMap[poolId][_user];\n }\n\n /**\n * @notice returns list of UserInfo for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserInfoList(address _user) external view returns (UserInfo[] memory) {\n uint256 length = poolInfoList.length;\n UserInfo[] memory userInfoList = new UserInfo[](length);\n for (uint256 i = 0; i < length; i++) {\n userInfoList[i] = userInfoMap[i][_user];\n }\n return userInfoList;\n }\n\n /**\n * @notice returns accumulated reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardList(address _user) external view returns (uint256[] memory) {\n uint256 length = poolInfoList.length;\n uint256[] memory rewardList = new uint256[](length);\n for (uint256 i = 0; i < length; i++) {\n rewardList[i] = _getUserAccumulatedReward(i, _user);\n }\n return rewardList;\n }\n\n /**\n * @notice returns the pool token balance a user has on the contract\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n UserInfo memory ui = getUserInfo(_poolToken, _user);\n return ui.amount;\n }\n\n /**\n * @notice returns the accumulated liquid reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBePaidLiquid(address _user)\n external\n view\n returns (uint256)\n {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n calculatedUnlockedImmediatelyPercent.mul(_getUserAccumulatedReward(i, _user)).div(\n 10000\n )\n );\n }\n\n return result;\n }\n\n /**\n * @notice returns the accumulated vested reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBeVested(address _user) external view returns (uint256) {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n (10000 - calculatedUnlockedImmediatelyPercent)\n .mul(_getUserAccumulatedReward(i, _user))\n .div(10000)\n );\n }\n\n return result;\n }\n\n /**\n * @dev calculate the unlocked immediate percentage of specific pool token\n * use the poolTokensUnlockedImmediatelyPercent by default, if it is not set, then use the unlockedImmediatelyPercent\n */\n function calcUnlockedImmediatelyPercent(address _poolToken) public view returns (uint256) {\n uint256 poolTokenUnlockedImmediatelyPercent =\n poolTokensUnlockedImmediatelyPercent[_poolToken];\n return\n poolTokenUnlockedImmediatelyPercent > 0\n ? poolTokenUnlockedImmediatelyPercent\n : unlockedImmediatelyPercent;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningConfigToken.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/IERC20_.sol\";\n\n/**\n * @title Dummy token with 0 total supply.\n *\n * @dev We need this token for having a flexibility with LiquidityMining configuration\n */\ncontract LiquidityMiningConfigToken is IERC20_ {\n function totalSupply() external view returns (uint256) {\n return 0;\n }\n\n function balanceOf(address account) external view returns (uint256) {\n return 0;\n }\n\n function transfer(address recipient, uint256 amount) external returns (bool) {\n return false;\n }\n\n function allowance(address owner, address spender) external view returns (uint256) {\n return 0;\n }\n\n function approve(address spender, uint256 amount) external returns (bool) {\n return false;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool) {\n return false;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./LiquidityMiningStorage.sol\";\nimport \"../proxy/UpgradableProxy.sol\";\n\n/**\n * @dev LiquidityMining contract should be upgradable, use UpgradableProxy\n */\ncontract LiquidityMiningProxy is LiquidityMiningStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/farm/LiquidityMiningStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../utils/AdminRole.sol\";\n\ncontract LiquidityMiningStorage is AdminRole {\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many pool tokens the user has provided.\n uint256 rewardDebt; // Reward debt. See explanation below.\n uint256 accumulatedReward; //Reward that's ready to be transferred\n //\n // We do some fancy math here. Basically, any point in time, the amount of reward tokens\n // entitled to a user but is accumulated to be distributed is:\n //\n // accumulated reward = (user.amount * pool.accumulatedRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accumulatedRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the accumulated reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 poolToken; // Address of LP token contract.\n uint96 allocationPoint; // How many allocation points assigned to this pool. Amount of reward tokens to distribute per block.\n uint256 lastRewardBlock; // Last block number that reward tokens distribution occurs.\n uint256 accumulatedRewardPerShare; // Accumulated amount of reward tokens per share, times 1e12. See below.\n }\n\n // Rewards tokens created per block.\n uint256 public rewardTokensPerBlock;\n // The block number when reward token mining starts.\n uint256 public startBlock;\n // Block number when bonus reward token period ends.\n uint256 public bonusEndBlock;\n // Block number when reward token period ends.\n uint256 public endBlock;\n\n //Wrapper contract which will be a proxy between user and LM\n address public wrapper;\n\n // Info of each pool.\n PoolInfo[] public poolInfoList;\n // Mapping pool token address => pool id\n mapping(address => uint256) poolIdList;\n // Total allocation points. Must be the sum of all allocation points in all pools.\n uint256 public totalAllocationPoint;\n\n // Info of each user that stakes LP tokens.\n mapping(uint256 => mapping(address => UserInfo)) public userInfoMap;\n // Total balance this contract should have to handle withdrawal for all users\n uint256 public totalUsersBalance;\n\n /// @dev The SOV token\n IERC20 public SOV;\n\n /// @dev The locked vault contract to deposit LP's rewards into.\n ILockedSOV public lockedSOV;\n\n // The % which determines how much will be unlocked immediately.\n /// @dev 10000 is 100%\n uint256 public unlockedImmediatelyPercent;\n\n /// @dev overwrite the unlockedImmediatelyPercent for specific token.\n mapping(address => uint256) public poolTokensUnlockedImmediatelyPercent;\n}\n" + }, + "contracts/feeds/BProPriceFeed.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IMoCState.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The BPro Price Feed contract.\n *\n * This contract gets/sets the MoC (Money on Chain) address of its state\n * contract and queries its method bproUsdPrice to get bPro/USD valuation.\n * */\ncontract BProPriceFeed is IPriceFeedsExt, Ownable {\n address public mocStateAddress;\n\n event SetMoCStateAddress(address indexed mocStateAddress, address changerAddress);\n\n /**\n * @notice Initializes a new MoC state.\n *\n * @param _mocStateAddress MoC state address\n * */\n constructor(address _mocStateAddress) public {\n setMoCStateAddress(_mocStateAddress);\n }\n\n /**\n * @notice Get BPro USD price.\n *\n * @return the BPro USD Price [using mocPrecision]\n */\n function latestAnswer() external view returns (uint256) {\n IMoCState _mocState = IMoCState(mocStateAddress);\n return _mocState.bproUsdPrice();\n }\n\n /**\n * @notice Supposed to get the MoC update time, but instead\n * get the current timestamp.\n *\n * @return Always returns current block's timestamp.\n * */\n function latestTimestamp() external view returns (uint256) {\n return now; /// MoC state doesn't return update timestamp.\n }\n\n /**\n * @notice Set MoC state address.\n *\n * @param _mocStateAddress The MoC state address.\n * */\n function setMoCStateAddress(address _mocStateAddress) public onlyOwner {\n require(Address.isContract(_mocStateAddress), \"_mocStateAddress not a contract\");\n mocStateAddress = _mocStateAddress;\n emit SetMoCStateAddress(mocStateAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/IMoCState.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IMoCState {\n function getRbtcInBitPro(bytes32 bucket) external view returns (uint256);\n\n function globalMaxBPro() external view returns (uint256);\n\n function maxBPro(bytes32 bucket) external view returns (uint256);\n\n function absoluteMaxBPro() external view returns (uint256);\n\n function maxBProWithDiscount() external view returns (uint256);\n\n function bproTecPrice() external view returns (uint256);\n\n function bucketBProTecPrice(bytes32 bucket) external view returns (uint256);\n\n function bproDiscountPrice() external view returns (uint256);\n\n function bproUsdPrice() external view returns (uint256);\n\n function bproSpotDiscountRate() external view returns (uint256);\n\n function getBucketNBPro(bytes32 bucket) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IPriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface IPriceFeeds {\n function queryRate(address sourceToken, address destToken)\n external\n view\n returns (uint256 rate, uint256 precision);\n\n function queryPrecision(address sourceToken, address destToken)\n external\n view\n returns (uint256 precision);\n\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) external view returns (uint256 destAmount);\n\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) external view returns (uint256 sourceToDestSwapRate);\n\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\n\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (uint256);\n\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\n\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\n\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (bool);\n\n function getFastGasPrice(address payToken) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IRSKOracle {\n function updatePrice(uint256 price, uint256 timestamp) external;\n\n function getPricing() external view returns (uint256, uint256);\n\n function setOracleAddress(address addr) external;\n\n function clearOracleAddress() external;\n}\n" + }, + "contracts/feeds/IV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IV1PoolOracle {\n function read(uint256 price, uint256 timestamp)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function latestAnswer() external view returns (uint256);\n\n function liquidityPool() external view returns (address);\n\n function latestPrice(address _baseToken) external view returns (uint256 answer);\n}\n\ninterface ILiquidityPoolV1Converter {\n function reserveTokens(uint256 index) external view returns (address);\n}\n" + }, + "contracts/feeds/PriceFeedRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IRSKOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @notice The Price Feed RSK Oracle contract.\n *\n * This contract implements RSK Oracle query functionality,\n * getting the price and the last timestamp from an external oracle contract.\n * */\ncontract PriceFeedRSKOracle is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public rskOracleAddress;\n\n /* Events */\n\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new RSK Oracle.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _rskOracleAddress) public {\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256 _price) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (_price, ) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestTimestamp() external view returns (uint256 _timestamp) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (, _timestamp) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/PriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./PriceFeedsConstants.sol\";\n\ninterface IPriceFeedsExt {\n function latestAnswer() external view returns (uint256);\n}\n\n/**\n * @title The Price Feeds contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract queries the price feeds contracts where\n * oracles updates token prices computing relative token prices.\n * And besides it includes some calculations about loans such as\n * drawdown, margin and collateral.\n * */\ncontract PriceFeeds is Constants, Ownable {\n using SafeMath for uint256;\n\n /* Events */\n\n event GlobalPricingPaused(address indexed sender, bool indexed isPaused);\n\n /* Storage */\n\n /// Mapping of PriceFeedsExt instances.\n /// token => pricefeed\n mapping(address => IPriceFeedsExt) public pricesFeeds;\n\n /// Decimals of supported tokens.\n mapping(address => uint256) public decimals;\n\n /// Value on rBTC weis for the protocol token.\n uint256 public protocolTokenEthPrice = 0.0002 ether;\n\n /// Flag to pause pricings.\n bool public globalPricingPaused = false;\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires 3 parameters.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * @param _protocolTokenAddress The address of the protocol token.\n * @param _baseTokenAddress The address of the base token.\n * */\n constructor(\n address _wrbtcTokenAddress,\n address _protocolTokenAddress,\n address _baseTokenAddress\n ) public {\n /// Set decimals for this token.\n decimals[address(0)] = 18;\n decimals[_wrbtcTokenAddress] = 18;\n _setWrbtcToken(_wrbtcTokenAddress);\n _setProtocolTokenAddress(_protocolTokenAddress);\n _setBaseToken(_baseTokenAddress);\n }\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @dev Public wrapper for _queryRate internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function queryRate(address sourceToken, address destToken)\n public\n view\n returns (uint256 rate, uint256 precision)\n {\n return _queryRate(sourceToken, destToken);\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @dev Public wrapper for _getDecimalPrecision internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function queryPrecision(address sourceToken, address destToken) public view returns (uint256) {\n return sourceToken != destToken ? _getDecimalPrecision(sourceToken, destToken) : 10**18;\n }\n\n /**\n * @notice Price conversor: Calculate the price of an amount of source\n * tokens in destiny token units.\n *\n * @dev NOTE: This function returns 0 during a pause, rather than a revert.\n * Ensure calling contracts handle correctly.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of the source tokens.\n *\n * @return destAmount The amount of destiny tokens equivalent in price\n * to the amount of source tokens.\n * */\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) public view returns (uint256 destAmount) {\n if (globalPricingPaused) {\n return 0;\n }\n\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n destAmount = sourceAmount.mul(rate).div(precision);\n }\n\n /**\n * @notice Calculate the swap rate between two tokens.\n *\n * Regarding slippage, there is a hardcoded slippage limit of 5%, enforced\n * by this function for all borrowing, lending and margin trading\n * originated swaps performed in the Sovryn exchange.\n *\n * This means all operations in the Sovryn exchange are subject to losing\n * up to 5% from the internal swap performed.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of source tokens.\n * @param destAmount The amount of destiny tokens.\n * @param maxSlippage The maximum slippage limit.\n *\n * @return sourceToDestSwapRate The swap rate between tokens.\n * */\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) public view returns (uint256 sourceToDestSwapRate) {\n require(!globalPricingPaused, \"pricing is paused\");\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n sourceToDestSwapRate = destAmount.mul(precision).div(sourceAmount);\n\n if (rate > sourceToDestSwapRate) {\n uint256 spreadValue = rate - sourceToDestSwapRate;\n spreadValue = spreadValue.mul(10**20).div(sourceToDestSwapRate);\n require(spreadValue <= maxSlippage, \"price disagreement\");\n }\n }\n\n /**\n * @notice Calculate the rBTC amount equivalent to a given token amount.\n * Native coin on RSK is rBTC. This code comes from Ethereum applications,\n * so Eth refers to 10**18 weis of native coin, i.e.: 1 rBTC.\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n *\n * @return ethAmount The amount of rBTC equivalent.\n * */\n function amountInEth(address tokenAddress, uint256 amount)\n public\n view\n returns (uint256 ethAmount)\n {\n /// Token is wrBTC, amount in rBTC is the same.\n if (tokenAddress == address(wrbtcToken)) {\n ethAmount = amount;\n } else {\n (uint256 toEthRate, uint256 toEthPrecision) =\n queryRate(tokenAddress, address(wrbtcToken));\n ethAmount = amount.mul(toEthRate).div(toEthPrecision);\n }\n }\n\n /**\n * @notice Calculate the maximum drawdown of a loan.\n *\n * A drawdown is commonly defined as the decline from a high peak to a\n * pullback low of a specific investment or equity in an account.\n *\n * Drawdown magnitude refers to the amount of value that a user loses\n * during the drawdown period.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param margin The relation between the position size and the loan.\n * margin = (total position size - loan) / loan\n *\n * @return maxDrawdown The maximum drawdown.\n * */\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 margin\n ) public view returns (uint256 maxDrawdown) {\n uint256 loanToCollateralAmount;\n if (collateralToken == loanToken) {\n loanToCollateralAmount = loanAmount;\n } else {\n (uint256 rate, uint256 precision) = queryRate(loanToken, collateralToken);\n loanToCollateralAmount = loanAmount.mul(rate).div(precision);\n }\n\n uint256 combined =\n loanToCollateralAmount.add(loanToCollateralAmount.mul(margin).div(10**20));\n\n maxDrawdown = collateralAmount > combined ? collateralAmount - combined : 0;\n }\n\n /**\n * @notice Calculate the margin and the collateral on rBTC.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralInEthAmount The amount of collateral on rBTC.\n * */\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralInEthAmount) {\n (currentMargin, ) = getCurrentMargin(\n loanToken,\n collateralToken,\n loanAmount,\n collateralAmount\n );\n\n collateralInEthAmount = amountInEth(collateralToken, collateralAmount);\n }\n\n /**\n * @notice Calculate the margin of a loan.\n *\n * @dev current margin = (total position size - loan) / loan\n * The collateral amount passed as parameter equals the total position size.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralToLoanRate The price ratio between collateral and\n * loan tokens.\n * */\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralToLoanRate) {\n uint256 collateralToLoanAmount;\n if (collateralToken == loanToken) {\n collateralToLoanAmount = collateralAmount;\n collateralToLoanRate = 10**18;\n } else {\n uint256 collateralToLoanPrecision;\n (collateralToLoanRate, collateralToLoanPrecision) = queryRate(\n collateralToken,\n loanToken\n );\n\n collateralToLoanRate = collateralToLoanRate.mul(10**18).div(collateralToLoanPrecision);\n\n collateralToLoanAmount = collateralAmount.mul(collateralToLoanRate).div(10**18);\n }\n\n if (loanAmount != 0 && collateralToLoanAmount >= loanAmount) {\n return (\n collateralToLoanAmount.sub(loanAmount).mul(10**20).div(loanAmount),\n collateralToLoanRate\n );\n } else {\n return (0, collateralToLoanRate);\n }\n }\n\n /**\n * @notice Get assessment about liquidating a loan.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param maintenanceMargin The minimum margin before liquidation.\n *\n * @return True/false to liquidate the loan.\n * */\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) public view returns (bool) {\n (uint256 currentMargin, ) =\n getCurrentMargin(loanToken, collateralToken, loanAmount, collateralAmount);\n\n return currentMargin <= maintenanceMargin;\n }\n\n /*\n * Owner functions\n */\n\n /**\n * @notice Set new value for protocolTokenEthPrice\n *\n * @param newPrice The new value for protocolTokenEthPrice\n * */\n function setProtocolTokenEthPrice(uint256 newPrice) external onlyOwner {\n require(newPrice != 0, \"invalid price\");\n protocolTokenEthPrice = newPrice;\n }\n\n /**\n * @notice Populate pricesFeeds mapping w/ values from feeds[]\n *\n * @param tokens The array of tokens to loop and get addresses.\n * @param feeds The array of contract instances for every token.\n * */\n function setPriceFeed(address[] calldata tokens, IPriceFeedsExt[] calldata feeds)\n external\n onlyOwner\n {\n require(tokens.length == feeds.length, \"count mismatch\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n pricesFeeds[tokens[i]] = feeds[i];\n }\n }\n\n /**\n * @notice Populate decimals mapping w/ values from tokens[].decimals\n *\n * @param tokens The array of tokens to loop and get values from.\n * */\n function setDecimals(IERC20[] calldata tokens) external onlyOwner {\n for (uint256 i = 0; i < tokens.length; i++) {\n decimals[address(tokens[i])] = tokens[i].decimals();\n }\n }\n\n /**\n * @notice Set flag globalPricingPaused\n *\n * @param isPaused The new status of pause (true/false).\n * */\n function setGlobalPricingPaused(bool isPaused) external onlyOwner {\n if (globalPricingPaused != isPaused) {\n globalPricingPaused = isPaused;\n\n emit GlobalPricingPaused(msg.sender, isPaused);\n }\n }\n\n /*\n * Internal functions\n */\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n /// Different tokens, query prices and perform division.\n if (sourceToken != destToken) {\n uint256 sourceRate;\n if (sourceToken != address(baseToken) && sourceToken != protocolTokenAddress) {\n IPriceFeedsExt _sourceFeed = pricesFeeds[sourceToken];\n require(address(_sourceFeed) != address(0), \"unsupported src feed\");\n\n /// Query token price on priceFeedsExt instance.\n sourceRate = _sourceFeed.latestAnswer();\n require(sourceRate != 0 && (sourceRate >> 128) == 0, \"price error\");\n } else {\n sourceRate = sourceToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n uint256 destRate;\n if (destToken != address(baseToken) && destToken != protocolTokenAddress) {\n IPriceFeedsExt _destFeed = pricesFeeds[destToken];\n require(address(_destFeed) != address(0), \"unsupported dst feed\");\n\n /// Query token price on priceFeedsExt instance.\n destRate = _destFeed.latestAnswer();\n require(destRate != 0 && (destRate >> 128) == 0, \"price error\");\n } else {\n destRate = destToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n rate = sourceRate.mul(10**18).div(destRate);\n\n precision = _getDecimalPrecision(sourceToken, destToken);\n\n /// Same tokens, return 1 with decimals.\n } else {\n rate = 10**18;\n precision = 10**18;\n }\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function _getDecimalPrecision(address sourceToken, address destToken)\n internal\n view\n returns (uint256)\n {\n /// Same tokens, return 1 with decimals.\n if (sourceToken == destToken) {\n return 10**18;\n\n /// Different tokens, query ERC20 precisions and return 18 +- diff.\n } else {\n uint256 sourceTokenDecimals = decimals[sourceToken];\n if (sourceTokenDecimals == 0) sourceTokenDecimals = IERC20(sourceToken).decimals();\n\n uint256 destTokenDecimals = decimals[destToken];\n if (destTokenDecimals == 0) destTokenDecimals = IERC20(destToken).decimals();\n\n if (destTokenDecimals >= sourceTokenDecimals)\n return 10**(SafeMath.sub(18, destTokenDecimals - sourceTokenDecimals));\n else return 10**(SafeMath.add(18, sourceTokenDecimals - destTokenDecimals));\n }\n }\n}\n" + }, + "contracts/feeds/PriceFeedsConstants.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The Price Feeds Constants contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract keep the addresses of token instances for wrBTC, base token\n * and protocol token.\n * */\ncontract Constants {\n IWrbtcERC20 public wrbtcToken;\n IWrbtcERC20 public baseToken;\n address internal protocolTokenAddress;\n\n /**\n * @notice Set wrBTC token address.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * */\n function _setWrbtcToken(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"_wrbtcTokenAddress not a contract\");\n wrbtcToken = IWrbtcERC20(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Set protocol token address.\n *\n * @param _protocolTokenAddress The address of the protocol token.\n * */\n function _setProtocolTokenAddress(address _protocolTokenAddress) internal {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n protocolTokenAddress = _protocolTokenAddress;\n }\n\n /**\n * @notice Set base token address.\n *\n * @param _baseTokenAddress The address of the base token.\n * */\n function _setBaseToken(address _baseTokenAddress) internal {\n require(Address.isContract(_baseTokenAddress), \"_baseTokenAddress not a contract\");\n baseToken = IWrbtcERC20(_baseTokenAddress);\n }\n}\n" + }, + "contracts/feeds/PriceFeedV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IV1PoolOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./IPriceFeeds.sol\";\n\n/**\n * @notice The Price Feed V1 Pool Oracle contract.\n *\n * This contract implements V1 Pool Oracle query functionality,\n * getting the price from v1 pool oracle.\n * */\ncontract PriceFeedV1PoolOracle is IPriceFeedsExt, Ownable {\n using SafeMath for uint256;\n /* Storage */\n\n address public v1PoolOracleAddress;\n address public wRBTCAddress;\n address public docAddress;\n address public baseCurrency;\n\n /* Events */\n event SetV1PoolOracleAddress(address indexed v1PoolOracleAddress, address changerAddress);\n event SetWRBTCAddress(address indexed wRBTCAddress, address changerAddress);\n event SetDOCAddress(address indexed docAddress, address changerAddress);\n event SetBaseCurrency(address indexed baseCurrency, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new V1 Pool Oracle.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n * @param _wRBTCAddress The wrbtc token address.\n * @param _docAddress The doc token address.\n * */\n constructor(\n address _v1PoolOracleAddress,\n address _wRBTCAddress,\n address _docAddress,\n address _baseCurrency\n ) public {\n setRBTCAddress(_wRBTCAddress);\n setDOCAddress(_docAddress);\n setV1PoolOracleAddress(_v1PoolOracleAddress);\n setBaseCurrency(_baseCurrency);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256) {\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(v1PoolOracleAddress);\n\n uint256 _price = _v1PoolOracle.latestPrice(baseCurrency);\n\n // Need to convert to USD, since the V1 pool return value is based on BTC\n uint256 priceInUSD = _convertAnswerToUsd(_price);\n require(priceInUSD != 0, \"price error\");\n\n return priceInUSD;\n }\n\n function _convertAnswerToUsd(uint256 _valueInBTC) private view returns (uint256) {\n address _priceFeeds = msg.sender;\n\n uint256 precision = IPriceFeeds(_priceFeeds).queryPrecision(wRBTCAddress, docAddress);\n uint256 valueInUSD =\n IPriceFeeds(_priceFeeds).queryReturn(wRBTCAddress, docAddress, _valueInBTC);\n\n /// Need to multiply by query precision (doc's precision) and divide by 1*10^18 (Because the based price in v1 pool is using 18 decimals)\n return valueInUSD.mul(precision).div(1e18);\n }\n\n /**\n * @notice Set the V1 Pool Oracle address.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n */\n function setV1PoolOracleAddress(address _v1PoolOracleAddress) public onlyOwner {\n require(Address.isContract(_v1PoolOracleAddress), \"_v1PoolOracleAddress not a contract\");\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(_v1PoolOracleAddress);\n address liquidityPool = _v1PoolOracle.liquidityPool();\n require(\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(0) == wRBTCAddress ||\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(1) == wRBTCAddress,\n \"one of the two reserves needs to be wrbtc\"\n );\n v1PoolOracleAddress = _v1PoolOracleAddress;\n emit SetV1PoolOracleAddress(v1PoolOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the rBtc address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the rBtc\n *\n * @param _wRBTCAddress The rBTC address\n */\n function setRBTCAddress(address _wRBTCAddress) public onlyOwner {\n require(_wRBTCAddress != address(0), \"wRBTC address cannot be zero address\");\n wRBTCAddress = _wRBTCAddress;\n emit SetWRBTCAddress(wRBTCAddress, msg.sender);\n }\n\n /**\n * @notice Set the DoC address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the DoC\n *\n * @param _docAddress The DoC address\n */\n function setDOCAddress(address _docAddress) public onlyOwner {\n require(_docAddress != address(0), \"DOC address cannot be zero address\");\n docAddress = _docAddress;\n emit SetDOCAddress(_docAddress, msg.sender);\n }\n\n /**\n * @notice Set the base currency address. That's the reserve address which is not WRBTC\n *\n * @param _baseCurrency The base currency address\n */\n function setBaseCurrency(address _baseCurrency) public onlyOwner {\n require(_baseCurrency != address(0), \"Base currency address cannot be zero address\");\n baseCurrency = _baseCurrency;\n emit SetBaseCurrency(_baseCurrency, msg.sender);\n }\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsLocal.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\n\n/**\n * @title Price Feeds Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the logic of setting and getting rates between two tokens.\n * */\ncontract PriceFeedsLocal is PriceFeeds {\n mapping(address => mapping(address => uint256)) public rates;\n\n /// uint256 public slippageMultiplier = 100 ether;\n\n /**\n * @notice Deploy local price feed contract.\n *\n * @param _wrbtcTokenAddress The address of the wrBTC instance.\n * @param _protocolTokenAddress The address of the protocol token instance.\n * */\n constructor(address _wrbtcTokenAddress, address _protocolTokenAddress)\n public\n PriceFeeds(_wrbtcTokenAddress, _protocolTokenAddress, _wrbtcTokenAddress)\n {}\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n if (sourceToken == destToken) {\n rate = 10**18;\n precision = 10**18;\n } else {\n if (sourceToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = protocolTokenEthPrice;\n } else if (destToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = SafeMath.div(10**36, protocolTokenEthPrice);\n } else {\n if (rates[sourceToken][destToken] != 0) {\n rate = rates[sourceToken][destToken];\n } else {\n uint256 sourceToEther =\n rates[sourceToken][address(wrbtcToken)] != 0\n ? rates[sourceToken][address(wrbtcToken)]\n : 10**18;\n uint256 etherToDest =\n rates[address(wrbtcToken)][destToken] != 0\n ? rates[address(wrbtcToken)][destToken]\n : 10**18;\n\n rate = sourceToEther.mul(etherToDest).div(10**18);\n }\n }\n precision = _getDecimalPrecision(sourceToken, destToken);\n }\n }\n\n /**\n * @notice Owner set price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param rate The price ratio source/dest.\n * */\n function setRates(\n address sourceToken,\n address destToken,\n uint256 rate\n ) public onlyOwner {\n if (sourceToken != destToken) {\n rates[sourceToken][destToken] = rate;\n rates[destToken][sourceToken] = SafeMath.div(10**36, rate);\n }\n }\n\n /*function setSlippageMultiplier(\n uint256 _slippageMultiplier)\n public\n onlyOwner\n {\n require (slippageMultiplier != _slippageMultiplier && _slippageMultiplier <= 100 ether);\n slippageMultiplier = _slippageMultiplier;\n }*/\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsMoC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\nimport \"../IRSKOracle.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\ninterface Medianizer {\n function peek() external view returns (bytes32, bool);\n}\n\n/**\n * @title Price Feed of MoC (Money on Chain) contract.\n *\n * This contract contains the logic to set MoC oracles\n * and query last price update.\n * */\ncontract PriceFeedsMoC is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public mocOracleAddress;\n address public rskOracleAddress;\n\n /* Events */\n\n event SetMoCOracleAddress(address indexed mocOracleAddress, address changerAddress);\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new MoC Oracle.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _mocOracleAddress, address _rskOracleAddress) public {\n setMoCOracleAddress(_mocOracleAddress);\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestAnswer() external view returns (uint256) {\n (bytes32 value, bool hasValue) = Medianizer(mocOracleAddress).peek();\n if (hasValue) {\n return uint256(value);\n } else {\n (uint256 price, ) = IRSKOracle(rskOracleAddress).getPricing();\n return price;\n }\n }\n\n /**\n * @notice Set the MoC Oracle address.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n */\n function setMoCOracleAddress(address _mocOracleAddress) public onlyOwner {\n require(Address.isContract(_mocOracleAddress), \"_mocOracleAddress not a contract\");\n mocOracleAddress = _mocOracleAddress;\n emit SetMoCOracleAddress(mocOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/USDTPriceFeed.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./PriceFeeds.sol\";\n\n/**\n * @notice The Price Feed USDT contract.\n *\n * This contract implements USDT query functionality,\n * getting the price and the last timestamp from a\n * trivial formula, always returning 1 and now.\n * */\ncontract USDTPriceFeed is IPriceFeedsExt {\n uint256 private constant USDT_RATE = 1 ether;\n\n /**\n * @notice Get the USDT price.\n *\n * @return Always returns the trivial rate of 1.\n * */\n function latestAnswer() external view returns (uint256) {\n return USDT_RATE;\n }\n\n /**\n * @notice Get the las time the price was updated.\n * @return Always trivial current block's timestamp.\n */\n function latestTimestamp() external view returns (uint256) {\n return now;\n }\n}\n" + }, + "contracts/governance/ApprovalReceiver.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./ErrorDecoder.sol\";\nimport \"../token/IApproveAndCall.sol\";\n\n/**\n * @title Base contract for receiving approval from SOV token.\n */\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\n modifier onlyThisContract() {\n // Accepts calls only from receiveApproval function.\n require(msg.sender == address(this), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external {\n // Accepts calls only from SOV token.\n require(msg.sender == _getToken(), \"unauthorized\");\n require(msg.sender == _token, \"unauthorized\");\n\n // Only allowed methods.\n bool isAllowed = false;\n bytes4[] memory selectors = _getSelectors();\n bytes4 sig = _getSig(_data);\n for (uint256 i = 0; i < selectors.length; i++) {\n if (sig == selectors[i]) {\n isAllowed = true;\n break;\n }\n }\n require(isAllowed, \"method is not allowed\");\n\n // Check sender and amount.\n address sender;\n uint256 amount;\n (, sender, amount) = abi.decode(\n abi.encodePacked(bytes28(0), _data),\n (bytes32, address, uint256)\n );\n require(sender == _sender, \"sender mismatch\");\n require(amount == _amount, \"amount mismatch\");\n\n _call(_data);\n }\n\n /**\n * @notice Returns token address, only this address can be a sender for receiveApproval.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, 0x. When overriden, the token address making the call.\n */\n function _getToken() internal view returns (address) {\n return address(0);\n }\n\n /**\n * @notice Returns list of function selectors allowed to be invoked.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, empty array. When overriden, allowed selectors.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n return new bytes4[](0);\n }\n\n /**\n * @notice Makes call and reverts w/ enhanced error message.\n * @param _data Error message as bytes.\n */\n function _call(bytes memory _data) internal {\n (bool success, bytes memory returnData) = address(this).call(_data);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"receiveApproval: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"receiveApproval: \", string(returnData)));\n }\n }\n }\n\n /**\n * @notice Extracts the called function selector, a hash of the signature.\n * @dev The first four bytes of the call data for a function call specifies\n * the function to be called. It is the first (left, high-order in big-endian)\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\n * Example:\n * msg.data:\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\n * 000450000000000000000000000000000000000000000000000000000000000000001\n * selector (or method ID): 0xcdcd77c0\n * signature: baz(uint32,bool)\n * @param _data The msg.data from the low level call.\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\n */\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\n assembly {\n sig := mload(add(_data, 32))\n }\n }\n}\n" + }, + "contracts/governance/ErrorDecoder.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base contract to properly handle returned data on failed calls\n * @dev On EVM if the return data length of a call is less than 68,\n * then the transaction fails silently without a revert message!\n *\n * As described in the Solidity documentation\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\n * the revert reason is an ABI-encoded string consisting of:\n * 0x08c379a0 // Function selector (method id) for \"Error(string)\" signature\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\n *\n * Another example, debug data from test:\n * 0x08c379a0\n * 0000000000000000000000000000000000000000000000000000000000000020\n * 0000000000000000000000000000000000000000000000000000000000000034\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n *\n * Parsed into:\n * Data offset: 20\n * Length: 34\n * Error message:\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n */\ncontract ErrorDecoder {\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\n\n /**\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\n * @param str1 First string, usually a hardcoded context written by dev.\n * @param str2 Second string, usually the error message from the reverted call.\n * @return The concatenated error string\n */\n function _addErrorMessage(string memory str1, string memory str2)\n internal\n pure\n returns (string memory)\n {\n bytes memory bytesStr1 = bytes(str1);\n bytes memory bytesStr2 = bytes(str2);\n string memory str12 =\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\n bytes memory bytesStr12 = bytes(str12);\n uint256 j = 0;\n for (uint256 i = 0; i < bytesStr1.length; i++) {\n bytesStr12[j++] = bytesStr1[i];\n }\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\n bytesStr12[j++] = bytesStr2[i];\n }\n return string(bytesStr12);\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../Staking/SafeMath96.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../interfaces/IConverterAMM.sol\";\n\n/**\n * @title The FeeSharingCollector contract.\n * @notice This contract withdraws fees to be paid to SOV Stakers from the protocol.\n * Stakers call withdraw() to get their share of the fees.\n *\n * @notice Staking is not only granting voting rights, but also access to fee\n * sharing according to the own voting power in relation to the total. Whenever\n * somebody decides to collect the fees from the protocol, they get transferred\n * to a proxy contract which invests the funds in the lending pool and keeps\n * the pool tokens.\n *\n * The fee sharing proxy will be set as feesController of the protocol contract.\n * This allows the fee sharing proxy to withdraw the fees. The fee sharing\n * proxy holds the pool tokens and keeps track of which user owns how many\n * tokens. In order to know how many tokens a user owns, the fee sharing proxy\n * needs to know the user’s weighted stake in relation to the total weighted\n * stake (aka total voting power).\n *\n * Because both values are subject to change, they may be different on each fee\n * withdrawal. To be able to calculate a user’s share of tokens when he wants\n * to withdraw, we need checkpoints.\n *\n * This contract is intended to be set as the protocol fee collector.\n * Anybody can invoke the withdrawFees function which uses\n * protocol.withdrawFees to obtain available fees from operations on a\n * certain token. These fees are deposited in the corresponding loanPool.\n * Also, the staking contract sends slashed tokens to this contract.\n * When a user calls the withdraw function, the contract transfers the fee sharing\n * rewards in proportion to the user’s weighted stake since the last withdrawal.\n *\n * The protocol initially collects fees in all tokens.\n * Then the FeeSharingCollector wihtdraws fees from the protocol.\n * When the fees are withdrawn all the tokens except SOV will be converted to wRBTC\n * and then transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n * */\ncontract FeeSharingCollector is\n SafeMath96,\n IFeeSharingCollector,\n Ownable,\n FeeSharingCollectorStorage\n{\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n address constant ZERO_ADDRESS = address(0);\n address public constant RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT =\n address(uint160(uint256(keccak256(\"RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\"))));\n\n /* Events */\n\n /// @notice Deprecated event after the unification between wrbtc & rbtc\n // event FeeWithdrawn(address indexed sender, address indexed token, uint256 amount);\n event FeeWithdrawnInRBTC(address indexed sender, uint256 amount);\n\n /// @notice An event emitted when tokens transferred.\n event TokensTransferred(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when checkpoint added.\n event CheckpointAdded(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeWithdrawn(\n address indexed sender,\n address indexed receiver,\n address indexed token,\n uint256 amount\n );\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeProcessedNoWithdraw(\n address indexed sender,\n address indexed token,\n uint256 prevProcessedCheckpoints,\n uint256 newProcessedCheckpoints\n );\n\n /**\n * @notice An event emitted when fee from AMM get withdrawn.\n *\n * @param sender sender who initiate the withdrawn amm fees.\n * @param converter the converter address.\n * @param amount total amount of fee (Already converted to WRBTC).\n */\n event FeeAMMWithdrawn(address indexed sender, address indexed converter, uint256 amount);\n\n /// @notice An event emitted when converter address has been registered to be whitelisted.\n event WhitelistedConverter(address indexed sender, address converter);\n\n /// @notice An event emitted when converter address has been removed from whitelist.\n event UnwhitelistedConverter(address indexed sender, address converter);\n\n event RBTCWithdrawn(address indexed sender, address indexed receiver, uint256 amount);\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWrbtcToken,\n address indexed newWrbtcToken\n );\n\n event SetLoanTokenWrbtc(\n address indexed sender,\n address indexed oldLoanTokenWrbtc,\n address indexed newLoanTokenWrbtc\n );\n\n /* Modifier */\n modifier oneTimeExecution(bytes4 _funcSig) {\n require(\n !isFunctionExecuted[_funcSig],\n \"FeeSharingCollector: function can only be called once\"\n );\n _;\n isFunctionExecuted[_funcSig] = true;\n }\n\n /* Functions */\n\n /// @dev fallback function to support rbtc transfer when unwrap the wrbtc.\n function() external payable {}\n\n /**\n * @dev initialize function for fee sharing collector proxy\n * @param wrbtcToken wrbtc token address\n * @param loanWrbtcToken address of loan token wrbtc (IWrbtc)\n */\n function initialize(address wrbtcToken, address loanWrbtcToken)\n external\n onlyOwner\n oneTimeExecution(this.initialize.selector)\n {\n require(\n wrbtcTokenAddress == address(0) && loanTokenWrbtcAddress == address(0),\n \"wrbtcToken or loanWrbtcToken has been initialized\"\n );\n setWrbtcToken(wrbtcToken);\n setLoanTokenWrbtc(loanWrbtcToken);\n }\n\n /**\n * @notice Set the wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newWrbtcTokenAddress The new address of the wrbtc token.\n * */\n function setWrbtcToken(address newWrbtcTokenAddress) public onlyOwner {\n require(Address.isContract(newWrbtcTokenAddress), \"newWrbtcTokenAddress not a contract\");\n emit SetWrbtcToken(msg.sender, wrbtcTokenAddress, newWrbtcTokenAddress);\n wrbtcTokenAddress = newWrbtcTokenAddress;\n }\n\n /**\n * @notice Set the loan wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newLoanTokenWrbtcAddress The new address of the loan wrbtc token.\n * */\n function setLoanTokenWrbtc(address newLoanTokenWrbtcAddress) public onlyOwner {\n require(\n Address.isContract(newLoanTokenWrbtcAddress),\n \"newLoanTokenWrbtcAddress not a contract\"\n );\n emit SetLoanTokenWrbtc(msg.sender, loanTokenWrbtcAddress, newLoanTokenWrbtcAddress);\n loanTokenWrbtcAddress = newLoanTokenWrbtcAddress;\n }\n\n /**\n * @notice Withdraw fees for the given token:\n * lendingFee + tradingFee + borrowingFee\n * the fees (except SOV) will be converted in wRBTC form, and then will be transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n *\n * @param _tokens array address of the token\n * */\n function withdrawFees(address[] calldata _tokens) external {\n for (uint256 i = 0; i < _tokens.length; i++) {\n require(\n Address.isContract(_tokens[i]),\n \"FeeSharingCollector::withdrawFees: token is not a contract\"\n );\n }\n\n uint256 wrbtcAmountWithdrawn = protocol.withdrawFees(_tokens, address(this));\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap the wrbtc to rbtc, and hold the rbtc.\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFees: wrbtc token amount exceeds 96 bits\"\n );\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, amount96);\n }\n\n // note deprecated event since we unify the wrbtc & rbtc\n // emit FeeWithdrawn(msg.sender, RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, poolTokenAmount);\n\n // note new emitted event\n emit FeeWithdrawnInRBTC(msg.sender, wrbtcAmountWithdrawn);\n }\n\n /**\n * @notice Withdraw amm fees for the given converter addresses:\n * protocolFee from the conversion\n * the fees will be converted in wRBTC form, and then will be transferred to wRBTC loan pool\n *\n * @param _converters array addresses of the converters\n * */\n function withdrawFeesAMM(address[] memory _converters) public {\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n // Validate\n _validateWhitelistedConverter(_converters);\n\n uint96 totalPoolTokenAmount;\n for (uint256 i = 0; i < _converters.length; i++) {\n uint256 wrbtcAmountWithdrawn =\n IConverterAMM(_converters[i]).withdrawFees(address(this));\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap wrbtc to rbtc, and hold the rbtc\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFeesAMM: wrbtc token amount exceeds 96 bits\"\n );\n\n totalPoolTokenAmount = add96(\n totalPoolTokenAmount,\n amount96,\n \"FeeSharingCollector::withdrawFeesAMM: total wrbtc token amount exceeds 96 bits\"\n );\n\n emit FeeAMMWithdrawn(msg.sender, _converters[i], wrbtcAmountWithdrawn);\n }\n }\n\n if (totalPoolTokenAmount > 0) {\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, totalPoolTokenAmount);\n }\n }\n\n /**\n * @notice Transfer tokens to this contract.\n * @dev We just update amount of tokens here and write checkpoint in a separate methods\n * in order to prevent adding checkpoints too often.\n * @param _token Address of the token.\n * @param _amount Amount to be transferred.\n * */\n function transferTokens(address _token, uint96 _amount) public {\n require(_token != ZERO_ADDRESS, \"FeeSharingCollector::transferTokens: invalid address\");\n require(_amount > 0, \"FeeSharingCollector::transferTokens: invalid amount\");\n\n /// @notice Transfer tokens from msg.sender\n bool success = IERC20(_token).transferFrom(address(msg.sender), address(this), _amount);\n require(success, \"Staking::transferTokens: token transfer failed\");\n\n // if _token is wrbtc, need to unwrap it to rbtc\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n if (_token == address(wrbtcToken)) {\n wrbtcToken.withdraw(_amount);\n _token = RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT;\n }\n\n _addCheckpoint(_token, _amount);\n\n emit TokensTransferred(msg.sender, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC / native tokens to this contract.\n * @dev We just write checkpoint here (based on the rbtc value that is sent) in a separate methods\n * in order to prevent adding checkpoints too often.\n * */\n function transferRBTC() external payable {\n uint96 _amount = uint96(msg.value);\n require(_amount > 0, \"FeeSharingCollector::transferRBTC: invalid value\");\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, _amount);\n\n emit TokensTransferred(msg.sender, ZERO_ADDRESS, _amount);\n }\n\n /**\n * @notice Add checkpoint with accumulated amount by function invocation.\n * @param _token Address of the token.\n * */\n function _addCheckpoint(address _token, uint96 _amount) internal {\n if (block.timestamp - lastFeeWithdrawalTime[_token] >= FEE_WITHDRAWAL_INTERVAL) {\n lastFeeWithdrawalTime[_token] = block.timestamp;\n uint96 amount =\n add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: amount exceeds 96 bits\"\n );\n\n /// @notice Reset unprocessed amount of tokens to zero.\n unprocessedAmount[_token] = 0;\n\n /// @notice Write a regular checkpoint.\n _writeTokenCheckpoint(_token, amount);\n } else {\n unprocessedAmount[_token] = add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: unprocessedAmount exceeds 96 bits\"\n );\n }\n }\n\n function _withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n /// @dev Prevents block gas limit hit when processing checkpoints\n require(\n _maxCheckpoints > 0,\n \"FeeSharingCollector::withdraw: _maxCheckpoints should be positive\"\n );\n\n address user = msg.sender;\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n uint256 processedUserCheckpoints = processedCheckpoints[user][_token];\n (uint256 amount, uint256 end) =\n _getAccumulatedFees(user, _token, processedUserCheckpoints, _maxCheckpoints);\n if (amount == 0) {\n if (end > processedUserCheckpoints) {\n emit UserFeeProcessedNoWithdraw(msg.sender, _token, processedUserCheckpoints, end);\n processedCheckpoints[user][_token] = end;\n return (0, end);\n } else {\n // getting here most likely means smth wrong with the state\n revert(\"FeeSharingCollector::withdrawFees: no tokens for withdrawal\");\n }\n }\n\n processedCheckpoints[user][_token] = end;\n if (loanTokenWrbtcAddress == _token) {\n // We will change, so that feeSharingCollector will directly burn then loanToken (IWRBTC) to rbtc and send to the user --- by call burnToBTC function\n ILoanTokenWRBTC(_token).burnToBTC(_receiver, amount, false);\n } else {\n // Previously it directly send the loanToken to the user\n require(\n IERC20(_token).transfer(_receiver, amount),\n \"FeeSharingCollector::withdraw: withdrawal failed\"\n );\n }\n\n emit UserFeeWithdrawn(msg.sender, _receiver, _token, amount);\n\n return (amount, end);\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power. Therefore, staking more\n * SOV and/or staking for longer will increase your share of the fees\n * generated, meaning you will earn more from staking.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed. Must be positive value.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public nonReentrant {\n _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n /// @notice Validates if the checkpoint is payable for the user\n function validFromCheckpointsParam(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n address _user\n ) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n // _fromCheckpoint is checkpoint number, not array index, so should be > 1\n require(tokenData.fromCheckpoint > 1, \"_fromCheckpoint param must be > 1\");\n uint256 fromCheckpointIndex = tokenData.fromCheckpoint - 1;\n require(\n tokenData.fromCheckpoint > processedCheckpoints[_user][tokenData.tokenAddress],\n \"_fromCheckpoint param must be > userProcessedCheckpoints\"\n );\n require(\n tokenData.fromCheckpoint <= totalTokenCheckpoints[tokenData.tokenAddress],\n \"_fromCheckpoint should be <= totalTokenCheckpoints\"\n );\n\n Checkpoint memory prevCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex - 1];\n\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n prevCheckpoint.blockNumber - 1,\n prevCheckpoint.timestamp\n );\n require(\n weightedStake == 0,\n \"User weighted stake should be zero at previous checkpoint\"\n );\n\n Checkpoint memory fromCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex];\n weightedStake = staking.getPriorWeightedStake(\n _user,\n fromCheckpoint.blockNumber - 1,\n fromCheckpoint.timestamp\n );\n\n require(weightedStake > 0, \"User weighted stake should be > 0 at _fromCheckpoint\");\n }\n }\n\n function validRBTCBasedTokens(address[] memory _tokens) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n address _token = _tokens[i];\n if (\n _token != RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT &&\n _token != wrbtcTokenAddress &&\n _token != loanTokenWrbtcAddress\n ) {\n revert(\"only rbtc-based tokens are allowed\");\n }\n }\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender/receiver.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @dev WARNING! This function skips all the checkpoints before '_fromCheckpoint' irreversibly, use with care\n *\n * @param _tokens Array of TokenWithSkippedCheckpointsWithdraw struct, which contains the token address, and fromCheckpoiint\n * fromCheckpoints Skips all the checkpoints before '_fromCheckpoint'\n * should be calculated offchain with getNextPositiveUserCheckpoint function\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n *\n * @return total processed checkpoints\n * */\n function _withdrawStartingFromCheckpoints(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validFromCheckpointsParam(_tokens, msg.sender);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n if (_maxCheckpoints == 0) break;\n uint256 endToken;\n uint256 totalAmount;\n\n uint256 previousProcessedUserCheckpoints =\n processedCheckpoints[msg.sender][tokenData.tokenAddress];\n uint256 startingCheckpoint =\n tokenData.fromCheckpoint > previousProcessedUserCheckpoints\n ? tokenData.fromCheckpoint\n : previousProcessedUserCheckpoints;\n\n if (\n tokenData.tokenAddress == wrbtcTokenAddress ||\n tokenData.tokenAddress == loanTokenWrbtcAddress ||\n tokenData.tokenAddress == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\n ) {\n (totalAmount, endToken) = _withdrawRbtcTokenStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n } else {\n (, endToken) = _withdrawStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n }\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint).add(1);\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n if (rbtcAmountToSend > 0) {\n // send all rbtc withdrawal\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Function to wrap:\n * 1. regular withdrawal for both rbtc & non-rbtc token\n * 2. skipped checkpoints withdrawal for both rbtc & non-rbtc token\n *\n * @param _nonRbtcTokensRegularWithdraw array of non-rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _rbtcTokensRegularWithdraw array of rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _tokensWithSkippedCheckpoints array of rbtc & non-rbtc TokenWithSkippedCheckpointsWithdraw struct, which has skipped checkpoints that will be withdrawn\n *\n */\n function claimAllCollectedFees(\n address[] calldata _nonRbtcTokensRegularWithdraw,\n address[] calldata _rbtcTokensRegularWithdraw,\n TokenWithSkippedCheckpointsWithdraw[] calldata _tokensWithSkippedCheckpoints,\n uint32 _maxCheckpoints,\n address _receiver\n ) external nonReentrant {\n uint256 totalProcessedCheckpoints;\n\n /** Process normal multiple withdrawal for RBTC based tokens */\n if (_rbtcTokensRegularWithdraw.length > 0) {\n totalProcessedCheckpoints = _withdrawRbtcTokens(\n _rbtcTokensRegularWithdraw,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process normal non-rbtc token withdrawal */\n for (uint256 i = 0; i < _nonRbtcTokensRegularWithdraw.length; i++) {\n if (_maxCheckpoints == 0) break;\n uint256 endTokenCheckpoint;\n\n address _nonRbtcTokenAddress = _nonRbtcTokensRegularWithdraw[i];\n\n /** starting checkpoint is the previous processedCheckpoints for token */\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_nonRbtcTokenAddress];\n\n (, endTokenCheckpoint) = _withdraw(_nonRbtcTokenAddress, _maxCheckpoints, _receiver);\n\n uint256 _previousUsedCheckpoint = endTokenCheckpoint.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n _previousUsedCheckpoint.add(1);\n }\n\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process token with skipped checkpoints withdrawal */\n if (_tokensWithSkippedCheckpoints.length > 0) {\n totalProcessedCheckpoints = _withdrawStartingFromCheckpoints(\n _tokensWithSkippedCheckpoints,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n }\n\n function _withdrawStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10 meaning we should set 9 user's processed checkpoints\n // after _withdraw() the user's processedCheckpoints should be 10\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n (totalAmount, endTokenCheckpoint) = _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function _withdrawRbtcToken(address _token, uint32 _maxCheckpoints)\n internal\n returns (uint256 totalAmount, uint256 endTokenCheckpoint)\n {\n address user = msg.sender;\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n (totalAmount, endTokenCheckpoint) = _getRBTCBalance(_token, user, _maxCheckpoints);\n\n if (totalAmount > 0) {\n processedCheckpoints[user][_token] = endTokenCheckpoint;\n if (_token == address(wrbtcToken)) {\n // unwrap the wrbtc\n wrbtcToken.withdraw(totalAmount);\n } else if (_token == loanTokenWrbtcAddress) {\n // pull out the iWRBTC to rbtc to this feeSharingCollector contract\n /** @dev will use the burned result from IWRBTC to RBTC as return total amount */\n totalAmount = ILoanTokenWRBTC(loanTokenWrbtcAddress).burnToBTC(\n address(this),\n totalAmount,\n false\n );\n }\n }\n }\n\n /**\n * @dev withdraw all of the RBTC balance based on particular checkpoints\n *\n * This function will withdraw RBTC balance which is passed as _token param, so it could be either of these:\n * - rbtc balance or\n * - wrbtc balance which will be unwrapped to rbtc or\n * - iwrbtc balance which will be unwrapped to rbtc or\n *\n *\n * @param _tokens array of either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _maxCheckpoints Maximum number of checkpoints to be processed to workaround block gas limit\n * @param _receiver An optional tokens receiver (msg.sender used if 0)\n */\n function _withdrawRbtcTokens(\n address[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validRBTCBasedTokens(_tokens);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n if (_maxCheckpoints == 0) break;\n address _token = _tokens[i];\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_token];\n\n (uint256 totalAmount, uint256 endToken) =\n _withdrawRbtcToken(_tokens[i], _maxCheckpoints);\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n // we only need to add used checkpoint by 1 only if starting checkpoint > 0\n _previousUsedCheckpoint.add(1);\n }\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n // send all rbtc\n if (rbtcAmountToSend > 0) {\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Withdraw either specific RBTC related token balance or all RBTC related tokens balances.\n * RBTC related here means, it could be either rbtc, wrbtc, or iwrbtc, depends on the _token param.\n */\n function _withdrawRbtcTokenStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) private returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10\n // after _withdraw() user's processedCheckpoints should be 10 =>\n // set processed checkpoints = 9, next maping index = 9 (10th checkpoint)\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n return _withdrawRbtcToken(_token, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n external\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n return _getNextPositiveUserCheckpoint(_user, _token, _startFrom, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function _getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n internal\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n if (staking.isVestingContract(_user)) {\n return (0, false, false);\n }\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n\n if (processedUserCheckpoints >= totalCheckpoints || totalCheckpoints == 0) {\n return (totalCheckpoints, false, false);\n }\n\n uint256 startFrom =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n\n uint256 end = startFrom.add(_maxCheckpoints);\n if (end >= totalCheckpoints) {\n end = totalCheckpoints;\n }\n\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startFrom; i < end; i++) {\n Checkpoint storage tokenCheckpoint = tokenCheckpoints[_token][i];\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n tokenCheckpoint.blockNumber - 1,\n tokenCheckpoint.timestamp\n );\n if (weightedStake > 0) {\n // i is the index and we need to return checkpoint num which is i + 1\n return (i + 1, i > processedUserCheckpoints, true);\n }\n }\n return (end, end > processedUserCheckpoints, false);\n }\n\n /**\n * @notice Get the accumulated loan pool fee of the message sender.\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @return The accumulated fee for the message sender.\n * */\n function getAccumulatedFees(address _user, address _token) public view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: 0\n });\n return amount;\n }\n\n /**\n * @notice Get the accumulated fee rewards for the message sender for a checkpoints range\n *\n * @dev This function is required to keep consistent with caching of weighted voting power when claiming fees\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The accumulated fees rewards for the _user in the given checkpoints interval: [_startFrom, _startFrom + maxCheckpoints].\n * */\n function getAccumulatedFeesForCheckpointsRange(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees(_user, _token, _startFrom, _maxCheckpoints);\n return amount;\n }\n\n /**\n * @dev Get all user fees reward per maxCheckpoint starting from latest processed checkpoint\n *\n * @dev e.g: Total user checkpoint for the particualar token = 300,\n * when we call this function with 50 maxCheckpoint, it will return 6 fee values in array form.\n * if there is no more fees, it will return empty array.\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The next checkpoint num which is the starting point to fetch all of the fees, array of calculated fees.\n * */\n function getAllUserFeesPerMaxCheckpoints(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256[] memory fees) {\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 totalTokensCheckpointsIndex = totalCheckpoints > 0 ? totalCheckpoints - 1 : 0;\n\n if (totalTokensCheckpointsIndex < _startFrom) return fees;\n\n uint256 arrSize = totalTokensCheckpointsIndex.sub(_startFrom).div(_maxCheckpoints) + 1;\n\n fees = new uint256[](arrSize);\n\n for (uint256 i = 0; i < fees.length; i++) {\n (uint256 fee, ) =\n _getAccumulatedFees(\n _user,\n _token,\n _startFrom + i * _maxCheckpoints,\n _maxCheckpoints\n );\n fees[i] = fee;\n }\n\n return fees;\n }\n\n /**\n * @notice Gets accumulated fees for a user starting from a given checkpoint\n *\n * @param _user Address of the user's account.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Max checkpoints to process at once to fit into block gas limit\n * @param _startFrom Checkpoint num to start calculations from\n *\n * @return feesAmount - accumulated fees amount\n * @return endCheckpoint - last checkpoint of fees calculation\n * */\n function _getAccumulatedFees(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 feesAmount, uint256 endCheckpoint) {\n if (staking.isVestingContract(_user)) {\n return (0, 0);\n }\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n uint256 startOfRange =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n endCheckpoint = _maxCheckpoints > 0\n ? _getEndOfRange(startOfRange, _token, _maxCheckpoints)\n : totalTokenCheckpoints[_token];\n\n if (startOfRange >= totalTokenCheckpoints[_token]) {\n return (0, endCheckpoint);\n }\n\n uint256 cachedLockDate = 0;\n uint96 cachedWeightedStake = 0;\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startOfRange; i < endCheckpoint; i++) {\n Checkpoint memory checkpoint = tokenCheckpoints[_token][i];\n uint256 lockDate = staking.timestampToLockDate(checkpoint.timestamp);\n uint96 weightedStake;\n if (lockDate == cachedLockDate) {\n weightedStake = cachedWeightedStake;\n } else {\n /// @dev We need to use \"checkpoint.blockNumber - 1\" here to calculate weighted stake\n /// For the same block like we did for total voting power in _writeTokenCheckpoint\n weightedStake = staking.getPriorWeightedStake(\n _user,\n checkpoint.blockNumber - 1,\n checkpoint.timestamp\n );\n cachedWeightedStake = weightedStake;\n cachedLockDate = lockDate;\n }\n uint256 share =\n uint256(checkpoint.numTokens).mul(weightedStake).div(\n uint256(checkpoint.totalWeightedStake)\n );\n feesAmount = feesAmount.add(share);\n }\n return (feesAmount, endCheckpoint);\n }\n\n /**\n * @notice Withdrawal should only be possible for blocks which were already\n * mined. If the fees are withdrawn in the same block as the user withdrawal\n * they are not considered by the withdrawing logic (to avoid inconsistencies).\n *\n * @param _start Start of the range.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of a pool token.\n * @param _maxCheckpoints Checkpoint index incremental.\n * */\n function _getEndOfRange(\n uint256 _start,\n address _token,\n uint32 _maxCheckpoints\n ) internal view returns (uint256) {\n uint256 nextCheckpointIndex = totalTokenCheckpoints[_token];\n if (nextCheckpointIndex == 0) {\n return 0;\n }\n uint256 end;\n\n if (_maxCheckpoints == 0) {\n /// @dev All checkpoints will be processed (only for getter outside of a transaction).\n end = nextCheckpointIndex;\n } else {\n end = safe32(\n _start + _maxCheckpoints,\n \"FeeSharingCollector::withdraw: checkpoint index exceeds 32 bits\"\n );\n if (end > nextCheckpointIndex) {\n end = nextCheckpointIndex;\n }\n }\n\n /// @dev Withdrawal should only be possible for blocks which were already mined.\n uint32 lastBlockNumber = tokenCheckpoints[_token][end - 1].blockNumber;\n if (block.number == lastBlockNumber) {\n end--;\n }\n return end;\n }\n\n /**\n * @notice Write a regular checkpoint w/ the foolowing data:\n * block number, block timestamp, total weighted stake and num of tokens.\n * @param _token The pool token address.\n * @param _numTokens The amount of pool tokens.\n * */\n function _writeTokenCheckpoint(address _token, uint96 _numTokens) internal {\n uint32 blockNumber =\n safe32(\n block.number,\n \"FeeSharingCollector::_writeCheckpoint: block number exceeds 32 bits\"\n );\n uint32 blockTimestamp =\n safe32(\n block.timestamp,\n \"FeeSharingCollector::_writeCheckpoint: block timestamp exceeds 32 bits\"\n );\n uint256 nextCheckpointsIndex = totalTokenCheckpoints[_token];\n\n uint96 totalWeightedStake = _getVoluntaryWeightedStake(blockNumber - 1, block.timestamp);\n require(totalWeightedStake > 0, \"Invalid totalWeightedStake\");\n if (\n nextCheckpointsIndex > 0 &&\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].blockNumber == blockNumber\n ) {\n tokenCheckpoints[_token][nextCheckpointsIndex - 1]\n .totalWeightedStake = totalWeightedStake;\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].numTokens = _numTokens;\n } else {\n tokenCheckpoints[_token][nextCheckpointsIndex] = Checkpoint(\n blockNumber,\n blockTimestamp,\n totalWeightedStake,\n _numTokens\n );\n totalTokenCheckpoints[_token] = nextCheckpointsIndex + 1;\n }\n emit CheckpointAdded(msg.sender, _token, _numTokens);\n }\n\n /**\n * Queries the total weighted stake and the weighted stake of vesting contracts and returns the difference\n * @param blockNumber the blocknumber\n * @param timestamp the timestamp\n */\n function _getVoluntaryWeightedStake(uint32 blockNumber, uint256 timestamp)\n internal\n view\n returns (uint96 totalWeightedStake)\n {\n uint96 vestingWeightedStake = staking.getPriorVestingWeightedStake(blockNumber, timestamp);\n totalWeightedStake = staking.getPriorTotalVotingPower(blockNumber, timestamp);\n totalWeightedStake = sub96(\n totalWeightedStake,\n vestingWeightedStake,\n \"FeeSharingCollector::_getTotalVoluntaryWeightedStake: vested stake exceeds total stake\"\n );\n }\n\n /**\n * @dev Whitelisting converter address.\n *\n * @param converterAddress converter address to be whitelisted.\n */\n function addWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n require(Address.isContract(converterAddress), \"Non contract address given\");\n whitelistedConverterList.add(converterAddress);\n emit WhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @dev Removing converter address from whitelist.\n *\n * @param converterAddress converter address to be removed from whitelist.\n */\n function removeWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n whitelistedConverterList.remove(converterAddress);\n emit UnwhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @notice Getter to query all of the whitelisted converter.\n * @return All of the whitelisted converter list.\n */\n function getWhitelistedConverterList() external view returns (address[] memory converterList) {\n converterList = whitelistedConverterList.enumerate();\n }\n\n /**\n * @dev validate array of given address whether is whitelisted or not.\n * @dev if one of them is not whitelisted, then revert.\n *\n * @param converterAddresses array of converter addresses.\n */\n function _validateWhitelistedConverter(address[] memory converterAddresses) private view {\n for (uint256 i = 0; i < converterAddresses.length; i++) {\n require(whitelistedConverterList.contains(converterAddresses[i]), \"Invalid Converter\");\n }\n }\n\n function withdrawWRBTC(address receiver, uint256 wrbtcAmount) external onlyOwner {\n IERC20 wrbtcToken = IERC20(wrbtcTokenAddress);\n\n uint256 balance = wrbtcToken.balanceOf(address(this));\n require(wrbtcAmount <= balance, \"Insufficient balance\");\n\n wrbtcToken.safeTransfer(receiver, wrbtcAmount);\n }\n\n /**\n * @dev This function is dedicated to recover the wrong fee allocation for the 4 year vesting contracts.\n * This function can only be called once\n * The affected tokens to be withdrawn\n * 1. RBTC\n * 2. ZUSD\n * 3. SOV\n * The amount for all of the tokens above is hardcoded\n * The withdrawn tokens will be sent to the owner.\n */\n function recoverIncorrectAllocatedFees()\n external\n oneTimeExecution(this.recoverIncorrectAllocatedFees.selector)\n onlyOwner\n {\n uint256 rbtcAmount = 878778886164898400;\n uint256 zusdAmount = 16658600400155126000000;\n uint256 sovAmount = 6275898259771202000000;\n\n address zusdToken = 0xdB107FA69E33f05180a4C2cE9c2E7CB481645C2d;\n address sovToken = 0xEFc78fc7d48b64958315949279Ba181c2114ABBd;\n\n // Withdraw rbtc\n (bool success, ) = owner().call.value(rbtcAmount)(\"\");\n require(\n success,\n \"FeeSharingCollector::recoverIncorrectAllocatedFees: Withdrawal rbtc failed\"\n );\n\n // Withdraw ZUSD\n IERC20(zusdToken).safeTransfer(owner(), zusdAmount);\n\n // Withdraw SOV\n IERC20(sovToken).safeTransfer(owner(), sovAmount);\n }\n\n /**\n * @dev view function that calculate the total RBTC that includes:\n * - RBTC\n * - WRBTC\n * - iWRBTC * iWRBTC.tokenPrice()\n * @param _user address of the user.\n * @return rbtc balance of the given user's address.\n */\n function getAccumulatedRBTCFeeBalances(address _user) external view returns (uint256) {\n (uint256 _rbtcAmount, uint256 _wrbtcAmount, uint256 _iWrbtcAmount, , , ) =\n _getRBTCBalances(_user, 0);\n uint256 iWRBTCAmountInRBTC =\n _iWrbtcAmount.mul(ILoanTokenWRBTC(loanTokenWrbtcAddress).tokenPrice()).div(1e18);\n return _rbtcAmount.add(_wrbtcAmount).add(iWRBTCAmountInRBTC);\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _rbtcAmount rbtc amount\n * @return _wrbtcAmount wrbtc amount\n * @return _iWrbtcAmount iWrbtc (wrbtc lending pool token) amount * token price\n * @return _endRBTC end time of accumulated fee calculation for rbtc\n * @return _endWRBTC end time of accumulated fee calculation for wrbtc\n * @return _endIWRBTC end time of accumulated fee calculation for iwrbtc\n */\n function _getRBTCBalances(address _user, uint32 _maxCheckpoints)\n private\n view\n returns (\n uint256 _rbtcAmount,\n uint256 _wrbtcAmount,\n uint256 _iWrbtcAmount,\n uint256 _endRBTC,\n uint256 _endWRBTC,\n uint256 _endIWRBTC\n )\n {\n (_rbtcAmount, _endRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n\n (_wrbtcAmount, _endWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: wrbtcTokenAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n (_iWrbtcAmount, _endIWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: loanTokenWrbtcAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _token either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _tokenAmount token (rbtc, or wrbtc, or iwrbtc) amount\n * @return _endToken end time of accumulated fee calculation for token (rbtc, or wrbtc, or iwrbtc )\n */\n function _getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 _tokenAmount, uint256 _endToken) {\n if (\n _token == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT ||\n _token == wrbtcTokenAddress ||\n _token == loanTokenWrbtcAddress\n ) {\n (_tokenAmount, _endToken) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n } else {\n revert(\"FeeSharingCollector::_getRBTCBalance: only rbtc-based tokens are allowed\");\n }\n }\n\n // @todo update dependency `numTokenCheckpoints` -> `totalTokenCheckpoints` and deprecate numTokenCheckpoints function\n /**\n * @dev This getter function `numTokenCheckpoints` is added for backwards compatibility\n * broken when renamed `numTokenCheckpoints` storage variable to `totalTokenCheckpoints`.\n *\n * @param _token token address to get checkpoints for\n *\n * @return Total token checkpoints\n */\n function numTokenCheckpoints(address _token) external view returns (uint256) {\n return totalTokenCheckpoints[_token];\n }\n}\n\n/* Interfaces */\ninterface ILoanToken {\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n}\n\ninterface ILoanTokenWRBTC {\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function tokenPrice() external view returns (uint256 price);\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title FeeSharingCollectorProxy contract.\n * @dev FeeSharingCollectorProxy contract should be upgradable, use UpgradableProxy.\n * FeeSharingCollectorStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract FeeSharingCollectorProxy is FeeSharingCollectorStorage, UpgradableProxy {\n /**\n * @notice Construct a new feeSharingCollectorProxy contract.\n * @param _protocol The address of the sovryn protocol.\n * @param _staking The address of the staking\n */\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorStorage.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../mixins/EnumerableAddressSet.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\n\n/**\n * @title FeeSharingCollectorStorage contact\n * @notice Just the storage part of FeeSharingCollector contract, and FeeSharingCollectorProxy. No functions,\n * only constant, variables and required structures (mappings)\n * */\ncontract FeeSharingCollectorStorage is Ownable {\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet;\n uint256 constant FEE_WITHDRAWAL_INTERVAL = 172800;\n\n IProtocol public protocol;\n IStaking public staking;\n\n /// @notice Checkpoints by index per pool token address\n mapping(address => mapping(uint256 => Checkpoint)) public tokenCheckpoints;\n\n /// @notice The number of checkpoints for each token address.\n mapping(address => uint256) public totalTokenCheckpoints;\n\n /// @notice\n /// user => token => processed checkpoints\n mapping(address => mapping(address => uint256)) public processedCheckpoints;\n\n /// @notice Last time fees were withdrawn per pool token address:\n /// token => time\n mapping(address => uint256) public lastFeeWithdrawalTime;\n\n /// @notice Amount of tokens that were transferred, but not saved in checkpoints.\n /// token => amount\n mapping(address => uint96) public unprocessedAmount;\n\n struct Checkpoint {\n uint32 blockNumber;\n uint32 timestamp;\n uint96 totalWeightedStake;\n uint96 numTokens;\n }\n\n struct TokenWithSkippedCheckpointsWithdraw {\n address tokenAddress;\n uint256 fromCheckpoint;\n }\n\n /**\n * @dev Add extra modifier (Reentrancy) below.\n * Because we cannot add any additional storage slot before this storage contract after initial deployment\n */\n\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Additional storage for converter whitelist mechanism.\n * @dev Initialization here does not works. We need to create a separate setter & getter.\n * @dev Just set the visibility to internal should be fine.\n */\n EnumerableAddressSet.AddressSet internal whitelistedConverterList;\n\n mapping(bytes4 => bool) public isFunctionExecuted;\n\n /**\n * @dev Wrbtc token address\n */\n address public wrbtcTokenAddress;\n\n /**\n * @dev iWrbtc loan token address\n */\n address public loanTokenWrbtcAddress;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n\n/* Interfaces */\n\ninterface IProtocol {\n /**\n *\n * @param tokens The array address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function underlyingToLoanPool(address token) external view returns (address);\n\n function wrbtcToken() external view returns (IWrbtcERC20);\n\n function getSovTokenAddress() external view returns (address);\n}\n" + }, + "contracts/governance/GovernorAlpha.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./Staking/SafeMath96.sol\";\nimport \"./Timelock.sol\";\nimport \"./Staking/interfaces/IStaking.sol\";\nimport \"../rsk/RSKAddrValidator.sol\";\n\n/**\n * @title Governance Contract.\n * @notice This is an adapted clone of compound’s governance model. In general,\n * the process is the same: Token holders can make (executable) proposals if\n * they possess enough voting power, vote on proposals during a predefined\n * voting period and in the end evaluate the outcome. If successful, the\n * proposal will be scheduled on the timelock contract. Only after sufficient\n * time passed, it can be executed. A minimum voting power is required for\n * making a proposal as well as a minimum quorum.\n *\n * Voting power in the Bitocracy:\n * Stakers will receive voting power in the Bitocracy in return for their\n * staking commitment. This voting power is weighted by how much SOV is staked\n * and for how long the staking period is - staking more SOV over longer staking\n * periods results in higher voting power. With this voting power, users can\n * vote for or against any SIP in bitocracy.sovryn.app.\n * */\ncontract GovernorAlpha is SafeMath96 {\n /* Storage */\n\n /// @notice The name of this contract.\n string public constant NAME = \"Sovryn Governor Alpha\";\n\n /// @notice The maximum number of actions that can be included in a proposal.\n function proposalMaxOperations() public pure returns (uint256) {\n return 10;\n } // 10 actions\n\n /// @notice The delay before voting on a proposal may take place, once proposed.\n function votingDelay() public pure returns (uint256) {\n return 1;\n } // 1 block\n\n /// @notice The duration of voting on a proposal, in blocks.\n function votingPeriod() public pure returns (uint256) {\n return 2880;\n } // ~1 day in blocks (assuming 30s blocks)\n\n /// @notice The address of the Sovryn Protocol Timelock.\n ITimelock public timelock;\n\n /// @notice The address of the Sovryn staking contract.\n IStaking public staking;\n\n /// @notice The address of the Governor Guardian.\n address public guardian;\n\n /// @notice The total number of proposals.\n uint256 public proposalCount;\n\n /// @notice Percentage of current total voting power require to vote.\n uint96 public quorumPercentageVotes;\n\n // @notice Majority percentage.\n uint96 public majorityPercentageVotes;\n\n struct Proposal {\n /// @notice Unique id for looking up a proposal.\n uint256 id;\n /// @notice The block at which voting begins: holders must delegate their votes prior to this block.\n uint32 startBlock;\n /// @notice The block at which voting ends: votes must be cast prior to this block.\n uint32 endBlock;\n /// @notice Current number of votes in favor of this proposal.\n uint96 forVotes;\n /// @notice Current number of votes in opposition to this proposal.\n uint96 againstVotes;\n ///@notice the quorum required for this proposal.\n uint96 quorum;\n ///@notice the majority percentage required for this proposal.\n uint96 majorityPercentage;\n /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds.\n uint64 eta;\n /// @notice the start time is required for the staking contract.\n uint64 startTime;\n /// @notice Flag marking whether the proposal has been canceled.\n bool canceled;\n /// @notice Flag marking whether the proposal has been executed.\n bool executed;\n /// @notice Creator of the proposal.\n address proposer;\n /// @notice the ordered list of target addresses for calls to be made.\n address[] targets;\n /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made.\n uint256[] values;\n /// @notice The ordered list of function signatures to be called.\n string[] signatures;\n /// @notice The ordered list of calldata to be passed to each call.\n bytes[] calldatas;\n /// @notice Receipts of ballots for the entire set of voters.\n mapping(address => Receipt) receipts;\n }\n\n /// @notice Ballot receipt record for a voter\n struct Receipt {\n /// @notice Whether or not a vote has been cast.\n bool hasVoted;\n /// @notice Whether or not the voter supports the proposal.\n bool support;\n /// @notice The number of votes the voter had, which were cast.\n uint96 votes;\n }\n\n /// @notice Possible states that a proposal may be in.\n enum ProposalState {\n Pending,\n Active,\n Canceled,\n Defeated,\n Succeeded,\n Queued,\n Expired,\n Executed\n }\n\n /// @notice The official record of all proposals ever proposed.\n mapping(uint256 => Proposal) public proposals;\n\n /// @notice The latest proposal for each proposer.\n mapping(address => uint256) public latestProposalIds;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the ballot struct used by the contract.\n bytes32 public constant BALLOT_TYPEHASH = keccak256(\"Ballot(uint256 proposalId,bool support)\");\n\n /* Events */\n\n /// @notice An event emitted when a new proposal is created.\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint256 startBlock,\n uint256 endBlock,\n string description\n );\n\n /// @notice An event emitted when a vote has been cast on a proposal.\n event VoteCast(address voter, uint256 proposalId, bool support, uint256 votes);\n\n /// @notice An event emitted when a proposal has been canceled.\n event ProposalCanceled(uint256 id);\n\n /// @notice An event emitted when a proposal has been queued in the Timelock.\n event ProposalQueued(uint256 id, uint256 eta);\n\n /// @notice An event emitted when a proposal has been executed in the Timelock.\n event ProposalExecuted(uint256 id);\n\n /* Functions */\n\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 _quorumPercentageVotes,\n uint96 _majorityPercentageVotes\n ) public {\n timelock = ITimelock(timelock_);\n staking = IStaking(staking_);\n guardian = guardian_;\n quorumPercentageVotes = _quorumPercentageVotes;\n majorityPercentageVotes = _majorityPercentageVotes;\n }\n\n /// @notice The number of votes required in order for a voter to become a proposer.\n function proposalThreshold() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(\n block.number - 1,\n \"GovernorAlpha::proposalThreshold: block number overflow\"\n ),\n block.timestamp\n );\n // 1% of current total voting power.\n return totalVotingPower / 100;\n }\n\n /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.\n function quorumVotes() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(block.number - 1, \"GovernorAlpha::quorumVotes: block number overflow\"),\n block.timestamp\n );\n // 4% of current total voting power.\n return\n mul96(\n quorumPercentageVotes,\n totalVotingPower,\n \"GovernorAlpha::quorumVotes:multiplication overflow\"\n ) / 100;\n }\n\n /**\n * @notice Create a new proposal.\n * @param targets Array of contract addresses to perform proposal execution.\n * @param values Array of rBTC amounts to send on proposal execution.\n * @param signatures Array of function signatures to call on proposal execution.\n * @param calldatas Array of payloads for the calls on proposal execution.\n * @param description Text describing the purpose of the proposal.\n * */\n function propose(\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // note: passing this block's timestamp, but the number of the previous block.\n // todo: think if it would be better to pass block.timestamp - 30 (average block time)\n // (probably not because proposal starts in 1 block from now).\n uint96 threshold = proposalThreshold();\n require(\n staking.getPriorVotes(msg.sender, sub256(block.number, 1), block.timestamp) >\n threshold,\n \"GovernorAlpha::propose: proposer votes below proposal threshold\"\n );\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"GovernorAlpha::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"GovernorAlpha::propose: must provide actions\");\n require(\n targets.length <= proposalMaxOperations(),\n \"GovernorAlpha::propose: too many actions\"\n );\n\n uint256 latestProposalId = latestProposalIds[msg.sender];\n if (latestProposalId != 0) {\n ProposalState proposersLatestProposalState = state(latestProposalId);\n require(\n proposersLatestProposalState != ProposalState.Active,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already active proposal\"\n );\n require(\n proposersLatestProposalState != ProposalState.Pending,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal\"\n );\n }\n\n uint256 startBlock = add256(block.number, votingDelay());\n uint256 endBlock = add256(startBlock, votingPeriod());\n\n proposalCount++;\n\n /// @dev quorum: proposalThreshold is 1% of total votes, we can save gas using this pre calculated value.\n /// @dev startTime: Required by the staking contract. not used by the governance contract itself.\n Proposal memory newProposal =\n Proposal({\n id: proposalCount,\n startBlock: safe32(\n startBlock,\n \"GovernorAlpha::propose: start block number overflow\"\n ),\n endBlock: safe32(endBlock, \"GovernorAlpha::propose: end block number overflow\"),\n forVotes: 0,\n againstVotes: 0,\n quorum: mul96(\n quorumPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on quorum computation\"\n ),\n majorityPercentage: mul96(\n majorityPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on majorityPercentage computation\"\n ),\n eta: 0,\n startTime: safe64(block.timestamp, \"GovernorAlpha::propose: startTime overflow\"),\n canceled: false,\n executed: false,\n proposer: msg.sender,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas\n });\n\n proposals[newProposal.id] = newProposal;\n latestProposalIds[newProposal.proposer] = newProposal.id;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n values,\n signatures,\n calldatas,\n startBlock,\n endBlock,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Enqueue a proposal and everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function queue(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Succeeded,\n \"GovernorAlpha::queue: proposal can only be queued if it is succeeded\"\n );\n Proposal storage proposal = proposals[proposalId];\n uint256 eta = add256(block.timestamp, timelock.delay());\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n proposal.eta = safe64(eta, \"GovernorAlpha::queue: ETA overflow\");\n emit ProposalQueued(proposalId, eta);\n }\n\n /**\n * @notice Tries to enqueue a proposal, verifying it has not been previously queued.\n * @param target Contract addresses to perform proposal execution.\n * @param value rBTC amount to send on proposal execution.\n * @param signature Function signature to call on proposal execution.\n * @param data Payload for the call on proposal execution.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function _queueOrRevert(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !timelock.queuedTransactions(\n keccak256(abi.encode(target, value, signature, data, eta))\n ),\n \"GovernorAlpha::_queueOrRevert: proposal action already queued at eta\"\n );\n timelock.queueTransaction(target, value, signature, data, eta);\n }\n\n /**\n * @notice Execute a proposal by looping and performing everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function execute(uint256 proposalId) public payable {\n require(\n state(proposalId) == ProposalState.Queued,\n \"GovernorAlpha::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.executeTransaction.value(proposal.values[i])(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal by looping and cancelling everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function cancel(uint256 proposalId) public {\n ProposalState state = state(proposalId);\n require(\n state != ProposalState.Executed,\n \"GovernorAlpha::cancel: cannot cancel executed proposal\"\n );\n\n Proposal storage proposal = proposals[proposalId];\n /// @notice Cancel only if sent by the guardian.\n require(msg.sender == guardian, \"GovernorAlpha::cancel: sender isn't a guardian\");\n\n proposal.canceled = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalCanceled(proposalId);\n }\n\n /**\n * @notice Get a proposal list of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return Arrays of the 4 call parameters: targets, values, signatures, calldatas.\n * */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.values, p.signatures, p.calldatas);\n }\n\n /**\n * @notice Get a proposal receipt.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param voter A governance stakeholder with voting power.\n * @return The voter receipt of the proposal.\n * */\n function getReceipt(uint256 proposalId, address voter) public view returns (Receipt memory) {\n return proposals[proposalId].receipts[voter];\n }\n\n /**\n * @notice Casts a vote by sender.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function castVote(uint256 proposalId, bool support) public {\n return _castVote(msg.sender, proposalId, support);\n }\n\n /**\n * @notice Voting with EIP-712 Signatures.\n *\n * Voting power can be delegated to any address, and then can be used to\n * vote on proposals. A key benefit to users of by-signature functionality\n * is that they can create a signed vote transaction for free, and have a\n * trusted third-party spend rBTC(or ETH) on gas fees and write it to the\n * blockchain for them.\n *\n * The third party in this scenario, submitting the SOV-holder’s signed\n * transaction holds a voting power that is for only a single proposal.\n * The signatory still holds the power to vote on their own behalf in\n * the proposal if the third party has not yet published the signed\n * transaction that was given to them.\n *\n * @dev The signature needs to be broken up into 3 parameters, known as\n * v, r and s:\n * const r = '0x' + sig.substring(2).substring(0, 64);\n * const s = '0x' + sig.substring(2).substring(64, 128);\n * const v = '0x' + sig.substring(2).substring(128, 130);\n *\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * @param v The recovery byte of the signature.\n * @param r Half of the ECDSA signature pair.\n * @param s Half of the ECDSA signature pair.\n * */\n function castVoteBySig(\n uint256 proposalId,\n bool support,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public {\n /**\n * @dev The DOMAIN_SEPARATOR is a hash that uniquely identifies a\n * smart contract. It is built from a string denoting it as an\n * EIP712 Domain, the name of the token contract, the version,\n * the chainId in case it changes, and the address that the\n * contract is deployed at.\n * */\n bytes32 domainSeparator =\n keccak256(\n abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this))\n );\n\n /// @dev GovernorAlpha uses BALLOT_TYPEHASH, while Staking uses DELEGATION_TYPEHASH\n bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support));\n\n bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n address signatory = ecrecover(digest, v, r, s);\n\n /// @dev Verify address is not null and PK is not null either.\n require(\n RSKAddrValidator.checkPKNotZero(signatory),\n \"GovernorAlpha::castVoteBySig: invalid signature\"\n );\n return _castVote(signatory, proposalId, support);\n }\n\n /**\n * @notice Cast a vote, adding it to the total counting.\n * @param voter A governance stakeholder with voting power that is casting the vote.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function _castVote(\n address voter,\n uint256 proposalId,\n bool support\n ) internal {\n require(\n state(proposalId) == ProposalState.Active,\n \"GovernorAlpha::_castVote: voting is closed\"\n );\n Proposal storage proposal = proposals[proposalId];\n Receipt storage receipt = proposal.receipts[voter];\n require(receipt.hasVoted == false, \"GovernorAlpha::_castVote: voter already voted\");\n uint96 votes = staking.getPriorVotes(voter, proposal.startBlock, proposal.startTime);\n\n if (support) {\n proposal.forVotes = add96(\n proposal.forVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n } else {\n proposal.againstVotes = add96(\n proposal.againstVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n }\n\n receipt.hasVoted = true;\n receipt.support = support;\n receipt.votes = votes;\n\n emit VoteCast(voter, proposalId, support, votes);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __acceptAdmin() public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__acceptAdmin: sender must be gov guardian\"\n );\n timelock.acceptAdmin();\n }\n\n /// @notice Sets guardian address to zero.\n function __abdicate() public {\n require(msg.sender == guardian, \"GovernorAlpha::__abdicate: sender must be gov guardian\");\n guardian = address(0);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.queueTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.executeTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /**\n * @notice Get a proposal state.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return The state of the proposal: Canceled, Pending, Active, Defeated,\n * Succeeded, Executed, Expired.\n * */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"GovernorAlpha::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n\n if (proposal.canceled) {\n return ProposalState.Canceled;\n }\n\n if (block.number <= proposal.startBlock) {\n return ProposalState.Pending;\n }\n\n if (block.number <= proposal.endBlock) {\n return ProposalState.Active;\n }\n\n uint96 totalVotes =\n add96(\n proposal.forVotes,\n proposal.againstVotes,\n \"GovernorAlpha:: state: forVotes + againstVotes > uint96\"\n );\n uint96 totalVotesMajorityPercentage =\n div96(totalVotes, 100, \"GovernorAlpha:: state: division error\");\n totalVotesMajorityPercentage = mul96(\n totalVotesMajorityPercentage,\n majorityPercentageVotes,\n \"GovernorAlpha:: state: totalVotes * majorityPercentage > uint96\"\n );\n if (proposal.forVotes <= totalVotesMajorityPercentage || totalVotes < proposal.quorum) {\n return ProposalState.Defeated;\n }\n\n if (proposal.eta == 0) {\n return ProposalState.Succeeded;\n }\n\n if (proposal.executed) {\n return ProposalState.Executed;\n }\n\n if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) {\n return ProposalState.Expired;\n }\n\n return ProposalState.Queued;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function add256(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"addition overflow\");\n return c;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function sub256(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b <= a, \"subtraction underflow\");\n return a - b;\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n}\n\n/* Interfaces */\n\ninterface TimelockInterface {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\ninterface StakingInterface {\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n}\n" + }, + "contracts/governance/GovernorVault.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title Governance Vault.\n * @notice This contract stores tokens and rBTC only transfereble by owner,\n * i.e. Sovryn governance.\n * */\ncontract GovernorVault is Ownable {\n /* Events */\n\n event Deposited(address indexed sender, uint256 amount);\n event TokensTransferred(address indexed receiver, address indexed token, uint256 amount);\n event RbtcTransferred(address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer tokens.\n * @param _receiver The receiver of tokens.\n * @param _token The address of token contract.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _receiver,\n address _token,\n uint256 _amount\n ) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n require(_token != address(0), \"Invalid token address\");\n\n require(IERC20(_token).transfer(_receiver, _amount), \"Transfer failed\");\n emit TokensTransferred(_receiver, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC.\n * @param _receiver The receiver of RBTC.\n * @param _amount The amount to be transferred.\n * */\n function transferRbtc(address payable _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n\n address(_receiver).transfer(_amount);\n emit RbtcTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {\n if (msg.value > 0) {\n emit Deposited(msg.sender, msg.value);\n }\n }\n}\n" + }, + "contracts/governance/IFeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * */\ninterface IFeeSharingCollector {\n function withdrawFees(address[] calldata _token) external;\n\n function transferTokens(address _token, uint96 _amount) external;\n\n function withdraw(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external;\n}\n" + }, + "contracts/governance/Staking/interfaces/IStaking.sol": { + "content": "pragma solidity ^0.5.17;\n\npragma experimental ABIEncoderV2;\n\n/**\n * @title Interface for Staking modules governance/Staking/modules\n */\n\ninterface IStaking {\n /*************************** StakingAdminModule ***************************/\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external;\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external;\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external;\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external;\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) external;\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external;\n\n /**\n * @notice Allows the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external;\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external;\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external;\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\n\n /*************************** StakingGovernanceModule ***************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\n * be internal instead of a public function.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external;\n\n /*************************** StakingStakeModule ***************************/\n\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance);\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes);\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\n\n /*************************** StakingStorageModule ***************************/\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n /// @return uint256(MAX_VOTING_WEIGHT);\n function getStorageMaxVotingWeight() external pure returns (uint256);\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n /// @return uint256(WEIGHT_FACTOR);\n function getStorageWeightFactor() external pure returns (uint256);\n\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\n function getStorageDefaultWeightScaling() external pure returns (uint256);\n\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\n\n /// @notice The EIP-712 typehash for the contract's domain.\n /// @return uint256(DOMAIN_TYPEHASH);\n function getStorageDomainTypehash() external pure returns (uint256);\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n /// @return uint256(DELEGATION_TYPEHASH);\n function getStorageDelegationTypehash() external pure returns (uint256);\n\n /// @return name;\n function getStorageName() external view returns (string memory);\n\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n function kickoffTS() external view returns (uint256);\n\n /// @notice The token to be staked\n function SOVToken() external view returns (address);\n\n /// @notice Stakers delegated voting power\n /// @param staker - the delegating address\n /// @param until - delegated voting\n /// @return _delegate - voting power delegated to address\n function delegates(address staker, uint256 until) external view returns (address _delegate);\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately\n /// see function unlockAllTokens() for details\n function allUnlocked() external view returns (bool);\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\n function newStakingContract() external view returns (address);\n\n /// CHECKPOINTS\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\n function totalStakingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n function numTotalStakingCheckpoints(uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n function delegateStakingCheckpoints(\n address delagatee,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n function userStakingCheckpoints(\n address user,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number\n function numUserStakingCheckpoints(address user, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n function nonces(address user) external view returns (uint256 nonce);\n\n /// SLASHING ///\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n function feeSharing() external view returns (address);\n\n /// @notice used for weight scaling when unstaking with slashing.\n /// @return uint96 DEFAULT_WEIGHT_SCALING\n function weightScaling() external view returns (uint96);\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n function admins(address isAdmin) external view returns (bool);\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n function vestingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\n\n ///@notice vesting registry contract PROXY address\n function vestingRegistryLogic() external view returns (address);\n\n /// @dev user => flag whether user has pauser role.\n function pausers(address isPauser) external view returns (bool);\n\n /// @dev Staking contract is paused\n function paused() external view returns (bool);\n\n /// @dev Staking contract is frozen\n function frozen() external view returns (bool);\n\n /*************************** StakingVestingModule ***************************/\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool);\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external;\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external;\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes);\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n /*************************** StakingWithdrawModule ***************************/\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * */\n function governanceWithdrawVesting(address vesting, address receiver) external;\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96);\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external;\n\n /*************************** WeightedStakingModule ***************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The date/timestamp of the unstaking time.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * TODO: WeightedStaking::weightedStakeByDate should probably better\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Returns public constant MAX_DURATION\n * preserved for backwards compatibility\n * Use getStorageMaxDurationToStakeTokens()\n * @return uint96 MAX_DURATION for staking\n **/\n function MAX_DURATION() external view returns (uint256);\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() external view returns (address);\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() external view returns (bool);\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) external;\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external;\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() external view returns (uint256);\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param maxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\n}\n" + }, + "contracts/governance/Staking/modules/shared/CheckpointsShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\n\n/**\n * @title Checkpoints contract.\n * @notice Increases and decreases storage values for users, delegatees and\n * total daily stake.\n * */\ncontract CheckpointsShared is StakingStorageShared, SafeMath96 {\n /// @notice An event emitted when an account changes its delegate.\n event DelegateChanged(\n address indexed delegator,\n uint256 lockedUntil,\n address indexed fromDelegate,\n address indexed toDelegate\n );\n\n /// @notice An event emitted when a delegate account's stake balance changes.\n event DelegateStakeChanged(\n address indexed delegate,\n uint256 lockedUntil,\n uint256 previousBalance,\n uint256 newBalance\n );\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n event ContractCodeHashAdded(bytes32 hash);\n\n event ContractCodeHashRemoved(bytes32 hash);\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n event TeamVestingCancelled(address indexed caller, address receiver);\n\n event TeamVestingPartiallyCancelled(\n address indexed caller,\n address receiver,\n uint256 nextStartFrom\n );\n\n constructor() internal {\n // abstract\n }\n\n /**\n * @notice Increases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = add96(vested, value, \"CP01\"); // vested overflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Decreases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = sub96(vested, value, \"CP02\"); // vested underflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Writes on storage the user vested amount.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newVest The new vest balance.\n * */\n function _writeVestingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newVest\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP03\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n vestingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n vestingCheckpoints[lockedTS][nCheckpoints - 1].stake = newVest;\n } else {\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newVest);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP04\"); // staked overflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP05\"); // staked underflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the user stake.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeUserCheckpoint(\n address account,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP06\"); // block number > 32 bits\n\n if (\n nCheckpoints > 0 &&\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n userStakingCheckpoints[account][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numUserStakingCheckpoints[account][lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP07\"); // block number > 32 bits\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = 0;\n // @dev We need to check delegate checkpoint value here,\n //\t\tbecause we had an issue in `stake` function:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n // @dev It can be greater than 0, but inconsistent after 3 transactions\n if (staked > value) {\n newStake = sub96(staked, value, \"CP08\"); // staked underflow\n }\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the delegate stake.\n * @param delegatee The delegate address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeDelegateCheckpoint(\n address delegatee,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP09\"); // block numb > 32 bits\n uint96 oldStake = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n\n if (\n nCheckpoints > 0 &&\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].fromBlock ==\n blockNumber\n ) {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numDelegateStakingCheckpoints[delegatee][lockedTS] = nCheckpoints + 1;\n }\n emit DelegateStakeChanged(delegatee, lockedTS, oldStake, newStake);\n }\n\n /**\n * @notice Increases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP10\"); // staked overflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP11\"); // staked underflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the total stake.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeStakingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP12\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n totalStakingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newStake);\n numTotalStakingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Get the current balance of an account locked until a certain date.\n * @param account The user address.\n * @param lockDate The lock date.\n * @return The stake amount.\n * */\n function _currentBalance(address account, uint256 lockDate) internal view returns (uint96) {\n uint32 _numUnserStakingCheckpoints = numUserStakingCheckpoints[account][lockDate] - 1;\n return userStakingCheckpoints[account][lockDate][_numUnserStakingCheckpoints].stake;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\nimport \"../../../../openzeppelin/SafeMath.sol\";\nimport \"../../../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking modules shared functionality\n */\ncontract StakingShared is StakingStorageShared, SafeMath96 {\n using SafeMath for uint256;\n\n uint256 internal constant FOUR_WEEKS = 4 weeks;\n\n /**\n * @dev Throws if paused.\n */\n modifier whenNotPaused() {\n require(!paused, \"paused\"); // SS03\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\"); // SS01\n _;\n }\n\n /**\n\t * @dev Throws if called by any account other than the owner or admin or pauser.\n\t \n\tmodifier onlyAuthorizedOrPauser() {\n\t\trequire(isOwner() || admins[msg.sender] || pausers[msg.sender], \"unauthorized\"); // WS02\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if called by any account other than the owner or pauser.\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || pausers[msg.sender], \"unauthorized\"); // SS02\n _;\n }\n\n /**\n * @dev Throws if called by any account other than pauser.\n * @notice Uncomment when needed\n */\n /*\n\tmodifier onlyPauser() {\n\t\trequire(pausers[msg.sender], \"Not pauser\");\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if frozen.\n */\n modifier whenNotFrozen() {\n require(!frozen, \"paused\"); // SS04\n _;\n }\n\n constructor() internal {\n // abstract\n }\n\n function _notSameBlockAsStakingCheckpoint(uint256 lockDate, address stakeFor) internal view {\n uint32 nCheckpoints = numUserStakingCheckpoints[stakeFor][lockDate];\n bool notSameBlock =\n userStakingCheckpoints[stakeFor][lockDate][nCheckpoints - 1].fromBlock != block.number;\n require(notSameBlock, \"cannot be mined in the same block as last stake\"); // S20\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = kickoffTS;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / TWO_WEEKS;\n lockDate = periodFromKickoff * TWO_WEEKS + start;\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS14\n\n date = _adjustDateForOrigin(date);\n uint32 nCheckpoints = numUserStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (userStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return userStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (userStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = userStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return userStakingCheckpoints[account][date][lower].stake;\n }\n\n /**\n * @dev origin vesting contracts have different dates\n * we need to add 2 weeks to get end of period (by default, it's start)\n * @param date The staking date to compute the power for.\n * @return unlocking date.\n */\n function _adjustDateForOrigin(uint256 date) internal view returns (uint256) {\n uint256 adjustedDate = _timestampToLockDate(date);\n //origin vesting contracts have different dates\n //we need to add 2 weeks to get end of period (by default, it's start)\n if (adjustedDate != date) {\n date = adjustedDate + TWO_WEEKS;\n }\n return date;\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function _computeWeightByDate(uint256 date, uint256 startDate)\n internal\n pure\n returns (uint96 weight)\n {\n require(date >= startDate, \"date < startDate\"); // WS18\n uint256 remainingTime = (date - startDate);\n require(MAX_DURATION >= remainingTime, \"remaining time > max duration\"); // WS19\n /// @dev x = max days - remaining days\n uint96 x = uint96(MAX_DURATION - remainingTime) / (1 days);\n /// @dev w = (m^2 - x^2)/m^2 +1 (multiplied by the weight factor)\n weight = add96(\n WEIGHT_FACTOR,\n mul96(\n MAX_VOTING_WEIGHT * WEIGHT_FACTOR,\n sub96(\n MAX_DURATION_POW_2,\n x * x,\n \"weight underflow\" // WS20\n ),\n \"weight mul overflow\" // WS21\n ) / MAX_DURATION_POW_2,\n \"overflow on weight\" // WS22\n );\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function _isVestingContract(address stakerAddress) internal view returns (bool) {\n bool isVesting;\n bytes32 codeHash;\n\n assembly {\n codeHash := extcodehash(stakerAddress)\n }\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingStorageShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../../openzeppelin/Ownable.sol\";\nimport \"../../../../interfaces/IERC20.sol\";\nimport \"../../../IFeeSharingCollector.sol\";\nimport \"../../../Vesting/IVestingRegistry.sol\";\n\n/**\n * @title StakingStorageShared contract is inherited by Staking modules.\n * @notice Just the storage part of stacking contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingProxy and Checkpoints contracts.\n *\n * What is SOV staking?\n * The purpose of the SOV token is to provide a pseudonymous,\n * censorship-resistant mechanism for governing the parameters of the Sovryn\n * protocol, while aligning the incentives of protocol governors with the\n * long-term success of the protocol. Any SOV token holder can choose to\n * stake (lock up) their tokens for a fixed period of time in return for\n * voting rights in the Bitocracy. Stakers are further incentivised through\n * fee and slashing rewards.\n * */\ncontract StakingStorageShared is Ownable {\n /// @notice 2 weeks in seconds.\n uint256 constant TWO_WEEKS = 1209600;\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n uint96 public constant MAX_VOTING_WEIGHT = 9;\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n uint96 public constant WEIGHT_FACTOR = 10;\n\n /// @notice The maximum duration to stake tokens for.\n uint256 public constant MAX_DURATION = 1092 days;\n\n /// @notice The maximum duration ^2\n uint96 constant MAX_DURATION_POW_2 = 1092 * 1092;\n\n /// @notice Default weight scaling.\n uint96 constant DEFAULT_WEIGHT_SCALING = 3;\n\n /// @notice Range for weight scaling.\n uint96 constant MIN_WEIGHT_SCALING = 1;\n uint96 constant MAX_WEIGHT_SCALING = 9;\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n uint256 public kickoffTS;\n\n string name = \"SOVStaking\";\n\n /// @notice The token to be staked.\n IERC20 public SOVToken;\n\n /// @notice A record of each accounts delegate.\n mapping(address => mapping(uint256 => address)) public delegates;\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately.\n bool public allUnlocked = false;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n bytes32 public constant DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 lockDate,uint256 nonce,uint256 expiry)\");\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure.\n address public newStakingContract;\n\n /*************************** Checkpoints *******************************/\n\n /// @notice A checkpoint for marking the stakes from a given block\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public totalStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numTotalStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public delegateStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numDelegateStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public userStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numUserStakingCheckpoints;\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n mapping(address => uint256) public nonces;\n\n /*************************** Slashing *******************************/\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n IFeeSharingCollector public feeSharing;\n\n /// @notice used for weight scaling when unstaking with slashing.\n uint96 public weightScaling = DEFAULT_WEIGHT_SCALING;\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n mapping(address => bool) public vestingWhitelist;\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n mapping(address => bool) public admins;\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n mapping(bytes32 => bool) public vestingCodeHashes;\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public vestingCheckpoints;\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numVestingCheckpoints;\n\n ///@notice vesting registry contract\n IVestingRegistry public vestingRegistryLogic;\n\n /// @dev user => flag whether user has pauser role.\n mapping(address => bool) public pausers;\n\n /// @dev Staking contract is paused\n bool public paused;\n\n /// @dev Staking contract is frozen\n bool public frozen;\n\n /// @dev max iterations that can be supported in 1 tx for the withdrawal\n uint256 internal maxVestingWithdrawIterations;\n\n constructor() internal {\n //abstract\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingAdminModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Admin Module.\n * @notice Implements administrative functionality pause, freeze and setting addresses and parameters\n * related to staking\n * */\ncontract StakingAdminModule is IFunctionsList, StakingShared {\n using Address for address payable;\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(_admin != address(0), \"cannot add the zero address as an admin\");\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(admins[_admin], \"address is not an admin\");\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external onlyOwner whenNotFrozen {\n require(_pauser != address(0), \"cannot add the zero address as a pauser\");\n pausers[_pauser] = true;\n emit PauserAddedOrRemoved(_pauser, true);\n }\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external onlyOwner whenNotFrozen {\n require(pausers[_pauser], \"address is not a pauser\");\n delete pausers[_pauser];\n emit PauserAddedOrRemoved(_pauser, false);\n }\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) public onlyPauserOrOwner whenNotFrozen {\n paused = _pause;\n emit StakingPaused(_pause);\n }\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external onlyPauserOrOwner {\n require(_freeze != frozen, \"Cannot freeze/unfreeze to the same state\"); // WS25\n if (_freeze) pauseUnpause(true);\n frozen = _freeze;\n emit StakingFrozen(_freeze);\n }\n\n /**\n * @notice Allow the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external onlyOwner whenNotFrozen {\n require(_feeSharing != address(0), \"FeeSharing address shouldn't be 0\"); // S17\n feeSharing = IFeeSharingCollector(_feeSharing);\n }\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external onlyOwner whenNotFrozen {\n require(\n MIN_WEIGHT_SCALING <= _weightScaling && _weightScaling <= MAX_WEIGHT_SCALING,\n \"scaling doesn't belong to range [1, 9]\" // S18\n );\n weightScaling = _weightScaling;\n }\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external onlyOwner whenNotFrozen {\n require(_newStakingContract != address(0), \"can't reset the new staking contract to 0\"); // S16\n newStakingContract = _newStakingContract;\n }\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external whenNotFrozen {\n require(newStakingContract != address(0), \"there is no new staking contract set\"); // S19\n revert(\"not implemented\");\n /// @dev implementation:\n /// @dev Iterate over all possible lock dates from now until now + MAX_DURATION.\n /// @dev Read the stake & delegate of the msg.sender\n /// @dev If stake > 0, stake it at the new contract until the lock date with the current delegate.\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](13);\n functionsList[0] = this.addAdmin.selector;\n functionsList[1] = this.removeAdmin.selector;\n functionsList[2] = this.addPauser.selector;\n functionsList[3] = this.removePauser.selector;\n functionsList[4] = this.pauseUnpause.selector;\n functionsList[5] = this.freezeUnfreeze.selector;\n functionsList[6] = this.setFeeSharing.selector;\n functionsList[7] = this.setWeightScaling.selector;\n functionsList[8] = this.setNewStakingContract.selector;\n functionsList[9] = this.owner.selector;\n functionsList[10] = this.isOwner.selector;\n functionsList[11] = this.transferOwnership.selector;\n functionsList[12] = this.migrateToNewStakingContract.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingGovernanceModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/IVesting.sol\";\n\n/**\n * @title Staking Governance Module contract\n * @notice Implements voting power and delegation functionality\n * */\ncontract StakingGovernanceModule is IFunctionsList, StakingShared, CheckpointsShared {\n using Address for address payable;\n\n /************* TOTAL VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n /// @dev Start the computation with the exact or previous unlocking date (voting weight remians the same until the next break point).\n uint256 start = _timestampToLockDate(time);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n totalVotingPower = add96(\n totalVotingPower,\n _totalPowerByDate(i, start, blockNumber),\n \"arrays mismatch\"\n ); // WS06\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorTotalStakesForDate(date, blockNumber);\n /// @dev weight is multiplied by some factor to allow decimals.\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS07\n }\n\n /****************************** DELEGATED VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96) {\n return getPriorVotes(account, block.number - 1, block.timestamp);\n }\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96 votes) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n votes = add96(\n votes,\n _totalPowerByDateForDelegatee(account, i, start, blockNumber),\n \"overflow - total VP\"\n ); // WS09\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDateForDelegatee(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS10\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n date = _adjustDateForOrigin(date);\n return _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined yet\"); // WS11\n\n uint32 nCheckpoints = numDelegateStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (delegateStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return delegateStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (delegateStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = delegateStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return delegateStakingCheckpoints[account][date][lower].stake;\n }\n\n /**************** SHARED FUNCTIONS *********************/\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for. Adjusted to the next valid lock date, as necessary\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n public\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorTotalStakesForDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function _getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS08\n\n uint32 nCheckpoints = numTotalStakingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (totalStakingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return totalStakingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n // Next check implicit zero balance\n if (totalStakingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Checkpoint memory cp = totalStakingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return totalStakingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Set new delegatee. Move from user's current delegate to a new\n * delegatee the stake balance.\n * @param delegator The user address to move stake balance from its current delegatee.\n * @param delegatee The new delegatee. The address to move stake balance to.\n * @param lockedTS The lock date.\n * @dev Reverts if delegator balance or delegatee is not valid, unless the sender is a vesting contract.\n * */\n function _delegate(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n address currentDelegate = delegates[delegator][lockedTS];\n uint96 delegatorBalance = _currentBalance(delegator, lockedTS);\n\n // vesting contracts will in multiple cases try to delegate a zero balance\n // or to the existing delegatee\n if (_isVestingContract(msg.sender)) {\n if (delegatorBalance == 0 || currentDelegate == delegatee) {\n return;\n }\n } else {\n require(delegatorBalance > 0, \"no stake to delegate\");\n require(currentDelegate != delegatee, \"cannot delegate to the existing delegatee\");\n }\n\n delegates[delegator][lockedTS] = delegatee;\n\n emit DelegateChanged(delegator, lockedTS, currentDelegate, delegatee);\n\n _moveDelegates(currentDelegate, delegatee, delegatorBalance, lockedTS);\n }\n\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n function _delegateNext(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n if (_isVestingContract(msg.sender)) {\n uint256 nextLock = lockedTS.add(TWO_WEEKS);\n address currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n\n // @dev workaround for the issue with a delegation of the latest stake\n uint256 endDate = IVesting(msg.sender).endDate();\n nextLock = lockedTS.add(FOUR_WEEKS);\n if (nextLock == endDate) {\n currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n }\n }\n }\n\n /**\n * @notice Move an amount of delegate stake from a source address to a\n * destination address.\n * @param srcRep The address to get the staked amount from.\n * @param dstRep The address to send the staked amount to.\n * @param amount The staked amount to move.\n * @param lockedTS The lock date.\n * */\n function _moveDelegates(\n address srcRep,\n address dstRep,\n uint96 amount,\n uint256 lockedTS\n ) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) _decreaseDelegateStake(srcRep, lockedTS, amount);\n\n if (dstRep != address(0)) _increaseDelegateStake(dstRep, lockedTS, amount);\n }\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function _getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external whenNotPaused {\n require(delegatee != address(0), \"cannot delegate to the zero address\");\n _notSameBlockAsStakingCheckpoint(lockDate, msg.sender);\n\n _delegate(msg.sender, delegatee, lockDate);\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n _delegateNext(msg.sender, delegatee, lockDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](6);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStakeModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking contract staking functionality module\n * @notice Implements staking functionality\n **/\ncontract StakingStakeModule is IFunctionsList, StakingShared, CheckpointsShared, ApprovalReceiver {\n using SafeMath for uint256;\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stake(msg.sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external onlyThisContract whenNotPaused whenNotFrozen {\n _stake(sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * */\n function _stake(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted\n ) internal {\n _stakeOptionalTokenTransfer(\n sender,\n amount,\n until,\n stakeFor,\n delegatee,\n timeAdjusted,\n true // transfer SOV\n );\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * @param transferToken Should transfer SOV - false for multiple iterations like in stakeBySchedule\n * */\n function _stakeOptionalTokenTransfer(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted,\n bool transferToken\n ) internal {\n require(amount > 0, \"amount needs to be bigger than 0\"); // S01\n\n if (!timeAdjusted) {\n until = _timestampToLockDate(until);\n }\n require(\n until > block.timestamp,\n \"Staking::_timestampToLockDate: staking period too short\"\n ); // S02\n\n /// @dev Stake for the sender if not specified otherwise.\n if (stakeFor == address(0)) {\n stakeFor = sender;\n }\n // must wait a block before staking again for that same deadline\n _notSameBlockAsStakingCheckpoint(until, stakeFor);\n\n /// @dev Delegate for stakeFor if not specified otherwise.\n if (delegatee == address(0)) {\n delegatee = stakeFor;\n }\n\n /// @dev Do not stake longer than the max duration.\n if (!timeAdjusted) {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n }\n\n uint96 previousBalance = _currentBalance(stakeFor, until);\n\n /// @dev Increase stake.\n _increaseStake(sender, amount, stakeFor, until, transferToken);\n\n // @dev Previous version wasn't working properly for the following case:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n address previousDelegatee = delegates[stakeFor][until];\n\n if (previousDelegatee != delegatee) {\n // @dev only the user that stakes for himself is allowed to delegate VP to another address\n // which works with vesting stakes and prevents vulnerability of delegating VP to an arbitrary address from\n // any address\n\n if (delegatee != stakeFor) {\n require(\n stakeFor == sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n } else if (sender != stakeFor && previousDelegatee != address(0)) {\n require(stakeFor == sender, \"Only sender is allowed to change delegatee\");\n }\n\n /// @dev Update delegatee.\n delegates[stakeFor][until] = delegatee;\n\n /// @dev Decrease stake on previous balance for previous delegatee.\n _decreaseDelegateStake(previousDelegatee, until, previousBalance);\n\n /// @dev Add previousBalance to amount.\n amount = add96(previousBalance, amount, \"add amounts failed\");\n }\n\n /// @dev Increase stake.\n _increaseDelegateStake(delegatee, until, amount);\n emit DelegateChanged(stakeFor, until, previousDelegatee, delegatee);\n }\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until)\n external\n whenNotPaused\n whenNotFrozen\n {\n previousLock = _timestampToLockDate(previousLock);\n until = _timestampToLockDate(until);\n\n _notSameBlockAsStakingCheckpoint(previousLock, msg.sender);\n\n /// @dev Do not exceed the max duration, no overflow possible.\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n\n require(previousLock < until, \"must increase staking duration\"); // S04\n\n /// @dev Update checkpoints.\n /// @dev TODO James: Can reading stake at block.number -1 cause trouble with multiple tx in a block?\n uint96 amount = _getPriorUserStakeByDate(msg.sender, previousLock, block.number - 1);\n require(amount > 0, \"no stakes till the prev lock date\"); // S05\n _decreaseUserStake(msg.sender, previousLock, amount);\n _increaseUserStake(msg.sender, until, amount);\n\n if (_isVestingContract(msg.sender)) {\n _decreaseVestingStake(previousLock, amount);\n _increaseVestingStake(until, amount);\n }\n\n _decreaseDailyStake(previousLock, amount);\n _increaseDailyStake(until, amount);\n\n /// @dev Delegate might change: if there is already a delegate set for the until date, it will remain the delegate for this position\n address delegateFrom = delegates[msg.sender][previousLock];\n delegates[msg.sender][previousLock] = address(0); //the previousLock delegates nullifying before reading that form `until` guards in case delegateTo == until\n address delegateTo = delegates[msg.sender][until];\n if (delegateTo == address(0)) {\n delegateTo = delegateFrom;\n delegates[msg.sender][until] = delegateFrom;\n }\n _decreaseDelegateStake(delegateFrom, previousLock, amount);\n _increaseDelegateStake(delegateTo, until, amount);\n\n emit ExtendedStakingDuration(msg.sender, previousLock, until, amount);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param until The date until which the tokens will be staked.\n * @param transferToken if false - token transfer should be handled separately\n * */\n function _increaseStake(\n address sender,\n uint96 amount,\n address stakeFor,\n uint256 until,\n bool transferToken\n ) internal {\n /// @dev Retrieve the SOV tokens.\n if (transferToken)\n require(\n SOVToken.transferFrom(sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // IS10\n\n /// @dev Increase staked balance.\n uint96 balance = _currentBalance(stakeFor, until);\n balance = add96(balance, amount, \"increaseStake: overflow\"); // IS20\n\n /// @dev Update checkpoints.\n _increaseDailyStake(until, amount);\n _increaseUserStake(stakeFor, until, amount);\n\n if (_isVestingContract(stakeFor)) _increaseVestingStake(until, amount);\n\n emit TokensStaked(stakeFor, amount, until, balance);\n }\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function _stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) internal {\n require(amount > 0, \"Invalid amount\");\n require(duration <= MAX_DURATION, \"Invalid duration\");\n require(intervalLength > 0, \"Invalid interval length\");\n require(intervalLength % TWO_WEEKS == 0, \"Invalid interval length\");\n if (delegatee != stakeFor && delegatee != address(0)) {\n require(\n stakeFor == msg.sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n }\n /**\n * @dev Stake them until lock dates according to the vesting schedule.\n * Note: because staking is only possible in periods of 2 weeks,\n * the total duration might end up a bit shorter than specified\n * depending on the date of staking.\n * */\n uint256 start = _timestampToLockDate(block.timestamp + cliff);\n uint256 end = _timestampToLockDate(block.timestamp + duration);\n require(start <= end, \"Invalid schedule\");\n uint256 numIntervals;\n if (start < end) {\n numIntervals = (end - start) / intervalLength + 1;\n } else {\n numIntervals = 1;\n }\n uint256 stakedPerInterval = amount / numIntervals;\n\n /// @dev transferring total SOV amount before staking\n require(\n SOVToken.transferFrom(msg.sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // SS10\n /// @dev stakedPerInterval might lose some dust on rounding. Add it to the first staking date.\n if (numIntervals >= 1) {\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(amount - stakedPerInterval * (numIntervals - 1)),\n start,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n /// @dev Stake the rest in 4 week intervals.\n for (uint256 i = start + intervalLength; i <= end; i += intervalLength) {\n /// @dev Stakes for itself, delegates to the owner.\n _notSameBlockAsStakingCheckpoint(i, stakeFor); // must wait a block before staking again for that same deadline\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(stakedPerInterval),\n i,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n }\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance) {\n for (uint256 i = kickoffTS; i <= block.timestamp + MAX_DURATION; i += TWO_WEEKS) {\n balance = add96(balance, _currentBalance(account, i), \"Staking::balanceOf: overflow\"); // S12\n }\n }\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96) {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n return nCheckpoints > 0 ? totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake : 0;\n }\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes)\n {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n\n /// @dev Calculate stakes.\n uint256 count = 0;\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n if (_currentBalance(account, i) > 0) {\n count++;\n }\n }\n dates = new uint256[](count);\n stakes = new uint96[](count);\n\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n uint256 j = 0;\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n uint96 balance = _currentBalance(account, i);\n if (balance > 0) {\n dates[j] = i;\n stakes[j] = balance;\n j++;\n }\n }\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOVToken);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeWithApproval.selector;\n return selectors;\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256) {\n return _timestampToLockDate(timestamp);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](10);\n functionsList[0] = this.stake.selector;\n functionsList[1] = this.stakeWithApproval.selector;\n functionsList[2] = this.extendStakingDuration.selector;\n functionsList[3] = this.stakesBySchedule.selector;\n functionsList[4] = this.stakeBySchedule.selector;\n functionsList[5] = this.balanceOf.selector;\n functionsList[6] = this.getCurrentStakedUntil.selector;\n functionsList[7] = this.getStakes.selector;\n functionsList[8] = this.timestampToLockDate.selector;\n functionsList[9] = this.receiveApproval.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStorageModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/StakingStorageShared.sol\";\n\n/**\n * @title Staking Storage Module\n * @notice Provides getters for public storage variables\n **/\ncontract StakingStorageModule is IFunctionsList, StakingStorageShared {\n function getStorageDefaultWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256) {\n return MAX_DURATION;\n }\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n function getStorageMaxVotingWeight() external pure returns (uint256) {\n return uint256(MAX_VOTING_WEIGHT);\n }\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n function getStorageWeightFactor() external pure returns (uint256) {\n return uint256(WEIGHT_FACTOR);\n }\n\n /// @notice Default weight scaling.\n function getStorageDefaulWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling)\n {\n return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING));\n }\n\n /// @notice The EIP-712 typehash for the contract's domain.\n function getStorageDomainTypehash() external pure returns (uint256) {\n return uint256(DOMAIN_TYPEHASH);\n }\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n function getStorageDelegationTypehash() external pure returns (uint256) {\n return uint256(DELEGATION_TYPEHASH);\n }\n\n function getStorageName() external view returns (string memory) {\n return name;\n }\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() public view returns (uint256) {\n return maxVestingWithdrawIterations;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](32);\n functionsList[0] = this.getStorageMaxDurationToStakeTokens.selector;\n functionsList[1] = this.getStorageMaxVotingWeight.selector;\n functionsList[2] = this.getStorageWeightFactor.selector;\n functionsList[3] = this.getStorageDefaulWeightScaling.selector;\n functionsList[4] = this.getStorageRangeForWeightScaling.selector;\n functionsList[5] = this.getStorageDomainTypehash.selector;\n functionsList[6] = this.getStorageDelegationTypehash.selector;\n functionsList[7] = this.getStorageName.selector;\n functionsList[8] = this.kickoffTS.selector;\n functionsList[9] = this.SOVToken.selector;\n functionsList[10] = this.delegates.selector;\n functionsList[11] = this.allUnlocked.selector;\n functionsList[12] = this.newStakingContract.selector;\n functionsList[13] = this.totalStakingCheckpoints.selector;\n functionsList[14] = this.numTotalStakingCheckpoints.selector;\n functionsList[15] = this.delegateStakingCheckpoints.selector;\n functionsList[16] = this.numDelegateStakingCheckpoints.selector;\n functionsList[17] = this.userStakingCheckpoints.selector;\n functionsList[18] = this.numUserStakingCheckpoints.selector;\n functionsList[19] = this.nonces.selector;\n functionsList[20] = this.feeSharing.selector;\n functionsList[21] = this.weightScaling.selector;\n functionsList[22] = this.vestingWhitelist.selector;\n functionsList[23] = this.admins.selector;\n functionsList[24] = this.vestingCodeHashes.selector;\n functionsList[25] = this.vestingCheckpoints.selector;\n functionsList[26] = this.numVestingCheckpoints.selector;\n functionsList[27] = this.vestingRegistryLogic.selector;\n functionsList[28] = this.pausers.selector;\n functionsList[29] = this.paused.selector;\n functionsList[30] = this.frozen.selector;\n functionsList[31] = this.getMaxVestingWithdrawIterations.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingVestingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Vesting Module contract\n * @notice Implements interaction with Vesting functionality: vesting registry, vesting staking\n * */\ncontract StakingVestingModule is IFunctionsList, StakingShared {\n event ContractCodeHashAdded(bytes32 hash);\n event ContractCodeHashRemoved(bytes32 hash);\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external onlyOwner whenNotFrozen {\n vestingRegistryLogic = IVestingRegistry(_vestingRegistryProxy);\n }\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(lockedDates.length == values.length, \"arrays mismatch\"); // WS05\n\n uint256 length = lockedDates.length;\n for (uint256 i = 0; i < length; i++) {\n _setVestingStake(lockedDates[i], values[i]);\n }\n }\n\n /**\n * @notice Sets the users' vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to be set.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function _setVestingStake(uint256 lockedTS, uint96 value) internal {\n require(\n lockedTS > kickoffTS,\n \"Invalid lock dates: must greater than contract creation timestamp\"\n );\n\n // locked date must be multiples of 14 days / TWO_WEEKS\n require(\n (lockedTS - kickoffTS) % TWO_WEEKS == 0,\n \"Invalid lock dates: not multiples of 14 days\"\n );\n\n // locked date must not exceed the MAX_DURATION\n if (lockedTS > block.timestamp) {\n require(\n lockedTS - block.timestamp <= MAX_DURATION,\n \"Invalid lock dates: exceed max duration\"\n );\n }\n\n // the value must not exceed the total staked at the given locked date\n uint32 nStakeCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 totalStaked = totalStakingCheckpoints[lockedTS][nStakeCheckpoints - 1].stake;\n require(\n value <= totalStaked,\n \"Invalid stake amount: greater than the total staked for given date\"\n );\n\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint32 blockNumber;\n\n Checkpoint memory recentCP = vestingCheckpoints[lockedTS][nCheckpoints - 1];\n if (nCheckpoints == 0) blockNumber = uint32(block.number) - 1;\n else blockNumber = recentCP.fromBlock + 1;\n\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, value);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n\n emit VestingStakeSet(lockedTS, value);\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n uint96 priorStake = _getPriorUserStakeByDate(account, date, blockNumber);\n // @dev we need to modify function in order to workaround issue with Vesting.withdrawTokens:\n //\t\treturn 1 instead of 0 if message sender is a contract.\n if (priorStake == 0 && _isVestingContract(msg.sender)) {\n priorStake = 1;\n }\n return priorStake;\n }\n\n /*************************** Weighted Vesting Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes)\n {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedVestingStakeByDate(i, start, blockNumber);\n if (weightedStake > 0) {\n votes = add96(votes, weightedStake, \"overflow on total weight\"); // WS15\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n power = _weightedVestingStakeByDate(date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorVestingStakeByDate(date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul oveflow\") / WEIGHT_FACTOR; // WS16\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorVestingStakeByDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS17\n\n uint32 nCheckpoints = numVestingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (vestingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return vestingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (vestingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = vestingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return vestingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n require(vestingCodeHashes[codeHash], \"not a registered vesting code hash\");\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool) {\n bool isVesting;\n bytes32 codeHash = _getCodeHash(stakerAddress);\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](9);\n functionsList[0] = this.setVestingRegistry.selector;\n functionsList[1] = this.setVestingStakes.selector;\n functionsList[2] = this.getPriorUserStakeByDate.selector;\n functionsList[3] = this.getPriorVestingWeightedStake.selector;\n functionsList[4] = this.getPriorVestingStakeByDate.selector;\n functionsList[5] = this.addContractCodeHash.selector;\n functionsList[6] = this.removeContractCodeHash.selector;\n functionsList[7] = this.isVestingContract.selector;\n functionsList[8] = this.weightedVestingStakeByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingWithdrawModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/ITeamVesting.sol\";\nimport \"../../Vesting/IVesting.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking withdrawal functionality module\n **/\ncontract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShared {\n using SafeMath for uint256;\n\n event MaxVestingWithdrawIterationsUpdated(uint256 oldMaxIterations, uint256 newMaxIterations);\n\n /// @dev Struct for direct withdraw function -- to avoid stack too deep issue\n struct VestingConfig {\n address vestingAddress;\n uint256 startDate;\n uint256 endDate;\n uint256 cliff;\n uint256 duration;\n address tokenOwner;\n }\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev If until is not a valid lock date, the next lock date after until is used.\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n // adjust until here to avoid adjusting multiple times, and to make sure an adjusted date is passed to\n // _notSameBlockAsStakingCheckpoint\n until = _adjustDateForOrigin(until);\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, false);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe need to check block.timestamp here\n _withdrawNext(until, receiver, false);\n }\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external onlyAuthorized whenNotFrozen {\n /// require the caller only for team vesting contract.\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n _cancelTeamVesting(vesting, receiver, startFrom);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param _vesting The vesting address.\n * @param _receiver The receiving address.\n * @param _startFrom The start value for the iterations.\n * or just unlocked tokens (false).\n *\n * @return nextStartFrom is a timestamp to be used for next withdrawal.\n * @return notCompleted flag that indicates that the cancel team vesting is not completely done.\n * */\n function _cancelTeamVesting(\n address _vesting,\n address _receiver,\n uint256 _startFrom\n ) private returns (uint256 nextStartFrom, bool notCompleted) {\n require(_receiver != address(0), \"receiver address invalid\");\n\n ITeamVesting teamVesting = ITeamVesting(_vesting);\n\n VestingConfig memory vestingConfig =\n VestingConfig(\n _vesting,\n teamVesting.startDate(),\n teamVesting.endDate(),\n teamVesting.cliff(),\n teamVesting.duration(),\n teamVesting.tokenOwner()\n );\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them, as long as the itrations less than maxVestingWithdrawIterations.\n uint256 end = vestingConfig.endDate;\n\n uint256 defaultStart = vestingConfig.startDate + vestingConfig.cliff;\n\n _startFrom = _startFrom >= defaultStart ? _startFrom : defaultStart;\n\n /// @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 totalIterationValue =\n (_startFrom + (TWO_WEEKS * (maxVestingWithdrawIterations - 1)));\n uint256 adjustedEnd = end < totalIterationValue ? end : totalIterationValue;\n\n /// @dev Withdraw for each unlocked position.\n for (uint256 i = _startFrom; i <= adjustedEnd; i += TWO_WEEKS) {\n /// @dev Read amount to withdraw.\n uint96 tempStake = _getPriorUserStakeByDate(_vesting, i, block.number - 1);\n\n if (tempStake > 0) {\n /// @dev do governance direct withdraw for team vesting\n _withdrawFromTeamVesting(tempStake, i, _receiver, vestingConfig);\n }\n }\n\n if (adjustedEnd < end) {\n nextStartFrom = adjustedEnd + TWO_WEEKS;\n emit TeamVestingPartiallyCancelled(msg.sender, _receiver, nextStartFrom);\n return (nextStartFrom, true);\n } else {\n emit TeamVestingCancelled(msg.sender, _receiver);\n return (end, false);\n }\n }\n\n /**\n * @notice Send user' staked tokens to a receiver taking into account punishments.\n * Sovryn encourages long-term commitment and thinking. When/if you unstake before\n * the end of the staking period, a percentage of the original staking amount will\n * be slashed. This amount is also added to the reward pool and is distributed\n * between all other stakers.\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * Needs to be adjusted to the next valid lock date before calling this function.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdraw(\n uint96 amount,\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n // @dev it's very unlikely some one will have 1/10**18 SOV staked in Vesting contract\n //\t\tthis check is a part of workaround for Vesting.withdrawTokens issue\n if (amount == 1 && _isVestingContract(msg.sender)) {\n return;\n }\n _validateWithdrawParams(msg.sender, amount, until);\n\n /// @dev Determine the receiver.\n if (receiver == address(0)) receiver = msg.sender;\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(msg.sender, until, amount);\n if (_isVestingContract(msg.sender)) _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[msg.sender][until], until, amount);\n\n /// @dev Early unstaking should be punished.\n if (block.timestamp < until && !allUnlocked && !isGovernance) {\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n amount -= punishedAmount;\n\n /// @dev punishedAmount can be 0 if block.timestamp are very close to 'until'\n if (punishedAmount > 0) {\n require(address(feeSharing) != address(0), \"FeeSharing address wasn't set\"); // S08\n /// @dev Move punished amount to fee sharing.\n /// @dev Approve transfer here and let feeSharing do transfer and write checkpoint.\n SOVToken.approve(address(feeSharing), punishedAmount);\n feeSharing.transferTokens(address(SOVToken), punishedAmount);\n }\n }\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(msg.sender, amount, until, receiver, isGovernance);\n }\n\n /**\n * @notice Send user' staked tokens to a receiver.\n * This function is dedicated only for direct withdrawal from staking contract.\n * Currently only being used by cancelTeamVesting()\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender.\n * @param vestingConfig The vesting config.\n * @dev VestingConfig struct intended to avoid stack too deep issue, and it contains this properties:\n address vestingAddress; // vesting contract address\n uint256 startDate; //start date of vesting\n uint256 endDate; // end date of vesting\n uint256 cliff; // after this time period the tokens begin to unlock\n uint256 duration; // after this period all the tokens will be unlocked\n address tokenOwner; // owner of the vested tokens\n * */\n function _withdrawFromTeamVesting(\n uint96 amount,\n uint256 until,\n address receiver,\n VestingConfig memory vestingConfig\n ) internal {\n address vesting = vestingConfig.vestingAddress;\n\n until = _timestampToLockDate(until);\n _validateWithdrawParams(vesting, amount, until);\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(vesting, until, amount);\n\n _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[vesting][until], until, amount);\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(vesting, amount, until, receiver, true);\n }\n\n // @dev withdraws tokens for lock date 2 weeks later than given lock date\n function _withdrawNext(\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n if (_isVestingContract(msg.sender)) {\n // nextLock needs to be adjusted to the next valid lock date to make sure we don't accidentally\n // withdraw stakes that are in the future and would get slashed (if until is not\n // a valid lock date). but until is already handled in the withdraw function\n uint256 nextLock = until.add(TWO_WEEKS);\n if (isGovernance || block.timestamp >= nextLock) {\n uint96 stakes = _getPriorUserStakeByDate(msg.sender, nextLock, block.number - 1);\n if (stakes > 0) {\n _withdraw(stakes, nextLock, receiver, isGovernance);\n }\n }\n }\n }\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked. Adjusted to the next valid lock date, if necessary.\n * @return Amount to withraw and penalty amount\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96)\n {\n until = _adjustDateForOrigin(until);\n _validateWithdrawParams(msg.sender, amount, until);\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n return (amount - punishedAmount, punishedAmount);\n }\n\n /**\n * @notice Get punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _getPunishedAmount(uint96 amount, uint256 until) internal view returns (uint96) {\n uint256 date = _timestampToLockDate(block.timestamp);\n uint96 weight = _computeWeightByDate(until, date); /// @dev (10 - 1) * WEIGHT_FACTOR\n weight = weight * weightScaling;\n return (amount * weight) / WEIGHT_FACTOR / 100;\n }\n\n /**\n * @notice Validate withdraw parameters.\n * @param account Address to be validated.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _validateWithdrawParams(\n address account,\n uint96 amount,\n uint256 until\n ) internal view {\n require(amount > 0, \"Amount of tokens to withdraw must be > 0\"); // S10\n uint96 balance = _getPriorUserStakeByDate(account, until, block.number - 1);\n require(amount <= balance, \"Staking::withdraw: not enough balance\"); // S11\n }\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external onlyOwner whenNotFrozen {\n allUnlocked = true;\n emit TokensUnlocked(SOVToken.balanceOf(address(this)));\n }\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param newMaxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 newMaxIterations)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(newMaxIterations > 0, \"Invalid max iterations\");\n emit MaxVestingWithdrawIterationsUpdated(maxVestingWithdrawIterations, newMaxIterations);\n maxVestingWithdrawIterations = newMaxIterations;\n }\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev This function is dedicated only to support backward compatibility for sovryn ecosystem that has been implementing this staking contract.\n * @dev Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/4bbfe5bd0311ca71e4ef0e3af810d3791d8e4061/contracts/governance/Staking/modules/StakingWithdrawModule.sol#L78\n * */\n function governanceWithdrawVesting(address vesting, address receiver)\n public\n onlyAuthorized\n whenNotFrozen\n {\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n ITeamVesting teamVesting = ITeamVesting(vesting);\n uint256 teamVestingStartDate = teamVesting.startDate();\n uint256 teamVestingCliff = teamVesting.cliff();\n\n uint256 nextStartFrom = teamVestingStartDate + teamVestingCliff;\n bool withdrawFlag = true;\n\n bool notCompleted;\n\n /**\n * The withdrawal is limited to certain iterations (set in maxVestingWithdrawIterations), so in order to withdraw all, we need to iterate until it is fully withdrawn.\n */\n while (withdrawFlag) {\n /**\n * notCompleted is the flag whether the withdrawal is fully withdrawn or not.\n * As long as the notCompleted is true, we will keep the iteration using the nextStartFrom.\n */\n (nextStartFrom, notCompleted) = _cancelTeamVesting(vesting, receiver, nextStartFrom);\n withdrawFlag = notCompleted ? true : false;\n }\n\n emit VestingTokensWithdrawn(vesting, receiver);\n }\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n require(vestingWhitelist[msg.sender], \"unauthorized\"); // S07\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, true);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe don't need to check block.timestamp here\n _withdrawNext(until, receiver, true);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.withdraw.selector;\n functionsList[1] = this.cancelTeamVesting.selector;\n functionsList[2] = this.getWithdrawAmounts.selector;\n functionsList[3] = this.unlockAllTokens.selector;\n functionsList[4] = this.setMaxVestingWithdrawIterations.selector;\n functionsList[5] = this.governanceWithdraw.selector;\n functionsList[6] = this.governanceWithdrawVesting.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/WeightedStakingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Weighted Staking module contract.\n * @notice Implements getters for weighted staking functionality\n * */\ncontract WeightedStakingModule is IFunctionsList, StakingShared, CheckpointsShared {\n /*************************** User Weighted Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The start date/timestamp from which to calculate the weighted stake.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake) {\n return _getPriorWeightedStake(account, blockNumber, date);\n }\n\n function _getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) internal view returns (uint96 priorWeightedStake) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedStakeByDate(account, i, start, blockNumber);\n if (weightedStake > 0) {\n priorWeightedStake = add96(\n priorWeightedStake,\n weightedStake,\n \"overflow on total weight calc\"\n ); // WS12\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n return _weightedStakeByDate(account, date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function _weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorUserStakeByDate(account, date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS13\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight)\n {\n return _computeWeightByDate(date, startDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](3);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/SafeMath96.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n/**\n * @title SafeMath96 contract.\n * @notice Improved Solidity's arithmetic operations with added overflow checks.\n * @dev SafeMath96 uses uint96, unsigned integers of 96 bits length, so every\n * integer from 0 to 2^96-1 can be operated.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * SafeMath restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this contract instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n * */\ncontract SafeMath96 {\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function safe64(uint256 n, string memory errorMessage) internal pure returns (uint64) {\n require(n < 2**64, errorMessage);\n return uint64(n);\n }\n\n function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) {\n require(n < 2**96, errorMessage);\n return uint96(n);\n }\n\n /**\n * @notice Adds two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `+` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe addition a+b.\n * */\n function add96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n uint96 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n /**\n * @notice Substracts two unsigned integers, reverting on underflow.\n * @dev Counterpart to Solidity's `-` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on underflow.\n * @return The safe substraction a-b.\n * */\n function sub96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n require(b <= a, errorMessage);\n return a - b;\n }\n\n /**\n * @notice Multiplies two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `*` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe product a*b.\n * */\n function mul96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n if (a == 0) {\n return 0;\n }\n\n uint96 c = a * b;\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @notice Divides two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `/` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe division a/b.\n * */\n function div96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint96 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n}\n" + }, + "contracts/governance/Staking/StakingProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./modules/shared/StakingStorageShared.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Staking Proxy contract.\n * @dev Staking contract should be upgradable, use UpgradableProxy.\n * StakingStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingProxy is StakingStorageShared, UpgradableProxy {\n /**\n * @notice Construct a new staking contract.\n * @param SOV The address of the SOV token address.\n */\n constructor(address SOV) public {\n SOVToken = IERC20(SOV);\n kickoffTS = block.timestamp;\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewards.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Staking Rewards Contract.\n * @notice This is a trial incentive program.\n * In this, the SOV emitted and becoming liquid from the Adoption Fund could be utilized\n * to offset the higher APY's offered for Liquidity Mining events.\n * Vesting contract stakes are excluded from these rewards.\n * Only wallets which have staked previously liquid SOV are eligible for these rewards.\n * Tokenholders who stake their SOV receive staking rewards, a pro-rata share\n * of the revenue that the platform generates from various transaction fees\n * plus revenues from stakers who have a portion of their SOV slashed for\n * early unstaking.\n * */\ncontract StakingRewards is StakingRewardsStorage {\n using SafeMath for uint256;\n\n /// @notice Emitted when SOV is withdrawn\n /// @param receiver The address which recieves the SOV\n /// @param amount The amount withdrawn from the Smart Contract\n event RewardWithdrawn(address indexed receiver, uint256 amount);\n\n /**\n * @notice Replacement of constructor by initialize function for Upgradable Contracts\n * This function will be called only once by the owner.\n * @param _SOV SOV token address\n * @param _staking StakingProxy address should be passed\n * */\n function initialize(address _SOV, IStaking _staking) external onlyOwner {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n SOV = IERC20(_SOV);\n staking = _staking;\n startTime = staking.timestampToLockDate(block.timestamp);\n setMaxDuration(15 * TWO_WEEKS);\n deploymentBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Stops the current rewards program.\n * @dev All stakes existing on the contract at the point in time of\n * cancellation continue accruing rewards until the end of the staking\n * period being rewarded\n * */\n function stop() external onlyOwner {\n require(stopBlock == 0, \"Already stopped\");\n stopBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Collect rewards\n * @dev User calls this function to collect SOV staking rewards as per the SIP-0024 program.\n * The weighted stake is calculated using getPriorWeightedStake. Block number sent to the functon\n * must be a finalised block, hence we deduct 1 from the current block. User is only allowed to withdraw\n * after intervals of 14 days.\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * The issue is that we can only run for a max duration and if someone stakes for the\n * first time after the max duration is over, the reward will always return 0. Thus, we need to restart\n * from the duration that elapsed without generating rewards.\n * */\n function collectReward(uint256 restartTime) external {\n (uint256 withdrawalTime, uint256 amount) = getStakerCurrentReward(true, restartTime);\n require(withdrawalTime > 0 && amount > 0, \"no valid reward\");\n withdrawals[msg.sender] = withdrawalTime;\n _payReward(msg.sender, amount);\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred.\n */\n function withdrawTokensByOwner(address _receiverAddress) external onlyOwner {\n uint256 value = SOV.balanceOf(address(this));\n _transferSOV(_receiverAddress, value);\n }\n\n /**\n * @notice Changes average block time - based on blockchain\n * @dev If average block time significantly changes, we can update it here and use for block number calculation\n */\n function setAverageBlockTime(uint256 _averageBlockTime) external onlyOwner {\n averageBlockTime = _averageBlockTime;\n }\n\n /**\n * @notice This function computes the last staking checkpoint and calculates the corresponding\n * block number using the average block time which is then added to the mapping `checkpointBlockDetails`.\n */\n function setBlock() external {\n uint256 lastCheckpointTime = staking.timestampToLockDate(block.timestamp);\n _setBlock(lastCheckpointTime);\n }\n\n /**\n * @notice This function computes the block number using the average block time for a given historical\n * checkpoint which is added to the mapping `checkpointBlockDetails`.\n * @param _time Exact staking checkpoint time\n */\n function setHistoricalBlock(uint256 _time) external {\n _setBlock(_time);\n }\n\n /**\n * @notice Sets the max duration\n * @dev Rewards can be collected for a maximum duration at a time. This\n * is to avoid Block Gas Limit failures. Setting it zero would mean that it will loop\n * through the entire duration since the start of rewards program.\n * It should ideally be set to a value, for which the rewards can be easily processed.\n * @param _duration Max duration for which rewards can be collected at a go (in seconds)\n * */\n function setMaxDuration(uint256 _duration) public onlyOwner {\n maxDuration = _duration;\n }\n\n /**\n * @notice Internal function to calculate weighted stake\n * @dev If the rewards program is stopped, the user will still continue to\n * earn till the end of staking period based on the stop block.\n * @param _staker Staker address\n * @param _block Last finalised block\n * @param _date The date to compute prior weighted stakes\n * @return The weighted stake\n * */\n function _computeRewardForDate(\n address _staker,\n uint256 _block,\n uint256 _date\n ) internal view returns (uint256 weightedStake) {\n weightedStake = staking.getPriorWeightedStake(_staker, _block, _date);\n if (stopBlock > 0 && stopBlock < _block) {\n uint256 previousWeightedStake =\n staking.getPriorWeightedStake(_staker, stopBlock, _date);\n if (previousWeightedStake < weightedStake) {\n weightedStake = previousWeightedStake;\n }\n }\n }\n\n /**\n * @notice Internal function to pay rewards\n * @dev Base rate is annual, but we pay interest for 14 days,\n * which is 1/26 of one staking year (1092 days)\n * @param _staker User address\n * @param amount the reward amount\n * */\n function _payReward(address _staker, uint256 amount) internal {\n require(SOV.balanceOf(address(this)) >= amount, \"not enough funds to reward user\");\n claimedBalances[_staker] = claimedBalances[_staker].add(amount);\n _transferSOV(_staker, amount);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit RewardWithdrawn(_receiver, _amount);\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Internal function to calculate and set block\n * */\n function _setBlock(uint256 _checkpointTime) internal {\n uint256 currentTS = block.timestamp;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n require(checkpointBlockDetails[_checkpointTime] == 0, \"block number already set\");\n uint256 checkpointBlock =\n lastFinalisedBlock.sub(((currentTS.sub(_checkpointTime)).div(averageBlockTime)));\n checkpointBlockDetails[_checkpointTime] = checkpointBlock;\n }\n\n /**\n * @notice Get staker's current accumulated reward\n * @dev The collectReward() function internally calls this function to calculate reward amount\n * @param considerMaxDuration True: Runs for the maximum duration - used in tx not to run out of gas\n * False - to query total rewards\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * @return The timestamp of last withdrawal\n * @return The accumulated reward\n */\n function getStakerCurrentReward(bool considerMaxDuration, uint256 restartTime)\n public\n view\n returns (uint256 lastWithdrawalInterval, uint256 amount)\n {\n uint256 weightedStake;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n uint256 currentTS = block.timestamp;\n uint256 duration;\n address staker = msg.sender;\n uint256 lastWithdrawal = withdrawals[staker];\n\n uint256 lastStakingInterval = staking.timestampToLockDate(currentTS);\n lastWithdrawalInterval = lastWithdrawal > 0 ? lastWithdrawal : startTime;\n if (lastStakingInterval <= lastWithdrawalInterval) return (0, 0);\n /* Normally the restart time is 0. If this function returns a valid lastWithdrawalInterval\n\t\tand zero amount - that means there were no valid rewards for that period. So the new period must start\n\t\tfrom the end of the last interval or till the time no rewards are accumulated i.e. restartTime */\n if (restartTime >= lastWithdrawalInterval) {\n uint256 latestRestartTime = staking.timestampToLockDate(restartTime);\n lastWithdrawalInterval = latestRestartTime;\n }\n\n if (considerMaxDuration) {\n uint256 addedMaxDuration = lastWithdrawalInterval.add(maxDuration);\n duration = addedMaxDuration < currentTS\n ? staking.timestampToLockDate(addedMaxDuration)\n : lastStakingInterval;\n } else {\n duration = lastStakingInterval;\n }\n for (uint256 i = lastWithdrawalInterval; i < duration; i += TWO_WEEKS) {\n uint256 referenceBlock = checkpointBlockDetails[i];\n if (referenceBlock == 0) {\n referenceBlock = lastFinalisedBlock.sub(\n ((currentTS.sub(i)).div(averageBlockTime))\n );\n }\n if (referenceBlock < deploymentBlock) referenceBlock = deploymentBlock;\n weightedStake = weightedStake.add(_computeRewardForDate(staker, referenceBlock, i));\n }\n lastWithdrawalInterval = duration;\n amount = weightedStake.mul(BASE_RATE).div(DIVISOR);\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title StakingRewards Proxy contract.\n * @dev StakingRewards contract should be upgradable. Used UpgradableProxy.\n * StakingRewardsStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy with\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingRewardsProxy is StakingRewardsStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking Rewards Storage Contract.\n * @notice Just the storage part of staking rewards contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingRewardsProxy.\n *\n * What is SOV staking rewards - SIP-0024?\n * The purpose of the SOV staking rewards - SIP-0024 is to reward,\n * \"marginal stakers\" (ie, stakers by choice, not currently vesting) with liquid SOV\n * at the beginning of each new staking interval.\n * */\ncontract StakingRewardsStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n ///@notice the staking proxy contract address\n IStaking public staking;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 1209600;\n\n /// @notice Annual Base Rate - it is the maximum interest rate(APY)\n uint256 public constant BASE_RATE = 2975;\n\n /// @notice DIVISOR is set as 2600000 = 26 (num periods per year) * 10 (max voting weight) * 10000 (2975 -> 0.2975)\n uint256 public constant DIVISOR = 2600000;\n\n /// @notice Maximum duration to collect rewards at one go\n uint256 public maxDuration;\n\n /// @notice Represents the time when the contract is deployed\n uint256 public startTime;\n\n /// @notice Represents the block when the Staking Rewards pogram is stopped\n uint256 public stopBlock;\n\n /// @notice User Address -> Last Withdrawn Timestamp\n mapping(address => uint256) public withdrawals;\n\n /// @notice User Address -> Claimed Balance\n mapping(address => uint256) public claimedBalances;\n\n /// @notice Represents the block when the StakingRwards Program is started\n uint256 public deploymentBlock;\n\n /// Moved the variables from Initializable contract to resolve issue caused by incorrect Inheritance Order\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /// @notice BlockTime -> BlockNumber for a Staking Checkpoint\n mapping(uint256 => uint256) public checkpointBlockDetails;\n\n /// @notice Average Block Time - making it flexible\n uint256 public averageBlockTime;\n}\n" + }, + "contracts/governance/Timelock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./ErrorDecoder.sol\";\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\n/**\n * @title Sovryn Protocol Timelock contract, based on Compound system.\n *\n * @notice This contract lets Sovryn governance system set up its\n * own Time Lock instance to execute transactions proposed through the\n * GovernorAlpha contract instance.\n *\n * The Timelock contract allows its admin (Sovryn governance on\n * GovernorAlpha contract) to add arbitrary function calls to a\n * queue. This contract can only execute a function call if the\n * function call has been in the queue for at least 3 hours.\n *\n * Anytime the Timelock contract makes a function call, it must be the\n * case that the function call was first made public by having been publicly\n * added to the queue at least 3 hours prior.\n *\n * The intention is to provide GovernorAlpha contract the functionality to\n * queue proposal actions. This would mean that any changes made by Sovryn\n * governance of any contract would necessarily come with at least an\n * advanced warning. This makes the Sovryn system follow a “time-delayed,\n * opt-out” upgrade pattern (rather than an “instant, forced” upgrade pattern).\n *\n * Time-delaying admin actions gives users a chance to exit system if its\n * admins become malicious or compromised (or make a change that the users\n * do not like). Downside is that honest admins would be unable\n * to lock down functionality to protect users if a critical bug was found.\n *\n * Delayed transactions reduce the amount of trust required by users of Sovryn\n * and the overall risk for contracts building on top of it, as GovernorAlpha.\n * */\ncontract Timelock is ErrorDecoder, ITimelock {\n using SafeMath for uint256;\n\n uint256 public constant GRACE_PERIOD = 14 days;\n uint256 public constant MINIMUM_DELAY = 3 hours;\n uint256 public constant MAXIMUM_DELAY = 30 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /**\n * @notice Function called on instance deployment of the contract.\n * @param admin_ Governance contract address.\n * @param delay_ Time to wait for queued transactions to be executed.\n * */\n constructor(address admin_, uint256 delay_) public {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {}\n\n /**\n * @notice Set a new delay when executing the contract calls.\n * @param delay_ The amount of time to wait until execution.\n * */\n function setDelay(uint256 delay_) public {\n require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n require(delay_ >= MINIMUM_DELAY, \"Timelock::setDelay: Delay must exceed minimum delay.\");\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n /**\n * @notice Accept a new admin for the timelock.\n * */\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n /**\n * @notice Set a new pending admin for the timelock.\n * @param pendingAdmin_ The new pending admin address.\n * */\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n /**\n * @notice Queue a new transaction from the governance contract.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function queueTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public returns (bytes32) {\n require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n /**\n * @notice Cancel a transaction.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function cancelTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public {\n require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n /**\n * @notice Executes a previously queued transaction from the governance.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function executeTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public payable returns (bytes memory) {\n require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call.value(value)(callData);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"Timelock::executeTransaction: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"Timelock::executeTransaction: \", string(returnData)));\n }\n }\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n /**\n * @notice A function used to get the current Block Timestamp.\n * @dev Timestamp of the current block in seconds since the epoch.\n * It is a Unix time stamp. So, it has the complete information about\n * the date, hours, minutes, and seconds (in UTC) when the block was\n * created.\n * */\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" + }, + "contracts/governance/Vesting/DevelopmentFund.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Development Fund.\n * @author Franklin Richards\n * @notice You can use this contract for timed token release from Dev Fund.\n */\ncontract DevelopmentFund {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The current contract status.\n enum Status { Deployed, Active, Expired }\n Status public status;\n\n /// @notice The owner of the locked tokens (usually Governance).\n address public lockedTokenOwner;\n /// @notice The owner of the unlocked tokens (usually MultiSig).\n address public unlockedTokenOwner;\n /// @notice The emergency transfer wallet/contract.\n address public safeVault;\n /// @notice The new locked token owner waiting to be approved.\n address public newLockedTokenOwner;\n\n /// @notice The last token release timestamp or the time of contract creation.\n uint256 public lastReleaseTime;\n\n /// @notice The release duration array in seconds.\n uint256[] public releaseDuration;\n /// @notice The release token amount.\n uint256[] public releaseTokenAmount;\n\n /* Events */\n\n /// @notice Emitted when the contract is activated.\n event DevelopmentFundActivated();\n\n /// @notice Emitted when the contract is expired due to total token transfer.\n event DevelopmentFundExpired();\n\n /// @notice Emitted when a new locked owner is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current locked owner.\n event NewLockedOwnerAdded(address indexed _initiator, address indexed _newLockedOwner);\n\n /// @notice Emitted when a new locked owner is approved to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _oldLockedOwner The address of the previous locked owner.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current unlocked owner.\n event NewLockedOwnerApproved(\n address indexed _initiator,\n address indexed _oldLockedOwner,\n address indexed _newLockedOwner\n );\n\n /// @notice Emitted when a new unlocked owner is updated in the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newUnlockedOwner The address which is updated as the new unlocked owner.\n /// @dev Can only be initiated by the current locked owner.\n event UnlockedOwnerUpdated(address indexed _initiator, address indexed _newUnlockedOwner);\n\n /// @notice Emitted when a new token deposit is done.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new release schedule is created.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseCount The number of releases planned in the schedule.\n event TokenReleaseChanged(address indexed _initiator, uint256 _releaseCount);\n\n /// @notice Emitted when a unlocked owner transfers all the tokens to a safe vault.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token withdrawn.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done in an emergency situation only to a predetermined wallet by locked token owner.\n event LockedTokenTransferByUnlockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /// @notice Emitted when a unlocked owner withdraws the released tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token withdrawn.\n /// @param _releaseCount The total number of releases done based on duration.\n event UnlockedTokenWithdrawalByUnlockedOwner(\n address indexed _initiator,\n uint256 _amount,\n uint256 _releaseCount\n );\n\n /// @notice Emitted when a locked owner transfers all the tokens to a receiver.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token transfer.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done only by locked token owner.\n event LockedTokenTransferByLockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /* Modifiers */\n\n modifier onlyLockedTokenOwner() {\n require(msg.sender == lockedTokenOwner, \"Only Locked Token Owner can call this.\");\n _;\n }\n\n modifier onlyUnlockedTokenOwner() {\n require(msg.sender == unlockedTokenOwner, \"Only Unlocked Token Owner can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _lockedTokenOwner The owner of the locked tokens & contract.\n * @param _safeVault The emergency wallet/contract to transfer token.\n * @param _unlockedTokenOwner The owner of the unlocked tokens.\n * @param _lastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev Initial release schedule should be verified, error will result in either redeployment or calling changeTokenReleaseSchedule() after init() along with token transfer.\n */\n constructor(\n address _SOV,\n address _lockedTokenOwner,\n address _safeVault,\n address _unlockedTokenOwner,\n uint256 _lastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_lockedTokenOwner != address(0), \"Locked token & contract owner address invalid.\");\n require(_safeVault != address(0), \"Safe Vault address invalid.\");\n require(_unlockedTokenOwner != address(0), \"Unlocked token address invalid.\");\n\n SOV = IERC20(_SOV);\n lockedTokenOwner = _lockedTokenOwner;\n safeVault = _safeVault;\n unlockedTokenOwner = _unlockedTokenOwner;\n\n lastReleaseTime = _lastReleaseTime;\n /// If last release time passed is zero, then current time stamp will be used as the last release time.\n if (_lastReleaseTime == 0) {\n lastReleaseTime = block.timestamp;\n }\n\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n }\n\n /**\n * @notice This function is called once after deployment for token transfer based on schedule.\n * @dev Without calling this function, the contract will not work.\n */\n function init() public checkStatus(Status.Deployed) {\n uint256[] memory _releaseTokenAmount = releaseTokenAmount;\n require(_releaseTokenAmount.length != 0, \"Release Schedule not set.\");\n\n /// Getting the current release schedule total token amount.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _releaseTotalTokenAmount);\n require(txStatus, \"Not enough token sent to change release schedule.\");\n\n status = Status.Active;\n\n emit DevelopmentFundActivated();\n }\n\n /**\n * @notice Update Locked Token Owner.\n * @param _newLockedTokenOwner The owner of the locked tokens & contract.\n */\n function updateLockedTokenOwner(address _newLockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newLockedTokenOwner != address(0), \"New locked token owner address invalid.\");\n\n newLockedTokenOwner = _newLockedTokenOwner;\n\n emit NewLockedOwnerAdded(msg.sender, _newLockedTokenOwner);\n }\n\n /**\n * @notice Approve Locked Token Owner.\n * @dev This approval is an added security to avoid development fund takeover by a compromised locked token owner.\n */\n function approveLockedTokenOwner() public onlyUnlockedTokenOwner checkStatus(Status.Active) {\n require(newLockedTokenOwner != address(0), \"No new locked owner added.\");\n\n emit NewLockedOwnerApproved(msg.sender, lockedTokenOwner, newLockedTokenOwner);\n\n lockedTokenOwner = newLockedTokenOwner;\n\n newLockedTokenOwner = address(0);\n }\n\n /**\n * @notice Update Unlocked Token Owner.\n * @param _newUnlockedTokenOwner The new unlocked token owner.\n */\n function updateUnlockedTokenOwner(address _newUnlockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newUnlockedTokenOwner != address(0), \"New unlocked token owner address invalid.\");\n\n unlockedTokenOwner = _newUnlockedTokenOwner;\n\n emit UnlockedOwnerUpdated(msg.sender, _newUnlockedTokenOwner);\n }\n\n /**\n * @notice Deposit tokens to this contract.\n * @param _amount the amount of tokens deposited.\n * @dev These tokens can be withdrawn/transferred any time by the lockedTokenOwner.\n */\n function depositTokens(uint256 _amount) public checkStatus(Status.Active) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDeposit(msg.sender, _amount);\n }\n\n /**\n * @notice Change the Token release schedule. It creates a completely new schedule, and does not append on the previous one.\n * @param _newLastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev _releaseDuration and _releaseTokenAmount should be specified in reverse order of release.\n */\n function changeTokenReleaseSchedule(\n uint256 _newLastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public onlyLockedTokenOwner checkStatus(Status.Active) {\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// If the last release time has to be changed, then you can pass a new one here.\n /// Or else, the duration of release will be calculated based on this timestamp.\n /// Even a future timestamp can be mentioned here.\n if (_newLastReleaseTime != 0) {\n lastReleaseTime = _newLastReleaseTime;\n }\n\n /// Checking if the contract have enough token balance for the release.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n /// Getting the current token balance of the contract.\n uint256 remainingTokens = SOV.balanceOf(address(this));\n\n /// If the token balance is not sufficient, then we transfer the change to contract.\n if (remainingTokens < _releaseTotalTokenAmount) {\n bool txStatus =\n SOV.transferFrom(\n msg.sender,\n address(this),\n _releaseTotalTokenAmount.sub(remainingTokens)\n );\n require(txStatus, \"Not enough token sent to change release schedule.\");\n } else if (remainingTokens > _releaseTotalTokenAmount) {\n /// If there are more tokens than required, send the extra tokens back.\n bool txStatus =\n SOV.transfer(msg.sender, remainingTokens.sub(_releaseTotalTokenAmount));\n require(txStatus, \"Token not received by the Locked Owner.\");\n }\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n\n emit TokenReleaseChanged(msg.sender, _releaseDuration.length);\n }\n\n /**\n * @notice Transfers all of the remaining tokens in an emergency situation.\n * @dev This could be called when governance or development fund might be compromised.\n */\n function transferTokensByUnlockedTokenOwner()\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(safeVault, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByUnlockedOwner(msg.sender, safeVault, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /**\n * @notice Withdraws all unlocked/released token.\n * @param _amount The amount to be withdrawn.\n */\n function withdrawTokensByUnlockedTokenOwner(uint256 _amount)\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_amount > 0, \"Zero can't be withdrawn.\");\n\n uint256 count; /// To know how many elements to be removed from the release schedule.\n uint256 amount = _amount; /// To know the total amount to be transferred.\n uint256 newLastReleaseTimeMemory = lastReleaseTime; /// Better to use memory than storage.\n uint256 releaseLength = releaseDuration.length.sub(1); /// Also checks if there are any elements in the release schedule.\n\n /// Getting the amount of tokens, the number of releases and calculating the total duration.\n while (\n amount > 0 &&\n newLastReleaseTimeMemory.add(releaseDuration[releaseLength]) < block.timestamp\n ) {\n if (amount >= releaseTokenAmount[releaseLength]) {\n amount = amount.sub(releaseTokenAmount[releaseLength]);\n newLastReleaseTimeMemory = newLastReleaseTimeMemory.add(\n releaseDuration[releaseLength]\n );\n count++;\n } else {\n /// This will be the last case, if correct amount is passed.\n releaseTokenAmount[releaseLength] = releaseTokenAmount[releaseLength].sub(amount);\n amount = 0;\n }\n releaseLength--;\n }\n\n /// Checking to see if atleast a single schedule was reached or not.\n require(count > 0 || amount == 0, \"No release schedule reached.\");\n\n /// If locked token owner tries to send a higher amount that schedule\n uint256 value = _amount.sub(amount);\n\n /// Now clearing up the release schedule.\n releaseDuration.length -= count;\n releaseTokenAmount.length -= count;\n\n /// Updating the last release time.\n lastReleaseTime = newLastReleaseTimeMemory;\n\n /// Sending the amount to unlocked token owner.\n bool txStatus = SOV.transfer(msg.sender, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit UnlockedTokenWithdrawalByUnlockedOwner(msg.sender, value, count);\n }\n\n /**\n * @notice Transfers all of the remaining tokens by the owner maybe for an upgrade.\n * @dev This could be called when the current development fund has to be upgraded.\n * @param _receiver The address which receives this token transfer.\n */\n function transferTokensByLockedTokenOwner(address _receiver)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(_receiver, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByLockedOwner(msg.sender, _receiver, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token release duration.\n * @return _currentReleaseDuration The current release duration.\n */\n function getReleaseDuration() public view returns (uint256[] memory _releaseTokenDuration) {\n return releaseDuration;\n }\n\n /**\n * @notice Function to read the current token release amount.\n * @return _currentReleaseTokenAmount The current release token amount.\n */\n function getReleaseTokenAmount()\n public\n view\n returns (uint256[] memory _currentReleaseTokenAmount)\n {\n return releaseTokenAmount;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../IFeeSharingCollector.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../proxy/UpgradableProxy.sol\";\nimport \"../../../openzeppelin/Address.sol\";\n\n/**\n * @title Four Year Vesting Contract.\n *\n * @notice A four year vesting contract.\n *\n * @dev Vesting contract is upgradable,\n * Make sure the vesting owner is multisig otherwise it will be\n * catastrophic.\n * */\ncontract FourYearVesting is FourYearVestingStorage, UpgradableProxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharingCollector Fee sharing proxy address.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n address _feeSharingCollector,\n uint256 _extendDurationFor\n ) public {\n require(Address.isContract(_logic), \"_logic not a contract\");\n require(_SOV != address(0), \"SOV address invalid\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(Address.isContract(_stakingAddress), \"_stakingAddress not a contract\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(Address.isContract(_feeSharingCollector), \"_feeSharingCollector not a contract\");\n require((_extendDurationFor % FOUR_WEEKS) == 0, \"invalid duration\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n tokenOwner = _tokenOwner;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n maxInterval = 18 * FOUR_WEEKS;\n extendDurationFor = _extendDurationFor;\n }\n\n /**\n * @notice Set address of the implementation - vesting owner.\n * @dev Overriding setImplementation function of UpgradableProxy. The logic can only be\n * modified when both token owner and veting owner approve. Since\n * setImplementation can only be called by vesting owner, we also need to check\n * if the new logic is already approved by the token owner.\n * @param _implementation Address of the implementation. Must match with what is set by token owner.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n require(Address.isContract(_implementation), \"_implementation not a contract\");\n require(newImplementation == _implementation, \"address mismatch\");\n _setImplementation(_implementation);\n newImplementation = address(0);\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"./FourYearVesting.sol\";\nimport \"./IFourYearVestingFactory.sol\";\n\n/**\n * @title Four Year Vesting Factory: Contract to deploy four year vesting contracts.\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract FourYearVestingFactory is IFourYearVestingFactory, Ownable {\n /// @dev Added an event to keep track of the vesting contract created for a token owner\n event FourYearVestingCreated(address indexed tokenOwner, address indexed vestingAddress);\n\n /**\n * @notice Deploys four year vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwnerMultisig The address of an owner of vesting contract.\n * @dev _vestingOwnerMultisig should ALWAYS be multisig.\n * @param _fourYearVestingLogic The implementation contract.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * @return The four year vesting contract address.\n * */\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external onlyOwner returns (address) {\n address fourYearVesting =\n address(\n new FourYearVesting(\n _fourYearVestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _feeSharing,\n _extendDurationFor\n )\n );\n Ownable(fourYearVesting).transferOwnership(_vestingOwnerMultisig);\n emit FourYearVestingCreated(_tokenOwner, fourYearVesting);\n return fourYearVesting;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./IFourYearVesting.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Four Year Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by FourYearVestingFactory contract.\n * */\ncontract FourYearVestingLogic is IFourYearVesting, FourYearVestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n\n /* Events */\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n event TokenOwnerChanged(address indexed newOwner, address indexed oldOwner);\n\n /* Modifiers */\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Sets the max interval.\n * @param _interval Max interval for which tokens scheduled shall be staked.\n * */\n function setMaxInterval(uint256 _interval) external onlyOwner {\n require(_interval.mod(FOUR_WEEKS) == 0, \"invalid interval\");\n maxInterval = _interval;\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount)\n {\n (lastSchedule, remainingAmount) = _stakeTokens(msg.sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokensWithApproval(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) external onlyThisContract returns (uint256 lastSchedule, uint256 remainingAmount) {\n (lastSchedule, remainingAmount) = _stakeTokens(_sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) external onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n uint256 stakingEndDate = endDate;\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate.add(cliff); i <= stakingEndDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) external onlyTokenOwner {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external onlyTokenOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Change token owner - only vesting owner is allowed to change.\n * @dev Modifies token owner. This must be followed by approval\n * from token owner.\n * @param _newTokenOwner Address of new token owner.\n * */\n function changeTokenOwner(address _newTokenOwner) public onlyOwner {\n require(_newTokenOwner != address(0), \"invalid new token owner address\");\n require(_newTokenOwner != tokenOwner, \"same owner not allowed\");\n newTokenOwner = _newTokenOwner;\n }\n\n /**\n * @notice Approve token owner change - only token Owner.\n * @dev Token owner can only be modified\n * when both vesting owner and token owner have approved. This\n * function ascertains the approval of token owner.\n * */\n function approveOwnershipTransfer() public onlyTokenOwner {\n require(newTokenOwner != address(0), \"invalid address\");\n tokenOwner = newTokenOwner;\n newTokenOwner = address(0);\n emit TokenOwnerChanged(tokenOwner, msg.sender);\n }\n\n /**\n * @notice Set address of the implementation - only Token Owner.\n * @dev This function sets the new implementation address.\n * It must also be approved by the Vesting owner.\n * @param _newImplementation Address of the new implementation.\n * */\n function setImpl(address _newImplementation) public onlyTokenOwner {\n require(_newImplementation != address(0), \"invalid new implementation address\");\n newImplementation = _newImplementation;\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() external onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Extends stakes(unlocked till timeDuration) for four year vesting contracts.\n * @dev Tokens are vested for 4 years. Since the max staking\n * period is 3 years and the tokens are unlocked only after the first year(timeDuration) is\n * passed, hence, we usually extend the duration of staking for all unlocked tokens for the first\n * year by 3 years. In some cases, the timeDuration can differ.\n * */\n function extendStaking() external {\n uint256 timeDuration = startDate.add(extendDurationFor);\n uint256[] memory dates;\n uint96[] memory stakes;\n (dates, stakes) = staking.getStakes(address(this));\n\n for (uint256 i = 0; i < dates.length; i++) {\n if ((dates[i] < block.timestamp) && (dates[i] <= timeDuration) && (stakes[i] > 0)) {\n staking.extendStakingDuration(dates[i], dates[i].add(156 weeks));\n endDate = dates[i].add(156 weeks);\n } else {\n break;\n }\n }\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function _stakeTokens(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) internal returns (uint256 lastSchedule, uint256 remainingAmount) {\n // Creating a new staking schedule for the same vesting contract is disallowed unlike normal vesting\n require(\n (startDate == 0) ||\n (startDate > 0 && remainingStakeAmount > 0 && _restartStakeSchedule > 0),\n \"create new vesting address\"\n );\n uint256 restartDate;\n uint256 relativeAmount;\n // Calling the _stakeTokens function first time for the vesting contract\n // Runs for maxInterval only (consider maxInterval = 18 * 4 = 72 weeks)\n if (startDate == 0 && _restartStakeSchedule == 0) {\n startDate = staking.timestampToLockDate(block.timestamp); // Set only once\n durationLeft = duration; // We do not touch duration and cliff as they are used throughout\n cliffAdded = cliff; // Hence, durationLeft and cliffAdded is created\n }\n // Calling the _stakeTokens second/third time - we start from the end of previous interval\n // and the remaining amount(amount left after tokens are staked in the previous interval)\n if (_restartStakeSchedule > 0) {\n require(\n _restartStakeSchedule == lastStakingSchedule && _amount == remainingStakeAmount,\n \"invalid params\"\n );\n restartDate = _restartStakeSchedule;\n } else {\n restartDate = startDate;\n }\n // Runs only once when the _stakeTokens is called for the first time\n if (endDate == 0) {\n endDate = staking.timestampToLockDate(block.timestamp.add(duration));\n }\n uint256 addedMaxInterval = restartDate.add(maxInterval); // run for maxInterval\n if (addedMaxInterval < endDate) {\n // Runs for max interval\n lastStakingSchedule = addedMaxInterval;\n relativeAmount = (_amount.mul(maxInterval)).div(durationLeft); // (_amount * 18) / 39\n durationLeft = durationLeft.sub(maxInterval); // durationLeft - 18 periods(72 weeks)\n remainingStakeAmount = _amount.sub(relativeAmount); // Amount left to be staked in subsequent intervals\n } else {\n // Normal run\n lastStakingSchedule = endDate; // if staking intervals left < 18 periods(72 weeks)\n remainingStakeAmount = 0;\n durationLeft = 0;\n relativeAmount = _amount; // Stake all amount left\n }\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), relativeAmount);\n require(success, \"transfer failed\");\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), relativeAmount);\n\n staking.stakesBySchedule(\n relativeAmount,\n cliffAdded,\n duration.sub(durationLeft),\n FOUR_WEEKS,\n address(this),\n tokenOwner\n );\n if (durationLeft == 0) {\n // All tokens staked\n cliffAdded = 0;\n } else {\n cliffAdded = cliffAdded.add(maxInterval); // Add cliff to the end of previous maxInterval\n }\n\n emit TokensStaked(_sender, relativeAmount);\n return (lastStakingSchedule, remainingStakeAmount);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n /// @dev For four year vesting, withdrawal of stakes for the first year is not allowed. These\n /// stakes are extended for three years. In some cases the withdrawal may be allowed at a different\n /// time and hence we use extendDurationFor.\n for (uint256 i = startDate.add(extendDurationFor); i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number.sub(1));\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../Staking/interfaces/IStaking.sol\";\nimport \"../../IFeeSharingCollector.sol\";\n\n/**\n * @title Four Year Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for four year vesting.\n * It is parent of FourYearVestingLogic and FourYearVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract FourYearVestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n // Used lower case for cliff and duration to maintain consistency with normal vesting\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public constant cliff = 4 weeks;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public constant duration = 156 weeks;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n /// @notice Maximum interval to stake tokens at one go\n uint256 public maxInterval;\n\n /// @notice End of previous staking schedule.\n uint256 public lastStakingSchedule;\n\n /// @notice Amount of shares left to be staked.\n uint256 public remainingStakeAmount;\n\n /// @notice Durations left.\n uint256 public durationLeft;\n\n /// @notice Cliffs added.\n uint256 public cliffAdded;\n\n /// @notice Address of new token owner.\n address public newTokenOwner;\n\n /// @notice Address of new implementation.\n address public newImplementation;\n\n /// @notice Duration(from start) till the time unlocked tokens are extended(for 3 years)\n uint256 public extendDurationFor;\n\n /// @dev Please add new state variables below this line. Mark them internal and\n /// add a getter function while upgrading the contracts.\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IFourYearVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IFourYearVesting {\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount);\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingFactory contract to override empty\n * implemention of deployFourYearVesting function\n * and use an instance of FourYearVestingFactory.\n */\ninterface IFourYearVestingFactory {\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/GenericTokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\n\n/**\n * @title Token sender contract.\n *\n * @notice This contract includes functions to transfer tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract GenericTokenSender is AdminRole {\n /* Events */\n\n event TokensTransferred(address indexed token, address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer given amounts of tokens to the given addresses.\n * @param _token The address of the token.\n * @param _receivers The addresses of the receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferTokensUsingList(\n address _token,\n address[] calldata _receivers,\n uint256[] calldata _amounts\n ) external onlyAuthorized {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferTokens(_token, _receivers[i], _amounts[i]);\n }\n }\n\n function() external payable {}\n\n /**\n * @notice Transfer tokens to given address.\n * @param _token The address of the token.\n * @param _receiver The address of the token receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) external onlyAuthorized {\n _transferTokens(_token, _receiver, _amount);\n }\n\n function _transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n if (_token != address(0)) {\n require(IERC20(_token).transfer(_receiver, _amount), \"transfer failed\");\n } else {\n (bool success, ) = _receiver.call.value(_amount)(\"\");\n require(success, \"RBTC transfer failed\");\n }\n emit TokensTransferred(_token, _receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/ITeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for TeamVesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by Staking contract to cancel the team vesting\n * function having the vesting contract instance address.\n */\ninterface ITeamVesting {\n function startDate() external view returns (uint256);\n\n function cliff() external view returns (uint256);\n\n function endDate() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function tokenOwner() external view returns (address);\n\n function governanceWithdrawTokens(address receiver) external;\n}\n" + }, + "contracts/governance/Vesting/IVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IVesting {\n function duration() external returns (uint256);\n\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 amount) external;\n\n function tokenOwner() external view returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingFactory contract to override empty\n * implemention of deployVesting and deployTeamVesting functions\n * and on VestingRegistry contract to use an instance of VestingFactory.\n */\ninterface IVestingFactory {\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for upgradable Vesting Registry contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IVestingRegistry {\n function getVesting(address _tokenOwner) external view returns (address);\n\n function getTeamVesting(address _tokenOwner) external view returns (address);\n\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n function isVestingAddress(address _vestingAddress) external view returns (bool);\n\n function isTeamVesting(address _vestingAddress) external view returns (bool);\n}\n" + }, + "contracts/governance/Vesting/OrigingVestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./VestingRegistry.sol\";\n\n/**\n * @title Temp contract for checking address, creating and staking tokens.\n * @notice It casts an instance of vestingRegistry and by using createVesting\n * function it creates a vesting, gets it and stakes some tokens w/ this vesting.\n * */\ncontract OrigingVestingCreator is Ownable {\n VestingRegistry public vestingRegistry;\n\n mapping(address => bool) processedList;\n\n constructor(address _vestingRegistry) public {\n vestingRegistry = VestingRegistry(_vestingRegistry);\n }\n\n /**\n * @notice Create a vesting, get it and stake some tokens w/ this vesting.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount of tokens to be vested.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyOwner {\n require(_tokenOwner != address(0), \"Invalid address\");\n require(!processedList[_tokenOwner], \"Already processed\");\n\n processedList[_tokenOwner] = true;\n\n vestingRegistry.createVesting(_tokenOwner, _amount, _cliff, _duration);\n address vesting = vestingRegistry.getVesting(_tokenOwner);\n vestingRegistry.stakeTokens(vesting, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/OriginInvestorsClaim.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./VestingRegistry.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\n\n/**\n * @title Origin investors claim vested cSOV tokens.\n * @notice // TODO: fund this contract with a total amount of SOV needed to distribute.\n * */\ncontract OriginInvestorsClaim is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// VestingRegistry public constant vestingRegistry = VestingRegistry(0x80B036ae59B3e38B573837c01BB1DB95515b7E6B);\n\n uint256 public totalAmount;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant SOV_VESTING_CLIFF = 6 weeks;\n\n uint256 public kickoffTS;\n uint256 public vestingTerm;\n uint256 public investorsQty;\n bool public investorsListInitialized;\n VestingRegistry public vestingRegistry;\n IStaking public staking;\n IERC20 public SOVToken;\n\n /// @dev user => flag : Whether user has admin role.\n mapping(address => bool) public admins;\n\n /// @dev investor => Amount : Origin investors entitled to claim SOV.\n mapping(address => uint256) public investorsAmountsList;\n\n /* Events */\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n event InvestorsAmountsListAppended(uint256 qty, uint256 amount);\n event ClaimVested(address indexed investor, uint256 amount);\n event ClaimTransferred(address indexed investor, uint256 amount);\n event InvestorsAmountsListInitialized(uint256 qty, uint256 totalAmount);\n\n /* Modifiers */\n\n /// @dev Throws if called by any account other than the owner or admin.\n modifier onlyAuthorized() {\n require(\n isOwner() || admins[msg.sender],\n \"OriginInvestorsClaim::onlyAuthorized: should be authorized\"\n );\n _;\n }\n\n /// @dev Throws if called by any account not whitelisted.\n modifier onlyWhitelisted() {\n require(\n investorsAmountsList[msg.sender] != 0,\n \"OriginInvestorsClaim::onlyWhitelisted: not whitelisted or already claimed\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an initialized investors list.\n modifier notInitialized() {\n require(\n !investorsListInitialized,\n \"OriginInvestorsClaim::notInitialized: the investors list should not be set as initialized\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an uninitialized investors list.\n modifier initialized() {\n require(\n investorsListInitialized,\n \"OriginInvestorsClaim::initialized: the investors list has not been set yet\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires one parameter:\n * @param vestingRegistryAddress The vestingRegistry contract instance address.\n * */\n constructor(address vestingRegistryAddress) public {\n vestingRegistry = VestingRegistry(vestingRegistryAddress);\n staking = IStaking(vestingRegistry.staking());\n kickoffTS = staking.kickoffTS();\n SOVToken = IERC20(staking.SOVToken());\n vestingTerm = kickoffTS + SOV_VESTING_CLIFF;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice In case we have unclaimed tokens or in emergency case\n * this function transfers all SOV tokens to a given address.\n * @param toAddress The recipient address of all this contract tokens.\n * */\n function authorizedBalanceWithdraw(address toAddress) public onlyAuthorized {\n require(\n SOVToken.transfer(toAddress, SOVToken.balanceOf(address(this))),\n \"OriginInvestorsClaim::authorizedTransferBalance: transfer failed\"\n );\n }\n\n /**\n * @notice Should be called after the investors list setup completed.\n * This function checks whether the SOV token balance of the contract is\n * enough and sets status list to initialized.\n * */\n function setInvestorsAmountsListInitialized() public onlyAuthorized notInitialized {\n require(\n SOVToken.balanceOf(address(this)) >= totalAmount,\n \"OriginInvestorsClaim::setInvestorsAmountsList: the contract is not enough financed\"\n );\n\n investorsListInitialized = true;\n\n emit InvestorsAmountsListInitialized(investorsQty, totalAmount);\n }\n\n /**\n * @notice The contract should be approved or transferred necessary\n * amount of SOV prior to calling the function.\n * @param investors The list of investors addresses to add to the list.\n * Duplicates will be skipped.\n * @param claimAmounts The list of amounts for investors investors[i]\n * will receive claimAmounts[i] of SOV.\n * */\n function appendInvestorsAmountsList(\n address[] calldata investors,\n uint256[] calldata claimAmounts\n ) external onlyAuthorized notInitialized {\n uint256 subQty;\n uint256 sumAmount;\n require(\n investors.length == claimAmounts.length,\n \"OriginInvestorsClaim::appendInvestorsAmountsList: investors.length != claimAmounts.length\"\n );\n\n for (uint256 i = 0; i < investors.length; i++) {\n if (investorsAmountsList[investors[i]] == 0) {\n investorsAmountsList[investors[i]] = claimAmounts[i];\n sumAmount = sumAmount.add(claimAmounts[i]);\n } else {\n subQty = subQty.add(1);\n }\n }\n\n investorsQty = investorsQty.add(investors.length.sub(subQty));\n totalAmount = totalAmount.add(sumAmount);\n emit InvestorsAmountsListAppended(investors.length.sub(subQty), sumAmount);\n }\n\n /**\n * @notice Claim tokens from this contract.\n * If vestingTerm is not yet achieved a vesting is created.\n * Otherwise tokens are tranferred.\n * */\n function claim() external onlyWhitelisted initialized {\n if (now < vestingTerm) {\n createVesting();\n } else {\n transfer();\n }\n }\n\n /**\n * @notice Transfer tokens from this contract to a vestingRegistry contract.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to vesting contract.\n * */\n function createVesting() internal {\n uint256 cliff = vestingTerm.sub(now);\n uint256 duration = cliff;\n uint256 amount = investorsAmountsList[msg.sender];\n address vestingContractAddress;\n\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n vestingContractAddress == address(0),\n \"OriginInvestorsClaim::withdraw: the claimer has an active vesting contract\"\n );\n\n delete investorsAmountsList[msg.sender];\n\n vestingRegistry.createVesting(msg.sender, amount, cliff, duration);\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n SOVToken.transfer(address(vestingRegistry), amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n vestingRegistry.stakeTokens(vestingContractAddress, amount);\n\n emit ClaimVested(msg.sender, amount);\n }\n\n /**\n * @notice Transfer tokens from this contract to the sender.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to its account.\n * */\n function transfer() internal {\n uint256 amount = investorsAmountsList[msg.sender];\n\n delete investorsAmountsList[msg.sender];\n\n /**\n * @dev Withdraw only for those claiming after the cliff, i.e. without vesting contracts.\n * Those with vestingContracts should withdraw using Vesting.withdrawTokens\n * from Vesting (VestingLogic) contract.\n * */\n require(\n SOVToken.transfer(msg.sender, amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n\n emit ClaimTransferred(msg.sender, amount);\n }\n}\n" + }, + "contracts/governance/Vesting/TeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n//import \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../proxy/Proxy.sol\";\n\n/**\n * @title Team Vesting Contract.\n *\n * @notice A regular vesting contract, but the owner (governance) is able to\n * withdraw earlier without a slashing.\n *\n * @dev Vesting contracts shouldn't be upgradable,\n * use Proxy instead of UpgradableProxy.\n * */\ncontract TeamVesting is VestingStorage, Proxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollector\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_duration >= _cliff, \"duration must be bigger than or equal to the cliff\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n require(_duration <= staking.MAX_DURATION(), \"duration may not exceed the max duration\");\n tokenOwner = _tokenOwner;\n cliff = _cliff;\n duration = _duration;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n }\n}\n" + }, + "contracts/governance/Vesting/TokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title SOV Token sender contract.\n *\n * @notice This contract includes functions to transfer SOV tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract TokenSender is Ownable {\n /* Storage */\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @dev user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n constructor(address _SOV) public {\n require(_SOV != address(0), \"SOV address invalid\");\n\n SOV = _SOV;\n }\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Transfer given amounts of SOV to the given addresses.\n * @param _receivers The addresses of the SOV receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferSOVusingList(address[] memory _receivers, uint256[] memory _amounts)\n public\n onlyAuthorized\n {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferSOV(_receivers[i], _amounts[i]);\n }\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyAuthorized {\n _transferSOV(_receiver, _amount);\n }\n\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/Vesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./TeamVesting.sol\";\n\n/**\n * @title Vesting Contract.\n * @notice Team tokens and investor tokens are vested. Therefore, a smart\n * contract needs to be developed to enforce the vesting schedule.\n *\n * */\ncontract Vesting is TeamVesting {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollectorProxy\n )\n public\n TeamVesting(\n _logic,\n _SOV,\n _stakingAddress,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharingCollectorProxy\n )\n {}\n\n /**\n * @dev We need to add this implementation to prevent proxy call VestingLogic.governanceWithdrawTokens\n * @param receiver The receiver of the token withdrawal.\n * */\n function governanceWithdrawTokens(address receiver) public {\n revert(\"operation not supported\");\n }\n}\n" + }, + "contracts/governance/Vesting/VestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"./VestingRegistryLogic.sol\";\nimport \"./VestingLogic.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingCreator is AdminRole {\n using SafeMath for uint256;\n\n ///@notice Boolean to check both vesting creation and staking is completed for a record\n bool vestingCreated;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 2 weeks;\n\n ///@notice the SOV token contract\n IERC20 public SOV;\n\n ///@notice the vesting registry contract\n VestingRegistryLogic public vestingRegistryLogic;\n\n ///@notice Holds Vesting Data\n struct VestingData {\n uint256 amount;\n uint256 cliff;\n uint256 duration;\n bool governanceControl; ///@dev true - tokens can be withdrawn by governance\n address tokenOwner;\n uint256 vestingCreationType;\n }\n\n ///@notice list of vesting to be processed\n VestingData[] public vestingDataList;\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event TokensStaked(address indexed vesting, address indexed tokenOwner, uint256 amount);\n event VestingDataRemoved(address indexed caller, address indexed tokenOwner);\n event DataCleared(address indexed caller);\n\n constructor(address _SOV, address _vestingRegistryProxy) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_vestingRegistryProxy != address(0), \"Vesting registry address invalid\");\n\n SOV = IERC20(_SOV);\n vestingRegistryLogic = VestingRegistryLogic(_vestingRegistryProxy);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings to be processed to the list\n */\n function addVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _amounts,\n uint256[] calldata _cliffs,\n uint256[] calldata _durations,\n bool[] calldata _governanceControls,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n require(\n _tokenOwners.length == _amounts.length &&\n _tokenOwners.length == _cliffs.length &&\n _tokenOwners.length == _durations.length &&\n _tokenOwners.length == _governanceControls.length,\n \"arrays mismatch\"\n );\n\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(\n _durations[i] >= _cliffs[i],\n \"duration must be bigger than or equal to the cliff\"\n );\n require(_amounts[i] > 0, \"vesting amount cannot be 0\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_cliffs[i].mod(TWO_WEEKS) == 0, \"cliffs should have intervals of two weeks\");\n require(\n _durations[i].mod(TWO_WEEKS) == 0,\n \"durations should have intervals of two weeks\"\n );\n VestingData memory vestingData =\n VestingData({\n amount: _amounts[i],\n cliff: _cliffs[i],\n duration: _durations[i],\n governanceControl: _governanceControls[i],\n tokenOwner: _tokenOwners[i],\n vestingCreationType: _vestingCreationTypes[i]\n });\n vestingDataList.push(vestingData);\n }\n }\n\n /**\n * @notice Creates vesting contract and stakes tokens\n * @dev Vesting and Staking are merged for calls that fits the gas limit\n */\n function processNextVesting() external {\n processVestingCreation();\n processStaking();\n }\n\n /**\n * @notice Creates vesting contract without staking any tokens\n * @dev Separating the Vesting and Staking to tackle Block Gas Limit\n */\n function processVestingCreation() public {\n require(!vestingCreated, \"staking not done for the previous vesting\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n _createAndGetVesting(vestingData);\n vestingCreated = true;\n }\n }\n\n /**\n * @notice Staking vested tokens\n * @dev it can be the case when vesting creation and tokens staking can't be done in one transaction because of block gas limit\n */\n function processStaking() public {\n require(vestingCreated, \"cannot stake without vesting creation\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n address vestingAddress =\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n require(SOV.approve(address(vesting), vestingData.amount), \"Approve failed\");\n vesting.stakeTokens(vestingData.amount);\n emit TokensStaked(vestingAddress, vestingData.tokenOwner, vestingData.amount);\n address tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n vestingCreated = false;\n }\n\n /**\n * @notice removes next vesting data from the list\n * @dev we process inverted list\n * @dev we should be able to remove incorrect vesting data that can't be processed\n */\n function removeNextVesting() external onlyAuthorized {\n address tokenOwnerDetails;\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n\n /**\n * @notice removes all data about unprocessed vestings to be processed\n */\n function clearVestingDataList() public onlyAuthorized {\n delete vestingDataList;\n emit DataCleared(msg.sender);\n }\n\n /**\n * @notice returns address after vesting creation\n */\n function getVestingAddress() external view returns (address) {\n return\n _getVesting(\n vestingDataList[vestingDataList.length - 1].tokenOwner,\n vestingDataList[vestingDataList.length - 1].cliff,\n vestingDataList[vestingDataList.length - 1].duration,\n vestingDataList[vestingDataList.length - 1].governanceControl,\n vestingDataList[vestingDataList.length - 1].vestingCreationType\n );\n }\n\n /**\n * @notice returns period i.e. ((duration - cliff) / 4 WEEKS)\n * @dev will be used for deciding if vesting and staking needs to be processed\n * in a single transaction or separate transactions\n */\n function getVestingPeriod() external view returns (uint256) {\n uint256 duration = vestingDataList[vestingDataList.length - 1].duration;\n uint256 cliff = vestingDataList[vestingDataList.length - 1].cliff;\n uint256 fourWeeks = TWO_WEEKS.mul(2);\n uint256 period = duration.sub(cliff).div(fourWeeks);\n return period;\n }\n\n /**\n * @notice returns count of vestings to be processed\n */\n function getUnprocessedCount() external view returns (uint256) {\n return vestingDataList.length;\n }\n\n /**\n * @notice returns total amount of vestings to be processed\n */\n function getUnprocessedAmount() public view returns (uint256) {\n uint256 amount = 0;\n uint256 length = vestingDataList.length;\n for (uint256 i = 0; i < length; i++) {\n amount = amount.add(vestingDataList[i].amount);\n }\n return amount;\n }\n\n /**\n * @notice checks if contract balance is enough to process all vestings\n */\n function isEnoughBalance() public view returns (bool) {\n return SOV.balanceOf(address(this)) >= getUnprocessedAmount();\n }\n\n /**\n * @notice returns missed balance to process all vestings\n */\n function getMissingBalance() external view returns (uint256) {\n if (isEnoughBalance()) {\n return 0;\n }\n return getUnprocessedAmount() - SOV.balanceOf(address(this));\n }\n\n /**\n * @notice creates TeamVesting or Vesting contract\n * @dev new contract won't be created if account already has contract of the same type\n */\n function _createAndGetVesting(VestingData memory vestingData)\n internal\n returns (address vesting)\n {\n if (vestingData.governanceControl) {\n vestingRegistryLogic.createTeamVesting(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n } else {\n vestingRegistryLogic.createVestingAddr(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n }\n return\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n }\n\n /**\n * @notice returns an address of TeamVesting or Vesting contract (depends on a governance control)\n */\n function _getVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n bool _governanceControl,\n uint256 _vestingCreationType\n ) internal view returns (address vestingAddress) {\n if (_governanceControl) {\n vestingAddress = vestingRegistryLogic.getTeamVesting(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n } else {\n vestingAddress = vestingRegistryLogic.getVestingAddr(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n }\n }\n}\n" + }, + "contracts/governance/Vesting/VestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./Vesting.sol\";\nimport \"./TeamVesting.sol\";\nimport \"./IVestingFactory.sol\";\n\n/**\n * @title Vesting Factory: Contract to deploy vesting contracts\n * of two types: vesting (TokenHolder) and team vesting (Multisig).\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract VestingFactory is IVestingFactory, Ownable {\n address public vestingLogic;\n\n constructor(address _vestingLogic) public {\n require(_vestingLogic != address(0), \"invalid vesting logic address\");\n vestingLogic = _vestingLogic;\n }\n\n /**\n * @notice Deploys Vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner /// @dev owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new Vesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n\n /**\n * @notice Deploys Team Vesting contract.\n * @param _SOV The address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner //owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new TeamVesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by a VestingFactory contract.\n * */\ncontract VestingLogic is IVesting, VestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n /* Events */\n\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(\n address indexed caller,\n address receiver,\n uint256 startFrom,\n uint256 end\n );\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(uint256 _amount) public {\n _stakeTokens(msg.sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokensWithApproval(address _sender, uint256 _amount) public onlyThisContract {\n _stakeTokens(_sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * */\n function _stakeTokens(address _sender, uint256 _amount) internal {\n /// @dev Maybe better to allow staking unil the cliff was reached.\n if (startDate == 0) {\n startDate = staking.timestampToLockDate(block.timestamp);\n }\n endDate = staking.timestampToLockDate(block.timestamp + duration);\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), _amount);\n require(success);\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), _amount);\n\n staking.stakeBySchedule(_amount, cliff, duration, FOUR_WEEKS, address(this), tokenOwner);\n\n emit TokensStaked(_sender, _amount);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) public onlyOwners {\n uint256 startFrom = startDate + cliff;\n _withdrawTokens(receiver, startFrom, block.timestamp);\n }\n\n /**\n * @notice Withdraws unlocked tokens partially (based on the max withdraw iteration that has been set) from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n * @param maxWithdrawIterations max withdrawal iteration to work around block gas limit issue.\n * */\n function withdrawTokensStartingFrom(\n address receiver,\n uint256 startFrom,\n uint256 maxWithdrawIterations\n ) public onlyOwners {\n uint256 defaultStartFrom = startDate + cliff;\n\n startFrom = _timestampToLockDate(startFrom);\n startFrom = startFrom < defaultStartFrom ? defaultStartFrom : startFrom;\n\n // @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 maxWithdrawDate = (startFrom + (FOUR_WEEKS * (maxWithdrawIterations.sub(1))));\n uint256 endAt = endDate < maxWithdrawDate ? endDate : maxWithdrawDate;\n _withdrawTokens(receiver, startFrom, endAt);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param startFrom start withdrawal from date.\n * @param endAt end time for regular withdrawal\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(\n address receiver,\n uint256 startFrom,\n uint256 endAt\n ) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n if (staking.allUnlocked()) {\n end = endAt < endDate ? endAt : endDate;\n } else {\n end = endAt < block.timestamp ? endAt : block.timestamp;\n if (end > endDate) end = endDate;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startFrom; i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number - 1);\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver, startFrom, end);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) public onlyOwners {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() public onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = startDate + cliff;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / FOUR_WEEKS;\n lockDate = periodFromKickoff * FOUR_WEEKS + start;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Registry contract.\n *\n * @notice On January 25, 2020, Sovryn launched the Genesis Reservation system.\n * Sovryn community members who controlled a special NFT were granted access to\n * stake BTC or rBTC for cSOV tokens at a rate of 2500 satoshis per cSOV. Per\n * SIP-0003, up to 2,000,000 cSOV were made available in the Genesis event,\n * which will be redeemable on a 1:1 basis for cSOV, subject to approval by\n * existing SOV holders.\n *\n * On 15 Feb 2021 Sovryn is taking another step in its journey to decentralized\n * financial sovereignty with the vote on SIP 0005. This proposal will enable\n * participants of the Genesis Reservation system to redeem their reserved cSOV\n * tokens for SOV. They will also have the choice to redeem cSOV for rBTC if\n * they decide to exit the system.\n *\n * This contract deals with the vesting and redemption of cSOV tokens.\n * */\ncontract VestingRegistry is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The cSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract.\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVReImburse(address from, uint256 CSOVamount, uint256 reImburseAmount);\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing collector proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n //---ACL------------------------------------------------------------------\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * TODO: This ACL logic should be available on OpenZeppeling Ownable.sol\n * or on our own overriding sovrynOwnable. This same logic is repeated\n * on OriginInvestorsClaim.sol, TokenSender.sol and VestingRegistry2.sol\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice cSOV payout to sender with rBTC currency.\n * 1.- Check holder cSOV balance by adding up every cSOV token balance.\n * 2.- ReImburse rBTC if funds available.\n * 3.- And store holder address in processedList.\n */\n function reImburse() public isNotProcessed isNotBlacklisted {\n uint256 CSOVAmountWei = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n CSOVAmountWei = CSOVAmountWei.add(balance);\n }\n\n require(CSOVAmountWei > lockedAmount[msg.sender], \"holder has no CSOV\");\n CSOVAmountWei -= lockedAmount[msg.sender];\n processedList[msg.sender] = true;\n\n /**\n * @dev Found and fixed the SIP-0007 bug on VestingRegistry::reImburse formula.\n * More details at Documenting Code issues at point 11 in\n * https://docs.google.com/document/d/10idTD1K6JvoBmtPKGuJ2Ub_mMh6qTLLlTP693GQKMyU/\n * Previous buggy code: uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**10);\n * */\n uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**8);\n require(address(this).balance >= reImburseAmount, \"Not enough funds to reimburse\");\n msg.sender.transfer(reImburseAmount);\n\n emit CSOVReImburse(msg.sender, CSOVAmountWei, reImburseAmount);\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Exchange cSOV to SOV with 1:1 rate\n */\n function exchangeAllCSOV() public isNotProcessed isNotBlacklisted {\n processedList[msg.sender] = true;\n\n uint256 amount = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n amount += balance;\n }\n\n require(amount > lockedAmount[msg.sender], \"amount invalid\");\n amount -= lockedAmount[msg.sender];\n\n _createVestingForCSOV(amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param _vesting The address of Vesting contract.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n /// @dev TODO: Owner of OwnerVesting contracts - the same address as tokenOwner.\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry2.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title VestingRegistry 2 contract.\n * @notice One time contract needed to distribute tokens to origin sales investors.\n * */\ncontract VestingRegistry2 is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The CSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry3.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingRegistry3 is Ownable {\n using SafeMath for uint256;\n\n IVestingFactory public vestingFactory;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n //@notice fee sharing proxy\n address public feeSharingCollector;\n //@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n //TODO add to the documentation: address can have only one vesting of each type\n //user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n //user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n constructor(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"./VestingRegistryStorage.sol\";\n\ncontract VestingRegistryLogic is VestingRegistryStorage {\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event VestingCreationAndTypesSet(\n address indexed vesting,\n VestingCreationAndTypeDetails vestingCreationAndType\n );\n\n /**\n * @notice Replace constructor with initialize function for Upgradable Contracts\n * This function will be called only once by the owner\n * */\n function initialize(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner,\n address _lockedSOV,\n address[] calldata _vestingRegistries\n ) external onlyOwner initializer {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n require(_lockedSOV != address(0), \"LockedSOV address invalid\");\n\n _setVestingFactory(_vestingFactory);\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n lockedSOV = LockedSOV(_lockedSOV);\n for (uint256 i = 0; i < _vestingRegistries.length; i++) {\n require(_vestingRegistries[i] != address(0), \"Vesting registry address invalid\");\n vestingRegistries.push(IVestingRegistry(_vestingRegistries[i]));\n }\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) external onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Internal function that sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings that were deployed in previous vesting registries\n * @dev migration of data from previous vesting registy contracts\n */\n function addDeployedVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingCreationTypes[i] > 0, \"vesting creation type must be greater than 0\");\n _addDeployedVestings(_tokenOwners[i], _vestingCreationTypes[i]);\n }\n }\n\n /**\n * @notice adds four year vestings to vesting registry logic\n * @param _tokenOwners array of token owners\n * @param _vestingAddresses array of vesting addresses\n */\n function addFourYearVestings(\n address[] calldata _tokenOwners,\n address[] calldata _vestingAddresses\n ) external onlyAuthorized {\n require(_tokenOwners.length == _vestingAddresses.length, \"arrays mismatch\");\n uint256 vestingCreationType = 4;\n uint256 cliff = 4 weeks;\n uint256 duration = 156 weeks;\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(!isVesting[_vestingAddresses[i]], \"vesting exists\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingAddresses[i] != address(0), \"vesting cannot be 0 address\");\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwners[i],\n uint256(VestingType.Vesting),\n cliff,\n duration,\n vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n vestingCreationType,\n _vestingAddresses[i]\n );\n vestingsOf[_tokenOwners[i]].push(uid);\n isVesting[_vestingAddresses[i]] = true;\n }\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @dev Calls a public createVestingAddr function with vestingCreationType. This is to accomodate the existing logic for LockedSOV\n * @dev vestingCreationType 0 = LockedSOV\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAuthorized {\n createVestingAddr(_tokenOwner, _amount, _cliff, _duration, 3);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createVestingAddr(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.Vesting),\n _vestingCreationType\n );\n\n emit VestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) external onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.TeamVesting),\n _vestingCreationType\n );\n\n emit TeamVestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) external onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n * @dev Calls a public getVestingAddr function with cliff and duration. This is to accomodate the existing logic for LockedSOV\n * @dev We need to use LockedSOV.changeRegistryCliffAndDuration function very judiciously\n * @dev vestingCreationType 0 - LockedSOV\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return getVestingAddr(_tokenOwner, lockedSOV.cliff(), lockedSOV.duration(), 3);\n }\n\n /**\n * @notice public function that returns vesting contract address for the given token owner, cliff, duration\n * @dev Important: Please use this instead of getVesting function\n */\n function getVestingAddr(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner, cliff, duration\n */\n function getTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @dev check if the specific vesting address is team vesting or not\n * @dev read the vestingType from vestingCreationAndTypes storage\n *\n * @param _vestingAddress address of vesting contract\n *\n * @return true for teamVesting, false for normal vesting\n */\n function isTeamVesting(address _vestingAddress) external view returns (bool) {\n return (vestingCreationAndTypes[_vestingAddress].isSet &&\n vestingCreationAndTypes[_vestingAddress].vestingType ==\n uint32(VestingType.TeamVesting));\n }\n\n /**\n * @dev setter function to register existing vesting contract to vestingCreationAndTypes storage\n * @dev need to set the function visilibty to public to support VestingCreationAndTypeDetails struct as parameter\n *\n * @param _vestingAddresses array of vesting address\n * @param _vestingCreationAndTypes array for VestingCreationAndTypeDetails struct\n */\n function registerVestingToVestingCreationAndTypes(\n address[] memory _vestingAddresses,\n VestingCreationAndTypeDetails[] memory _vestingCreationAndTypes\n ) public onlyAuthorized {\n require(_vestingAddresses.length == _vestingCreationAndTypes.length, \"Unmatched length\");\n for (uint256 i = 0; i < _vestingCreationAndTypes.length; i++) {\n VestingCreationAndTypeDetails memory _vestingCreationAndType =\n _vestingCreationAndTypes[i];\n address _vestingAddress = _vestingAddresses[i];\n\n vestingCreationAndTypes[_vestingAddress] = _vestingCreationAndType;\n\n emit VestingCreationAndTypesSet(\n _vestingAddress,\n vestingCreationAndTypes[_vestingAddress]\n );\n }\n }\n\n /**\n * @notice Internal function to deploy Vesting/Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _type the type of vesting\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _type,\n uint256 _vestingCreationType\n ) internal returns (address) {\n address vesting;\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, _type, _cliff, _duration, _vestingCreationType)\n )\n );\n if (vestings[uid].vestingAddress == address(0)) {\n if (_type == 1) {\n vesting = vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n } else {\n vesting = vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n }\n vestings[uid] = Vesting(_type, _vestingCreationType, vesting);\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vesting] = true;\n\n vestingCreationAndTypes[vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(_type),\n vestingCreationType: uint128(_vestingCreationType)\n });\n\n emit VestingCreationAndTypesSet(vesting, vestingCreationAndTypes[vesting]);\n }\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice stores the addresses of Vesting contracts from all three previous versions of Vesting Registry\n */\n function _addDeployedVestings(address _tokenOwner, uint256 _vestingCreationType) internal {\n uint256 uid;\n uint256 i = _vestingCreationType - 1;\n\n address vestingAddress = vestingRegistries[i].getVesting(_tokenOwner);\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.Vesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n _vestingCreationType,\n vestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vestingAddress] = true;\n }\n\n address teamVestingAddress = vestingRegistries[i].getTeamVesting(_tokenOwner);\n if (teamVestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(teamVestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.TeamVesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.TeamVesting),\n _vestingCreationType,\n teamVestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[teamVestingAddress] = true;\n }\n }\n\n /**\n * @notice returns all vesting details for the given token owner\n */\n function getVestingsOf(address _tokenOwner) external view returns (Vesting[] memory) {\n uint256[] memory vestingIds = vestingsOf[_tokenOwner];\n uint256 length = vestingIds.length;\n Vesting[] memory _vestings = new Vesting[](vestingIds.length);\n for (uint256 i = 0; i < length; i++) {\n _vestings[i] = vestings[vestingIds[i]];\n }\n return _vestings;\n }\n\n /**\n * @notice returns cliff and duration for Vesting & TeamVesting contracts\n */\n function getVestingDetails(address _vestingAddress)\n external\n view\n returns (uint256 cliff, uint256 duration)\n {\n VestingLogic vesting = VestingLogic(_vestingAddress);\n return (vesting.cliff(), vesting.duration());\n }\n\n /**\n * @notice returns if the address is a vesting address\n */\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return isVesting[_vestingAddress];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./VestingRegistryStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Vesting Registry Proxy contract.\n * @dev Vesting Registry contract should be upgradable, use UpgradableProxy.\n * VestingRegistryStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract VestingRegistryProxy is VestingRegistryStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Initializable.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"../../locked/LockedSOV.sol\";\nimport \"./IVestingRegistry.sol\";\n\n/**\n * @title Vesting Registry Storage Contract.\n *\n * @notice This contract is just the storage required for vesting registry.\n * It is parent of VestingRegistryProxy and VestingRegistryLogic.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\n\ncontract VestingRegistryStorage is Initializable, AdminRole {\n ///@notice the vesting factory contract\n IVestingFactory public vestingFactory;\n\n ///@notice the Locked SOV contract\n ///@dev NOTES: No need to update lockedSOV in this contract, since it might break the vestingRegistry if the new lockedSOV does not have the same value of cliff & duration.\n ILockedSOV public lockedSOV;\n\n ///@notice the list of vesting registries\n IVestingRegistry[] public vestingRegistries;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n\n ///@notice fee sharing proxy\n address public feeSharingCollector;\n\n ///@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n ///@notice Vesting details\n struct Vesting {\n uint256 vestingType;\n uint256 vestingCreationType;\n address vestingAddress;\n }\n\n ///@notice A record of vesting details for a unique id\n ///@dev vestings[uid] returns vesting data\n mapping(uint256 => Vesting) public vestings;\n\n ///@notice A record of all unique ids for a particular token owner\n ///@dev vestingsOf[tokenOwner] returns array of unique ids\n mapping(address => uint256[]) public vestingsOf;\n\n ///@notice A record of all vesting addresses\n ///@dev isVesting[address] returns if the address is a vesting address\n mapping(address => bool) public isVesting;\n\n /// @notice Store vesting creation type & vesting type information\n /// @dev it is packed into 1 single storage slot for cheaper gas usage\n struct VestingCreationAndTypeDetails {\n bool isSet;\n uint32 vestingType;\n uint128 vestingCreationType;\n }\n\n ///@notice A record of all vesting addresses with the detail\n ///@dev vestingDetail[vestingAddress] returns Vesting struct data\n ///@dev can be used to easily check the vesting type / creation type based on the vesting address itself\n mapping(address => VestingCreationAndTypeDetails) public vestingCreationAndTypes;\n}\n" + }, + "contracts/governance/Vesting/VestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\n\n/**\n * @title Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for vesting.\n * It is parent of VestingLogic and TeamVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract VestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public cliff;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 constant FOUR_WEEKS = 4 weeks;\n}\n" + }, + "contracts/interfaces/IChai.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IERC20.sol\";\n\ninterface IPot {\n function dsr() external view returns (uint256);\n\n function chi() external view returns (uint256);\n\n function rho() external view returns (uint256);\n}\n\ncontract IChai is IERC20 {\n function move(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function join(address dst, uint256 wad) external;\n\n function draw(address src, uint256 wad) external;\n\n function exit(address src, uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IConverterAMM.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IConverterAMM {\n function withdrawFees(address receiver) external returns (uint256);\n}\n" + }, + "contracts/interfaces/IERC20.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ncontract IERC20 {\n string public name;\n uint8 public decimals;\n string public symbol;\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address _who) external view returns (uint256);\n\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/interfaces/IERC777.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777Token standard as defined in the EIP.\n *\n * This contract uses the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let\n * token holders and recipients react to token movements by using setting implementers\n * for the associated interfaces in said registry. See {IERC1820Registry} and\n * {ERC1820Implementer}.\n */\ninterface IERC777 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the smallest part of the token that is not divisible. This\n * means all token operations (creation, movement and destruction) must have\n * amounts that are a multiple of this number.\n *\n * For most token contracts, this value will equal 1.\n */\n function granularity() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by an account (`owner`).\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * If send or receive hooks are registered for the caller and `recipient`,\n * the corresponding functions will be called with `data` and empty\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes calldata data\n ) external;\n\n /**\n * @dev Destroys `amount` tokens from the caller's account, reducing the\n * total supply.\n *\n * If a send hook is registered for the caller, the corresponding function\n * will be called with `data` and empty `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n */\n function burn(uint256 amount, bytes calldata data) external;\n\n /**\n * @dev Returns true if an account is an operator of `tokenHolder`.\n * Operators can send and burn tokens on behalf of their owners. All\n * accounts are their own operator.\n *\n * See {operatorSend} and {operatorBurn}.\n */\n function isOperatorFor(address operator, address tokenHolder) external view returns (bool);\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor}.\n *\n * Emits an {AuthorizedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function authorizeOperator(address operator) external;\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor} and {defaultOperators}.\n *\n * Emits a {RevokedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function revokeOperator(address operator) external;\n\n /**\n * @dev Returns the list of default operators. These accounts are operators\n * for all token holders, even if {authorizeOperator} was never called on\n * them.\n *\n * This list is immutable, but individual holders may revoke these via\n * {revokeOperator}, in which case {isOperatorFor} will return false.\n */\n function defaultOperators() external view returns (address[] memory);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must\n * be an operator of `sender`.\n *\n * If send or receive hooks are registered for `sender` and `recipient`,\n * the corresponding functions will be called with `data` and\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - `sender` cannot be the zero address.\n * - `sender` must have at least `amount` tokens.\n * - the caller must be an operator for `sender`.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n /**\n * @dev Destoys `amount` tokens from `account`, reducing the total supply.\n * The caller must be an operator of `account`.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `data` and `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n * - the caller must be an operator for `account`.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n event Sent(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Minted(\n address indexed operator,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Burned(\n address indexed operator,\n address indexed from,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event AuthorizedOperator(address indexed operator, address indexed tokenHolder);\n\n event RevokedOperator(address indexed operator, address indexed tokenHolder);\n}\n" + }, + "contracts/interfaces/IERC777Recipient.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.\n *\n * Accounts can be notified of {IERC777} tokens being sent to them by having a\n * contract implement this interface (contract holders can be their own\n * implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Recipient {\n /**\n * @dev Called by an {IERC777} token contract whenever tokens are being\n * moved or created into a registered account (`to`). The type of operation\n * is conveyed by `from` being the zero address or not.\n *\n * This call occurs _after_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the post-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/IERC777Sender.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensSender standard as defined in the EIP.\n *\n * {IERC777} Token holders can be notified of operations performed on their\n * tokens by having a contract implement this interface (contract holders can be\n * their own implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Sender {\n /**\n * @dev Called by an {IERC777} token contract whenever a registered holder's\n * (`from`) tokens are about to be moved or destroyed. The type of operation\n * is conveyed by `to` being the zero address or not.\n *\n * This call occurs _before_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the pre-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/ILoanPool.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface ILoanPool {\n function tokenPrice() external view returns (uint256 price);\n\n function borrowInterestRate() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/ILoanTokenModules.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\ninterface ILoanTokenModules {\n /** EVENT */\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /// topic: 0x9bbd2de400810774339120e2f8a2b517ed748595e944529bba8ebabf314d0591\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n\n /** INTERFACE */\n\n /** START LOAN TOKEN SETTINGS LOWER ADMIN */\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n\n function setAdmin(address _admin) external;\n\n function setPauser(address _pauser) external;\n\n function setupLoanParams(LoanParams[] calldata loanParamsList, bool areTorqueLoans) external;\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external;\n\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) external;\n\n function toggleFunctionPause(\n string calldata funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) external;\n\n function setTransactionLimits(address[] calldata addresses, uint256[] calldata limits)\n external;\n\n function changeLoanTokenNameAndSymbol(string calldata _name, string calldata _symbol) external;\n\n /** END LOAN TOKEN SETTINGS LOWER ADMIN */\n\n /** START LOAN TOKEN LOGIC STANDARD */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n address affiliateReferrer, // The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes // Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function borrowInterestRate() external view returns (uint256);\n\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n\n function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid);\n\n function checkPause(string calldata funcId) external view returns (bool isPaused);\n\n function nextBorrowInterestRate(uint256 borrowAmount) external view returns (uint256);\n\n function totalAssetBorrow() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes calldata /// loanDataBytes: arbitrary order data (for future use).\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n );\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function setLiquidityMiningAddress(address LMAddress) external;\n\n function getLiquidityMiningAddress() external view returns (address);\n\n function setStakingContractAddress(address _stakingContractAddress) external;\n\n function getStakingContractAddress() external view returns (address);\n\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n external\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n );\n\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 depositAmount);\n\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 borrowAmount);\n\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) external view;\n\n function getMaxEscrowAmount(uint256 leverageAmount)\n external\n view\n returns (uint256 maxEscrowAmount);\n\n function checkpointPrice(address _user) external view returns (uint256 price);\n\n function assetBalanceOf(address _owner) external view returns (uint256);\n\n function profitOf(address user) external view returns (int256);\n\n function tokenPrice() external view returns (uint256 price);\n\n function avgBorrowInterestRate() external view returns (uint256);\n\n function supplyInterestRate() external view returns (uint256);\n\n function nextSupplyInterestRate(uint256 supplyAmount) external view returns (uint256);\n\n function totalSupplyInterestRate(uint256 assetSupply) external view returns (uint256);\n\n function loanTokenAddress() external view returns (address);\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n external\n view\n returns (uint256, uint256);\n\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external;\n\n /** START LOAN TOKEN BASE */\n function initialPrice() external view returns (uint256);\n\n /** START LOAN TOKEN LOGIC LM */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external returns (uint256 minted);\n\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 redeemed);\n\n /** START LOAN TOKEN LOGIC WRBTC */\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n returns (uint256 mintAmount);\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function marketLiquidity() external view returns (uint256);\n\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n external\n view\n returns (uint256);\n\n /** START LOAN TOKEN LOGIC STORAGE */\n function pauser() external view returns (address);\n\n function liquidityMiningAddress() external view returns (address);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n /** START ADVANCED TOKEN */\n function approve(address _spender, uint256 _value) external returns (bool);\n\n /** START ADVANCED TOKEN STORAGE */\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function balanceOf(address _owner) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function loanParamsIds(uint256) external view returns (bytes32);\n}\n" + }, + "contracts/interfaces/ISovryn.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\npragma experimental ABIEncoderV2;\n//TODO: stored in ./interfaces only while brownie isn't removed\n//TODO: move to contracts/interfaces after with brownie is removed\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\ncontract ISovryn is\n State,\n ProtocolSettingsEvents,\n LoanSettingsEvents,\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n LoanClosingsEvents,\n SwapsEvents,\n AffiliatesEvents,\n FeesEvents\n{\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n ////// Protocol //////\n\n function replaceContract(address target) external;\n\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\n\n function getTarget(string calldata sig) external view returns (address);\n\n ////// Protocol Settings //////\n\n function setSovrynProtocolAddress(address newProtocolAddress) external;\n\n function setSOVTokenAddress(address newSovTokenAddress) external;\n\n function setLockedSOVAddress(address newSOVLockedAddress) external;\n\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\n\n function setPriceFeedContract(address newContract) external;\n\n function setSwapsImplContract(address newContract) external;\n\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\n\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\n\n function setLendingFeePercent(uint256 newValue) external;\n\n function setTradingFeePercent(uint256 newValue) external;\n\n function setBorrowingFeePercent(uint256 newValue) external;\n\n function setSwapExternalFeePercent(uint256 newValue) external;\n\n function setAffiliateFeePercent(uint256 newValue) external;\n\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\n\n function setLiquidationIncentivePercent(uint256 newAmount) external;\n\n function setMaxDisagreement(uint256 newAmount) external;\n\n function setSourceBuffer(uint256 newAmount) external;\n\n function setMaxSwapSize(uint256 newAmount) external;\n\n function setFeesController(address newController) external;\n\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n returns (address, bool);\n\n function depositProtocolToken(uint256 amount) external;\n\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function setWrbtcToken(address wrbtcTokenAddress) external;\n\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\n\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\n\n function setRolloverBaseReward(uint256 transactionCost) external;\n\n function setRebatePercent(uint256 rebatePercent) external;\n\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external;\n\n function getSpecialRebates(address sourceToken, address destToken)\n external\n view\n returns (uint256 specialRebatesPercent);\n\n function togglePaused(bool paused) external;\n\n function isProtocolPaused() external view returns (bool);\n\n ////// SwapsImplSovrynSwapModule //////\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (address);\n\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\n\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn);\n\n ////// Loan Settings //////\n\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function getLoanParams(bytes32[] calldata loanParamsIdList)\n external\n view\n returns (LoanParams[] memory loanParamsList);\n\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n\n ////// Loan Openings //////\n\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external;\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n ////// Loan Closings //////\n\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n );\n\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata loanDataBytes\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n ////// Loan Maintenance //////\n\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount // must match msg.value if ether is sent\n ) external payable;\n\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 actualWithdrawAmount);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n );\n\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; // collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\n\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\n\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external returns (uint256 secondsExtended);\n\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 secondsReduced);\n\n ////// Swaps External //////\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view;\n\n ////// Affiliates Module //////\n\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\n\n function setUserNotFirstTradeFlag(address user) external;\n\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\n\n function getReferralsList(address referrer) external view returns (address[] memory refList);\n\n function getAffiliatesReferrerBalances(address referrer)\n external\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\n\n function getAffiliatesReferrerTokensList(address referrer)\n external\n view\n returns (address[] memory tokensList);\n\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n external\n view\n returns (uint256);\n\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) external;\n\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\n\n function getProtocolAddress() external view returns (address);\n\n function getSovTokenAddress() external view returns (address);\n\n function getLockedSOVAddress() external view returns (address);\n\n function getFeeRebatePercent() external view returns (uint256);\n\n function getMinReferralsToPayout() external view returns (uint256);\n\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\n\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\n\n function getAffiliateTradingTokenFeePercent()\n external\n view\n returns (uint256 affiliateTradingTokenFeePercent);\n\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount);\n\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\n\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\n\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\n\n function getDedicatedSOVRebate() external view returns (uint256);\n\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\n\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory);\n\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\n\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external;\n\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\n\n function setAdmin(address newAdmin) external;\n\n function getAdmin() external view returns (address);\n\n function setPauser(address newPauser) external;\n\n function getPauser() external view returns (address);\n}\n" + }, + "contracts/interfaces/IWrbtc.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface IWrbtc {\n function deposit() external payable;\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IWrbtcERC20.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IWrbtc.sol\";\nimport \"./IERC20.sol\";\n\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\n" + }, + "contracts/locked/ILockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title The Locked SOV Interface.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This interface is an incomplete yet useful for future migration of LockedSOV Contract.\n * @dev Only use it if you know what you are doing.\n */\ninterface ILockedSOV {\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external;\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external;\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external;\n\n function cliff() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function getLockedBalance(address _addr) external view returns (uint256 _balance);\n\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance);\n}\n" + }, + "contracts/locked/LockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../governance/Vesting/VestingRegistry.sol\";\nimport \"../governance/Vesting/VestingLogic.sol\";\nimport \"./ILockedSOV.sol\";\n\n/**\n * @title The Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This contract is used to receive reward from other contracts, Create Vesting and Stake Tokens.\n */\ncontract LockedSOV is ILockedSOV {\n using SafeMath for uint256;\n\n uint256 public constant MAX_BASIS_POINT = 10000;\n uint256 public constant MAX_DURATION = 37;\n\n /* Storage */\n\n /// @notice True if the migration to a new Locked SOV Contract has started.\n bool public migration;\n\n /// @notice The cliff is the time period after which the tokens begin to unlock.\n uint256 public cliff;\n /// @notice The duration is the time period after all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n /// @notice The Vesting registry contract.\n VestingRegistry public vestingRegistry;\n /// @notice The New (Future) Locked SOV.\n ILockedSOV public newLockedSOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) private lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) private unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) private isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /// @notice Emitted when Vesting Registry, Duration and/or Cliff is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vestingRegistry The Vesting Registry Contract.\n /// @param _cliff The time period after which the tokens begin to unlock.\n /// @param _duration The time period after all tokens will have been unlocked.\n event RegistryCliffAndDurationUpdated(\n address indexed _initiator,\n address indexed _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n );\n\n /// @notice Emitted when a new deposit is made.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user to whose un/locked balance a new deposit was made.\n /// @param _sovAmount The amount of SOV to be added to the un/locked balance.\n /// @param _basisPoint The % (in Basis Point) which determines how much will be unlocked immediately.\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n /// @notice Emitted when a user withdraws the fund.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _sovAmount The amount of SOV withdrawn from the unlocked balance.\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n /// @notice Emitted when a user creates a vesting for himself.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _vesting The Vesting Contract.\n event VestingCreated(\n address indexed _initiator,\n address indexed _userAddress,\n address indexed _vesting\n );\n\n /// @notice Emitted when a user stakes tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vesting The Vesting Contract.\n /// @param _amount The amount of locked tokens staked by the user.\n event TokenStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /// @notice Emitted when an admin initiates a migration to new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedSOV The address of the new Locked SOV Contract.\n event MigrationStarted(address indexed _initiator, address indexed _newLockedSOV);\n\n /// @notice Emitted when a user initiates the transfer to a new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of locked tokens to transfer from this contract to the new one.\n event UserTransfered(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n modifier migrationAllowed {\n require(migration, \"Migration has not yet started.\");\n _;\n }\n\n /* Constructor */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV Token Address.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @param _admins The list of Admins to be added.\n */\n constructor(\n address _SOV,\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration,\n address[] memory _admins\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_vestingRegistry != address(0), \"Vesting registry address is invalid.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n SOV = IERC20(_SOV);\n vestingRegistry = VestingRegistry(_vestingRegistry);\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /* Public or External Functions */\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n * @dev Only callable by an Admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address.\");\n require(!isAdmin[_newAdmin], \"Address is already admin.\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n * @dev Only callable by an Admin.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin.\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice The function to update the Vesting Registry, Duration and Cliff.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @dev IMPORTANT 1: You have to change Vesting Registry if you want to change Duration and/or Cliff.\n * IMPORTANT 2: `_cliff` and `_duration` is multiplied by 4 weeks in this function.\n */\n function changeRegistryCliffAndDuration(\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAdmin {\n require(\n address(vestingRegistry) != _vestingRegistry,\n \"Vesting Registry has to be different for changing duration and cliff.\"\n );\n /// If duration is also zero, then it is similar to Unlocked SOV.\n require(_duration != 0, \"Duration cannot be zero.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n vestingRegistry = VestingRegistry(_vestingRegistry);\n\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n emit RegistryCliffAndDurationUpdated(msg.sender, _vestingRegistry, _cliff, _duration);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // MAX_BASIS_POINT is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < MAX_BASIS_POINT, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(MAX_BASIS_POINT);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice A function to withdraw the unlocked balance.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdraw(address _receiverAddress) public {\n _withdraw(msg.sender, _receiverAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n /**\n * @notice Creates vesting if not already created and Stakes tokens for a user.\n * @dev Only use this function if the `duration` is small.\n */\n function createVestingAndStake() public {\n _createVestingAndStake(msg.sender);\n }\n\n function _createVestingAndStake(address _sender) private {\n address vestingAddr = _getVesting(_sender);\n\n if (vestingAddr == address(0)) {\n vestingAddr = _createVesting(_sender);\n }\n\n _stakeTokens(_sender, vestingAddr);\n }\n\n /**\n * @notice Creates vesting contract (if it hasn't been created yet) for the calling user.\n * @return _vestingAddress The New Vesting Contract Created.\n */\n function createVesting() public returns (address _vestingAddress) {\n _vestingAddress = _createVesting(msg.sender);\n }\n\n /**\n * @notice Stakes tokens for a user who already have a vesting created.\n * @dev The user should already have a vesting created, else this function will throw error.\n */\n function stakeTokens() public {\n VestingLogic vesting = VestingLogic(_getVesting(msg.sender));\n\n require(\n cliff == vesting.cliff() && duration == vesting.duration(),\n \"Wrong Vesting Schedule.\"\n );\n\n _stakeTokens(msg.sender, address(vesting));\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdrawAndStakeTokens(address _receiverAddress) external {\n _withdraw(msg.sender, _receiverAddress);\n _createVestingAndStake(msg.sender);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n /**\n * @notice Function to start the process of migration to new contract.\n * @param _newLockedSOV The new locked sov contract address.\n */\n function startMigration(address _newLockedSOV) external onlyAdmin {\n require(_newLockedSOV != address(0), \"New Locked SOV Address is Invalid.\");\n newLockedSOV = ILockedSOV(_newLockedSOV);\n SOV.approve(_newLockedSOV, uint256(-1));\n migration = true;\n\n emit MigrationStarted(msg.sender, _newLockedSOV);\n }\n\n /**\n * @notice Function to transfer the locked balance from this contract to new LockedSOV Contract.\n * @dev Address is not specified to discourage selling lockedSOV to other address.\n */\n function transfer() external migrationAllowed {\n uint256 amount = lockedBalances[msg.sender];\n lockedBalances[msg.sender] = 0;\n\n newLockedSOV.depositSOV(msg.sender, amount);\n\n emit UserTransfered(msg.sender, amount);\n }\n\n /* Internal Functions */\n\n /**\n * @notice Creates a Vesting Contract for a user.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n * @dev Does not do anything if Vesting Contract was already created.\n */\n function _createVesting(address _tokenOwner) internal returns (address _vestingAddress) {\n /// Here zero is given in place of amount, as amount is not really used in `vestingRegistry.createVesting()`.\n vestingRegistry.createVesting(_tokenOwner, 0, cliff, duration);\n _vestingAddress = _getVesting(_tokenOwner);\n emit VestingCreated(msg.sender, _tokenOwner, _vestingAddress);\n }\n\n /**\n * @notice Returns the Vesting Contract Address.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n */\n function _getVesting(address _tokenOwner) internal view returns (address _vestingAddress) {\n return vestingRegistry.getVesting(_tokenOwner);\n }\n\n /**\n * @notice Stakes the tokens in a particular vesting contract.\n * @param _vesting The Vesting Contract Address.\n */\n function _stakeTokens(address _sender, address _vesting) internal {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n require(SOV.approve(_vesting, amount), \"Approve failed.\");\n VestingLogic(_vesting).stakeTokens(amount);\n\n emit TokenStaked(_sender, _vesting, amount);\n }\n\n /* Getter or Read Functions */\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) external view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n\n /**\n * @notice The function to check is an address is admin or not.\n * @param _addr The address of the user to check the admin status.\n * @return _status True if admin, False otherwise.\n */\n function adminStatus(address _addr) external view returns (bool _status) {\n return isAdmin[_addr];\n }\n}\n" + }, + "contracts/mixins/EnumerableAddressSet.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Based on Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * As of v2.5.0, only `address` sets are supported.\n *\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\n *\n * _Available since v2.5.0._\n */\nlibrary EnumerableAddressSet {\n struct AddressSet {\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(address => uint256) index;\n address[] values;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n * Returns false if the value was already in the set.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n * Returns false if the value was not present in the set.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n // If the element we're deleting is the last one, we can just remove it without doing a swap\n if (lastIndex != toDeleteIndex) {\n address lastValue = set.values[lastIndex];\n\n // Move the last value to the index where the deleted value is\n set.values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n // Delete the index entry for the deleted value\n delete set.index[value];\n\n // Delete the old entry for the moved value\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns an array with all values in the set. O(N).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\n address[] memory output = new address[](set.values.length);\n for (uint256 i; i < set.values.length; i++) {\n output[i] = set.values[i];\n }\n return output;\n }\n\n /**\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n \n * @param start start index of chunk\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\n */\n function enumerateChunk(\n AddressSet storage set,\n uint256 start,\n uint256 count\n ) internal view returns (address[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = (set.values.length < end || count == 0) ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new address[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @dev Returns the number of elements on the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /** @dev Returns the element stored at position `index` in the set. O(1).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes32Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\n * */\nlibrary EnumerableBytes32Set {\n struct Bytes32Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes32 => uint256) index;\n bytes32[] values;\n }\n\n /**\n * @notice Add an address value to a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to add.\n *\n * @return False if the value was already in the set.\n */\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return addBytes32(set, value);\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove an address value from a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to remove.\n *\n * @return False if the address was not present in the set.\n */\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return removeBytes32(set, value);\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function containsAddress(Bytes32Set storage set, address addrvalue)\n internal\n view\n returns (bool)\n {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes32Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes32[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes32[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes4Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`.\n * */\nlibrary EnumerableBytes4Set {\n struct Bytes4Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes4 => uint256) index;\n bytes4[] values;\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes4 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes4Set storage set, bytes4 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes4Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes4[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes4[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes4Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes4Set storage set, uint256 index) internal view returns (bytes4) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/FeesHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ISovryn.sol\";\nimport \"../core/objects/LoanParamsStruct.sol\";\n\n/**\n * @title The Fees Helper contract.\n *\n * This contract calculates and pays lending/borrow fees and rewards.\n * */\ncontract FeesHelper is State, FeesEvents {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Calculate trading fee.\n * @param feeTokenAmount The amount of tokens to trade.\n * @return The fee of the trade.\n * */\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\n }\n\n /**\n * @notice Calculate swap external fee.\n * @param feeTokenAmount The amount of token to swap.\n * @return The fee of the swap.\n */\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\n }\n\n /*\n\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - tradingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);\n\t}*/\n\n /**\n * @notice Calculate the loan origination fee.\n * @param feeTokenAmount The amount of tokens to borrow.\n * @return The fee of the loan.\n * */\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\n /*\n\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - borrowingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);*/\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\n *\n * @param referrer The affiliate referrer address to send the reward to.\n * @param trader The account that performs this trade.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n *\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\n * */\n function _payTradingFeeToAffiliate(\n address referrer,\n address trader,\n address feeToken,\n uint256 tradingFee\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\n address(this)\n )\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n * */\n function _payTradingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 tradingFee\n ) internal {\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\n if (tradingFee != 0) {\n if (affiliatesUserReferrer[user] != address(0)) {\n _payTradingFeeToAffiliate(\n affiliatesUserReferrer[user],\n user,\n feeToken,\n protocolTradingFee\n );\n protocolTradingFee = (\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\n )\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\n }\n\n /// Increase the storage variable keeping track of the accumulated fees.\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\n protocolTradingFee\n );\n\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\n }\n }\n\n /**\n * @notice Settle the borrowing fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the borrowig fee is paid.\n * @param borrowingFee The height of the fee.\n * */\n function _payBorrowingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 borrowingFee\n ) internal {\n if (borrowingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\n\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\n }\n }\n\n /**\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\n * @param user The address to send the reward to.\n * @param feeToken The address of the token in which the lending fee is paid.\n * @param lendingFee The height of the fee.\n * */\n function _payLendingFee(\n address user,\n address feeToken,\n uint256 lendingFee\n ) internal {\n if (lendingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\n\n emit PayLendingFee(user, feeToken, lendingFee);\n\n //// NOTE: Lenders do not receive a fee reward ////\n }\n }\n\n /// Settle and pay borrowers based on the fees generated by their interest payments.\n function _settleFeeRewardForInterestExpense(\n LoanInterest storage loanInterestLocal,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n address user,\n uint256 interestTime\n ) internal {\n /// This represents the fee generated by a borrower's interest payment.\n uint256 interestExpenseFee =\n interestTime\n .sub(loanInterestLocal.updatedTimestamp)\n .mul(loanInterestLocal.owedPerDay)\n .mul(lendingFeePercent)\n .div(1 days * 10**20);\n\n loanInterestLocal.updatedTimestamp = interestTime;\n\n if (interestExpenseFee != 0) {\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\n }\n }\n\n /**\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associeated loan - used for logging only.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * */\n function _payFeeReward(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 feeAmount\n ) internal {\n uint256 rewardAmount;\n uint256 _feeRebatePercent = feeRebatePercent;\n address _priceFeeds = priceFeeds;\n\n if (specialRebates[feeToken][feeTokenPair] > 0) {\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\n }\n\n /// Note: this should be refactored.\n /// Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\n feeAmount.mul(_feeRebatePercent).div(10**20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n // Check the dedicated SOV that is used to pay trading rebate rewards\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"deposit(address,uint256,uint256)\",\n user,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n )\n );\n\n if (success) {\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\n\n emit EarnReward(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n } else {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n }\n}\n" + }, + "contracts/mixins/InterestUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"./FeesHelper.sol\";\n\n/**\n * @title The Interest User contract.\n *\n * This contract pays loan interests.\n * */\ncontract InterestUser is VaultController, FeesHelper {\n using SafeERC20 for IERC20;\n\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n /**\n * @notice Internal function to pay interest of a loan.\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * */\n function _payInterest(address lender, address interestToken) internal {\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\n\n uint256 interestOwedNow = 0;\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\n interestOwedNow = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(1 days);\n\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n\n if (interestOwedNow > lenderInterestLocal.owedTotal)\n interestOwedNow = lenderInterestLocal.owedTotal;\n\n if (interestOwedNow != 0) {\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\n\n _payInterestTransfer(lender, interestToken, interestOwedNow);\n }\n } else {\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n }\n }\n\n /**\n * @notice Internal function to transfer tokens for the interest of a loan.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * @param interestOwedNow The amount of interest to pay.\n * */\n function _payInterestTransfer(\n address lender,\n address interestToken,\n uint256 interestOwedNow\n ) internal {\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\n /// TODO: refactor: data incapsulation violation and DRY design principles\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\n\n _payLendingFee(lender, interestToken, lendingFee);\n\n /// Transfers the interest to the lender, less the interest fee.\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\n\n /// Event Log\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\n }\n}\n" + }, + "contracts/mixins/LiquidationHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\n/**\n * @title The Liquidation Helper contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract computes the liquidation amount.\n * */\ncontract LiquidationHelper is State {\n /**\n * @notice Compute how much needs to be liquidated in order to restore the\n * desired margin (maintenance + 5%).\n *\n * @param principal The total borrowed amount (in loan tokens).\n * @param collateral The collateral (in collateral tokens).\n * @param currentMargin The current margin.\n * @param maintenanceMargin The maintenance (minimum) margin.\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n *\n * @return maxLiquidatable The collateral you can get liquidating.\n * @return maxSeizable The loan you available for liquidation.\n * @return incentivePercent The discount on collateral.\n * */\n function _getLiquidationAmounts(\n uint256 principal,\n uint256 collateral,\n uint256 currentMargin,\n uint256 maintenanceMargin,\n uint256 collateralToLoanRate\n )\n internal\n view\n returns (\n uint256 maxLiquidatable,\n uint256 maxSeizable,\n uint256 incentivePercent\n )\n {\n incentivePercent = liquidationIncentivePercent;\n if (currentMargin > maintenanceMargin || collateralToLoanRate == 0) {\n return (maxLiquidatable, maxSeizable, incentivePercent);\n } else if (currentMargin <= incentivePercent) {\n return (principal, collateral, currentMargin);\n }\n\n /// 5 percentage points above maintenance.\n uint256 desiredMargin = maintenanceMargin.add(5 ether);\n\n /// maxLiquidatable = ((1 + desiredMargin)*principal - collateralToLoanRate*collateral) / (desiredMargin - 0.05)\n maxLiquidatable = desiredMargin.add(10**20).mul(principal).div(10**20);\n maxLiquidatable = maxLiquidatable.sub(collateral.mul(collateralToLoanRate).div(10**18));\n maxLiquidatable = maxLiquidatable.mul(10**20).div(desiredMargin.sub(incentivePercent));\n if (maxLiquidatable > principal) {\n maxLiquidatable = principal;\n }\n\n /// maxSeizable = maxLiquidatable * (1 + incentivePercent) / collateralToLoanRate\n maxSeizable = maxLiquidatable.mul(incentivePercent.add(10**20));\n maxSeizable = maxSeizable.div(collateralToLoanRate).div(100);\n if (maxSeizable > collateral) {\n maxSeizable = collateral;\n }\n\n return (maxLiquidatable, maxSeizable, incentivePercent);\n }\n}\n" + }, + "contracts/mixins/ModuleCommonFunctionalities.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\ncontract ModuleCommonFunctionalities is State {\n modifier whenNotPaused() {\n require(!pause, \"Paused\");\n _;\n }\n}\n" + }, + "contracts/mixins/ProtocolTokenUser.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\n\n/**\n * @title The Protocol Token User contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to withdraw protocol tokens.\n * */\ncontract ProtocolTokenUser is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Internal function to withdraw an amount of protocol tokens from this contract.\n *\n * @param receiver The address of the recipient.\n * @param amount The amount of tokens to withdraw.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function _withdrawProtocolToken(address receiver, uint256 amount)\n internal\n returns (address, bool)\n {\n uint256 withdrawAmount = amount;\n\n uint256 tokenBalance = protocolTokenHeld;\n if (withdrawAmount > tokenBalance) {\n withdrawAmount = tokenBalance;\n }\n if (withdrawAmount == 0) {\n return (protocolTokenAddress, false);\n }\n\n protocolTokenHeld = tokenBalance.sub(withdrawAmount);\n\n IERC20(protocolTokenAddress).safeTransfer(receiver, withdrawAmount);\n\n return (protocolTokenAddress, true);\n }\n}\n" + }, + "contracts/mixins/RewardHelper.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title The Reward Helper contract.\n * @notice This contract calculates the reward for rollover transactions.\n *\n * A rollover is a renewal of a deposit. Instead of liquidating a deposit\n * on maturity, you can roll it over into a new deposit. The outstanding\n * principal of the old deposit is rolled over with or without the interest\n * outstanding on it.\n * */\ncontract RewardHelper is State {\n using SafeMath for uint256;\n\n /**\n * @notice Calculate the reward of a rollover transaction.\n *\n * @param collateralToken The address of the collateral token.\n * @param loanToken The address of the loan token.\n * @param positionSize The amount of value of the position.\n *\n * @return The base fee + the flex fee.\n */\n function _getRolloverReward(\n address collateralToken,\n address loanToken,\n uint256 positionSize\n ) internal view returns (uint256 reward) {\n uint256 positionSizeInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(loanToken, collateralToken, positionSize);\n uint256 rolloverBaseRewardInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(\n address(wrbtcToken),\n collateralToken,\n rolloverBaseReward\n );\n\n return\n rolloverBaseRewardInCollateralToken\n .mul(2) /// baseFee\n .add(positionSizeInCollateralToken.mul(rolloverFlexFeePercent).div(10**20)); /// flexFee = 0.1% of position size\n }\n}\n" + }, + "contracts/mixins/VaultController.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\n\n/**\n * @title The Vault Controller contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to deposit and withdraw wrBTC and\n * other tokens from the vault.\n * */\ncontract VaultController is State {\n using SafeERC20 for IERC20;\n\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\n\n /**\n * @notice Deposit wrBTC into the vault.\n *\n * @param from The address of the account paying the deposit.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherDeposit(address from, uint256 value) internal {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n _wrbtcToken.deposit.value(value)();\n\n emit VaultDeposit(address(_wrbtcToken), from, value);\n }\n\n /**\n * @notice Withdraw wrBTC from the vault.\n *\n * @param to The address of the recipient.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherWithdraw(address to, uint256 value) internal {\n if (value != 0) {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n uint256 balance = address(this).balance;\n if (value > balance) {\n _wrbtcToken.withdraw(value - balance);\n }\n Address.sendValue(to, value);\n\n emit VaultWithdraw(address(_wrbtcToken), to, value);\n }\n }\n\n /**\n * @notice Deposit tokens into the vault.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying the deposit.\n * @param value The amount of tokens to transfer.\n */\n function vaultDeposit(\n address token,\n address from,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransferFrom(from, address(this), value);\n\n emit VaultDeposit(token, from, value);\n }\n }\n\n /**\n * @notice Withdraw tokens from the vault.\n *\n * @param token The address of the token instance.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultWithdraw(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransfer(to, value);\n\n emit VaultWithdraw(token, to, value);\n }\n }\n\n /**\n * @notice Transfer tokens from an account into another one.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultTransfer(\n address token,\n address from,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n if (from == address(this)) {\n IERC20(token).safeTransfer(to, value);\n } else {\n IERC20(token).safeTransferFrom(from, to, value);\n }\n }\n }\n\n /**\n * @notice Approve an allowance of tokens to be spent by an account.\n *\n * @param token The address of the token instance.\n * @param to The address of the spender.\n * @param value The amount of tokens to allow.\n */\n function vaultApprove(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\n IERC20(token).safeApprove(to, 0);\n }\n IERC20(token).safeApprove(to, value);\n }\n}\n" + }, + "contracts/mockup/BlockMockUp.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title Used to get and set mock block number.\n */\ncontract BlockMockUp {\n uint256 public blockNum;\n\n /**\n * @notice To get the `blockNum`.\n * @return _blockNum The block number.\n */\n function getBlockNum() public view returns (uint256 _blockNum) {\n return blockNum;\n }\n\n /**\n * @notice To set the `blockNum`.\n * @param _blockNum The block number.\n */\n function setBlockNum(uint256 _blockNum) public {\n blockNum = _blockNum;\n }\n}\n" + }, + "contracts/mockup/FeeSharingCollectorMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/FeeSharingCollector/FeeSharingCollector.sol\";\n\ncontract FeeSharingCollectorMockup is FeeSharingCollector {\n struct TestData {\n address loanPoolToken;\n uint32 maxCheckpoints;\n address receiver;\n }\n\n TestData public testData;\n\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n testData = TestData(_token, _maxCheckpoints, _receiver);\n }\n\n function trueWithdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function addCheckPoint(address loanPoolToken, uint256 poolTokenAmount) public {\n uint96 amount96 =\n safe96(\n poolTokenAmount,\n \"FeeSharingCollectorProxy::withdrawFees: pool token amount exceeds 96 bits\"\n );\n _addCheckpoint(loanPoolToken, amount96);\n }\n\n function setTotalTokenCheckpoints(address _token, uint256 qty) public {\n totalTokenCheckpoints[_token] = qty;\n }\n\n function setUserProcessedCheckpoints(\n address _user,\n address _token,\n uint256 num\n ) public {\n processedCheckpoints[_user][_token] = num;\n }\n\n function getFullAccumulatedFees(\n address _user,\n address _token,\n uint32 _maxCheckpoints\n ) public view returns (uint256 amount, uint256 end) {\n (amount, end) = _getAccumulatedFees(_user, _token, 0, _maxCheckpoints);\n }\n\n function endOfRangeWithZeroMaxCheckpoint(address _token) public view returns (uint256) {\n return _getEndOfRange(0, _token, 0);\n }\n\n function getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) public view returns (uint256 _tokenAmount, uint256 _endToken) {\n return _getRBTCBalance(_token, _user, _maxCheckpoints);\n }\n\n function testWithdrawReentrancy(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n}\n" + }, + "contracts/mockup/GovernorAlphaMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/GovernorAlpha.sol\";\n\ncontract GovernorAlphaMockup is GovernorAlpha {\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 quorumVotes_,\n uint96 _minPercentageVotes\n ) public GovernorAlpha(timelock_, staking_, guardian_, quorumVotes_, _minPercentageVotes) {}\n\n function votingPeriod() public pure returns (uint256) {\n return 10;\n }\n\n function queueProposals(uint256[] calldata proposalIds) external {\n for (uint256 i = 0; i < proposalIds.length; i++) {\n queue(proposalIds[i]);\n }\n }\n}\n" + }, + "contracts/mockup/LiquidityMiningMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract LiquidityMiningMockup is LiquidityMining {\n function getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n public\n view\n returns (uint256)\n {\n return _getPassedBlocksWithBonusMultiplier(_from, _to);\n }\n\n function getPoolAccumulatedReward(address _poolToken) public view returns (uint256, uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n return _getPoolAccumulatedReward(pool);\n }\n}\n" + }, + "contracts/mockup/LiquidityPoolV1ConverterMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/IERC20.sol\";\n\ncontract LiquidityPoolV1ConverterMockup {\n IERC20[] public reserveTokens;\n IERC20 wrbtcToken;\n uint256 totalFeeMockupValue;\n address feesController;\n\n constructor(IERC20 _token0, IERC20 _token1) public {\n reserveTokens.push(_token0);\n reserveTokens.push(_token1);\n }\n\n function setFeesController(address _feesController) public {\n feesController = _feesController;\n }\n\n function setWrbtcToken(IERC20 _wrbtcToken) public {\n wrbtcToken = _wrbtcToken;\n }\n\n function setTotalFeeMockupValue(uint256 _totalFeeMockupValue) public {\n totalFeeMockupValue = _totalFeeMockupValue;\n }\n\n function withdrawFees(address _receiver) external returns (uint256) {\n require(msg.sender == feesController, \"unauthorized\");\n\n // transfer wrbtc\n wrbtcToken.transfer(_receiver, totalFeeMockupValue);\n return totalFeeMockupValue;\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/LoanClosingsWith.sol\";\n\ncontract LoanClosingsWithMockup is LoanClosingsWith {\n function worthTheTransfer(address, uint256) internal returns (bool) {\n return true;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithoutInvariantCheck.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanClosingsWithMockup.sol\";\n\ncontract LoanClosingsWithoutInvariantCheck is LoanClosingsWithMockup {\n /** Override the modifier of invariant check so that we can test the shared reentrancy guard */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n _;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicLMMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\n\ncontract LoanTokenLogicLMMockup is LoanTokenLogicLM {\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n returns (uint256 loanAmountPaid)\n {\n _callOptionalReturn(\n 0x2c34D66a5ca8686330e100372Eb3FDFB5aEECD0B, //Random EOA for testing\n abi.encodeWithSelector(IERC20(receiver).transfer.selector, receiver, burnAmount),\n \"error\"\n );\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicV2Mockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicV1Mockup is LoanTokenLogicStandard {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](27);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n // res[31] = this.totalSupply.selector;\n res[25] = this.balanceOf.selector;\n res[26] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n\ncontract LoanTokenLogicV2Mockup is LoanTokenLogicStandard {\n function testNewFunction() external pure returns (bool) {\n return true;\n }\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](29);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mockup\n res[28] = this.testNewFunction.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/mockup/lockedSOVFailedMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An interface for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete interface of the Locked SOV Contract.\n */\ncontract LockedSOVFailedMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The user balances.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n revert(\"For testing purposes\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/LockedSOVMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An mockup for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete mockup of the Locked SOV Contract.\n */\ncontract LockedSOVMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n event TokensStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // 10000 is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < 10000, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(10000);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n function _createVestingAndStake(address _sender) private {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n emit TokensStaked(_sender, address(0), amount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/MockAffiliates.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/Affiliates.sol\";\n\ncontract MockAffiliates is Affiliates {\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n }\n}\n" + }, + "contracts/mockup/MockFourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/Vesting/fouryear/FourYearVestingLogic.sol\";\n\ncontract MockFourYearVestingLogic is FourYearVestingLogic {\n /**\n * @notice gets duration left\n */\n function getDurationLeft() external view returns (uint256) {\n return durationLeft;\n }\n}\n" + }, + "contracts/mockup/MockLoanTokenLogic.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogic is LoanTokenLogic {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](31);\n\n // Loan Token Logic\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mock\n res[28] = this.setAffiliatesReferrer.selector;\n res[29] = this.setUserNotFirstTradeFlag.selector;\n res[30] = this.getMarginBorrowAmountAndRate.selector;\n\n return (res, stringToBytes32(\"MockLoanTokenLogic\"));\n }\n\n function setAffiliatesReferrer(address user, address referrer) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(user, referrer);\n }\n\n function setUserNotFirstTradeFlag(address user) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(user);\n }\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n\n /*function initialize(address target) external onlyOwner {\n\t\t_setTarget(this.setAffiliatesUserReferrer.selector, target);\n\t}*/\n}\n\ncontract ILoanTokenModulesMock is ILoanTokenModules {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user) external;\n}\n" + }, + "contracts/mockup/MockLoanTokenLogicLM.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogicLM is LoanTokenLogicLM {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n /** LoanTokenLogicLM function signature */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\"));\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\"));\n res[2] = bytes4(keccak256(\"burn(address,uint256)\"));\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\"));\n\n return (res, stringToBytes32(\"MockLoanTokenLogicLM\"));\n }\n}\n" + }, + "contracts/mockup/modules/IWeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract IWeightedStakingModuleMockup {\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) external;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) external;\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external;\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) external;\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/mockup/modules/StakingModuleBlockMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/StakingGovernanceModule.sol\";\nimport \"../../governance/Staking/modules/StakingStakeModule.sol\";\nimport \"../../governance/Staking/modules/StakingVestingModule.sol\";\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../BlockMockUp.sol\";\n\ncontract StakingModuleBlockMockup is\n IFunctionsList,\n StakingGovernanceModule,\n StakingStakeModule,\n StakingVestingModule,\n WeightedStakingModule\n{\n uint96 public priorWeightedStake;\n mapping(uint256 => uint96) public priorWeightedStakeAtBlock;\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n function balanceOf_MultipliedByTwo(address account) external view returns (uint256) {\n return this.balanceOf(account) * 2;\n }\n\n uint96 priorTotalVotingPower;\n\n function MOCK_priorTotalVotingPower(uint96 _priorTotalVotingPower) public {\n priorTotalVotingPower = _priorTotalVotingPower;\n }\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n return\n priorTotalVotingPower != 0\n ? priorTotalVotingPower\n : super.getPriorTotalVotingPower(blockNumber, time);\n }\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) public view returns (bool) {\n bytes32 codeHash = _getCodeHash(stakerAddress);\n return vestingCodeHashes[codeHash];\n }\n\n function getPriorWeightedStakeAtBlock(uint256 blockNum) public view returns (uint256) {\n return uint256(priorWeightedStakeAtBlock[blockNum]);\n }\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n // StakingGovernanceModule\n bytes4[] memory functionsList = new bytes4[](31);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n\n // StakingStakeModule\n functionsList[6] = this.stake.selector;\n functionsList[7] = this.stakeWithApproval.selector;\n functionsList[8] = this.extendStakingDuration.selector;\n functionsList[9] = this.stakesBySchedule.selector;\n functionsList[10] = this.stakeBySchedule.selector;\n functionsList[11] = this.balanceOf.selector;\n functionsList[12] = this.getCurrentStakedUntil.selector;\n functionsList[13] = this.getStakes.selector;\n functionsList[14] = this.timestampToLockDate.selector;\n\n //StakingVestingModule\n functionsList[15] = this.setVestingRegistry.selector;\n functionsList[16] = this.setVestingStakes.selector;\n functionsList[17] = this.getPriorUserStakeByDate.selector;\n functionsList[18] = this.getPriorVestingWeightedStake.selector;\n functionsList[19] = this.getPriorVestingStakeByDate.selector;\n functionsList[20] = this.addContractCodeHash.selector;\n functionsList[21] = this.removeContractCodeHash.selector;\n functionsList[22] = this.isVestingContract.selector;\n\n //BlockMockup\n functionsList[23] = this.setBlockMockUpAddr.selector;\n functionsList[24] = this.MOCK_priorWeightedStake.selector;\n functionsList[25] = this.MOCK_priorWeightedStakeAtBlock.selector;\n\n //WeightedStakingModule\n functionsList[26] = this.getPriorWeightedStake.selector;\n functionsList[27] = this.weightedStakeByDate.selector;\n functionsList[28] = this.computeWeightByDate.selector;\n functionsList[29] = this.priorWeightedStakeAtBlock.selector;\n functionsList[30] = this.getPriorWeightedStakeAtBlock.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/modules/StakingSharedModuleMock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/shared/StakingShared.sol\";\nimport \"../BlockMockUp.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\n\ncontract StakingModuleMock is IFunctionsList, StakingShared {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](1);\n functionList[0] = this.setBlockMockUpAddr.selector;\n }\n}\n" + }, + "contracts/mockup/modules/StakingWrapperMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\ncontract StakingWrapperMockup {\n uint256 constant TWO_WEEKS = 1209600;\n\n IStaking staking;\n IERC20 token;\n\n constructor(IStaking _staking, IERC20 _token) public {\n staking = _staking;\n token = _token;\n }\n\n function stake2times(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stake(amount, until, stakeFor, delegatee);\n }\n\n function stakeAndExtend(uint96 amount, uint256 until) external {\n require(token.transferFrom(msg.sender, address(this), amount));\n token.approve(address(staking), amount);\n\n staking.stake(amount, until, address(this), address(this));\n staking.extendStakingDuration(until, until + TWO_WEEKS);\n }\n\n function stakeAndStakeBySchedule(\n uint96 amount,\n uint256 until,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n}\n" + }, + "contracts/mockup/modules/WeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract WeightedStakingModuleMockup is WeightedStakingModule {\n uint96 priorWeightedStake;\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n mapping(uint256 => uint96) priorWeightedStakeAtBlock;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n functionsList[3] = this.MOCK_priorWeightedStake.selector;\n functionsList[4] = this.MOCK_priorWeightedStakeAtBlock.selector;\n functionsList[5] = this.calculatePriorWeightedStake.selector;\n functionsList[6] = this.setDelegateStake.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n//@todo can I change this proxy to EIP-1822 proxy standard, please. https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\ncontract PreviousLoanToken is AdvancedTokenStorage {\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../connectors/loantoken/interfaces/ProtocolSettingsLike.sol\";\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n// It is a LoanToken implementation!\ncontract PreviousLoanTokenSettingsLowerAdmin is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress\n\n // ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n // ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n //@todo check for restrictions in this contract\n modifier onlyAdmin() {\n require(msg.sender == address(this) || msg.sender == owner(), \"unauthorized\");\n _;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function init(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans // isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n // These params should be percentages represented like so: 5% = 5000000000000000000\n // rateMultiplier + baseRate can't exceed 100%\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; // 80 ether\n kinkLevel = _kinkLevel; // 90 ether\n maxScaleRate = _maxScaleRate; // 100 ether\n }\n\n function toggleFunctionPause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyAdmin {\n // keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /**\n * sets the transaction limit per token address\n * @param addresses the token addresses\n * @param limits the limit denominated in the currency of the token address\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyOwner\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n}\n" + }, + "contracts/mockup/PriceFeedsMoCMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../feeds/testnet/PriceFeedsMoC.sol\";\n\n// This contract is only for test purposes\n// https://github.com/money-on-chain/Amphiraos-Oracle/blob/master/contracts/medianizer/medianizer.sol\ncontract PriceFeedsMoCMockup is Medianizer {\n uint256 public value;\n bool public has;\n\n function peek() external view returns (bytes32, bool) {\n return (bytes32(value), has);\n }\n\n function setValue(uint256 _value) public {\n value = _value;\n }\n\n function setHas(bool _has) public {\n has = _has;\n }\n}\n" + }, + "contracts/mockup/ProtocolSettingsMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/ProtocolSettings.sol\";\n\ncontract ProtocolSettingsMockup is ProtocolSettings {\n function setLendingFeeTokensHeld(address token, uint256 amout) public {\n lendingFeeTokensHeld[token] = amout;\n }\n\n function setTradingFeeTokensHeld(address token, uint256 amout) public {\n tradingFeeTokensHeld[token] = amout;\n }\n\n function setBorrowingFeeTokensHeld(address token, uint256 amout) public {\n borrowingFeeTokensHeld[token] = amout;\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n\n _setTarget(this.setLendingFeeTokensHeld.selector, target);\n _setTarget(this.setTradingFeeTokensHeld.selector, target);\n _setTarget(this.setBorrowingFeeTokensHeld.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n\n _setTarget(this.getDefaultPathConversion.selector, target);\n }\n}\n" + }, + "contracts/mockup/proxy/ImplementationMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\n\ncontract ImplementationMockup is StorageMockup {\n function setValue(uint256 _value) public {\n value = _value;\n emit ValueChanged(_value);\n }\n\n function getValue() public view returns (uint256) {\n return value;\n }\n}\n" + }, + "contracts/mockup/proxy/ProxyMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract ProxyMockup is StorageMockup, UpgradableProxy {}\n" + }, + "contracts/mockup/proxy/StorageMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\ncontract StorageMockup {\n uint256 value;\n\n event ValueChanged(uint256 value);\n}\n" + }, + "contracts/mockup/RBTCWrapperProxyMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract RBTCWrapperProxyMockup {\n LiquidityMining public liquidityMining;\n\n constructor(LiquidityMining _liquidityMining) public {\n liquidityMining = _liquidityMining;\n }\n\n function claimReward(address _poolToken) public {\n liquidityMining.claimReward(_poolToken, msg.sender);\n }\n\n function claimRewardFromAllPools() public {\n liquidityMining.claimRewardFromAllPools(msg.sender);\n }\n\n function withdraw(address _poolToken, uint256 _amount) public {\n liquidityMining.withdraw(_poolToken, _amount, msg.sender);\n }\n}\n" + }, + "contracts/mockup/StakingRewardsMockUp.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/StakingRewards/StakingRewards.sol\";\nimport \"./BlockMockUp.sol\";\n\n/**\n * @title Staking Rewards Contract MockUp\n * @notice This is used for Testing\n * */\ncontract StakingRewardsMockUp is StakingRewards {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n using SafeMath for uint256;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n}\n" + }, + "contracts/mockup/TimelockHarness.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"../governance/Timelock.sol\";\n\ninterface Administered {\n function _acceptAdmin() external returns (uint256);\n}\n\ncontract TimelockHarness is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, delay_) {}\n\n function setDelayWithoutChecking(uint256 delay_) public {\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function harnessSetPendingAdmin(address pendingAdmin_) public {\n pendingAdmin = pendingAdmin_;\n }\n\n function harnessSetAdmin(address admin_) public {\n admin = admin_;\n }\n}\n\ncontract TimelockTest is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, 2 days) {\n delay = delay_;\n }\n\n function harnessSetAdmin(address admin_) public {\n require(msg.sender == admin);\n admin = admin_;\n }\n\n function harnessAcceptAdmin(Administered administered) public {\n administered._acceptAdmin();\n }\n}\n" + }, + "contracts/mockup/VestingLogicMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/Vesting/VestingLogic.sol\";\n\ncontract VestingLogicMockup is VestingLogic {\n /**\n * @dev we had a bug in a loop: \"i < endDate\" instead of \"i <= endDate\"\n */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n}\n" + }, + "contracts/mockup/VestingRegistryLogicMockUp.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\nimport \"../governance/Vesting/VestingRegistryLogic.sol\";\n\ncontract VestingRegistryLogicMockup is VestingRegistryLogic {\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return true;\n }\n\n function setTeamVesting(address _vesting, uint256 _vestingCreationType) external {\n vestingCreationAndTypes[_vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(VestingType.TeamVesting),\n vestingCreationType: uint128(_vestingCreationType)\n });\n }\n}\n" + }, + "contracts/modules/Affiliates.sol": { + "content": "/**\n * Copyright 2017-2020, Sovryn, All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Affiliates contract.\n * @notice Track referrals and reward referrers (affiliates) with tokens.\n * In-detail specifications are found at https://wiki.sovryn.app/en/community/Affiliates\n * @dev Module: Affiliates upgradable\n * Storage: from State, functions called from Protocol by delegatecall\n */\ncontract Affiliates is State, AffiliatesEvents, ModuleCommonFunctionalities {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Void constructor.\n */\n // solhint-disable-next-line no-empty-blocks\n constructor() public {}\n\n /**\n * @notice Avoid calls to this contract except for those explicitly declared.\n */\n function() external {\n revert(\"Affiliates - fallback not allowed\");\n }\n\n /**\n * @notice Set delegate callable functions by proxy contract.\n * @dev This contract is designed as a module, this way logic can be\n * expanded and upgraded w/o losing storage that is kept in the protocol (State.sol)\n * initialize() is used to register in the proxy external (module) functions\n * to be called via the proxy.\n * @param target The address of a new logic implementation.\n */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setAffiliatesReferrer.selector];\n _setTarget(this.setAffiliatesReferrer.selector, target);\n _setTarget(this.getUserNotFirstTradeFlag.selector, target);\n _setTarget(this.getReferralsList.selector, target);\n _setTarget(this.setUserNotFirstTradeFlag.selector, target);\n _setTarget(this.payTradingFeeToAffiliatesReferrer.selector, target);\n _setTarget(this.getAffiliatesReferrerBalances.selector, target);\n _setTarget(this.getAffiliatesReferrerTokenBalance.selector, target);\n _setTarget(this.getAffiliatesReferrerTokensList.selector, target);\n _setTarget(this.withdrawAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.withdrawAllAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.getMinReferralsToPayout.selector, target);\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n _setTarget(this.getAffiliateRewardsHeld.selector, target);\n _setTarget(this.getAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.getAffiliatesTokenRewardsValueInRbtc.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"Affiliates\");\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from loan pools.\n */\n modifier onlyCallableByLoanPools() {\n require(loanPoolToUnderlying[msg.sender] != address(0), \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from within protocol functions.\n */\n modifier onlyCallableInternal() {\n require(msg.sender == protocolAddress, \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Data structure comprised of 3 flags to compute the result of setting a referrer.\n */\n struct SetAffiliatesReferrerResult {\n bool success;\n bool alreadySet;\n bool userNotFirstTradeFlag;\n }\n\n /**\n * @notice Loan pool calls this function to tell affiliates\n * a user coming from a referrer is trading and should be registered if not yet.\n * Taking into account some user status flags may lead to the user and referrer\n * become added or not to the affiliates record.\n *\n * @param user The address of the user that is trading on loan pools.\n * @param referrer The address of the referrer the user is coming from.\n */\n function setAffiliatesReferrer(address user, address referrer)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n SetAffiliatesReferrerResult memory result;\n\n result.userNotFirstTradeFlag = getUserNotFirstTradeFlag(user);\n result.alreadySet = affiliatesUserReferrer[user] != address(0);\n result.success = !(result.userNotFirstTradeFlag || result.alreadySet || user == referrer);\n if (result.success) {\n affiliatesUserReferrer[user] = referrer;\n referralsList[referrer].add(user);\n emit SetAffiliatesReferrer(user, referrer);\n } else {\n emit SetAffiliatesReferrerFail(\n user,\n referrer,\n result.alreadySet,\n result.userNotFirstTradeFlag\n );\n }\n }\n\n /**\n * @notice Getter to query the referrals coming from a referrer.\n * @param referrer The address of a given referrer.\n * @return The referralsList mapping value by referrer.\n */\n function getReferralsList(address referrer) external view returns (address[] memory refList) {\n refList = referralsList[referrer].enumerate();\n return refList;\n }\n\n /**\n * @notice Getter to query the not-first-trade flag of a user.\n * @param user The address of a given user.\n * @return The userNotFirstTradeFlag mapping value by user.\n */\n function getUserNotFirstTradeFlag(address user) public view returns (bool) {\n return userNotFirstTradeFlag[user];\n }\n\n /**\n * @notice Setter to toggle on the not-first-trade flag of a user.\n * @param user The address of a given user.\n */\n function setUserNotFirstTradeFlag(address user)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n if (!userNotFirstTradeFlag[user]) {\n userNotFirstTradeFlag[user] = true;\n emit SetUserNotFirstTradeFlag(user);\n }\n }\n\n /**\n * @notice Internal getter to query the fee share for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function _getAffiliatesTradingFeePercentForSOV() internal view returns (uint256) {\n return affiliateFeePercent;\n }\n\n /**\n * @notice Internal to calculate the affiliates trading token fee amount.\n * Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * This _getReferrerTradingFeeForToken calculates the first one\n * by applying a custom percentage multiplier.\n * @param feeTokenAmount The trading token fee amount.\n * @return The affiliates share of the trading token fee amount.\n */\n function _getReferrerTradingFeeForToken(uint256 feeTokenAmount)\n internal\n view\n returns (uint256)\n {\n return feeTokenAmount.mul(getAffiliateTradingTokenFeePercent()).div(10**20);\n }\n\n /**\n * @notice Getter to query the fee share of trading token fee for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function getAffiliateTradingTokenFeePercent() public view returns (uint256) {\n return affiliateTradingTokenFeePercent;\n }\n\n /**\n * @notice Getter to query referral threshold for paying out to the referrer.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The minimum number of referrals set by Protocol.\n */\n function getMinReferralsToPayout() public view returns (uint256) {\n return minReferralsToPayout;\n }\n\n /**\n * @notice Get the sovToken reward of a trade.\n * @dev The reward is worth x% of the trading fee.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * @return The reward amount.\n * */\n function _getSovBonusAmount(address feeToken, uint256 feeAmount)\n internal\n view\n returns (uint256)\n {\n uint256 rewardAmount;\n address _priceFeeds = priceFeeds;\n\n /// @dev Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// dest token = SOV\n feeAmount.mul(_getAffiliatesTradingFeePercentForSOV()).div(1e20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n return rewardAmount;\n }\n\n /**\n * @notice Protocol calls this function to pay the affiliates rewards to a user (referrer).\n *\n * @dev Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * Both are paid in this function.\n *\n * @dev Actually they are not paid, but just holded by protocol until user claims them by\n * actively calling withdrawAffiliatesReferrerTokenFees() function,\n * and/or when unvesting lockedSOV.\n *\n * @dev To be precise, what this function does is updating the registers of the rewards\n * for the referrer including the assignment of the SOV tokens as rewards to the\n * referrer's vesting contract.\n *\n * @param referrer The address of the referrer.\n * @param trader The address of the trader.\n * @param token The address of the token in which the trading/borrowing fee was paid.\n * @param tradingFeeTokenBaseAmount Total trading fee amount, the base for calculating referrer's fees.\n *\n * @return referrerBonusSovAmount The amount of SOV tokens paid to the referrer (through a vesting contract, lockedSOV).\n * @return referrerBonusTokenAmount The amount of trading tokens paid directly to the referrer.\n */\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n )\n external\n onlyCallableInternal\n whenNotPaused\n returns (uint256 referrerBonusSovAmount, uint256 referrerBonusTokenAmount)\n {\n bool isHeld = referralsList[referrer].length() < getMinReferralsToPayout();\n bool bonusPaymentIsSuccess = true;\n uint256 paidReferrerBonusSovAmount;\n\n /// Process token fee rewards first.\n referrerBonusTokenAmount = _getReferrerTradingFeeForToken(tradingFeeTokenBaseAmount);\n if (!affiliatesReferrerTokensList[referrer].contains(token))\n affiliatesReferrerTokensList[referrer].add(token);\n affiliatesReferrerBalances[referrer][token] = affiliatesReferrerBalances[referrer][token]\n .add(referrerBonusTokenAmount);\n\n /// Then process SOV rewards.\n referrerBonusSovAmount = _getSovBonusAmount(token, tradingFeeTokenBaseAmount);\n uint256 rewardsHeldByProtocol = affiliateRewardsHeld[referrer];\n\n if (isHeld) {\n /// If referrals less than minimum, temp the rewards SOV to the storage\n affiliateRewardsHeld[referrer] = rewardsHeldByProtocol.add(referrerBonusSovAmount);\n } else {\n /// If referrals >= minimum, directly send all of the remain rewards to locked sov\n /// Call depositSOV() in LockedSov contract\n /// Set the affiliaterewardsheld = 0\n if (affiliateRewardsHeld[referrer] > 0) {\n affiliateRewardsHeld[referrer] = 0;\n }\n\n paidReferrerBonusSovAmount = referrerBonusSovAmount.add(rewardsHeldByProtocol);\n IERC20(sovTokenAddress).approve(lockedSOVAddress, paidReferrerBonusSovAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"depositSOV(address,uint256)\",\n referrer,\n paidReferrerBonusSovAmount\n )\n );\n\n if (!success) {\n bonusPaymentIsSuccess = false;\n }\n }\n\n if (bonusPaymentIsSuccess) {\n emit PayTradingFeeToAffiliate(\n referrer,\n trader, // trader\n token,\n isHeld,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n } else {\n emit PayTradingFeeToAffiliateFail(\n referrer,\n trader, // trader\n token,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n }\n\n return (referrerBonusSovAmount, referrerBonusTokenAmount);\n }\n\n /**\n * @notice Referrer calls this function to receive its reward in a given token.\n * It will send the other (non-SOV) reward tokens from trading protocol fees,\n * to the referrer’s wallet.\n * @dev Rewards are held by protocol in different tokens coming from trading fees.\n * Referrer has to claim them one by one for every token with accumulated balance.\n * @param token The address of the token to withdraw.\n * @param receiver The address of the withdrawal beneficiary.\n * @param amount The amount of tokens to claim. If greater than balance, just sends balance.\n */\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) public whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n uint256 referrerTokenBalance = affiliatesReferrerBalances[referrer][token];\n uint256 withdrawAmount = referrerTokenBalance > amount ? amount : referrerTokenBalance;\n\n require(withdrawAmount > 0, \"Affiliates: cannot withdraw zero amount\");\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n uint256 newReferrerTokenBalance = referrerTokenBalance.sub(withdrawAmount);\n\n if (newReferrerTokenBalance == 0) {\n _removeAffiliatesReferrerToken(referrer, token);\n } else {\n affiliatesReferrerBalances[referrer][token] = newReferrerTokenBalance;\n }\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawAffiliatesReferrerTokenFees(referrer, receiver, token, withdrawAmount);\n }\n\n /**\n * @notice Withdraw to msg.sender all token fees for a referrer.\n * @dev It's done by looping through its available tokens.\n * @param receiver The address of the withdrawal beneficiary.\n */\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n (address[] memory tokenAddresses, uint256[] memory tokenBalances) =\n getAffiliatesReferrerBalances(referrer);\n for (uint256 i; i < tokenAddresses.length; i++) {\n withdrawAffiliatesReferrerTokenFees(tokenAddresses[i], receiver, tokenBalances[i]);\n }\n }\n\n /**\n * @notice Internal function to delete a referrer's token balance.\n * @param referrer The address of the referrer.\n * @param token The address of the token specifying the balance to remove.\n */\n function _removeAffiliatesReferrerToken(address referrer, address token) internal {\n delete affiliatesReferrerBalances[referrer][token];\n affiliatesReferrerTokensList[referrer].remove(token);\n }\n\n /**\n * @notice Get all token balances of a referrer.\n * @param referrer The address of the referrer.\n * @return referrerTokensList The array of available tokens (keys).\n * @return referrerTokensBalances The array of token balances (values).\n */\n function getAffiliatesReferrerBalances(address referrer)\n public\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances)\n {\n referrerTokensList = getAffiliatesReferrerTokensList(referrer);\n referrerTokensBalances = new uint256[](referrerTokensList.length);\n for (uint256 i; i < referrerTokensList.length; i++) {\n referrerTokensBalances[i] = getAffiliatesReferrerTokenBalance(\n referrer,\n referrerTokensList[i]\n );\n }\n return (referrerTokensList, referrerTokensBalances);\n }\n\n /**\n * @dev Get all token rewards estimation value in rbtc.\n *\n * @param referrer Address of referrer.\n *\n * @return The value estimation in rbtc.\n */\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount)\n {\n address[] memory tokensList = getAffiliatesReferrerTokensList(referrer);\n address _priceFeeds = priceFeeds;\n\n for (uint256 i; i < tokensList.length; i++) {\n // Get the value of each token in rbtc\n\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n tokensList[i], // source token\n address(wrbtcToken), // dest token = SOV\n affiliatesReferrerBalances[referrer][tokensList[i]] // total token rewards\n )\n );\n\n assembly {\n if eq(success, 1) {\n rbtcTotalAmount := add(rbtcTotalAmount, mload(add(data, 32)))\n }\n }\n }\n }\n\n /**\n * @notice Get all available tokens at the affiliates program for a given referrer.\n * @param referrer The address of a given referrer.\n * @return tokensList The list of available tokens.\n */\n function getAffiliatesReferrerTokensList(address referrer)\n public\n view\n returns (address[] memory tokensList)\n {\n tokensList = affiliatesReferrerTokensList[referrer].enumerate();\n return tokensList;\n }\n\n /**\n * @notice Getter to query the affiliate balance for a given referrer and token.\n * @param referrer The address of the referrer.\n * @param token The address of the token to get balance for.\n * @return The affiliatesReferrerBalances mapping value by referrer and token keys.\n */\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n public\n view\n returns (uint256)\n {\n return affiliatesReferrerBalances[referrer][token];\n }\n\n /**\n * @notice Getter to query the address of referrer for a given user.\n * @param user The address of the user.\n * @return The address on affiliatesUserReferrer mapping value by user key.\n */\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user];\n }\n\n /**\n * @notice Getter to query the reward amount held for a given referrer.\n * @param referrer The address of the referrer.\n * @return The affiliateRewardsHeld mapping value by referrer key.\n */\n function getAffiliateRewardsHeld(address referrer) public view returns (uint256) {\n return affiliateRewardsHeld[referrer];\n }\n}\n" + }, + "contracts/modules/interfaces/ProtocolAffiliatesInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolAffiliatesInterface {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user_) external;\n\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\n\n function payTradingFeeToAffiliatesReferrer(\n address affiliate,\n address trader,\n address token,\n uint256 amount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n}\n" + }, + "contracts/modules/interfaces/ProtocolSwapExternalInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolSwapExternalInterface {\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n}\n" + }, + "contracts/modules/LoanClosingsLiquidation.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsLiquidation contract.\n * @notice Ways to close a loan: liquidation. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsLiquidation is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.liquidate.selector];\n _setTarget(this.liquidate.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsLiquidation\"\n );\n }\n\n /**\n * @notice Liquidate an unhealty loan.\n *\n * @dev Public wrapper for _liquidate internal function.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * loanId is the ID of the loan, which is created on loan opening.\n * It can be obtained either by parsing the Trade event or by reading\n * the open loans from the contract by calling getActiveLoans or getUserLoans.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n return _liquidate(loanId, receiver, closeAmount);\n }\n\n /**\n * @notice Internal function for liquidating an unhealthy loan.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function _liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin <= loanParamsLocal.maintenanceMargin, \"healthy position\");\n\n loanCloseAmount = closeAmount;\n\n //amounts to restore the desired margin (maintencance + 5%)\n (uint256 maxLiquidatable, uint256 maxSeizable, ) =\n _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n\n if (loanCloseAmount < maxLiquidatable) {\n //close maxLiquidatable if tiny position will remain\n uint256 remainingAmount = maxLiquidatable - loanCloseAmount;\n remainingAmount = _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingAmount <= TINY_AMOUNT) {\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable.mul(loanCloseAmount).div(maxLiquidatable);\n }\n } else if (loanCloseAmount > maxLiquidatable) {\n // adjust down the close amount to the max\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable;\n }\n\n require(loanCloseAmount != 0, \"nothing to liquidate\");\n\n // liquidator deposits the principal being closed\n _returnPrincipalWithDeposit(loanParamsLocal.loanToken, address(this), loanCloseAmount);\n\n // a portion of the principal is repaid to the lender out of interest refunded\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n loanLocal.borrower\n );\n\n if (loanCloseAmount > loanCloseAmountLessInterest) {\n // full interest refund goes to the borrower\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanCloseAmount - loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmountLessInterest != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n seizedToken = loanParamsLocal.collateralToken;\n\n if (seizedAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(seizedAmount);\n\n _withdrawAsset(seizedToken, receiver, seizedAmount);\n }\n\n _closeLoan(loanLocal, loanCloseAmount);\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n seizedAmount,\n collateralToLoanRate,\n 0,\n currentMargin,\n CloseTypes.Liquidation\n );\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsRollover.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsRollover contract.\n * @notice Ways to close a loan: rollover. Margin trade\n * positions are always closed with a swap.\n *\n * */\ncontract LoanClosingsRollover is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.rollover.selector];\n _setTarget(this.rollover.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsRollover\"\n );\n }\n\n /**\n * @notice Roll over a loan.\n *\n * @dev Public wrapper for _rollover internal function.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * The function rollover on the protocol contract extends the loan\n * duration by the maximum term (28 days for margin trades at the moment\n * of writing), pays the interest to the lender and refunds the caller\n * for the gas cost by sending 2 * the gas cost using the fast gas price\n * as base for the calculation.\n *\n * @param loanId The ID of the loan to roll over.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n * */\n function rollover(\n bytes32 loanId,\n bytes calldata // for future use /*loanDataBytes*/\n ) external nonReentrant globallyNonReentrant iTokenSupplyUnchanged(loanId) whenNotPaused {\n // restrict to EOAs to prevent griefing attacks, during interest rate recalculation\n require(msg.sender == tx.origin, \"EOAs call\");\n\n return\n _rollover(\n loanId,\n \"\" // loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for roll over a loan.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * @param loanId The ID of the loan to roll over.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n * */\n function _rollover(bytes32 loanId, bytes memory loanDataBytes) internal {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n require(block.timestamp > loanLocal.endTimestamp.sub(3600), \"healthy position\");\n require(loanPoolToUnderlying[loanLocal.lender] != address(0), \"invalid lender\");\n\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n // Handle back interest: calculates interest owned since the loan endtime passed but the loan remained open\n uint256 backInterestTime;\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestTime = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestTime.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(1 days);\n }\n\n //note: to avoid code duplication, it would be nicer to store loanParamsLocal.maxLoanTerm in a local variable\n //however, we've got stack too deep issues if we do so.\n if (loanParamsLocal.maxLoanTerm != 0) {\n // fixed-term loan, so need to query iToken for latest variable rate\n uint256 owedPerDay =\n loanLocal.principal.mul(ILoanPool(loanLocal.lender).borrowInterestRate()).div(\n 365 * 10**20\n );\n\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(\n loanInterestLocal.owedPerDay\n );\n\n loanInterestLocal.owedPerDay = owedPerDay;\n\n //if the loan has been open for longer than an additional period, add at least 1 additional day\n if (backInterestTime >= loanParamsLocal.maxLoanTerm) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n }\n //extend by the max loan term\n else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(loanParamsLocal.maxLoanTerm);\n }\n } else {\n // loanInterestLocal.owedPerDay doesn't change\n if (backInterestTime >= MONTH) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n } else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(MONTH);\n }\n }\n\n uint256 interestAmountRequired = loanLocal.endTimestamp.sub(block.timestamp);\n interestAmountRequired = interestAmountRequired.mul(loanInterestLocal.owedPerDay);\n interestAmountRequired = interestAmountRequired.div(1 days);\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n\n // add backInterestOwed\n interestAmountRequired = interestAmountRequired.add(backInterestOwed);\n\n // collect interest (needs to be converted from the collateral)\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n 0, //min swap 0 -> swap connector estimates the amount of source tokens to use\n interestAmountRequired, //required destination tokens\n true, // returnTokenIsCollateral\n loanDataBytes\n );\n\n //received more tokens than needed to pay the interest\n if (destTokenAmountReceived > interestAmountRequired) {\n // swap rest back to collateral, if the amount is big enough to cover gas cost\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n )\n ) {\n (destTokenAmountReceived, , ) = _swapBackExcess(\n loanLocal,\n loanParamsLocal,\n destTokenAmountReceived - interestAmountRequired, //amount to be swapped\n loanDataBytes\n );\n sourceTokenAmountUsed = sourceTokenAmountUsed.sub(destTokenAmountReceived);\n }\n //else give it to the protocol as a lending fee\n else {\n _payLendingFee(\n loanLocal.borrower,\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n );\n }\n }\n\n //subtract the interest from the collateral\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n if (backInterestOwed != 0) {\n // pay out backInterestOwed\n\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n uint256 rolloverReward =\n _getRolloverReward(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.principal\n );\n\n if (rolloverReward != 0) {\n // if the reward > collateral:\n if (rolloverReward > loanLocal.collateral) {\n // 1. pay back the remaining loan to the lender\n // 2. pay the remaining collateral to msg.sender\n // 3. close the position & emit close event\n _closeWithSwap(\n loanLocal.id,\n msg.sender,\n loanLocal.collateral,\n false,\n \"\" // loanDataBytes\n );\n } else {\n // pay out reward to caller\n loanLocal.collateral = loanLocal.collateral.sub(rolloverReward);\n\n _withdrawAsset(loanParamsLocal.collateralToken, msg.sender, rolloverReward);\n }\n }\n\n if (loanLocal.collateral > 0) {\n //close whole loan if tiny position will remain\n if (_getAmountInRbtc(loanParamsLocal.loanToken, loanLocal.principal) <= TINY_AMOUNT) {\n _closeWithSwap(\n loanLocal.id,\n loanLocal.borrower,\n loanLocal.collateral, // swap all collaterals\n false,\n \"\" /// loanDataBytes\n );\n } else {\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n require(\n currentMargin > 3 ether, // ensure there's more than 3% margin remaining\n \"unhealthy position\"\n );\n }\n }\n\n if (loanLocal.active) {\n emit Rollover(\n loanLocal.borrower, // user (borrower)\n loanLocal.lender, // lender\n loanLocal.id, // loanId\n loanLocal.principal, // principal\n loanLocal.collateral, // collateral\n loanLocal.endTimestamp, // endTimestamp\n msg.sender, // rewardReceiver\n rolloverReward // reward\n );\n }\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsShared.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/RewardHelper.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\n/**\n * @title LoanClosingsShared contract.\n * @notice This contract should only contains the internal function that is being used / utilized by\n * LoanClosingsLiquidation, LoanClosingsRollover & LoanClosingsWith contract\n *\n * */\ncontract LoanClosingsShared is\n LoanClosingsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n RewardHelper,\n ModuleCommonFunctionalities\n{\n uint256 internal constant MONTH = 365 days / 12;\n //0.00001 BTC, would be nicer in State.sol, but would require a redeploy of the complete protocol, so adding it here instead\n //because it's not shared state anyway and only used by this contract\n uint256 public constant paySwapExcessToBorrowerThreshold = 10000000000000;\n\n uint256 public constant TINY_AMOUNT = 25e13;\n\n enum CloseTypes { Deposit, Swap, Liquidation }\n\n /** modifier for invariant check */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n Loan storage loanLocal = loans[loanId];\n\n require(loanLocal.lender != address(0), \"Invalid loan token pool address\");\n\n uint256 previousITokenSupply = ILoanTokenModules(loanLocal.lender).totalSupply();\n\n _;\n\n /// Validate iToken total supply\n require(\n previousITokenSupply == ILoanTokenModules(loanLocal.lender).totalSupply(),\n \"loan token supply invariant check failure\"\n );\n }\n\n /**\n * @dev computes the interest which needs to be refunded to the borrower based on the amount he's closing and either\n * subtracts it from the amount which still needs to be paid back (in case outstanding amount > interest) or withdraws the\n * excess to the borrower (in case interest > outstanding).\n * @param loanLocal the loan\n * @param loanParamsLocal the loan params\n * @param loanCloseAmount the amount to be closed (base for the computation)\n * @param receiver the address of the receiver (usually the borrower)\n * */\n function _settleInterestToPrincipal(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 loanCloseAmount,\n address receiver\n ) internal returns (uint256) {\n uint256 loanCloseAmountLessInterest = loanCloseAmount;\n\n //compute the interest which neeeds to be refunded to the borrower (because full interest is paid on loan )\n uint256 interestRefundToBorrower =\n _settleInterest(loanParamsLocal, loanLocal, loanCloseAmountLessInterest);\n\n uint256 interestAppliedToPrincipal;\n //if the outstanding loan is bigger than the interest to be refunded, reduce the amount to be paid back / closed by the interest\n if (loanCloseAmountLessInterest >= interestRefundToBorrower) {\n // apply all of borrower interest refund torwards principal\n interestAppliedToPrincipal = interestRefundToBorrower;\n\n // principal needed is reduced by this amount\n loanCloseAmountLessInterest -= interestRefundToBorrower;\n\n // no interest refund remaining\n interestRefundToBorrower = 0;\n } else {\n //if the interest refund is bigger than the outstanding loan, the user needs to get back the interest\n // principal fully covered by excess interest\n interestAppliedToPrincipal = loanCloseAmountLessInterest;\n\n // amount refunded is reduced by this amount\n interestRefundToBorrower -= loanCloseAmountLessInterest;\n\n // principal fully covered by excess interest\n loanCloseAmountLessInterest = 0;\n\n if (interestRefundToBorrower != 0) {\n // refund overage\n _withdrawAsset(loanParamsLocal.loanToken, receiver, interestRefundToBorrower);\n }\n }\n\n //pay the interest to the lender\n //note: this is a waste of gas, because the loanCloseAmountLessInterest is withdrawn to the lender, too. It could be done at once.\n if (interestAppliedToPrincipal != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, interestAppliedToPrincipal);\n }\n\n return loanCloseAmountLessInterest;\n }\n\n // The receiver always gets back an ERC20 (even wrbtc)\n function _returnPrincipalWithDeposit(\n address loanToken,\n address receiver,\n uint256 principalNeeded\n ) internal {\n if (principalNeeded != 0) {\n if (msg.value == 0) {\n vaultTransfer(loanToken, msg.sender, receiver, principalNeeded);\n } else {\n require(loanToken == address(wrbtcToken), \"wrong asset sent\");\n require(msg.value >= principalNeeded, \"not enough ether\");\n wrbtcToken.deposit.value(principalNeeded)();\n if (receiver != address(this)) {\n vaultTransfer(loanToken, address(this), receiver, principalNeeded);\n }\n if (msg.value > principalNeeded) {\n // refund overage\n Address.sendValue(msg.sender, msg.value - principalNeeded);\n }\n }\n } else {\n require(msg.value == 0, \"wrong asset sent\");\n }\n }\n\n /**\n * @dev checks if the amount of the asset to be transfered is worth the transfer fee\n * @param asset the asset to be transfered\n * @param amount the amount to be transfered\n * @return True if the amount is bigger than the threshold\n * */\n function worthTheTransfer(address asset, uint256 amount) internal returns (bool) {\n uint256 amountInRbtc = _getAmountInRbtc(asset, amount);\n emit swapExcess(\n amountInRbtc > paySwapExcessToBorrowerThreshold,\n amount,\n amountInRbtc,\n paySwapExcessToBorrowerThreshold\n );\n\n return amountInRbtc > paySwapExcessToBorrowerThreshold;\n }\n\n /**\n * swaps collateral tokens for loan tokens\n * @param loanLocal the loan object\n * @param loanParamsLocal the loan parameters\n * @param swapAmount the amount to be swapped\n * @param principalNeeded the required destination token amount\n * @param returnTokenIsCollateral if true -> required destination token amount will be passed on, else not\n * note: quite dirty. should be refactored.\n * @param loanDataBytes additional loan data (not in use for token swaps)\n * */\n function _doCollateralSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n loanLocal.collateral, // maxSourceTokenAmount\n returnTokenIsCollateral\n ? principalNeeded // requiredDestTokenAmount\n : 0,\n false, // bypassFee\n loanDataBytes\n );\n require(destTokenAmountReceived >= principalNeeded, \"insufficient dest amount\");\n require(sourceTokenAmountUsed <= loanLocal.collateral, \"excessive source amount\");\n }\n\n /**\n * @notice Withdraw asset to receiver.\n *\n * @param assetToken The loan token.\n * @param receiver The address of the receiver.\n * @param assetAmount The loan token amount.\n * */\n function _withdrawAsset(\n address assetToken,\n address receiver,\n uint256 assetAmount\n ) internal {\n if (assetAmount != 0) {\n if (assetToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, assetAmount);\n } else {\n vaultWithdraw(assetToken, receiver, assetAmount);\n }\n }\n }\n\n /**\n * @notice Internal function to close a loan.\n *\n * @param loanLocal The loan object.\n * @param loanCloseAmount The amount to close: principal or lower.\n *\n * */\n function _closeLoan(Loan storage loanLocal, uint256 loanCloseAmount) internal {\n require(loanCloseAmount != 0, \"nothing to close\");\n\n if (loanCloseAmount == loanLocal.principal) {\n loanLocal.principal = 0;\n loanLocal.active = false;\n loanLocal.endTimestamp = block.timestamp;\n loanLocal.pendingTradesId = 0;\n activeLoansSet.removeBytes32(loanLocal.id);\n lenderLoanSets[loanLocal.lender].removeBytes32(loanLocal.id);\n borrowerLoanSets[loanLocal.borrower].removeBytes32(loanLocal.id);\n } else {\n loanLocal.principal = loanLocal.principal.sub(loanCloseAmount);\n }\n }\n\n function _settleInterest(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 closePrincipal\n ) internal returns (uint256) {\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 interestTime = block.timestamp;\n if (interestTime > loanLocal.endTimestamp) {\n interestTime = loanLocal.endTimestamp;\n }\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n interestTime\n );\n\n uint256 owedPerDayRefund;\n if (closePrincipal < loanLocal.principal) {\n owedPerDayRefund = loanInterestLocal.owedPerDay.mul(closePrincipal).div(\n loanLocal.principal\n );\n } else {\n owedPerDayRefund = loanInterestLocal.owedPerDay;\n }\n\n // update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.sub(owedPerDayRefund);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(owedPerDayRefund);\n\n // update borrower interest\n uint256 interestRefundToBorrower = loanLocal.endTimestamp.sub(interestTime);\n interestRefundToBorrower = interestRefundToBorrower.mul(owedPerDayRefund);\n interestRefundToBorrower = interestRefundToBorrower.div(1 days);\n\n if (closePrincipal < loanLocal.principal) {\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(\n interestRefundToBorrower\n );\n } else {\n loanInterestLocal.depositTotal = 0;\n }\n\n // update remaining lender interest values\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.sub(\n closePrincipal\n );\n\n uint256 owedTotal = lenderInterestLocal.owedTotal;\n lenderInterestLocal.owedTotal = owedTotal > interestRefundToBorrower\n ? owedTotal - interestRefundToBorrower\n : 0;\n\n return interestRefundToBorrower;\n }\n\n /**\n * @notice Check sender is borrower or delegatee and loan id exists.\n *\n * @param loanId byte32 of the loan id.\n * */\n function _checkAuthorized(bytes32 loanId) internal view {\n Loan storage loanLocal = loans[loanId];\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n }\n\n /**\n * @notice Internal function for closing a position by swapping the\n * collateral back to loan tokens, paying the lender and withdrawing\n * the remainder.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collatral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid\n * out in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(swapAmount != 0, \"swapAmount == 0\");\n\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't swap more than collateral.\n swapAmount = swapAmount > loanLocal.collateral ? loanLocal.collateral : swapAmount;\n\n //close whole loan if tiny position will remain\n if (loanLocal.collateral - swapAmount > 0) {\n if (\n _getAmountInRbtc(\n loanParamsLocal.collateralToken,\n loanLocal.collateral - swapAmount\n ) <= TINY_AMOUNT\n ) {\n swapAmount = loanLocal.collateral;\n }\n }\n\n uint256 loanCloseAmountLessInterest;\n if (swapAmount == loanLocal.collateral || returnTokenIsCollateral) {\n /// loanCloseAmountLessInterest will be passed as required amount amount of destination tokens.\n /// this means, the actual swapAmount passed to the swap contract does not matter at all.\n /// the source token amount will be computed depending on the required amount amount of destination tokens.\n loanCloseAmount = swapAmount == loanLocal.collateral\n ? loanLocal.principal\n : loanLocal.principal.mul(swapAmount).div(loanLocal.collateral);\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Computes the interest refund for the borrower and sends it to the lender to cover part of the principal.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n } else {\n /// loanCloseAmount is calculated after swap; for this case we want to swap the entire source amount\n /// and determine the loanCloseAmount and withdraw amount based on that.\n loanCloseAmountLessInterest = 0;\n }\n\n uint256 coveredPrincipal;\n uint256 usedCollateral;\n\n /// swapAmount repurposed for collateralToLoanSwapRate to avoid stack too deep error.\n (coveredPrincipal, usedCollateral, withdrawAmount, swapAmount) = _coverPrincipalWithSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount, /// The amount of source tokens to swap (only matters if !returnTokenIsCollateral or loanCloseAmountLessInterest = 0)\n loanCloseAmountLessInterest, /// This is the amount of destination tokens we want to receive (only matters if returnTokenIsCollateral)\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (loanCloseAmountLessInterest == 0) {\n /// Condition prior to swap: swapAmount != loanLocal.collateral && !returnTokenIsCollateral\n\n /// Amounts that is closed.\n loanCloseAmount = coveredPrincipal;\n if (coveredPrincipal != loanLocal.principal) {\n loanCloseAmount = loanCloseAmount.mul(usedCollateral).div(loanLocal.collateral);\n }\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Amount that is returned to the lender.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n\n /// Remaining amount withdrawn to the receiver.\n withdrawAmount = withdrawAmount.add(coveredPrincipal).sub(loanCloseAmountLessInterest);\n } else {\n /// Pay back the amount which was covered by the swap.\n loanCloseAmountLessInterest = coveredPrincipal;\n }\n\n require(loanCloseAmountLessInterest != 0, \"closeAmount is 0 after swap\");\n\n /// Reduce the collateral by the amount which was swapped for the closure.\n if (usedCollateral != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(usedCollateral);\n }\n\n /// Repays principal to lender.\n /// The lender always gets back an ERC20 (even wrbtc), so we call\n /// withdraw directly rather than use the _withdrawAsset helper function.\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, loanCloseAmountLessInterest);\n\n withdrawToken = returnTokenIsCollateral\n ? loanParamsLocal.collateralToken\n : loanParamsLocal.loanToken;\n\n if (withdrawAmount != 0) {\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n usedCollateral,\n swapAmount, /// collateralToLoanSwapRate\n CloseTypes.Swap\n );\n }\n\n /**\n * @notice Close a loan.\n *\n * @dev Wrapper for _closeLoan internal function.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan params.\n * @param loanCloseAmount The amount to close: principal or lower.\n * @param collateralCloseAmount The amount of collateral to close.\n * @param collateralToLoanSwapRate The price rate collateral/loan token.\n * @param closeType The type of loan close.\n * */\n function _finalizeClose(\n Loan storage loanLocal,\n LoanParams storage loanParamsLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanSwapRate,\n CloseTypes closeType\n ) internal {\n _closeLoan(loanLocal, loanCloseAmount);\n\n address _priceFeeds = priceFeeds;\n uint256 currentMargin;\n uint256 collateralToLoanRate;\n\n /// This is still called even with full loan close to return collateralToLoanRate\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).getCurrentMargin.selector,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n )\n );\n assembly {\n if eq(success, 1) {\n currentMargin := mload(add(data, 32))\n collateralToLoanRate := mload(add(data, 64))\n }\n }\n /// Note: We can safely skip the margin check if closing\n /// via closeWithDeposit or if closing the loan in full by any method.\n require(\n closeType == CloseTypes.Deposit ||\n loanLocal.principal == 0 || /// loan fully closed\n currentMargin > loanParamsLocal.maintenanceMargin,\n \"unhealthy position\"\n );\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n collateralCloseAmount,\n collateralToLoanRate,\n collateralToLoanSwapRate,\n currentMargin,\n closeType\n );\n }\n\n /**\n * swaps a share of a loan's collateral or the complete collateral in order to cover the principle.\n * @param loanLocal the loan\n * @param loanParamsLocal the loan parameters\n * @param swapAmount in case principalNeeded == 0 or !returnTokenIsCollateral, this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens needed for the swap is estimated by the connector.\n * @param principalNeeded the required amount of destination tokens in order to cover the principle (only used if returnTokenIsCollateral)\n * @param returnTokenIsCollateral tells if the user wants to withdraw his remaining collateral + profit in collateral tokens\n * @notice Swaps a share of a loan's collateral or the complete collateral\n * in order to cover the principle.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount In case principalNeeded == 0 or !returnTokenIsCollateral,\n * this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens\n * needed for the swap is estimated by the connector.\n * @param principalNeeded The required amount of destination tokens in order to\n * cover the principle (only used if returnTokenIsCollateral).\n * @param returnTokenIsCollateral Tells if the user wants to withdraw his\n * remaining collateral + profit in collateral tokens.\n *\n * @return coveredPrincipal The amount of principal that is covered.\n * @return usedCollateral The amount of collateral used.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _coverPrincipalWithSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 coveredPrincipal,\n uint256 usedCollateral,\n uint256 withdrawAmount,\n uint256 collateralToLoanSwapRate\n )\n {\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n (\n destTokenAmountReceived,\n sourceTokenAmountUsed,\n collateralToLoanSwapRate\n ) = _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount,\n principalNeeded,\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (returnTokenIsCollateral) {\n coveredPrincipal = principalNeeded;\n\n /// Better fill than expected.\n if (destTokenAmountReceived > coveredPrincipal) {\n /// Send excess to borrower if the amount is big enough to be\n /// worth the gas fees.\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - coveredPrincipal\n )\n ) {\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n destTokenAmountReceived - coveredPrincipal\n );\n }\n /// Else, give the excess to the lender (if it goes to the\n /// borrower, they're very confused. causes more trouble than it's worth)\n else {\n coveredPrincipal = destTokenAmountReceived;\n }\n }\n withdrawAmount = swapAmount > sourceTokenAmountUsed\n ? swapAmount - sourceTokenAmountUsed\n : 0;\n } else {\n require(sourceTokenAmountUsed == swapAmount, \"swap error\");\n\n if (swapAmount == loanLocal.collateral) {\n /// sourceTokenAmountUsed == swapAmount == loanLocal.collateral\n\n coveredPrincipal = principalNeeded;\n withdrawAmount = destTokenAmountReceived - principalNeeded;\n } else {\n /// sourceTokenAmountUsed == swapAmount < loanLocal.collateral\n\n if (destTokenAmountReceived >= loanLocal.principal) {\n /// Edge case where swap covers full principal.\n\n coveredPrincipal = loanLocal.principal;\n withdrawAmount = destTokenAmountReceived - loanLocal.principal;\n\n /// Excess collateral refunds to the borrower.\n _withdrawAsset(\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n loanLocal.collateral - sourceTokenAmountUsed\n );\n sourceTokenAmountUsed = loanLocal.collateral;\n } else {\n coveredPrincipal = destTokenAmountReceived;\n withdrawAmount = 0;\n }\n }\n }\n\n usedCollateral = sourceTokenAmountUsed > swapAmount ? sourceTokenAmountUsed : swapAmount;\n }\n\n function _emitClosingEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanRate,\n uint256 collateralToLoanSwapRate,\n uint256 currentMargin,\n CloseTypes closeType\n ) internal {\n if (closeType == CloseTypes.Deposit) {\n emit CloseWithDeposit(\n loanLocal.borrower, /// user (borrower)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n msg.sender, /// closer\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n loanCloseAmount, /// loanCloseAmount\n collateralCloseAmount, /// collateralCloseAmount\n collateralToLoanRate, /// collateralToLoanRate\n currentMargin /// currentMargin\n );\n } else if (closeType == CloseTypes.Swap) {\n /// exitPrice = 1 / collateralToLoanSwapRate\n if (collateralToLoanSwapRate != 0) {\n collateralToLoanSwapRate = SafeMath.div(10**36, collateralToLoanSwapRate);\n }\n\n /// currentLeverage = 100 / currentMargin\n if (currentMargin != 0) {\n currentMargin = SafeMath.div(10**38, currentMargin);\n }\n\n emit CloseWithSwap(\n loanLocal.borrower, /// user (trader)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n msg.sender, /// closer\n collateralCloseAmount, /// positionCloseSize\n loanCloseAmount, /// loanCloseAmount\n collateralToLoanSwapRate, /// exitPrice (1 / collateralToLoanSwapRate)\n currentMargin /// currentLeverage\n );\n } else if (closeType == CloseTypes.Liquidation) {\n emit Liquidate(\n loanLocal.borrower, // user (borrower)\n msg.sender, // liquidator\n loanLocal.id, // loanId\n loanLocal.lender, // lender\n loanParamsLocal.loanToken, // loanToken\n loanParamsLocal.collateralToken, // collateralToken\n loanCloseAmount, // loanCloseAmount\n collateralCloseAmount, // collateralCloseAmount\n collateralToLoanRate, // collateralToLoanRate\n currentMargin // currentMargin\n );\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal view returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n IPriceFeeds(priceFeeds).queryRate(asset, address(wrbtcToken));\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /**\n * @dev private function which check the loanLocal & loanParamsLocal does exist\n *\n * @param loanId bytes32 of loanId\n *\n * @return Loan storage\n * @return LoanParams storage\n */\n function _checkLoan(bytes32 loanId) internal view returns (Loan storage, LoanParams storage) {\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n return (loanLocal, loanParamsLocal);\n }\n}\n" + }, + "contracts/modules/LoanClosingsWith.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsWith contract.\n * @notice Close a loan w/deposit, close w/swap. There are 2 functions for ending a loan on the\n * protocol contract: closeWithSwap and closeWithDeposit. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsWith is LoanClosingsShared {\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n\n /**\n * @notice Closes a loan by doing a deposit.\n *\n * @dev Public wrapper for _closeWithDeposit internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens. (e.g. rBTC on a iSUSD contract).\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n public\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return _closeWithDeposit(loanId, receiver, depositAmount);\n }\n\n /**\n * @notice Close a position by swapping the collateral back to loan tokens\n * paying the lender and withdrawing the remainder.\n *\n * @dev Public wrapper for _closeWithSwap internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collateral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid out\n * in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes memory // for future use /*loanDataBytes*/\n )\n public\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return\n _closeWithSwap(\n loanId,\n receiver,\n swapAmount,\n returnTokenIsCollateral,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for closing a loan by doing a deposit.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens.\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(depositAmount != 0, \"depositAmount == 0\");\n\n //TODO should we skip this check if invoked from rollover ?\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't close more than the full principal.\n loanCloseAmount = depositAmount > loanLocal.principal\n ? loanLocal.principal\n : depositAmount;\n\n //revert if tiny position remains\n uint256 remainingAmount = loanLocal.principal - loanCloseAmount;\n if (remainingAmount > 0) {\n require(\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount) > TINY_AMOUNT,\n \"Tiny amount when closing with deposit\"\n );\n }\n\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(loanLocal, loanParamsLocal, loanCloseAmount, receiver);\n\n if (loanCloseAmountLessInterest != 0) {\n _returnPrincipalWithDeposit(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmount == loanLocal.principal) {\n withdrawAmount = loanLocal.collateral;\n } else {\n withdrawAmount = loanLocal.collateral.mul(loanCloseAmount).div(loanLocal.principal);\n }\n\n withdrawToken = loanParamsLocal.collateralToken;\n\n if (withdrawAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(withdrawAmount);\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n withdrawAmount, /// collateralCloseAmount\n 0, /// collateralToLoanSwapRate\n CloseTypes.Deposit\n );\n }\n\n /**\n * @notice Function to check whether the given loanId & deposit amount when closing with deposit will cause the tiny position\n *\n * @param loanId The id of the loan.\n * @param depositAmount Defines how much the deposit amount to close the position.\n *\n * @return isTinyPosition true is indicating tiny position, false otherwise.\n * @return tinyPositionAmount will return 0 for non tiny position, and will return the amount of tiny position if true\n */\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount)\n {\n (Loan memory loanLocal, LoanParams memory loanParamsLocal) = _checkLoan(loanId);\n\n if (depositAmount < loanLocal.principal) {\n uint256 remainingAmount = loanLocal.principal - depositAmount;\n uint256 remainingRBTCAmount =\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingRBTCAmount < TINY_AMOUNT) {\n isTinyPosition = true;\n tinyPositionAmount = remainingRBTCAmount;\n }\n }\n\n return (isTinyPosition, tinyPositionAmount);\n }\n}\n" + }, + "contracts/modules/LoanMaintenance.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Maintenance contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to query loan data and to modify its status\n * by withdrawing or depositing collateral.\n * */\ncontract LoanMaintenance is\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n LiquidationHelper,\n ModuleCommonFunctionalities\n{\n // Keep the old LoanReturnData for backward compatibility (especially for the watcher)\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n // The new struct which contained borrower & creation time of a loan\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set initial values of proxy targets.\n *\n * @param target The address of the logic contract instance.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.depositCollateral.selector];\n _setTarget(this.depositCollateral.selector, target);\n _setTarget(this.withdrawCollateral.selector, target);\n _setTarget(this.withdrawAccruedInterest.selector, target);\n _setTarget(this.extendLoanDuration.selector, target);\n _setTarget(this.reduceLoanDuration.selector, target);\n _setTarget(this.getLenderInterestData.selector, target);\n _setTarget(this.getLoanInterestData.selector, target);\n _setTarget(this.getUserLoans.selector, target);\n _setTarget(this.getUserLoansV2.selector, target);\n _setTarget(this.getLoan.selector, target);\n _setTarget(this.getLoanV2.selector, target);\n _setTarget(this.getActiveLoans.selector, target);\n _setTarget(this.getActiveLoansV2.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanMaintenance\");\n }\n\n /**\n * @notice Increase the margin of a position by depositing additional collateral.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount /// must match msg.value if ether is sent\n ) external payable nonReentrant whenNotPaused {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.value == 0 || loanParamsLocal.collateralToken == address(wrbtcToken),\n \"wrong asset sent\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(depositAmount);\n\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.collateralToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n\n (uint256 collateralToLoanRate, ) =\n IPriceFeeds(priceFeeds).queryRate(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n\n emit DepositCollateral(loanId, depositAmount, collateralToLoanRate);\n }\n\n /**\n * @notice Withdraw from the collateral. This reduces the margin of a position.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 actualWithdrawAmount) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral,\n loanParamsLocal.maintenanceMargin\n );\n\n if (withdrawAmount > maxDrawdown) {\n actualWithdrawAmount = maxDrawdown;\n } else {\n actualWithdrawAmount = withdrawAmount;\n }\n\n loanLocal.collateral = loanLocal.collateral.sub(actualWithdrawAmount);\n\n if (loanParamsLocal.collateralToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, actualWithdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.collateralToken, receiver, actualWithdrawAmount);\n }\n }\n\n /**\n * @notice Withdraw accrued loan interest.\n *\n * @dev Wrapper for _payInterest internal function.\n *\n * @param loanToken The loan token address.\n * */\n function withdrawAccruedInterest(address loanToken) external whenNotPaused {\n /// Pay outstanding interest to lender.\n _payInterest(\n msg.sender, /// Lender.\n loanToken\n );\n }\n\n /**\n * @notice Extend the loan duration by as much time as depositAmount can buy.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in loan tokens. Used to pay the interest for the new duration.\n * @param useCollateral Whether pay interests w/ the collateral. If true, depositAmount of loan tokens\n *\t\t\t\t\t\twill be purchased with the collateral.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n *\n * @return secondsExtended The amount of time in seconds the loan is extended.\n * */\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external payable nonReentrant whenNotPaused returns (uint256 secondsExtended) {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n !useCollateral ||\n msg.sender == loanLocal.borrower ||\n delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(\n msg.value == 0 || (!useCollateral && loanParamsLocal.loanToken == address(wrbtcToken)),\n \"wrong asset sent\"\n );\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n /// Handle back interest: calculates interest owned since the loan\n /// endtime passed but the loan remained open.\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestOwed = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestOwed.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(86400);\n\n require(depositAmount > backInterestOwed, \"deposit cannot cover back interest\");\n }\n\n /// Deposit interest.\n if (useCollateral) {\n /// Used the whole converted loanToken to extend the loan duration\n depositAmount = _doCollateralSwap(loanLocal, loanParamsLocal, depositAmount);\n } else {\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.loanToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n }\n\n if (backInterestOwed != 0) {\n depositAmount = depositAmount.sub(backInterestOwed);\n\n /// Pay out backInterestOwed\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n secondsExtended = depositAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(secondsExtended);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(depositAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .add(depositAmount);\n }\n\n /**\n * @notice Reduce the loan duration by withdrawing from the deposited interest.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in loan tokens.\n *\n * @return secondsReduced The amount of time in seconds the loan is reduced.\n * */\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 secondsReduced) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(loanLocal.endTimestamp > block.timestamp, \"loan term has ended\");\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 interestDepositRemaining =\n loanLocal.endTimestamp.sub(block.timestamp).mul(loanInterestLocal.owedPerDay).div(\n 86400\n );\n require(withdrawAmount < interestDepositRemaining, \"withdraw amount too high\");\n\n /// Withdraw interest.\n if (loanParamsLocal.loanToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, withdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.loanToken, receiver, withdrawAmount);\n }\n\n secondsReduced = withdrawAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n require(loanLocal.endTimestamp > secondsReduced, \"loan too short\");\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.sub(secondsReduced);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(withdrawAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .sub(withdrawAmount);\n }\n\n /**\n * @notice Get current lender interest data totals for all loans\n * with a specific oracle and interest token.\n *\n * @param lender The lender address.\n * @param loanToken The loan token address.\n *\n * @return interestPaid The total amount of interest that has been paid to a lender so far.\n * @return interestPaidDate The date of the last interest pay out, or 0 if no interest has been withdrawn yet.\n * @return interestOwedPerDay The amount of interest the lender is earning per day.\n * @return interestUnPaid The total amount of interest the lender is owned and not yet withdrawn.\n * @return interestFeePercent The fee retained by the protocol before interest is paid to the lender.\n * @return principalTotal The total amount of outstanding principal the lender has loaned.\n * */\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n )\n {\n LenderInterest memory lenderInterestLocal = lenderInterest[lender][loanToken];\n\n interestUnPaid = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(86400);\n if (interestUnPaid > lenderInterestLocal.owedTotal)\n interestUnPaid = lenderInterestLocal.owedTotal;\n\n return (\n lenderInterestLocal.paidTotal,\n lenderInterestLocal.paidTotal != 0 ? lenderInterestLocal.updatedTimestamp : 0,\n lenderInterestLocal.owedPerDay,\n lenderInterestLocal.updatedTimestamp != 0 ? interestUnPaid : 0,\n lendingFeePercent,\n lenderInterestLocal.principalTotal\n );\n }\n\n /**\n * @notice Get current interest data for a loan.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loanToken The loan token that interest is paid in.\n * @return interestOwedPerDay The amount of interest the borrower is paying per day.\n * @return interestDepositTotal The total amount of interest the borrower has deposited.\n * @return interestDepositRemaining The amount of deposited interest that is not yet owed to a lender.\n * */\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n )\n {\n loanToken = loanParams[loans[loanId].loanParamsId].loanToken;\n interestOwedPerDay = loanInterest[loanId].owedPerDay;\n interestDepositTotal = loanInterest[loanId].depositTotal;\n\n uint256 endTimestamp = loans[loanId].endTimestamp;\n uint256 interestTime = block.timestamp > endTimestamp ? endTimestamp : block.timestamp;\n interestDepositRemaining = endTimestamp > interestTime\n ? endTimestamp.sub(interestTime).mul(interestOwedPerDay).div(86400)\n : 0;\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData) {\n return\n _getLoan(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2) {\n return\n _getLoanV2(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get all active loans.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @dev New view function which will return the loan data.\n * @dev This function was created to support backward compatibility\n * @dev As in we the old getActiveLoans function is not expected to be changed by the wathcers.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loanData The data structure\n * @return extendedLoanData The data structure which contained (borrower & creation time)\n */\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Internal function to get one loan data structure.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ the loan information.\n * */\n function _getLoan(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnData memory loanData) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanData;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanData;\n }\n\n return\n LoanReturnData({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable\n });\n }\n\n /**\n * @notice Internal function to get one loan data structure v2.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data v2 structure w/ the loan information.\n * */\n function _getLoanV2(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnDataV2 memory loanDataV2) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanDataV2;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanDataV2;\n }\n\n return\n LoanReturnDataV2({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n borrower: loanLocal.borrower,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable,\n creationTimestamp: loanLocal.startTimestamp\n });\n }\n\n /**\n * @notice Internal function to collect interest from the collateral.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param depositAmount The amount of underlying tokens provided on the loan.\n * */\n function _doCollateralSwap(\n Loan storage loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 depositAmount\n ) internal returns (uint256 purchasedLoanToken) {\n /// Reverts in _loanSwap if amountNeeded can't be bought.\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanLocal.collateral, /// minSourceTokenAmount\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n depositAmount, /// requiredDestTokenAmount (partial spend of loanLocal.collateral to fill this amount)\n true, /// bypassFee\n \"\" /// loanDataBytes\n );\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n /// Ensure the loan is still healthy.\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n return destTokenAmountReceived;\n }\n}\n" + }, + "contracts/modules/LoanOpenings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\n/**\n * @title Loan Openings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to borrow and trade.\n * */\ncontract LoanOpenings is\n LoanOpeningsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n ModuleCommonFunctionalities\n{\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\n _setTarget(this.borrowOrTradeFromPool.selector, target);\n _setTarget(this.setDelegatedManager.selector, target);\n _setTarget(this.getEstimatedMarginExposure.selector, target);\n _setTarget(this.getRequiredCollateral.selector, target);\n _setTarget(this.getBorrowAmount.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanOpenings\");\n }\n\n /**\n * @notice Borrow or trade from pool.\n *\n * @dev Note: Only callable by loan pools (iTokens).\n * Wrapper to _borrowOrTrade internal function.\n *\n * @param loanParamsId The ID of the loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return newPrincipal The new loan size.\n * @return newCollateral The new collateral amount.\n * */\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n bytes calldata loanDataBytes\n )\n external\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 newPrincipal, uint256 newCollateral)\n {\n require(msg.value == 0 || loanDataBytes.length != 0, \"loanDataBytes required with ether\");\n\n /// Only callable by loan pools.\n require(loanPoolToUnderlying[msg.sender] != address(0), \"not authorized\");\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n /// Get required collateral.\n uint256 collateralAmountRequired =\n _getRequiredCollateral(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentValues.newPrincipal,\n initialMargin,\n isTorqueLoan\n );\n require(collateralAmountRequired != 0, \"collateral is 0\");\n\n return\n _borrowOrTrade(\n loanParamsLocal,\n loanId,\n isTorqueLoan,\n collateralAmountRequired,\n initialMargin,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @dev Wrapper for _setDelegatedManager internal function.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external whenNotPaused {\n require(loans[loanId].borrower == msg.sender, \"unauthorized\");\n\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\n }\n\n /**\n * @notice Get the estimated margin exposure.\n *\n * Margin is the money borrowed from a broker to purchase an investment\n * and is the difference between the total value of investment and the\n * loan amount. Margin trading refers to the practice of using borrowed\n * funds from a broker to trade a financial asset, which forms the\n * collateral for the loan from the broker.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param loanTokenSent The amount of loan tokens sent.\n * @param collateralTokenSent The amount of collateral tokens sent.\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\n * @param newPrincipal The updated amount of principal (current debt).\n *\n * @return The margin exposure.\n * */\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256) {\n uint256 maxLoanTerm = 2419200; // 28 days\n\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\n\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\n\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\n uint256 tradingFee = _getTradingFee(swapAmount);\n if (tradingFee != 0) {\n swapAmount = swapAmount.sub(tradingFee);\n }\n\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\n if (receivedAmount == 0) {\n return 0;\n } else {\n return collateralTokenSent.add(receivedAmount);\n }\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Calls internal _getRequiredCollateral and add fees.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralAmountRequired The required collateral.\n * */\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 collateralAmountRequired) {\n if (marginAmount != 0) {\n collateralAmountRequired = _getRequiredCollateral(\n loanToken,\n collateralToken,\n newPrincipal,\n marginAmount,\n isTorqueLoan\n );\n\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n // cannot be applied solely as it drives to some other tests failure\n /*\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (collateralAmountRequired != 0 && feePercent != 0) {\n\t\t\t\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t);\n\t\t\t}*/\n\n uint256 fee =\n isTorqueLoan\n ? _getBorrowingFee(collateralAmountRequired)\n : _getTradingFee(collateralAmountRequired);\n if (fee != 0) {\n collateralAmountRequired = collateralAmountRequired.add(fee);\n }\n }\n }\n\n /**\n * @notice Get the borrow amount of a trade loan.\n *\n * @dev Basically borrowAmount = collateral / marginAmount\n *\n * Collateral is something that helps secure a loan. When you borrow money,\n * you agree that your lender can take something and sell it to get their\n * money back if you fail to repay the loan. That's the collateral.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param collateralTokenAmount The amount of collateral.\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return borrowAmount The borrow amount.\n * */\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 borrowAmount) {\n if (marginAmount != 0) {\n if (isTorqueLoan) {\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\n }\n uint256 collateral = collateralTokenAmount;\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\n if (fee != 0) {\n collateral = collateral.sub(fee);\n }\n if (loanToken == collateralToken) {\n borrowAmount = collateral.mul(10**20).div(marginAmount);\n } else {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestPrecision != 0) {\n borrowAmount = collateral\n .mul(10**20)\n .mul(sourceToDestRate)\n .div(marginAmount)\n .div(sourceToDestPrecision);\n }\n }\n /*\n\t\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t\t// cannot be applied solely as it drives to some other tests failure\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (borrowAmount != 0 && feePercent != 0) {\n\t\t\t\tborrowAmount = borrowAmount\n\t\t\t\t\t.mul(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t)\n\t\t\t\t\t.divCeil(10**20);\n\t\t\t}*/\n }\n }\n\n /**\n * @notice Borrow or trade.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param collateralAmountRequired The required amount of collateral.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return The new loan size.\n * @return The new collateral amount.\n * */\n function _borrowOrTrade(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 collateralAmountRequired,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n require(\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\n \"collateral/loan match\"\n );\n require(initialMargin >= loanParamsLocal.minInitialMargin, \"initialMargin too low\");\n\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\n require(\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\n \"invalid interest\"\n );\n\n // @note this fix is for borrowing only\n uint256 sentNewPrincipal = isTorqueLoan ? sentValues.newPrincipal : 0;\n\n /// Initialize loan.\n Loan storage loanLocal =\n loans[\n _initializeLoan(\n loanParamsLocal,\n loanId,\n initialMargin,\n sentAddresses,\n sentValues.newPrincipal\n )\n ];\n\n // Get required interest.\n uint256 amount =\n _initializeInterest(\n loanParamsLocal,\n loanLocal,\n sentValues.interestRate, /// newRate\n sentValues.newPrincipal, /// newPrincipal,\n sentValues.interestInitialAmount /// torqueInterest\n );\n\n /// substract out interest from usable loanToken sent.\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\n\n if (isTorqueLoan) {\n require(sentValues.loanTokenSent == 0, \"surplus loan token\");\n\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\n // need to temp into local state to avoid\n address _collateralToken = loanParamsLocal.collateralToken;\n address _loanToken = loanParamsLocal.loanToken;\n if (borrowingFee != 0) {\n _payBorrowingFee(\n sentAddresses.borrower, /// borrower\n loanLocal.id,\n _collateralToken, /// fee token\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n borrowingFee\n );\n\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\n }\n } else {\n /// Update collateral after trade.\n sentValues = _updateCollateralAfterTrade(\n loanId,\n loanParamsLocal,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /// Settle collateral.\n require(\n _isCollateralSatisfied(\n loanParamsLocal,\n loanLocal,\n initialMargin,\n sentValues.collateralTokenSent,\n collateralAmountRequired,\n sentNewPrincipal\n ),\n \"collateral insufficient\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\n\n if (isTorqueLoan) {\n /// reclaiming variable -> interestDuration\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\n } else {\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\n }\n\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\n\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\n }\n\n function _updateCollateralAfterTrade(\n bytes32 loanId,\n LoanParams memory loanParamsLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (MarginTradeStructHelpers.SentAmounts memory) {\n uint256 receivedAmount;\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\n loanId,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentAddresses.borrower, /// borrower\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\n false, /// bypassFee\n loanDataBytes\n );\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\n\n /// Check the minEntryPrice with the rate\n require(\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\n \"entry price above the minimum\"\n );\n\n return sentValues;\n }\n\n /**\n * @notice Finalize an open loan.\n *\n * @dev Finalize it by updating local parameters of the loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _finalizeOpen(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bool isTorqueLoan\n ) internal {\n /// @dev TODO: here the actual used rate and margin should go.\n (uint256 initialMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(initialMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n if (loanLocal.startTimestamp == block.timestamp) {\n uint256 loanToCollateralPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken\n );\n uint256 collateralToLoanPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\n loanLocal.startRate = isTorqueLoan\n ? collateralToLoanRate\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\n }\n\n _emitOpeningEvents(\n loanParamsLocal,\n loanLocal,\n sentAddresses,\n sentValues,\n collateralToLoanRate,\n initialMargin,\n isTorqueLoan\n );\n }\n\n /**\n * @notice Emit the opening events.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n * @param margin The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _emitOpeningEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n uint256 collateralToLoanRate,\n uint256 margin,\n bool isTorqueLoan\n ) internal {\n if (isTorqueLoan) {\n emit Borrow(\n sentAddresses.borrower, /// user (borrower)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n sentValues.newPrincipal, /// newPrincipal\n sentValues.collateralTokenSent, /// newCollateral\n sentValues.interestRate, /// interestRate\n sentValues.interestDuration, /// interestDuration\n collateralToLoanRate, /// collateralToLoanRate,\n margin /// currentMargin\n );\n } else {\n /// currentLeverage = 100 / currentMargin\n margin = SafeMath.div(10**38, margin);\n\n emit Trade(\n sentAddresses.borrower, /// user (trader)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n sentValues.collateralTokenSent, /// positionSize\n sentValues.newPrincipal, /// borrowedAmount\n sentValues.interestRate, /// interestRate,\n loanLocal.endTimestamp, /// settlementDate\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\n sentValues.entryLeverage, /// entryLeverage\n margin /// currentLeverage\n );\n }\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegator The address of previous manager.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function _setDelegatedManager(\n bytes32 loanId,\n address delegator,\n address delegated,\n bool toggle\n ) internal {\n delegatedManagers[loanId][delegated] = toggle;\n\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\n }\n\n /**\n * @notice Calculate whether the collateral is satisfied.\n *\n * @dev Basically check collateral + drawdown >= 98% of required.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param initialMargin The initial amount of margin.\n * @param newCollateral The amount of new collateral.\n * @param collateralAmountRequired The amount of required collateral.\n * @param newPrincipal The amount to borrow.\n *\n * @return Whether the collateral is satisfied.\n * */\n function _isCollateralSatisfied(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 initialMargin,\n uint256 newCollateral,\n uint256 collateralAmountRequired,\n uint256 newPrincipal\n ) internal view returns (bool) {\n /// Allow at most 2% under-collateralized.\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\n\n if (newCollateral < collateralAmountRequired) {\n /// Check that existing collateral is sufficient coverage.\n if (loanLocal.collateral != 0) {\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal.sub(newPrincipal), // sub(newPrincipal) to exclude the new borrowed amount from the total principal to calculate maxDrawdown for existing loan\n loanLocal.collateral,\n initialMargin\n );\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\n } else {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @notice Initialize a loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan.\n * @param initialMargin The amount of margin of the trade.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\n * @return The loanId.\n * */\n function _initializeLoan(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n uint256 newPrincipal\n ) internal returns (bytes32) {\n require(loanParamsLocal.active, \"loanParams disabled\");\n\n address lender = sentAddresses.lender;\n address borrower = sentAddresses.borrower;\n address manager = sentAddresses.manager;\n\n Loan memory loanLocal;\n\n if (loanId == 0) {\n borrowerNonce[borrower]++;\n loanId = keccak256(\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\n );\n require(loans[loanId].id == 0, \"loan exists\");\n\n loanLocal = Loan({\n id: loanId,\n loanParamsId: loanParamsLocal.id,\n pendingTradesId: 0,\n active: true,\n principal: newPrincipal,\n collateral: 0, /// calculated later\n startTimestamp: block.timestamp,\n endTimestamp: 0, /// calculated later\n startMargin: initialMargin,\n startRate: 0, /// queried later\n borrower: borrower,\n lender: lender\n });\n\n activeLoansSet.addBytes32(loanId);\n lenderLoanSets[lender].addBytes32(loanId);\n borrowerLoanSets[borrower].addBytes32(loanId);\n } else {\n loanLocal = loans[loanId];\n require(\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\n \"loan has ended\"\n );\n require(loanLocal.borrower == borrower, \"borrower mismatch\");\n require(loanLocal.lender == lender, \"lender mismatch\");\n require(loanLocal.loanParamsId == loanParamsLocal.id, \"loanParams mismatch\");\n\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\n }\n\n if (manager != address(0)) {\n _setDelegatedManager(loanId, borrower, manager, true);\n }\n\n loans[loanId] = loanLocal;\n\n return loanId;\n }\n\n /**\n * @notice Initialize a loan interest.\n *\n * @dev A Torque loan is an indefinite-term loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param newRate The new interest rate of the loan.\n * @param newPrincipal The new principal amount of the loan.\n * @param torqueInterest The interest rate of the Torque loan.\n *\n * @return interestAmountRequired The interest amount required.\n * */\n function _initializeInterest(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n uint256 newRate,\n uint256 newPrincipal,\n uint256 torqueInterest /// ignored for fixed-term loans\n ) internal returns (uint256 interestAmountRequired) {\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 previousDepositRemaining;\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\n previousDepositRemaining = loanLocal\n .endTimestamp\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\n .mul(loanInterestLocal.owedPerDay)\n .div(86400);\n }\n\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\n\n /// Update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n\n if (maxLoanTerm == 0) {\n /// Indefinite-term (Torque) loan.\n\n /// torqueInterest != 0 was confirmed earlier.\n loanLocal.endTimestamp = torqueInterest\n .add(previousDepositRemaining)\n .mul(86400)\n .div(loanInterestLocal.owedPerDay)\n .add(block.timestamp);\n\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxLoanTerm > 3600, \"loan too short\");\n\n interestAmountRequired = torqueInterest;\n } else {\n /// Fixed-term loan.\n\n if (loanLocal.endTimestamp == 0) {\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\n }\n\n interestAmountRequired = loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(owedPerDay)\n .div(86400);\n }\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n /// Update remaining lender interest values.\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Basically collateral = newPrincipal * marginAmount\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralTokenAmount The required collateral.\n * */\n function _getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) internal view returns (uint256 collateralTokenAmount) {\n if (loanToken == collateralToken) {\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\n } else {\n /// Using the price feed instead of the swap expected return\n /// because we need the rate in the inverse direction\n /// so the swap is probably farther off than the price feed.\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestRate != 0) {\n collateralTokenAmount = newPrincipal\n .mul(sourceToDestPrecision)\n .div(sourceToDestRate)\n .mul(marginAmount)\n .div(10**20);\n /*TODO: review\n\t\t\t\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\n }\n }\n // ./tests/loan-token/TradingTestToken.test.js\n if (isTorqueLoan && collateralTokenAmount != 0) {\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\n collateralTokenAmount\n );\n }\n }\n}\n" + }, + "contracts/modules/LoanSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to get and set loan parameters.\n * */\ncontract LoanSettings is State, LoanSettingsEvents, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"LoanSettings - fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setupLoanParams.selector];\n _setTarget(this.setupLoanParams.selector, target);\n _setTarget(this.disableLoanParams.selector, target);\n _setTarget(this.getLoanParams.selector, target);\n _setTarget(this.getLoanParamsList.selector, target);\n _setTarget(this.getTotalPrincipal.selector, target);\n _setTarget(this.minInitialMargin.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanSettings\");\n }\n\n /**\n * @notice Setup loan parameters, by looping every loan\n * and populating its parameters.\n *\n * @dev For each loan calls _setupLoanParams internal function.\n *\n * @param loanParamsList The array of loan parameters.\n *\n * @return loanParamsIdList The array of loan parameters IDs.\n * */\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n whenNotPaused\n returns (bytes32[] memory loanParamsIdList)\n {\n loanParamsIdList = new bytes32[](loanParamsList.length);\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsIdList[i] = _setupLoanParams(loanParamsList[i]);\n }\n }\n\n /**\n * @notice Deactivate LoanParams for future loans. Active loans\n * using it are unaffected.\n *\n * @param loanParamsIdList The array of loan parameters IDs to deactivate.\n * */\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external whenNotPaused {\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n require(msg.sender == loanParams[loanParamsIdList[i]].owner, \"unauthorized owner\");\n loanParams[loanParamsIdList[i]].active = false;\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n emit LoanParamsDisabled(\n loanParamsLocal.id,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdDisabled(loanParamsLocal.id, loanParamsLocal.owner);\n }\n }\n\n /**\n * @notice Get loan parameters for every matching IDs.\n *\n * @param loanParamsIdList The array of loan parameters IDs to match.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParams(bytes32[] memory loanParamsIdList)\n public\n view\n returns (LoanParams[] memory loanParamsList)\n {\n loanParamsList = new LoanParams[](loanParamsIdList.length);\n uint256 itemCount;\n\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n if (loanParamsLocal.id == 0) {\n continue;\n }\n loanParamsList[itemCount] = loanParamsLocal;\n itemCount++;\n }\n\n if (itemCount < loanParamsList.length) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get loan parameters for an owner and a given page\n * defined by an offset and a limit.\n *\n * @param owner The address of the loan owner.\n * @param start The page offset.\n * @param count The page limit.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList) {\n EnumerableBytes32Set.Bytes32Set storage set = userLoanParamSets[owner];\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loanParamsList;\n }\n\n loanParamsList = new bytes32[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n loanParamsList[itemCount] = set.get(i + start - 1);\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get the total principal of the loans by a lender.\n *\n * @param lender The address of the lender.\n * @param loanToken The address of the token instance.\n *\n * @return The total principal of the loans.\n * */\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256) {\n return lenderInterest[lender][loanToken].principalTotal;\n }\n\n /**\n * @notice Setup a loan parameters.\n *\n * @param loanParamsLocal The loan parameters.\n *\n * @return loanParamsId The loan parameters ID.\n * */\n function _setupLoanParams(LoanParams memory loanParamsLocal) internal returns (bytes32) {\n bytes32 loanParamsId =\n keccak256(\n abi.encodePacked(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm,\n block.timestamp\n )\n );\n require(loanParams[loanParamsId].id == 0, \"loanParams exists\");\n\n require(\n loanParamsLocal.loanToken != address(0) &&\n loanParamsLocal.collateralToken != address(0) &&\n loanParamsLocal.minInitialMargin > loanParamsLocal.maintenanceMargin &&\n (loanParamsLocal.maxLoanTerm == 0 || loanParamsLocal.maxLoanTerm > 3600), /// A defined maxLoanTerm has to be greater than one hour.\n \"invalid params\"\n );\n\n loanParamsLocal.id = loanParamsId;\n loanParamsLocal.active = true;\n loanParamsLocal.owner = msg.sender;\n\n loanParams[loanParamsId] = loanParamsLocal;\n userLoanParamSets[msg.sender].addBytes32(loanParamsId);\n\n emit LoanParamsSetup(\n loanParamsId,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdSetup(loanParamsId, loanParamsLocal.owner);\n\n return loanParamsId;\n }\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256) {\n return loanParams[loanParamsId].minInitialMargin;\n }\n}\n" + }, + "contracts/modules/ProtocolSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../mixins/ProtocolTokenUser.sol\";\nimport \"../modules/interfaces/ProtocolSwapExternalInterface.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../governance/IFeeSharingCollector.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title Protocol Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to customize protocol settings.\n * */\ncontract ProtocolSettings is\n State,\n ProtocolTokenUser,\n ProtocolSettingsEvents,\n ModuleCommonFunctionalities\n{\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyAdminOrOwner {\n address prevModuleContractAddress = logicTargets[this.setPriceFeedContract.selector];\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n _setTarget(this.setRebatePercent.selector, target);\n _setTarget(this.setSpecialRebates.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.togglePaused.selector, target);\n _setTarget(this.isProtocolPaused.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n _setTarget(this.setRolloverFlexFeePercent.selector, target);\n _setTarget(this.getDefaultPathConversion.selector, target);\n _setTarget(this.setDefaultPathConversion.selector, target);\n _setTarget(this.removeDefaultPathConversion.selector, target);\n _setTarget(this.setAdmin.selector, target);\n _setTarget(this.getAdmin.selector, target);\n _setTarget(this.setPauser.selector, target);\n _setTarget(this.getPauser.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"ProtocolSettings\");\n }\n\n /**\n * setting wrong address will break inter module functions calling\n * should be set once\n */\n function setSovrynProtocolAddress(address newProtocolAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address oldProtocolAddress = protocolAddress;\n protocolAddress = newProtocolAddress;\n\n emit SetProtocolAddress(msg.sender, oldProtocolAddress, newProtocolAddress);\n }\n\n function setSOVTokenAddress(address newSovTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newSovTokenAddress), \"newSovTokenAddress not a contract\");\n\n address oldTokenAddress = sovTokenAddress;\n sovTokenAddress = newSovTokenAddress;\n\n emit SetSOVTokenAddress(msg.sender, oldTokenAddress, newSovTokenAddress);\n }\n\n function setLockedSOVAddress(address newLockedSOVAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newLockedSOVAddress), \"newLockSOVAddress not a contract\");\n\n address oldLockedSOVAddress = lockedSOVAddress;\n lockedSOVAddress = newLockedSOVAddress;\n\n emit SetLockedSOVAddress(msg.sender, oldLockedSOVAddress, newLockedSOVAddress);\n }\n\n /**\n * @notice Set the basis point of trading rebate rewards (SOV), max value is 9999 (99.99% liquid, 0.01% vested).\n *\n * @param newBasisPoint Basis point value.\n */\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newBasisPoint <= 9999, \"value too high\");\n\n uint256 oldBasisPoint = tradingRebateRewardsBasisPoint;\n tradingRebateRewardsBasisPoint = newBasisPoint;\n\n emit SetTradingRebateRewardsBasisPoint(msg.sender, oldBasisPoint, newBasisPoint);\n }\n\n /**\n * @notice Update the minimum number of referrals to get affiliates rewards.\n *\n * @param newMinReferrals The new minimum number of referrals.\n * */\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n uint256 oldMinReferrals = minReferralsToPayout;\n minReferralsToPayout = newMinReferrals;\n\n emit SetMinReferralsToPayoutAffiliates(msg.sender, oldMinReferrals, newMinReferrals);\n }\n\n /**\n * @notice Set the address of the Price Feed instance.\n *\n * @param newContract The address of the Price Feed new instance.\n * */\n function setPriceFeedContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = priceFeeds;\n priceFeeds = newContract;\n\n emit SetPriceFeedContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set the address of the asset swapper instance.\n *\n * @param newContract The address of the asset swapper new instance.\n * */\n function setSwapsImplContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = swapsImpl;\n swapsImpl = newContract;\n\n emit SetSwapsImplContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set a list of loan pools and its tokens.\n *\n * @param pools The array of addresses of new loan pool instances.\n * @param assets The array of addresses of the corresponding underlying tokens.\n * */\n function setLoanPool(address[] calldata pools, address[] calldata assets)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(pools.length == assets.length, \"count mismatch\");\n\n for (uint256 i = 0; i < pools.length; i++) {\n require(pools[i] != assets[i], \"pool == asset\");\n require(pools[i] != address(0), \"pool == 0\");\n require(\n assets[i] != address(0) || loanPoolToUnderlying[pools[i]] != address(0),\n \"pool not exists\"\n );\n if (assets[i] == address(0)) {\n underlyingToLoanPool[loanPoolToUnderlying[pools[i]]] = address(0);\n loanPoolToUnderlying[pools[i]] = address(0);\n loanPoolsSet.removeAddress(pools[i]);\n } else {\n loanPoolToUnderlying[pools[i]] = assets[i];\n underlyingToLoanPool[assets[i]] = pools[i];\n loanPoolsSet.addAddress(pools[i]);\n }\n\n emit SetLoanPool(msg.sender, pools[i], assets[i]);\n }\n }\n\n /**\n * @notice Set a list of supported tokens by populating the\n * storage supportedTokens mapping.\n *\n * @param addrs The array of addresses of the tokens.\n * @param toggles The array of flags indicating whether\n * the corresponding token is supported or not.\n * */\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(addrs.length == toggles.length, \"count mismatch\");\n\n for (uint256 i = 0; i < addrs.length; i++) {\n supportedTokens[addrs[i]] = toggles[i];\n\n emit SetSupportedTokens(msg.sender, addrs[i], toggles[i]);\n }\n }\n\n /**\n * @notice Set the value of lendingFeePercent storage variable.\n *\n * @param newValue The new value for lendingFeePercent.\n * */\n function setLendingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = lendingFeePercent;\n lendingFeePercent = newValue;\n\n emit SetLendingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of tradingFeePercent storage variable.\n *\n * @param newValue The new value for tradingFeePercent.\n * */\n function setTradingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = tradingFeePercent;\n tradingFeePercent = newValue;\n\n emit SetTradingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of borrowingFeePercent storage variable.\n *\n * @param newValue The new value for borrowingFeePercent.\n * */\n function setBorrowingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = borrowingFeePercent;\n borrowingFeePercent = newValue;\n\n emit SetBorrowingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of swapExtrernalFeePercent storage variable\n *\n * @param newValue the new value for swapExternalFeePercent\n */\n function setSwapExternalFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = swapExtrernalFeePercent;\n swapExtrernalFeePercent = newValue;\n\n emit SetSwapExternalFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateFeePercent storage variable.\n *\n * @param newValue The new value for affiliateFeePercent.\n * */\n function setAffiliateFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateFeePercent;\n affiliateFeePercent = newValue;\n\n emit SetAffiliateFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateTradingTokenFeePercent storage variable.\n *\n * @param newValue The new value for affiliateTradingTokenFeePercent.\n * */\n function setAffiliateTradingTokenFeePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateTradingTokenFeePercent;\n affiliateTradingTokenFeePercent = newValue;\n\n emit SetAffiliateTradingTokenFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of liquidationIncentivePercent storage variable.\n *\n * @param newValue The new value for liquidationIncentivePercent.\n * */\n function setLiquidationIncentivePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = liquidationIncentivePercent;\n liquidationIncentivePercent = newValue;\n\n emit SetLiquidationIncentivePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of the maximum swap spread.\n *\n * @param newValue The new value for maxDisagreement.\n * */\n function setMaxDisagreement(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n maxDisagreement = newValue;\n }\n\n /**\n * @notice Set the value of the maximum source buffer.\n *\n * @dev To avoid rounding issues on the swap rate a small buffer is implemented.\n *\n * @param newValue The new value for the maximum source buffer.\n * */\n function setSourceBuffer(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n sourceBuffer = newValue;\n }\n\n /**\n * @notice Set the value of the swap size limit.\n *\n * @param newValue The new value for the maximum swap size.\n * */\n function setMaxSwapSize(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n uint256 oldValue = maxSwapSize;\n maxSwapSize = newValue;\n\n emit SetMaxSwapSize(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the address of the feesController instance.\n *\n * @dev The fee sharing proxy must be the feesController of the\n * protocol contract. This allows the fee sharing proxy\n * to withdraw the fees.\n *\n * @param newController The new address of the feesController.\n * */\n function setFeesController(address newController) external onlyAdminOrOwner whenNotPaused {\n address oldController = feesController;\n feesController = newController;\n\n emit SetFeesController(msg.sender, oldController, newController);\n }\n\n /**\n * @notice Set the pauser address of sovryn protocol.\n *\n * only pauser or owner can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Get pauser address.\n *\n *\n * @return pauser address.\n */\n function getPauser() external view returns (address) {\n return pauser;\n }\n\n /*\n * @notice Set the admin address of sovryn protocol.\n *\n * only owner can perform this action.\n *\n * @param newAdmin The new address of the admin.\n * */\n function setAdmin(address newAdmin) external onlyOwner {\n emit SetAdmin(msg.sender, admin, newAdmin);\n admin = newAdmin;\n }\n\n /**\n * @dev Get admin address.\n *\n *\n * @return admin address.\n */\n function getAdmin() external view returns (address) {\n return admin;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * from three sources: lending, trading and borrowing.\n * The fees (except SOV) will be converted to wRBTC.\n * For SOV, it will be deposited directly to feeSharingCollector from the protocol.\n *\n * @param tokens The array of address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n whenNotPaused\n returns (uint256 totalWRBTCWithdrawn)\n {\n require(msg.sender == feesController, \"unauthorized\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n uint256 lendingBalance = lendingFeeTokensHeld[tokens[i]];\n if (lendingBalance > 0) {\n lendingFeeTokensHeld[tokens[i]] = 0;\n lendingFeeTokensPaid[tokens[i]] = lendingFeeTokensPaid[tokens[i]].add(\n lendingBalance\n );\n }\n\n uint256 tradingBalance = tradingFeeTokensHeld[tokens[i]];\n if (tradingBalance > 0) {\n tradingFeeTokensHeld[tokens[i]] = 0;\n tradingFeeTokensPaid[tokens[i]] = tradingFeeTokensPaid[tokens[i]].add(\n tradingBalance\n );\n }\n\n uint256 borrowingBalance = borrowingFeeTokensHeld[tokens[i]];\n if (borrowingBalance > 0) {\n borrowingFeeTokensHeld[tokens[i]] = 0;\n borrowingFeeTokensPaid[tokens[i]] = borrowingFeeTokensPaid[tokens[i]].add(\n borrowingBalance\n );\n }\n\n uint256 tempAmount = lendingBalance.add(tradingBalance).add(borrowingBalance);\n\n if (tempAmount == 0) {\n continue;\n }\n\n uint256 amountConvertedToWRBTC;\n if (tokens[i] == address(sovTokenAddress)) {\n IERC20(tokens[i]).approve(feesController, tempAmount);\n IFeeSharingCollector(feesController).transferTokens(\n address(sovTokenAddress),\n uint96(tempAmount)\n );\n amountConvertedToWRBTC = 0;\n } else {\n if (tokens[i] == address(wrbtcToken)) {\n amountConvertedToWRBTC = tempAmount;\n\n IERC20(address(wrbtcToken)).safeTransfer(receiver, amountConvertedToWRBTC);\n } else {\n IERC20(tokens[i]).approve(protocolAddress, tempAmount);\n\n (amountConvertedToWRBTC, ) = ProtocolSwapExternalInterface(protocolAddress)\n .swapExternal(\n tokens[i], // source token address\n address(wrbtcToken), // dest token address\n feesController, // set feeSharingCollector as receiver\n protocolAddress, // protocol as the sender\n tempAmount, // source token amount\n 0, // reqDestToken\n 0, // minReturn\n \"\" // loan data bytes\n );\n\n /// Will revert if disagreement found.\n IPriceFeeds(priceFeeds).checkPriceDisagreement(\n tokens[i],\n address(wrbtcToken),\n tempAmount,\n amountConvertedToWRBTC,\n maxDisagreement\n );\n }\n\n totalWRBTCWithdrawn = totalWRBTCWithdrawn.add(amountConvertedToWRBTC);\n }\n\n emit WithdrawFees(\n msg.sender,\n tokens[i],\n receiver,\n lendingBalance,\n tradingBalance,\n borrowingBalance,\n amountConvertedToWRBTC\n );\n }\n\n return totalWRBTCWithdrawn;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from lending operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = lendingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n lendingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n lendingFeeTokensPaid[token] = lendingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawLendingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from trading operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = tradingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n tradingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n tradingFeeTokensPaid[token] = tradingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawTradingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from borrowing operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = borrowingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n borrowingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n borrowingFeeTokensPaid[token] = borrowingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawBorrowingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The owner calls this function to withdraw protocol tokens.\n *\n * @dev Wrapper for ProtocolTokenUser::_withdrawProtocolToken internal function.\n *\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of tokens to get.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n onlyAdminOrOwner\n whenNotPaused\n returns (address, bool)\n {\n return _withdrawProtocolToken(receiver, amount);\n }\n\n /**\n * @notice The owner calls this function to deposit protocol tokens.\n *\n * @param amount The tokens of fees to send.\n * */\n function depositProtocolToken(uint256 amount) external onlyAdminOrOwner whenNotPaused {\n /// @dev Update local balance\n protocolTokenHeld = protocolTokenHeld.add(amount);\n\n /// @dev Send the tokens\n IERC20(protocolTokenAddress).safeTransferFrom(msg.sender, address(this), amount);\n }\n\n /**\n * @notice Get a list of loan pools.\n *\n * @param start The offset.\n * @param count The limit.\n *\n * @return The array of loan pools.\n * */\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory)\n {\n return loanPoolsSet.enumerate(start, count);\n }\n\n /**\n * @notice Check whether a token is a pool token.\n *\n * @dev By querying its underlying token.\n *\n * @param loanPool The token address to check.\n * */\n function isLoanPool(address loanPool) external view returns (bool) {\n return loanPoolToUnderlying[loanPool] != address(0);\n }\n\n /**\n * @notice Set the contract registry address of the SovrynSwap network.\n *\n * @param registryAddress the address of the registry contract.\n * */\n function setSovrynSwapContractRegistryAddress(address registryAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(registryAddress), \"registryAddress not a contract\");\n\n address oldSovrynSwapContractRegistryAddress = sovrynSwapContractRegistryAddress;\n sovrynSwapContractRegistryAddress = registryAddress;\n\n emit SetSovrynSwapContractRegistryAddress(\n msg.sender,\n oldSovrynSwapContractRegistryAddress,\n sovrynSwapContractRegistryAddress\n );\n }\n\n /**\n * @notice Set the wrBTC contract address.\n *\n * @param wrbtcTokenAddress The address of the wrBTC contract.\n * */\n function setWrbtcToken(address wrbtcTokenAddress) external onlyAdminOrOwner whenNotPaused {\n require(Address.isContract(wrbtcTokenAddress), \"wrbtcTokenAddress not a contract\");\n\n address oldwrbtcToken = address(wrbtcToken);\n wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n emit SetWrbtcToken(msg.sender, oldwrbtcToken, wrbtcTokenAddress);\n }\n\n /**\n * @notice Set the protocol token contract address.\n *\n * @param _protocolTokenAddress The address of the protocol token contract.\n * */\n function setProtocolTokenAddress(address _protocolTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n\n address oldProtocolTokenAddress = protocolTokenAddress;\n protocolTokenAddress = _protocolTokenAddress;\n\n emit SetProtocolTokenAddress(msg.sender, oldProtocolTokenAddress, _protocolTokenAddress);\n }\n\n /**\n * @notice Set rollover base reward. It should be denominated in wrBTC.\n *\n * @param baseRewardValue The base reward.\n * */\n function setRolloverBaseReward(uint256 baseRewardValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(baseRewardValue > 0, \"Base reward is zero\");\n\n uint256 oldValue = rolloverBaseReward;\n rolloverBaseReward = baseRewardValue;\n\n emit SetRolloverBaseReward(msg.sender, oldValue, rolloverBaseReward);\n }\n\n /**\n * @notice Set the fee rebate percent.\n *\n * @param rebatePercent The fee rebate percent.\n * */\n function setRebatePercent(uint256 rebatePercent) external onlyAdminOrOwner whenNotPaused {\n require(rebatePercent <= 10**20, \"Fee rebate is too high\");\n\n uint256 oldRebatePercent = feeRebatePercent;\n feeRebatePercent = rebatePercent;\n\n emit SetRebatePercent(msg.sender, oldRebatePercent, rebatePercent);\n }\n\n /**\n * @notice Set the special fee rebate percent for specific pair\n *\n * @param specialRebatesPercent The new special fee rebate percent.\n * */\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external onlyAdminOrOwner whenNotPaused {\n // Set max special rebates to 1000%\n require(specialRebatesPercent <= 1000e18, \"Special fee rebate is too high\");\n\n uint256 oldSpecialRebatesPercent = specialRebates[sourceToken][destToken];\n specialRebates[sourceToken][destToken] = specialRebatesPercent;\n\n emit SetSpecialRebates(\n msg.sender,\n sourceToken,\n destToken,\n oldSpecialRebatesPercent,\n specialRebatesPercent\n );\n }\n\n /**\n * @notice Get a rebate percent of specific pairs.\n *\n * @param sourceTokenAddress The source of pairs.\n * @param destTokenAddress The dest of pairs.\n *\n * @return The percent rebates of the pairs.\n * */\n function getSpecialRebates(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 specialRebatesPercent)\n {\n return specialRebates[sourceTokenAddress][destTokenAddress];\n }\n\n function getProtocolAddress() external view returns (address) {\n return protocolAddress;\n }\n\n function getSovTokenAddress() external view returns (address) {\n return sovTokenAddress;\n }\n\n function getLockedSOVAddress() external view returns (address) {\n return lockedSOVAddress;\n }\n\n function getFeeRebatePercent() external view returns (uint256) {\n return feeRebatePercent;\n }\n\n function togglePaused(bool paused) external onlyPauserOrOwner {\n require(paused != pause, \"Can't toggle\");\n pause = paused;\n emit TogglePaused(msg.sender, !paused, paused);\n }\n\n function isProtocolPaused() external view returns (bool) {\n return pause;\n }\n\n function getSwapExternalFeePercent() external view returns (uint256) {\n return swapExtrernalFeePercent;\n }\n\n /**\n * @notice Get the basis point of trading rebate rewards.\n *\n * @return The basis point value.\n */\n function getTradingRebateRewardsBasisPoint() external view returns (uint256) {\n return tradingRebateRewardsBasisPoint;\n }\n\n /**\n * @dev Get how much SOV that is dedicated to pay the trading rebate rewards.\n * @notice If SOV balance is less than the fees held, it will return 0.\n *\n * @return total dedicated SOV.\n */\n function getDedicatedSOVRebate() public view returns (uint256) {\n uint256 sovProtocolBalance = IERC20(sovTokenAddress).balanceOf(address(this));\n uint256 sovFees =\n lendingFeeTokensHeld[sovTokenAddress].add(tradingFeeTokensHeld[sovTokenAddress]).add(\n borrowingFeeTokensHeld[sovTokenAddress]\n );\n\n return sovProtocolBalance >= sovFees ? sovProtocolBalance.sub(sovFees) : 0;\n }\n\n /**\n * @notice Set rolloverFlexFeePercent (max value is 1%)\n *\n * @param newRolloverFlexFeePercent uint256 value of new rollover flex fee percentage (0.1 ether = 0.1%)\n */\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newRolloverFlexFeePercent <= 1e18, \"value too high\");\n uint256 oldRolloverFlexFeePercent = rolloverFlexFeePercent;\n rolloverFlexFeePercent = newRolloverFlexFeePercent;\n\n emit SetRolloverFlexFeePercent(\n msg.sender,\n oldRolloverFlexFeePercent,\n newRolloverFlexFeePercent\n );\n }\n\n /**\n * @dev Get default path conversion for pairs.\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address.\n *\n * @return default path of the conversion.\n */\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory)\n {\n return defaultPathConversion[sourceTokenAddress][destTokenAddress];\n }\n\n /**\n * @dev Set default path conversion for pairs.\n *\n * @param defaultPath array of addresses for the default path.\n *\n */\n function setDefaultPathConversion(IERC20[] calldata defaultPath)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address sourceTokenAddress = address(defaultPath[0]);\n address destTokenAddress = address(defaultPath[defaultPath.length - 1]);\n\n uint256 defaultPathLength = defaultPath.length;\n require(defaultPathLength >= 3, \"ERR_PATH_LENGTH\");\n\n for (uint256 i = 0; i < defaultPathLength; i++) {\n require(Address.isContract(address(defaultPath[i])), \"ERR_PATH_NON_CONTRACT_ADDR\");\n }\n\n defaultPathConversion[sourceTokenAddress][destTokenAddress] = defaultPath;\n\n emit SetDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPath\n );\n }\n\n /**\n * @dev Remove the default path conversion for pairs\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address\n */\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(\n defaultPathConversion[sourceTokenAddress][destTokenAddress].length > 0,\n \"DEFAULT_PATH_EMPTY\"\n );\n\n IERC20[] memory defaultPathValue =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n delete defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n emit RemoveDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPathValue\n );\n }\n}\n" + }, + "contracts/modules/SwapsExternal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Swaps External contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to calculate and execute swaps.\n * */\ncontract SwapsExternal is VaultController, SwapsUser, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.swapExternal.selector];\n _setTarget(this.swapExternal.selector, target);\n _setTarget(this.getSwapExpectedReturn.selector, target);\n _setTarget(this.checkPriceDivergence.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"SwapsExternal\");\n }\n\n /**\n * @notice Perform a swap w/ tokens or rBTC as source currency.\n *\n * @dev External wrapper that calls SwapsUser::_swapsCall\n * after turning potential incoming rBTC into wrBTC tokens.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param receiver The address of the recipient account.\n * @param returnToSender The address of the sender account.\n * @param sourceTokenAmount The amount of source tokens.\n * @param requiredDestTokenAmount The amount of required destiny tokens.\n * @param minReturn Minimum amount (position size) in the collateral tokens.\n * @param swapData Additional swap data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes memory swapData\n )\n public\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(sourceTokenAmount != 0, \"sourceTokenAmount == 0\");\n checkPriceDivergence(sourceToken, destToken, sourceTokenAmount, minReturn);\n\n /// @dev Get payed value, be it rBTC or tokenized.\n if (msg.value != 0) {\n if (sourceToken == address(0)) {\n sourceToken = address(wrbtcToken);\n }\n require(sourceToken == address(wrbtcToken), \"sourceToken mismatch\");\n require(msg.value == sourceTokenAmount, \"sourceTokenAmount mismatch\");\n\n /// @dev Update wrBTC balance for this contract.\n wrbtcToken.deposit.value(sourceTokenAmount)();\n } else {\n if (address(this) != msg.sender) {\n IERC20(sourceToken).safeTransferFrom(msg.sender, address(this), sourceTokenAmount);\n }\n }\n\n /// @dev Perform the swap w/ tokens.\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n receiver,\n returnToSender,\n msg.sender /// user\n ],\n [\n sourceTokenAmount, /// minSourceTokenAmount\n sourceTokenAmount, /// maxSourceTokenAmount\n requiredDestTokenAmount\n ],\n 0, /// loanId (not tied to a specific loan)\n false, /// bypassFee\n swapData,\n true // the flag for swapExternal (so that it will use the swapExternalFeePercent)\n );\n\n emit ExternalSwap(\n msg.sender, /// user\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Get the swap expected return value.\n *\n * @dev External wrapper that calls SwapsUser::_swapsExpectedReturn\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n *\n * @return The expected return value.\n * */\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n }\n\n /**\n * @notice Check the slippage based on the swapExpectedReturn.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n * @param minReturn The amount (max slippage) that will be compared to the swapsExpectedReturn.\n *\n */\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view {\n uint256 destTokenAmount = _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n require(destTokenAmount >= minReturn, \"destTokenAmountReceived too low\");\n }\n}\n" + }, + "contracts/modules/SwapsImplSovrynSwapModule.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../swaps/connectors/SwapsImplSovrynSwapLib.sol\";\nimport \"../events/ModulesCommonEvents.sol\";\n\ncontract SwapsImplSovrynSwapModule is State, ModulesCommonEvents {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress =\n logicTargets[this.getSovrynSwapNetworkContract.selector];\n _setTarget(this.getSovrynSwapNetworkContract.selector, target);\n _setTarget(this.getContractHexName.selector, target);\n _setTarget(this.swapsImplExpectedRate.selector, target);\n _setTarget(this.swapsImplExpectedReturn.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"SwapsImplSovrynSwapModule\"\n );\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n return SwapsImplSovrynSwapLib.getContractHexName(source);\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n return SwapsImplSovrynSwapLib.getSovrynSwapNetworkContract(sovrynSwapRegistryAddress);\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return\n SwapsImplSovrynSwapLib.getExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn) {\n return\n SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n}\n" + }, + "contracts/multisig/MultiSigKeyHolders.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/Ownable.sol\";\n\n/**\n * @title Multi Signature Key Holders contract.\n *\n * This contract contains the implementation of functions to add and remove\n * key holders w/ rBTC and BTC addresses.\n * */\ncontract MultiSigKeyHolders is Ownable {\n /* Storage */\n\n uint256 public constant MAX_OWNER_COUNT = 50;\n\n string private constant ERROR_INVALID_ADDRESS = \"Invalid address\";\n string private constant ERROR_INVALID_REQUIRED = \"Invalid required\";\n\n /// Flag and index for Ethereum address.\n mapping(address => Data) private isEthereumAddressAdded;\n\n /// List of Ethereum addresses.\n address[] private ethereumAddresses;\n\n /// Required number of signatures for the Ethereum multisig.\n uint256 public ethereumRequired = 2;\n\n /// Flag and index for Bitcoin address.\n mapping(string => Data) private isBitcoinAddressAdded;\n\n /// List of Bitcoin addresses.\n string[] private bitcoinAddresses;\n\n /// Required number of signatures for the Bitcoin multisig.\n uint256 public bitcoinRequired = 2;\n\n /// Helps removing items from array.\n struct Data {\n bool added;\n uint248 index;\n }\n\n /* Events */\n\n event EthereumAddressAdded(address indexed account);\n event EthereumAddressRemoved(address indexed account);\n event EthereumRequirementChanged(uint256 required);\n event BitcoinAddressAdded(string account);\n event BitcoinAddressRemoved(string account);\n event BitcoinRequirementChanged(uint256 required);\n\n /* Modifiers */\n\n modifier validRequirement(uint256 ownerCount, uint256 _required) {\n require(\n ownerCount <= MAX_OWNER_COUNT &&\n _required <= ownerCount &&\n _required != 0 &&\n ownerCount != 0,\n ERROR_INVALID_REQUIRED\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function addEthereumAddress(address _address) public onlyOwner {\n _addEthereumAddress(_address);\n }\n\n /**\n * @notice Add rBTC addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function _addEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (!isEthereumAddressAdded[_address].added) {\n isEthereumAddressAdded[_address] = Data({\n added: true,\n index: uint248(ethereumAddresses.length)\n });\n ethereumAddresses.push(_address);\n }\n\n emit EthereumAddressAdded(_address);\n }\n\n /**\n * @notice Remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeEthereumAddress(address _address) public onlyOwner {\n _removeEthereumAddress(_address);\n }\n\n /**\n * @notice Remove rBTC addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (isEthereumAddressAdded[_address].added) {\n uint248 index = isEthereumAddressAdded[_address].index;\n if (index != ethereumAddresses.length - 1) {\n ethereumAddresses[index] = ethereumAddresses[ethereumAddresses.length - 1];\n isEthereumAddressAdded[ethereumAddresses[index]].index = index;\n }\n ethereumAddresses.length--;\n delete isEthereumAddressAdded[_address];\n }\n\n emit EthereumAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether rBTC address is a key holder.\n * @param _address The rBTC address to be checked.\n * */\n function isEthereumAddressOwner(address _address) public view returns (bool) {\n return isEthereumAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of rBTC key holders.\n * */\n function getEthereumAddresses() public view returns (address[] memory) {\n return ethereumAddresses;\n }\n\n /**\n * @notice Set flag ethereumRequired to true/false.\n * @param _required The new value of the ethereumRequired flag.\n * */\n function changeEthereumRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(ethereumAddresses.length, _required)\n {\n ethereumRequired = _required;\n emit EthereumRequirementChanged(_required);\n }\n\n /**\n * @notice Add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function addBitcoinAddress(string memory _address) public onlyOwner {\n _addBitcoinAddress(_address);\n }\n\n /**\n * @notice Add bitcoin addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function _addBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (!isBitcoinAddressAdded[_address].added) {\n isBitcoinAddressAdded[_address] = Data({\n added: true,\n index: uint248(bitcoinAddresses.length)\n });\n bitcoinAddresses.push(_address);\n }\n\n emit BitcoinAddressAdded(_address);\n }\n\n /**\n * @notice Remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeBitcoinAddress(string memory _address) public onlyOwner {\n _removeBitcoinAddress(_address);\n }\n\n /**\n * @notice Remove bitcoin addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (isBitcoinAddressAdded[_address].added) {\n uint248 index = isBitcoinAddressAdded[_address].index;\n if (index != bitcoinAddresses.length - 1) {\n bitcoinAddresses[index] = bitcoinAddresses[bitcoinAddresses.length - 1];\n isBitcoinAddressAdded[bitcoinAddresses[index]].index = index;\n }\n bitcoinAddresses.length--;\n delete isBitcoinAddressAdded[_address];\n }\n\n emit BitcoinAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether bitcoin address is a key holder.\n * @param _address The bitcoin address to be checked.\n * */\n function isBitcoinAddressOwner(string memory _address) public view returns (bool) {\n return isBitcoinAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of bitcoin key holders.\n * */\n function getBitcoinAddresses() public view returns (string[] memory) {\n return bitcoinAddresses;\n }\n\n /**\n * @notice Set flag bitcoinRequired to true/false.\n * @param _required The new value of the bitcoinRequired flag.\n * */\n function changeBitcoinRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(bitcoinAddresses.length, _required)\n {\n bitcoinRequired = _required;\n emit BitcoinRequirementChanged(_required);\n }\n\n /**\n * @notice Add rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress the rBTC addresses to be added.\n * @param _bitcoinAddress the bitcoin addresses to be added.\n * */\n function addEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _addEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _addBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n\n /**\n * @notice Remove rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress The rBTC addresses to be removed.\n * @param _bitcoinAddress The bitcoin addresses to be removed.\n * */\n function removeEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _removeEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _removeBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n}\n" + }, + "contracts/openzeppelin/Address.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256('')`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n codehash := extcodehash(account)\n }\n return (codehash != accountHash && codehash != 0x0);\n }\n\n /**\n * @dev Converts an `address` into `address payable`. Note that this is\n * simply a type cast: the actual underlying value is not changed.\n *\n * _Available since v2.4.0._\n */\n function toPayable(address account) internal pure returns (address payable) {\n return address(uint160(account));\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n *\n * _Available since v2.4.0._\n */\n function sendValue(address recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-call-value\n (bool success, ) = recipient.call.value(amount)(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n}\n" + }, + "contracts/openzeppelin/Context.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n // Empty internal constructor, to prevent people from mistakenly deploying\n // an instance of this contract, which should be used via inheritance.\n constructor() internal {}\n\n // solhint-disable-previous-line no-empty-blocks\n\n function _msgSender() internal view returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n" + }, + "contracts/openzeppelin/ERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./Context.sol\";\nimport \"./IERC20_.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20Mintable}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20_ {\n using SafeMath for uint256;\n\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20};\n *\n * Requirements:\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for `sender`'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n _allowances[sender][_msgSender()].sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n _approve(\n _msgSender(),\n spender,\n _allowances[_msgSender()][spender].sub(\n subtractedValue,\n \"ERC20: decreased allowance below zero\"\n )\n );\n return true;\n }\n\n /**\n * @dev Moves tokens `amount` from `sender` to `recipient`.\n *\n * This is internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _balances[sender] = _balances[sender].sub(\n amount,\n \"ERC20: transfer amount exceeds balance\"\n );\n _balances[recipient] = _balances[recipient].add(amount);\n emit Transfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n *\n * This is internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`.`amount` is then deducted\n * from the caller's allowance.\n *\n * See {_burn} and {_approve}.\n */\n function _burnFrom(address account, uint256 amount) internal {\n _burn(account, amount);\n _approve(\n account,\n _msgSender(),\n _allowances[account][_msgSender()].sub(amount, \"ERC20: burn amount exceeds allowance\")\n );\n }\n}\n" + }, + "contracts/openzeppelin/ERC20Detailed.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20_.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n */\ncontract ERC20Detailed is IERC20_ {\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n */\n constructor(\n string memory name,\n string memory symbol,\n uint8 decimals\n ) public {\n _name = name;\n _symbol = symbol;\n _decimals = decimals;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/openzeppelin/IERC20_.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20_ {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/openzeppelin/Initializable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n */\ncontract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(_initializing || !_initialized, \"Initializable: contract is already initialized\");\n\n bool isTopLevelCall = !_initializing;\n if (isTopLevelCall) {\n _initializing = true;\n _initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n _initializing = false;\n }\n }\n}\n" + }, + "contracts/openzeppelin/Ownable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() public view returns (bool) {\n return _msgSender() == _owner;\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public onlyOwner {\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n */\n function _transferOwnership(address newOwner) internal {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n}\n" + }, + "contracts/openzeppelin/PausableOz.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./Ownable.sol\";\n\ncontract PausableOz is Ownable {\n /**\n * @dev Emitted when the pause is triggered by the owner (`account`).\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by the owner (`account`).\n */\n event Unpaused(address account);\n\n bool internal _paused;\n\n constructor() internal {}\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n */\n modifier whenNotPaused() {\n require(!_paused, \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n */\n modifier whenPaused() {\n require(_paused, \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/openzeppelin/ReentrancyGuard.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title Helps contracts guard against reentrancy attacks.\n * @author Remco Bloemen , Eenae \n * @dev If you mark a function `nonReentrant`, you should also\n * mark it `external`.\n */\ncontract ReentrancyGuard {\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n" + }, + "contracts/openzeppelin/SafeERC20.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./SafeMath.sol\";\nimport \"./Address.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\n );\n }\n\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n // solhint-disable-next-line max-line-length\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance =\n token.allowance(address(this), spender).sub(\n value,\n \"SafeERC20: decreased allowance below zero\"\n );\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves.\n\n // A Solidity high level call has three parts:\n // 1. The target address is checked to verify it contains contract code\n // 2. The call itself is made, and success asserted\n // 3. The return value is decoded, which in turn checks the size of the returned data.\n // solhint-disable-next-line max-line-length\n require(address(token).isContract(), \"SafeERC20: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(data);\n require(success, \"SafeERC20: low-level call failed\");\n\n if (returndata.length > 0) {\n // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "contracts/openzeppelin/SafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n *\n * _Available since v2.4.0._\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\n return divCeil(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n\n if (a == 0) {\n return 0;\n }\n uint256 c = ((a - 1) / b) + 1;\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\n return _a < _b ? _a : _b;\n }\n}\n" + }, + "contracts/openzeppelin/SignedSafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title SignedSafeMath\n * @dev Signed math operations with safety checks that revert on error.\n */\nlibrary SignedSafeMath {\n int256 private constant _INT256_MIN = -2**255;\n\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n require(!(a == -1 && b == _INT256_MIN), \"SignedSafeMath: multiplication overflow\");\n\n int256 c = a * b;\n require(c / a == b, \"SignedSafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n require(b != 0, \"SignedSafeMath: division by zero\");\n require(!(b == -1 && a == _INT256_MIN), \"SignedSafeMath: division overflow\");\n\n int256 c = a / b;\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a - b;\n require((b >= 0 && c <= a) || (b < 0 && c > a), \"SignedSafeMath: subtraction overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a + b;\n require((b >= 0 && c >= a) || (b < 0 && c < a), \"SignedSafeMath: addition overflow\");\n\n return c;\n }\n}\n" + }, + "contracts/proxy/modules/interfaces/IFunctionsList.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\ninterface IFunctionsList {\n function getFunctionsList() external pure returns (bytes4[] memory functionSignatures);\n}\n" + }, + "contracts/proxy/modules/interfaces/IModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\n/**\n * ModulesProxyRegistry Interface\n */\n\ncontract IModulesProxyRegistry {\n event AddModule(address indexed moduleAddress);\n event ReplaceModule(address indexed oldAddress, address indexed newAddress);\n event RemoveModule(address indexed moduleAddress);\n event SetModuleFuncImplementation(\n bytes4 indexed _funcSig,\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use ReplaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external;\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl) external;\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external;\n\n /// @notice to disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external;\n\n /// @param _sig function signature to get impmementation address for\n /// @return function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address);\n\n /// @notice verifies if no functions from the module deployed already registered\n /// @param _impl module implementation address to verify\n /// @return true if module can be added\n function canAddModule(address _impl) external view returns (bool);\n\n /// @notice Multiple modules verification if no functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return True if all modules can be added, false otherwise\n function canNotAddModules(address[] calldata _implementations)\n external\n view\n returns (address[] memory modules);\n\n /// @notice used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n );\n}\n" + }, + "contracts/proxy/modules/ModulesProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"./ModulesProxyRegistry.sol\";\n\n/**\n * ModulesProxy serves as a storage processed by a set of logic contracts - modules\n * Modules functions are registered in the contract's slots generated per func sig\n * All the function calls except for own Proxy functions are delegated to\n * the registered functions\n * The ModulesProxy is designed as a universal solution for refactorig contracts\n * reaching a 24K size limit (EIP-170)\n *\n * Upgradability is implemented at a module level to provide consistency\n * It does not allow to replace separate functions - only the whole module\n * meaning that if a module being registered contains other modules function signatures\n * then these modulea should be replaced completely - all the functions should be removed\n * to avoid leftovers or accidental replacements and therefore functional inconsistency.\n *\n * A module is either a new non-overlapping with registered modules\n * or a complete replacement of another registered module\n * in which case all the old module functions are unregistered and then\n * the new module functions are registered\n * There is also a separate function to unregister a module which unregisters all the functions\n * There is no option to unregister a subset of module functions - one should use pausable functionality\n * to achieve this\n */\n\ncontract ModulesProxy is ModulesProxyRegistry {\n // Uncomment for using beforeFallback() hook\n /*\n bytes private constant BEFORE_FALLBACK_SIG = abi.encodeWithSignature(\"beforeFallback()\");\n bytes4 private constant BEFORE_FALLBACK_SIG_BYTES4 = bytes4(keccak256(abi.encodePacked(\"beforeFallback()\")));\n */\n\n /**\n * @notice Fallback function delegates calls to modules.\n * Returns whatever the implementation call returns.\n * Has a hook to execute before delegating calls\n * To activate register a module with beforeFallback() function\n */\n function() external payable {\n /*\n // Commented to safe gas by default\n // Uncomment for using beforeFallback() hook \n // Implement and register beforeFallback() function in a module\n address beforeFallback = _getFuncImplementation(BEFORE_FALLBACK_SIG_BYTES4);\n if (beforeFallback != address(0)) {\n (bool success, ) = beforeFallback.delegatecall(bytes(0x39b0111a)); // abi.encodeWithSignature(\"beforeFallback()\")\n require(success, \"ModulesProxy::fallback: beforeFallback() fail\"); //MP02\n }\n */\n\n address target = _getFuncImplementation(msg.sig);\n require(target != address(0), \"ModulesProxy:target module not registered\"); // MP03\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/modules/ModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"../../utils/Utils.sol\";\nimport \"../../utils/ProxyOwnable.sol\";\nimport \"../modules/interfaces/IFunctionsList.sol\";\nimport \"../modules/interfaces/IModulesProxyRegistry.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * ModulesProxyRegistry provides modules registration/removing/replacing functionality to ModulesProxy\n * Designed to be inherited\n */\n\ncontract ModulesProxyRegistry is IModulesProxyRegistry, ProxyOwnable {\n using Address for address;\n\n bytes32 internal constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n\n ///@notice Constructor is internal to make contract abstract\n constructor() internal {\n // abstract\n }\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use replaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external onlyProxyOwner {\n _addModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external onlyProxyOwner {\n _addModules(_implementations);\n }\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl)\n external\n onlyProxyOwner\n {\n _replaceModule(_oldModuleImpl, _newModuleImpl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external onlyProxyOwner {\n require(\n _implementationsFrom.length == _implementationsTo.length,\n \"ModulesProxyRegistry::replaceModules: arrays sizes must be equal\"\n ); //MR10\n\n // because the order of addresses is arbitrary, all modules are removed first to avoid collisions\n _removeModules(_implementationsFrom);\n _addModules(_implementationsTo);\n }\n\n /// @notice To disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external onlyProxyOwner {\n _removeModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external onlyProxyOwner {\n _removeModules(_implementations);\n }\n\n /// @param _sig Function signature to get impmementation address for\n /// @return Function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address) {\n return _getFuncImplementation(_sig);\n }\n\n /// @notice Verifies if no functions from the module already registered\n /// @param _impl Module implementation address to verify\n /// @return True if module can be added\n function canAddModule(address _impl) external view returns (bool) {\n return _canAddModule(_impl);\n }\n\n /// @notice Multiple modules verification if there are functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return addresses of registered modules\n function canNotAddModules(address[] memory _implementations)\n public\n view\n returns (address[] memory)\n {\n for (uint256 i = 0; i < _implementations.length; i++) {\n if (_canAddModule(_implementations[i])) {\n delete _implementations[i];\n }\n }\n return _implementations;\n }\n\n /// @notice Used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return Clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n )\n {\n require(\n _newModule.isContract(),\n \"ModulesProxyRegistry::checkClashingFuncSelectors: address is not a contract\"\n ); //MR06\n bytes4[] memory newModuleFunctions = IFunctionsList(_newModule).getFunctionsList();\n bytes4[] memory proxyRegistryFunctions = _getFunctionsList(); //registry functions list\n uint256 clashingProxyRegistryFuncsSize;\n uint256 clashingArraySize;\n uint256 clashingArrayIndex;\n uint256 clashingRegistryArrayIndex;\n\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0) && funcImpl != _newModule) {\n clashingArraySize++;\n } else if (_isFuncClashingWithProxyFunctions(newModuleFunctions[i]))\n clashingProxyRegistryFuncsSize++;\n }\n clashingModules = new address[](clashingArraySize);\n clashingModulesFuncSelectors = new bytes4[](clashingArraySize);\n clashingProxyRegistryFuncSelectors = new bytes4[](clashingProxyRegistryFuncsSize);\n\n if (clashingArraySize == 0 && clashingProxyRegistryFuncsSize == 0)\n //return empty arrays\n return (\n clashingModules,\n clashingModulesFuncSelectors,\n clashingProxyRegistryFuncSelectors\n );\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0)) {\n clashingModules[clashingArrayIndex] = funcImpl;\n clashingModulesFuncSelectors[clashingArrayIndex] = newModuleFunctions[i];\n clashingArrayIndex++;\n }\n for (uint256 j = 0; j < proxyRegistryFunctions.length; j++) {\n //ModulesProxyRegistry has a clashing function selector\n if (proxyRegistryFunctions[j] == newModuleFunctions[i]) {\n clashingProxyRegistryFuncSelectors[\n clashingRegistryArrayIndex\n ] = proxyRegistryFunctions[j];\n clashingRegistryArrayIndex++;\n }\n }\n }\n }\n\n /// Verifies the deployed contract address is a registered module contract\n /// @param _impl deployment address to verify\n /// @return true if _impl address is a registered module\n function isModuleRegistered(address _impl) external view returns (bool) {\n return _getFirstRegisteredModuleAddress(_impl) == _impl;\n }\n\n /****************** INTERNAL FUNCTIONS ******************/\n\n function _getFirstRegisteredModuleAddress(address _impl) internal view returns (address) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_getRegisteredModuleAddress: address is not a contract\"\n );\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n address _moduleImpl = _getFuncImplementation(functions[i]);\n if (_moduleImpl != address(0)) {\n return (_moduleImpl);\n }\n }\n return address(0);\n }\n\n function _getFuncImplementation(bytes4 _sig) internal view returns (address) {\n //TODO: add querying Registry for logic address and then delegate call to it OR use proxy memory slots like this:\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n address implementation;\n assembly {\n implementation := sload(key)\n }\n return implementation;\n }\n\n function _addModule(address _impl) internal {\n require(_impl.isContract(), \"ModulesProxyRegistry::_addModule: address is not a contract\"); //MR01\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n require(\n _getFuncImplementation(functions[i]) == address(0),\n \"ModulesProxyRegistry::_addModule: function already registered - use replaceModule function\"\n ); //MR02\n require(functions[i] != bytes4(0), \"does not allow empty function id\"); // MR03\n require(\n !_isFuncClashingWithProxyFunctions(functions[i]),\n \"ModulesProxyRegistry::_addModule: has a function with the same signature\"\n ); //MR09\n _setModuleFuncImplementation(functions[i], _impl);\n }\n emit AddModule(_impl);\n }\n\n function _addModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _addModule(_implementations[i]);\n }\n }\n\n function _removeModule(address _impl) internal onlyProxyOwner {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_removeModule: address is not a contract\"\n ); //MR07\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n _setModuleFuncImplementation(functions[i], address(0));\n\n emit RemoveModule(_impl);\n }\n\n function _removeModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _removeModule(_implementations[i]);\n }\n }\n\n function _replaceModule(address _oldModuleImpl, address _newModuleImpl) internal {\n if (_oldModuleImpl != _newModuleImpl) {\n require(\n _newModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _newModuleImpl is not a contract\"\n ); //MR03\n require(\n _oldModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _oldModuleImpl is not a contract\"\n ); //MR04\n _removeModule(_oldModuleImpl);\n _addModule(_newModuleImpl);\n\n emit ReplaceModule(_oldModuleImpl, _newModuleImpl);\n }\n }\n\n function _setModuleFuncImplementation(bytes4 _sig, address _impl) internal {\n emit SetModuleFuncImplementation(_sig, _getFuncImplementation(_sig), _impl);\n\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n assembly {\n sstore(key, _impl)\n }\n }\n\n function _isFuncClashingWithProxyFunctions(bytes4 _sig) internal pure returns (bool) {\n bytes4[] memory functionList = _getFunctionsList();\n for (uint256 i = 0; i < functionList.length; i++) {\n if (_sig == functionList[i])\n //ModulesProxyRegistry has function with the same id\n return true;\n }\n return false;\n }\n\n function _canAddModule(address _impl) internal view returns (bool) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_canAddModule: address is not a contract\"\n ); //MR06\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n if (_getFuncImplementation(functions[i]) != address(0)) return (false);\n return true;\n }\n\n function _getFunctionsList() internal pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](13);\n functionList[0] = this.getFuncImplementation.selector;\n functionList[1] = this.addModule.selector;\n functionList[2] = this.addModules.selector;\n functionList[3] = this.removeModule.selector;\n functionList[4] = this.removeModules.selector;\n functionList[5] = this.replaceModule.selector;\n functionList[6] = this.replaceModules.selector;\n functionList[7] = this.canAddModule.selector;\n functionList[8] = this.canNotAddModules.selector;\n functionList[9] = this.setProxyOwner.selector;\n functionList[10] = this.getProxyOwner.selector;\n functionList[11] = this.checkClashingFuncSelectors.selector;\n functionList[12] = this.isModuleRegistered.selector;\n return functionList;\n }\n}\n" + }, + "contracts/proxy/Proxy.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base Proxy contract.\n * @notice The proxy performs delegated calls to the contract implementation\n * it is pointing to. This way upgradable contracts are possible on blockchain.\n *\n * Delegating proxy contracts are widely used for both upgradeability and gas\n * savings. These proxies rely on a logic contract (also known as implementation\n * contract or master copy) that is called using delegatecall. This allows\n * proxies to keep a persistent state (storage and balance) while the code is\n * delegated to the logic contract.\n *\n * Proxy contract is meant to be inherited and its internal functions\n * _setImplementation and _setProxyOwner to be called when upgrades become\n * neccessary.\n *\n * The loan token (iToken) contract as well as the protocol contract act as\n * proxies, delegating all calls to underlying contracts. Therefore, if you\n * want to interact with them using web3, you need to use the ABIs from the\n * contracts containing the actual logic or the interface contract.\n * ABI for LoanToken contracts: LoanTokenLogicStandard\n * ABI for Protocol contract: ISovryn\n *\n * @dev UpgradableProxy is the contract that inherits Proxy and wraps these\n * functions.\n * */\ncontract Proxy {\n bytes32 private constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);\n event ImplementationChanged(\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /**\n * @notice Set sender as an owner.\n * */\n constructor() public {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @notice Throw error if called not by an owner.\n * */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Proxy:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the implementation.\n * @param _implementation Address of the implementation.\n * */\n function _setImplementation(address _implementation) internal {\n require(_implementation != address(0), \"Proxy::setImplementation: invalid address\");\n emit ImplementationChanged(getImplementation(), _implementation);\n\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n sstore(key, _implementation)\n }\n }\n\n /**\n * @notice Return address of the implementation.\n * @return Address of the implementation.\n * */\n function getImplementation() public view returns (address _implementation) {\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n _implementation := sload(key)\n }\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"Proxy::setProxyOwner: invalid address\");\n emit OwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Return address of the owner.\n * @return Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n address implementation = getImplementation();\n require(implementation != address(0), \"Proxy::(): implementation not found\");\n\n assembly {\n let pointer := mload(0x40)\n calldatacopy(pointer, 0, calldatasize)\n let result := delegatecall(gas, implementation, pointer, calldatasize, 0, 0)\n let size := returndatasize\n returndatacopy(pointer, 0, size)\n\n switch result\n case 0 {\n revert(pointer, size)\n }\n default {\n return(pointer, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/UpgradableProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Proxy.sol\";\n\n/**\n * @title Upgradable Proxy contract.\n * @notice A disadvantage of the immutable ledger is that nobody can change the\n * source code of a smart contract after it’s been deployed. In order to fix\n * bugs or introduce new features, smart contracts need to be upgradable somehow.\n *\n * Although it is not possible to upgrade the code of an already deployed smart\n * contract, it is possible to set-up a proxy contract architecture that will\n * allow to use new deployed contracts as if the main logic had been upgraded.\n *\n * A proxy architecture pattern is such that all message calls go through a\n * Proxy contract that will redirect them to the latest deployed contract logic.\n * To upgrade, a new version of the contract is deployed, and the Proxy is\n * updated to reference the new contract address.\n * */\ncontract UpgradableProxy is Proxy {\n /**\n * @notice Set address of the implementation.\n * @dev Wrapper for _setImplementation that exposes the function\n * as public for owner to be able to set a new version of the\n * contract as current pointing implementation.\n * @param _implementation Address of the implementation.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n _setImplementation(_implementation);\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n}\n" + }, + "contracts/reentrancy/Mutex.sol": { + "content": "pragma solidity ^0.5.17;\n\n/*\n * @title Global Mutex contract\n *\n * @notice A mutex contract that allows only one function to be called at a time out\n * of a large set of functions. *Anyone* in the network can freely use any instance\n * of this contract to add a universal mutex to any function in any contract.\n */\ncontract Mutex {\n /*\n * We use an uint to store the mutex state.\n */\n uint256 public value;\n\n /*\n * @notice Increment the mutex state and return the new value.\n *\n * @dev This is the function that will be called by anyone to change the mutex\n * state. It is purposely not protected by any access control\n */\n function incrementAndGetValue() external returns (uint256) {\n /*\n * increment value using unsafe math. This is safe because we are\n * pretty certain no one will ever increment the value 2^256 times\n * in a single transaction.\n */\n return ++value;\n }\n}\n" + }, + "contracts/reentrancy/SharedReentrancyGuard.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Mutex.sol\";\n\n/*\n * @title Abstract contract for shared reentrancy guards\n *\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\n * that there's no reentrancy between *any* functions marked with the modifier.\n *\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\n */\ncontract SharedReentrancyGuard {\n /*\n * This is the address of the mutex contract that will be used as the\n * reentrancy guard.\n *\n * The address is hardcoded to avoid changing the memory layout of\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\n * because the Mutex contract is always deployed to the same address, with the\n * same method used in the deployment of ERC1820Registry.\n */\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\n\n /*\n * This is the modifier that will be used to protect functions from\n * reentrancy. It will call the mutex contract to increment the mutex\n * state and then revert if the mutex state was changed by another\n * nested call.\n */\n modifier globallyNonReentrant() {\n uint256 previous = MUTEX.incrementAndGetValue();\n\n _;\n\n /*\n * If the mutex state was changed by a nested function call, then\n * the value of the state variable will be different from the previous value.\n */\n require(previous == MUTEX.value(), \"reentrancy violation\");\n }\n}\n" + }, + "contracts/rsk/RSKAddrValidator.sol": { + "content": "// SPDX-License-Identifier:MIT\npragma solidity ^0.5.17;\n\nlibrary RSKAddrValidator {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n * */\n function checkPKNotZero(address addr) internal pure returns (bool) {\n return (addr != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && addr != address(0));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key.\n * */\n function safeEquals(address addr1, address addr2) internal pure returns (bool) {\n return (addr1 == addr2 &&\n addr1 != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\n addr1 != address(0));\n }\n}\n" + }, + "contracts/swaps/connectors/interfaces/IContractRegistry.sol": { + "content": "pragma solidity 0.5.17;\n\ncontract IContractRegistry {\n function addressOf(bytes32 contractName) public view returns (address);\n}\n" + }, + "contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol": { + "content": "pragma solidity >=0.5.8 <=0.5.17;\n\nimport \"../../../interfaces/IERC20.sol\";\n\ncontract ISovrynSwapNetwork {\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256);\n\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\n\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory);\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwap.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../../core/State.sol\";\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\n\n/**\n * @dev WARNING: This contract is deprecated, all public functions are moved to the protocol modules.\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\ncontract SwapsImplSovrynSwap is State {\n using SafeERC20 for IERC20;\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n constructor() internal {\n // abstract\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destination tokens.\n * @param receiverAddress The address who will received the swap token results\n * @param returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * @param minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * @param maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address receiverAddress,\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n require(\n supportedTokens[sourceTokenAddress] && supportedTokens[destTokenAddress],\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = estimateSourceTokenAmount(\n sourceTokenAddress,\n destTokenAddress,\n requiredDestTokenAmount,\n maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n allowTransfer(sourceTokenAmountUsed, sourceTokenAddress, address(sovrynSwapNetwork));\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n uint256 sourceToDestPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n internalExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n maxSourceTokenAmount,\n sovrynSwapContractRegistryAddress\n );\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > sourceBuffer) buffer = sourceBuffer;\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistryAddress\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * @param sovrynSwapContractRegistry The sovryn swap contract reigstry address.\n * @param defaultPath The default path for specific pairs.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistry,\n IERC20[] memory defaultPath\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistry);\n\n IERC20[] memory path =\n defaultPath.length >= 3\n ? defaultPath\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\nimport \"../../interfaces/ISovryn.sol\";\n\n/**\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\nlibrary SwapsImplSovrynSwapLib {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n struct SwapParams {\n address sourceTokenAddress;\n address destTokenAddress;\n address receiverAddress;\n address returnToSenderAddress;\n uint256 minSourceTokenAmount;\n uint256 maxSourceTokenAmount;\n uint256 requiredDestTokenAmount;\n }\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param params SwapParams struct\n * sourceTokenAddress The address of the source tokens.\n * destTokenAddress The address of the destination tokens.\n * receiverAddress The address who will received the swap token results\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * requiredDestTokenAmount The required amount of destination tokens.\n * */\n function swap(SwapParams memory params)\n public\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(params.sourceTokenAddress != params.destTokenAddress, \"source == dest\");\n\n ISovryn iSovryn = ISovryn(address(this));\n require(\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\n iSovryn.supportedTokens(params.destTokenAddress),\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\n\n IERC20[] memory path =\n _getConversionPath(\n params.sourceTokenAddress,\n params.destTokenAddress,\n sovrynSwapNetwork\n );\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = params.minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (params.requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\n params.sourceTokenAddress,\n params.destTokenAddress,\n params.requiredDestTokenAmount,\n params.maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n params.requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = params.requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n _allowTransfer(\n sourceTokenAmountUsed,\n params.sourceTokenAddress,\n address(sovrynSwapNetwork)\n );\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n params.receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (params.returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(params.sourceTokenAddress).safeTransfer(\n params.returnToSenderAddress,\n params.maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function _allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function _estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n ISovryn iSovryn = ISovryn(address(this));\n uint256 sourceToDestPrecision =\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function getExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function getExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function _getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/testnet/SwapsImplLocal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../../core/State.sol\";\nimport \"../../../openzeppelin/SafeERC20.sol\";\nimport \"../../../feeds/IPriceFeeds.sol\";\nimport \"../../../testhelpers/TestToken.sol\";\n\n/**\n * @title Swaps Implementation Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate calculations.\n * */\ncontract SwapsImplLocal is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Swap two tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address, /*receiverAddress*/\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n\n (uint256 tradeRate, uint256 precision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n if (requiredDestTokenAmount == 0) {\n sourceTokenAmountUsed = minSourceTokenAmount;\n destTokenAmountReceived = minSourceTokenAmount.mul(tradeRate).div(precision);\n } else {\n destTokenAmountReceived = requiredDestTokenAmount;\n sourceTokenAmountUsed = requiredDestTokenAmount.mul(precision).div(tradeRate);\n require(sourceTokenAmountUsed <= minSourceTokenAmount, \"destAmount too great\");\n }\n\n TestToken(sourceTokenAddress).burn(address(this), sourceTokenAmountUsed);\n TestToken(destTokenAddress).mint(address(this), destTokenAmountReceived);\n\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Calculate the expected price rate of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n *\n * @return precision The expected price rate.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * @notice Calculate the expected return of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n * @param defaultPath defaultPath for swap.\n *\n * @return precision The expected return.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused,\n IERC20[] memory defaultPath\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n}\n" + }, + "contracts/swaps/SwapsUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../mixins/FeesHelper.sol\";\nimport \"./connectors/SwapsImplSovrynSwapLib.sol\";\n\n/**\n * @title Perform token swaps for loans and trades.\n * */\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\n /**\n * @notice Internal loan swap.\n *\n * @param loanId The ID of the loan.\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of destination tokens.\n * @param user The user address.\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * @param bypassFee To bypass or not the fee.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived\n * @return sourceTokenAmountUsed\n * @return sourceToDestSwapRate\n * */\n function _loanSwap(\n bytes32 loanId,\n address sourceToken,\n address destToken,\n address user,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount,\n bool bypassFee,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 sourceToDestSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n address(this), // receiver\n address(this), // returnToSender\n user\n ],\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\n loanId,\n bypassFee,\n loanDataBytes,\n false // swap external flag, set to false so that it will use the tradingFeePercent\n );\n\n /// Will revert if swap size too large.\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\n\n /// Will revert if disagreement found.\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived,\n maxDisagreement\n );\n\n emit LoanSwap(\n loanId,\n sourceToken,\n destToken,\n user,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Wrapper for _swapsCall_internal function.\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n * @param loanId The Id of the associated loan.\n * @param miscBool True/false to bypassFee.\n * @param loanDataBytes Additional loan data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall(\n address[5] memory addrs,\n uint256[3] memory vals,\n bytes32 loanId,\n bool miscBool, /// bypassFee\n bytes memory loanDataBytes,\n bool isSwapExternal\n ) internal returns (uint256, uint256) {\n /// addrs[0]: sourceToken\n /// addrs[1]: destToken\n /// addrs[2]: receiver\n /// addrs[3]: returnToSender\n /// addrs[4]: user\n /// vals[0]: minSourceTokenAmount\n /// vals[1]: maxSourceTokenAmount\n /// vals[2]: requiredDestTokenAmount\n\n require(vals[0] != 0 || vals[1] != 0, \"min or max source token amount needs to be set\");\n\n if (vals[1] == 0) {\n vals[1] = vals[0];\n }\n require(vals[0] <= vals[1], \"sourceAmount larger than max\");\n\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n\n uint256 tradingFee;\n if (!miscBool) {\n /// bypassFee\n if (vals[2] == 0) {\n /// condition: vals[0] will always be used as sourceAmount\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[0]);\n } else {\n tradingFee = _getTradingFee(vals[0]);\n }\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId,\n addrs[0], /// sourceToken (feeToken)\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n vals[0] = vals[0].sub(tradingFee);\n }\n } else {\n /// Condition: unknown sourceAmount will be used.\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[2]);\n } else {\n tradingFee = _getTradingFee(vals[2]);\n }\n\n if (tradingFee != 0) {\n vals[2] = vals[2].add(tradingFee);\n }\n }\n }\n\n require(loanDataBytes.length == 0, \"invalid state\");\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\n\n if (vals[2] == 0) {\n /// There's no minimum destTokenAmount, but all of vals[0]\n /// (minSourceTokenAmount) must be spent.\n require(sourceTokenAmountUsed == vals[0], \"swap too large to fill\");\n\n if (tradingFee != 0) {\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\n }\n } else {\n /// There's a minimum destTokenAmount required, but\n /// sourceTokenAmountUsed won't be greater\n /// than vals[1] (maxSourceTokenAmount)\n require(sourceTokenAmountUsed <= vals[1], \"swap fill too large\");\n require(destTokenAmountReceived >= vals[2], \"insufficient swap liquidity\");\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId, /// loanId,\n addrs[1], /// destToken (feeToken)\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\n }\n }\n\n return (destTokenAmountReceived, sourceTokenAmountUsed);\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Calls swapsImpl::internalSwap\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\n internal\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n SwapsImplSovrynSwapLib.SwapParams memory swapParams;\n\n swapParams.sourceTokenAddress = addrs[0];\n swapParams.destTokenAddress = addrs[1];\n swapParams.receiverAddress = addrs[2];\n swapParams.returnToSenderAddress = addrs[3];\n swapParams.minSourceTokenAmount = vals[0];\n swapParams.maxSourceTokenAmount = vals[1];\n swapParams.requiredDestTokenAmount = vals[2];\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = SwapsImplSovrynSwapLib.swap(swapParams);\n }\n\n /**\n * @notice Calculate expected amount of destination tokens.\n *\n * @dev Calls swapsImpl::internalExpectedReturn\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destination tokens.\n * @param sourceTokenAmount The amount of the source tokens.\n *\n * @param destTokenAmount The amount of destination tokens.\n * */\n function _swapsExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) internal view returns (uint256 destTokenAmount) {\n destTokenAmount = SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceToken,\n destToken,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Verify that the amount of tokens are under the swap limit.\n *\n * @dev Calls priceFeeds::amountInEth\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n * */\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\n uint256 _maxSwapSize = maxSwapSize;\n if (_maxSwapSize != 0) {\n uint256 amountInEth;\n if (tokenAddress == address(wrbtcToken)) {\n amountInEth = amount;\n } else {\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\n }\n require(amountInEth <= _maxSwapSize, \"swap too large\");\n }\n }\n}\n" + }, + "contracts/testhelpers/FlashLoanerTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n// \"SPDX-License-Identifier: Apache-2.0\"\n\nimport \"../interfaces/IERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./ITokenFlashLoanTest.sol\";\n\ncontract FlashLoanerTest is Ownable {\n function initiateFlashLoanTest(\n address loanToken,\n address iToken,\n uint256 flashLoanAmount\n ) internal returns (bytes memory success) {\n ITokenFlashLoanTest iTokenContract = ITokenFlashLoanTest(iToken);\n return\n iTokenContract.flashBorrow(\n flashLoanAmount,\n address(this),\n address(this),\n \"\",\n abi.encodeWithSignature(\n \"executeOperation(address,address,uint256)\",\n loanToken,\n iToken,\n flashLoanAmount\n )\n );\n }\n\n function repayFlashLoan(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) internal {\n IERC20(loanToken).transfer(iToken, loanAmount);\n }\n\n function executeOperation(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) external returns (bytes memory success) {\n emit BalanceOf(IERC20(loanToken).balanceOf(address(this)));\n emit ExecuteOperation(loanToken, iToken, loanAmount);\n repayFlashLoan(loanToken, iToken, loanAmount);\n return bytes(\"1\");\n }\n\n function doStuffWithFlashLoan(\n address token,\n address iToken,\n uint256 amount\n ) external onlyOwner {\n bytes memory result;\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n result = initiateFlashLoanTest(token, iToken, amount);\n\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n // after loan checks and what not.\n if (hashCompareWithLengthCheck(bytes(\"1\"), result)) {\n revert(\"failed executeOperation\");\n }\n }\n\n function hashCompareWithLengthCheck(bytes memory a, bytes memory b)\n internal\n pure\n returns (bool)\n {\n if (a.length != b.length) {\n return false;\n } else {\n return keccak256(a) == keccak256(b);\n }\n }\n\n event ExecuteOperation(address loanToken, address iToken, uint256 loanAmount);\n\n event BalanceOf(uint256 balance);\n}\n" + }, + "contracts/testhelpers/interfaces/IERC1820Registry.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the global ERC1820 Registry, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register\n * implementers for interfaces in this registry, as well as query support.\n *\n * Implementers may be shared by multiple accounts, and can also implement more\n * than a single interface for each account. Contracts can implement interfaces\n * for themselves, but externally-owned accounts (EOA) must delegate this to a\n * contract.\n *\n * {IERC165} interfaces can also be queried via the registry.\n *\n * For an in-depth explanation and source code analysis, see the EIP text.\n */\ninterface IERC1820Registry {\n /**\n * @dev Sets `newManager` as the manager for `account`. A manager of an\n * account is able to set interface implementers for it.\n *\n * By default, each account is its own manager. Passing a value of `0x0` in\n * `newManager` will reset the manager to this initial state.\n *\n * Emits a {ManagerChanged} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n */\n function setManager(address account, address newManager) external;\n\n /**\n * @dev Returns the manager for `account`.\n *\n * See {setManager}.\n */\n function getManager(address account) external view returns (address);\n\n /**\n * @dev Sets the `implementer` contract as `account`'s implementer for\n * `interfaceHash`.\n *\n * `account` being the zero address is an alias for the caller's address.\n * The zero address can also be used in `implementer` to remove an old one.\n *\n * See {interfaceHash} to learn how these are created.\n *\n * Emits an {InterfaceImplementerSet} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not\n * end in 28 zeroes).\n * - `implementer` must implement {IERC1820Implementer} and return true when\n * queried for support, unless `implementer` is the caller. See\n * {IERC1820Implementer-canImplementInterfaceForAddress}.\n */\n function setInterfaceImplementer(\n address account,\n bytes32 interfaceHash,\n address implementer\n ) external;\n\n /**\n * @dev Returns the implementer of `interfaceHash` for `account`. If no such\n * implementer is registered, returns the zero address.\n *\n * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28\n * zeroes), `account` will be queried for support of it.\n *\n * `account` being the zero address is an alias for the caller's address.\n */\n function getInterfaceImplementer(address account, bytes32 interfaceHash)\n external\n view\n returns (address);\n\n /**\n * @dev Returns the interface hash for an `interfaceName`, as defined in the\n * corresponding\n * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].\n */\n function interfaceHash(string calldata interfaceName) external pure returns (bytes32);\n\n /**\n * @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n * @param account Address of the contract for which to update the cache.\n * @param interfaceId ERC165 interface for which to update the cache.\n */\n function updateERC165Cache(address account, bytes4 interfaceId) external;\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not.\n * If the result is not cached a direct lookup on the contract address is performed.\n * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n * {updateERC165Cache} with the contract address.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165Interface(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n event InterfaceImplementerSet(\n address indexed account,\n bytes32 indexed interfaceHash,\n address indexed implementer\n );\n\n event ManagerChanged(address indexed account, address indexed newManager);\n}\n" + }, + "contracts/testhelpers/ITokenFlashLoanTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n// \"SPDX-License-Identifier: Apache-2.0\"\n\ninterface ITokenFlashLoanTest {\n function flashBorrow(\n uint256 borrowAmount,\n address borrower,\n address target,\n string calldata signature,\n bytes calldata data\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/testhelpers/LoanTokenLogicTest.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicTest is LoanTokenLogic {\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestNonReentrantValueSetter.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\ncontract TestNonReentrantValueSetter is SharedReentrancyGuard {\n uint256 public value;\n\n // This will fail if another globallyNonReentrant function has already been entered\n function setValue(uint256 newValue) public globallyNonReentrant {\n value = newValue;\n }\n\n // this will always fail if `other.setValue` is globallyNonReentrant\n function setOtherContractValueNonReentrant(address other, uint256 newValue)\n external\n globallyNonReentrant\n {\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n\n // this is intentionally not globallyNonReentrant and should work even if both contracts are non-reentrant\n function setThisAndOtherContractValue(address other, uint256 newValue) external {\n setValue(newValue);\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestValueSetterProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract TestValueSetterProxy is UpgradableProxy {\n // This is here for the memory layout\n uint256 public value;\n}\n" + }, + "contracts/testhelpers/staking/StakingTester.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../TestToken.sol\";\n\ncontract StakingTester {\n IStaking public staking;\n TestToken public token;\n\n constructor(address _staking, address _token) public {\n staking = IStaking(_staking);\n token = TestToken(_token);\n }\n\n function stakeAndWithdraw(uint96 _amount, uint256 _until) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _until, address(this), address(this));\n staking.withdraw(_amount, _until, address(this));\n }\n\n function stakeAndDelegate(\n uint96 _amount,\n address _delegatee,\n uint256 _lockDate\n ) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _lockDate, address(this), address(this));\n staking.delegate(_delegatee, _lockDate);\n }\n}\n" + }, + "contracts/testhelpers/TestCoverage.sol": { + "content": "/**\n * In order to test some functionalities like Pausable::pausable() modifier,\n * it is required to add a contract to invoke them and get a full coverage on tests.\n */\n\npragma solidity 0.5.17;\n\nimport \"../connectors/loantoken/Pausable.sol\";\nimport \"../governance/Staking/SafeMath96.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../connectors/loantoken/AdvancedToken.sol\";\nimport \"../connectors/loantoken/LoanTokenLogicStorage.sol\";\n\ncontract TestCoverage is\n Pausable,\n SafeMath96,\n VaultController,\n AdvancedToken,\n LoanTokenLogicStorage\n{\n /// @dev Pausable is currently an unused contract that still is operative\n /// because margin trade flashloan functionality has been commented out.\n /// In case it were restored, contract would become used again, so for a\n /// complete test coverage it is required to test it.\n\n function dummyPausableFunction() external pausable(msg.sig) {\n /// @dev do nothing, just to check if modifier is working\n }\n\n /// @dev This function should be located on Pausable contract in the case\n /// it has to be used again by flashloan restoration.\n function togglePause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047)\n )\n );\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /// @dev Testing internal functions of governance/Staking/SafeMath96.sol\n function testSafeMath96_safe32(uint256 n) public pure returns (uint32) {\n // Public wrapper for SafeMath96 internal function\n return safe32(n, \"overflow\");\n }\n\n function testSafeMath96_safe64(uint256 n) public pure returns (uint64) {\n // Public wrapper for SafeMath96 internal function\n return safe64(n, \"overflow\");\n }\n\n function testSafeMath96_safe96(uint256 n) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return safe96(n, \"overflow\");\n }\n\n function testSafeMath96_sub96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return sub96(a, b, \"underflow\");\n }\n\n function testSafeMath96_mul96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return mul96(a, b, \"overflow\");\n }\n\n function testSafeMath96_div96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return div96(a, b, \"division by 0\");\n }\n\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;\n EnumerableBytes32Set.Bytes32Set internal aSet;\n\n function testEnum_AddRemove(bytes32 a, bytes32 b) public returns (bool) {\n aSet.addBytes32(a);\n return aSet.removeBytes32(b);\n }\n\n function testEnum_AddAddress(address a, address b) public returns (bool) {\n aSet.addAddress(a);\n return aSet.containsAddress(b);\n }\n\n function testEnum_AddAddressesAndEnumerate(\n address a,\n address b,\n uint256 start,\n uint256 count\n ) public returns (bytes32[] memory) {\n aSet.addAddress(a);\n aSet.addAddress(b);\n return aSet.enumerate(start, count);\n }\n\n /// @dev Wrapper to test internal function never called along current codebase\n function testVaultController_vaultApprove(\n address token,\n address to,\n uint256 value\n ) public {\n vaultApprove(token, to, value);\n }\n\n /// @dev mint wrapper w/o previous checks\n function testMint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) public {\n _mint(_to, _tokenAmount, _assetAmount, _price);\n }\n\n /// @dev wrapper for a function unreachable to tests\n function testStringToBytes32(string memory source) public pure returns (bytes32 result) {\n return stringToBytes32(source);\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some ERC777 from the lending pool.\n * 2. Close the loan with closeWithDeposit function in the protocol.\n * 3. Burn all iERC777.\n *\n * The cross-reentrancy happened in step#3. It might happened through a hook function (tokensToSend) that is implemented in this contract to support the ERC777 transfer.\n * Inside the hook function, it will try to mint the iERC777.\n * The details about the hook functions can be found here: https://eips.ethereum.org/EIPS/eip-777#hooks\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithDeposit function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyERC777 {\n address public loanToken;\n address public WRBTC;\n address public SUSD; /// ERC777\n ProtocolLike public sovrynProtocol;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iUSDTBalance;\n }\n\n function() external payable {}\n\n constructor(\n address _loanToken,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanToken = _loanToken;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777TokensSender\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: WRBTC has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n });\n\n IERC20(WRBTC).approve(loanToken, initial.susdBalance);\n\n ILoanTokenModules(loanToken).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n WRBTC,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanToken).loanParamsIds(\n uint256(keccak256(abi.encodePacked(WRBTC, true)))\n );\n bytes32 loan_id =\n keccak256(abi.encodePacked(loanParamsLocalId, loanToken, _borrower, _borrowerNonce));\n\n // STEP 3 close the borrowed position with a deposit\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(address(sovrynProtocol), _SUSDBalance);\n sovrynProtocol.closeWithDeposit(\n loan_id,\n address(this),\n collateralTokenSent.mul(20).div(100) // make it 20% higher from initial borrow amount\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iSUSD\n uint256 _iSUSDBalance = ILoanTokenModules(loanToken).balanceOf(_borrower);\n ILoanTokenModules(loanToken).burn(_receiver, _iSUSDBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n // });\n }\n\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256,\n bytes calldata,\n bytes calldata\n ) external {\n if (operator == address(sovrynProtocol) && to == loanToken && from == address(this)) {\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(loanToken, _SUSDBalance);\n\n ILoanTokenModules(loanToken).mint(address(this), 1000000 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyRBTC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some WRBTC from the lending pool.\n * 2. Close the loan with closeWithSwap function in the protocol.\n * 3. Burn all iWRBTC.\n *\n * The refund happened in step #3, which will send back the RBTC back to this contract.\n * Then, this contract will try to do another iWRBTC minting to the loan token --> this is where the cross-reentrancy happened between the protocol & the loan token contract.\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithSwap function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyRBTC {\n address public loanTokenWRBTC;\n address public WRBTC;\n address public SUSD;\n ProtocolLike public sovrynProtocol;\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iWRBTCBalance;\n }\n\n function() external payable {\n if (msg.sender == address(sovrynProtocol)) {\n uint256 latestRBTCBalance = address(this).balance;\n IWrbtcERC20(WRBTC).deposit.value(14 ether)();\n uint256 _WRBTCBalance = IERC20(WRBTC).balanceOf(address(this));\n IERC20(WRBTC).approve(loanTokenWRBTC, _WRBTCBalance);\n\n ILoanTokenModules(loanTokenWRBTC).mint(address(this), 14 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n\n constructor(\n address _loanTokenWRBTC,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanTokenWRBTC = _loanTokenWRBTC;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: SUSD has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n });\n\n IERC20(SUSD).approve(loanTokenWRBTC, initial.susdBalance);\n\n ILoanTokenModules(loanTokenWRBTC).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n SUSD,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanTokenWRBTC).loanParamsIds(\n uint256(keccak256(abi.encodePacked(SUSD, true)))\n );\n bytes32 loan_id =\n keccak256(\n abi.encodePacked(loanParamsLocalId, loanTokenWRBTC, _borrower, _borrowerNonce)\n );\n\n // STEP 3 close the borrowed position with a swap (probably works just as well with deposit)\n sovrynProtocol.closeWithSwap(\n loan_id,\n msg.sender,\n collateralTokenSent.mul(200).div(100), // make it 20% higher from initial collateral sent to make sure whole position is closed\n true,\n \"\"\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iRBTC\n uint256 _iWRBTCBalance = ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower);\n ILoanTokenModules(loanTokenWRBTC).burn(_receiver, _iWRBTCBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n // });\n }\n}\n" + }, + "contracts/testhelpers/TestLibraries.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../rsk/RSKAddrValidator.sol\";\n\n// contract for testing libraries\ncontract TestLibraries {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n */\n function RSKAddrValidator_checkPKNotZero(address addr) public pure returns (bool) {\n return (RSKAddrValidator.checkPKNotZero(addr));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key\n */\n function RSKAddrValidator_safeEquals(address addr1, address addr2) public pure returns (bool) {\n return (RSKAddrValidator.safeEquals(addr1, addr2));\n }\n}\n" + }, + "contracts/testhelpers/TestSovrynSwap.sol": { + "content": "/**\n * Test file simulating the SovrynSwap network\n * */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"./TestToken.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestSovrynSwap {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n address public priceFeeds;\n\n constructor(address feed) public {\n priceFeeds = feed;\n }\n\n /**\n * simulating the contract registry. always returns the address of this contract\n * */\n function addressOf(bytes32 contractName) public view returns (address) {\n return address(this);\n }\n\n /**\n * calculates the return tokens when swapping _amount, makes sure the return is bigger than _minReturn,\n * mints and burns the test tokens accordingly.\n * */\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256) {\n //compute the return for the amount of tokens provided\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n uint256 actualReturn = _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n\n require(actualReturn >= _minReturn, \"insufficient source tokens provided\");\n\n TestToken(address(_path[0])).burn(address(msg.sender), _amount);\n TestToken(address(_path[1])).mint(address(_beneficiary), actualReturn);\n return actualReturn;\n }\n\n /**\n * queries the rate from the Price Feed contract and computes the expected return amount based on the\n * amout of source tokens to be swapped.\n * */\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n\n return _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * returns the conversion path -> always a direct path\n * */\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory)\n {\n IERC20[] memory path = new IERC20[](2);\n path[0] = _sourceToken;\n path[1] = _targetToken;\n return path;\n }\n}\n" + }, + "contracts/testhelpers/TestToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestToken {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balances[_who], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[_who] = balances[_who].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(_who, _value);\n emit Transfer(_who, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/testhelpers/TestTokenERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Context.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../interfaces/IERC777.sol\";\nimport \"../interfaces/IERC777Recipient.sol\";\nimport \"../interfaces/IERC777Sender.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\n\ncontract TestTokenERC777 is Context, IERC777, IERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n mapping(address => uint256) private _balances;\n\n uint256 private _totalSupply;\n\n // We inline the result of the following hashes because Solidity doesn't resolve them at compile time.\n // See https://github.com/ethereum/solidity/issues/4024.\n\n // keccak256(\"ERC777TokensSender\")\n bytes32 private constant TOKENS_SENDER_INTERFACE_HASH =\n 0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895;\n\n // keccak256(\"ERC777TokensRecipient\")\n bytes32 private constant TOKENS_RECIPIENT_INTERFACE_HASH =\n 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;\n\n // This isn't ever read from - it's only used to respond to the defaultOperators query.\n address[] private _defaultOperatorsArray;\n\n // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).\n mapping(address => bool) private _defaultOperators;\n\n // For each account, a mapping of its operators and revoked default operators.\n mapping(address => mapping(address => bool)) private _operators;\n mapping(address => mapping(address => bool)) private _revokedDefaultOperators;\n\n // ERC20-allowances\n mapping(address => mapping(address => uint256)) private _allowances;\n\n /**\n * @dev `defaultOperators` may be an empty array.\n */\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _initialSupply,\n uint8 _decimals,\n address[] memory defaultOperators\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n _defaultOperatorsArray = defaultOperators;\n for (uint256 i = 0; i < _defaultOperatorsArray.length; i++) {\n _defaultOperators[_defaultOperatorsArray[i]] = true;\n }\n\n _mint(msg.sender, msg.sender, _initialSupply, \"\", \"\");\n\n // register interfaces\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777Token\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n /**\n * @dev See {IERC777-granularity}.\n *\n * This implementation always returns `1`.\n */\n function granularity() public view returns (uint256) {\n return 1;\n }\n\n /**\n * @dev See {IERC777-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev Returns the amount of tokens owned by an account (`tokenHolder`).\n */\n function balanceOf(address tokenHolder) public view returns (uint256) {\n return _balances[tokenHolder];\n }\n\n /**\n * @dev See {IERC777-send}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes memory data\n ) public {\n _send(_msgSender(), _msgSender(), recipient, amount, data, \"\", true);\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient}\n * interface if it is a contract.\n *\n * Also emits a {Sent} event.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n\n address from = _msgSender();\n\n _callTokensToSend(from, from, recipient, amount, \"\", \"\");\n\n _move(from, from, recipient, amount, \"\", \"\");\n\n _callTokensReceived(from, from, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev See {IERC777-burn}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function burn(uint256 amount, bytes memory data) public {\n _burn(_msgSender(), _msgSender(), amount, data, \"\");\n }\n\n /**\n * @dev See {IERC777-isOperatorFor}.\n */\n function isOperatorFor(address operator, address tokenHolder) public view returns (bool) {\n return\n operator == tokenHolder ||\n (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||\n _operators[tokenHolder][operator];\n }\n\n /**\n * @dev See {IERC777-authorizeOperator}.\n */\n function authorizeOperator(address operator) public {\n require(_msgSender() != operator, \"ERC777: authorizing self as operator\");\n\n if (_defaultOperators[operator]) {\n delete _revokedDefaultOperators[_msgSender()][operator];\n } else {\n _operators[_msgSender()][operator] = true;\n }\n\n emit AuthorizedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-revokeOperator}.\n */\n function revokeOperator(address operator) public {\n require(operator != _msgSender(), \"ERC777: revoking self as operator\");\n\n if (_defaultOperators[operator]) {\n _revokedDefaultOperators[_msgSender()][operator] = true;\n } else {\n delete _operators[_msgSender()][operator];\n }\n\n emit RevokedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-defaultOperators}.\n */\n function defaultOperators() public view returns (address[] memory) {\n return _defaultOperatorsArray;\n }\n\n /**\n * @dev See {IERC777-operatorSend}.\n *\n * Emits {Sent} and {IERC20-Transfer} events.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), sender),\n \"ERC777: caller is not an operator for holder\"\n );\n _send(_msgSender(), sender, recipient, amount, data, operatorData, true);\n }\n\n /**\n * @dev See {IERC777-operatorBurn}.\n *\n * Emits {Burned} and {IERC20-Transfer} events.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), account),\n \"ERC777: caller is not an operator for holder\"\n );\n _burn(_msgSender(), account, amount, data, operatorData);\n }\n\n /**\n * @dev See {IERC20-allowance}.\n *\n * Note that operator and allowance concepts are orthogonal: operators may\n * not have allowance, and accounts with allowance may not be operators\n * themselves.\n */\n function allowance(address holder, address spender) public view returns (uint256) {\n return _allowances[holder][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Note that accounts cannot have allowance issued by their operators.\n */\n function approve(address spender, uint256 value) public returns (bool) {\n address holder = _msgSender();\n _approve(holder, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Note that operator and allowance concepts are orthogonal: operators cannot\n * call `transferFrom` (unless they have allowance), and accounts with\n * allowance cannot call `operatorSend` (unless they are operators).\n *\n * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.\n */\n function transferFrom(\n address holder,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n require(holder != address(0), \"ERC777: transfer from the zero address\");\n\n address spender = _msgSender();\n\n _callTokensToSend(spender, holder, recipient, amount, \"\", \"\");\n\n _move(spender, holder, recipient, amount, \"\", \"\");\n\n _approve(\n holder,\n spender,\n _allowances[holder][spender].sub(amount, \"ERC777: transfer amount exceeds allowance\")\n );\n\n _callTokensReceived(spender, holder, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `operator`, `data` and `operatorData`.\n *\n * See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits {Minted} and {IERC20-Transfer} events.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - if `account` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function _mint(\n address operator,\n address account,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n require(account != address(0), \"ERC777: mint to the zero address\");\n\n // Update state variables\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n\n _callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);\n\n emit Minted(operator, account, amount, userData, operatorData);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Send tokens\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _send(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n require(from != address(0), \"ERC777: send from the zero address\");\n require(to != address(0), \"ERC777: send to the zero address\");\n\n _callTokensToSend(operator, from, to, amount, userData, operatorData);\n\n _move(operator, from, to, amount, userData, operatorData);\n\n _callTokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData,\n requireReceptionAck\n );\n }\n\n /**\n * @dev Burn tokens\n * @param operator address operator requesting the operation\n * @param from address token holder address\n * @param amount uint256 amount of tokens to burn\n * @param data bytes extra information provided by the token holder\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _burn(\n address operator,\n address from,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) internal {\n require(from != address(0), \"ERC777: burn from the zero address\");\n\n _callTokensToSend(operator, from, address(0), amount, data, operatorData);\n\n // Update state variables\n _balances[from] = _balances[from].sub(amount, \"ERC777: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n\n emit Burned(operator, from, amount, data, operatorData);\n emit Transfer(from, address(0), amount);\n }\n\n function _move(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) private {\n _balances[from] = _balances[from].sub(amount, \"ERC777: transfer amount exceeds balance\");\n _balances[to] = _balances[to].add(amount);\n\n emit Sent(operator, from, to, amount, userData, operatorData);\n emit Transfer(from, to, amount);\n }\n\n function _approve(\n address holder,\n address spender,\n uint256 value\n ) internal {\n // TODO: restore this require statement if this function becomes internal, or is called at a new callsite. It is\n // currently unnecessary.\n //require(holder != address(0), \"ERC777: approve from the zero address\");\n require(spender != address(0), \"ERC777: approve to the zero address\");\n\n _allowances[holder][spender] = value;\n emit Approval(holder, spender, value);\n }\n\n /**\n * @dev Call from.tokensToSend() if the interface is registered\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _callTokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Sender(implementer).tokensToSend(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n }\n }\n\n /**\n * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but\n * tokensReceived() was not registered for the recipient\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _callTokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Recipient(implementer).tokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n } else if (requireReceptionAck) {\n require(\n !to.isContract(),\n \"ERC777: token recipient contract has no implementer for ERC777TokensRecipient\"\n );\n }\n }\n\n function mint(address _to, uint256 _value) public {\n // Update state variables\n _totalSupply = _totalSupply.add(_value);\n _balances[_to] = _balances[_to].add(_value);\n\n emit Minted(msg.sender, _to, _value, \"\", \"\");\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balanceOf(_who), \"balance too low\");\n\n _burn(msg.sender, _who, _value, \"\", \"\");\n }\n}\n" + }, + "contracts/testhelpers/TestTokenLimited.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestTokenLimited {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n require(_value <= 100000 ether, \"max mint amount exceeded\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(uint256 _value) public {\n require(_value <= balances[msg.sender], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(msg.sender, _value);\n emit Transfer(msg.sender, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/token/IApproveAndCall.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/ApprovalReceiver.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IApproveAndCall {\n /**\n * @notice Receives approval from SOV token.\n * @param _sender The sender of SOV.approveAndCall function.\n * @param _amount The amount was approved.\n * @param _token The address of token.\n * @param _data The data will be used for low level call.\n * */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/token/SOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/ERC20Detailed.sol\";\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./IApproveAndCall.sol\";\n\n/**\n * @title Sovryn Token: SOV is an ERC-20 token contract for Sovryn governance.\n *\n * @notice This contract accounts for all holders' balances.\n *\n * @dev This contract represents a token with dynamic supply.\n * The owner of the token contract can mint/burn tokens to/from any account\n * based upon previous governance voting and approval.\n * */\ncontract SOV is ERC20, ERC20Detailed, Ownable {\n string constant NAME = \"Sovryn Token\";\n string constant SYMBOL = \"SOV\";\n uint8 constant DECIMALS = 18;\n\n /**\n * @notice Constructor called on deployment, initiates the contract.\n * @dev On deployment, some amount of tokens will be minted for the owner.\n * @param _initialAmount The amount of tokens to be minted on contract creation.\n * */\n constructor(uint256 _initialAmount) public ERC20Detailed(NAME, SYMBOL, DECIMALS) {\n if (_initialAmount != 0) {\n _mint(msg.sender, _initialAmount);\n }\n }\n\n /**\n * @notice Creates new tokens and sends them to the recipient.\n * @dev Don't create more than 2^96/10 tokens before updating the governance first.\n * @param _account The recipient address to get the minted tokens.\n * @param _amount The amount of tokens to be minted.\n * */\n function mint(address _account, uint256 _amount) public onlyOwner {\n _mint(_account, _amount);\n }\n\n /**\n * @notice Approves and then calls the receiving contract.\n * Useful to encapsulate sending tokens to a contract in one call.\n * Solidity has no native way to send tokens to contracts.\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\n * @param _spender The contract address to spend the tokens.\n * @param _amount The amount of tokens to be sent.\n * @param _data Parameters for the contract call, such as endpoint signature.\n * */\n function approveAndCall(\n address _spender,\n uint256 _amount,\n bytes memory _data\n ) public {\n approve(_spender, _amount);\n IApproveAndCall(_spender).receiveApproval(msg.sender, _amount, address(this), _data);\n }\n}\n" + }, + "contracts/utils/AdminRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\n\ncontract AdminRole is Ownable {\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * or on our own overriding sovrynOwnable.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n}\n" + }, + "contracts/utils/PausableRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/PausableOz.sol\";\n\ncontract PausableRole is PausableOz {\n address public pauser;\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n\n /**\n * @dev Modifier to make a function callable only when the caller is pauser or owner\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"Pausable: unauthorized\"); // SS02\n _;\n }\n\n /**\n * @notice Set the pauser address.\n *\n * only pauser can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyPauserOrOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyPauserOrOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/utils/ProxyOwnable.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\n/**\n * Based on OpenZeppelin's Ownable contract:\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\n *\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract ProxyOwnable {\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Ownable:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"ProxyOwnable::setProxyOwner: invalid address\");\n emit ProxyOwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Set address of the owner (only owner can call this function)\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n\n /**\n * @notice Return address of the owner.\n * @return _owner Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n}\n" + }, + "contracts/utils/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\nlibrary Utils {\n function stringToBytes32(string memory source) internal pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + }, + "remappings": [ + "ds-test/=foundry/lib/forge-std/lib/ds-test/src/", + "forge-std/=foundry/lib/forge-std/src/" + ] + } +} \ No newline at end of file diff --git a/deployment/deployments/rskSovrynMainnet/solcInputs/444414c40f489390e118f5b65a5947cc.json b/deployment/deployments/rskSovrynMainnet/solcInputs/444414c40f489390e118f5b65a5947cc.json new file mode 100644 index 000000000..cc792c440 --- /dev/null +++ b/deployment/deployments/rskSovrynMainnet/solcInputs/444414c40f489390e118f5b65a5947cc.json @@ -0,0 +1,711 @@ +{ + "language": "Solidity", + "sources": { + "contracts/connectors/loantoken/AdvancedToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Advanced Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedToken implements standard ERC-20 approval, mint and burn token functionality.\n * Logic (AdvancedToken) is kept aside from storage (AdvancedTokenStorage).\n *\n * For example, LoanTokenLogicDai contract uses AdvancedToken::_mint() to mint\n * its Loan Dai iTokens.\n * */\ncontract AdvancedToken is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n /**\n * @notice Set an amount as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n *\n * @param _spender The account address that will be able to spend the tokens.\n * @param _value The amount of tokens allowed to spend.\n * */\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @notice The iToken minting process. Meant to issue Loan iTokens.\n * Lenders are able to open an iToken position, by minting them.\n * This function is called by LoanTokenLogicStandard::_mintToken\n * @param _to The recipient of the minted tTokens.\n * @param _tokenAmount The amount of iTokens to be minted.\n * @param _assetAmount The amount of lended tokens (asset to lend).\n * @param _price The price of the lended tokens.\n * @return The updated balance of the recipient.\n * */\n function _mint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n require(_to != address(0), \"15\");\n\n uint256 _balance = balances[_to].add(_tokenAmount);\n balances[_to] = _balance;\n\n totalSupply_ = totalSupply_.add(_tokenAmount);\n\n emit Mint(_to, _tokenAmount, _assetAmount, _price);\n emit Transfer(address(0), _to, _tokenAmount);\n\n return _balance;\n }\n\n /**\n * @notice The iToken burning process. Meant to destroy Loan iTokens.\n * Lenders are able to close an iToken position, by burning them.\n * This function is called by LoanTokenLogicStandard::_burnToken\n * @param _who The owner of the iTokens to burn.\n * @param _tokenAmount The amount of iTokens to burn.\n * @param _assetAmount The amount of lended tokens.\n * @param _price The price of the lended tokens.\n * @return The updated balance of the iTokens owner.\n * */\n function _burn(\n address _who,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n //bzx compare\n //TODO: Unit test\n uint256 _balance = balances[_who].sub(_tokenAmount, \"16\");\n\n // a rounding error may leave dust behind, so we clear this out\n if (_balance <= 10) {\n // We can't leave such small balance quantities.\n _tokenAmount = _tokenAmount.add(_balance);\n _balance = 0;\n }\n balances[_who] = _balance;\n\n totalSupply_ = totalSupply_.sub(_tokenAmount);\n\n emit Burn(_who, _tokenAmount, _assetAmount, _price);\n emit Transfer(_who, address(0), _tokenAmount);\n return _balance;\n }\n}\n" + }, + "contracts/connectors/loantoken/AdvancedTokenStorage.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./LoanTokenBase.sol\";\n\n/**\n * @title Advanced Token Storage contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedTokenStorage implements standard ERC-20 getters functionality:\n * totalSupply, balanceOf, allowance and some events.\n * iToken logic is divided into several contracts AdvancedToken,\n * AdvancedTokenStorage and LoanTokenBase.\n * */\ncontract AdvancedTokenStorage is LoanTokenBase {\n using SafeMath for uint256;\n\n /* Events */\n\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /* Storage */\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n /* Functions */\n\n /**\n * @notice Get the total supply of iTokens.\n * @return The total number of iTokens in existence as of now.\n * */\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n /**\n * @notice Get the amount of iTokens owned by an account.\n * @param _owner The account owner of the iTokens.\n * @return The number of iTokens an account owns.\n * */\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n /**\n * @notice Get the amount of iTokens allowed to be spent by a\n * given account on behalf of the owner.\n * @param _owner The account owner of the iTokens.\n * @param _spender The account allowed to send the iTokens.\n * @return The number of iTokens an account is allowing the spender\n * to send on its behalf.\n * */\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/connectors/loantoken/interfaces/FeedsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface FeedsLike {\n function queryRate(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 rate, uint256 precision);\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../lib/MarginTradeStructHelpers.sol\";\n\ninterface ProtocolLike {\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function priceFeeds() external view returns (address);\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function lendingFeePercent() external view returns (uint256);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function borrowerNonce(address) external view returns (uint256);\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata // for future use /*loanDataBytes*/\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolSettingsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../core/objects/LoanParamsStruct.sol\";\n\ninterface ProtocolSettingsLike {\n function setupLoanParams(LoanParamsStruct.LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n}\n" + }, + "contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol": { + "content": "pragma solidity 0.5.17;\n\nlibrary MarginTradeStructHelpers {\n struct SentAddresses {\n address lender;\n address borrower;\n address receiver;\n address manager;\n }\n\n struct SentAmounts {\n uint256 interestRate;\n uint256 newPrincipal;\n uint256 interestInitialAmount;\n uint256 loanTokenSent;\n uint256 collateralTokenSent;\n uint256 minEntryPrice;\n uint256 loanToCollateralSwapRate;\n uint256 interestDuration;\n uint256 entryLeverage;\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Loan Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * A loan token (iToken) is created as a proxy to an upgradable token contract.\n *\n * Examples of loan tokens on Sovryn are iRBTC, iDOC, iUSDT, iBPro,\n * iSOV (near future).\n *\n * Lenders receive iTokens that collect interest from the lending pool\n * which they can redeem by withdrawing them. The i in iToken stands for interest.\n *\n * Do not confuse iTokens with underlying tokens. iDOC is an iToken (loan token)\n * whilest DOC is the underlying token (currency).\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\n * */\ncontract LoanToken is AdvancedTokenStorage {\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n address public admin;\n\n /**\n * @notice Deploy loan token proxy.\n * Sets ERC20 parameters of the token.\n *\n * @param _newOwner The address of the new owner.\n * @param _newTarget The address of the new target contract instance.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice Public owner setter for target address.\n * @dev Calls internal setter.\n * @param _newTarget The address of the new target contract instance.\n * */\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n /**\n * @notice Internal setter for target address.\n * @param _newTarget The address of the new target contract instance.\n * */\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n /**\n * @notice Internal setter for sovrynContract address.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * */\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n /**\n * @notice Internal setter for wrBTC address.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n /**\n * @notice Public owner cloner for pointed loan token.\n * Sets ERC20 parameters of the token.\n *\n * @dev TODO: add check for double init.\n * idk but init usually can be called only once.\n *\n * @param _loanTokenAddress The address of the pointed loan token instance.\n * @param _name The ERC20 token name.\n * @param _symbol The ERC20 token symbol.\n * */\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; /// starting price of 1\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenBase.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SignedSafeMath.sol\";\nimport \"../../openzeppelin/ReentrancyGuard.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\nimport \"./Pausable.sol\";\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title Loan Token Base contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Specific loan related storage for iTokens.\n *\n * An loan token or iToken is a representation of a user funds in the pool and the\n * interest they've earned. The redemption value of iTokens continually increase\n * from the accretion of interest paid into the lending pool by borrowers. The user\n * can sell iTokens to exit its position. The user might potentially use them as\n * collateral wherever applicable.\n *\n * There are three main tokens in the bZx system, iTokens, pTokens, and BZRX tokens.\n * The bZx system of lending and borrowing depends on iTokens and pTokens, and when\n * users lend or borrow money on bZx, their crypto assets go into or come out of\n * global liquidity pools, which are pools of funds shared between many different\n * exchanges. When lenders supply funds into the global liquidity pools, they\n * automatically receive iTokens; When users borrow money to open margin trading\n * positions, they automatically receive pTokens. The system is also designed to\n * use the BZRX tokens, which are only used to pay fees on the network currently.\n * */\ncontract LoanTokenBase is ReentrancyGuard, SharedReentrancyGuard, Ownable, Pausable {\n uint256 internal constant WEI_PRECISION = 10**18;\n uint256 internal constant WEI_PERCENT_PRECISION = 10**20;\n\n int256 internal constant sWEI_PRECISION = 10**18;\n\n /// @notice Standard ERC-20 properties\n string public name;\n string public symbol;\n uint8 public decimals;\n\n /// @notice The address of the loan token (asset to lend) instance.\n address public loanTokenAddress;\n\n uint256 public baseRate;\n uint256 public rateMultiplier;\n uint256 public lowUtilBaseRate;\n uint256 public lowUtilRateMultiplier;\n\n uint256 public targetLevel;\n uint256 public kinkLevel;\n uint256 public maxScaleRate;\n\n uint256 internal _flTotalAssetSupply;\n uint256 public checkpointSupply;\n uint256 public initialPrice;\n\n /// uint88 for tight packing -> 8 + 88 + 160 = 256\n uint88 internal lastSettleTime_;\n\n /// Mapping of keccak256(collateralToken, isTorqueLoan) to loanParamsId.\n mapping(uint256 => bytes32) public loanParamsIds;\n\n /// Price of token at last user checkpoint.\n mapping(address => uint256) internal checkpointPrices_;\n\n // the maximum trading/borrowing/lending limit per token address\n mapping(address => uint256) public transactionLimit;\n // 0 -> no limit\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicBeacon.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../mixins/EnumerableBytes32Set.sol\";\nimport \"../../mixins/EnumerableBytes4Set.sol\";\nimport \"../../utils/PausableRole.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Loan Token Logic Beacon contract.\n *\n * @notice This contract stored the target logic implementation of LoanTokens which has the same logic implementation (LoanTokenLogicLM / LoanTokenLogicWrbtc)\n * Apart from storing the target logic implementation, this contract also has a pause functionality.\n * By implementing pause/unpause functionality in this beacon contract, we can pause the loan token that has the same Logic (LoanTokenLogicLM / LoanTokenLogicWrbtc) at one call.\n * Meanwhile the pause/unpause function in the LoanTokenLogicProxy is used to pause/unpause specific LoanToken\n */\n\ncontract LoanTokenLogicBeacon is PausableRole {\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; // enumerable map of bytes4 or addresses\n\n mapping(bytes4 => address) private logicTargets;\n\n struct LoanTokenLogicModuleUpdate {\n address implementation; // address implementaion of the module\n uint256 updateTimestamp; // time of update\n }\n\n mapping(bytes32 => LoanTokenLogicModuleUpdate[]) public moduleUpgradeLog; /** the module name as the key */\n\n mapping(bytes32 => uint256) public activeModuleIndex; /** To store the current active index log for module */\n\n mapping(bytes32 => EnumerableBytes4Set.Bytes4Set) private activeFuncSignatureList; /** Store the current active function signature */\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n * This is the overriden function from the pausable contract, so that we can use custom error message.\n */\n modifier whenNotPaused() {\n require(!_paused, \"LoanTokenLogicBeacon:paused mode\");\n _;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This function will store the updated protocol module to the storage (For rollback purposes)\n *\n * @param loanTokenModuleAddress The module target address\n */\n function registerLoanTokenModule(address loanTokenModuleAddress) external onlyOwner {\n bytes32 moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n\n // Store the upgrade to the log\n moduleUpgradeLog[moduleName].push(\n LoanTokenLogicModuleUpdate(loanTokenModuleAddress, block.timestamp)\n );\n activeModuleIndex[moduleName] = moduleUpgradeLog[moduleName].length - 1;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This registration will require target contract to have the exact function getListFunctionSignatures() which will return functionSignatureList and the moduleName in bytes32\n *\n * @param loanTokenModuleAddress the target logic of the loan token module\n *\n * @return the module name\n */\n function _registerLoanTokenModule(address loanTokenModuleAddress) private returns (bytes32) {\n require(\n Address.isContract(loanTokenModuleAddress),\n \"LoanTokenModuleAddress is not a contract\"\n );\n\n // Get the list of function signature on this loanTokenModulesAddress\n (bytes4[] memory functionSignatureList, bytes32 moduleName) =\n ILoanTokenLogicModules(loanTokenModuleAddress).getListFunctionSignatures();\n\n /// register / update the module function signature address implementation\n for (uint256 i; i < functionSignatureList.length; i++) {\n require(functionSignatureList[i] != bytes4(0x0), \"ERR_EMPTY_FUNC_SIGNATURE\");\n logicTargets[functionSignatureList[i]] = loanTokenModuleAddress;\n if (!activeFuncSignatureList[moduleName].contains(functionSignatureList[i]))\n activeFuncSignatureList[moduleName].addBytes4(functionSignatureList[i]);\n }\n\n /// delete the \"removed\" module function signature in the current implementation\n bytes4[] memory activeSignatureListEnum =\n activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n for (uint256 i; i < activeSignatureListEnum.length; i++) {\n bytes4 activeSigBytes = activeSignatureListEnum[i];\n if (logicTargets[activeSigBytes] != loanTokenModuleAddress) {\n logicTargets[activeSigBytes] = address(0);\n activeFuncSignatureList[moduleName].removeBytes4(activeSigBytes);\n }\n }\n\n return moduleName;\n }\n\n /**\n * @dev get all active function signature list based on the module name.\n *\n * @param moduleName in bytes32.\n *\n * @return the array of function signature.\n */\n function getActiveFuncSignatureList(bytes32 moduleName)\n public\n view\n returns (bytes4[] memory signatureList)\n {\n signatureList = activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n return signatureList;\n }\n\n /**\n * @dev Get total length of the module upgrade log.\n *\n * @param moduleName in bytes32.\n *\n * @return length of module upgrade log.\n */\n function getModuleUpgradeLogLength(bytes32 moduleName) external view returns (uint256) {\n return moduleUpgradeLog[moduleName].length;\n }\n\n /**\n * @notice This function will rollback particular module to the spesific index / version of deployment\n *\n * @param moduleName Name of module in bytes32 format\n * @param index index / version of previous deployment\n */\n function rollback(bytes32 moduleName, uint256 index) external onlyOwner {\n address loanTokenModuleAddress = moduleUpgradeLog[moduleName][index].implementation;\n moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n activeModuleIndex[moduleName] = index;\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(bytes4 sig) external view whenNotPaused returns (address) {\n return logicTargets[sig];\n }\n}\n\ninterface ILoanTokenLogicModules {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory, bytes32 moduleName);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicProxy.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./AdvancedTokenStorage.sol\";\nimport \"../../openzeppelin/Initializable.sol\";\n\n/**\n * @title Loan Token Logic Proxy contract.\n *\n * @notice This contract contains the proxy functionality and it will query the logic target from LoanTokenLogicBeacon\n * This contract will also has the pause/unpause functionality. The purpose of this pausability is so that we can pause/unpause from the loan token level.\n *\n */\ncontract LoanTokenLogicProxy is AdvancedTokenStorage {\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT\n */\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT (CONSTANT / IMMUTABLE)\n */\n\n bytes32 internal constant LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT =\n keccak256(\"LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT\");\n\n modifier onlyAdmin() {\n require(isOwner(), \"LoanTokenLogicProxy:unauthorized\");\n _;\n }\n\n /**\n * @notice Fallback function performs a logic implementation address query to LoanTokenLogicBeacon and then do delegate call to that query result address.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n // query the logic target implementation address from the LoanTokenLogicBeacon\n address target = ILoanTokenLogicBeacon(_beaconAddress()).getTarget(msg.sig);\n require(target != address(0), \"LoanTokenLogicProxy:target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @dev Returns the current Loan Token logic Beacon.\n * @return Address of the current LoanTokenLogicBeacon.\n */\n function _beaconAddress() internal view returns (address beaconAddress) {\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n assembly {\n beaconAddress := sload(slot)\n }\n }\n\n /**\n * @return The address of the current LoanTokenLogicBeacon.\n */\n function beaconAddress() external view returns (address) {\n return _beaconAddress();\n }\n\n /**\n * @dev Set/update the new beacon address.\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon.\n */\n function _setBeaconAddress(address _newBeaconAddress) private {\n require(\n Address.isContract(_newBeaconAddress),\n \"Cannot set beacon address to a non-contract address\"\n );\n\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n\n assembly {\n sstore(slot, _newBeaconAddress)\n }\n }\n\n /**\n * @dev External function to set the new LoanTokenLogicBeacon Address\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon\n */\n function setBeaconAddress(address _newBeaconAddress) external onlyAdmin {\n _setBeaconAddress(_newBeaconAddress);\n }\n\n /**\n * @dev External function to return the LoanTokenLogicProxy of loan token (target of LoanToken contract).\n * Ideally this getter should be added in the LoanToken contract\n * but since LoanToken contract can't be changed, adding the getter in this contract will do\n * because it will use the context of LoanToken contract.\n *\n * @return target address of LoanToken contract\n */\n function getTarget() external view returns (address) {\n return target_;\n }\n}\n\ninterface ILoanTokenLogicBeacon {\n function getTarget(bytes4 functionSignature)\n external\n view\n returns (address logicTargetAddress);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicShared.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicStorage.sol\";\nimport \"./interfaces/ProtocolLike.sol\";\nimport \"./interfaces/FeedsLike.sol\";\nimport \"./interfaces/ProtocolSettingsLike.sol\";\nimport \"../../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../../farm/ILiquidityMining.sol\";\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../governance/Vesting/IVesting.sol\";\n\n/**\n * @dev This contract shares functions used by both LoanTokenLogicSplit and LoanTokenLogicStandard\n */\ncontract LoanTokenLogicShared is LoanTokenLogicStorage {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /**\n * @notice Update the user's checkpoint price and profit so far.\n * In this loan token contract, whenever some tokens are minted or burned,\n * the _updateCheckpoints() function is invoked to update the stats to\n * reflect the balance changes.\n *\n * @param _user The user address.\n * @param _oldBalance The user's previous balance.\n * @param _newBalance The user's updated balance.\n * @param _currentPrice The current loan token price.\n * */\n function _updateCheckpoints(\n address _user,\n uint256 _oldBalance,\n uint256 _newBalance,\n uint256 _currentPrice\n ) internal {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(_user, iToken_ProfitSoFar));\n\n int256 _currentProfit;\n if (_newBalance == 0) {\n _currentPrice = 0;\n } else if (_oldBalance != 0) {\n _currentProfit = _profitOf(slot, _oldBalance, _currentPrice, checkpointPrices_[_user]);\n }\n\n assembly {\n sstore(slot, _currentProfit)\n }\n\n checkpointPrices_[_user] = _currentPrice;\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice Transfer tokens, low level.\n * Checks allowance, updates sender and recipient balances\n * and updates checkpoints too.\n *\n * @param _from The tokens' owner.\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @param _allowanceAmount The amount of tokens allowed to transfer.\n *\n * @return Success true/false.\n * */\n function _internalTransferFrom(\n address _from,\n address _to,\n uint256 _value,\n uint256 _allowanceAmount\n ) internal returns (bool) {\n if (_allowanceAmount != uint256(-1)) {\n allowed[_from][msg.sender] = _allowanceAmount.sub(_value, \"14\");\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, _allowanceAmount, allowed[_from][msg.sender]);\n }\n\n require(_to != address(0), \"15\");\n\n uint256 _balancesFrom = balances[_from];\n uint256 _balancesFromNew = _balancesFrom.sub(_value, \"16\");\n balances[_from] = _balancesFromNew;\n\n uint256 _balancesTo = balances[_to];\n uint256 _balancesToNew = _balancesTo.add(_value);\n balances[_to] = _balancesToNew;\n\n /// @dev Handle checkpoint update.\n uint256 _currentPrice = tokenPrice();\n\n //checkpoints are not being used by the smart contract logic itself, but just for external use (query the profit)\n //only update the checkpoints of a user if he's not depositing to / withdrawing from the lending pool\n if (_from != liquidityMiningAddress && _to != liquidityMiningAddress) {\n _updateCheckpoints(_from, _balancesFrom, _balancesFromNew, _currentPrice);\n _updateCheckpoints(_to, _balancesTo, _balancesToNew, _currentPrice);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n /**\n * @notice Profit calculation based on checkpoints of price.\n * @param slot The user slot.\n * @param _balance The user balance.\n * @param _currentPrice The current price of the loan token.\n * @param _checkpointPrice The price of the loan token on checkpoint.\n * @return The profit of a user.\n * */\n function _profitOf(\n bytes32 slot,\n uint256 _balance,\n uint256 _currentPrice,\n uint256 _checkpointPrice\n ) internal view returns (int256 profitSoFar) {\n if (_checkpointPrice == 0) {\n return 0;\n }\n\n assembly {\n profitSoFar := sload(slot)\n }\n\n profitSoFar = int256(_currentPrice)\n .sub(int256(_checkpointPrice))\n .mul(int256(_balance))\n .div(sWEI_PRECISION)\n .add(profitSoFar);\n }\n\n /**\n * @notice Loan token price calculation considering unpaid interests.\n * @return The loan token price.\n * */\n function tokenPrice() public view returns (uint256 price) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _tokenPrice(_totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Get the total amount of loan tokens on debt.\n * Calls protocol getTotalPrincipal function.\n * In the context of borrowing, principal is the initial size of a loan.\n * It can also be the amount still owed on a loan. If you take out a\n * $50,000 mortgage, for example, the principal is $50,000. If you pay off\n * $30,000, the principal balance now consists of the remaining $20,000.\n *\n * @return The total amount of loan tokens on debt.\n * */\n function totalAssetBorrow() public view returns (uint256) {\n return\n ProtocolLike(sovrynContractAddress).getTotalPrincipal(address(this), loanTokenAddress);\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice .\n *\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param withdrawalAmount The amount of tokens to withdraw.\n *\n * @return msgValue The amount of rBTC sent minus the collateral on tokens.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = loanTokenAddress;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n _safeTransfer(_loanTokenAddress, sentAddresses.receiver, withdrawalAmount, \"\");\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n /**\n * This is a critical piece of code!\n * rBTC are supposed to be held by the contract itself, while other tokens are being transfered from the sender directly.\n * */\n if (collateralTokenSent != 0) {\n if (\n collateralTokenAddress == _wrbtcToken &&\n msgValue != 0 &&\n msgValue >= collateralTokenSent\n ) {\n IWrbtc(_wrbtcToken).deposit.value(collateralTokenSent)();\n _safeTransfer(\n collateralTokenAddress,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-a\"\n );\n msgValue -= collateralTokenSent;\n } else {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-b\"\n );\n }\n }\n\n if (loanTokenSent != 0) {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n\n /**\n * @notice Withdraw loan token interests from protocol.\n * This function only operates once per block.\n * It asks protocol to withdraw accrued interests for the loan token.\n *\n * @dev Internal sync required on every loan trade before starting.\n * */\n function _settleInterest() internal {\n uint88 ts = uint88(block.timestamp);\n if (lastSettleTime_ != ts) {\n ProtocolLike(sovrynContractAddress).withdrawAccruedInterest(loanTokenAddress);\n\n lastSettleTime_ = ts;\n }\n }\n\n /**\n * @notice Imitate a Solidity high-level call (i.e. a regular function\n * call to a contract), relaxing the requirement on the return value:\n * the return value is optional (but if data is returned, it must not be\n * false).\n *\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n * @param errorMsg The error message on failure.\n * */\n function _callOptionalReturn(\n address token,\n bytes memory data,\n string memory errorMsg\n ) internal {\n require(Address.isContract(token), \"call to a non-contract address\");\n (bool success, bytes memory returndata) = token.call(data);\n require(success, errorMsg);\n\n if (returndata.length != 0) {\n require(abi.decode(returndata, (bool)), errorMsg);\n }\n }\n\n /**\n * @notice Execute the ERC20 token's `transfer` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransfer(\n address token,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transfer.selector, to, amount),\n errorMsg\n );\n }\n\n /**\n * @notice Execute the ERC20 token's `transferFrom` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param from The source address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransferFrom(\n address token,\n address from,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transferFrom.selector, from, to, amount),\n errorMsg\n );\n }\n\n /** Internal view function */\n /**\n * @notice Compute the token price.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The token price.\n * */\n function _tokenPrice(uint256 assetSupply) internal view returns (uint256) {\n uint256 totalTokenSupply = totalSupply_;\n\n return\n totalTokenSupply != 0 ? assetSupply.mul(10**18).div(totalTokenSupply) : initialPrice;\n }\n\n /**\n * @notice Get two kind of interests: owed per day and yet to be paid.\n * @return interestOwedPerDay The interest per day.\n * @return interestUnPaid The interest not yet paid.\n * */\n function _getAllInterest()\n internal\n view\n returns (uint256 interestOwedPerDay, uint256 interestUnPaid)\n {\n /// interestPaid, interestPaidDate, interestOwedPerDay, interestUnPaid, interestFeePercent, principalTotal\n uint256 interestFeePercent;\n (, , interestOwedPerDay, interestUnPaid, interestFeePercent, ) = ProtocolLike(\n sovrynContractAddress\n )\n .getLenderInterestData(address(this), loanTokenAddress);\n\n interestUnPaid = interestUnPaid.mul(SafeMath.sub(10**20, interestFeePercent)).div(10**20);\n }\n\n /**\n * @notice Compute the total amount of loan tokens on supply.\n * @param interestUnPaid The interest not yet paid.\n * @return assetSupply The total amount of loan tokens on supply.\n * */\n function _totalAssetSupply(uint256 interestUnPaid)\n internal\n view\n returns (uint256 assetSupply)\n {\n if (totalSupply_ != 0) {\n uint256 assetsBalance = _flTotalAssetSupply; /// Temporary locked totalAssetSupply during a flash loan transaction.\n if (assetsBalance == 0) {\n assetsBalance = _underlyingBalance().add(totalAssetBorrow());\n }\n\n return assetsBalance.add(interestUnPaid);\n }\n }\n\n /**\n * @notice Get the loan contract balance.\n * @return The balance of the loan token for this contract.\n * */\n function _underlyingBalance() internal view returns (uint256) {\n return IERC20(loanTokenAddress).balanceOf(address(this));\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicSplit.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\n/**\n * @title Loan Token Logic Standard contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Logic around loan tokens (iTokens) required to operate borrowing,\n * and margin trading financial processes.\n *\n * The user provides funds to the lending pool using the mint function and\n * withdraws funds from the lending pool using the burn function. Mint and\n * burn refer to minting and burning loan tokens. Loan tokens represent a\n * share of the pool and gather interest over time.\n *\n * Interest rates are determined by supply and demand. When a lender deposits\n * funds, the interest rates go down. When a trader borrows funds, the\n * interest rates go up. Fulcrum uses a simple linear interest rate formula\n * of the form y = mx + b. The interest rate starts at 1% when loans aren't\n * being utilized and scales up to 40% when all the funds in the loan pool\n * are being borrowed.\n *\n * The borrow rate is determined at the time of the loan and represents the\n * net contribution of each borrower. Each borrower's interest contribution\n * is determined by the utilization rate of the pool and is netted against\n * all prior borrows. This means that the total amount of interest flowing\n * into the lending pool is not directly changed by lenders entering or\n * exiting the pool. The entrance or exit of lenders only impacts how the\n * interest payments are split up.\n *\n * For example, if there are 2 lenders with equal holdings each earning\n * 5% APR, but one of the lenders leave, then the remaining lender will earn\n * 10% APR since the interest payments don't have to be split between two\n * individuals.\n * */\ncontract LoanTokenLogicSplit is LoanTokenLogicShared {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /* Public functions */\n\n /**\n * @notice Mint loan token wrapper.\n * Adds a check before calling low level _mintToken function.\n * The function retrieves the tokens from the message sender, so make sure\n * to first approve the loan token contract to access your funds. This is\n * done by calling approve(address spender, uint amount) on the ERC20\n * token contract, where spender is the loan token contract address and\n * amount is the amount to be deposited.\n *\n * @param receiver The account getting the minted tokens.\n * @param depositAmount The amount of underlying tokens provided on the\n * loan. (Not the number of loan tokens to mint).\n *\n * @return The amount of loan tokens minted.\n * */\n function mint(address receiver, uint256 depositAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice Burn loan token wrapper.\n * Adds a pay-out transfer after calling low level _burnToken function.\n * In order to withdraw funds to the pool, call burn on the respective\n * loan token contract. This will burn your loan tokens and send you the\n * underlying token in exchange.\n *\n * @param receiver The account getting the minted tokens.\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 loanAmountPaid)\n {\n loanAmountPaid = _burnToken(burnAmount);\n\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (loanAmountPaid != 0) {\n _safeTransfer(loanTokenAddress, receiver, loanAmountPaid, \"5\");\n }\n }\n\n /**\n * @notice transfers the underlying asset from the msg.sender and mints tokens for the receiver\n * @param receiver the address of the iToken receiver\n * @param depositAmount the amount of underlying assets to be deposited\n * @return the amount of iTokens issued\n */\n function _mintToken(address receiver, uint256 depositAmount)\n internal\n returns (uint256 mintAmount)\n {\n uint256 currentPrice;\n\n //calculate amount to mint and transfer the underlying asset\n (mintAmount, currentPrice) = _prepareMinting(depositAmount);\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n receiver\n );\n uint256 oldBalance = balances[receiver].add(balanceOnLM);\n uint256 newBalance = oldBalance.add(mintAmount);\n\n //mint the tokens to the receiver\n _mint(receiver, mintAmount, depositAmount, currentPrice);\n\n //update the checkpoint of the receiver\n _updateCheckpoints(receiver, oldBalance, newBalance, currentPrice);\n }\n\n /**\n * calculates the amount of tokens to mint and transfers the underlying asset to this contract\n * @param depositAmount the amount of the underyling asset deposited\n * @return the amount to be minted\n */\n function _prepareMinting(uint256 depositAmount)\n internal\n returns (uint256 mintAmount, uint256 currentPrice)\n {\n require(depositAmount != 0, \"17\");\n\n _settleInterest();\n\n currentPrice = _tokenPrice(_totalAssetSupply(0));\n mintAmount = depositAmount.mul(10**18).div(currentPrice);\n\n if (msg.value == 0) {\n _safeTransferFrom(loanTokenAddress, msg.sender, address(this), depositAmount, \"18\");\n } else {\n IWrbtc(wrbtcTokenAddress).deposit.value(depositAmount)();\n }\n }\n\n /**\n * @notice A wrapper for AdvancedToken::_burn\n *\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function _burnToken(uint256 burnAmount) internal returns (uint256 loanAmountPaid) {\n require(burnAmount != 0, \"19\");\n\n if (burnAmount > balanceOf(msg.sender)) {\n require(burnAmount == uint256(-1), \"32\");\n burnAmount = balanceOf(msg.sender);\n }\n\n _settleInterest();\n\n uint256 currentPrice = _tokenPrice(_totalAssetSupply(0));\n\n uint256 loanAmountOwed = burnAmount.mul(currentPrice).div(10**18);\n uint256 loanAmountAvailableInContract = _underlyingBalance();\n\n loanAmountPaid = loanAmountOwed;\n require(loanAmountPaid <= loanAmountAvailableInContract, \"37\");\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n uint256 oldBalance = balances[msg.sender].add(balanceOnLM);\n uint256 newBalance = oldBalance.sub(burnAmount);\n\n _burn(msg.sender, burnAmount, loanAmountPaid, currentPrice);\n\n //this function does not only update the checkpoints but also the current profit of the user\n //all for external use only\n _updateCheckpoints(msg.sender, oldBalance, newBalance, currentPrice);\n }\n\n function _mintWithLM(address receiver, uint256 depositAmount)\n internal\n returns (uint256 minted)\n {\n //mint the tokens for the receiver\n minted = _mintToken(receiver, depositAmount);\n\n //transfer the tokens from the receiver to the LM address\n _internalTransferFrom(receiver, liquidityMiningAddress, minted, minted);\n\n //inform the LM mining contract\n ILiquidityMining(liquidityMiningAddress).onTokensDeposited(receiver, minted);\n }\n\n function _burnFromLM(uint256 burnAmount) internal returns (uint256) {\n uint256 balanceOnLM =\n ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n require(balanceOnLM.add(balanceOf(msg.sender)) >= burnAmount, \"not enough balance\");\n\n if (balanceOnLM > 0) {\n //withdraw pool tokens and LM rewards to the passed address\n if (balanceOnLM < burnAmount) {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n balanceOnLM,\n msg.sender\n );\n } else {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n burnAmount,\n msg.sender\n );\n }\n }\n //burn the tokens of the msg.sender\n return _burnToken(burnAmount);\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStandard.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\ncontract LoanTokenLogicStandard is LoanTokenLogicShared {\n /**\n * @notice Transfer tokens wrapper.\n * Sets token owner the msg.sender.\n * Sets maximun allowance uint256(-1) to ensure tokens are always transferred.\n *\n * If the recipient (_to) is a vesting contract address, transfer the token to the tokenOwner of the vesting contract itself.\n *\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @return Success true/false.\n * */\n function transfer(address _to, uint256 _value) external returns (bool) {\n /** need additional check address(0) here to support backward compatibility\n * in case we don't want to activate this check, just need to set the stakingContractAddress to 0 address\n */\n if (\n stakingContractAddress != address(0) &&\n IStaking(stakingContractAddress).isVestingContract(_to)\n ) {\n (bool success, bytes memory data) =\n _to.staticcall(abi.encodeWithSelector(IVesting(_to).tokenOwner.selector));\n\n if (success) _to = abi.decode(data, (address));\n }\n\n return _internalTransferFrom(msg.sender, _to, _value, uint256(-1));\n }\n\n /**\n * @notice Moves `_value` loan tokens from `_from` to `_to` using the\n * allowance mechanism. Calls internal _internalTransferFrom function.\n *\n * @return A boolean value indicating whether the operation succeeded.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool) {\n return\n _internalTransferFrom(\n _from,\n _to,\n _value,\n //allowed[_from][msg.sender]\n ProtocolLike(sovrynContractAddress).isLoanPool(msg.sender)\n ? uint256(-1)\n : allowed[_from][msg.sender]\n );\n }\n\n /**\n * @notice Borrow funds from the pool.\n * The underlying loan token may not be used as collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * (150% of the withdrawn amount worth in collateral tokens).\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param borrower The one paying for the collateral.\n * @param receiver The one receiving the withdrawn amount.\n *\n * @return New principal and new collateral added to loan.\n * */\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes memory /// loanDataBytes: arbitrary order data (for future use).\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n )\n {\n require(withdrawAmount != 0, \"6\");\n\n _checkPause();\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n\n require(\n (msg.value == 0 || msg.value == collateralTokenSent) &&\n (collateralTokenSent != 0 || loanId != 0) &&\n (collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0) &&\n (loanId == 0 || msg.sender == borrower),\n \"7\"\n );\n\n /// @dev We have an issue regarding contract size code is too big. 1 of the solution is need to keep the error message 32 bytes length\n // Temporarily, we combine this require to the above, so can save the contract size code\n // require(collateralTokenSent != 0 || loanId != 0, \"8\");\n // require(collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0, \"9\");\n\n /// @dev Ensure authorized use of existing loan.\n // require(loanId == 0 || msg.sender == borrower, \"401 use of existing loan\");\n\n /// @dev The condition is never met.\n /// Address zero is not allowed by previous require validation.\n /// This check is unneeded and was lowering the test coverage index.\n // if (collateralTokenAddress == address(0)) {\n // \tcollateralTokenAddress = wrbtcTokenAddress;\n // }\n\n require(collateralTokenAddress != loanTokenAddress, \"10\");\n\n _settleInterest();\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this); /// The lender.\n sentAddresses.borrower = borrower;\n sentAddresses.receiver = receiver;\n /// sentAddresses.manager = address(0); /// The manager.\n\n sentAmounts.newPrincipal = withdrawAmount;\n\n /// interestRate, interestInitialAmount, borrowAmount (newBorrowAmount).\n (\n sentAmounts.interestRate,\n sentAmounts.interestInitialAmount,\n sentAmounts.newPrincipal\n ) = _getInterestRateAndBorrowAmount(\n sentAmounts.newPrincipal,\n _totalAssetSupply(0), /// Interest is settled above.\n initialLoanDuration\n );\n\n /// sentAmounts.loanTokenSent = 0; /// loanTokenSent\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n return\n _borrowOrTrade(\n loanId,\n withdrawAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ]\n ),\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Borrow and immediately get into a position.\n *\n * Trading on margin is used to increase an investor's buying power.\n * Margin is the amount of money required to open a position, while\n * leverage is the multiple of exposure to account equity.\n *\n * Leverage allows you to trade positions LARGER than the amount\n * of money in your trading account. Leverage is expressed as a ratio.\n *\n * When trading on margin, investors first deposit some token that then\n * serves as collateral for the loan, and then pay ongoing interest\n * payments on the money they borrow.\n *\n * Margin trading = taking a loan and swapping it:\n * In order to open a margin trade position,\n * 1.- The user calls marginTrade on the loan token contract.\n * 2.- The loan token contract provides the loan and sends it for processing\n * to the protocol proxy contract.\n * 3.- The protocol proxy contract uses the module LoanOpening to create a\n * position and swaps the loan tokens to collateral tokens.\n * 4.- The Sovryn Swap network looks up the correct converter and swaps the\n * tokens.\n * If successful, the position is being held by the protocol proxy contract,\n * which is why positions need to be closed at the protocol proxy contract.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n * */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // value of loan token in collateral\n bytes memory loanDataBytes /// Arbitrary order data.\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n _checkPause();\n\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n require(collateralTokenAddress != loanTokenAddress, \"11\");\n\n /// @dev Ensure authorized use of existing loan.\n require(loanId == 0 || msg.sender == trader, \"401 use of existing loan\");\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n if (transactionLimit[loanTokenAddress] > 0)\n require(loanTokenSent <= transactionLimit[loanTokenAddress]);\n\n /// @dev Compute the worth of the total deposit in loan tokens.\n /// (loanTokenSent + convert(collateralTokenSent))\n /// No actual swap happening here.\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n require(totalDeposit != 0, \"12\");\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this);\n sentAddresses.borrower = trader;\n sentAddresses.receiver = trader;\n /// sentAddresses.manager = address(0); /// The manager.\n\n /// sentAmounts.interestRate = 0; /// interestRate (found later).\n sentAmounts.newPrincipal = totalDeposit;\n /// sentAmounts.interestInitialAmount = 0; /// interestInitialAmount (interest is calculated based on fixed-term loan).\n sentAmounts.loanTokenSent = loanTokenSent;\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n _settleInterest();\n\n (sentAmounts.newPrincipal, sentAmounts.interestRate) = _getMarginBorrowAmountAndRate( /// borrowAmount, interestRate\n leverageAmount,\n sentAmounts.newPrincipal /// depositAmount\n );\n\n require(\n _getAmountInRbtc(loanTokenAddress, sentAmounts.newPrincipal) > TINY_AMOUNT,\n \"principal too small\"\n );\n\n /// @dev Converting to initialMargin\n leverageAmount = SafeMath.div(10**38, leverageAmount);\n sentAmounts.minEntryPrice = minEntryPrice;\n return\n _borrowOrTrade(\n loanId,\n 0, /// withdrawAmount\n leverageAmount, //initial margin\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n );\n }\n\n /**\n * @notice Wrapper for marginTrade invoking setAffiliatesReferrer to track\n * referral trade by affiliates program.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param affiliateReferrer The address of the referrer from affiliates program.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n */\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, /// Value of loan token in collateral\n address affiliateReferrer, /// The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n if (affiliateReferrer != address(0))\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(\n trader,\n affiliateReferrer\n );\n return\n marginTrade(\n loanId,\n leverageAmount,\n loanTokenSent,\n collateralTokenSent,\n collateralTokenAddress,\n trader,\n minEntryPrice,\n loanDataBytes\n );\n }\n\n /* Public View functions */\n\n /**\n * @notice Wrapper for internal _profitOf low level function.\n * @param user The user address.\n * @return The profit of a user.\n * */\n function profitOf(address user) external view returns (int256) {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(user, iToken_ProfitSoFar));\n //TODO + LM balance\n return _profitOf(slot, balances[user], tokenPrice(), checkpointPrices_[user]);\n }\n\n /**\n * @notice Getter for the price checkpoint mapping.\n * @param _user The user account as the mapping index.\n * @return The price on the checkpoint for this user.\n * */\n function checkpointPrice(address _user) public view returns (uint256 price) {\n return checkpointPrices_[_user];\n }\n\n /**\n * @notice Get current liquidity.\n * A part of total funds supplied are borrowed. Liquidity = supply - borrow\n * @return The market liquidity.\n * */\n function marketLiquidity() public view returns (uint256) {\n uint256 totalSupply = _totalAssetSupply(0);\n uint256 totalBorrow = totalAssetBorrow();\n if (totalSupply > totalBorrow) {\n return totalSupply - totalBorrow;\n }\n }\n\n /**\n * @notice Wrapper for average borrow interest.\n * @return The average borrow interest.\n * */\n function avgBorrowInterestRate() public view returns (uint256) {\n return _avgBorrowInterestRate(totalAssetBorrow());\n }\n\n /**\n * @notice Get borrow interest rate.\n * The minimum rate the next base protocol borrower will receive\n * for variable-rate loans.\n * @return The borrow interest rate.\n * */\n function borrowInterestRate() public view returns (uint256) {\n return _nextBorrowInterestRate(0);\n }\n\n /**\n * @notice Public wrapper for internal call.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest rate.\n * */\n function nextBorrowInterestRate(uint256 borrowAmount) public view returns (uint256) {\n return _nextBorrowInterestRate(borrowAmount);\n }\n\n /**\n * @notice Get interest rate.\n *\n * @return Interest that lenders are currently receiving when supplying to\n * the pool.\n * */\n function supplyInterestRate() public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0));\n }\n\n /**\n * @notice Get interest rate w/ added supply.\n * @param supplyAmount The amount of tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of tokens to the pool.\n * */\n function nextSupplyInterestRate(uint256 supplyAmount) public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0).add(supplyAmount));\n }\n\n /**\n * @notice Get interest rate w/ added supply assets.\n * @param assetSupply The amount of loan tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of loan tokens to the pool.\n * */\n function totalSupplyInterestRate(uint256 assetSupply) public view returns (uint256) {\n uint256 assetBorrow = totalAssetBorrow();\n if (assetBorrow != 0) {\n return calculateSupplyInterestRate(assetBorrow, assetSupply);\n }\n }\n\n /**\n * @notice Get the total amount of loan tokens on supply.\n * @dev Wrapper for internal _totalAssetSupply function.\n * @return The total amount of loan tokens on supply.\n * */\n function totalAssetSupply() public view returns (uint256) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _totalAssetSupply(interestUnPaid);\n }\n\n /**\n * @notice Compute the maximum deposit amount under current market conditions.\n * @dev maxEscrowAmount = liquidity * (100 - interestForDuration) / 100\n * @param leverageAmount The chosen multiplier with 18 decimals.\n * */\n function getMaxEscrowAmount(uint256 leverageAmount)\n public\n view\n returns (uint256 maxEscrowAmount)\n {\n /**\n * @dev Mathematical imperfection: depending on liquidity we might be able\n * to borrow more if utilization is below the kink level.\n * */\n uint256 interestForDuration = maxScaleRate.mul(28).div(365);\n uint256 factor = uint256(10**20).sub(interestForDuration);\n uint256 maxLoanSize = marketLiquidity().mul(factor).div(10**20);\n maxEscrowAmount = maxLoanSize.mul(10**18).div(leverageAmount);\n }\n\n /**\n * @notice Get loan token balance.\n * @return The user's balance of underlying token.\n * */\n function assetBalanceOf(address _owner) public view returns (uint256) {\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0)) {\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n _owner\n );\n }\n return balanceOf(_owner).add(balanceOnLM).mul(tokenPrice()).div(10**18);\n }\n\n /**\n * @notice Get margin information on a trade.\n *\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The principal, the collateral and the interestRate.\n * */\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n public\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n )\n {\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n\n (principal, interestRate) = _getMarginBorrowAmountAndRate(leverageAmount, totalDeposit);\n if (principal > _underlyingBalance()) {\n return (0, 0, 0);\n }\n\n loanTokenSent = loanTokenSent.add(principal);\n\n collateral = ProtocolLike(sovrynContractAddress).getEstimatedMarginExposure(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent,\n collateralTokenSent,\n interestRate,\n principal\n );\n }\n\n /**\n * @notice Calculate the deposit required to a given borrow.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param borrowAmount The amount of borrow.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of deposit required.\n * */\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 depositAmount) {\n if (borrowAmount != 0) {\n (, , uint256 newBorrowAmount) =\n _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (newBorrowAmount <= _underlyingBalance()) {\n if (collateralTokenAddress == address(0))\n collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ];\n return\n ProtocolLike(sovrynContractAddress)\n .getRequiredCollateral(\n loanTokenAddress,\n collateralTokenAddress,\n newBorrowAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin\n true /// isTorqueLoan\n )\n .add(10); /// Some dust to compensate for rounding errors.\n }\n }\n }\n\n /**\n * @notice Calculate the borrow allowed for a given deposit.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param depositAmount The amount of deposit.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of borrow allowed.\n * */\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 borrowAmount) {\n if (depositAmount != 0) {\n if (collateralTokenAddress == address(0)) collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))];\n borrowAmount = ProtocolLike(sovrynContractAddress).getBorrowAmount(\n loanTokenAddress,\n collateralTokenAddress,\n depositAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin,\n true /// isTorqueLoan\n );\n\n (, , borrowAmount) = _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (borrowAmount > _underlyingBalance()) {\n borrowAmount = 0;\n }\n }\n }\n\n /**\n * @notice Check if entry price lies above a minimum\n *\n * @param loanTokenSent The amount of deposit.\n * @param collateralTokenAddress The token address of collateral.\n * @param minEntryPrice Value of loan token in collateral\n * */\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) public view {\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokensReceived =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent\n );\n uint256 collateralTokenPrice =\n (collateralTokensReceived.mul(WEI_PRECISION)).div(loanTokenSent);\n require(collateralTokenPrice >= minEntryPrice, \"entry price above the minimum\");\n }\n\n /**\n * @notice Compute the next supply interest adjustment.\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next supply interest adjustment.\n * */\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n public\n view\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply >= assetBorrow) {\n return\n _avgBorrowInterestRate(assetBorrow)\n .mul(_utilizationRate(assetBorrow, assetSupply))\n .mul(\n SafeMath.sub(10**20, ProtocolLike(sovrynContractAddress).lendingFeePercent())\n )\n .div(10**40);\n }\n }\n\n /* Internal functions */\n\n /**\n * @notice Compute what the deposit is worth in loan tokens using the swap rate\n * used for loan size computation.\n *\n * @param collateralTokenAddress The token address of the collateral.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param loanTokenSent The number of loan tokens provided by the user.\n *\n * @return The value of the deposit in loan tokens.\n * */\n function _totalDeposit(\n address collateralTokenAddress,\n uint256 collateralTokenSent,\n uint256 loanTokenSent\n ) internal view returns (uint256 totalDeposit) {\n totalDeposit = loanTokenSent;\n\n if (collateralTokenSent != 0) {\n /// @dev Get the oracle rate from collateral -> loan\n (uint256 collateralToLoanRate, uint256 collateralToLoanPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n collateralTokenAddress,\n loanTokenAddress\n );\n require(\n (collateralToLoanRate != 0) && (collateralToLoanPrecision != 0),\n \"invalid rate collateral token\"\n );\n\n /// @dev Compute the loan token amount with the oracle rate.\n uint256 loanTokenAmount =\n collateralTokenSent.mul(collateralToLoanRate).div(collateralToLoanPrecision);\n\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokenAmount =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenAmount\n );\n\n /// @dev Probably not the same due to the price difference.\n if (collateralTokenAmount != collateralTokenSent) {\n //scale the loan token amount accordingly, so we'll get the expected position size in the end\n loanTokenAmount = loanTokenAmount.mul(collateralTokenAmount).div(\n collateralTokenSent\n );\n }\n\n totalDeposit = loanTokenAmount.add(totalDeposit);\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n asset,\n wrbtcTokenAddress\n );\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /*\n * @notice Compute interest rate and other loan parameters.\n *\n * @param borrowAmount The amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n *\n * @return The interest rate, the interest calculated based on fixed-term\n * loan, and the new borrow amount.\n * */\n function _getInterestRateAndBorrowAmount(\n uint256 borrowAmount,\n uint256 assetSupply,\n uint256 initialLoanDuration /// Duration in seconds.\n )\n internal\n view\n returns (\n uint256 interestRate,\n uint256 interestInitialAmount,\n uint256 newBorrowAmount\n )\n {\n interestRate = _nextBorrowInterestRate2(borrowAmount, assetSupply);\n\n /// newBorrowAmount = borrowAmount * 10^18 / (10^18 - interestRate * 7884000 * 10^18 / 31536000 / 10^20)\n newBorrowAmount = borrowAmount.mul(10**18).div(\n SafeMath.sub(\n 10**18,\n interestRate.mul(initialLoanDuration).mul(10**18).div(31536000 * 10**20) /// 365 * 86400 * 10**20\n )\n );\n\n interestInitialAmount = newBorrowAmount.sub(borrowAmount);\n }\n\n /**\n * @notice Compute principal and collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialMargin The initial margin with 18 decimals\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return The new principal and the new collateral. Principal is the\n * complete borrowed amount (in loan tokens). Collateral is the complete\n * position size (loan + margin) (in collateral tokens).\n * */\n function _borrowOrTrade(\n bytes32 loanId,\n uint256 withdrawAmount,\n uint256 initialMargin,\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n _checkPause();\n require(\n sentAmounts.newPrincipal <= _underlyingBalance() && /// newPrincipal (borrowed amount + fees)\n sentAddresses.borrower != address(0), /// The borrower.\n \"24\"\n );\n\n if (sentAddresses.receiver == address(0)) {\n sentAddresses.receiver = sentAddresses.borrower; /// The receiver = the borrower.\n }\n\n /// @dev Handle transfers prior to adding newPrincipal to loanTokenSent\n uint256 msgValue =\n _verifyTransfers(collateralTokenAddress, sentAddresses, sentAmounts, withdrawAmount);\n\n /**\n * @dev Adding the loan token portion from the lender to loanTokenSent\n * (add the loan to the loan tokens sent from the user).\n * */\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.add(sentAmounts.newPrincipal); /// newPrincipal\n\n if (withdrawAmount != 0) {\n /// @dev withdrawAmount already sent to the borrower, so we aren't sending it to the protocol.\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.sub(withdrawAmount);\n }\n\n bool withdrawAmountExist = false; /// Default is false, but added just as to make sure.\n\n if (withdrawAmount != 0) {\n withdrawAmountExist = true;\n }\n\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, withdrawAmountExist)))\n ];\n\n (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent) = ProtocolLike(\n sovrynContractAddress\n )\n .borrowOrTradeFromPool\n .value(msgValue)(\n loanParamsId,\n loanId,\n withdrawAmountExist,\n initialMargin,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n ); /// newPrincipal, newCollateral\n require(sentAmounts.newPrincipal != 0, \"25\");\n\n /// @dev Setting not-first-trade flag to prevent binding to an affiliate existing users post factum.\n /// @dev REFACTOR: move to a general interface: ProtocolSettingsLike?\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(\n sentAddresses.borrower\n );\n\n return (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent); // newPrincipal, newCollateral\n }\n\n /* Internal View functions */\n\n /**\n * @notice Compute the average borrow interest rate.\n * @param assetBorrow The amount of loan tokens on debt.\n * @return The average borrow interest rate.\n * */\n function _avgBorrowInterestRate(uint256 assetBorrow) internal view returns (uint256) {\n if (assetBorrow != 0) {\n (uint256 interestOwedPerDay, ) = _getAllInterest();\n return interestOwedPerDay.mul(10**20).mul(365).div(assetBorrow);\n }\n }\n\n /**\n * @notice Compute the next borrow interest adjustment.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate(uint256 borrowAmount) internal view returns (uint256) {\n uint256 interestUnPaid;\n if (borrowAmount != 0) {\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n uint256 balance = _underlyingBalance().add(interestUnPaid);\n if (borrowAmount > balance) {\n borrowAmount = balance;\n }\n }\n\n return _nextBorrowInterestRate2(borrowAmount, _totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Compute the next borrow interest adjustment under target-kink\n * level analysis.\n *\n * The \"kink\" in the cDAI interest rate model reflects the utilization rate\n * at which the slope of the interest rate goes from \"gradual\" to \"steep\".\n * That is, below this utilization rate, the slope of the interest rate\n * curve is gradual. Above this utilization rate, it is steep.\n *\n * Because of this dynamic between the interest rate curves before and\n * after the \"kink\", the \"kink\" can be thought of as the target utilization\n * rate. Above that rate, it quickly becomes expensive to borrow (and\n * commensurately lucrative for suppliers).\n *\n * @param newBorrowAmount The new amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate2(uint256 newBorrowAmount, uint256 assetSupply)\n internal\n view\n returns (uint256 nextRate)\n {\n uint256 utilRate = _utilizationRate(totalAssetBorrow().add(newBorrowAmount), assetSupply);\n\n uint256 thisMinRate;\n uint256 thisRateAtKink;\n uint256 thisBaseRate = baseRate;\n uint256 thisRateMultiplier = rateMultiplier;\n uint256 thisTargetLevel = targetLevel;\n uint256 thisKinkLevel = kinkLevel;\n uint256 thisMaxScaleRate = maxScaleRate;\n\n if (utilRate < thisTargetLevel) {\n // target targetLevel utilization when utilization is under targetLevel\n utilRate = thisTargetLevel;\n }\n\n if (utilRate > thisKinkLevel) {\n /// @dev Scale rate proportionally up to 100%\n uint256 thisMaxRange = WEI_PERCENT_PRECISION - thisKinkLevel; /// Will not overflow.\n\n utilRate -= thisKinkLevel;\n if (utilRate > thisMaxRange) utilRate = thisMaxRange;\n\n // Modified the rate calculation as it is slightly exaggerated around kink level\n // thisRateAtKink = thisRateMultiplier.add(thisBaseRate).mul(thisKinkLevel).div(WEI_PERCENT_PRECISION);\n thisRateAtKink = thisKinkLevel.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n nextRate = utilRate\n .mul(SafeMath.sub(thisMaxScaleRate, thisRateAtKink))\n .div(thisMaxRange)\n .add(thisRateAtKink);\n } else {\n nextRate = utilRate.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n thisMinRate = thisBaseRate;\n thisRateAtKink = thisRateMultiplier.add(thisBaseRate);\n\n if (nextRate < thisMinRate) nextRate = thisMinRate;\n else if (nextRate > thisRateAtKink) nextRate = thisRateAtKink;\n }\n }\n\n /**\n * @notice Compute the loan size and interest rate.\n * @param leverageAmount The leverage with 18 decimals.\n * @param depositAmount The amount the user deposited in underlying loan tokens.\n * @return borrowAmount The amount of tokens to borrow.\n * @return interestRate The interest rate to pay on the position.\n * */\n function _getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n internal\n view\n returns (uint256 borrowAmount, uint256 interestRate)\n {\n uint256 loanSizeBeforeInterest = depositAmount.mul(leverageAmount).div(10**18);\n /**\n * @dev Mathematical imperfection. we calculate the interest rate based on\n * the loanSizeBeforeInterest, but the actual borrowed amount will be bigger.\n * */\n interestRate = _nextBorrowInterestRate2(loanSizeBeforeInterest, _totalAssetSupply(0));\n /// @dev Assumes that loan, collateral, and interest token are the same.\n borrowAmount = _adjustLoanSize(interestRate, 28 days, loanSizeBeforeInterest);\n }\n\n /**\n * @notice Make sure call is not paused.\n * @dev Used for internal verification if the called function is paused.\n * It throws an exception in case it's not.\n * */\n function _checkPause() internal view {\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n msg.sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n bool isPaused;\n assembly {\n isPaused := sload(slot)\n }\n require(!isPaused, \"unauthorized\");\n }\n\n /**\n * @notice Adjusts the loan size to make sure the expected exposure remains after prepaying the interest.\n * @dev loanSizeWithInterest = loanSizeBeforeInterest * 100 / (100 - interestForDuration)\n * @param interestRate The interest rate to pay on the position.\n * @param maxDuration The maximum duration of the position (until rollover).\n * @param loanSizeBeforeInterest The loan size before interest is added.\n * */\n function _adjustLoanSize(\n uint256 interestRate,\n uint256 maxDuration,\n uint256 loanSizeBeforeInterest\n ) internal pure returns (uint256 loanSizeWithInterest) {\n uint256 interestForDuration = interestRate.mul(maxDuration).div(365 days);\n uint256 divisor = uint256(10**20).sub(interestForDuration);\n loanSizeWithInterest = loanSizeBeforeInterest.mul(10**20).div(divisor);\n }\n\n /**\n * @notice Calculate the utilization rate.\n * @dev Utilization rate = assetBorrow / assetSupply\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The utilization rate.\n * */\n function _utilizationRate(uint256 assetBorrow, uint256 assetSupply)\n internal\n pure\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply != 0) {\n /// U = total_borrow / total_supply\n return assetBorrow.mul(10**20).div(assetSupply);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./AdvancedToken.sol\";\n\ncontract LoanTokenLogicStorage is AdvancedToken {\n /// DO NOT ADD VARIABLES HERE - SEE BELOW\n\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /// @dev Add new variables here on the bottom.\n address public earlyAccessToken; //not used anymore, but staying for upgradability\n address public pauser;\n /** The address of the liquidity mining contract */\n address public liquidityMiningAddress;\n\n /** The address of the staking contract */\n address public stakingContractAddress;\n\n /// @dev Used by flashBorrow function.\n uint256 public constant VERSION = 6;\n /// @dev Used by flashBorrow function.\n address internal constant arbitraryCaller = 0x000F400e6818158D541C3EBE45FE3AA0d47372FF;\n bytes32 internal constant iToken_ProfitSoFar =\n 0x37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb6; // keccak256(\"iToken_ProfitSoFar\")\n uint256 public constant TINY_AMOUNT = 25e13;\n\n function stringToBytes32(string memory source) public pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"unauthorized\"); // SS02\n _;\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogic is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenMintAndBurn also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenLogicStandard also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\")); /// LoanTokenLogicStandard\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\")); /// LoanTokenLogicLM\n res[2] = bytes4(keccak256(\"burn(address,uint256)\")); /// LoanTokenLogicStandard\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\")); /// LoanTokenLogicLM\n\n return (res, stringToBytes32(\"LoanTokenLogicLM\"));\n }\n\n /**\n * @notice deposit into the lending pool and optionally participate at the Liquidity Mining Program\n * @param receiver the receiver of the tokens\n * @param depositAmount The amount of underlying tokens provided on the loan.\n *\t\t\t\t\t\t(Not the number of loan tokens to mint).\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 minted) {\n if (useLM) return _mintWithLM(receiver, depositAmount);\n else return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice withdraws from the lending pool and optionally retrieves the pool tokens from the\n * Liquidity Mining Contract\n * @param receiver the receiver of the underlying tokens. note: potetial LM rewards are always sent to the msg.sender\n * @param burnAmount The amount of pool tokens to redeem.\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 redeemed) {\n if (useLM) redeemed = _burnFromLM(burnAmount);\n else redeemed = _burnToken(burnAmount);\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (redeemed != 0) {\n _safeTransfer(loanTokenAddress, receiver, redeemed, \"asset transfer failed\");\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtc.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogicWrbtc is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtc\"));\n }\n\n /**\n * @dev internal override functions\n * @dev Put all of internal override function dedicated to the loanTokenWrtbc module here\n * e.g: _verifyTransfers will override the implementation of _verifyTransfers in loanTokenLogicSplit\n */\n\n /**\n * @notice Handle transfers prior to adding newPrincipal to loanTokenSent.\n *\n * @param collateralTokenAddress The address of the collateral token.\n * @param sentAddresses The struct which contains addresses of\n * - lender\n * - borrower\n * - receiver\n * - manager\n *\n * @param sentAmounts The struct which contains uint256 of:\n * - interestRate\n * - newPrincipal\n * - interestInitialAmount\n * - loanTokenSent\n * - collateralTokenSent\n *\n * @param withdrawalAmount The amount to withdraw.\n *\n * @return msgValue The amount of value sent.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = _wrbtcToken;\n address receiver = sentAddresses.receiver;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n IWrbtcERC20(_wrbtcToken).withdraw(withdrawalAmount);\n Address.sendValue(receiver, withdrawalAmount);\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n\n if (collateralTokenSent != 0) {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28\"\n );\n }\n\n if (loanTokenSent != 0) {\n if (msgValue != 0 && msgValue >= loanTokenSent) {\n IWrbtc(_wrbtcToken).deposit.value(loanTokenSent)();\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, loanTokenSent, \"29\");\n msgValue -= loanTokenSent;\n } else {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtcLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicWrbtcLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token Mint and Burn.\n res[0] = this.mint.selector;\n res[1] = this.burn.selector;\n\n // Loan Token WRBTC\n res[2] = this.mintWithBTC.selector;\n res[3] = this.burnToBTC.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtcLM\"));\n }\n\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n if (useLM) return _mintWithLM(receiver, msg.value);\n else return _mintToken(receiver, msg.value);\n }\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 loanAmountPaid) {\n loanAmountPaid = useLM ? _burnFromLM(burnAmount) : _burnToken(burnAmount);\n\n if (loanAmountPaid != 0) {\n IWrbtcERC20(wrbtcTokenAddress).withdraw(loanAmountPaid);\n Address.sendValue(receiver, loanAmountPaid);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/shared/LoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../AdvancedToken.sol\";\nimport \"../../interfaces/ProtocolSettingsLike.sol\";\nimport \"../../LoanTokenLogicStorage.sol\";\n\ncontract LoanTokenSettingsLowerAdmin is LoanTokenLogicStorage {\n using SafeMath for uint256;\n\n /// @dev TODO: Check for restrictions in this contract.\n modifier onlyAdmin() {\n require(isOwner() || msg.sender == admin, \"unauthorized\");\n _;\n }\n\n /* Events */\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](15);\n res[0] = this.setAdmin.selector;\n res[1] = this.setPauser.selector;\n res[2] = this.setupLoanParams.selector;\n res[3] = this.disableLoanParams.selector;\n res[4] = this.setDemandCurve.selector;\n res[5] = this.toggleFunctionPause.selector;\n res[6] = this.setTransactionLimits.selector;\n res[7] = this.changeLoanTokenNameAndSymbol.selector;\n res[8] = this.pauser.selector;\n res[9] = this.setLiquidityMiningAddress.selector;\n res[10] = this.withdrawRBTCTo.selector;\n res[11] = this.getLiquidityMiningAddress.selector;\n res[12] = this.checkPause.selector;\n res[13] = this.setStakingContractAddress.selector;\n res[14] = this.getStakingContractAddress.selector;\n return (res, stringToBytes32(\"LoanTokenSettingsLowerAdmin\"));\n }\n\n /**\n * @notice Set admin account.\n * @param _admin The address of the account to grant admin permissions.\n * */\n function setAdmin(address _admin) public onlyOwner {\n admin = _admin;\n }\n\n /**\n * @notice Set pauser account.\n * @param _pauser The address of the account to grant pause permissions.\n * */\n function setPauser(address _pauser) public onlyOwner {\n pauser = _pauser;\n }\n\n /**\n * @notice Fallback function not allowed\n * */\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n /**\n * @notice Set loan token parameters.\n *\n * @param loanParamsList The array of loan parameters.\n * @param areTorqueLoans Whether the loan is a torque loan.\n * */\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans /// isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n /**\n * @notice Disable loan token parameters.\n *\n * @param collateralTokens The array of collateral tokens.\n * @param isTorqueLoans Whether the loan is a torque loan.\n * */\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n /**\n * @notice Set loan token parameters about the demand curve.\n *\n * @dev These params should be percentages represented\n * like so: 5% = 5000000000000000000 /// 18 digits precision.\n * rateMultiplier + baseRate can't exceed 100%\n *\n * To maintain a healthy credit score, it's important to keep your\n * credit utilization rate (CUR) low (_lowUtilBaseRate). In general\n * you don't want your CUR to exceed 30%, but increasingly financial\n * experts are recommending that you don't want to go above 10% if you\n * really want an excellent credit score.\n *\n * Interest rates tend to cluster around the kink level of a kinked\n * interest rate model. More info at https://arxiv.org/pdf/2006.13922.pdf\n * and https://compound.finance/governance/proposals/12\n *\n * @param _baseRate The interest rate.\n * @param _rateMultiplier The precision multiplier for base rate.\n * @param _lowUtilBaseRate The credit utilization rate (CUR) low value.\n * @param _lowUtilRateMultiplier The precision multiplier for low util base rate.\n * @param _targetLevel The target level.\n * @param _kinkLevel The level that interest rates cluster on kinked model.\n * @param _maxScaleRate The maximum rate of the scale.\n * */\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; /// 80 ether\n kinkLevel = _kinkLevel; /// 90 ether\n maxScaleRate = _maxScaleRate; /// 100 ether\n }\n\n /**\n * @notice Set the pause flag for a function to true or false.\n *\n * @dev Combining the hash of \"iToken_FunctionPause\" string and a function\n * selector gets a slot to write a flag for pause state.\n *\n * @param funcId The ID of a function, the selector.\n * @param isPaused true/false value of the flag.\n * */\n function toggleFunctionPause(\n string memory funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyPauserOrOwner {\n bool paused;\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n paused := sload(slot)\n }\n require(paused != isPaused, \"isPaused is already set to that value\");\n assembly {\n sstore(slot, isPaused)\n }\n emit ToggledFunctionPaused(funcId, !isPaused, isPaused);\n }\n\n /**\n * Set the transaction limit per token address.\n * @param addresses The token addresses.\n * @param limits The limit denominated in the currency of the token address.\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyAdmin\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n\n /**\n *\t@notice Update the loan token parameters.\n *\t@param _name The new name of the loan token.\n *\t@param _symbol The new symbol of the loan token.\n * */\n function changeLoanTokenNameAndSymbol(string memory _name, string memory _symbol)\n public\n onlyAdmin\n {\n name = _name;\n symbol = _symbol;\n }\n\n /**\n * @notice Withdraws RBTC from the contract by Multisig.\n * @param _receiverAddress The address where the rBTC has to be transferred.\n * @param _amount The amount of rBTC to be transferred.\n */\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external onlyOwner {\n require(_receiverAddress != address(0), \"receiver address invalid\");\n require(_amount > 0, \"non-zero withdraw amount expected\");\n require(_amount <= address(this).balance, \"withdraw amount cannot exceed balance\");\n _receiverAddress.transfer(_amount);\n emit WithdrawRBTCTo(_receiverAddress, _amount);\n }\n\n /**\n * @notice sets the liquidity mining contract address\n * @param LMAddress the address of the liquidity mining contract\n */\n function setLiquidityMiningAddress(address LMAddress) external onlyOwner {\n liquidityMiningAddress = LMAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for liquidityMiningAddress\n\n\t * @return liquidityMiningAddress\n\t */\n function getLiquidityMiningAddress() public view returns (address) {\n return liquidityMiningAddress;\n }\n\n /**\n * @notice sets the staking contract address\n * @param _stakingContractAddress the address of the staking contract\n */\n function setStakingContractAddress(address _stakingContractAddress) external onlyOwner {\n stakingContractAddress = _stakingContractAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for stakingContractAddress\n\n\t * @return stakingContractAddress\n\t */\n function getStakingContractAddress() public view returns (address) {\n return stakingContractAddress;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param funcId The function ID, the selector.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function checkPause(string memory funcId) public view returns (bool isPaused) {\n bytes4 sig = bytes4(keccak256(abi.encodePacked(funcId)));\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n isPaused := sload(slot)\n }\n return isPaused;\n }\n}\n" + }, + "contracts/connectors/loantoken/Pausable.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Pausable contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * The contract implements pausable functionality by reading on slots the\n * pause state of contract functions.\n * */\ncontract Pausable {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 internal constant Pausable_FunctionPause =\n 0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047;\n\n modifier pausable(bytes4 sig) {\n require(!_isPaused(sig), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param sig The function ID, the selector on bytes4.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function _isPaused(bytes4 sig) internal view returns (bool isPaused) {\n bytes32 slot = keccak256(abi.encodePacked(sig, Pausable_FunctionPause));\n assembly {\n isPaused := sload(slot)\n }\n }\n}\n" + }, + "contracts/core/Objects.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./objects/LoanStruct.sol\";\nimport \"./objects/LoanParamsStruct.sol\";\nimport \"./objects/OrderStruct.sol\";\nimport \"./objects/LenderInterestStruct.sol\";\nimport \"./objects/LoanInterestStruct.sol\";\n\n/**\n * @title Objects contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract inherints and aggregates several structures needed to handle\n * loans on the protocol.\n * */\ncontract Objects is\n LoanStruct,\n LoanParamsStruct,\n OrderStruct,\n LenderInterestStruct,\n LoanInterestStruct\n{\n\n}\n" + }, + "contracts/core/objects/LenderInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Lender Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Lender Interest.\n * */\ncontract LenderInterestStruct {\n struct LenderInterest {\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\n uint256 paidTotal; /// Total interest paid so far for asset.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Interest.\n * */\ncontract LoanInterestStruct {\n struct LoanInterest {\n uint256 owedPerDay; /// Interest owed per day for loan.\n uint256 depositTotal; /// Total escrowed interest for loan.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanParamsStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Parameters.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Parameters.\n * */\ncontract LoanParamsStruct {\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n}\n" + }, + "contracts/core/objects/LoanStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Object.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Object.\n * */\ncontract LoanStruct {\n struct Loan {\n bytes32 id; /// ID of the loan.\n bytes32 loanParamsId; /// The linked loan params ID.\n bytes32 pendingTradesId; /// The linked pending trades ID.\n bool active; /// If false, the loan has been fully closed.\n uint256 principal; /// Total borrowed amount outstanding.\n uint256 collateral; /// Total collateral escrowed for the loan.\n uint256 startTimestamp; /// Loan start time.\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\n uint256 startMargin; /// Initial margin when the loan opened.\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\n address borrower; /// Borrower of this loan.\n address lender; /// Lender of this loan.\n }\n}\n" + }, + "contracts/core/objects/OrderStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Order.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Order.\n * */\ncontract OrderStruct {\n struct Order {\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\n uint256 interestRate; /// Interest rate defined by the creator of this order.\n uint256 minLoanTerm; /// Minimum loan term allowed.\n uint256 maxLoanTerm; /// Maximum loan term allowed.\n uint256 createdTimestamp; /// Timestamp when this order was created.\n uint256 expirationTimestamp; /// Timestamp when this order expires.\n }\n}\n" + }, + "contracts/core/Protocol.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./State.sol\";\n\n/**\n * @title Sovryn Protocol contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the proxy functionality to deploy Protocol anchor\n * and logic apart, turning it upgradable.\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822\n * */\ncontract sovrynProtocol is State {\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = logicTargets[msg.sig];\n require(target != address(0), \"target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice External owner target initializer.\n * @param target The target addresses.\n * */\n function replaceContract(address target) external onlyOwner {\n (bool success, ) =\n target.delegatecall(abi.encodeWithSignature(\"initialize(address)\", target));\n require(success, \"setup failed\");\n }\n\n /**\n * @notice External owner setter for target addresses.\n * @param sigsArr The array of signatures.\n * @param targetsArr The array of addresses.\n * */\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr)\n external\n onlyOwner\n {\n require(sigsArr.length == targetsArr.length, \"count mismatch\");\n\n for (uint256 i = 0; i < sigsArr.length; i++) {\n _setTarget(bytes4(keccak256(abi.encodePacked(sigsArr[i]))), targetsArr[i]);\n }\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(string calldata sig) external view returns (address) {\n return logicTargets[bytes4(keccak256(abi.encodePacked(sig)))];\n }\n}\n" + }, + "contracts/core/State.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./Objects.sol\";\nimport \"../mixins/EnumerableAddressSet.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/ReentrancyGuard.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title State contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage values of the Protocol.\n * */\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\n using SafeMath for uint256;\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n\n /// Handles asset reference price lookups.\n address public priceFeeds;\n\n /// Handles asset swaps using dex liquidity.\n address public swapsImpl;\n\n /// Contract registry address of the Sovryn swap network.\n address public sovrynSwapContractRegistryAddress;\n\n /// Implementations of protocol functions.\n mapping(bytes4 => address) public logicTargets;\n\n /// Loans: loanId => Loan\n mapping(bytes32 => Loan) public loans;\n\n /// Loan parameters: loanParamsId => LoanParams\n mapping(bytes32 => LoanParams) public loanParams;\n\n /// lender => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\n\n /// borrower => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\n\n /// loanId => delegated => approved\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\n\n /**\n *** Interest ***\n **/\n\n /// lender => loanToken => LenderInterest object\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\n\n /// loanId => LoanInterest object\n mapping(bytes32 => LoanInterest) public loanInterest;\n\n /**\n *** Internals ***\n **/\n\n /// Implementations set.\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\n\n /// Active loans set.\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\n\n /// Lender loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\n\n /// Borrow loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\n\n /// User loan params set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\n\n /// Address controlling fee withdrawals.\n address public feesController;\n\n /// 10% fee /// Fee taken from lender interest payments.\n uint256 public lendingFeePercent = 10**19;\n\n /// Total interest fees received and not withdrawn per asset.\n mapping(address => uint256) public lendingFeeTokensHeld;\n\n /// Total interest fees withdraw per asset.\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\n mapping(address => uint256) public lendingFeeTokensPaid;\n\n /// 0.15% fee /// Fee paid for each trade.\n uint256 public tradingFeePercent = 15 * 10**16;\n\n /// Total trading fees received and not withdrawn per asset.\n mapping(address => uint256) public tradingFeeTokensHeld;\n\n /// Total trading fees withdraw per asset\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\n mapping(address => uint256) public tradingFeeTokensPaid;\n\n /// 0.09% fee /// Origination fee paid for each loan.\n uint256 public borrowingFeePercent = 9 * 10**16;\n\n /// Total borrowing fees received and not withdrawn per asset.\n mapping(address => uint256) public borrowingFeeTokensHeld;\n\n /// Total borrowing fees withdraw per asset.\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\n mapping(address => uint256) public borrowingFeeTokensPaid;\n\n /// Current protocol token deposit balance.\n uint256 public protocolTokenHeld;\n\n /// Lifetime total payout of protocol token.\n uint256 public protocolTokenPaid;\n\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\n uint256 public affiliateFeePercent = 5 * 10**18;\n\n /// 5% collateral discount /// Discount on collateral for liquidators.\n uint256 public liquidationIncentivePercent = 5 * 10**18;\n\n /// loanPool => underlying\n mapping(address => address) public loanPoolToUnderlying;\n\n /// underlying => loanPool\n mapping(address => address) public underlyingToLoanPool;\n\n /// Loan pools set.\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\n\n /// Supported tokens for swaps.\n mapping(address => bool) public supportedTokens;\n\n /// % disagreement between swap rate and reference rate.\n uint256 public maxDisagreement = 5 * 10**18;\n\n /// Used as buffer for swap source amount estimations.\n uint256 public sourceBuffer = 10000;\n\n /// Maximum support swap size in rBTC\n uint256 public maxSwapSize = 50 ether;\n\n /// Nonce per borrower. Used for loan id creation.\n mapping(address => uint256) public borrowerNonce;\n\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\n uint256 public rolloverBaseReward = 16800000000000;\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\n\n IWrbtcERC20 public wrbtcToken;\n address public protocolTokenAddress;\n\n /// 50% fee rebate\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\n uint256 public feeRebatePercent = 50 * 10**18;\n\n address public admin;\n\n /// For modules interaction.\n address public protocolAddress;\n\n /**\n *** Affiliates ***\n **/\n\n /// The flag is set on the user's first trade.\n mapping(address => bool) public userNotFirstTradeFlag;\n\n /// User => referrer (affiliate).\n mapping(address => address) public affiliatesUserReferrer;\n\n /// List of referral addresses affiliated to the referrer.\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\n\n /// @dev Referral threshold for paying out to the referrer.\n /// The referrer reward is being accumulated and locked until the threshold is passed.\n uint256 public minReferralsToPayout = 3;\n\n /// @dev Total affiliate SOV rewards that held in the protocol\n /// (Because the minimum referrals is less than the rule)\n mapping(address => uint256) public affiliateRewardsHeld;\n\n /// @dev For affiliates SOV Bonus proccess.\n address public sovTokenAddress;\n address public lockedSOVAddress;\n\n /// @dev 20% fee share of trading token fee.\n /// Fee share of trading token fee for affiliate program.\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\n\n /// @dev Addresses of tokens in which commissions were paid to referrers.\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\n\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\n\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\n bool public pause; //Flag to pause all protocol modules\n\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\n\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\n uint256 internal tradingRebateRewardsBasisPoint;\n\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\n /// Will be used in internal swap.\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\n\n address internal pauser;\n\n /**\n * @notice Add signature and target to storage.\n * @dev Protocol is a proxy and requires a way to add every\n * module function dynamically during deployment.\n * */\n function _setTarget(bytes4 sig, address target) internal {\n logicTargets[sig] = target;\n\n if (target != address(0)) {\n logicTargetsSet.addBytes32(bytes32(sig));\n } else {\n logicTargetsSet.removeBytes32(bytes32(sig));\n }\n }\n\n modifier onlyAdminOrOwner() {\n require(isOwner() || admin == (msg.sender), \"unauthorized\");\n _;\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || pauser == (msg.sender), \"unauthorized\");\n _;\n }\n}\n" + }, + "contracts/escrow/Escrow.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Ethereum Pool to accept SOV Token.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice You can use this contract for deposit of SOV tokens for some time and withdraw later.\n */\ncontract Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalDeposit;\n /// @notice The release timestamp for the tokens deposited.\n uint256 public releaseTime;\n /// @notice The amount of token we would be accepting as deposit at max.\n uint256 public depositLimit;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The multisig contract which handles the fund.\n address public multisig;\n\n /// @notice The user balances.\n mapping(address => uint256) userBalances;\n\n /// @notice The current contract status.\n /// @notice Deployed - Deployed the contract.\n /// @notice Deposit - Time to deposit in the contract by the users.\n /// @notice Holding - Deposit is closed and now the holding period starts.\n /// @notice Withdraw - Time to withdraw in the contract by the users.\n /// @notice Expired - The contract is now closed completely.\n enum Status { Deployed, Deposit, Holding, Withdraw, Expired }\n Status public status;\n\n /* Events */\n\n /// @notice Emitted when the contract deposit starts.\n event EscrowActivated();\n\n /// @notice Emitted when the contract is put in holding state. No new token deposit accepted by User.\n event EscrowInHoldingState();\n\n /// @notice Emitted when the contract is put in withdraw state. Users can now withdraw tokens.\n event EscrowInWithdrawState();\n\n /// @notice Emitted when the contract is expired after withdraws are made/total token transfer.\n event EscrowFundExpired();\n\n /// @notice Emitted when a new multisig is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newMultisig The address which is added as the new multisig.\n /// @dev Can only be initiated by the current multisig.\n event NewMultisig(address indexed _initiator, address indexed _newMultisig);\n\n /// @notice Emitted when the release timestamp is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseTimestamp The updated release timestamp for the withdraw.\n event TokenReleaseUpdated(address indexed _initiator, uint256 _releaseTimestamp);\n\n /// @notice Emitted when the deposit limit is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _depositLimit The updated deposit limit.\n event TokenDepositLimitUpdated(address indexed _initiator, uint256 _depositLimit);\n\n /// @notice Emitted when a new token deposit is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when we reach the token deposit limit.\n event DepositLimitReached();\n\n /// @notice Emitted when a token withdraw is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdrawByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyMultisig() {\n require(msg.sender == multisig, \"Only Multisig can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n modifier checkRelease() {\n require(\n releaseTime != 0 && releaseTime <= block.timestamp,\n \"The release time has not started yet.\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_multisig != address(0), \"Invalid Multisig Address.\");\n\n SOV = IERC20(_SOV);\n multisig = _multisig;\n\n emit NewMultisig(msg.sender, _multisig);\n\n releaseTime = _releaseTime;\n depositLimit = _depositLimit;\n\n status = Status.Deployed;\n }\n\n /**\n * @notice This function is called once after deployment for starting the deposit action.\n * @dev Without calling this function, the contract will not start accepting tokens.\n */\n function init() external onlyMultisig checkStatus(Status.Deployed) {\n status = Status.Deposit;\n\n emit EscrowActivated();\n }\n\n /**\n * @notice Update Multisig.\n * @param _newMultisig The new owner of the tokens & contract.\n */\n function updateMultisig(address _newMultisig) external onlyMultisig {\n require(_newMultisig != address(0), \"New Multisig address invalid.\");\n\n multisig = _newMultisig;\n\n emit NewMultisig(msg.sender, _newMultisig);\n }\n\n /**\n * @notice Update Release Timestamp.\n * @param _newReleaseTime The new release timestamp for token release.\n * @dev Zero is also a valid timestamp, if the release time is not scheduled yet.\n */\n function updateReleaseTimestamp(uint256 _newReleaseTime) external onlyMultisig {\n releaseTime = _newReleaseTime;\n\n emit TokenReleaseUpdated(msg.sender, _newReleaseTime);\n }\n\n /**\n * @notice Update Deposit Limit.\n * @param _newDepositLimit The new deposit limit.\n * @dev IMPORTANT: Should not decrease than already deposited.\n */\n function updateDepositLimit(uint256 _newDepositLimit) external onlyMultisig {\n require(\n _newDepositLimit >= totalDeposit,\n \"Deposit already higher than the limit trying to be set.\"\n );\n depositLimit = _newDepositLimit;\n\n emit TokenDepositLimitUpdated(msg.sender, _newDepositLimit);\n }\n\n /**\n * @notice Deposit tokens to this contract by User.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the user inorder for this function to work.\n * These tokens can be withdrawn/transferred during Holding State by the Multisig.\n */\n function depositTokens(uint256 _amount) external checkStatus(Status.Deposit) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n uint256 amount = _amount;\n\n if (totalDeposit.add(_amount) >= depositLimit) {\n amount = depositLimit.sub(totalDeposit);\n emit DepositLimitReached();\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n userBalances[msg.sender] = userBalances[msg.sender].add(amount);\n totalDeposit = totalDeposit.add(amount);\n\n emit TokenDeposit(msg.sender, amount);\n }\n\n /**\n * @notice Update contract state to Holding.\n * @dev Once called, the contract no longer accepts any more deposits.\n * The multisig can now withdraw tokens from the contract after the contract is in Holding State.\n */\n function changeStateToHolding() external onlyMultisig checkStatus(Status.Deposit) {\n status = Status.Holding;\n\n emit EscrowInHoldingState();\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred. Zero address if the withdraw is to be done in Multisig.\n * @dev Can only be called after the token state is changed to Holding.\n */\n function withdrawTokensByMultisig(address _receiverAddress)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n address receiverAddress = msg.sender;\n if (_receiverAddress != address(0)) {\n receiverAddress = _receiverAddress;\n }\n\n uint256 value = SOV.balanceOf(address(this));\n /// Sending the amount to multisig.\n bool txStatus = SOV.transfer(receiverAddress, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdrawByMultisig(msg.sender, value);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n * Once the token deposit is higher than the total deposits done, the contract state is changed to Withdraw.\n */\n function depositTokensByMultisig(uint256 _amount)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDepositByMultisig(msg.sender, _amount);\n\n if (SOV.balanceOf(address(this)) >= totalDeposit) {\n status = Status.Withdraw;\n emit EscrowInWithdrawState();\n }\n }\n\n /**\n * @notice Withdraws token from the contract by User.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokens() public checkRelease checkStatus(Status.Withdraw) {\n uint256 amount = userBalances[msg.sender];\n userBalances[msg.sender] = 0;\n bool txStatus = SOV.transfer(msg.sender, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdraw(msg.sender, amount);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token balance of a particular user.\n * @return _addr The user address whose balance has to be checked.\n */\n function getUserBalance(address _addr) external view returns (uint256 balance) {\n return userBalances[_addr];\n }\n}\n" + }, + "contracts/escrow/EscrowReward.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Escrow.sol\";\nimport \"../locked/ILockedSOV.sol\";\n\n/**\n * @title A reward distribution contract for Sovryn Ethereum Pool Escrow Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice Multisig can use this contract for depositing of Reward tokens based on the total token deposit.\n */\ncontract EscrowReward is Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total reward tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalRewardDeposit;\n\n /// @notice The Locked SOV contract.\n ILockedSOV public lockedSOV;\n\n /* Events */\n\n /// @notice Emitted when the Locked SOV Contract address is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _lockedSOV The address of the Locked SOV Contract.\n event LockedSOVUpdated(address indexed _initiator, address indexed _lockedSOV);\n\n /// @notice Emitted when a new reward token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event RewardDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a Reward token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event RewardTokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _lockedSOV The Locked SOV Contract address.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _lockedSOV,\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public Escrow(_SOV, _multisig, _releaseTime, _depositLimit) {\n if (_lockedSOV != address(0)) {\n lockedSOV = ILockedSOV(_lockedSOV);\n }\n }\n\n /**\n * @notice Set the Locked SOV Contract Address if not already done.\n * @param _lockedSOV The Locked SOV Contract address.\n */\n function updateLockedSOV(address _lockedSOV) external onlyMultisig {\n require(_lockedSOV != address(0), \"Invalid Reward Token Address.\");\n\n lockedSOV = ILockedSOV(_lockedSOV);\n\n emit LockedSOVUpdated(msg.sender, _lockedSOV);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n */\n function depositRewardByMultisig(uint256 _amount) external onlyMultisig {\n require(\n status != Status.Withdraw,\n \"Reward Token deposit is only allowed before User Withdraw starts.\"\n );\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n totalRewardDeposit = totalRewardDeposit.add(_amount);\n txStatus = SOV.approve(address(lockedSOV), totalRewardDeposit);\n require(txStatus, \"Token Approval was not successful.\");\n\n emit RewardDepositByMultisig(msg.sender, _amount);\n }\n\n /**\n * @notice Withdraws token and reward from the contract by User. Reward is gone to lockedSOV contract for future vesting.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokensAndReward() external checkRelease checkStatus(Status.Withdraw) {\n // Reward calculation have to be done initially as the User Balance is zeroed out .\n uint256 reward = userBalances[msg.sender].mul(totalRewardDeposit).div(totalDeposit);\n withdrawTokens();\n\n lockedSOV.depositSOV(msg.sender, reward);\n\n emit RewardTokenWithdraw(msg.sender, reward);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the reward a particular user can get.\n * @param _addr The address of the user whose reward is to be read.\n * @return reward The reward received by the user.\n */\n function getReward(address _addr) external view returns (uint256 reward) {\n if (userBalances[_addr].mul(totalRewardDeposit) == 0) {\n return 0;\n }\n return userBalances[_addr].mul(totalRewardDeposit).div(totalDeposit);\n }\n}\n" + }, + "contracts/events/AffiliatesEvents.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\ncontract AffiliatesEvents is ModulesCommonEvents {\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\n\n event SetAffiliatesReferrerFail(\n address indexed user,\n address indexed referrer,\n bool alreadySet,\n bool userNotFirstTrade\n );\n\n event SetUserNotFirstTradeFlag(address indexed user);\n\n event PayTradingFeeToAffiliate(\n address indexed referrer,\n address trader,\n address indexed token,\n bool indexed isHeld,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountPaid\n );\n\n event PayTradingFeeToAffiliateFail(\n address indexed referrer,\n address trader,\n address indexed token,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountTryingToPaid\n );\n\n event WithdrawAffiliatesReferrerTokenFees(\n address indexed referrer,\n address indexed receiver,\n address indexed tokenAddress,\n uint256 amount\n );\n}\n" + }, + "contracts/events/FeesEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Fees Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for fee payments.\n * */\ncontract FeesEvents {\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\n\n event PayTradingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event PayBorrowingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event EarnReward(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n\n event EarnRewardFail(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n}\n" + }, + "contracts/events/LoanClosingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Closing Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan closing operations.\n * */\ncontract LoanClosingsEvents is ModulesCommonEvents {\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\n event CloseWithDeposit(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address closer,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\n event CloseWithSwap(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n address closer,\n uint256 positionCloseSize,\n uint256 loanCloseAmount,\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\n uint256 currentLeverage\n );\n\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\n event Liquidate(\n address indexed user,\n address indexed liquidator,\n bytes32 indexed loanId,\n address lender,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n event Rollover(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n uint256 principal,\n uint256 collateral,\n uint256 endTimestamp,\n address rewardReceiver,\n uint256 reward\n );\n\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\n}\n" + }, + "contracts/events/LoanMaintenanceEvents.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Maintenance Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan maintenance operations.\n * */\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\n}\n" + }, + "contracts/events/LoanOpeningsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Openings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan openings operations.\n * */\ncontract LoanOpeningsEvents is ModulesCommonEvents {\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\n event Borrow(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 newCollateral,\n uint256 interestRate,\n uint256 interestDuration,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\n event Trade(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n uint256 positionSize,\n uint256 borrowedAmount,\n uint256 interestRate,\n uint256 settlementDate,\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\n uint256 entryLeverage,\n uint256 currentLeverage\n );\n\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\n event DelegatedManagerSet(\n bytes32 indexed loanId,\n address indexed delegator,\n address indexed delegated,\n bool isActive\n );\n}\n" + }, + "contracts/events/LoanSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan settings operations.\n * */\ncontract LoanSettingsEvents is ModulesCommonEvents {\n event LoanParamsSetup(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\n\n event LoanParamsDisabled(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\n}\n" + }, + "contracts/events/ModulesCommonEvents.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title The common events for all modules\n * @notice This contract contains the events which will be used by all modules\n **/\n\ncontract ModulesCommonEvents {\n event ProtocolModuleContractReplaced(\n address indexed prevModuleContractAddress,\n address indexed newModuleContractAddress,\n bytes32 indexed module\n );\n}\n" + }, + "contracts/events/ProtocolSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title The Protocol Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for protocol settings operations.\n * */\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\n\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\n\n event SetLoanPool(\n address indexed sender,\n address indexed loanPool,\n address indexed underlying\n );\n\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\n\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateTradingTokenFeePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetLiquidationIncentivePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetFeesController(\n address indexed sender,\n address indexed oldController,\n address indexed newController\n );\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWethToken,\n address indexed newWethToken\n );\n\n event SetSovrynSwapContractRegistryAddress(\n address indexed sender,\n address indexed oldSovrynSwapContractRegistryAddress,\n address indexed newSovrynSwapContractRegistryAddress\n );\n\n event SetProtocolTokenAddress(\n address indexed sender,\n address indexed oldProtocolToken,\n address indexed newProtocolToken\n );\n\n event WithdrawFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 lendingAmount,\n uint256 tradingAmount,\n uint256 borrowingAmount,\n uint256 wRBTCConverted\n );\n\n event WithdrawLendingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawTradingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawBorrowingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetRebatePercent(\n address indexed sender,\n uint256 oldRebatePercent,\n uint256 newRebatePercent\n );\n\n event SetSpecialRebates(\n address indexed sender,\n address indexed sourceToken,\n address indexed destToken,\n uint256 oldSpecialRebatesPercent,\n uint256 newSpecialRebatesPercent\n );\n\n event SetProtocolAddress(\n address indexed sender,\n address indexed oldProtocol,\n address indexed newProtocol\n );\n\n event SetMinReferralsToPayoutAffiliates(\n address indexed sender,\n uint256 oldMinReferrals,\n uint256 newMinReferrals\n );\n\n event SetSOVTokenAddress(\n address indexed sender,\n address indexed oldTokenAddress,\n address indexed newTokenAddress\n );\n\n event SetLockedSOVAddress(\n address indexed sender,\n address indexed oldAddress,\n address indexed newAddress\n );\n\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\n\n event SetTradingRebateRewardsBasisPoint(\n address indexed sender,\n uint256 oldBasisPoint,\n uint256 newBasisPoint\n );\n\n event SetRolloverFlexFeePercent(\n address indexed sender,\n uint256 oldRolloverFlexFeePercent,\n uint256 newRolloverFlexFeePercent\n );\n\n event SetDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event RemoveDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n}\n" + }, + "contracts/events/SwapsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Swaps Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for swap operations.\n * */\ncontract SwapsEvents is ModulesCommonEvents {\n event LoanSwap(\n bytes32 indexed loanId,\n address indexed sourceToken,\n address indexed destToken,\n address borrower,\n uint256 sourceAmount,\n uint256 destAmount\n );\n\n event ExternalSwap(\n address indexed user,\n address indexed sourceToken,\n address indexed destToken,\n uint256 sourceAmount,\n uint256 destAmount\n );\n}\n" + }, + "contracts/farm/ILiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\n\ninterface ILiquidityMining {\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external;\n\n function onTokensDeposited(address _user, uint256 _amount) external;\n\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/farm/LiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./LiquidityMiningStorage.sol\";\nimport \"./ILiquidityMining.sol\";\n\ncontract LiquidityMining is ILiquidityMining, LiquidityMiningStorage {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n /* Constants */\n\n uint256 public constant PRECISION = 1e12;\n // Bonus multiplier for early liquidity providers.\n // During bonus period each passed block will be calculated like N passed blocks, where N = BONUS_MULTIPLIER\n uint256 public constant BONUS_BLOCK_MULTIPLIER = 10;\n\n uint256 public constant SECONDS_PER_BLOCK = 30;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event PoolTokenAdded(address indexed user, address indexed poolToken, uint256 allocationPoint);\n event PoolTokenUpdated(\n address indexed user,\n address indexed poolToken,\n uint256 newAllocationPoint,\n uint256 oldAllocationPoint\n );\n event Deposit(address indexed user, address indexed poolToken, uint256 amount);\n event RewardClaimed(address indexed user, address indexed poolToken, uint256 amount);\n event Withdraw(address indexed user, address indexed poolToken, uint256 amount);\n event EmergencyWithdraw(\n address indexed user,\n address indexed poolToken,\n uint256 amount,\n uint256 accumulatedReward\n );\n\n /* Functions */\n\n /**\n * @notice Initialize mining.\n *\n * @param _SOV The SOV token.\n * @param _rewardTokensPerBlock The number of reward tokens per block.\n * @param _startDelayBlocks The number of blocks should be passed to start\n * mining.\n * @param _numberOfBonusBlocks The number of blocks when each block will\n * be calculated as N blocks (BONUS_BLOCK_MULTIPLIER).\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n * SOV rewards are not paid directly to liquidity providers. Instead they\n * are deposited into a lockedSOV vault contract.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n */\n function initialize(\n IERC20 _SOV,\n uint256 _rewardTokensPerBlock,\n uint256 _startDelayBlocks,\n uint256 _numberOfBonusBlocks,\n address _wrapper,\n ILockedSOV _lockedSOV,\n uint256 _unlockedImmediatelyPercent\n ) external onlyAuthorized {\n /// @dev Non-idempotent function. Must be called just once.\n require(address(SOV) == address(0), \"Already initialized\");\n require(address(_SOV) != address(0), \"Invalid token address\");\n require(_startDelayBlocks > 0, \"Invalid start block\");\n require(\n _unlockedImmediatelyPercent < 10000,\n \"Unlocked immediately percent has to be less than 10000.\"\n );\n\n SOV = _SOV;\n rewardTokensPerBlock = _rewardTokensPerBlock;\n startBlock = block.number + _startDelayBlocks;\n bonusEndBlock = startBlock + _numberOfBonusBlocks;\n wrapper = _wrapper;\n lockedSOV = _lockedSOV;\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets lockedSOV contract.\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n */\n function setLockedSOV(ILockedSOV _lockedSOV) external onlyAuthorized {\n require(address(_lockedSOV) != address(0), \"Invalid lockedSOV Address.\");\n lockedSOV = _lockedSOV;\n }\n\n /**\n * @notice Sets unlocked immediately percent.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setUnlockedImmediatelyPercent(uint256 _unlockedImmediatelyPercent)\n external\n onlyAuthorized\n {\n require(\n _unlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets unlocked immediately percent overwrite for specific pool token.\n * @param _poolToken the address of pool token\n * @param _poolTokenUnlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setPoolTokenUnlockedImmediatelyPercent(\n address _poolToken,\n uint256 _poolTokenUnlockedImmediatelyPercent\n ) external onlyAuthorized {\n require(\n _poolTokenUnlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n poolTokensUnlockedImmediatelyPercent[_poolToken] = _poolTokenUnlockedImmediatelyPercent;\n }\n\n /**\n * @notice sets wrapper proxy contract\n * @dev can be set to zero address to remove wrapper\n */\n function setWrapper(address _wrapper) external onlyAuthorized {\n wrapper = _wrapper;\n }\n\n /**\n * @notice stops mining by setting end block\n */\n function stopMining() external onlyAuthorized {\n require(endBlock == 0, \"Already stopped\");\n\n endBlock = block.number;\n }\n\n /**\n * @notice Transfers SOV tokens to given address.\n * Owner use this function to withdraw SOV from LM contract\n * into another account.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) external onlyAuthorized {\n require(_receiver != address(0), \"Receiver address invalid\");\n require(_amount != 0, \"Amount invalid\");\n\n /// @dev Do not transfer more SOV than available.\n uint256 SOVBal = SOV.balanceOf(address(this));\n if (_amount > SOVBal) {\n _amount = SOVBal;\n }\n\n /// @dev The actual transfer.\n require(SOV.transfer(_receiver, _amount), \"Transfer failed\");\n\n /// @dev Event log.\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Get the missed SOV balance of LM contract.\n *\n * @return The amount of SOV tokens according to totalUsersBalance\n * in excess of actual SOV balance of the LM contract.\n * */\n function getMissedBalance() external view returns (uint256) {\n uint256 balance = SOV.balanceOf(address(this));\n return balance >= totalUsersBalance ? 0 : totalUsersBalance.sub(balance);\n }\n\n /**\n * @notice adds a new lp to the pool. Can only be called by the owner or an admin\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _withUpdate the flag whether we need to update all pools\n */\n function add(\n address _poolToken,\n uint96 _allocationPoint,\n bool _withUpdate\n ) external onlyAuthorized {\n require(_allocationPoint > 0, \"Invalid allocation point\");\n require(_poolToken != address(0), \"Invalid token address\");\n require(poolIdList[_poolToken] == 0, \"Token already added\");\n\n if (_withUpdate) {\n updateAllPools();\n }\n\n uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;\n totalAllocationPoint = totalAllocationPoint.add(_allocationPoint);\n\n poolInfoList.push(\n PoolInfo({\n poolToken: IERC20(_poolToken),\n allocationPoint: _allocationPoint,\n lastRewardBlock: lastRewardBlock,\n accumulatedRewardPerShare: 0\n })\n );\n //indexing starts from 1 in order to check whether token was already added\n poolIdList[_poolToken] = poolInfoList.length;\n\n emit PoolTokenAdded(msg.sender, _poolToken, _allocationPoint);\n }\n\n /**\n * @notice updates the given pool's reward tokens allocation point\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function update(\n address _poolToken,\n uint96 _allocationPoint,\n bool _updateAllFlag\n ) external onlyAuthorized {\n if (_updateAllFlag) {\n updateAllPools();\n } else {\n updatePool(_poolToken);\n }\n _updateToken(_poolToken, _allocationPoint);\n }\n\n function _updateToken(address _poolToken, uint96 _allocationPoint) internal {\n uint256 poolId = _getPoolId(_poolToken);\n\n uint256 previousAllocationPoint = poolInfoList[poolId].allocationPoint;\n totalAllocationPoint = totalAllocationPoint.sub(previousAllocationPoint).add(\n _allocationPoint\n );\n poolInfoList[poolId].allocationPoint = _allocationPoint;\n\n emit PoolTokenUpdated(msg.sender, _poolToken, _allocationPoint, previousAllocationPoint);\n }\n\n /**\n * @notice updates the given pools' reward tokens allocation points\n * @param _poolTokens array of addresses of pool tokens\n * @param _allocationPoints array of allocation points (weight) for the given pools\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function updateTokens(\n address[] calldata _poolTokens,\n uint96[] calldata _allocationPoints,\n bool _updateAllFlag\n ) external onlyAuthorized {\n require(_poolTokens.length == _allocationPoints.length, \"Arrays mismatch\");\n\n if (_updateAllFlag) {\n updateAllPools();\n }\n uint256 length = _poolTokens.length;\n for (uint256 i = 0; i < length; i++) {\n if (!_updateAllFlag) {\n updatePool(_poolTokens[i]);\n }\n _updateToken(_poolTokens[i], _allocationPoints[i]);\n }\n }\n\n /**\n * @notice returns reward multiplier over the given _from to _to block\n * @param _from the first block for a calculation\n * @param _to the last block for a calculation\n */\n function _getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n internal\n view\n returns (uint256)\n {\n if (_from < startBlock) {\n _from = startBlock;\n }\n if (endBlock > 0 && _to > endBlock) {\n _to = endBlock;\n }\n if (_to <= bonusEndBlock) {\n return _to.sub(_from).mul(BONUS_BLOCK_MULTIPLIER);\n } else if (_from >= bonusEndBlock) {\n return _to.sub(_from);\n } else {\n return\n bonusEndBlock.sub(_from).mul(BONUS_BLOCK_MULTIPLIER).add(_to.sub(bonusEndBlock));\n }\n }\n\n function _getUserAccumulatedReward(uint256 _poolId, address _user)\n internal\n view\n returns (uint256)\n {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_user];\n\n uint256 accumulatedRewardPerShare = pool.accumulatedRewardPerShare;\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (block.number > pool.lastRewardBlock && poolTokenBalance != 0) {\n (, uint256 accumulatedRewardPerShare_) = _getPoolAccumulatedReward(pool);\n accumulatedRewardPerShare = accumulatedRewardPerShare.add(accumulatedRewardPerShare_);\n }\n\n return\n user.accumulatedReward.add(\n user.amount.mul(accumulatedRewardPerShare).div(PRECISION).sub(user.rewardDebt)\n );\n }\n\n /**\n * @notice returns accumulated reward\n * @param _poolToken the address of pool token\n * @param _user the user address\n */\n function getUserAccumulatedReward(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n uint256 poolId = _getPoolId(_poolToken);\n return _getUserAccumulatedReward(poolId, _user);\n }\n\n /**\n * @notice returns estimated reward\n * @param _poolToken the address of pool token\n * @param _amount the amount of tokens to be deposited\n * @param _duration the duration of liquidity providing in seconds\n */\n function getEstimatedReward(\n address _poolToken,\n uint256 _amount,\n uint256 _duration\n ) external view returns (uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n uint256 start = block.number;\n uint256 end = start.add(_duration.div(SECONDS_PER_BLOCK));\n (, uint256 accumulatedRewardPerShare) =\n _getPoolAccumulatedReward(pool, _amount, start, end);\n return _amount.mul(accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Updates reward variables for all pools.\n * @dev Be careful of gas spending!\n */\n function updateAllPools() public {\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n _updatePool(i);\n }\n }\n\n /**\n * @notice Updates reward variables of the given pool to be up-to-date\n * @param _poolToken the address of pool token\n */\n function updatePool(address _poolToken) public {\n uint256 poolId = _getPoolId(_poolToken);\n _updatePool(poolId);\n }\n\n function _updatePool(uint256 _poolId) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n\n //this pool has been updated recently\n if (block.number <= pool.lastRewardBlock) {\n return;\n }\n\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (poolTokenBalance == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n (uint256 accumulatedReward_, uint256 accumulatedRewardPerShare_) =\n _getPoolAccumulatedReward(pool);\n pool.accumulatedRewardPerShare = pool.accumulatedRewardPerShare.add(\n accumulatedRewardPerShare_\n );\n pool.lastRewardBlock = block.number;\n\n totalUsersBalance = totalUsersBalance.add(accumulatedReward_);\n }\n\n function _getPoolAccumulatedReward(PoolInfo storage _pool)\n internal\n view\n returns (uint256, uint256)\n {\n return _getPoolAccumulatedReward(_pool, 0, _pool.lastRewardBlock, block.number);\n }\n\n function _getPoolAccumulatedReward(\n PoolInfo storage _pool,\n uint256 _additionalAmount,\n uint256 _startBlock,\n uint256 _endBlock\n ) internal view returns (uint256, uint256) {\n uint256 passedBlocks = _getPassedBlocksWithBonusMultiplier(_startBlock, _endBlock);\n uint256 accumulatedReward =\n passedBlocks.mul(rewardTokensPerBlock).mul(_pool.allocationPoint).div(\n totalAllocationPoint\n );\n\n uint256 poolTokenBalance = _pool.poolToken.balanceOf(address(this));\n poolTokenBalance = poolTokenBalance.add(_additionalAmount);\n uint256 accumulatedRewardPerShare = accumulatedReward.mul(PRECISION).div(poolTokenBalance);\n return (accumulatedReward, accumulatedRewardPerShare);\n }\n\n /**\n * @notice deposits pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it or to msg.sender\n */\n function deposit(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n _deposit(_poolToken, _amount, _user, false);\n }\n\n /**\n * @notice if the lending pools directly mint/transfer tokens to this address, process it like a user deposit\n * @dev only callable by the pool which issues the tokens\n * @param _user the user address\n * @param _amount the minted amount\n */\n function onTokensDeposited(address _user, uint256 _amount) external {\n //the msg.sender is the pool token. if the msg.sender is not a valid pool token, _deposit will revert\n _deposit(msg.sender, _amount, _user, true);\n }\n\n /**\n * @notice internal function for depositing pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it\n * @param alreadyTransferred true if the pool tokens have already been transferred\n */\n function _deposit(\n address _poolToken,\n uint256 _amount,\n address _user,\n bool alreadyTransferred\n ) internal {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _user != address(0) ? _user : msg.sender;\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n\n _updatePool(poolId);\n //sends reward directly to the user\n _updateReward(pool, user);\n\n if (_amount > 0) {\n //receives pool tokens from msg.sender, it can be user or WrapperProxy contract\n if (!alreadyTransferred)\n pool.poolToken.safeTransferFrom(address(msg.sender), address(this), _amount);\n user.amount = user.amount.add(_amount);\n }\n _updateRewardDebt(pool, user);\n emit Deposit(userAddress, _poolToken, _amount);\n }\n\n /**\n * @notice transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimReward(address _poolToken, address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n _claimReward(poolId, userAddress, true);\n }\n\n function _claimReward(\n uint256 _poolId,\n address _userAddress,\n bool _isStakingTokens\n ) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_userAddress];\n\n _updatePool(_poolId);\n _updateReward(pool, user);\n _transferReward(address(pool.poolToken), user, _userAddress, _isStakingTokens, true);\n _updateRewardDebt(pool, user);\n }\n\n /**\n * @notice transfers reward tokens from all pools\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimRewardFromAllPools(address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n uint256 poolId = i;\n _claimReward(poolId, userAddress, false);\n }\n\n if (\n lockedSOV.getLockedBalance(userAddress) > 0 ||\n lockedSOV.getUnlockedBalance(userAddress) > 0\n ) {\n lockedSOV.withdrawAndStakeTokensFrom(userAddress);\n }\n }\n\n /**\n * @notice withdraws pool tokens and transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the user address will be used to process a withdrawal (can be passed only by wrapper contract)\n */\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n require(user.amount >= _amount, \"Not enough balance\");\n\n _updatePool(poolId);\n _updateReward(pool, user);\n _transferReward(_poolToken, user, userAddress, false, false);\n\n user.amount = user.amount.sub(_amount);\n\n //msg.sender is wrapper -> send to wrapper\n if (msg.sender == wrapper) {\n pool.poolToken.safeTransfer(address(msg.sender), _amount);\n }\n //msg.sender is user or pool token (lending pool) -> send to user\n else {\n pool.poolToken.safeTransfer(userAddress, _amount);\n }\n\n _updateRewardDebt(pool, user);\n emit Withdraw(userAddress, _poolToken, _amount);\n }\n\n function _getUserAddress(address _user) internal view returns (address) {\n address userAddress = msg.sender;\n if (_user != address(0)) {\n //only wrapper can pass _user parameter\n require(\n msg.sender == wrapper || poolIdList[msg.sender] != 0,\n \"only wrapper or pools may withdraw for a user\"\n );\n userAddress = _user;\n }\n return userAddress;\n }\n\n function _updateReward(PoolInfo storage pool, UserInfo storage user) internal {\n //update user accumulated reward\n if (user.amount > 0) {\n //add reward for the previous amount of deposited tokens\n uint256 accumulatedReward =\n user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION).sub(\n user.rewardDebt\n );\n user.accumulatedReward = user.accumulatedReward.add(accumulatedReward);\n }\n }\n\n function _updateRewardDebt(PoolInfo storage pool, UserInfo storage user) internal {\n //reward accumulated before amount update (should be subtracted during next reward calculation)\n user.rewardDebt = user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Send reward in SOV to the lockedSOV vault.\n * @param _user The user info, to get its reward share.\n * @param _userAddress The address of the user, to send SOV in its behalf.\n * @param _isStakingTokens The flag whether we need to stake tokens\n * @param _isCheckingBalance The flag whether we need to throw error or don't process reward if SOV balance isn't enough\n */\n function _transferReward(\n address _poolToken,\n UserInfo storage _user,\n address _userAddress,\n bool _isStakingTokens,\n bool _isCheckingBalance\n ) internal {\n uint256 userAccumulatedReward = _user.accumulatedReward;\n /// @dev get unlock immediate percent of the pool token.\n uint256 calculatedUnlockedImmediatelyPercent = calcUnlockedImmediatelyPercent(_poolToken);\n\n /// @dev Transfer if enough SOV balance on this LM contract.\n uint256 balance = SOV.balanceOf(address(this));\n if (balance >= userAccumulatedReward) {\n totalUsersBalance = totalUsersBalance.sub(userAccumulatedReward);\n _user.accumulatedReward = 0;\n\n /// @dev If calculatedUnlockedImmediatelyPercent is 100%, transfer the reward to the LP (user).\n /// else, deposit it into lockedSOV vault contract, but first\n /// SOV deposit must be approved to move the SOV tokens\n /// from this LM contract into the lockedSOV vault.\n if (calculatedUnlockedImmediatelyPercent == 10000) {\n SOV.transfer(_userAddress, userAccumulatedReward);\n } else {\n require(SOV.approve(address(lockedSOV), userAccumulatedReward), \"Approve failed\");\n lockedSOV.deposit(\n _userAddress,\n userAccumulatedReward,\n calculatedUnlockedImmediatelyPercent\n );\n\n if (_isStakingTokens) {\n lockedSOV.withdrawAndStakeTokensFrom(_userAddress);\n }\n }\n\n /// @dev Event log.\n emit RewardClaimed(_userAddress, _poolToken, userAccumulatedReward);\n } else {\n require(!_isCheckingBalance, \"Claiming reward failed\");\n }\n }\n\n /**\n * @notice withdraws pool tokens without transferring reward tokens\n * @param _poolToken the address of pool token\n * @dev EMERGENCY ONLY\n */\n function emergencyWithdraw(address _poolToken) external {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][msg.sender];\n\n _updatePool(poolId);\n _updateReward(pool, user);\n\n totalUsersBalance = totalUsersBalance.sub(user.accumulatedReward);\n uint256 userAmount = user.amount;\n uint256 userAccumulatedReward = user.accumulatedReward;\n user.amount = 0;\n user.rewardDebt = 0;\n user.accumulatedReward = 0;\n pool.poolToken.safeTransfer(address(msg.sender), userAmount);\n\n emit EmergencyWithdraw(msg.sender, _poolToken, userAmount, userAccumulatedReward);\n }\n\n /**\n * @notice returns pool id\n * @param _poolToken the address of pool token\n */\n function getPoolId(address _poolToken) external view returns (uint256) {\n return _getPoolId(_poolToken);\n }\n\n function _getPoolId(address _poolToken) internal view returns (uint256) {\n uint256 poolId = poolIdList[_poolToken];\n require(poolId > 0, \"Pool token not found\");\n return poolId - 1;\n }\n\n /**\n * @notice returns count of pool tokens\n */\n function getPoolLength() external view returns (uint256) {\n return poolInfoList.length;\n }\n\n /**\n * @notice returns list of pool token's info\n */\n function getPoolInfoList() external view returns (PoolInfo[] memory) {\n return poolInfoList;\n }\n\n /**\n * @notice returns pool info for the given token\n * @param _poolToken the address of pool token\n */\n function getPoolInfo(address _poolToken) external view returns (PoolInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return poolInfoList[poolId];\n }\n\n /**\n * @notice returns list of [amount, accumulatedReward] for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserBalanceList(address _user) external view returns (uint256[2][] memory) {\n uint256 length = poolInfoList.length;\n uint256[2][] memory userBalanceList = new uint256[2][](length);\n for (uint256 i = 0; i < length; i++) {\n userBalanceList[i][0] = userInfoMap[i][_user].amount;\n userBalanceList[i][1] = _getUserAccumulatedReward(i, _user);\n }\n return userBalanceList;\n }\n\n /**\n * @notice returns UserInfo for the given pool and user\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserInfo(address _poolToken, address _user) public view returns (UserInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return userInfoMap[poolId][_user];\n }\n\n /**\n * @notice returns list of UserInfo for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserInfoList(address _user) external view returns (UserInfo[] memory) {\n uint256 length = poolInfoList.length;\n UserInfo[] memory userInfoList = new UserInfo[](length);\n for (uint256 i = 0; i < length; i++) {\n userInfoList[i] = userInfoMap[i][_user];\n }\n return userInfoList;\n }\n\n /**\n * @notice returns accumulated reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardList(address _user) external view returns (uint256[] memory) {\n uint256 length = poolInfoList.length;\n uint256[] memory rewardList = new uint256[](length);\n for (uint256 i = 0; i < length; i++) {\n rewardList[i] = _getUserAccumulatedReward(i, _user);\n }\n return rewardList;\n }\n\n /**\n * @notice returns the pool token balance a user has on the contract\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n UserInfo memory ui = getUserInfo(_poolToken, _user);\n return ui.amount;\n }\n\n /**\n * @notice returns the accumulated liquid reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBePaidLiquid(address _user)\n external\n view\n returns (uint256)\n {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n calculatedUnlockedImmediatelyPercent.mul(_getUserAccumulatedReward(i, _user)).div(\n 10000\n )\n );\n }\n\n return result;\n }\n\n /**\n * @notice returns the accumulated vested reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBeVested(address _user) external view returns (uint256) {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n (10000 - calculatedUnlockedImmediatelyPercent)\n .mul(_getUserAccumulatedReward(i, _user))\n .div(10000)\n );\n }\n\n return result;\n }\n\n /**\n * @dev calculate the unlocked immediate percentage of specific pool token\n * use the poolTokensUnlockedImmediatelyPercent by default, if it is not set, then use the unlockedImmediatelyPercent\n */\n function calcUnlockedImmediatelyPercent(address _poolToken) public view returns (uint256) {\n uint256 poolTokenUnlockedImmediatelyPercent =\n poolTokensUnlockedImmediatelyPercent[_poolToken];\n return\n poolTokenUnlockedImmediatelyPercent > 0\n ? poolTokenUnlockedImmediatelyPercent\n : unlockedImmediatelyPercent;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningConfigToken.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/IERC20_.sol\";\n\n/**\n * @title Dummy token with 0 total supply.\n *\n * @dev We need this token for having a flexibility with LiquidityMining configuration\n */\ncontract LiquidityMiningConfigToken is IERC20_ {\n function totalSupply() external view returns (uint256) {\n return 0;\n }\n\n function balanceOf(address account) external view returns (uint256) {\n return 0;\n }\n\n function transfer(address recipient, uint256 amount) external returns (bool) {\n return false;\n }\n\n function allowance(address owner, address spender) external view returns (uint256) {\n return 0;\n }\n\n function approve(address spender, uint256 amount) external returns (bool) {\n return false;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool) {\n return false;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./LiquidityMiningStorage.sol\";\nimport \"../proxy/UpgradableProxy.sol\";\n\n/**\n * @dev LiquidityMining contract should be upgradable, use UpgradableProxy\n */\ncontract LiquidityMiningProxy is LiquidityMiningStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/farm/LiquidityMiningStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../utils/AdminRole.sol\";\n\ncontract LiquidityMiningStorage is AdminRole {\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many pool tokens the user has provided.\n uint256 rewardDebt; // Reward debt. See explanation below.\n uint256 accumulatedReward; //Reward that's ready to be transferred\n //\n // We do some fancy math here. Basically, any point in time, the amount of reward tokens\n // entitled to a user but is accumulated to be distributed is:\n //\n // accumulated reward = (user.amount * pool.accumulatedRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accumulatedRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the accumulated reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 poolToken; // Address of LP token contract.\n uint96 allocationPoint; // How many allocation points assigned to this pool. Amount of reward tokens to distribute per block.\n uint256 lastRewardBlock; // Last block number that reward tokens distribution occurs.\n uint256 accumulatedRewardPerShare; // Accumulated amount of reward tokens per share, times 1e12. See below.\n }\n\n // Rewards tokens created per block.\n uint256 public rewardTokensPerBlock;\n // The block number when reward token mining starts.\n uint256 public startBlock;\n // Block number when bonus reward token period ends.\n uint256 public bonusEndBlock;\n // Block number when reward token period ends.\n uint256 public endBlock;\n\n //Wrapper contract which will be a proxy between user and LM\n address public wrapper;\n\n // Info of each pool.\n PoolInfo[] public poolInfoList;\n // Mapping pool token address => pool id\n mapping(address => uint256) poolIdList;\n // Total allocation points. Must be the sum of all allocation points in all pools.\n uint256 public totalAllocationPoint;\n\n // Info of each user that stakes LP tokens.\n mapping(uint256 => mapping(address => UserInfo)) public userInfoMap;\n // Total balance this contract should have to handle withdrawal for all users\n uint256 public totalUsersBalance;\n\n /// @dev The SOV token\n IERC20 public SOV;\n\n /// @dev The locked vault contract to deposit LP's rewards into.\n ILockedSOV public lockedSOV;\n\n // The % which determines how much will be unlocked immediately.\n /// @dev 10000 is 100%\n uint256 public unlockedImmediatelyPercent;\n\n /// @dev overwrite the unlockedImmediatelyPercent for specific token.\n mapping(address => uint256) public poolTokensUnlockedImmediatelyPercent;\n}\n" + }, + "contracts/feeds/BProPriceFeed.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IMoCState.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The BPro Price Feed contract.\n *\n * This contract gets/sets the MoC (Money on Chain) address of its state\n * contract and queries its method bproUsdPrice to get bPro/USD valuation.\n * */\ncontract BProPriceFeed is IPriceFeedsExt, Ownable {\n address public mocStateAddress;\n\n event SetMoCStateAddress(address indexed mocStateAddress, address changerAddress);\n\n /**\n * @notice Initializes a new MoC state.\n *\n * @param _mocStateAddress MoC state address\n * */\n constructor(address _mocStateAddress) public {\n setMoCStateAddress(_mocStateAddress);\n }\n\n /**\n * @notice Get BPro USD price.\n *\n * @return the BPro USD Price [using mocPrecision]\n */\n function latestAnswer() external view returns (uint256) {\n IMoCState _mocState = IMoCState(mocStateAddress);\n return _mocState.bproUsdPrice();\n }\n\n /**\n * @notice Supposed to get the MoC update time, but instead\n * get the current timestamp.\n *\n * @return Always returns current block's timestamp.\n * */\n function latestTimestamp() external view returns (uint256) {\n return now; /// MoC state doesn't return update timestamp.\n }\n\n /**\n * @notice Set MoC state address.\n *\n * @param _mocStateAddress The MoC state address.\n * */\n function setMoCStateAddress(address _mocStateAddress) public onlyOwner {\n require(Address.isContract(_mocStateAddress), \"_mocStateAddress not a contract\");\n mocStateAddress = _mocStateAddress;\n emit SetMoCStateAddress(mocStateAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/IMoCState.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IMoCState {\n function getRbtcInBitPro(bytes32 bucket) external view returns (uint256);\n\n function globalMaxBPro() external view returns (uint256);\n\n function maxBPro(bytes32 bucket) external view returns (uint256);\n\n function absoluteMaxBPro() external view returns (uint256);\n\n function maxBProWithDiscount() external view returns (uint256);\n\n function bproTecPrice() external view returns (uint256);\n\n function bucketBProTecPrice(bytes32 bucket) external view returns (uint256);\n\n function bproDiscountPrice() external view returns (uint256);\n\n function bproUsdPrice() external view returns (uint256);\n\n function bproSpotDiscountRate() external view returns (uint256);\n\n function getBucketNBPro(bytes32 bucket) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IPriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface IPriceFeeds {\n function queryRate(address sourceToken, address destToken)\n external\n view\n returns (uint256 rate, uint256 precision);\n\n function queryPrecision(address sourceToken, address destToken)\n external\n view\n returns (uint256 precision);\n\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) external view returns (uint256 destAmount);\n\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) external view returns (uint256 sourceToDestSwapRate);\n\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\n\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (uint256);\n\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\n\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\n\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (bool);\n\n function getFastGasPrice(address payToken) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IRSKOracle {\n function updatePrice(uint256 price, uint256 timestamp) external;\n\n function getPricing() external view returns (uint256, uint256);\n\n function setOracleAddress(address addr) external;\n\n function clearOracleAddress() external;\n}\n" + }, + "contracts/feeds/IV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IV1PoolOracle {\n function read(uint256 price, uint256 timestamp)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function latestAnswer() external view returns (uint256);\n\n function liquidityPool() external view returns (address);\n\n function latestPrice(address _baseToken) external view returns (uint256 answer);\n}\n\ninterface ILiquidityPoolV1Converter {\n function reserveTokens(uint256 index) external view returns (address);\n}\n" + }, + "contracts/feeds/PriceFeedRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IRSKOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @notice The Price Feed RSK Oracle contract.\n *\n * This contract implements RSK Oracle query functionality,\n * getting the price and the last timestamp from an external oracle contract.\n * */\ncontract PriceFeedRSKOracle is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public rskOracleAddress;\n\n /* Events */\n\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new RSK Oracle.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _rskOracleAddress) public {\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256 _price) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (_price, ) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestTimestamp() external view returns (uint256 _timestamp) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (, _timestamp) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/PriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./PriceFeedsConstants.sol\";\n\ninterface IPriceFeedsExt {\n function latestAnswer() external view returns (uint256);\n}\n\n/**\n * @title The Price Feeds contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract queries the price feeds contracts where\n * oracles updates token prices computing relative token prices.\n * And besides it includes some calculations about loans such as\n * drawdown, margin and collateral.\n * */\ncontract PriceFeeds is Constants, Ownable {\n using SafeMath for uint256;\n\n /* Events */\n\n event GlobalPricingPaused(address indexed sender, bool indexed isPaused);\n\n /* Storage */\n\n /// Mapping of PriceFeedsExt instances.\n /// token => pricefeed\n mapping(address => IPriceFeedsExt) public pricesFeeds;\n\n /// Decimals of supported tokens.\n mapping(address => uint256) public decimals;\n\n /// Value on rBTC weis for the protocol token.\n uint256 public protocolTokenEthPrice = 0.0002 ether;\n\n /// Flag to pause pricings.\n bool public globalPricingPaused = false;\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires 3 parameters.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * @param _protocolTokenAddress The address of the protocol token.\n * @param _baseTokenAddress The address of the base token.\n * */\n constructor(\n address _wrbtcTokenAddress,\n address _protocolTokenAddress,\n address _baseTokenAddress\n ) public {\n /// Set decimals for this token.\n decimals[address(0)] = 18;\n decimals[_wrbtcTokenAddress] = 18;\n _setWrbtcToken(_wrbtcTokenAddress);\n _setProtocolTokenAddress(_protocolTokenAddress);\n _setBaseToken(_baseTokenAddress);\n }\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @dev Public wrapper for _queryRate internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function queryRate(address sourceToken, address destToken)\n public\n view\n returns (uint256 rate, uint256 precision)\n {\n return _queryRate(sourceToken, destToken);\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @dev Public wrapper for _getDecimalPrecision internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function queryPrecision(address sourceToken, address destToken) public view returns (uint256) {\n return sourceToken != destToken ? _getDecimalPrecision(sourceToken, destToken) : 10**18;\n }\n\n /**\n * @notice Price conversor: Calculate the price of an amount of source\n * tokens in destiny token units.\n *\n * @dev NOTE: This function returns 0 during a pause, rather than a revert.\n * Ensure calling contracts handle correctly.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of the source tokens.\n *\n * @return destAmount The amount of destiny tokens equivalent in price\n * to the amount of source tokens.\n * */\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) public view returns (uint256 destAmount) {\n if (globalPricingPaused) {\n return 0;\n }\n\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n destAmount = sourceAmount.mul(rate).div(precision);\n }\n\n /**\n * @notice Calculate the swap rate between two tokens.\n *\n * Regarding slippage, there is a hardcoded slippage limit of 5%, enforced\n * by this function for all borrowing, lending and margin trading\n * originated swaps performed in the Sovryn exchange.\n *\n * This means all operations in the Sovryn exchange are subject to losing\n * up to 5% from the internal swap performed.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of source tokens.\n * @param destAmount The amount of destiny tokens.\n * @param maxSlippage The maximum slippage limit.\n *\n * @return sourceToDestSwapRate The swap rate between tokens.\n * */\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) public view returns (uint256 sourceToDestSwapRate) {\n require(!globalPricingPaused, \"pricing is paused\");\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n sourceToDestSwapRate = destAmount.mul(precision).div(sourceAmount);\n\n if (rate > sourceToDestSwapRate) {\n uint256 spreadValue = rate - sourceToDestSwapRate;\n spreadValue = spreadValue.mul(10**20).div(sourceToDestSwapRate);\n require(spreadValue <= maxSlippage, \"price disagreement\");\n }\n }\n\n /**\n * @notice Calculate the rBTC amount equivalent to a given token amount.\n * Native coin on RSK is rBTC. This code comes from Ethereum applications,\n * so Eth refers to 10**18 weis of native coin, i.e.: 1 rBTC.\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n *\n * @return ethAmount The amount of rBTC equivalent.\n * */\n function amountInEth(address tokenAddress, uint256 amount)\n public\n view\n returns (uint256 ethAmount)\n {\n /// Token is wrBTC, amount in rBTC is the same.\n if (tokenAddress == address(wrbtcToken)) {\n ethAmount = amount;\n } else {\n (uint256 toEthRate, uint256 toEthPrecision) =\n queryRate(tokenAddress, address(wrbtcToken));\n ethAmount = amount.mul(toEthRate).div(toEthPrecision);\n }\n }\n\n /**\n * @notice Calculate the maximum drawdown of a loan.\n *\n * A drawdown is commonly defined as the decline from a high peak to a\n * pullback low of a specific investment or equity in an account.\n *\n * Drawdown magnitude refers to the amount of value that a user loses\n * during the drawdown period.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param margin The relation between the position size and the loan.\n * margin = (total position size - loan) / loan\n *\n * @return maxDrawdown The maximum drawdown.\n * */\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 margin\n ) public view returns (uint256 maxDrawdown) {\n uint256 loanToCollateralAmount;\n if (collateralToken == loanToken) {\n loanToCollateralAmount = loanAmount;\n } else {\n (uint256 rate, uint256 precision) = queryRate(loanToken, collateralToken);\n loanToCollateralAmount = loanAmount.mul(rate).div(precision);\n }\n\n uint256 combined =\n loanToCollateralAmount.add(loanToCollateralAmount.mul(margin).div(10**20));\n\n maxDrawdown = collateralAmount > combined ? collateralAmount - combined : 0;\n }\n\n /**\n * @notice Calculate the margin and the collateral on rBTC.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralInEthAmount The amount of collateral on rBTC.\n * */\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralInEthAmount) {\n (currentMargin, ) = getCurrentMargin(\n loanToken,\n collateralToken,\n loanAmount,\n collateralAmount\n );\n\n collateralInEthAmount = amountInEth(collateralToken, collateralAmount);\n }\n\n /**\n * @notice Calculate the margin of a loan.\n *\n * @dev current margin = (total position size - loan) / loan\n * The collateral amount passed as parameter equals the total position size.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralToLoanRate The price ratio between collateral and\n * loan tokens.\n * */\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralToLoanRate) {\n uint256 collateralToLoanAmount;\n if (collateralToken == loanToken) {\n collateralToLoanAmount = collateralAmount;\n collateralToLoanRate = 10**18;\n } else {\n uint256 collateralToLoanPrecision;\n (collateralToLoanRate, collateralToLoanPrecision) = queryRate(\n collateralToken,\n loanToken\n );\n\n collateralToLoanRate = collateralToLoanRate.mul(10**18).div(collateralToLoanPrecision);\n\n collateralToLoanAmount = collateralAmount.mul(collateralToLoanRate).div(10**18);\n }\n\n if (loanAmount != 0 && collateralToLoanAmount >= loanAmount) {\n return (\n collateralToLoanAmount.sub(loanAmount).mul(10**20).div(loanAmount),\n collateralToLoanRate\n );\n } else {\n return (0, collateralToLoanRate);\n }\n }\n\n /**\n * @notice Get assessment about liquidating a loan.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param maintenanceMargin The minimum margin before liquidation.\n *\n * @return True/false to liquidate the loan.\n * */\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) public view returns (bool) {\n (uint256 currentMargin, ) =\n getCurrentMargin(loanToken, collateralToken, loanAmount, collateralAmount);\n\n return currentMargin <= maintenanceMargin;\n }\n\n /*\n * Owner functions\n */\n\n /**\n * @notice Set new value for protocolTokenEthPrice\n *\n * @param newPrice The new value for protocolTokenEthPrice\n * */\n function setProtocolTokenEthPrice(uint256 newPrice) external onlyOwner {\n require(newPrice != 0, \"invalid price\");\n protocolTokenEthPrice = newPrice;\n }\n\n /**\n * @notice Populate pricesFeeds mapping w/ values from feeds[]\n *\n * @param tokens The array of tokens to loop and get addresses.\n * @param feeds The array of contract instances for every token.\n * */\n function setPriceFeed(address[] calldata tokens, IPriceFeedsExt[] calldata feeds)\n external\n onlyOwner\n {\n require(tokens.length == feeds.length, \"count mismatch\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n pricesFeeds[tokens[i]] = feeds[i];\n }\n }\n\n /**\n * @notice Populate decimals mapping w/ values from tokens[].decimals\n *\n * @param tokens The array of tokens to loop and get values from.\n * */\n function setDecimals(IERC20[] calldata tokens) external onlyOwner {\n for (uint256 i = 0; i < tokens.length; i++) {\n decimals[address(tokens[i])] = tokens[i].decimals();\n }\n }\n\n /**\n * @notice Set flag globalPricingPaused\n *\n * @param isPaused The new status of pause (true/false).\n * */\n function setGlobalPricingPaused(bool isPaused) external onlyOwner {\n if (globalPricingPaused != isPaused) {\n globalPricingPaused = isPaused;\n\n emit GlobalPricingPaused(msg.sender, isPaused);\n }\n }\n\n /*\n * Internal functions\n */\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n /// Different tokens, query prices and perform division.\n if (sourceToken != destToken) {\n uint256 sourceRate;\n if (sourceToken != address(baseToken) && sourceToken != protocolTokenAddress) {\n IPriceFeedsExt _sourceFeed = pricesFeeds[sourceToken];\n require(address(_sourceFeed) != address(0), \"unsupported src feed\");\n\n /// Query token price on priceFeedsExt instance.\n sourceRate = _sourceFeed.latestAnswer();\n require(sourceRate != 0 && (sourceRate >> 128) == 0, \"price error\");\n } else {\n sourceRate = sourceToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n uint256 destRate;\n if (destToken != address(baseToken) && destToken != protocolTokenAddress) {\n IPriceFeedsExt _destFeed = pricesFeeds[destToken];\n require(address(_destFeed) != address(0), \"unsupported dst feed\");\n\n /// Query token price on priceFeedsExt instance.\n destRate = _destFeed.latestAnswer();\n require(destRate != 0 && (destRate >> 128) == 0, \"price error\");\n } else {\n destRate = destToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n rate = sourceRate.mul(10**18).div(destRate);\n\n precision = _getDecimalPrecision(sourceToken, destToken);\n\n /// Same tokens, return 1 with decimals.\n } else {\n rate = 10**18;\n precision = 10**18;\n }\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function _getDecimalPrecision(address sourceToken, address destToken)\n internal\n view\n returns (uint256)\n {\n /// Same tokens, return 1 with decimals.\n if (sourceToken == destToken) {\n return 10**18;\n\n /// Different tokens, query ERC20 precisions and return 18 +- diff.\n } else {\n uint256 sourceTokenDecimals = decimals[sourceToken];\n if (sourceTokenDecimals == 0) sourceTokenDecimals = IERC20(sourceToken).decimals();\n\n uint256 destTokenDecimals = decimals[destToken];\n if (destTokenDecimals == 0) destTokenDecimals = IERC20(destToken).decimals();\n\n if (destTokenDecimals >= sourceTokenDecimals)\n return 10**(SafeMath.sub(18, destTokenDecimals - sourceTokenDecimals));\n else return 10**(SafeMath.add(18, sourceTokenDecimals - destTokenDecimals));\n }\n }\n}\n" + }, + "contracts/feeds/PriceFeedsConstants.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The Price Feeds Constants contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract keep the addresses of token instances for wrBTC, base token\n * and protocol token.\n * */\ncontract Constants {\n IWrbtcERC20 public wrbtcToken;\n IWrbtcERC20 public baseToken;\n address internal protocolTokenAddress;\n\n /**\n * @notice Set wrBTC token address.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * */\n function _setWrbtcToken(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"_wrbtcTokenAddress not a contract\");\n wrbtcToken = IWrbtcERC20(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Set protocol token address.\n *\n * @param _protocolTokenAddress The address of the protocol token.\n * */\n function _setProtocolTokenAddress(address _protocolTokenAddress) internal {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n protocolTokenAddress = _protocolTokenAddress;\n }\n\n /**\n * @notice Set base token address.\n *\n * @param _baseTokenAddress The address of the base token.\n * */\n function _setBaseToken(address _baseTokenAddress) internal {\n require(Address.isContract(_baseTokenAddress), \"_baseTokenAddress not a contract\");\n baseToken = IWrbtcERC20(_baseTokenAddress);\n }\n}\n" + }, + "contracts/feeds/PriceFeedV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IV1PoolOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./IPriceFeeds.sol\";\n\n/**\n * @notice The Price Feed V1 Pool Oracle contract.\n *\n * This contract implements V1 Pool Oracle query functionality,\n * getting the price from v1 pool oracle.\n * */\ncontract PriceFeedV1PoolOracle is IPriceFeedsExt, Ownable {\n using SafeMath for uint256;\n /* Storage */\n\n address public v1PoolOracleAddress;\n address public wRBTCAddress;\n address public docAddress;\n address public baseCurrency;\n\n /* Events */\n event SetV1PoolOracleAddress(address indexed v1PoolOracleAddress, address changerAddress);\n event SetWRBTCAddress(address indexed wRBTCAddress, address changerAddress);\n event SetDOCAddress(address indexed docAddress, address changerAddress);\n event SetBaseCurrency(address indexed baseCurrency, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new V1 Pool Oracle.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n * @param _wRBTCAddress The wrbtc token address.\n * @param _docAddress The doc token address.\n * */\n constructor(\n address _v1PoolOracleAddress,\n address _wRBTCAddress,\n address _docAddress,\n address _baseCurrency\n ) public {\n setRBTCAddress(_wRBTCAddress);\n setDOCAddress(_docAddress);\n setV1PoolOracleAddress(_v1PoolOracleAddress);\n setBaseCurrency(_baseCurrency);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256) {\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(v1PoolOracleAddress);\n\n uint256 _price = _v1PoolOracle.latestPrice(baseCurrency);\n\n // Need to convert to USD, since the V1 pool return value is based on BTC\n uint256 priceInUSD = _convertAnswerToUsd(_price);\n require(priceInUSD != 0, \"price error\");\n\n return priceInUSD;\n }\n\n function _convertAnswerToUsd(uint256 _valueInBTC) private view returns (uint256) {\n address _priceFeeds = msg.sender;\n\n uint256 precision = IPriceFeeds(_priceFeeds).queryPrecision(wRBTCAddress, docAddress);\n uint256 valueInUSD =\n IPriceFeeds(_priceFeeds).queryReturn(wRBTCAddress, docAddress, _valueInBTC);\n\n /// Need to multiply by query precision (doc's precision) and divide by 1*10^18 (Because the based price in v1 pool is using 18 decimals)\n return valueInUSD.mul(precision).div(1e18);\n }\n\n /**\n * @notice Set the V1 Pool Oracle address.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n */\n function setV1PoolOracleAddress(address _v1PoolOracleAddress) public onlyOwner {\n require(Address.isContract(_v1PoolOracleAddress), \"_v1PoolOracleAddress not a contract\");\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(_v1PoolOracleAddress);\n address liquidityPool = _v1PoolOracle.liquidityPool();\n require(\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(0) == wRBTCAddress ||\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(1) == wRBTCAddress,\n \"one of the two reserves needs to be wrbtc\"\n );\n v1PoolOracleAddress = _v1PoolOracleAddress;\n emit SetV1PoolOracleAddress(v1PoolOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the rBtc address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the rBtc\n *\n * @param _wRBTCAddress The rBTC address\n */\n function setRBTCAddress(address _wRBTCAddress) public onlyOwner {\n require(_wRBTCAddress != address(0), \"wRBTC address cannot be zero address\");\n wRBTCAddress = _wRBTCAddress;\n emit SetWRBTCAddress(wRBTCAddress, msg.sender);\n }\n\n /**\n * @notice Set the DoC address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the DoC\n *\n * @param _docAddress The DoC address\n */\n function setDOCAddress(address _docAddress) public onlyOwner {\n require(_docAddress != address(0), \"DOC address cannot be zero address\");\n docAddress = _docAddress;\n emit SetDOCAddress(_docAddress, msg.sender);\n }\n\n /**\n * @notice Set the base currency address. That's the reserve address which is not WRBTC\n *\n * @param _baseCurrency The base currency address\n */\n function setBaseCurrency(address _baseCurrency) public onlyOwner {\n require(_baseCurrency != address(0), \"Base currency address cannot be zero address\");\n baseCurrency = _baseCurrency;\n emit SetBaseCurrency(_baseCurrency, msg.sender);\n }\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsLocal.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\n\n/**\n * @title Price Feeds Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the logic of setting and getting rates between two tokens.\n * */\ncontract PriceFeedsLocal is PriceFeeds {\n mapping(address => mapping(address => uint256)) public rates;\n\n /// uint256 public slippageMultiplier = 100 ether;\n\n /**\n * @notice Deploy local price feed contract.\n *\n * @param _wrbtcTokenAddress The address of the wrBTC instance.\n * @param _protocolTokenAddress The address of the protocol token instance.\n * */\n constructor(address _wrbtcTokenAddress, address _protocolTokenAddress)\n public\n PriceFeeds(_wrbtcTokenAddress, _protocolTokenAddress, _wrbtcTokenAddress)\n {}\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n if (sourceToken == destToken) {\n rate = 10**18;\n precision = 10**18;\n } else {\n if (sourceToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = protocolTokenEthPrice;\n } else if (destToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = SafeMath.div(10**36, protocolTokenEthPrice);\n } else {\n if (rates[sourceToken][destToken] != 0) {\n rate = rates[sourceToken][destToken];\n } else {\n uint256 sourceToEther =\n rates[sourceToken][address(wrbtcToken)] != 0\n ? rates[sourceToken][address(wrbtcToken)]\n : 10**18;\n uint256 etherToDest =\n rates[address(wrbtcToken)][destToken] != 0\n ? rates[address(wrbtcToken)][destToken]\n : 10**18;\n\n rate = sourceToEther.mul(etherToDest).div(10**18);\n }\n }\n precision = _getDecimalPrecision(sourceToken, destToken);\n }\n }\n\n /**\n * @notice Owner set price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param rate The price ratio source/dest.\n * */\n function setRates(\n address sourceToken,\n address destToken,\n uint256 rate\n ) public onlyOwner {\n if (sourceToken != destToken) {\n rates[sourceToken][destToken] = rate;\n rates[destToken][sourceToken] = SafeMath.div(10**36, rate);\n }\n }\n\n /*function setSlippageMultiplier(\n uint256 _slippageMultiplier)\n public\n onlyOwner\n {\n require (slippageMultiplier != _slippageMultiplier && _slippageMultiplier <= 100 ether);\n slippageMultiplier = _slippageMultiplier;\n }*/\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsMoC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\nimport \"../IRSKOracle.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\ninterface Medianizer {\n function peek() external view returns (bytes32, bool);\n}\n\n/**\n * @title Price Feed of MoC (Money on Chain) contract.\n *\n * This contract contains the logic to set MoC oracles\n * and query last price update.\n * */\ncontract PriceFeedsMoC is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public mocOracleAddress;\n address public rskOracleAddress;\n\n /* Events */\n\n event SetMoCOracleAddress(address indexed mocOracleAddress, address changerAddress);\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new MoC Oracle.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _mocOracleAddress, address _rskOracleAddress) public {\n setMoCOracleAddress(_mocOracleAddress);\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestAnswer() external view returns (uint256) {\n (bytes32 value, bool hasValue) = Medianizer(mocOracleAddress).peek();\n if (hasValue) {\n return uint256(value);\n } else {\n (uint256 price, ) = IRSKOracle(rskOracleAddress).getPricing();\n return price;\n }\n }\n\n /**\n * @notice Set the MoC Oracle address.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n */\n function setMoCOracleAddress(address _mocOracleAddress) public onlyOwner {\n require(Address.isContract(_mocOracleAddress), \"_mocOracleAddress not a contract\");\n mocOracleAddress = _mocOracleAddress;\n emit SetMoCOracleAddress(mocOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/USDTPriceFeed.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./PriceFeeds.sol\";\n\n/**\n * @notice The Price Feed USDT contract.\n *\n * This contract implements USDT query functionality,\n * getting the price and the last timestamp from a\n * trivial formula, always returning 1 and now.\n * */\ncontract USDTPriceFeed is IPriceFeedsExt {\n uint256 private constant USDT_RATE = 1 ether;\n\n /**\n * @notice Get the USDT price.\n *\n * @return Always returns the trivial rate of 1.\n * */\n function latestAnswer() external view returns (uint256) {\n return USDT_RATE;\n }\n\n /**\n * @notice Get the las time the price was updated.\n * @return Always trivial current block's timestamp.\n */\n function latestTimestamp() external view returns (uint256) {\n return now;\n }\n}\n" + }, + "contracts/governance/ApprovalReceiver.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./ErrorDecoder.sol\";\nimport \"../token/IApproveAndCall.sol\";\n\n/**\n * @title Base contract for receiving approval from SOV token.\n */\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\n modifier onlyThisContract() {\n // Accepts calls only from receiveApproval function.\n require(msg.sender == address(this), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external {\n // Accepts calls only from SOV token.\n require(msg.sender == _getToken(), \"unauthorized\");\n require(msg.sender == _token, \"unauthorized\");\n\n // Only allowed methods.\n bool isAllowed = false;\n bytes4[] memory selectors = _getSelectors();\n bytes4 sig = _getSig(_data);\n for (uint256 i = 0; i < selectors.length; i++) {\n if (sig == selectors[i]) {\n isAllowed = true;\n break;\n }\n }\n require(isAllowed, \"method is not allowed\");\n\n // Check sender and amount.\n address sender;\n uint256 amount;\n (, sender, amount) = abi.decode(\n abi.encodePacked(bytes28(0), _data),\n (bytes32, address, uint256)\n );\n require(sender == _sender, \"sender mismatch\");\n require(amount == _amount, \"amount mismatch\");\n\n _call(_data);\n }\n\n /**\n * @notice Returns token address, only this address can be a sender for receiveApproval.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, 0x. When overriden, the token address making the call.\n */\n function _getToken() internal view returns (address) {\n return address(0);\n }\n\n /**\n * @notice Returns list of function selectors allowed to be invoked.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, empty array. When overriden, allowed selectors.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n return new bytes4[](0);\n }\n\n /**\n * @notice Makes call and reverts w/ enhanced error message.\n * @param _data Error message as bytes.\n */\n function _call(bytes memory _data) internal {\n (bool success, bytes memory returnData) = address(this).call(_data);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"receiveApproval: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"receiveApproval: \", string(returnData)));\n }\n }\n }\n\n /**\n * @notice Extracts the called function selector, a hash of the signature.\n * @dev The first four bytes of the call data for a function call specifies\n * the function to be called. It is the first (left, high-order in big-endian)\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\n * Example:\n * msg.data:\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\n * 000450000000000000000000000000000000000000000000000000000000000000001\n * selector (or method ID): 0xcdcd77c0\n * signature: baz(uint32,bool)\n * @param _data The msg.data from the low level call.\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\n */\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\n assembly {\n sig := mload(add(_data, 32))\n }\n }\n}\n" + }, + "contracts/governance/ErrorDecoder.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base contract to properly handle returned data on failed calls\n * @dev On EVM if the return data length of a call is less than 68,\n * then the transaction fails silently without a revert message!\n *\n * As described in the Solidity documentation\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\n * the revert reason is an ABI-encoded string consisting of:\n * 0x08c379a0 // Function selector (method id) for \"Error(string)\" signature\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\n *\n * Another example, debug data from test:\n * 0x08c379a0\n * 0000000000000000000000000000000000000000000000000000000000000020\n * 0000000000000000000000000000000000000000000000000000000000000034\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n *\n * Parsed into:\n * Data offset: 20\n * Length: 34\n * Error message:\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n */\ncontract ErrorDecoder {\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\n\n /**\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\n * @param str1 First string, usually a hardcoded context written by dev.\n * @param str2 Second string, usually the error message from the reverted call.\n * @return The concatenated error string\n */\n function _addErrorMessage(string memory str1, string memory str2)\n internal\n pure\n returns (string memory)\n {\n bytes memory bytesStr1 = bytes(str1);\n bytes memory bytesStr2 = bytes(str2);\n string memory str12 =\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\n bytes memory bytesStr12 = bytes(str12);\n uint256 j = 0;\n for (uint256 i = 0; i < bytesStr1.length; i++) {\n bytesStr12[j++] = bytesStr1[i];\n }\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\n bytesStr12[j++] = bytesStr2[i];\n }\n return string(bytesStr12);\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../Staking/SafeMath96.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../interfaces/IConverterAMM.sol\";\n\n/**\n * @title The FeeSharingCollector contract.\n * @notice This contract withdraws fees to be paid to SOV Stakers from the protocol.\n * Stakers call withdraw() to get their share of the fees.\n *\n * @notice Staking is not only granting voting rights, but also access to fee\n * sharing according to the own voting power in relation to the total. Whenever\n * somebody decides to collect the fees from the protocol, they get transferred\n * to a proxy contract which invests the funds in the lending pool and keeps\n * the pool tokens.\n *\n * The fee sharing proxy will be set as feesController of the protocol contract.\n * This allows the fee sharing proxy to withdraw the fees. The fee sharing\n * proxy holds the pool tokens and keeps track of which user owns how many\n * tokens. In order to know how many tokens a user owns, the fee sharing proxy\n * needs to know the user’s weighted stake in relation to the total weighted\n * stake (aka total voting power).\n *\n * Because both values are subject to change, they may be different on each fee\n * withdrawal. To be able to calculate a user’s share of tokens when he wants\n * to withdraw, we need checkpoints.\n *\n * This contract is intended to be set as the protocol fee collector.\n * Anybody can invoke the withdrawFees function which uses\n * protocol.withdrawFees to obtain available fees from operations on a\n * certain token. These fees are deposited in the corresponding loanPool.\n * Also, the staking contract sends slashed tokens to this contract.\n * When a user calls the withdraw function, the contract transfers the fee sharing\n * rewards in proportion to the user’s weighted stake since the last withdrawal.\n *\n * The protocol initially collects fees in all tokens.\n * Then the FeeSharingCollector wihtdraws fees from the protocol.\n * When the fees are withdrawn all the tokens except SOV will be converted to wRBTC\n * and then transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n * */\ncontract FeeSharingCollector is\n SafeMath96,\n IFeeSharingCollector,\n Ownable,\n FeeSharingCollectorStorage\n{\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n address constant ZERO_ADDRESS = address(0);\n address public constant RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT =\n address(uint160(uint256(keccak256(\"RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\"))));\n\n /* Events */\n\n /// @notice Deprecated event after the unification between wrbtc & rbtc\n // event FeeWithdrawn(address indexed sender, address indexed token, uint256 amount);\n event FeeWithdrawnInRBTC(address indexed sender, uint256 amount);\n\n /// @notice An event emitted when tokens transferred.\n event TokensTransferred(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when checkpoint added.\n event CheckpointAdded(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeWithdrawn(\n address indexed sender,\n address indexed receiver,\n address indexed token,\n uint256 amount\n );\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeProcessedNoWithdraw(\n address indexed sender,\n address indexed token,\n uint256 prevProcessedCheckpoints,\n uint256 newProcessedCheckpoints\n );\n\n /**\n * @notice An event emitted when fee from AMM get withdrawn.\n *\n * @param sender sender who initiate the withdrawn amm fees.\n * @param converter the converter address.\n * @param amount total amount of fee (Already converted to WRBTC).\n */\n event FeeAMMWithdrawn(address indexed sender, address indexed converter, uint256 amount);\n\n /// @notice An event emitted when converter address has been registered to be whitelisted.\n event WhitelistedConverter(address indexed sender, address converter);\n\n /// @notice An event emitted when converter address has been removed from whitelist.\n event UnwhitelistedConverter(address indexed sender, address converter);\n\n event RBTCWithdrawn(address indexed sender, address indexed receiver, uint256 amount);\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWrbtcToken,\n address indexed newWrbtcToken\n );\n\n event SetLoanTokenWrbtc(\n address indexed sender,\n address indexed oldLoanTokenWrbtc,\n address indexed newLoanTokenWrbtc\n );\n\n /* Modifier */\n modifier oneTimeExecution(bytes4 _funcSig) {\n require(\n !isFunctionExecuted[_funcSig],\n \"FeeSharingCollector: function can only be called once\"\n );\n _;\n isFunctionExecuted[_funcSig] = true;\n }\n\n /* Functions */\n\n /// @dev fallback function to support rbtc transfer when unwrap the wrbtc.\n function() external payable {}\n\n /**\n * @dev initialize function for fee sharing collector proxy\n * @param wrbtcToken wrbtc token address\n * @param loanWrbtcToken address of loan token wrbtc (IWrbtc)\n */\n function initialize(address wrbtcToken, address loanWrbtcToken)\n external\n onlyOwner\n oneTimeExecution(this.initialize.selector)\n {\n require(\n wrbtcTokenAddress == address(0) && loanTokenWrbtcAddress == address(0),\n \"wrbtcToken or loanWrbtcToken has been initialized\"\n );\n setWrbtcToken(wrbtcToken);\n setLoanTokenWrbtc(loanWrbtcToken);\n }\n\n /**\n * @notice Set the wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newWrbtcTokenAddress The new address of the wrbtc token.\n * */\n function setWrbtcToken(address newWrbtcTokenAddress) public onlyOwner {\n require(Address.isContract(newWrbtcTokenAddress), \"newWrbtcTokenAddress not a contract\");\n emit SetWrbtcToken(msg.sender, wrbtcTokenAddress, newWrbtcTokenAddress);\n wrbtcTokenAddress = newWrbtcTokenAddress;\n }\n\n /**\n * @notice Set the loan wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newLoanTokenWrbtcAddress The new address of the loan wrbtc token.\n * */\n function setLoanTokenWrbtc(address newLoanTokenWrbtcAddress) public onlyOwner {\n require(\n Address.isContract(newLoanTokenWrbtcAddress),\n \"newLoanTokenWrbtcAddress not a contract\"\n );\n emit SetLoanTokenWrbtc(msg.sender, loanTokenWrbtcAddress, newLoanTokenWrbtcAddress);\n loanTokenWrbtcAddress = newLoanTokenWrbtcAddress;\n }\n\n /**\n * @notice Withdraw fees for the given token:\n * lendingFee + tradingFee + borrowingFee\n * the fees (except SOV) will be converted in wRBTC form, and then will be transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n *\n * @param _tokens array address of the token\n * */\n function withdrawFees(address[] calldata _tokens) external {\n for (uint256 i = 0; i < _tokens.length; i++) {\n require(\n Address.isContract(_tokens[i]),\n \"FeeSharingCollector::withdrawFees: token is not a contract\"\n );\n }\n\n uint256 wrbtcAmountWithdrawn = protocol.withdrawFees(_tokens, address(this));\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap the wrbtc to rbtc, and hold the rbtc.\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFees: wrbtc token amount exceeds 96 bits\"\n );\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, amount96);\n }\n\n // note deprecated event since we unify the wrbtc & rbtc\n // emit FeeWithdrawn(msg.sender, RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, poolTokenAmount);\n\n // note new emitted event\n emit FeeWithdrawnInRBTC(msg.sender, wrbtcAmountWithdrawn);\n }\n\n /**\n * @notice Withdraw amm fees for the given converter addresses:\n * protocolFee from the conversion\n * the fees will be converted in wRBTC form, and then will be transferred to wRBTC loan pool\n *\n * @param _converters array addresses of the converters\n * */\n function withdrawFeesAMM(address[] memory _converters) public {\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n // Validate\n _validateWhitelistedConverter(_converters);\n\n uint96 totalPoolTokenAmount;\n for (uint256 i = 0; i < _converters.length; i++) {\n uint256 wrbtcAmountWithdrawn =\n IConverterAMM(_converters[i]).withdrawFees(address(this));\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap wrbtc to rbtc, and hold the rbtc\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFeesAMM: wrbtc token amount exceeds 96 bits\"\n );\n\n totalPoolTokenAmount = add96(\n totalPoolTokenAmount,\n amount96,\n \"FeeSharingCollector::withdrawFeesAMM: total wrbtc token amount exceeds 96 bits\"\n );\n\n emit FeeAMMWithdrawn(msg.sender, _converters[i], wrbtcAmountWithdrawn);\n }\n }\n\n if (totalPoolTokenAmount > 0) {\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, totalPoolTokenAmount);\n }\n }\n\n /**\n * @notice Transfer tokens to this contract.\n * @dev We just update amount of tokens here and write checkpoint in a separate methods\n * in order to prevent adding checkpoints too often.\n * @param _token Address of the token.\n * @param _amount Amount to be transferred.\n * */\n function transferTokens(address _token, uint96 _amount) public {\n require(_token != ZERO_ADDRESS, \"FeeSharingCollector::transferTokens: invalid address\");\n require(_amount > 0, \"FeeSharingCollector::transferTokens: invalid amount\");\n\n /// @notice Transfer tokens from msg.sender\n bool success = IERC20(_token).transferFrom(address(msg.sender), address(this), _amount);\n require(success, \"Staking::transferTokens: token transfer failed\");\n\n // if _token is wrbtc, need to unwrap it to rbtc\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n if (_token == address(wrbtcToken)) {\n wrbtcToken.withdraw(_amount);\n _token = RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT;\n }\n\n _addCheckpoint(_token, _amount);\n\n emit TokensTransferred(msg.sender, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC / native tokens to this contract.\n * @dev We just write checkpoint here (based on the rbtc value that is sent) in a separate methods\n * in order to prevent adding checkpoints too often.\n * */\n function transferRBTC() external payable {\n uint96 _amount = uint96(msg.value);\n require(_amount > 0, \"FeeSharingCollector::transferRBTC: invalid value\");\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, _amount);\n\n emit TokensTransferred(msg.sender, ZERO_ADDRESS, _amount);\n }\n\n /**\n * @notice Add checkpoint with accumulated amount by function invocation.\n * @param _token Address of the token.\n * */\n function _addCheckpoint(address _token, uint96 _amount) internal {\n if (block.timestamp - lastFeeWithdrawalTime[_token] >= FEE_WITHDRAWAL_INTERVAL) {\n lastFeeWithdrawalTime[_token] = block.timestamp;\n uint96 amount =\n add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: amount exceeds 96 bits\"\n );\n\n /// @notice Reset unprocessed amount of tokens to zero.\n unprocessedAmount[_token] = 0;\n\n /// @notice Write a regular checkpoint.\n _writeTokenCheckpoint(_token, amount);\n } else {\n unprocessedAmount[_token] = add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: unprocessedAmount exceeds 96 bits\"\n );\n }\n }\n\n function _withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n /// @dev Prevents block gas limit hit when processing checkpoints\n require(\n _maxCheckpoints > 0,\n \"FeeSharingCollector::withdraw: _maxCheckpoints should be positive\"\n );\n\n address user = msg.sender;\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n uint256 processedUserCheckpoints = processedCheckpoints[user][_token];\n (uint256 amount, uint256 end) =\n _getAccumulatedFees(user, _token, processedUserCheckpoints, _maxCheckpoints);\n if (amount == 0) {\n if (end > processedUserCheckpoints) {\n emit UserFeeProcessedNoWithdraw(msg.sender, _token, processedUserCheckpoints, end);\n processedCheckpoints[user][_token] = end;\n return (0, end);\n } else {\n // getting here most likely means smth wrong with the state\n revert(\"FeeSharingCollector::withdrawFees: no tokens for withdrawal\");\n }\n }\n\n processedCheckpoints[user][_token] = end;\n if (loanTokenWrbtcAddress == _token) {\n // We will change, so that feeSharingCollector will directly burn then loanToken (IWRBTC) to rbtc and send to the user --- by call burnToBTC function\n ILoanTokenWRBTC(_token).burnToBTC(_receiver, amount, false);\n } else {\n // Previously it directly send the loanToken to the user\n require(\n IERC20(_token).transfer(_receiver, amount),\n \"FeeSharingCollector::withdraw: withdrawal failed\"\n );\n }\n\n emit UserFeeWithdrawn(msg.sender, _receiver, _token, amount);\n\n return (amount, end);\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power. Therefore, staking more\n * SOV and/or staking for longer will increase your share of the fees\n * generated, meaning you will earn more from staking.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed. Must be positive value.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public nonReentrant {\n _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n /// @notice Validates if the checkpoint is payable for the user\n function validFromCheckpointsParam(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n address _user\n ) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n // _fromCheckpoint is checkpoint number, not array index, so should be > 1\n require(tokenData.fromCheckpoint > 1, \"_fromCheckpoint param must be > 1\");\n uint256 fromCheckpointIndex = tokenData.fromCheckpoint - 1;\n require(\n tokenData.fromCheckpoint > processedCheckpoints[_user][tokenData.tokenAddress],\n \"_fromCheckpoint param must be > userProcessedCheckpoints\"\n );\n require(\n tokenData.fromCheckpoint <= totalTokenCheckpoints[tokenData.tokenAddress],\n \"_fromCheckpoint should be <= totalTokenCheckpoints\"\n );\n\n Checkpoint memory prevCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex - 1];\n\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n prevCheckpoint.blockNumber - 1,\n prevCheckpoint.timestamp\n );\n require(\n weightedStake == 0,\n \"User weighted stake should be zero at previous checkpoint\"\n );\n\n Checkpoint memory fromCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex];\n weightedStake = staking.getPriorWeightedStake(\n _user,\n fromCheckpoint.blockNumber - 1,\n fromCheckpoint.timestamp\n );\n\n require(weightedStake > 0, \"User weighted stake should be > 0 at _fromCheckpoint\");\n }\n }\n\n function validRBTCBasedTokens(address[] memory _tokens) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n address _token = _tokens[i];\n if (\n _token != RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT &&\n _token != wrbtcTokenAddress &&\n _token != loanTokenWrbtcAddress\n ) {\n revert(\"only rbtc-based tokens are allowed\");\n }\n }\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender/receiver.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @dev WARNING! This function skips all the checkpoints before '_fromCheckpoint' irreversibly, use with care\n *\n * @param _tokens Array of TokenWithSkippedCheckpointsWithdraw struct, which contains the token address, and fromCheckpoiint\n * fromCheckpoints Skips all the checkpoints before '_fromCheckpoint'\n * should be calculated offchain with getNextPositiveUserCheckpoint function\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n *\n * @return total processed checkpoints\n * */\n function _withdrawStartingFromCheckpoints(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validFromCheckpointsParam(_tokens, msg.sender);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n if (_maxCheckpoints == 0) break;\n uint256 endToken;\n uint256 totalAmount;\n\n uint256 previousProcessedUserCheckpoints =\n processedCheckpoints[msg.sender][tokenData.tokenAddress];\n uint256 startingCheckpoint =\n tokenData.fromCheckpoint > previousProcessedUserCheckpoints\n ? tokenData.fromCheckpoint\n : previousProcessedUserCheckpoints;\n\n if (\n tokenData.tokenAddress == wrbtcTokenAddress ||\n tokenData.tokenAddress == loanTokenWrbtcAddress ||\n tokenData.tokenAddress == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\n ) {\n (totalAmount, endToken) = _withdrawRbtcTokenStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n } else {\n (, endToken) = _withdrawStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n }\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint).add(1);\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n if (rbtcAmountToSend > 0) {\n // send all rbtc withdrawal\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Function to wrap:\n * 1. regular withdrawal for both rbtc & non-rbtc token\n * 2. skipped checkpoints withdrawal for both rbtc & non-rbtc token\n *\n * @param _nonRbtcTokensRegularWithdraw array of non-rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _rbtcTokensRegularWithdraw array of rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _tokensWithSkippedCheckpoints array of rbtc & non-rbtc TokenWithSkippedCheckpointsWithdraw struct, which has skipped checkpoints that will be withdrawn\n *\n */\n function claimAllCollectedFees(\n address[] calldata _nonRbtcTokensRegularWithdraw,\n address[] calldata _rbtcTokensRegularWithdraw,\n TokenWithSkippedCheckpointsWithdraw[] calldata _tokensWithSkippedCheckpoints,\n uint32 _maxCheckpoints,\n address _receiver\n ) external nonReentrant {\n uint256 totalProcessedCheckpoints;\n\n /** Process normal multiple withdrawal for RBTC based tokens */\n if (_rbtcTokensRegularWithdraw.length > 0) {\n totalProcessedCheckpoints = _withdrawRbtcTokens(\n _rbtcTokensRegularWithdraw,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process normal non-rbtc token withdrawal */\n for (uint256 i = 0; i < _nonRbtcTokensRegularWithdraw.length; i++) {\n if (_maxCheckpoints == 0) break;\n uint256 endTokenCheckpoint;\n\n address _nonRbtcTokenAddress = _nonRbtcTokensRegularWithdraw[i];\n\n /** starting checkpoint is the previous processedCheckpoints for token */\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_nonRbtcTokenAddress];\n\n (, endTokenCheckpoint) = _withdraw(_nonRbtcTokenAddress, _maxCheckpoints, _receiver);\n\n uint256 _previousUsedCheckpoint = endTokenCheckpoint.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n _previousUsedCheckpoint.add(1);\n }\n\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process token with skipped checkpoints withdrawal */\n if (_tokensWithSkippedCheckpoints.length > 0) {\n totalProcessedCheckpoints = _withdrawStartingFromCheckpoints(\n _tokensWithSkippedCheckpoints,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n }\n\n function _withdrawStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10 meaning we should set 9 user's processed checkpoints\n // after _withdraw() the user's processedCheckpoints should be 10\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n (totalAmount, endTokenCheckpoint) = _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function _withdrawRbtcToken(address _token, uint32 _maxCheckpoints)\n internal\n returns (uint256 totalAmount, uint256 endTokenCheckpoint)\n {\n address user = msg.sender;\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n (totalAmount, endTokenCheckpoint) = _getRBTCBalance(_token, user, _maxCheckpoints);\n\n if (totalAmount > 0) {\n processedCheckpoints[user][_token] = endTokenCheckpoint;\n if (_token == address(wrbtcToken)) {\n // unwrap the wrbtc\n wrbtcToken.withdraw(totalAmount);\n } else if (_token == loanTokenWrbtcAddress) {\n // pull out the iWRBTC to rbtc to this feeSharingCollector contract\n /** @dev will use the burned result from IWRBTC to RBTC as return total amount */\n totalAmount = ILoanTokenWRBTC(loanTokenWrbtcAddress).burnToBTC(\n address(this),\n totalAmount,\n false\n );\n }\n }\n }\n\n /**\n * @dev withdraw all of the RBTC balance based on particular checkpoints\n *\n * This function will withdraw RBTC balance which is passed as _token param, so it could be either of these:\n * - rbtc balance or\n * - wrbtc balance which will be unwrapped to rbtc or\n * - iwrbtc balance which will be unwrapped to rbtc or\n *\n *\n * @param _tokens array of either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _maxCheckpoints Maximum number of checkpoints to be processed to workaround block gas limit\n * @param _receiver An optional tokens receiver (msg.sender used if 0)\n */\n function _withdrawRbtcTokens(\n address[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validRBTCBasedTokens(_tokens);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n if (_maxCheckpoints == 0) break;\n address _token = _tokens[i];\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_token];\n\n (uint256 totalAmount, uint256 endToken) =\n _withdrawRbtcToken(_tokens[i], _maxCheckpoints);\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n // we only need to add used checkpoint by 1 only if starting checkpoint > 0\n _previousUsedCheckpoint.add(1);\n }\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n // send all rbtc\n if (rbtcAmountToSend > 0) {\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Withdraw either specific RBTC related token balance or all RBTC related tokens balances.\n * RBTC related here means, it could be either rbtc, wrbtc, or iwrbtc, depends on the _token param.\n */\n function _withdrawRbtcTokenStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) private returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10\n // after _withdraw() user's processedCheckpoints should be 10 =>\n // set processed checkpoints = 9, next maping index = 9 (10th checkpoint)\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n return _withdrawRbtcToken(_token, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n external\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n return _getNextPositiveUserCheckpoint(_user, _token, _startFrom, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function _getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n internal\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n if (staking.isVestingContract(_user)) {\n return (0, false, false);\n }\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n\n if (processedUserCheckpoints >= totalCheckpoints || totalCheckpoints == 0) {\n return (totalCheckpoints, false, false);\n }\n\n uint256 startFrom =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n\n uint256 end = startFrom.add(_maxCheckpoints);\n if (end >= totalCheckpoints) {\n end = totalCheckpoints;\n }\n\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startFrom; i < end; i++) {\n Checkpoint storage tokenCheckpoint = tokenCheckpoints[_token][i];\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n tokenCheckpoint.blockNumber - 1,\n tokenCheckpoint.timestamp\n );\n if (weightedStake > 0) {\n // i is the index and we need to return checkpoint num which is i + 1\n return (i + 1, i > processedUserCheckpoints, true);\n }\n }\n return (end, end > processedUserCheckpoints, false);\n }\n\n /**\n * @notice Get the accumulated loan pool fee of the message sender.\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @return The accumulated fee for the message sender.\n * */\n function getAccumulatedFees(address _user, address _token) public view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: 0\n });\n return amount;\n }\n\n /**\n * @notice Get the accumulated fee rewards for the message sender for a checkpoints range\n *\n * @dev This function is required to keep consistent with caching of weighted voting power when claiming fees\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The accumulated fees rewards for the _user in the given checkpoints interval: [_startFrom, _startFrom + maxCheckpoints].\n * */\n function getAccumulatedFeesForCheckpointsRange(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees(_user, _token, _startFrom, _maxCheckpoints);\n return amount;\n }\n\n /**\n * @dev Get all user fees reward per maxCheckpoint starting from latest processed checkpoint\n *\n * @dev e.g: Total user checkpoint for the particualar token = 300,\n * when we call this function with 50 maxCheckpoint, it will return 6 fee values in array form.\n * if there is no more fees, it will return empty array.\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The next checkpoint num which is the starting point to fetch all of the fees, array of calculated fees.\n * */\n function getAllUserFeesPerMaxCheckpoints(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256[] memory fees) {\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 totalTokensCheckpointsIndex = totalCheckpoints > 0 ? totalCheckpoints - 1 : 0;\n\n if (totalTokensCheckpointsIndex < _startFrom) return fees;\n\n uint256 arrSize = totalTokensCheckpointsIndex.sub(_startFrom).div(_maxCheckpoints) + 1;\n\n fees = new uint256[](arrSize);\n\n for (uint256 i = 0; i < fees.length; i++) {\n (uint256 fee, ) =\n _getAccumulatedFees(\n _user,\n _token,\n _startFrom + i * _maxCheckpoints,\n _maxCheckpoints\n );\n fees[i] = fee;\n }\n\n return fees;\n }\n\n /**\n * @notice Gets accumulated fees for a user starting from a given checkpoint\n *\n * @param _user Address of the user's account.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Max checkpoints to process at once to fit into block gas limit\n * @param _startFrom Checkpoint num to start calculations from\n *\n * @return feesAmount - accumulated fees amount\n * @return endCheckpoint - last checkpoint of fees calculation\n * */\n function _getAccumulatedFees(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 feesAmount, uint256 endCheckpoint) {\n if (staking.isVestingContract(_user)) {\n return (0, 0);\n }\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n uint256 startOfRange =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n endCheckpoint = _maxCheckpoints > 0\n ? _getEndOfRange(startOfRange, _token, _maxCheckpoints)\n : totalTokenCheckpoints[_token];\n\n if (startOfRange >= totalTokenCheckpoints[_token]) {\n return (0, endCheckpoint);\n }\n\n uint256 cachedLockDate = 0;\n uint96 cachedWeightedStake = 0;\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startOfRange; i < endCheckpoint; i++) {\n Checkpoint memory checkpoint = tokenCheckpoints[_token][i];\n uint256 lockDate = staking.timestampToLockDate(checkpoint.timestamp);\n uint96 weightedStake;\n if (lockDate == cachedLockDate) {\n weightedStake = cachedWeightedStake;\n } else {\n /// @dev We need to use \"checkpoint.blockNumber - 1\" here to calculate weighted stake\n /// For the same block like we did for total voting power in _writeTokenCheckpoint\n weightedStake = staking.getPriorWeightedStake(\n _user,\n checkpoint.blockNumber - 1,\n checkpoint.timestamp\n );\n cachedWeightedStake = weightedStake;\n cachedLockDate = lockDate;\n }\n uint256 share =\n uint256(checkpoint.numTokens).mul(weightedStake).div(\n uint256(checkpoint.totalWeightedStake)\n );\n feesAmount = feesAmount.add(share);\n }\n return (feesAmount, endCheckpoint);\n }\n\n /**\n * @notice Withdrawal should only be possible for blocks which were already\n * mined. If the fees are withdrawn in the same block as the user withdrawal\n * they are not considered by the withdrawing logic (to avoid inconsistencies).\n *\n * @param _start Start of the range.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of a pool token.\n * @param _maxCheckpoints Checkpoint index incremental.\n * */\n function _getEndOfRange(\n uint256 _start,\n address _token,\n uint32 _maxCheckpoints\n ) internal view returns (uint256) {\n uint256 nextCheckpointIndex = totalTokenCheckpoints[_token];\n if (nextCheckpointIndex == 0) {\n return 0;\n }\n uint256 end;\n\n if (_maxCheckpoints == 0) {\n /// @dev All checkpoints will be processed (only for getter outside of a transaction).\n end = nextCheckpointIndex;\n } else {\n end = safe32(\n _start + _maxCheckpoints,\n \"FeeSharingCollector::withdraw: checkpoint index exceeds 32 bits\"\n );\n if (end > nextCheckpointIndex) {\n end = nextCheckpointIndex;\n }\n }\n\n /// @dev Withdrawal should only be possible for blocks which were already mined.\n uint32 lastBlockNumber = tokenCheckpoints[_token][end - 1].blockNumber;\n if (block.number == lastBlockNumber) {\n end--;\n }\n return end;\n }\n\n /**\n * @notice Write a regular checkpoint w/ the foolowing data:\n * block number, block timestamp, total weighted stake and num of tokens.\n * @param _token The pool token address.\n * @param _numTokens The amount of pool tokens.\n * */\n function _writeTokenCheckpoint(address _token, uint96 _numTokens) internal {\n uint32 blockNumber =\n safe32(\n block.number,\n \"FeeSharingCollector::_writeCheckpoint: block number exceeds 32 bits\"\n );\n uint32 blockTimestamp =\n safe32(\n block.timestamp,\n \"FeeSharingCollector::_writeCheckpoint: block timestamp exceeds 32 bits\"\n );\n uint256 nextCheckpointsIndex = totalTokenCheckpoints[_token];\n\n uint96 totalWeightedStake = _getVoluntaryWeightedStake(blockNumber - 1, block.timestamp);\n require(totalWeightedStake > 0, \"Invalid totalWeightedStake\");\n if (\n nextCheckpointsIndex > 0 &&\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].blockNumber == blockNumber\n ) {\n tokenCheckpoints[_token][nextCheckpointsIndex - 1]\n .totalWeightedStake = totalWeightedStake;\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].numTokens = _numTokens;\n } else {\n tokenCheckpoints[_token][nextCheckpointsIndex] = Checkpoint(\n blockNumber,\n blockTimestamp,\n totalWeightedStake,\n _numTokens\n );\n totalTokenCheckpoints[_token] = nextCheckpointsIndex + 1;\n }\n emit CheckpointAdded(msg.sender, _token, _numTokens);\n }\n\n /**\n * Queries the total weighted stake and the weighted stake of vesting contracts and returns the difference\n * @param blockNumber the blocknumber\n * @param timestamp the timestamp\n */\n function _getVoluntaryWeightedStake(uint32 blockNumber, uint256 timestamp)\n internal\n view\n returns (uint96 totalWeightedStake)\n {\n uint96 vestingWeightedStake = staking.getPriorVestingWeightedStake(blockNumber, timestamp);\n totalWeightedStake = staking.getPriorTotalVotingPower(blockNumber, timestamp);\n totalWeightedStake = sub96(\n totalWeightedStake,\n vestingWeightedStake,\n \"FeeSharingCollector::_getTotalVoluntaryWeightedStake: vested stake exceeds total stake\"\n );\n }\n\n /**\n * @dev Whitelisting converter address.\n *\n * @param converterAddress converter address to be whitelisted.\n */\n function addWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n require(Address.isContract(converterAddress), \"Non contract address given\");\n whitelistedConverterList.add(converterAddress);\n emit WhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @dev Removing converter address from whitelist.\n *\n * @param converterAddress converter address to be removed from whitelist.\n */\n function removeWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n whitelistedConverterList.remove(converterAddress);\n emit UnwhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @notice Getter to query all of the whitelisted converter.\n * @return All of the whitelisted converter list.\n */\n function getWhitelistedConverterList() external view returns (address[] memory converterList) {\n converterList = whitelistedConverterList.enumerate();\n }\n\n /**\n * @dev validate array of given address whether is whitelisted or not.\n * @dev if one of them is not whitelisted, then revert.\n *\n * @param converterAddresses array of converter addresses.\n */\n function _validateWhitelistedConverter(address[] memory converterAddresses) private view {\n for (uint256 i = 0; i < converterAddresses.length; i++) {\n require(whitelistedConverterList.contains(converterAddresses[i]), \"Invalid Converter\");\n }\n }\n\n function withdrawWRBTC(address receiver, uint256 wrbtcAmount) external onlyOwner {\n IERC20 wrbtcToken = IERC20(wrbtcTokenAddress);\n\n uint256 balance = wrbtcToken.balanceOf(address(this));\n require(wrbtcAmount <= balance, \"Insufficient balance\");\n\n wrbtcToken.safeTransfer(receiver, wrbtcAmount);\n }\n\n /**\n * @dev This function is dedicated to recover the wrong fee allocation for the 4 year vesting contracts.\n * This function can only be called once\n * The affected tokens to be withdrawn\n * 1. RBTC\n * 2. ZUSD\n * 3. SOV\n * The amount for all of the tokens above is hardcoded\n * The withdrawn tokens will be sent to the owner.\n */\n function recoverIncorrectAllocatedFees()\n external\n oneTimeExecution(this.recoverIncorrectAllocatedFees.selector)\n onlyOwner\n {\n uint256 rbtcAmount = 878778886164898400;\n uint256 zusdAmount = 16658600400155126000000;\n uint256 sovAmount = 6275898259771202000000;\n\n address zusdToken = 0xdB107FA69E33f05180a4C2cE9c2E7CB481645C2d;\n address sovToken = 0xEFc78fc7d48b64958315949279Ba181c2114ABBd;\n\n // Withdraw rbtc\n (bool success, ) = owner().call.value(rbtcAmount)(\"\");\n require(\n success,\n \"FeeSharingCollector::recoverIncorrectAllocatedFees: Withdrawal rbtc failed\"\n );\n\n // Withdraw ZUSD\n IERC20(zusdToken).safeTransfer(owner(), zusdAmount);\n\n // Withdraw SOV\n IERC20(sovToken).safeTransfer(owner(), sovAmount);\n }\n\n /**\n * @dev view function that calculate the total RBTC that includes:\n * - RBTC\n * - WRBTC\n * - iWRBTC * iWRBTC.tokenPrice()\n * @param _user address of the user.\n * @return rbtc balance of the given user's address.\n */\n function getAccumulatedRBTCFeeBalances(address _user) external view returns (uint256) {\n (uint256 _rbtcAmount, uint256 _wrbtcAmount, uint256 _iWrbtcAmount, , , ) =\n _getRBTCBalances(_user, 0);\n uint256 iWRBTCAmountInRBTC =\n _iWrbtcAmount.mul(ILoanTokenWRBTC(loanTokenWrbtcAddress).tokenPrice()).div(1e18);\n return _rbtcAmount.add(_wrbtcAmount).add(iWRBTCAmountInRBTC);\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _rbtcAmount rbtc amount\n * @return _wrbtcAmount wrbtc amount\n * @return _iWrbtcAmount iWrbtc (wrbtc lending pool token) amount * token price\n * @return _endRBTC end time of accumulated fee calculation for rbtc\n * @return _endWRBTC end time of accumulated fee calculation for wrbtc\n * @return _endIWRBTC end time of accumulated fee calculation for iwrbtc\n */\n function _getRBTCBalances(address _user, uint32 _maxCheckpoints)\n private\n view\n returns (\n uint256 _rbtcAmount,\n uint256 _wrbtcAmount,\n uint256 _iWrbtcAmount,\n uint256 _endRBTC,\n uint256 _endWRBTC,\n uint256 _endIWRBTC\n )\n {\n (_rbtcAmount, _endRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n\n (_wrbtcAmount, _endWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: wrbtcTokenAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n (_iWrbtcAmount, _endIWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: loanTokenWrbtcAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _token either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _tokenAmount token (rbtc, or wrbtc, or iwrbtc) amount\n * @return _endToken end time of accumulated fee calculation for token (rbtc, or wrbtc, or iwrbtc )\n */\n function _getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 _tokenAmount, uint256 _endToken) {\n if (\n _token == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT ||\n _token == wrbtcTokenAddress ||\n _token == loanTokenWrbtcAddress\n ) {\n (_tokenAmount, _endToken) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n } else {\n revert(\"FeeSharingCollector::_getRBTCBalance: only rbtc-based tokens are allowed\");\n }\n }\n\n // @todo update dependency `numTokenCheckpoints` -> `totalTokenCheckpoints` and deprecate numTokenCheckpoints function\n /**\n * @dev This getter function `numTokenCheckpoints` is added for backwards compatibility\n * broken when renamed `numTokenCheckpoints` storage variable to `totalTokenCheckpoints`.\n *\n * @param _token token address to get checkpoints for\n *\n * @return Total token checkpoints\n */\n function numTokenCheckpoints(address _token) external view returns (uint256) {\n return totalTokenCheckpoints[_token];\n }\n}\n\n/* Interfaces */\ninterface ILoanToken {\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n}\n\ninterface ILoanTokenWRBTC {\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function tokenPrice() external view returns (uint256 price);\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title FeeSharingCollectorProxy contract.\n * @dev FeeSharingCollectorProxy contract should be upgradable, use UpgradableProxy.\n * FeeSharingCollectorStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract FeeSharingCollectorProxy is FeeSharingCollectorStorage, UpgradableProxy {\n /**\n * @notice Construct a new feeSharingCollectorProxy contract.\n * @param _protocol The address of the sovryn protocol.\n * @param _staking The address of the staking\n */\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorStorage.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../mixins/EnumerableAddressSet.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\n\n/**\n * @title FeeSharingCollectorStorage contact\n * @notice Just the storage part of FeeSharingCollector contract, and FeeSharingCollectorProxy. No functions,\n * only constant, variables and required structures (mappings)\n * */\ncontract FeeSharingCollectorStorage is Ownable {\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet;\n uint256 constant FEE_WITHDRAWAL_INTERVAL = 172800;\n\n IProtocol public protocol;\n IStaking public staking;\n\n /// @notice Checkpoints by index per pool token address\n mapping(address => mapping(uint256 => Checkpoint)) public tokenCheckpoints;\n\n /// @notice The number of checkpoints for each token address.\n mapping(address => uint256) public totalTokenCheckpoints;\n\n /// @notice\n /// user => token => processed checkpoints\n mapping(address => mapping(address => uint256)) public processedCheckpoints;\n\n /// @notice Last time fees were withdrawn per pool token address:\n /// token => time\n mapping(address => uint256) public lastFeeWithdrawalTime;\n\n /// @notice Amount of tokens that were transferred, but not saved in checkpoints.\n /// token => amount\n mapping(address => uint96) public unprocessedAmount;\n\n struct Checkpoint {\n uint32 blockNumber;\n uint32 timestamp;\n uint96 totalWeightedStake;\n uint96 numTokens;\n }\n\n struct TokenWithSkippedCheckpointsWithdraw {\n address tokenAddress;\n uint256 fromCheckpoint;\n }\n\n /**\n * @dev Add extra modifier (Reentrancy) below.\n * Because we cannot add any additional storage slot before this storage contract after initial deployment\n */\n\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Additional storage for converter whitelist mechanism.\n * @dev Initialization here does not works. We need to create a separate setter & getter.\n * @dev Just set the visibility to internal should be fine.\n */\n EnumerableAddressSet.AddressSet internal whitelistedConverterList;\n\n mapping(bytes4 => bool) public isFunctionExecuted;\n\n /**\n * @dev Wrbtc token address\n */\n address public wrbtcTokenAddress;\n\n /**\n * @dev iWrbtc loan token address\n */\n address public loanTokenWrbtcAddress;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n\n/* Interfaces */\n\ninterface IProtocol {\n /**\n *\n * @param tokens The array address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function underlyingToLoanPool(address token) external view returns (address);\n\n function wrbtcToken() external view returns (IWrbtcERC20);\n\n function getSovTokenAddress() external view returns (address);\n}\n" + }, + "contracts/governance/GovernorAlpha.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./Staking/SafeMath96.sol\";\nimport \"./Timelock.sol\";\nimport \"./Staking/interfaces/IStaking.sol\";\nimport \"../rsk/RSKAddrValidator.sol\";\n\n/**\n * @title Governance Contract.\n * @notice This is an adapted clone of compound’s governance model. In general,\n * the process is the same: Token holders can make (executable) proposals if\n * they possess enough voting power, vote on proposals during a predefined\n * voting period and in the end evaluate the outcome. If successful, the\n * proposal will be scheduled on the timelock contract. Only after sufficient\n * time passed, it can be executed. A minimum voting power is required for\n * making a proposal as well as a minimum quorum.\n *\n * Voting power in the Bitocracy:\n * Stakers will receive voting power in the Bitocracy in return for their\n * staking commitment. This voting power is weighted by how much SOV is staked\n * and for how long the staking period is - staking more SOV over longer staking\n * periods results in higher voting power. With this voting power, users can\n * vote for or against any SIP in bitocracy.sovryn.app.\n * */\ncontract GovernorAlpha is SafeMath96 {\n /* Storage */\n\n /// @notice The name of this contract.\n string public constant NAME = \"Sovryn Governor Alpha\";\n\n /// @notice The maximum number of actions that can be included in a proposal.\n function proposalMaxOperations() public pure returns (uint256) {\n return 10;\n } // 10 actions\n\n /// @notice The delay before voting on a proposal may take place, once proposed.\n function votingDelay() public pure returns (uint256) {\n return 1;\n } // 1 block\n\n /// @notice The duration of voting on a proposal, in blocks.\n function votingPeriod() public pure returns (uint256) {\n return 2880;\n } // ~1 day in blocks (assuming 30s blocks)\n\n /// @notice The address of the Sovryn Protocol Timelock.\n ITimelock public timelock;\n\n /// @notice The address of the Sovryn staking contract.\n IStaking public staking;\n\n /// @notice The address of the Governor Guardian.\n address public guardian;\n\n /// @notice The total number of proposals.\n uint256 public proposalCount;\n\n /// @notice Percentage of current total voting power require to vote.\n uint96 public quorumPercentageVotes;\n\n // @notice Majority percentage.\n uint96 public majorityPercentageVotes;\n\n struct Proposal {\n /// @notice Unique id for looking up a proposal.\n uint256 id;\n /// @notice The block at which voting begins: holders must delegate their votes prior to this block.\n uint32 startBlock;\n /// @notice The block at which voting ends: votes must be cast prior to this block.\n uint32 endBlock;\n /// @notice Current number of votes in favor of this proposal.\n uint96 forVotes;\n /// @notice Current number of votes in opposition to this proposal.\n uint96 againstVotes;\n ///@notice the quorum required for this proposal.\n uint96 quorum;\n ///@notice the majority percentage required for this proposal.\n uint96 majorityPercentage;\n /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds.\n uint64 eta;\n /// @notice the start time is required for the staking contract.\n uint64 startTime;\n /// @notice Flag marking whether the proposal has been canceled.\n bool canceled;\n /// @notice Flag marking whether the proposal has been executed.\n bool executed;\n /// @notice Creator of the proposal.\n address proposer;\n /// @notice the ordered list of target addresses for calls to be made.\n address[] targets;\n /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made.\n uint256[] values;\n /// @notice The ordered list of function signatures to be called.\n string[] signatures;\n /// @notice The ordered list of calldata to be passed to each call.\n bytes[] calldatas;\n /// @notice Receipts of ballots for the entire set of voters.\n mapping(address => Receipt) receipts;\n }\n\n /// @notice Ballot receipt record for a voter\n struct Receipt {\n /// @notice Whether or not a vote has been cast.\n bool hasVoted;\n /// @notice Whether or not the voter supports the proposal.\n bool support;\n /// @notice The number of votes the voter had, which were cast.\n uint96 votes;\n }\n\n /// @notice Possible states that a proposal may be in.\n enum ProposalState {\n Pending,\n Active,\n Canceled,\n Defeated,\n Succeeded,\n Queued,\n Expired,\n Executed\n }\n\n /// @notice The official record of all proposals ever proposed.\n mapping(uint256 => Proposal) public proposals;\n\n /// @notice The latest proposal for each proposer.\n mapping(address => uint256) public latestProposalIds;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the ballot struct used by the contract.\n bytes32 public constant BALLOT_TYPEHASH = keccak256(\"Ballot(uint256 proposalId,bool support)\");\n\n /* Events */\n\n /// @notice An event emitted when a new proposal is created.\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint256 startBlock,\n uint256 endBlock,\n string description\n );\n\n /// @notice An event emitted when a vote has been cast on a proposal.\n event VoteCast(address voter, uint256 proposalId, bool support, uint256 votes);\n\n /// @notice An event emitted when a proposal has been canceled.\n event ProposalCanceled(uint256 id);\n\n /// @notice An event emitted when a proposal has been queued in the Timelock.\n event ProposalQueued(uint256 id, uint256 eta);\n\n /// @notice An event emitted when a proposal has been executed in the Timelock.\n event ProposalExecuted(uint256 id);\n\n /* Functions */\n\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 _quorumPercentageVotes,\n uint96 _majorityPercentageVotes\n ) public {\n timelock = ITimelock(timelock_);\n staking = IStaking(staking_);\n guardian = guardian_;\n quorumPercentageVotes = _quorumPercentageVotes;\n majorityPercentageVotes = _majorityPercentageVotes;\n }\n\n /// @notice The number of votes required in order for a voter to become a proposer.\n function proposalThreshold() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(\n block.number - 1,\n \"GovernorAlpha::proposalThreshold: block number overflow\"\n ),\n block.timestamp\n );\n // 1% of current total voting power.\n return totalVotingPower / 100;\n }\n\n /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.\n function quorumVotes() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(block.number - 1, \"GovernorAlpha::quorumVotes: block number overflow\"),\n block.timestamp\n );\n // 4% of current total voting power.\n return\n mul96(\n quorumPercentageVotes,\n totalVotingPower,\n \"GovernorAlpha::quorumVotes:multiplication overflow\"\n ) / 100;\n }\n\n /**\n * @notice Create a new proposal.\n * @param targets Array of contract addresses to perform proposal execution.\n * @param values Array of rBTC amounts to send on proposal execution.\n * @param signatures Array of function signatures to call on proposal execution.\n * @param calldatas Array of payloads for the calls on proposal execution.\n * @param description Text describing the purpose of the proposal.\n * */\n function propose(\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // note: passing this block's timestamp, but the number of the previous block.\n // todo: think if it would be better to pass block.timestamp - 30 (average block time)\n // (probably not because proposal starts in 1 block from now).\n uint96 threshold = proposalThreshold();\n require(\n staking.getPriorVotes(msg.sender, sub256(block.number, 1), block.timestamp) >\n threshold,\n \"GovernorAlpha::propose: proposer votes below proposal threshold\"\n );\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"GovernorAlpha::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"GovernorAlpha::propose: must provide actions\");\n require(\n targets.length <= proposalMaxOperations(),\n \"GovernorAlpha::propose: too many actions\"\n );\n\n uint256 latestProposalId = latestProposalIds[msg.sender];\n if (latestProposalId != 0) {\n ProposalState proposersLatestProposalState = state(latestProposalId);\n require(\n proposersLatestProposalState != ProposalState.Active,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already active proposal\"\n );\n require(\n proposersLatestProposalState != ProposalState.Pending,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal\"\n );\n }\n\n uint256 startBlock = add256(block.number, votingDelay());\n uint256 endBlock = add256(startBlock, votingPeriod());\n\n proposalCount++;\n\n /// @dev quorum: proposalThreshold is 1% of total votes, we can save gas using this pre calculated value.\n /// @dev startTime: Required by the staking contract. not used by the governance contract itself.\n Proposal memory newProposal =\n Proposal({\n id: proposalCount,\n startBlock: safe32(\n startBlock,\n \"GovernorAlpha::propose: start block number overflow\"\n ),\n endBlock: safe32(endBlock, \"GovernorAlpha::propose: end block number overflow\"),\n forVotes: 0,\n againstVotes: 0,\n quorum: mul96(\n quorumPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on quorum computation\"\n ),\n majorityPercentage: mul96(\n majorityPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on majorityPercentage computation\"\n ),\n eta: 0,\n startTime: safe64(block.timestamp, \"GovernorAlpha::propose: startTime overflow\"),\n canceled: false,\n executed: false,\n proposer: msg.sender,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas\n });\n\n proposals[newProposal.id] = newProposal;\n latestProposalIds[newProposal.proposer] = newProposal.id;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n values,\n signatures,\n calldatas,\n startBlock,\n endBlock,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Enqueue a proposal and everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function queue(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Succeeded,\n \"GovernorAlpha::queue: proposal can only be queued if it is succeeded\"\n );\n Proposal storage proposal = proposals[proposalId];\n uint256 eta = add256(block.timestamp, timelock.delay());\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n proposal.eta = safe64(eta, \"GovernorAlpha::queue: ETA overflow\");\n emit ProposalQueued(proposalId, eta);\n }\n\n /**\n * @notice Tries to enqueue a proposal, verifying it has not been previously queued.\n * @param target Contract addresses to perform proposal execution.\n * @param value rBTC amount to send on proposal execution.\n * @param signature Function signature to call on proposal execution.\n * @param data Payload for the call on proposal execution.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function _queueOrRevert(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !timelock.queuedTransactions(\n keccak256(abi.encode(target, value, signature, data, eta))\n ),\n \"GovernorAlpha::_queueOrRevert: proposal action already queued at eta\"\n );\n timelock.queueTransaction(target, value, signature, data, eta);\n }\n\n /**\n * @notice Execute a proposal by looping and performing everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function execute(uint256 proposalId) public payable {\n require(\n state(proposalId) == ProposalState.Queued,\n \"GovernorAlpha::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.executeTransaction.value(proposal.values[i])(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal by looping and cancelling everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function cancel(uint256 proposalId) public {\n ProposalState state = state(proposalId);\n require(\n state != ProposalState.Executed,\n \"GovernorAlpha::cancel: cannot cancel executed proposal\"\n );\n\n Proposal storage proposal = proposals[proposalId];\n /// @notice Cancel only if sent by the guardian.\n require(msg.sender == guardian, \"GovernorAlpha::cancel: sender isn't a guardian\");\n\n proposal.canceled = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalCanceled(proposalId);\n }\n\n /**\n * @notice Get a proposal list of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return Arrays of the 4 call parameters: targets, values, signatures, calldatas.\n * */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.values, p.signatures, p.calldatas);\n }\n\n /**\n * @notice Get a proposal receipt.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param voter A governance stakeholder with voting power.\n * @return The voter receipt of the proposal.\n * */\n function getReceipt(uint256 proposalId, address voter) public view returns (Receipt memory) {\n return proposals[proposalId].receipts[voter];\n }\n\n /**\n * @notice Casts a vote by sender.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function castVote(uint256 proposalId, bool support) public {\n return _castVote(msg.sender, proposalId, support);\n }\n\n /**\n * @notice Voting with EIP-712 Signatures.\n *\n * Voting power can be delegated to any address, and then can be used to\n * vote on proposals. A key benefit to users of by-signature functionality\n * is that they can create a signed vote transaction for free, and have a\n * trusted third-party spend rBTC(or ETH) on gas fees and write it to the\n * blockchain for them.\n *\n * The third party in this scenario, submitting the SOV-holder’s signed\n * transaction holds a voting power that is for only a single proposal.\n * The signatory still holds the power to vote on their own behalf in\n * the proposal if the third party has not yet published the signed\n * transaction that was given to them.\n *\n * @dev The signature needs to be broken up into 3 parameters, known as\n * v, r and s:\n * const r = '0x' + sig.substring(2).substring(0, 64);\n * const s = '0x' + sig.substring(2).substring(64, 128);\n * const v = '0x' + sig.substring(2).substring(128, 130);\n *\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * @param v The recovery byte of the signature.\n * @param r Half of the ECDSA signature pair.\n * @param s Half of the ECDSA signature pair.\n * */\n function castVoteBySig(\n uint256 proposalId,\n bool support,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public {\n /**\n * @dev The DOMAIN_SEPARATOR is a hash that uniquely identifies a\n * smart contract. It is built from a string denoting it as an\n * EIP712 Domain, the name of the token contract, the version,\n * the chainId in case it changes, and the address that the\n * contract is deployed at.\n * */\n bytes32 domainSeparator =\n keccak256(\n abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this))\n );\n\n /// @dev GovernorAlpha uses BALLOT_TYPEHASH, while Staking uses DELEGATION_TYPEHASH\n bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support));\n\n bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n address signatory = ecrecover(digest, v, r, s);\n\n /// @dev Verify address is not null and PK is not null either.\n require(\n RSKAddrValidator.checkPKNotZero(signatory),\n \"GovernorAlpha::castVoteBySig: invalid signature\"\n );\n return _castVote(signatory, proposalId, support);\n }\n\n /**\n * @notice Cast a vote, adding it to the total counting.\n * @param voter A governance stakeholder with voting power that is casting the vote.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function _castVote(\n address voter,\n uint256 proposalId,\n bool support\n ) internal {\n require(\n state(proposalId) == ProposalState.Active,\n \"GovernorAlpha::_castVote: voting is closed\"\n );\n Proposal storage proposal = proposals[proposalId];\n Receipt storage receipt = proposal.receipts[voter];\n require(receipt.hasVoted == false, \"GovernorAlpha::_castVote: voter already voted\");\n uint96 votes = staking.getPriorVotes(voter, proposal.startBlock, proposal.startTime);\n\n if (support) {\n proposal.forVotes = add96(\n proposal.forVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n } else {\n proposal.againstVotes = add96(\n proposal.againstVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n }\n\n receipt.hasVoted = true;\n receipt.support = support;\n receipt.votes = votes;\n\n emit VoteCast(voter, proposalId, support, votes);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __acceptAdmin() public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__acceptAdmin: sender must be gov guardian\"\n );\n timelock.acceptAdmin();\n }\n\n /// @notice Sets guardian address to zero.\n function __abdicate() public {\n require(msg.sender == guardian, \"GovernorAlpha::__abdicate: sender must be gov guardian\");\n guardian = address(0);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.queueTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.executeTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /**\n * @notice Get a proposal state.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return The state of the proposal: Canceled, Pending, Active, Defeated,\n * Succeeded, Executed, Expired.\n * */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"GovernorAlpha::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n\n if (proposal.canceled) {\n return ProposalState.Canceled;\n }\n\n if (block.number <= proposal.startBlock) {\n return ProposalState.Pending;\n }\n\n if (block.number <= proposal.endBlock) {\n return ProposalState.Active;\n }\n\n uint96 totalVotes =\n add96(\n proposal.forVotes,\n proposal.againstVotes,\n \"GovernorAlpha:: state: forVotes + againstVotes > uint96\"\n );\n uint96 totalVotesMajorityPercentage =\n div96(totalVotes, 100, \"GovernorAlpha:: state: division error\");\n totalVotesMajorityPercentage = mul96(\n totalVotesMajorityPercentage,\n majorityPercentageVotes,\n \"GovernorAlpha:: state: totalVotes * majorityPercentage > uint96\"\n );\n if (proposal.forVotes <= totalVotesMajorityPercentage || totalVotes < proposal.quorum) {\n return ProposalState.Defeated;\n }\n\n if (proposal.eta == 0) {\n return ProposalState.Succeeded;\n }\n\n if (proposal.executed) {\n return ProposalState.Executed;\n }\n\n if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) {\n return ProposalState.Expired;\n }\n\n return ProposalState.Queued;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function add256(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"addition overflow\");\n return c;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function sub256(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b <= a, \"subtraction underflow\");\n return a - b;\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n}\n\n/* Interfaces */\n\ninterface TimelockInterface {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\ninterface StakingInterface {\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n}\n" + }, + "contracts/governance/GovernorVault.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title Governance Vault.\n * @notice This contract stores tokens and rBTC only transfereble by owner,\n * i.e. Sovryn governance.\n * */\ncontract GovernorVault is Ownable {\n /* Events */\n\n event Deposited(address indexed sender, uint256 amount);\n event TokensTransferred(address indexed receiver, address indexed token, uint256 amount);\n event RbtcTransferred(address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer tokens.\n * @param _receiver The receiver of tokens.\n * @param _token The address of token contract.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _receiver,\n address _token,\n uint256 _amount\n ) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n require(_token != address(0), \"Invalid token address\");\n\n require(IERC20(_token).transfer(_receiver, _amount), \"Transfer failed\");\n emit TokensTransferred(_receiver, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC.\n * @param _receiver The receiver of RBTC.\n * @param _amount The amount to be transferred.\n * */\n function transferRbtc(address payable _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n\n address(_receiver).transfer(_amount);\n emit RbtcTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {\n if (msg.value > 0) {\n emit Deposited(msg.sender, msg.value);\n }\n }\n}\n" + }, + "contracts/governance/IFeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * */\ninterface IFeeSharingCollector {\n function withdrawFees(address[] calldata _token) external;\n\n function transferTokens(address _token, uint96 _amount) external;\n\n function withdraw(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external;\n}\n" + }, + "contracts/governance/Staking/interfaces/IStaking.sol": { + "content": "pragma solidity ^0.5.17;\n\npragma experimental ABIEncoderV2;\n\n/**\n * @title Interface for Staking modules governance/Staking/modules\n */\n\ninterface IStaking {\n /*************************** StakingAdminModule ***************************/\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external;\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external;\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external;\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external;\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) external;\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external;\n\n /**\n * @notice Allows the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external;\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external;\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external;\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\n\n /*************************** StakingGovernanceModule ***************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\n * be internal instead of a public function.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external;\n\n /*************************** StakingStakeModule ***************************/\n\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance);\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes);\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\n\n /*************************** StakingStorageModule ***************************/\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n /// @return uint256(MAX_VOTING_WEIGHT);\n function getStorageMaxVotingWeight() external pure returns (uint256);\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n /// @return uint256(WEIGHT_FACTOR);\n function getStorageWeightFactor() external pure returns (uint256);\n\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\n function getStorageDefaultWeightScaling() external pure returns (uint256);\n\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\n\n /// @notice The EIP-712 typehash for the contract's domain.\n /// @return uint256(DOMAIN_TYPEHASH);\n function getStorageDomainTypehash() external pure returns (uint256);\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n /// @return uint256(DELEGATION_TYPEHASH);\n function getStorageDelegationTypehash() external pure returns (uint256);\n\n /// @return name;\n function getStorageName() external view returns (string memory);\n\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n function kickoffTS() external view returns (uint256);\n\n /// @notice The token to be staked\n function SOVToken() external view returns (address);\n\n /// @notice Stakers delegated voting power\n /// @param staker - the delegating address\n /// @param until - delegated voting\n /// @return _delegate - voting power delegated to address\n function delegates(address staker, uint256 until) external view returns (address _delegate);\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately\n /// see function unlockAllTokens() for details\n function allUnlocked() external view returns (bool);\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\n function newStakingContract() external view returns (address);\n\n /// CHECKPOINTS\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\n function totalStakingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n function numTotalStakingCheckpoints(uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n function delegateStakingCheckpoints(\n address delagatee,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n function userStakingCheckpoints(\n address user,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number\n function numUserStakingCheckpoints(address user, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n function nonces(address user) external view returns (uint256 nonce);\n\n /// SLASHING ///\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n function feeSharing() external view returns (address);\n\n /// @notice used for weight scaling when unstaking with slashing.\n /// @return uint96 DEFAULT_WEIGHT_SCALING\n function weightScaling() external view returns (uint96);\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n function admins(address isAdmin) external view returns (bool);\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n function vestingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\n\n ///@notice vesting registry contract PROXY address\n function vestingRegistryLogic() external view returns (address);\n\n /// @dev user => flag whether user has pauser role.\n function pausers(address isPauser) external view returns (bool);\n\n /// @dev Staking contract is paused\n function paused() external view returns (bool);\n\n /// @dev Staking contract is frozen\n function frozen() external view returns (bool);\n\n /*************************** StakingVestingModule ***************************/\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool);\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external;\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external;\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes);\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n /*************************** StakingWithdrawModule ***************************/\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * */\n function governanceWithdrawVesting(address vesting, address receiver) external;\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96);\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external;\n\n /*************************** WeightedStakingModule ***************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The date/timestamp of the unstaking time.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * TODO: WeightedStaking::weightedStakeByDate should probably better\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Returns public constant MAX_DURATION\n * preserved for backwards compatibility\n * Use getStorageMaxDurationToStakeTokens()\n * @return uint96 MAX_DURATION for staking\n **/\n function MAX_DURATION() external view returns (uint256);\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() external view returns (address);\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() external view returns (bool);\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) external;\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external;\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() external view returns (uint256);\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param maxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\n}\n" + }, + "contracts/governance/Staking/modules/shared/CheckpointsShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\n\n/**\n * @title Checkpoints contract.\n * @notice Increases and decreases storage values for users, delegatees and\n * total daily stake.\n * */\ncontract CheckpointsShared is StakingStorageShared, SafeMath96 {\n /// @notice An event emitted when an account changes its delegate.\n event DelegateChanged(\n address indexed delegator,\n uint256 lockedUntil,\n address indexed fromDelegate,\n address indexed toDelegate\n );\n\n /// @notice An event emitted when a delegate account's stake balance changes.\n event DelegateStakeChanged(\n address indexed delegate,\n uint256 lockedUntil,\n uint256 previousBalance,\n uint256 newBalance\n );\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n event ContractCodeHashAdded(bytes32 hash);\n\n event ContractCodeHashRemoved(bytes32 hash);\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n event TeamVestingCancelled(address indexed caller, address receiver);\n\n event TeamVestingPartiallyCancelled(\n address indexed caller,\n address receiver,\n uint256 lastProcessedDate\n );\n\n constructor() internal {\n // abstract\n }\n\n /**\n * @notice Increases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = add96(vested, value, \"CP01\"); // vested overflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Decreases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = sub96(vested, value, \"CP02\"); // vested underflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Writes on storage the user vested amount.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newVest The new vest balance.\n * */\n function _writeVestingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newVest\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP03\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n vestingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n vestingCheckpoints[lockedTS][nCheckpoints - 1].stake = newVest;\n } else {\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newVest);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP04\"); // staked overflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP05\"); // staked underflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the user stake.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeUserCheckpoint(\n address account,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP06\"); // block number > 32 bits\n\n if (\n nCheckpoints > 0 &&\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n userStakingCheckpoints[account][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numUserStakingCheckpoints[account][lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP07\"); // block number > 32 bits\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = 0;\n // @dev We need to check delegate checkpoint value here,\n //\t\tbecause we had an issue in `stake` function:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n // @dev It can be greater than 0, but inconsistent after 3 transactions\n if (staked > value) {\n newStake = sub96(staked, value, \"CP08\"); // staked underflow\n }\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the delegate stake.\n * @param delegatee The delegate address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeDelegateCheckpoint(\n address delegatee,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP09\"); // block numb > 32 bits\n uint96 oldStake = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n\n if (\n nCheckpoints > 0 &&\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].fromBlock ==\n blockNumber\n ) {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numDelegateStakingCheckpoints[delegatee][lockedTS] = nCheckpoints + 1;\n }\n emit DelegateStakeChanged(delegatee, lockedTS, oldStake, newStake);\n }\n\n /**\n * @notice Increases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP10\"); // staked overflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP11\"); // staked underflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the total stake.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeStakingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP12\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n totalStakingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newStake);\n numTotalStakingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Get the current balance of an account locked until a certain date.\n * @param account The user address.\n * @param lockDate The lock date.\n * @return The stake amount.\n * */\n function _currentBalance(address account, uint256 lockDate) internal view returns (uint96) {\n uint32 _numUnserStakingCheckpoints = numUserStakingCheckpoints[account][lockDate] - 1;\n return userStakingCheckpoints[account][lockDate][_numUnserStakingCheckpoints].stake;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\nimport \"../../../../openzeppelin/SafeMath.sol\";\nimport \"../../../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking modules shared functionality\n */\ncontract StakingShared is StakingStorageShared, SafeMath96 {\n using SafeMath for uint256;\n\n uint256 internal constant FOUR_WEEKS = 4 weeks;\n\n /**\n * @dev Throws if paused.\n */\n modifier whenNotPaused() {\n require(!paused, \"paused\"); // SS03\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\"); // SS01\n _;\n }\n\n /**\n\t * @dev Throws if called by any account other than the owner or admin or pauser.\n\t \n\tmodifier onlyAuthorizedOrPauser() {\n\t\trequire(isOwner() || admins[msg.sender] || pausers[msg.sender], \"unauthorized\"); // WS02\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if called by any account other than the owner or pauser.\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || pausers[msg.sender], \"unauthorized\"); // SS02\n _;\n }\n\n /**\n * @dev Throws if called by any account other than pauser.\n * @notice Uncomment when needed\n */\n /*\n\tmodifier onlyPauser() {\n\t\trequire(pausers[msg.sender], \"Not pauser\");\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if frozen.\n */\n modifier whenNotFrozen() {\n require(!frozen, \"paused\"); // SS04\n _;\n }\n\n constructor() internal {\n // abstract\n }\n\n function _notSameBlockAsStakingCheckpoint(uint256 lockDate, address stakeFor) internal view {\n uint32 nCheckpoints = numUserStakingCheckpoints[stakeFor][lockDate];\n bool notSameBlock =\n userStakingCheckpoints[stakeFor][lockDate][nCheckpoints - 1].fromBlock != block.number;\n require(notSameBlock, \"cannot be mined in the same block as last stake\"); // S20\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = kickoffTS;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / TWO_WEEKS;\n lockDate = periodFromKickoff * TWO_WEEKS + start;\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS14\n\n date = _adjustDateForOrigin(date);\n uint32 nCheckpoints = numUserStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (userStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return userStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (userStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = userStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return userStakingCheckpoints[account][date][lower].stake;\n }\n\n /**\n * @dev origin vesting contracts have different dates\n * we need to add 2 weeks to get end of period (by default, it's start)\n * @param date The staking date to compute the power for.\n * @return unlocking date.\n */\n function _adjustDateForOrigin(uint256 date) internal view returns (uint256) {\n uint256 adjustedDate = _timestampToLockDate(date);\n //origin vesting contracts have different dates\n //we need to add 2 weeks to get end of period (by default, it's start)\n if (adjustedDate != date) {\n date = adjustedDate + TWO_WEEKS;\n }\n return date;\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function _computeWeightByDate(uint256 date, uint256 startDate)\n internal\n pure\n returns (uint96 weight)\n {\n require(date >= startDate, \"date < startDate\"); // WS18\n uint256 remainingTime = (date - startDate);\n require(MAX_DURATION >= remainingTime, \"remaining time > max duration\"); // WS19\n /// @dev x = max days - remaining days\n uint96 x = uint96(MAX_DURATION - remainingTime) / (1 days);\n /// @dev w = (m^2 - x^2)/m^2 +1 (multiplied by the weight factor)\n weight = add96(\n WEIGHT_FACTOR,\n mul96(\n MAX_VOTING_WEIGHT * WEIGHT_FACTOR,\n sub96(\n MAX_DURATION_POW_2,\n x * x,\n \"weight underflow\" // WS20\n ),\n \"weight mul overflow\" // WS21\n ) / MAX_DURATION_POW_2,\n \"overflow on weight\" // WS22\n );\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function _isVestingContract(address stakerAddress) internal view returns (bool) {\n bool isVesting;\n bytes32 codeHash;\n\n assembly {\n codeHash := extcodehash(stakerAddress)\n }\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingStorageShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../../openzeppelin/Ownable.sol\";\nimport \"../../../../interfaces/IERC20.sol\";\nimport \"../../../IFeeSharingCollector.sol\";\nimport \"../../../Vesting/IVestingRegistry.sol\";\n\n/**\n * @title StakingStorageShared contract is inherited by Staking modules.\n * @notice Just the storage part of stacking contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingProxy and Checkpoints contracts.\n *\n * What is SOV staking?\n * The purpose of the SOV token is to provide a pseudonymous,\n * censorship-resistant mechanism for governing the parameters of the Sovryn\n * protocol, while aligning the incentives of protocol governors with the\n * long-term success of the protocol. Any SOV token holder can choose to\n * stake (lock up) their tokens for a fixed period of time in return for\n * voting rights in the Bitocracy. Stakers are further incentivised through\n * fee and slashing rewards.\n * */\ncontract StakingStorageShared is Ownable {\n /// @notice 2 weeks in seconds.\n uint256 constant TWO_WEEKS = 1209600;\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n uint96 public constant MAX_VOTING_WEIGHT = 9;\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n uint96 public constant WEIGHT_FACTOR = 10;\n\n /// @notice The maximum duration to stake tokens for.\n uint256 public constant MAX_DURATION = 1092 days;\n\n /// @notice The maximum duration ^2\n uint96 constant MAX_DURATION_POW_2 = 1092 * 1092;\n\n /// @notice Default weight scaling.\n uint96 constant DEFAULT_WEIGHT_SCALING = 3;\n\n /// @notice Range for weight scaling.\n uint96 constant MIN_WEIGHT_SCALING = 1;\n uint96 constant MAX_WEIGHT_SCALING = 9;\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n uint256 public kickoffTS;\n\n string name = \"SOVStaking\";\n\n /// @notice The token to be staked.\n IERC20 public SOVToken;\n\n /// @notice A record of each accounts delegate.\n mapping(address => mapping(uint256 => address)) public delegates;\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately.\n bool public allUnlocked = false;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n bytes32 public constant DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 lockDate,uint256 nonce,uint256 expiry)\");\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure.\n address public newStakingContract;\n\n /*************************** Checkpoints *******************************/\n\n /// @notice A checkpoint for marking the stakes from a given block\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public totalStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numTotalStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public delegateStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numDelegateStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public userStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numUserStakingCheckpoints;\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n mapping(address => uint256) public nonces;\n\n /*************************** Slashing *******************************/\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n IFeeSharingCollector public feeSharing;\n\n /// @notice used for weight scaling when unstaking with slashing.\n uint96 public weightScaling = DEFAULT_WEIGHT_SCALING;\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n mapping(address => bool) public vestingWhitelist;\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n mapping(address => bool) public admins;\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n mapping(bytes32 => bool) public vestingCodeHashes;\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public vestingCheckpoints;\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numVestingCheckpoints;\n\n ///@notice vesting registry contract\n IVestingRegistry public vestingRegistryLogic;\n\n /// @dev user => flag whether user has pauser role.\n mapping(address => bool) public pausers;\n\n /// @dev Staking contract is paused\n bool public paused;\n\n /// @dev Staking contract is frozen\n bool public frozen;\n\n /// @dev max iterations that can be supported in 1 tx for the withdrawal\n uint256 internal maxVestingWithdrawIterations;\n\n constructor() internal {\n //abstract\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingAdminModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Admin Module.\n * @notice Implements administrative functionality pause, freeze and setting addresses and parameters\n * related to staking\n * */\ncontract StakingAdminModule is IFunctionsList, StakingShared {\n using Address for address payable;\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(_admin != address(0), \"cannot add the zero address as an admin\");\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(admins[_admin], \"address is not an admin\");\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external onlyOwner whenNotFrozen {\n require(_pauser != address(0), \"cannot add the zero address as a pauser\");\n pausers[_pauser] = true;\n emit PauserAddedOrRemoved(_pauser, true);\n }\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external onlyOwner whenNotFrozen {\n require(pausers[_pauser], \"address is not a pauser\");\n delete pausers[_pauser];\n emit PauserAddedOrRemoved(_pauser, false);\n }\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) public onlyPauserOrOwner whenNotFrozen {\n paused = _pause;\n emit StakingPaused(_pause);\n }\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external onlyPauserOrOwner {\n require(_freeze != frozen, \"Cannot freeze/unfreeze to the same state\"); // WS25\n if (_freeze) pauseUnpause(true);\n frozen = _freeze;\n emit StakingFrozen(_freeze);\n }\n\n /**\n * @notice Allow the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external onlyOwner whenNotFrozen {\n require(_feeSharing != address(0), \"FeeSharing address shouldn't be 0\"); // S17\n feeSharing = IFeeSharingCollector(_feeSharing);\n }\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external onlyOwner whenNotFrozen {\n require(\n MIN_WEIGHT_SCALING <= _weightScaling && _weightScaling <= MAX_WEIGHT_SCALING,\n \"scaling doesn't belong to range [1, 9]\" // S18\n );\n weightScaling = _weightScaling;\n }\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external onlyOwner whenNotFrozen {\n require(_newStakingContract != address(0), \"can't reset the new staking contract to 0\"); // S16\n newStakingContract = _newStakingContract;\n }\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external whenNotFrozen {\n require(newStakingContract != address(0), \"there is no new staking contract set\"); // S19\n revert(\"not implemented\");\n /// @dev implementation:\n /// @dev Iterate over all possible lock dates from now until now + MAX_DURATION.\n /// @dev Read the stake & delegate of the msg.sender\n /// @dev If stake > 0, stake it at the new contract until the lock date with the current delegate.\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](13);\n functionsList[0] = this.addAdmin.selector;\n functionsList[1] = this.removeAdmin.selector;\n functionsList[2] = this.addPauser.selector;\n functionsList[3] = this.removePauser.selector;\n functionsList[4] = this.pauseUnpause.selector;\n functionsList[5] = this.freezeUnfreeze.selector;\n functionsList[6] = this.setFeeSharing.selector;\n functionsList[7] = this.setWeightScaling.selector;\n functionsList[8] = this.setNewStakingContract.selector;\n functionsList[9] = this.owner.selector;\n functionsList[10] = this.isOwner.selector;\n functionsList[11] = this.transferOwnership.selector;\n functionsList[12] = this.migrateToNewStakingContract.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingGovernanceModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/IVesting.sol\";\n\n/**\n * @title Staking Governance Module contract\n * @notice Implements voting power and delegation functionality\n * */\ncontract StakingGovernanceModule is IFunctionsList, StakingShared, CheckpointsShared {\n using Address for address payable;\n\n /************* TOTAL VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n /// @dev Start the computation with the exact or previous unlocking date (voting weight remians the same until the next break point).\n uint256 start = _timestampToLockDate(time);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n totalVotingPower = add96(\n totalVotingPower,\n _totalPowerByDate(i, start, blockNumber),\n \"arrays mismatch\"\n ); // WS06\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorTotalStakesForDate(date, blockNumber);\n /// @dev weight is multiplied by some factor to allow decimals.\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS07\n }\n\n /****************************** DELEGATED VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96) {\n return getPriorVotes(account, block.number - 1, block.timestamp);\n }\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96 votes) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n votes = add96(\n votes,\n _totalPowerByDateForDelegatee(account, i, start, blockNumber),\n \"overflow - total VP\"\n ); // WS09\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDateForDelegatee(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS10\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n date = _adjustDateForOrigin(date);\n return _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined yet\"); // WS11\n\n uint32 nCheckpoints = numDelegateStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (delegateStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return delegateStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (delegateStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = delegateStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return delegateStakingCheckpoints[account][date][lower].stake;\n }\n\n /**************** SHARED FUNCTIONS *********************/\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for. Adjusted to the next valid lock date, as necessary\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n public\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorTotalStakesForDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function _getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS08\n\n uint32 nCheckpoints = numTotalStakingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (totalStakingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return totalStakingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n // Next check implicit zero balance\n if (totalStakingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Checkpoint memory cp = totalStakingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return totalStakingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Set new delegatee. Move from user's current delegate to a new\n * delegatee the stake balance.\n * @param delegator The user address to move stake balance from its current delegatee.\n * @param delegatee The new delegatee. The address to move stake balance to.\n * @param lockedTS The lock date.\n * @dev Reverts if delegator balance or delegatee is not valid, unless the sender is a vesting contract.\n * */\n function _delegate(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n address currentDelegate = delegates[delegator][lockedTS];\n uint96 delegatorBalance = _currentBalance(delegator, lockedTS);\n\n // vesting contracts will in multiple cases try to delegate a zero balance\n // or to the existing delegatee\n if (_isVestingContract(msg.sender)) {\n if (delegatorBalance == 0 || currentDelegate == delegatee) {\n return;\n }\n } else {\n require(delegatorBalance > 0, \"no stake to delegate\");\n require(currentDelegate != delegatee, \"cannot delegate to the existing delegatee\");\n }\n\n delegates[delegator][lockedTS] = delegatee;\n\n emit DelegateChanged(delegator, lockedTS, currentDelegate, delegatee);\n\n _moveDelegates(currentDelegate, delegatee, delegatorBalance, lockedTS);\n }\n\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n function _delegateNext(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n if (_isVestingContract(msg.sender)) {\n uint256 nextLock = lockedTS.add(TWO_WEEKS);\n address currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n\n // @dev workaround for the issue with a delegation of the latest stake\n uint256 endDate = IVesting(msg.sender).endDate();\n nextLock = lockedTS.add(FOUR_WEEKS);\n if (nextLock == endDate) {\n currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n }\n }\n }\n\n /**\n * @notice Move an amount of delegate stake from a source address to a\n * destination address.\n * @param srcRep The address to get the staked amount from.\n * @param dstRep The address to send the staked amount to.\n * @param amount The staked amount to move.\n * @param lockedTS The lock date.\n * */\n function _moveDelegates(\n address srcRep,\n address dstRep,\n uint96 amount,\n uint256 lockedTS\n ) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) _decreaseDelegateStake(srcRep, lockedTS, amount);\n\n if (dstRep != address(0)) _increaseDelegateStake(dstRep, lockedTS, amount);\n }\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function _getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external whenNotPaused {\n require(delegatee != address(0), \"cannot delegate to the zero address\");\n _notSameBlockAsStakingCheckpoint(lockDate, msg.sender);\n\n _delegate(msg.sender, delegatee, lockDate);\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n _delegateNext(msg.sender, delegatee, lockDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](6);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStakeModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking contract staking functionality module\n * @notice Implements staking functionality\n **/\ncontract StakingStakeModule is IFunctionsList, StakingShared, CheckpointsShared, ApprovalReceiver {\n using SafeMath for uint256;\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stake(msg.sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external onlyThisContract whenNotPaused whenNotFrozen {\n _stake(sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * */\n function _stake(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted\n ) internal {\n _stakeOptionalTokenTransfer(\n sender,\n amount,\n until,\n stakeFor,\n delegatee,\n timeAdjusted,\n true // transfer SOV\n );\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * @param transferToken Should transfer SOV - false for multiple iterations like in stakeBySchedule\n * */\n function _stakeOptionalTokenTransfer(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted,\n bool transferToken\n ) internal {\n require(amount > 0, \"amount needs to be bigger than 0\"); // S01\n\n if (!timeAdjusted) {\n until = _timestampToLockDate(until);\n }\n require(\n until > block.timestamp,\n \"Staking::_timestampToLockDate: staking period too short\"\n ); // S02\n\n /// @dev Stake for the sender if not specified otherwise.\n if (stakeFor == address(0)) {\n stakeFor = sender;\n }\n // must wait a block before staking again for that same deadline\n _notSameBlockAsStakingCheckpoint(until, stakeFor);\n\n /// @dev Delegate for stakeFor if not specified otherwise.\n if (delegatee == address(0)) {\n delegatee = stakeFor;\n }\n\n /// @dev Do not stake longer than the max duration.\n if (!timeAdjusted) {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n }\n\n uint96 previousBalance = _currentBalance(stakeFor, until);\n\n /// @dev Increase stake.\n _increaseStake(sender, amount, stakeFor, until, transferToken);\n\n // @dev Previous version wasn't working properly for the following case:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n address previousDelegatee = delegates[stakeFor][until];\n\n if (previousDelegatee != delegatee) {\n // @dev only the user that stakes for himself is allowed to delegate VP to another address\n // which works with vesting stakes and prevents vulnerability of delegating VP to an arbitrary address from\n // any address\n\n if (delegatee != stakeFor) {\n require(\n stakeFor == sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n } else if (sender != stakeFor && previousDelegatee != address(0)) {\n require(stakeFor == sender, \"Only sender is allowed to change delegatee\");\n }\n\n /// @dev Update delegatee.\n delegates[stakeFor][until] = delegatee;\n\n /// @dev Decrease stake on previous balance for previous delegatee.\n _decreaseDelegateStake(previousDelegatee, until, previousBalance);\n\n /// @dev Add previousBalance to amount.\n amount = add96(previousBalance, amount, \"add amounts failed\");\n }\n\n /// @dev Increase stake.\n _increaseDelegateStake(delegatee, until, amount);\n emit DelegateChanged(stakeFor, until, previousDelegatee, delegatee);\n }\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until)\n external\n whenNotPaused\n whenNotFrozen\n {\n previousLock = _timestampToLockDate(previousLock);\n until = _timestampToLockDate(until);\n\n _notSameBlockAsStakingCheckpoint(previousLock, msg.sender);\n\n /// @dev Do not exceed the max duration, no overflow possible.\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n\n require(previousLock < until, \"must increase staking duration\"); // S04\n\n /// @dev Update checkpoints.\n /// @dev TODO James: Can reading stake at block.number -1 cause trouble with multiple tx in a block?\n uint96 amount = _getPriorUserStakeByDate(msg.sender, previousLock, block.number - 1);\n require(amount > 0, \"no stakes till the prev lock date\"); // S05\n _decreaseUserStake(msg.sender, previousLock, amount);\n _increaseUserStake(msg.sender, until, amount);\n\n if (_isVestingContract(msg.sender)) {\n _decreaseVestingStake(previousLock, amount);\n _increaseVestingStake(until, amount);\n }\n\n _decreaseDailyStake(previousLock, amount);\n _increaseDailyStake(until, amount);\n\n /// @dev Delegate might change: if there is already a delegate set for the until date, it will remain the delegate for this position\n address delegateFrom = delegates[msg.sender][previousLock];\n delegates[msg.sender][previousLock] = address(0); //the previousLock delegates nullifying before reading that form `until` guards in case delegateTo == until\n address delegateTo = delegates[msg.sender][until];\n if (delegateTo == address(0)) {\n delegateTo = delegateFrom;\n delegates[msg.sender][until] = delegateFrom;\n }\n _decreaseDelegateStake(delegateFrom, previousLock, amount);\n _increaseDelegateStake(delegateTo, until, amount);\n\n emit ExtendedStakingDuration(msg.sender, previousLock, until, amount);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param until The date until which the tokens will be staked.\n * @param transferToken if false - token transfer should be handled separately\n * */\n function _increaseStake(\n address sender,\n uint96 amount,\n address stakeFor,\n uint256 until,\n bool transferToken\n ) internal {\n /// @dev Retrieve the SOV tokens.\n if (transferToken)\n require(\n SOVToken.transferFrom(sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // IS10\n\n /// @dev Increase staked balance.\n uint96 balance = _currentBalance(stakeFor, until);\n balance = add96(balance, amount, \"increaseStake: overflow\"); // IS20\n\n /// @dev Update checkpoints.\n _increaseDailyStake(until, amount);\n _increaseUserStake(stakeFor, until, amount);\n\n if (_isVestingContract(stakeFor)) _increaseVestingStake(until, amount);\n\n emit TokensStaked(stakeFor, amount, until, balance);\n }\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function _stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) internal {\n require(amount > 0, \"Invalid amount\");\n require(duration <= MAX_DURATION, \"Invalid duration\");\n require(intervalLength > 0, \"Invalid interval length\");\n require(intervalLength % TWO_WEEKS == 0, \"Invalid interval length\");\n if (delegatee != stakeFor && delegatee != address(0)) {\n require(\n stakeFor == msg.sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n }\n /**\n * @dev Stake them until lock dates according to the vesting schedule.\n * Note: because staking is only possible in periods of 2 weeks,\n * the total duration might end up a bit shorter than specified\n * depending on the date of staking.\n * */\n uint256 start = _timestampToLockDate(block.timestamp + cliff);\n uint256 end = _timestampToLockDate(block.timestamp + duration);\n require(start <= end, \"Invalid schedule\");\n uint256 numIntervals;\n if (start < end) {\n numIntervals = (end - start) / intervalLength + 1;\n } else {\n numIntervals = 1;\n }\n uint256 stakedPerInterval = amount / numIntervals;\n\n /// @dev transferring total SOV amount before staking\n require(\n SOVToken.transferFrom(msg.sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // SS10\n /// @dev stakedPerInterval might lose some dust on rounding. Add it to the first staking date.\n if (numIntervals >= 1) {\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(amount - stakedPerInterval * (numIntervals - 1)),\n start,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n /// @dev Stake the rest in 4 week intervals.\n for (uint256 i = start + intervalLength; i <= end; i += intervalLength) {\n /// @dev Stakes for itself, delegates to the owner.\n _notSameBlockAsStakingCheckpoint(i, stakeFor); // must wait a block before staking again for that same deadline\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(stakedPerInterval),\n i,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n }\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance) {\n for (uint256 i = kickoffTS; i <= block.timestamp + MAX_DURATION; i += TWO_WEEKS) {\n balance = add96(balance, _currentBalance(account, i), \"Staking::balanceOf: overflow\"); // S12\n }\n }\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96) {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n return nCheckpoints > 0 ? totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake : 0;\n }\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes)\n {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n\n /// @dev Calculate stakes.\n uint256 count = 0;\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n if (_currentBalance(account, i) > 0) {\n count++;\n }\n }\n dates = new uint256[](count);\n stakes = new uint96[](count);\n\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n uint256 j = 0;\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n uint96 balance = _currentBalance(account, i);\n if (balance > 0) {\n dates[j] = i;\n stakes[j] = balance;\n j++;\n }\n }\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOVToken);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeWithApproval.selector;\n return selectors;\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256) {\n return _timestampToLockDate(timestamp);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](10);\n functionsList[0] = this.stake.selector;\n functionsList[1] = this.stakeWithApproval.selector;\n functionsList[2] = this.extendStakingDuration.selector;\n functionsList[3] = this.stakesBySchedule.selector;\n functionsList[4] = this.stakeBySchedule.selector;\n functionsList[5] = this.balanceOf.selector;\n functionsList[6] = this.getCurrentStakedUntil.selector;\n functionsList[7] = this.getStakes.selector;\n functionsList[8] = this.timestampToLockDate.selector;\n functionsList[9] = this.receiveApproval.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStorageModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/StakingStorageShared.sol\";\n\n/**\n * @title Staking Storage Module\n * @notice Provides getters for public storage variables\n **/\ncontract StakingStorageModule is IFunctionsList, StakingStorageShared {\n function getStorageDefaultWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256) {\n return MAX_DURATION;\n }\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n function getStorageMaxVotingWeight() external pure returns (uint256) {\n return uint256(MAX_VOTING_WEIGHT);\n }\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n function getStorageWeightFactor() external pure returns (uint256) {\n return uint256(WEIGHT_FACTOR);\n }\n\n /// @notice Default weight scaling.\n function getStorageDefaulWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling)\n {\n return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING));\n }\n\n /// @notice The EIP-712 typehash for the contract's domain.\n function getStorageDomainTypehash() external pure returns (uint256) {\n return uint256(DOMAIN_TYPEHASH);\n }\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n function getStorageDelegationTypehash() external pure returns (uint256) {\n return uint256(DELEGATION_TYPEHASH);\n }\n\n function getStorageName() external view returns (string memory) {\n return name;\n }\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() public view returns (uint256) {\n return maxVestingWithdrawIterations;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](32);\n functionsList[0] = this.getStorageMaxDurationToStakeTokens.selector;\n functionsList[1] = this.getStorageMaxVotingWeight.selector;\n functionsList[2] = this.getStorageWeightFactor.selector;\n functionsList[3] = this.getStorageDefaulWeightScaling.selector;\n functionsList[4] = this.getStorageRangeForWeightScaling.selector;\n functionsList[5] = this.getStorageDomainTypehash.selector;\n functionsList[6] = this.getStorageDelegationTypehash.selector;\n functionsList[7] = this.getStorageName.selector;\n functionsList[8] = this.kickoffTS.selector;\n functionsList[9] = this.SOVToken.selector;\n functionsList[10] = this.delegates.selector;\n functionsList[11] = this.allUnlocked.selector;\n functionsList[12] = this.newStakingContract.selector;\n functionsList[13] = this.totalStakingCheckpoints.selector;\n functionsList[14] = this.numTotalStakingCheckpoints.selector;\n functionsList[15] = this.delegateStakingCheckpoints.selector;\n functionsList[16] = this.numDelegateStakingCheckpoints.selector;\n functionsList[17] = this.userStakingCheckpoints.selector;\n functionsList[18] = this.numUserStakingCheckpoints.selector;\n functionsList[19] = this.nonces.selector;\n functionsList[20] = this.feeSharing.selector;\n functionsList[21] = this.weightScaling.selector;\n functionsList[22] = this.vestingWhitelist.selector;\n functionsList[23] = this.admins.selector;\n functionsList[24] = this.vestingCodeHashes.selector;\n functionsList[25] = this.vestingCheckpoints.selector;\n functionsList[26] = this.numVestingCheckpoints.selector;\n functionsList[27] = this.vestingRegistryLogic.selector;\n functionsList[28] = this.pausers.selector;\n functionsList[29] = this.paused.selector;\n functionsList[30] = this.frozen.selector;\n functionsList[31] = this.getMaxVestingWithdrawIterations.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingVestingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Vesting Module contract\n * @notice Implements interaction with Vesting functionality: vesting registry, vesting staking\n * */\ncontract StakingVestingModule is IFunctionsList, StakingShared {\n event ContractCodeHashAdded(bytes32 hash);\n event ContractCodeHashRemoved(bytes32 hash);\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external onlyOwner whenNotFrozen {\n vestingRegistryLogic = IVestingRegistry(_vestingRegistryProxy);\n }\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(lockedDates.length == values.length, \"arrays mismatch\"); // WS05\n\n uint256 length = lockedDates.length;\n for (uint256 i = 0; i < length; i++) {\n _setVestingStake(lockedDates[i], values[i]);\n }\n }\n\n /**\n * @notice Sets the users' vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to be set.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function _setVestingStake(uint256 lockedTS, uint96 value) internal {\n require(\n lockedTS > kickoffTS,\n \"Invalid lock dates: must greater than contract creation timestamp\"\n );\n\n // locked date must be multiples of 14 days / TWO_WEEKS\n require(\n (lockedTS - kickoffTS) % TWO_WEEKS == 0,\n \"Invalid lock dates: not multiples of 14 days\"\n );\n\n // locked date must not exceed the MAX_DURATION\n if (lockedTS > block.timestamp) {\n require(\n lockedTS - block.timestamp <= MAX_DURATION,\n \"Invalid lock dates: exceed max duration\"\n );\n }\n\n // the value must not exceed the total staked at the given locked date\n uint32 nStakeCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 totalStaked = totalStakingCheckpoints[lockedTS][nStakeCheckpoints - 1].stake;\n require(\n value <= totalStaked,\n \"Invalid stake amount: greater than the total staked for given date\"\n );\n\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint32 blockNumber;\n\n Checkpoint memory recentCP = vestingCheckpoints[lockedTS][nCheckpoints - 1];\n if (nCheckpoints == 0) blockNumber = uint32(block.number) - 1;\n else blockNumber = recentCP.fromBlock + 1;\n\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, value);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n\n emit VestingStakeSet(lockedTS, value);\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n uint96 priorStake = _getPriorUserStakeByDate(account, date, blockNumber);\n // @dev we need to modify function in order to workaround issue with Vesting.withdrawTokens:\n //\t\treturn 1 instead of 0 if message sender is a contract.\n if (priorStake == 0 && _isVestingContract(msg.sender)) {\n priorStake = 1;\n }\n return priorStake;\n }\n\n /*************************** Weighted Vesting Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes)\n {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedVestingStakeByDate(i, start, blockNumber);\n if (weightedStake > 0) {\n votes = add96(votes, weightedStake, \"overflow on total weight\"); // WS15\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n power = _weightedVestingStakeByDate(date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorVestingStakeByDate(date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul oveflow\") / WEIGHT_FACTOR; // WS16\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorVestingStakeByDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS17\n\n uint32 nCheckpoints = numVestingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (vestingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return vestingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (vestingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = vestingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return vestingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n require(vestingCodeHashes[codeHash], \"not a registered vesting code hash\");\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool) {\n bool isVesting;\n bytes32 codeHash = _getCodeHash(stakerAddress);\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](9);\n functionsList[0] = this.setVestingRegistry.selector;\n functionsList[1] = this.setVestingStakes.selector;\n functionsList[2] = this.getPriorUserStakeByDate.selector;\n functionsList[3] = this.getPriorVestingWeightedStake.selector;\n functionsList[4] = this.getPriorVestingStakeByDate.selector;\n functionsList[5] = this.addContractCodeHash.selector;\n functionsList[6] = this.removeContractCodeHash.selector;\n functionsList[7] = this.isVestingContract.selector;\n functionsList[8] = this.weightedVestingStakeByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingWithdrawModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/ITeamVesting.sol\";\nimport \"../../Vesting/IVesting.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking withdrawal functionality module\n **/\ncontract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShared {\n using SafeMath for uint256;\n\n event MaxVestingWithdrawIterationsUpdated(uint256 oldMaxIterations, uint256 newMaxIterations);\n\n /// @dev Struct for direct withdraw function -- to avoid stack too deep issue\n struct VestingConfig {\n address vestingAddress;\n uint256 startDate;\n uint256 endDate;\n uint256 cliff;\n uint256 duration;\n address tokenOwner;\n }\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev If until is not a valid lock date, the next lock date after until is used.\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n // adjust until here to avoid adjusting multiple times, and to make sure an adjusted date is passed to\n // _notSameBlockAsStakingCheckpoint\n until = _adjustDateForOrigin(until);\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, false);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe need to check block.timestamp here\n _withdrawNext(until, receiver, false);\n }\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external onlyAuthorized whenNotFrozen {\n /// require the caller only for team vesting contract.\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n _cancelTeamVesting(vesting, receiver, startFrom);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param _vesting The vesting address.\n * @param _receiver The receiving address.\n * @param _startFrom The start value for the iterations.\n * or just unlocked tokens (false).\n * */\n function _cancelTeamVesting(\n address _vesting,\n address _receiver,\n uint256 _startFrom\n ) private {\n require(_receiver != address(0), \"receiver address invalid\");\n\n ITeamVesting teamVesting = ITeamVesting(_vesting);\n\n VestingConfig memory vestingConfig =\n VestingConfig(\n _vesting,\n teamVesting.startDate(),\n teamVesting.endDate(),\n teamVesting.cliff(),\n teamVesting.duration(),\n teamVesting.tokenOwner()\n );\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them, as long as the itrations less than maxVestingWithdrawIterations.\n uint256 end = vestingConfig.endDate;\n\n uint256 defaultStart = vestingConfig.startDate + vestingConfig.cliff;\n\n _startFrom = _startFrom >= defaultStart ? _startFrom : defaultStart;\n\n /// @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 totalIterationValue =\n (_startFrom + (TWO_WEEKS * (maxVestingWithdrawIterations - 1)));\n uint256 adjustedEnd = end < totalIterationValue ? end : totalIterationValue;\n\n /// @dev Withdraw for each unlocked position.\n for (uint256 i = _startFrom; i <= adjustedEnd; i += TWO_WEEKS) {\n /// @dev Read amount to withdraw.\n uint96 tempStake = _getPriorUserStakeByDate(_vesting, i, block.number - 1);\n\n if (tempStake > 0) {\n /// @dev do governance direct withdraw for team vesting\n _withdrawFromTeamVesting(tempStake, i, _receiver, vestingConfig);\n }\n }\n\n if (adjustedEnd < end) {\n emit TeamVestingPartiallyCancelled(msg.sender, _receiver, adjustedEnd);\n } else {\n emit TeamVestingCancelled(msg.sender, _receiver);\n }\n }\n\n /**\n * @notice Send user' staked tokens to a receiver taking into account punishments.\n * Sovryn encourages long-term commitment and thinking. When/if you unstake before\n * the end of the staking period, a percentage of the original staking amount will\n * be slashed. This amount is also added to the reward pool and is distributed\n * between all other stakers.\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * Needs to be adjusted to the next valid lock date before calling this function.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdraw(\n uint96 amount,\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n // @dev it's very unlikely some one will have 1/10**18 SOV staked in Vesting contract\n //\t\tthis check is a part of workaround for Vesting.withdrawTokens issue\n if (amount == 1 && _isVestingContract(msg.sender)) {\n return;\n }\n _validateWithdrawParams(msg.sender, amount, until);\n\n /// @dev Determine the receiver.\n if (receiver == address(0)) receiver = msg.sender;\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(msg.sender, until, amount);\n if (_isVestingContract(msg.sender)) _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[msg.sender][until], until, amount);\n\n /// @dev Early unstaking should be punished.\n if (block.timestamp < until && !allUnlocked && !isGovernance) {\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n amount -= punishedAmount;\n\n /// @dev punishedAmount can be 0 if block.timestamp are very close to 'until'\n if (punishedAmount > 0) {\n require(address(feeSharing) != address(0), \"FeeSharing address wasn't set\"); // S08\n /// @dev Move punished amount to fee sharing.\n /// @dev Approve transfer here and let feeSharing do transfer and write checkpoint.\n SOVToken.approve(address(feeSharing), punishedAmount);\n feeSharing.transferTokens(address(SOVToken), punishedAmount);\n }\n }\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(msg.sender, amount, until, receiver, isGovernance);\n }\n\n /**\n * @notice Send user' staked tokens to a receiver.\n * This function is dedicated only for direct withdrawal from staking contract.\n * Currently only being used by cancelTeamVesting()\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender.\n * @param vestingConfig The vesting config.\n * @dev VestingConfig struct intended to avoid stack too deep issue, and it contains this properties:\n address vestingAddress; // vesting contract address\n uint256 startDate; //start date of vesting\n uint256 endDate; // end date of vesting\n uint256 cliff; // after this time period the tokens begin to unlock\n uint256 duration; // after this period all the tokens will be unlocked\n address tokenOwner; // owner of the vested tokens\n * */\n function _withdrawFromTeamVesting(\n uint96 amount,\n uint256 until,\n address receiver,\n VestingConfig memory vestingConfig\n ) internal {\n address vesting = vestingConfig.vestingAddress;\n\n until = _timestampToLockDate(until);\n _validateWithdrawParams(vesting, amount, until);\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(vesting, until, amount);\n\n _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[vesting][until], until, amount);\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(vesting, amount, until, receiver, true);\n }\n\n // @dev withdraws tokens for lock date 2 weeks later than given lock date\n function _withdrawNext(\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n if (_isVestingContract(msg.sender)) {\n // nextLock needs to be adjusted to the next valid lock date to make sure we don't accidentally\n // withdraw stakes that are in the future and would get slashed (if until is not\n // a valid lock date). but until is already handled in the withdraw function\n uint256 nextLock = until.add(TWO_WEEKS);\n if (isGovernance || block.timestamp >= nextLock) {\n uint96 stakes = _getPriorUserStakeByDate(msg.sender, nextLock, block.number - 1);\n if (stakes > 0) {\n _withdraw(stakes, nextLock, receiver, isGovernance);\n }\n }\n }\n }\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked. Adjusted to the next valid lock date, if necessary.\n * @return Amount to withraw and penalty amount\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96)\n {\n until = _adjustDateForOrigin(until);\n _validateWithdrawParams(msg.sender, amount, until);\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n return (amount - punishedAmount, punishedAmount);\n }\n\n /**\n * @notice Get punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _getPunishedAmount(uint96 amount, uint256 until) internal view returns (uint96) {\n uint256 date = _timestampToLockDate(block.timestamp);\n uint96 weight = _computeWeightByDate(until, date); /// @dev (10 - 1) * WEIGHT_FACTOR\n weight = weight * weightScaling;\n return (amount * weight) / WEIGHT_FACTOR / 100;\n }\n\n /**\n * @notice Validate withdraw parameters.\n * @param account Address to be validated.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _validateWithdrawParams(\n address account,\n uint96 amount,\n uint256 until\n ) internal view {\n require(amount > 0, \"Amount of tokens to withdraw must be > 0\"); // S10\n uint96 balance = _getPriorUserStakeByDate(account, until, block.number - 1);\n require(amount <= balance, \"Staking::withdraw: not enough balance\"); // S11\n }\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external onlyOwner whenNotFrozen {\n allUnlocked = true;\n emit TokensUnlocked(SOVToken.balanceOf(address(this)));\n }\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param newMaxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 newMaxIterations)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(newMaxIterations > 0, \"Invalid max iterations\");\n emit MaxVestingWithdrawIterationsUpdated(maxVestingWithdrawIterations, newMaxIterations);\n maxVestingWithdrawIterations = newMaxIterations;\n }\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * @dev This function is dedicated only to support backward compatibility for sovryn ecosystem that has been implementing this staking contract.\n * @dev Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/4bbfe5bd0311ca71e4ef0e3af810d3791d8e4061/contracts/governance/Staking/modules/StakingWithdrawModule.sol#L78\n * */\n function governanceWithdrawVesting(address vesting, address receiver)\n public\n onlyAuthorized\n whenNotFrozen\n {\n vestingWhitelist[vesting] = true;\n ITeamVesting(vesting).governanceWithdrawTokens(receiver);\n vestingWhitelist[vesting] = false;\n\n emit VestingTokensWithdrawn(vesting, receiver);\n }\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n require(vestingWhitelist[msg.sender], \"unauthorized\"); // S07\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, true);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe don't need to check block.timestamp here\n _withdrawNext(until, receiver, true);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.withdraw.selector;\n functionsList[1] = this.cancelTeamVesting.selector;\n functionsList[2] = this.getWithdrawAmounts.selector;\n functionsList[3] = this.unlockAllTokens.selector;\n functionsList[4] = this.setMaxVestingWithdrawIterations.selector;\n functionsList[5] = this.governanceWithdraw.selector;\n functionsList[6] = this.governanceWithdrawVesting.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/WeightedStakingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Weighted Staking module contract.\n * @notice Implements getters for weighted staking functionality\n * */\ncontract WeightedStakingModule is IFunctionsList, StakingShared, CheckpointsShared {\n /*************************** User Weighted Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The start date/timestamp from which to calculate the weighted stake.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake) {\n return _getPriorWeightedStake(account, blockNumber, date);\n }\n\n function _getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) internal view returns (uint96 priorWeightedStake) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedStakeByDate(account, i, start, blockNumber);\n if (weightedStake > 0) {\n priorWeightedStake = add96(\n priorWeightedStake,\n weightedStake,\n \"overflow on total weight calc\"\n ); // WS12\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n return _weightedStakeByDate(account, date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function _weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorUserStakeByDate(account, date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS13\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight)\n {\n return _computeWeightByDate(date, startDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](3);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/SafeMath96.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n/**\n * @title SafeMath96 contract.\n * @notice Improved Solidity's arithmetic operations with added overflow checks.\n * @dev SafeMath96 uses uint96, unsigned integers of 96 bits length, so every\n * integer from 0 to 2^96-1 can be operated.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * SafeMath restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this contract instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n * */\ncontract SafeMath96 {\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function safe64(uint256 n, string memory errorMessage) internal pure returns (uint64) {\n require(n < 2**64, errorMessage);\n return uint64(n);\n }\n\n function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) {\n require(n < 2**96, errorMessage);\n return uint96(n);\n }\n\n /**\n * @notice Adds two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `+` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe addition a+b.\n * */\n function add96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n uint96 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n /**\n * @notice Substracts two unsigned integers, reverting on underflow.\n * @dev Counterpart to Solidity's `-` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on underflow.\n * @return The safe substraction a-b.\n * */\n function sub96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n require(b <= a, errorMessage);\n return a - b;\n }\n\n /**\n * @notice Multiplies two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `*` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe product a*b.\n * */\n function mul96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n if (a == 0) {\n return 0;\n }\n\n uint96 c = a * b;\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @notice Divides two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `/` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe division a/b.\n * */\n function div96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint96 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n}\n" + }, + "contracts/governance/Staking/StakingProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./modules/shared/StakingStorageShared.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Staking Proxy contract.\n * @dev Staking contract should be upgradable, use UpgradableProxy.\n * StakingStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingProxy is StakingStorageShared, UpgradableProxy {\n /**\n * @notice Construct a new staking contract.\n * @param SOV The address of the SOV token address.\n */\n constructor(address SOV) public {\n SOVToken = IERC20(SOV);\n kickoffTS = block.timestamp;\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewards.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Staking Rewards Contract.\n * @notice This is a trial incentive program.\n * In this, the SOV emitted and becoming liquid from the Adoption Fund could be utilized\n * to offset the higher APY's offered for Liquidity Mining events.\n * Vesting contract stakes are excluded from these rewards.\n * Only wallets which have staked previously liquid SOV are eligible for these rewards.\n * Tokenholders who stake their SOV receive staking rewards, a pro-rata share\n * of the revenue that the platform generates from various transaction fees\n * plus revenues from stakers who have a portion of their SOV slashed for\n * early unstaking.\n * */\ncontract StakingRewards is StakingRewardsStorage {\n using SafeMath for uint256;\n\n /// @notice Emitted when SOV is withdrawn\n /// @param receiver The address which recieves the SOV\n /// @param amount The amount withdrawn from the Smart Contract\n event RewardWithdrawn(address indexed receiver, uint256 amount);\n\n /**\n * @notice Replacement of constructor by initialize function for Upgradable Contracts\n * This function will be called only once by the owner.\n * @param _SOV SOV token address\n * @param _staking StakingProxy address should be passed\n * */\n function initialize(address _SOV, IStaking _staking) external onlyOwner {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n SOV = IERC20(_SOV);\n staking = _staking;\n startTime = staking.timestampToLockDate(block.timestamp);\n setMaxDuration(15 * TWO_WEEKS);\n deploymentBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Stops the current rewards program.\n * @dev All stakes existing on the contract at the point in time of\n * cancellation continue accruing rewards until the end of the staking\n * period being rewarded\n * */\n function stop() external onlyOwner {\n require(stopBlock == 0, \"Already stopped\");\n stopBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Collect rewards\n * @dev User calls this function to collect SOV staking rewards as per the SIP-0024 program.\n * The weighted stake is calculated using getPriorWeightedStake. Block number sent to the functon\n * must be a finalised block, hence we deduct 1 from the current block. User is only allowed to withdraw\n * after intervals of 14 days.\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * The issue is that we can only run for a max duration and if someone stakes for the\n * first time after the max duration is over, the reward will always return 0. Thus, we need to restart\n * from the duration that elapsed without generating rewards.\n * */\n function collectReward(uint256 restartTime) external {\n (uint256 withdrawalTime, uint256 amount) = getStakerCurrentReward(true, restartTime);\n require(withdrawalTime > 0 && amount > 0, \"no valid reward\");\n withdrawals[msg.sender] = withdrawalTime;\n _payReward(msg.sender, amount);\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred.\n */\n function withdrawTokensByOwner(address _receiverAddress) external onlyOwner {\n uint256 value = SOV.balanceOf(address(this));\n _transferSOV(_receiverAddress, value);\n }\n\n /**\n * @notice Changes average block time - based on blockchain\n * @dev If average block time significantly changes, we can update it here and use for block number calculation\n */\n function setAverageBlockTime(uint256 _averageBlockTime) external onlyOwner {\n averageBlockTime = _averageBlockTime;\n }\n\n /**\n * @notice This function computes the last staking checkpoint and calculates the corresponding\n * block number using the average block time which is then added to the mapping `checkpointBlockDetails`.\n */\n function setBlock() external {\n uint256 lastCheckpointTime = staking.timestampToLockDate(block.timestamp);\n _setBlock(lastCheckpointTime);\n }\n\n /**\n * @notice This function computes the block number using the average block time for a given historical\n * checkpoint which is added to the mapping `checkpointBlockDetails`.\n * @param _time Exact staking checkpoint time\n */\n function setHistoricalBlock(uint256 _time) external {\n _setBlock(_time);\n }\n\n /**\n * @notice Sets the max duration\n * @dev Rewards can be collected for a maximum duration at a time. This\n * is to avoid Block Gas Limit failures. Setting it zero would mean that it will loop\n * through the entire duration since the start of rewards program.\n * It should ideally be set to a value, for which the rewards can be easily processed.\n * @param _duration Max duration for which rewards can be collected at a go (in seconds)\n * */\n function setMaxDuration(uint256 _duration) public onlyOwner {\n maxDuration = _duration;\n }\n\n /**\n * @notice Internal function to calculate weighted stake\n * @dev If the rewards program is stopped, the user will still continue to\n * earn till the end of staking period based on the stop block.\n * @param _staker Staker address\n * @param _block Last finalised block\n * @param _date The date to compute prior weighted stakes\n * @return The weighted stake\n * */\n function _computeRewardForDate(\n address _staker,\n uint256 _block,\n uint256 _date\n ) internal view returns (uint256 weightedStake) {\n weightedStake = staking.getPriorWeightedStake(_staker, _block, _date);\n if (stopBlock > 0 && stopBlock < _block) {\n uint256 previousWeightedStake =\n staking.getPriorWeightedStake(_staker, stopBlock, _date);\n if (previousWeightedStake < weightedStake) {\n weightedStake = previousWeightedStake;\n }\n }\n }\n\n /**\n * @notice Internal function to pay rewards\n * @dev Base rate is annual, but we pay interest for 14 days,\n * which is 1/26 of one staking year (1092 days)\n * @param _staker User address\n * @param amount the reward amount\n * */\n function _payReward(address _staker, uint256 amount) internal {\n require(SOV.balanceOf(address(this)) >= amount, \"not enough funds to reward user\");\n claimedBalances[_staker] = claimedBalances[_staker].add(amount);\n _transferSOV(_staker, amount);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit RewardWithdrawn(_receiver, _amount);\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Internal function to calculate and set block\n * */\n function _setBlock(uint256 _checkpointTime) internal {\n uint256 currentTS = block.timestamp;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n require(checkpointBlockDetails[_checkpointTime] == 0, \"block number already set\");\n uint256 checkpointBlock =\n lastFinalisedBlock.sub(((currentTS.sub(_checkpointTime)).div(averageBlockTime)));\n checkpointBlockDetails[_checkpointTime] = checkpointBlock;\n }\n\n /**\n * @notice Get staker's current accumulated reward\n * @dev The collectReward() function internally calls this function to calculate reward amount\n * @param considerMaxDuration True: Runs for the maximum duration - used in tx not to run out of gas\n * False - to query total rewards\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * @return The timestamp of last withdrawal\n * @return The accumulated reward\n */\n function getStakerCurrentReward(bool considerMaxDuration, uint256 restartTime)\n public\n view\n returns (uint256 lastWithdrawalInterval, uint256 amount)\n {\n uint256 weightedStake;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n uint256 currentTS = block.timestamp;\n uint256 duration;\n address staker = msg.sender;\n uint256 lastWithdrawal = withdrawals[staker];\n\n uint256 lastStakingInterval = staking.timestampToLockDate(currentTS);\n lastWithdrawalInterval = lastWithdrawal > 0 ? lastWithdrawal : startTime;\n if (lastStakingInterval <= lastWithdrawalInterval) return (0, 0);\n /* Normally the restart time is 0. If this function returns a valid lastWithdrawalInterval\n\t\tand zero amount - that means there were no valid rewards for that period. So the new period must start\n\t\tfrom the end of the last interval or till the time no rewards are accumulated i.e. restartTime */\n if (restartTime >= lastWithdrawalInterval) {\n uint256 latestRestartTime = staking.timestampToLockDate(restartTime);\n lastWithdrawalInterval = latestRestartTime;\n }\n\n if (considerMaxDuration) {\n uint256 addedMaxDuration = lastWithdrawalInterval.add(maxDuration);\n duration = addedMaxDuration < currentTS\n ? staking.timestampToLockDate(addedMaxDuration)\n : lastStakingInterval;\n } else {\n duration = lastStakingInterval;\n }\n for (uint256 i = lastWithdrawalInterval; i < duration; i += TWO_WEEKS) {\n uint256 referenceBlock = checkpointBlockDetails[i];\n if (referenceBlock == 0) {\n referenceBlock = lastFinalisedBlock.sub(\n ((currentTS.sub(i)).div(averageBlockTime))\n );\n }\n if (referenceBlock < deploymentBlock) referenceBlock = deploymentBlock;\n weightedStake = weightedStake.add(_computeRewardForDate(staker, referenceBlock, i));\n }\n lastWithdrawalInterval = duration;\n amount = weightedStake.mul(BASE_RATE).div(DIVISOR);\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title StakingRewards Proxy contract.\n * @dev StakingRewards contract should be upgradable. Used UpgradableProxy.\n * StakingRewardsStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy with\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingRewardsProxy is StakingRewardsStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking Rewards Storage Contract.\n * @notice Just the storage part of staking rewards contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingRewardsProxy.\n *\n * What is SOV staking rewards - SIP-0024?\n * The purpose of the SOV staking rewards - SIP-0024 is to reward,\n * \"marginal stakers\" (ie, stakers by choice, not currently vesting) with liquid SOV\n * at the beginning of each new staking interval.\n * */\ncontract StakingRewardsStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n ///@notice the staking proxy contract address\n IStaking public staking;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 1209600;\n\n /// @notice Annual Base Rate - it is the maximum interest rate(APY)\n uint256 public constant BASE_RATE = 2975;\n\n /// @notice DIVISOR is set as 2600000 = 26 (num periods per year) * 10 (max voting weight) * 10000 (2975 -> 0.2975)\n uint256 public constant DIVISOR = 2600000;\n\n /// @notice Maximum duration to collect rewards at one go\n uint256 public maxDuration;\n\n /// @notice Represents the time when the contract is deployed\n uint256 public startTime;\n\n /// @notice Represents the block when the Staking Rewards pogram is stopped\n uint256 public stopBlock;\n\n /// @notice User Address -> Last Withdrawn Timestamp\n mapping(address => uint256) public withdrawals;\n\n /// @notice User Address -> Claimed Balance\n mapping(address => uint256) public claimedBalances;\n\n /// @notice Represents the block when the StakingRwards Program is started\n uint256 public deploymentBlock;\n\n /// Moved the variables from Initializable contract to resolve issue caused by incorrect Inheritance Order\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /// @notice BlockTime -> BlockNumber for a Staking Checkpoint\n mapping(uint256 => uint256) public checkpointBlockDetails;\n\n /// @notice Average Block Time - making it flexible\n uint256 public averageBlockTime;\n}\n" + }, + "contracts/governance/Timelock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./ErrorDecoder.sol\";\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\n/**\n * @title Sovryn Protocol Timelock contract, based on Compound system.\n *\n * @notice This contract lets Sovryn governance system set up its\n * own Time Lock instance to execute transactions proposed through the\n * GovernorAlpha contract instance.\n *\n * The Timelock contract allows its admin (Sovryn governance on\n * GovernorAlpha contract) to add arbitrary function calls to a\n * queue. This contract can only execute a function call if the\n * function call has been in the queue for at least 3 hours.\n *\n * Anytime the Timelock contract makes a function call, it must be the\n * case that the function call was first made public by having been publicly\n * added to the queue at least 3 hours prior.\n *\n * The intention is to provide GovernorAlpha contract the functionality to\n * queue proposal actions. This would mean that any changes made by Sovryn\n * governance of any contract would necessarily come with at least an\n * advanced warning. This makes the Sovryn system follow a “time-delayed,\n * opt-out” upgrade pattern (rather than an “instant, forced” upgrade pattern).\n *\n * Time-delaying admin actions gives users a chance to exit system if its\n * admins become malicious or compromised (or make a change that the users\n * do not like). Downside is that honest admins would be unable\n * to lock down functionality to protect users if a critical bug was found.\n *\n * Delayed transactions reduce the amount of trust required by users of Sovryn\n * and the overall risk for contracts building on top of it, as GovernorAlpha.\n * */\ncontract Timelock is ErrorDecoder, ITimelock {\n using SafeMath for uint256;\n\n uint256 public constant GRACE_PERIOD = 14 days;\n uint256 public constant MINIMUM_DELAY = 3 hours;\n uint256 public constant MAXIMUM_DELAY = 30 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /**\n * @notice Function called on instance deployment of the contract.\n * @param admin_ Governance contract address.\n * @param delay_ Time to wait for queued transactions to be executed.\n * */\n constructor(address admin_, uint256 delay_) public {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {}\n\n /**\n * @notice Set a new delay when executing the contract calls.\n * @param delay_ The amount of time to wait until execution.\n * */\n function setDelay(uint256 delay_) public {\n require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n require(delay_ >= MINIMUM_DELAY, \"Timelock::setDelay: Delay must exceed minimum delay.\");\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n /**\n * @notice Accept a new admin for the timelock.\n * */\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n /**\n * @notice Set a new pending admin for the timelock.\n * @param pendingAdmin_ The new pending admin address.\n * */\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n /**\n * @notice Queue a new transaction from the governance contract.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function queueTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public returns (bytes32) {\n require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n /**\n * @notice Cancel a transaction.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function cancelTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public {\n require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n /**\n * @notice Executes a previously queued transaction from the governance.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function executeTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public payable returns (bytes memory) {\n require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call.value(value)(callData);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"Timelock::executeTransaction: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"Timelock::executeTransaction: \", string(returnData)));\n }\n }\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n /**\n * @notice A function used to get the current Block Timestamp.\n * @dev Timestamp of the current block in seconds since the epoch.\n * It is a Unix time stamp. So, it has the complete information about\n * the date, hours, minutes, and seconds (in UTC) when the block was\n * created.\n * */\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" + }, + "contracts/governance/Vesting/DevelopmentFund.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Development Fund.\n * @author Franklin Richards\n * @notice You can use this contract for timed token release from Dev Fund.\n */\ncontract DevelopmentFund {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The current contract status.\n enum Status { Deployed, Active, Expired }\n Status public status;\n\n /// @notice The owner of the locked tokens (usually Governance).\n address public lockedTokenOwner;\n /// @notice The owner of the unlocked tokens (usually MultiSig).\n address public unlockedTokenOwner;\n /// @notice The emergency transfer wallet/contract.\n address public safeVault;\n /// @notice The new locked token owner waiting to be approved.\n address public newLockedTokenOwner;\n\n /// @notice The last token release timestamp or the time of contract creation.\n uint256 public lastReleaseTime;\n\n /// @notice The release duration array in seconds.\n uint256[] public releaseDuration;\n /// @notice The release token amount.\n uint256[] public releaseTokenAmount;\n\n /* Events */\n\n /// @notice Emitted when the contract is activated.\n event DevelopmentFundActivated();\n\n /// @notice Emitted when the contract is expired due to total token transfer.\n event DevelopmentFundExpired();\n\n /// @notice Emitted when a new locked owner is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current locked owner.\n event NewLockedOwnerAdded(address indexed _initiator, address indexed _newLockedOwner);\n\n /// @notice Emitted when a new locked owner is approved to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _oldLockedOwner The address of the previous locked owner.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current unlocked owner.\n event NewLockedOwnerApproved(\n address indexed _initiator,\n address indexed _oldLockedOwner,\n address indexed _newLockedOwner\n );\n\n /// @notice Emitted when a new unlocked owner is updated in the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newUnlockedOwner The address which is updated as the new unlocked owner.\n /// @dev Can only be initiated by the current locked owner.\n event UnlockedOwnerUpdated(address indexed _initiator, address indexed _newUnlockedOwner);\n\n /// @notice Emitted when a new token deposit is done.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new release schedule is created.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseCount The number of releases planned in the schedule.\n event TokenReleaseChanged(address indexed _initiator, uint256 _releaseCount);\n\n /// @notice Emitted when a unlocked owner transfers all the tokens to a safe vault.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token withdrawn.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done in an emergency situation only to a predetermined wallet by locked token owner.\n event LockedTokenTransferByUnlockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /// @notice Emitted when a unlocked owner withdraws the released tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token withdrawn.\n /// @param _releaseCount The total number of releases done based on duration.\n event UnlockedTokenWithdrawalByUnlockedOwner(\n address indexed _initiator,\n uint256 _amount,\n uint256 _releaseCount\n );\n\n /// @notice Emitted when a locked owner transfers all the tokens to a receiver.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token transfer.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done only by locked token owner.\n event LockedTokenTransferByLockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /* Modifiers */\n\n modifier onlyLockedTokenOwner() {\n require(msg.sender == lockedTokenOwner, \"Only Locked Token Owner can call this.\");\n _;\n }\n\n modifier onlyUnlockedTokenOwner() {\n require(msg.sender == unlockedTokenOwner, \"Only Unlocked Token Owner can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _lockedTokenOwner The owner of the locked tokens & contract.\n * @param _safeVault The emergency wallet/contract to transfer token.\n * @param _unlockedTokenOwner The owner of the unlocked tokens.\n * @param _lastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev Initial release schedule should be verified, error will result in either redeployment or calling changeTokenReleaseSchedule() after init() along with token transfer.\n */\n constructor(\n address _SOV,\n address _lockedTokenOwner,\n address _safeVault,\n address _unlockedTokenOwner,\n uint256 _lastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_lockedTokenOwner != address(0), \"Locked token & contract owner address invalid.\");\n require(_safeVault != address(0), \"Safe Vault address invalid.\");\n require(_unlockedTokenOwner != address(0), \"Unlocked token address invalid.\");\n\n SOV = IERC20(_SOV);\n lockedTokenOwner = _lockedTokenOwner;\n safeVault = _safeVault;\n unlockedTokenOwner = _unlockedTokenOwner;\n\n lastReleaseTime = _lastReleaseTime;\n /// If last release time passed is zero, then current time stamp will be used as the last release time.\n if (_lastReleaseTime == 0) {\n lastReleaseTime = block.timestamp;\n }\n\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n }\n\n /**\n * @notice This function is called once after deployment for token transfer based on schedule.\n * @dev Without calling this function, the contract will not work.\n */\n function init() public checkStatus(Status.Deployed) {\n uint256[] memory _releaseTokenAmount = releaseTokenAmount;\n require(_releaseTokenAmount.length != 0, \"Release Schedule not set.\");\n\n /// Getting the current release schedule total token amount.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _releaseTotalTokenAmount);\n require(txStatus, \"Not enough token sent to change release schedule.\");\n\n status = Status.Active;\n\n emit DevelopmentFundActivated();\n }\n\n /**\n * @notice Update Locked Token Owner.\n * @param _newLockedTokenOwner The owner of the locked tokens & contract.\n */\n function updateLockedTokenOwner(address _newLockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newLockedTokenOwner != address(0), \"New locked token owner address invalid.\");\n\n newLockedTokenOwner = _newLockedTokenOwner;\n\n emit NewLockedOwnerAdded(msg.sender, _newLockedTokenOwner);\n }\n\n /**\n * @notice Approve Locked Token Owner.\n * @dev This approval is an added security to avoid development fund takeover by a compromised locked token owner.\n */\n function approveLockedTokenOwner() public onlyUnlockedTokenOwner checkStatus(Status.Active) {\n require(newLockedTokenOwner != address(0), \"No new locked owner added.\");\n\n emit NewLockedOwnerApproved(msg.sender, lockedTokenOwner, newLockedTokenOwner);\n\n lockedTokenOwner = newLockedTokenOwner;\n\n newLockedTokenOwner = address(0);\n }\n\n /**\n * @notice Update Unlocked Token Owner.\n * @param _newUnlockedTokenOwner The new unlocked token owner.\n */\n function updateUnlockedTokenOwner(address _newUnlockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newUnlockedTokenOwner != address(0), \"New unlocked token owner address invalid.\");\n\n unlockedTokenOwner = _newUnlockedTokenOwner;\n\n emit UnlockedOwnerUpdated(msg.sender, _newUnlockedTokenOwner);\n }\n\n /**\n * @notice Deposit tokens to this contract.\n * @param _amount the amount of tokens deposited.\n * @dev These tokens can be withdrawn/transferred any time by the lockedTokenOwner.\n */\n function depositTokens(uint256 _amount) public checkStatus(Status.Active) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDeposit(msg.sender, _amount);\n }\n\n /**\n * @notice Change the Token release schedule. It creates a completely new schedule, and does not append on the previous one.\n * @param _newLastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev _releaseDuration and _releaseTokenAmount should be specified in reverse order of release.\n */\n function changeTokenReleaseSchedule(\n uint256 _newLastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public onlyLockedTokenOwner checkStatus(Status.Active) {\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// If the last release time has to be changed, then you can pass a new one here.\n /// Or else, the duration of release will be calculated based on this timestamp.\n /// Even a future timestamp can be mentioned here.\n if (_newLastReleaseTime != 0) {\n lastReleaseTime = _newLastReleaseTime;\n }\n\n /// Checking if the contract have enough token balance for the release.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n /// Getting the current token balance of the contract.\n uint256 remainingTokens = SOV.balanceOf(address(this));\n\n /// If the token balance is not sufficient, then we transfer the change to contract.\n if (remainingTokens < _releaseTotalTokenAmount) {\n bool txStatus =\n SOV.transferFrom(\n msg.sender,\n address(this),\n _releaseTotalTokenAmount.sub(remainingTokens)\n );\n require(txStatus, \"Not enough token sent to change release schedule.\");\n } else if (remainingTokens > _releaseTotalTokenAmount) {\n /// If there are more tokens than required, send the extra tokens back.\n bool txStatus =\n SOV.transfer(msg.sender, remainingTokens.sub(_releaseTotalTokenAmount));\n require(txStatus, \"Token not received by the Locked Owner.\");\n }\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n\n emit TokenReleaseChanged(msg.sender, _releaseDuration.length);\n }\n\n /**\n * @notice Transfers all of the remaining tokens in an emergency situation.\n * @dev This could be called when governance or development fund might be compromised.\n */\n function transferTokensByUnlockedTokenOwner()\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(safeVault, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByUnlockedOwner(msg.sender, safeVault, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /**\n * @notice Withdraws all unlocked/released token.\n * @param _amount The amount to be withdrawn.\n */\n function withdrawTokensByUnlockedTokenOwner(uint256 _amount)\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_amount > 0, \"Zero can't be withdrawn.\");\n\n uint256 count; /// To know how many elements to be removed from the release schedule.\n uint256 amount = _amount; /// To know the total amount to be transferred.\n uint256 newLastReleaseTimeMemory = lastReleaseTime; /// Better to use memory than storage.\n uint256 releaseLength = releaseDuration.length.sub(1); /// Also checks if there are any elements in the release schedule.\n\n /// Getting the amount of tokens, the number of releases and calculating the total duration.\n while (\n amount > 0 &&\n newLastReleaseTimeMemory.add(releaseDuration[releaseLength]) < block.timestamp\n ) {\n if (amount >= releaseTokenAmount[releaseLength]) {\n amount = amount.sub(releaseTokenAmount[releaseLength]);\n newLastReleaseTimeMemory = newLastReleaseTimeMemory.add(\n releaseDuration[releaseLength]\n );\n count++;\n } else {\n /// This will be the last case, if correct amount is passed.\n releaseTokenAmount[releaseLength] = releaseTokenAmount[releaseLength].sub(amount);\n amount = 0;\n }\n releaseLength--;\n }\n\n /// Checking to see if atleast a single schedule was reached or not.\n require(count > 0 || amount == 0, \"No release schedule reached.\");\n\n /// If locked token owner tries to send a higher amount that schedule\n uint256 value = _amount.sub(amount);\n\n /// Now clearing up the release schedule.\n releaseDuration.length -= count;\n releaseTokenAmount.length -= count;\n\n /// Updating the last release time.\n lastReleaseTime = newLastReleaseTimeMemory;\n\n /// Sending the amount to unlocked token owner.\n bool txStatus = SOV.transfer(msg.sender, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit UnlockedTokenWithdrawalByUnlockedOwner(msg.sender, value, count);\n }\n\n /**\n * @notice Transfers all of the remaining tokens by the owner maybe for an upgrade.\n * @dev This could be called when the current development fund has to be upgraded.\n * @param _receiver The address which receives this token transfer.\n */\n function transferTokensByLockedTokenOwner(address _receiver)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(_receiver, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByLockedOwner(msg.sender, _receiver, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token release duration.\n * @return _currentReleaseDuration The current release duration.\n */\n function getReleaseDuration() public view returns (uint256[] memory _releaseTokenDuration) {\n return releaseDuration;\n }\n\n /**\n * @notice Function to read the current token release amount.\n * @return _currentReleaseTokenAmount The current release token amount.\n */\n function getReleaseTokenAmount()\n public\n view\n returns (uint256[] memory _currentReleaseTokenAmount)\n {\n return releaseTokenAmount;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../IFeeSharingCollector.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../proxy/UpgradableProxy.sol\";\nimport \"../../../openzeppelin/Address.sol\";\n\n/**\n * @title Four Year Vesting Contract.\n *\n * @notice A four year vesting contract.\n *\n * @dev Vesting contract is upgradable,\n * Make sure the vesting owner is multisig otherwise it will be\n * catastrophic.\n * */\ncontract FourYearVesting is FourYearVestingStorage, UpgradableProxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharingCollector Fee sharing proxy address.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n address _feeSharingCollector,\n uint256 _extendDurationFor\n ) public {\n require(Address.isContract(_logic), \"_logic not a contract\");\n require(_SOV != address(0), \"SOV address invalid\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(Address.isContract(_stakingAddress), \"_stakingAddress not a contract\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(Address.isContract(_feeSharingCollector), \"_feeSharingCollector not a contract\");\n require((_extendDurationFor % FOUR_WEEKS) == 0, \"invalid duration\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n tokenOwner = _tokenOwner;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n maxInterval = 18 * FOUR_WEEKS;\n extendDurationFor = _extendDurationFor;\n }\n\n /**\n * @notice Set address of the implementation - vesting owner.\n * @dev Overriding setImplementation function of UpgradableProxy. The logic can only be\n * modified when both token owner and veting owner approve. Since\n * setImplementation can only be called by vesting owner, we also need to check\n * if the new logic is already approved by the token owner.\n * @param _implementation Address of the implementation. Must match with what is set by token owner.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n require(Address.isContract(_implementation), \"_implementation not a contract\");\n require(newImplementation == _implementation, \"address mismatch\");\n _setImplementation(_implementation);\n newImplementation = address(0);\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"./FourYearVesting.sol\";\nimport \"./IFourYearVestingFactory.sol\";\n\n/**\n * @title Four Year Vesting Factory: Contract to deploy four year vesting contracts.\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract FourYearVestingFactory is IFourYearVestingFactory, Ownable {\n /// @dev Added an event to keep track of the vesting contract created for a token owner\n event FourYearVestingCreated(address indexed tokenOwner, address indexed vestingAddress);\n\n /**\n * @notice Deploys four year vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwnerMultisig The address of an owner of vesting contract.\n * @dev _vestingOwnerMultisig should ALWAYS be multisig.\n * @param _fourYearVestingLogic The implementation contract.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * @return The four year vesting contract address.\n * */\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external onlyOwner returns (address) {\n address fourYearVesting =\n address(\n new FourYearVesting(\n _fourYearVestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _feeSharing,\n _extendDurationFor\n )\n );\n Ownable(fourYearVesting).transferOwnership(_vestingOwnerMultisig);\n emit FourYearVestingCreated(_tokenOwner, fourYearVesting);\n return fourYearVesting;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./IFourYearVesting.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Four Year Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by FourYearVestingFactory contract.\n * */\ncontract FourYearVestingLogic is IFourYearVesting, FourYearVestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n\n /* Events */\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n event TokenOwnerChanged(address indexed newOwner, address indexed oldOwner);\n\n /* Modifiers */\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Sets the max interval.\n * @param _interval Max interval for which tokens scheduled shall be staked.\n * */\n function setMaxInterval(uint256 _interval) external onlyOwner {\n require(_interval.mod(FOUR_WEEKS) == 0, \"invalid interval\");\n maxInterval = _interval;\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount)\n {\n (lastSchedule, remainingAmount) = _stakeTokens(msg.sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokensWithApproval(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) external onlyThisContract returns (uint256 lastSchedule, uint256 remainingAmount) {\n (lastSchedule, remainingAmount) = _stakeTokens(_sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) external onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n uint256 stakingEndDate = endDate;\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate.add(cliff); i <= stakingEndDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) external onlyTokenOwner {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external onlyTokenOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Change token owner - only vesting owner is allowed to change.\n * @dev Modifies token owner. This must be followed by approval\n * from token owner.\n * @param _newTokenOwner Address of new token owner.\n * */\n function changeTokenOwner(address _newTokenOwner) public onlyOwner {\n require(_newTokenOwner != address(0), \"invalid new token owner address\");\n require(_newTokenOwner != tokenOwner, \"same owner not allowed\");\n newTokenOwner = _newTokenOwner;\n }\n\n /**\n * @notice Approve token owner change - only token Owner.\n * @dev Token owner can only be modified\n * when both vesting owner and token owner have approved. This\n * function ascertains the approval of token owner.\n * */\n function approveOwnershipTransfer() public onlyTokenOwner {\n require(newTokenOwner != address(0), \"invalid address\");\n tokenOwner = newTokenOwner;\n newTokenOwner = address(0);\n emit TokenOwnerChanged(tokenOwner, msg.sender);\n }\n\n /**\n * @notice Set address of the implementation - only Token Owner.\n * @dev This function sets the new implementation address.\n * It must also be approved by the Vesting owner.\n * @param _newImplementation Address of the new implementation.\n * */\n function setImpl(address _newImplementation) public onlyTokenOwner {\n require(_newImplementation != address(0), \"invalid new implementation address\");\n newImplementation = _newImplementation;\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() external onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Extends stakes(unlocked till timeDuration) for four year vesting contracts.\n * @dev Tokens are vested for 4 years. Since the max staking\n * period is 3 years and the tokens are unlocked only after the first year(timeDuration) is\n * passed, hence, we usually extend the duration of staking for all unlocked tokens for the first\n * year by 3 years. In some cases, the timeDuration can differ.\n * */\n function extendStaking() external {\n uint256 timeDuration = startDate.add(extendDurationFor);\n uint256[] memory dates;\n uint96[] memory stakes;\n (dates, stakes) = staking.getStakes(address(this));\n\n for (uint256 i = 0; i < dates.length; i++) {\n if ((dates[i] < block.timestamp) && (dates[i] <= timeDuration) && (stakes[i] > 0)) {\n staking.extendStakingDuration(dates[i], dates[i].add(156 weeks));\n endDate = dates[i].add(156 weeks);\n } else {\n break;\n }\n }\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function _stakeTokens(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) internal returns (uint256 lastSchedule, uint256 remainingAmount) {\n // Creating a new staking schedule for the same vesting contract is disallowed unlike normal vesting\n require(\n (startDate == 0) ||\n (startDate > 0 && remainingStakeAmount > 0 && _restartStakeSchedule > 0),\n \"create new vesting address\"\n );\n uint256 restartDate;\n uint256 relativeAmount;\n // Calling the _stakeTokens function first time for the vesting contract\n // Runs for maxInterval only (consider maxInterval = 18 * 4 = 72 weeks)\n if (startDate == 0 && _restartStakeSchedule == 0) {\n startDate = staking.timestampToLockDate(block.timestamp); // Set only once\n durationLeft = duration; // We do not touch duration and cliff as they are used throughout\n cliffAdded = cliff; // Hence, durationLeft and cliffAdded is created\n }\n // Calling the _stakeTokens second/third time - we start from the end of previous interval\n // and the remaining amount(amount left after tokens are staked in the previous interval)\n if (_restartStakeSchedule > 0) {\n require(\n _restartStakeSchedule == lastStakingSchedule && _amount == remainingStakeAmount,\n \"invalid params\"\n );\n restartDate = _restartStakeSchedule;\n } else {\n restartDate = startDate;\n }\n // Runs only once when the _stakeTokens is called for the first time\n if (endDate == 0) {\n endDate = staking.timestampToLockDate(block.timestamp.add(duration));\n }\n uint256 addedMaxInterval = restartDate.add(maxInterval); // run for maxInterval\n if (addedMaxInterval < endDate) {\n // Runs for max interval\n lastStakingSchedule = addedMaxInterval;\n relativeAmount = (_amount.mul(maxInterval)).div(durationLeft); // (_amount * 18) / 39\n durationLeft = durationLeft.sub(maxInterval); // durationLeft - 18 periods(72 weeks)\n remainingStakeAmount = _amount.sub(relativeAmount); // Amount left to be staked in subsequent intervals\n } else {\n // Normal run\n lastStakingSchedule = endDate; // if staking intervals left < 18 periods(72 weeks)\n remainingStakeAmount = 0;\n durationLeft = 0;\n relativeAmount = _amount; // Stake all amount left\n }\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), relativeAmount);\n require(success, \"transfer failed\");\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), relativeAmount);\n\n staking.stakesBySchedule(\n relativeAmount,\n cliffAdded,\n duration.sub(durationLeft),\n FOUR_WEEKS,\n address(this),\n tokenOwner\n );\n if (durationLeft == 0) {\n // All tokens staked\n cliffAdded = 0;\n } else {\n cliffAdded = cliffAdded.add(maxInterval); // Add cliff to the end of previous maxInterval\n }\n\n emit TokensStaked(_sender, relativeAmount);\n return (lastStakingSchedule, remainingStakeAmount);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n /// @dev For four year vesting, withdrawal of stakes for the first year is not allowed. These\n /// stakes are extended for three years. In some cases the withdrawal may be allowed at a different\n /// time and hence we use extendDurationFor.\n for (uint256 i = startDate.add(extendDurationFor); i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number.sub(1));\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../Staking/interfaces/IStaking.sol\";\nimport \"../../IFeeSharingCollector.sol\";\n\n/**\n * @title Four Year Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for four year vesting.\n * It is parent of FourYearVestingLogic and FourYearVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract FourYearVestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n // Used lower case for cliff and duration to maintain consistency with normal vesting\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public constant cliff = 4 weeks;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public constant duration = 156 weeks;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n /// @notice Maximum interval to stake tokens at one go\n uint256 public maxInterval;\n\n /// @notice End of previous staking schedule.\n uint256 public lastStakingSchedule;\n\n /// @notice Amount of shares left to be staked.\n uint256 public remainingStakeAmount;\n\n /// @notice Durations left.\n uint256 public durationLeft;\n\n /// @notice Cliffs added.\n uint256 public cliffAdded;\n\n /// @notice Address of new token owner.\n address public newTokenOwner;\n\n /// @notice Address of new implementation.\n address public newImplementation;\n\n /// @notice Duration(from start) till the time unlocked tokens are extended(for 3 years)\n uint256 public extendDurationFor;\n\n /// @dev Please add new state variables below this line. Mark them internal and\n /// add a getter function while upgrading the contracts.\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IFourYearVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IFourYearVesting {\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount);\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingFactory contract to override empty\n * implemention of deployFourYearVesting function\n * and use an instance of FourYearVestingFactory.\n */\ninterface IFourYearVestingFactory {\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/GenericTokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\n\n/**\n * @title Token sender contract.\n *\n * @notice This contract includes functions to transfer tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract GenericTokenSender is AdminRole {\n /* Events */\n\n event TokensTransferred(address indexed token, address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer given amounts of tokens to the given addresses.\n * @param _token The address of the token.\n * @param _receivers The addresses of the receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferTokensUsingList(\n address _token,\n address[] calldata _receivers,\n uint256[] calldata _amounts\n ) external onlyAuthorized {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferTokens(_token, _receivers[i], _amounts[i]);\n }\n }\n\n function() external payable {}\n\n /**\n * @notice Transfer tokens to given address.\n * @param _token The address of the token.\n * @param _receiver The address of the token receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) external onlyAuthorized {\n _transferTokens(_token, _receiver, _amount);\n }\n\n function _transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n if (_token != address(0)) {\n require(IERC20(_token).transfer(_receiver, _amount), \"transfer failed\");\n } else {\n (bool success, ) = _receiver.call.value(_amount)(\"\");\n require(success, \"RBTC transfer failed\");\n }\n emit TokensTransferred(_token, _receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/ITeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for TeamVesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by Staking contract to call governanceWithdrawTokens\n * function having the vesting contract instance address.\n */\ninterface ITeamVesting {\n function startDate() external view returns (uint256);\n\n function cliff() external view returns (uint256);\n\n function endDate() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function tokenOwner() external view returns (address);\n\n function governanceWithdrawTokens(address receiver) external;\n}\n" + }, + "contracts/governance/Vesting/IVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IVesting {\n function duration() external returns (uint256);\n\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 amount) external;\n\n function tokenOwner() external view returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingFactory contract to override empty\n * implemention of deployVesting and deployTeamVesting functions\n * and on VestingRegistry contract to use an instance of VestingFactory.\n */\ninterface IVestingFactory {\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for upgradable Vesting Registry contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IVestingRegistry {\n function getVesting(address _tokenOwner) external view returns (address);\n\n function getTeamVesting(address _tokenOwner) external view returns (address);\n\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n function isVestingAddress(address _vestingAddress) external view returns (bool);\n\n function isTeamVesting(address _vestingAddress) external view returns (bool);\n}\n" + }, + "contracts/governance/Vesting/OrigingVestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./VestingRegistry.sol\";\n\n/**\n * @title Temp contract for checking address, creating and staking tokens.\n * @notice It casts an instance of vestingRegistry and by using createVesting\n * function it creates a vesting, gets it and stakes some tokens w/ this vesting.\n * */\ncontract OrigingVestingCreator is Ownable {\n VestingRegistry public vestingRegistry;\n\n mapping(address => bool) processedList;\n\n constructor(address _vestingRegistry) public {\n vestingRegistry = VestingRegistry(_vestingRegistry);\n }\n\n /**\n * @notice Create a vesting, get it and stake some tokens w/ this vesting.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount of tokens to be vested.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyOwner {\n require(_tokenOwner != address(0), \"Invalid address\");\n require(!processedList[_tokenOwner], \"Already processed\");\n\n processedList[_tokenOwner] = true;\n\n vestingRegistry.createVesting(_tokenOwner, _amount, _cliff, _duration);\n address vesting = vestingRegistry.getVesting(_tokenOwner);\n vestingRegistry.stakeTokens(vesting, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/OriginInvestorsClaim.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./VestingRegistry.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\n\n/**\n * @title Origin investors claim vested cSOV tokens.\n * @notice // TODO: fund this contract with a total amount of SOV needed to distribute.\n * */\ncontract OriginInvestorsClaim is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// VestingRegistry public constant vestingRegistry = VestingRegistry(0x80B036ae59B3e38B573837c01BB1DB95515b7E6B);\n\n uint256 public totalAmount;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant SOV_VESTING_CLIFF = 6 weeks;\n\n uint256 public kickoffTS;\n uint256 public vestingTerm;\n uint256 public investorsQty;\n bool public investorsListInitialized;\n VestingRegistry public vestingRegistry;\n IStaking public staking;\n IERC20 public SOVToken;\n\n /// @dev user => flag : Whether user has admin role.\n mapping(address => bool) public admins;\n\n /// @dev investor => Amount : Origin investors entitled to claim SOV.\n mapping(address => uint256) public investorsAmountsList;\n\n /* Events */\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n event InvestorsAmountsListAppended(uint256 qty, uint256 amount);\n event ClaimVested(address indexed investor, uint256 amount);\n event ClaimTransferred(address indexed investor, uint256 amount);\n event InvestorsAmountsListInitialized(uint256 qty, uint256 totalAmount);\n\n /* Modifiers */\n\n /// @dev Throws if called by any account other than the owner or admin.\n modifier onlyAuthorized() {\n require(\n isOwner() || admins[msg.sender],\n \"OriginInvestorsClaim::onlyAuthorized: should be authorized\"\n );\n _;\n }\n\n /// @dev Throws if called by any account not whitelisted.\n modifier onlyWhitelisted() {\n require(\n investorsAmountsList[msg.sender] != 0,\n \"OriginInvestorsClaim::onlyWhitelisted: not whitelisted or already claimed\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an initialized investors list.\n modifier notInitialized() {\n require(\n !investorsListInitialized,\n \"OriginInvestorsClaim::notInitialized: the investors list should not be set as initialized\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an uninitialized investors list.\n modifier initialized() {\n require(\n investorsListInitialized,\n \"OriginInvestorsClaim::initialized: the investors list has not been set yet\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires one parameter:\n * @param vestingRegistryAddress The vestingRegistry contract instance address.\n * */\n constructor(address vestingRegistryAddress) public {\n vestingRegistry = VestingRegistry(vestingRegistryAddress);\n staking = IStaking(vestingRegistry.staking());\n kickoffTS = staking.kickoffTS();\n SOVToken = IERC20(staking.SOVToken());\n vestingTerm = kickoffTS + SOV_VESTING_CLIFF;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice In case we have unclaimed tokens or in emergency case\n * this function transfers all SOV tokens to a given address.\n * @param toAddress The recipient address of all this contract tokens.\n * */\n function authorizedBalanceWithdraw(address toAddress) public onlyAuthorized {\n require(\n SOVToken.transfer(toAddress, SOVToken.balanceOf(address(this))),\n \"OriginInvestorsClaim::authorizedTransferBalance: transfer failed\"\n );\n }\n\n /**\n * @notice Should be called after the investors list setup completed.\n * This function checks whether the SOV token balance of the contract is\n * enough and sets status list to initialized.\n * */\n function setInvestorsAmountsListInitialized() public onlyAuthorized notInitialized {\n require(\n SOVToken.balanceOf(address(this)) >= totalAmount,\n \"OriginInvestorsClaim::setInvestorsAmountsList: the contract is not enough financed\"\n );\n\n investorsListInitialized = true;\n\n emit InvestorsAmountsListInitialized(investorsQty, totalAmount);\n }\n\n /**\n * @notice The contract should be approved or transferred necessary\n * amount of SOV prior to calling the function.\n * @param investors The list of investors addresses to add to the list.\n * Duplicates will be skipped.\n * @param claimAmounts The list of amounts for investors investors[i]\n * will receive claimAmounts[i] of SOV.\n * */\n function appendInvestorsAmountsList(\n address[] calldata investors,\n uint256[] calldata claimAmounts\n ) external onlyAuthorized notInitialized {\n uint256 subQty;\n uint256 sumAmount;\n require(\n investors.length == claimAmounts.length,\n \"OriginInvestorsClaim::appendInvestorsAmountsList: investors.length != claimAmounts.length\"\n );\n\n for (uint256 i = 0; i < investors.length; i++) {\n if (investorsAmountsList[investors[i]] == 0) {\n investorsAmountsList[investors[i]] = claimAmounts[i];\n sumAmount = sumAmount.add(claimAmounts[i]);\n } else {\n subQty = subQty.add(1);\n }\n }\n\n investorsQty = investorsQty.add(investors.length.sub(subQty));\n totalAmount = totalAmount.add(sumAmount);\n emit InvestorsAmountsListAppended(investors.length.sub(subQty), sumAmount);\n }\n\n /**\n * @notice Claim tokens from this contract.\n * If vestingTerm is not yet achieved a vesting is created.\n * Otherwise tokens are tranferred.\n * */\n function claim() external onlyWhitelisted initialized {\n if (now < vestingTerm) {\n createVesting();\n } else {\n transfer();\n }\n }\n\n /**\n * @notice Transfer tokens from this contract to a vestingRegistry contract.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to vesting contract.\n * */\n function createVesting() internal {\n uint256 cliff = vestingTerm.sub(now);\n uint256 duration = cliff;\n uint256 amount = investorsAmountsList[msg.sender];\n address vestingContractAddress;\n\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n vestingContractAddress == address(0),\n \"OriginInvestorsClaim::withdraw: the claimer has an active vesting contract\"\n );\n\n delete investorsAmountsList[msg.sender];\n\n vestingRegistry.createVesting(msg.sender, amount, cliff, duration);\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n SOVToken.transfer(address(vestingRegistry), amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n vestingRegistry.stakeTokens(vestingContractAddress, amount);\n\n emit ClaimVested(msg.sender, amount);\n }\n\n /**\n * @notice Transfer tokens from this contract to the sender.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to its account.\n * */\n function transfer() internal {\n uint256 amount = investorsAmountsList[msg.sender];\n\n delete investorsAmountsList[msg.sender];\n\n /**\n * @dev Withdraw only for those claiming after the cliff, i.e. without vesting contracts.\n * Those with vestingContracts should withdraw using Vesting.withdrawTokens\n * from Vesting (VestingLogic) contract.\n * */\n require(\n SOVToken.transfer(msg.sender, amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n\n emit ClaimTransferred(msg.sender, amount);\n }\n}\n" + }, + "contracts/governance/Vesting/TeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n//import \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../proxy/Proxy.sol\";\n\n/**\n * @title Team Vesting Contract.\n *\n * @notice A regular vesting contract, but the owner (governance) is able to\n * withdraw earlier without a slashing.\n *\n * @dev Vesting contracts shouldn't be upgradable,\n * use Proxy instead of UpgradableProxy.\n * */\ncontract TeamVesting is VestingStorage, Proxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollector\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_duration >= _cliff, \"duration must be bigger than or equal to the cliff\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n require(_duration <= staking.MAX_DURATION(), \"duration may not exceed the max duration\");\n tokenOwner = _tokenOwner;\n cliff = _cliff;\n duration = _duration;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n }\n}\n" + }, + "contracts/governance/Vesting/TokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title SOV Token sender contract.\n *\n * @notice This contract includes functions to transfer SOV tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract TokenSender is Ownable {\n /* Storage */\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @dev user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n constructor(address _SOV) public {\n require(_SOV != address(0), \"SOV address invalid\");\n\n SOV = _SOV;\n }\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Transfer given amounts of SOV to the given addresses.\n * @param _receivers The addresses of the SOV receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferSOVusingList(address[] memory _receivers, uint256[] memory _amounts)\n public\n onlyAuthorized\n {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferSOV(_receivers[i], _amounts[i]);\n }\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyAuthorized {\n _transferSOV(_receiver, _amount);\n }\n\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/Vesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./TeamVesting.sol\";\n\n/**\n * @title Vesting Contract.\n * @notice Team tokens and investor tokens are vested. Therefore, a smart\n * contract needs to be developed to enforce the vesting schedule.\n *\n * @dev TODO add tests for governanceWithdrawTokens.\n * */\ncontract Vesting is TeamVesting {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollectorProxy\n )\n public\n TeamVesting(\n _logic,\n _SOV,\n _stakingAddress,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharingCollectorProxy\n )\n {}\n\n /**\n * @dev We need to add this implementation to prevent proxy call VestingLogic.governanceWithdrawTokens\n * @param receiver The receiver of the token withdrawal.\n * */\n function governanceWithdrawTokens(address receiver) public {\n revert(\"operation not supported\");\n }\n}\n" + }, + "contracts/governance/Vesting/VestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"./VestingRegistryLogic.sol\";\nimport \"./VestingLogic.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingCreator is AdminRole {\n using SafeMath for uint256;\n\n ///@notice Boolean to check both vesting creation and staking is completed for a record\n bool vestingCreated;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 2 weeks;\n\n ///@notice the SOV token contract\n IERC20 public SOV;\n\n ///@notice the vesting registry contract\n VestingRegistryLogic public vestingRegistryLogic;\n\n ///@notice Holds Vesting Data\n struct VestingData {\n uint256 amount;\n uint256 cliff;\n uint256 duration;\n bool governanceControl; ///@dev true - tokens can be withdrawn by governance\n address tokenOwner;\n uint256 vestingCreationType;\n }\n\n ///@notice list of vesting to be processed\n VestingData[] public vestingDataList;\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event TokensStaked(address indexed vesting, address indexed tokenOwner, uint256 amount);\n event VestingDataRemoved(address indexed caller, address indexed tokenOwner);\n event DataCleared(address indexed caller);\n\n constructor(address _SOV, address _vestingRegistryProxy) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_vestingRegistryProxy != address(0), \"Vesting registry address invalid\");\n\n SOV = IERC20(_SOV);\n vestingRegistryLogic = VestingRegistryLogic(_vestingRegistryProxy);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings to be processed to the list\n */\n function addVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _amounts,\n uint256[] calldata _cliffs,\n uint256[] calldata _durations,\n bool[] calldata _governanceControls,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n require(\n _tokenOwners.length == _amounts.length &&\n _tokenOwners.length == _cliffs.length &&\n _tokenOwners.length == _durations.length &&\n _tokenOwners.length == _governanceControls.length,\n \"arrays mismatch\"\n );\n\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(\n _durations[i] >= _cliffs[i],\n \"duration must be bigger than or equal to the cliff\"\n );\n require(_amounts[i] > 0, \"vesting amount cannot be 0\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_cliffs[i].mod(TWO_WEEKS) == 0, \"cliffs should have intervals of two weeks\");\n require(\n _durations[i].mod(TWO_WEEKS) == 0,\n \"durations should have intervals of two weeks\"\n );\n VestingData memory vestingData =\n VestingData({\n amount: _amounts[i],\n cliff: _cliffs[i],\n duration: _durations[i],\n governanceControl: _governanceControls[i],\n tokenOwner: _tokenOwners[i],\n vestingCreationType: _vestingCreationTypes[i]\n });\n vestingDataList.push(vestingData);\n }\n }\n\n /**\n * @notice Creates vesting contract and stakes tokens\n * @dev Vesting and Staking are merged for calls that fits the gas limit\n */\n function processNextVesting() external {\n processVestingCreation();\n processStaking();\n }\n\n /**\n * @notice Creates vesting contract without staking any tokens\n * @dev Separating the Vesting and Staking to tackle Block Gas Limit\n */\n function processVestingCreation() public {\n require(!vestingCreated, \"staking not done for the previous vesting\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n _createAndGetVesting(vestingData);\n vestingCreated = true;\n }\n }\n\n /**\n * @notice Staking vested tokens\n * @dev it can be the case when vesting creation and tokens staking can't be done in one transaction because of block gas limit\n */\n function processStaking() public {\n require(vestingCreated, \"cannot stake without vesting creation\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n address vestingAddress =\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n require(SOV.approve(address(vesting), vestingData.amount), \"Approve failed\");\n vesting.stakeTokens(vestingData.amount);\n emit TokensStaked(vestingAddress, vestingData.tokenOwner, vestingData.amount);\n address tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n vestingCreated = false;\n }\n\n /**\n * @notice removes next vesting data from the list\n * @dev we process inverted list\n * @dev we should be able to remove incorrect vesting data that can't be processed\n */\n function removeNextVesting() external onlyAuthorized {\n address tokenOwnerDetails;\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n\n /**\n * @notice removes all data about unprocessed vestings to be processed\n */\n function clearVestingDataList() public onlyAuthorized {\n delete vestingDataList;\n emit DataCleared(msg.sender);\n }\n\n /**\n * @notice returns address after vesting creation\n */\n function getVestingAddress() external view returns (address) {\n return\n _getVesting(\n vestingDataList[vestingDataList.length - 1].tokenOwner,\n vestingDataList[vestingDataList.length - 1].cliff,\n vestingDataList[vestingDataList.length - 1].duration,\n vestingDataList[vestingDataList.length - 1].governanceControl,\n vestingDataList[vestingDataList.length - 1].vestingCreationType\n );\n }\n\n /**\n * @notice returns period i.e. ((duration - cliff) / 4 WEEKS)\n * @dev will be used for deciding if vesting and staking needs to be processed\n * in a single transaction or separate transactions\n */\n function getVestingPeriod() external view returns (uint256) {\n uint256 duration = vestingDataList[vestingDataList.length - 1].duration;\n uint256 cliff = vestingDataList[vestingDataList.length - 1].cliff;\n uint256 fourWeeks = TWO_WEEKS.mul(2);\n uint256 period = duration.sub(cliff).div(fourWeeks);\n return period;\n }\n\n /**\n * @notice returns count of vestings to be processed\n */\n function getUnprocessedCount() external view returns (uint256) {\n return vestingDataList.length;\n }\n\n /**\n * @notice returns total amount of vestings to be processed\n */\n function getUnprocessedAmount() public view returns (uint256) {\n uint256 amount = 0;\n uint256 length = vestingDataList.length;\n for (uint256 i = 0; i < length; i++) {\n amount = amount.add(vestingDataList[i].amount);\n }\n return amount;\n }\n\n /**\n * @notice checks if contract balance is enough to process all vestings\n */\n function isEnoughBalance() public view returns (bool) {\n return SOV.balanceOf(address(this)) >= getUnprocessedAmount();\n }\n\n /**\n * @notice returns missed balance to process all vestings\n */\n function getMissingBalance() external view returns (uint256) {\n if (isEnoughBalance()) {\n return 0;\n }\n return getUnprocessedAmount() - SOV.balanceOf(address(this));\n }\n\n /**\n * @notice creates TeamVesting or Vesting contract\n * @dev new contract won't be created if account already has contract of the same type\n */\n function _createAndGetVesting(VestingData memory vestingData)\n internal\n returns (address vesting)\n {\n if (vestingData.governanceControl) {\n vestingRegistryLogic.createTeamVesting(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n } else {\n vestingRegistryLogic.createVestingAddr(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n }\n return\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n }\n\n /**\n * @notice returns an address of TeamVesting or Vesting contract (depends on a governance control)\n */\n function _getVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n bool _governanceControl,\n uint256 _vestingCreationType\n ) internal view returns (address vestingAddress) {\n if (_governanceControl) {\n vestingAddress = vestingRegistryLogic.getTeamVesting(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n } else {\n vestingAddress = vestingRegistryLogic.getVestingAddr(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n }\n }\n}\n" + }, + "contracts/governance/Vesting/VestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./Vesting.sol\";\nimport \"./TeamVesting.sol\";\nimport \"./IVestingFactory.sol\";\n\n/**\n * @title Vesting Factory: Contract to deploy vesting contracts\n * of two types: vesting (TokenHolder) and team vesting (Multisig).\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract VestingFactory is IVestingFactory, Ownable {\n address public vestingLogic;\n\n constructor(address _vestingLogic) public {\n require(_vestingLogic != address(0), \"invalid vesting logic address\");\n vestingLogic = _vestingLogic;\n }\n\n /**\n * @notice Deploys Vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner /// @dev owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new Vesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n\n /**\n * @notice Deploys Team Vesting contract.\n * @param _SOV The address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner //owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new TeamVesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\n\n/**\n * @title Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by a VestingFactory contract.\n * */\ncontract VestingLogic is IVesting, VestingStorage, ApprovalReceiver {\n /* Events */\n\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(uint256 _amount) public {\n _stakeTokens(msg.sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokensWithApproval(address _sender, uint256 _amount) public onlyThisContract {\n _stakeTokens(_sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * */\n function _stakeTokens(address _sender, uint256 _amount) internal {\n /// @dev Maybe better to allow staking unil the cliff was reached.\n if (startDate == 0) {\n startDate = staking.timestampToLockDate(block.timestamp);\n }\n endDate = staking.timestampToLockDate(block.timestamp + duration);\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), _amount);\n require(success);\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), _amount);\n\n staking.stakeBySchedule(_amount, cliff, duration, FOUR_WEEKS, address(this), tokenOwner);\n\n emit TokensStaked(_sender, _amount);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws all tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * @dev Can be called only by owner.\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdrawTokens(address receiver) public {\n require(msg.sender == address(staking), \"unauthorized\");\n\n _withdrawTokens(receiver, true);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) public onlyOwners {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number - 1);\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n if (isGovernance) {\n staking.governanceWithdraw(stake, i, receiver);\n } else {\n staking.withdraw(stake, i, receiver);\n }\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) public onlyOwners {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() public onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Registry contract.\n *\n * @notice On January 25, 2020, Sovryn launched the Genesis Reservation system.\n * Sovryn community members who controlled a special NFT were granted access to\n * stake BTC or rBTC for cSOV tokens at a rate of 2500 satoshis per cSOV. Per\n * SIP-0003, up to 2,000,000 cSOV were made available in the Genesis event,\n * which will be redeemable on a 1:1 basis for cSOV, subject to approval by\n * existing SOV holders.\n *\n * On 15 Feb 2021 Sovryn is taking another step in its journey to decentralized\n * financial sovereignty with the vote on SIP 0005. This proposal will enable\n * participants of the Genesis Reservation system to redeem their reserved cSOV\n * tokens for SOV. They will also have the choice to redeem cSOV for rBTC if\n * they decide to exit the system.\n *\n * This contract deals with the vesting and redemption of cSOV tokens.\n * */\ncontract VestingRegistry is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The cSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract.\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVReImburse(address from, uint256 CSOVamount, uint256 reImburseAmount);\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing collector proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n //---ACL------------------------------------------------------------------\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * TODO: This ACL logic should be available on OpenZeppeling Ownable.sol\n * or on our own overriding sovrynOwnable. This same logic is repeated\n * on OriginInvestorsClaim.sol, TokenSender.sol and VestingRegistry2.sol\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice cSOV payout to sender with rBTC currency.\n * 1.- Check holder cSOV balance by adding up every cSOV token balance.\n * 2.- ReImburse rBTC if funds available.\n * 3.- And store holder address in processedList.\n */\n function reImburse() public isNotProcessed isNotBlacklisted {\n uint256 CSOVAmountWei = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n CSOVAmountWei = CSOVAmountWei.add(balance);\n }\n\n require(CSOVAmountWei > lockedAmount[msg.sender], \"holder has no CSOV\");\n CSOVAmountWei -= lockedAmount[msg.sender];\n processedList[msg.sender] = true;\n\n /**\n * @dev Found and fixed the SIP-0007 bug on VestingRegistry::reImburse formula.\n * More details at Documenting Code issues at point 11 in\n * https://docs.google.com/document/d/10idTD1K6JvoBmtPKGuJ2Ub_mMh6qTLLlTP693GQKMyU/\n * Previous buggy code: uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**10);\n * */\n uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**8);\n require(address(this).balance >= reImburseAmount, \"Not enough funds to reimburse\");\n msg.sender.transfer(reImburseAmount);\n\n emit CSOVReImburse(msg.sender, CSOVAmountWei, reImburseAmount);\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Exchange cSOV to SOV with 1:1 rate\n */\n function exchangeAllCSOV() public isNotProcessed isNotBlacklisted {\n processedList[msg.sender] = true;\n\n uint256 amount = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n amount += balance;\n }\n\n require(amount > lockedAmount[msg.sender], \"amount invalid\");\n amount -= lockedAmount[msg.sender];\n\n _createVestingForCSOV(amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param _vesting The address of Vesting contract.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n /// @dev TODO: Owner of OwnerVesting contracts - the same address as tokenOwner.\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry2.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title VestingRegistry 2 contract.\n * @notice One time contract needed to distribute tokens to origin sales investors.\n * */\ncontract VestingRegistry2 is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The CSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry3.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingRegistry3 is Ownable {\n using SafeMath for uint256;\n\n IVestingFactory public vestingFactory;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n //@notice fee sharing proxy\n address public feeSharingCollector;\n //@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n //TODO add to the documentation: address can have only one vesting of each type\n //user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n //user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n constructor(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"./VestingRegistryStorage.sol\";\n\ncontract VestingRegistryLogic is VestingRegistryStorage {\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event VestingCreationAndTypesSet(\n address indexed vesting,\n VestingCreationAndTypeDetails vestingCreationAndType\n );\n\n /**\n * @notice Replace constructor with initialize function for Upgradable Contracts\n * This function will be called only once by the owner\n * */\n function initialize(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner,\n address _lockedSOV,\n address[] calldata _vestingRegistries\n ) external onlyOwner initializer {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n require(_lockedSOV != address(0), \"LockedSOV address invalid\");\n\n _setVestingFactory(_vestingFactory);\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n lockedSOV = LockedSOV(_lockedSOV);\n for (uint256 i = 0; i < _vestingRegistries.length; i++) {\n require(_vestingRegistries[i] != address(0), \"Vesting registry address invalid\");\n vestingRegistries.push(IVestingRegistry(_vestingRegistries[i]));\n }\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) external onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Internal function that sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings that were deployed in previous vesting registries\n * @dev migration of data from previous vesting registy contracts\n */\n function addDeployedVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingCreationTypes[i] > 0, \"vesting creation type must be greater than 0\");\n _addDeployedVestings(_tokenOwners[i], _vestingCreationTypes[i]);\n }\n }\n\n /**\n * @notice adds four year vestings to vesting registry logic\n * @param _tokenOwners array of token owners\n * @param _vestingAddresses array of vesting addresses\n */\n function addFourYearVestings(\n address[] calldata _tokenOwners,\n address[] calldata _vestingAddresses\n ) external onlyAuthorized {\n require(_tokenOwners.length == _vestingAddresses.length, \"arrays mismatch\");\n uint256 vestingCreationType = 4;\n uint256 cliff = 4 weeks;\n uint256 duration = 156 weeks;\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(!isVesting[_vestingAddresses[i]], \"vesting exists\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingAddresses[i] != address(0), \"vesting cannot be 0 address\");\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwners[i],\n uint256(VestingType.Vesting),\n cliff,\n duration,\n vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n vestingCreationType,\n _vestingAddresses[i]\n );\n vestingsOf[_tokenOwners[i]].push(uid);\n isVesting[_vestingAddresses[i]] = true;\n }\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @dev Calls a public createVestingAddr function with vestingCreationType. This is to accomodate the existing logic for LockedSOV\n * @dev vestingCreationType 0 = LockedSOV\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAuthorized {\n createVestingAddr(_tokenOwner, _amount, _cliff, _duration, 3);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createVestingAddr(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.Vesting),\n _vestingCreationType\n );\n\n emit VestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) external onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.TeamVesting),\n _vestingCreationType\n );\n\n emit TeamVestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) external onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n * @dev Calls a public getVestingAddr function with cliff and duration. This is to accomodate the existing logic for LockedSOV\n * @dev We need to use LockedSOV.changeRegistryCliffAndDuration function very judiciously\n * @dev vestingCreationType 0 - LockedSOV\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return getVestingAddr(_tokenOwner, lockedSOV.cliff(), lockedSOV.duration(), 3);\n }\n\n /**\n * @notice public function that returns vesting contract address for the given token owner, cliff, duration\n * @dev Important: Please use this instead of getVesting function\n */\n function getVestingAddr(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner, cliff, duration\n */\n function getTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @dev check if the specific vesting address is team vesting or not\n * @dev read the vestingType from vestingCreationAndTypes storage\n *\n * @param _vestingAddress address of vesting contract\n *\n * @return true for teamVesting, false for normal vesting\n */\n function isTeamVesting(address _vestingAddress) external view returns (bool) {\n return (vestingCreationAndTypes[_vestingAddress].isSet &&\n vestingCreationAndTypes[_vestingAddress].vestingType ==\n uint32(VestingType.TeamVesting));\n }\n\n /**\n * @dev setter function to register existing vesting contract to vestingCreationAndTypes storage\n * @dev need to set the function visilibty to public to support VestingCreationAndTypeDetails struct as parameter\n *\n * @param _vestingAddresses array of vesting address\n * @param _vestingCreationAndTypes array for VestingCreationAndTypeDetails struct\n */\n function registerVestingToVestingCreationAndTypes(\n address[] memory _vestingAddresses,\n VestingCreationAndTypeDetails[] memory _vestingCreationAndTypes\n ) public onlyAuthorized {\n require(_vestingAddresses.length == _vestingCreationAndTypes.length, \"Unmatched length\");\n for (uint256 i = 0; i < _vestingCreationAndTypes.length; i++) {\n VestingCreationAndTypeDetails memory _vestingCreationAndType =\n _vestingCreationAndTypes[i];\n address _vestingAddress = _vestingAddresses[i];\n\n vestingCreationAndTypes[_vestingAddress] = _vestingCreationAndType;\n\n emit VestingCreationAndTypesSet(\n _vestingAddress,\n vestingCreationAndTypes[_vestingAddress]\n );\n }\n }\n\n /**\n * @notice Internal function to deploy Vesting/Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _type the type of vesting\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _type,\n uint256 _vestingCreationType\n ) internal returns (address) {\n address vesting;\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, _type, _cliff, _duration, _vestingCreationType)\n )\n );\n if (vestings[uid].vestingAddress == address(0)) {\n if (_type == 1) {\n vesting = vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n } else {\n vesting = vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n }\n vestings[uid] = Vesting(_type, _vestingCreationType, vesting);\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vesting] = true;\n\n vestingCreationAndTypes[vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(_type),\n vestingCreationType: uint128(_vestingCreationType)\n });\n\n emit VestingCreationAndTypesSet(vesting, vestingCreationAndTypes[vesting]);\n }\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice stores the addresses of Vesting contracts from all three previous versions of Vesting Registry\n */\n function _addDeployedVestings(address _tokenOwner, uint256 _vestingCreationType) internal {\n uint256 uid;\n uint256 i = _vestingCreationType - 1;\n\n address vestingAddress = vestingRegistries[i].getVesting(_tokenOwner);\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.Vesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n _vestingCreationType,\n vestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vestingAddress] = true;\n }\n\n address teamVestingAddress = vestingRegistries[i].getTeamVesting(_tokenOwner);\n if (teamVestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(teamVestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.TeamVesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.TeamVesting),\n _vestingCreationType,\n teamVestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[teamVestingAddress] = true;\n }\n }\n\n /**\n * @notice returns all vesting details for the given token owner\n */\n function getVestingsOf(address _tokenOwner) external view returns (Vesting[] memory) {\n uint256[] memory vestingIds = vestingsOf[_tokenOwner];\n uint256 length = vestingIds.length;\n Vesting[] memory _vestings = new Vesting[](vestingIds.length);\n for (uint256 i = 0; i < length; i++) {\n _vestings[i] = vestings[vestingIds[i]];\n }\n return _vestings;\n }\n\n /**\n * @notice returns cliff and duration for Vesting & TeamVesting contracts\n */\n function getVestingDetails(address _vestingAddress)\n external\n view\n returns (uint256 cliff, uint256 duration)\n {\n VestingLogic vesting = VestingLogic(_vestingAddress);\n return (vesting.cliff(), vesting.duration());\n }\n\n /**\n * @notice returns if the address is a vesting address\n */\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return isVesting[_vestingAddress];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./VestingRegistryStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Vesting Registry Proxy contract.\n * @dev Vesting Registry contract should be upgradable, use UpgradableProxy.\n * VestingRegistryStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract VestingRegistryProxy is VestingRegistryStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Initializable.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"../../locked/LockedSOV.sol\";\nimport \"./IVestingRegistry.sol\";\n\n/**\n * @title Vesting Registry Storage Contract.\n *\n * @notice This contract is just the storage required for vesting registry.\n * It is parent of VestingRegistryProxy and VestingRegistryLogic.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\n\ncontract VestingRegistryStorage is Initializable, AdminRole {\n ///@notice the vesting factory contract\n IVestingFactory public vestingFactory;\n\n ///@notice the Locked SOV contract\n ///@dev NOTES: No need to update lockedSOV in this contract, since it might break the vestingRegistry if the new lockedSOV does not have the same value of cliff & duration.\n ILockedSOV public lockedSOV;\n\n ///@notice the list of vesting registries\n IVestingRegistry[] public vestingRegistries;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n\n ///@notice fee sharing proxy\n address public feeSharingCollector;\n\n ///@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n ///@notice Vesting details\n struct Vesting {\n uint256 vestingType;\n uint256 vestingCreationType;\n address vestingAddress;\n }\n\n ///@notice A record of vesting details for a unique id\n ///@dev vestings[uid] returns vesting data\n mapping(uint256 => Vesting) public vestings;\n\n ///@notice A record of all unique ids for a particular token owner\n ///@dev vestingsOf[tokenOwner] returns array of unique ids\n mapping(address => uint256[]) public vestingsOf;\n\n ///@notice A record of all vesting addresses\n ///@dev isVesting[address] returns if the address is a vesting address\n mapping(address => bool) public isVesting;\n\n /// @notice Store vesting creation type & vesting type information\n /// @dev it is packed into 1 single storage slot for cheaper gas usage\n struct VestingCreationAndTypeDetails {\n bool isSet;\n uint32 vestingType;\n uint128 vestingCreationType;\n }\n\n ///@notice A record of all vesting addresses with the detail\n ///@dev vestingDetail[vestingAddress] returns Vesting struct data\n ///@dev can be used to easily check the vesting type / creation type based on the vesting address itself\n mapping(address => VestingCreationAndTypeDetails) public vestingCreationAndTypes;\n}\n" + }, + "contracts/governance/Vesting/VestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\n\n/**\n * @title Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for vesting.\n * It is parent of VestingLogic and TeamVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract VestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public cliff;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 constant FOUR_WEEKS = 4 weeks;\n}\n" + }, + "contracts/interfaces/IChai.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IERC20.sol\";\n\ninterface IPot {\n function dsr() external view returns (uint256);\n\n function chi() external view returns (uint256);\n\n function rho() external view returns (uint256);\n}\n\ncontract IChai is IERC20 {\n function move(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function join(address dst, uint256 wad) external;\n\n function draw(address src, uint256 wad) external;\n\n function exit(address src, uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IConverterAMM.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IConverterAMM {\n function withdrawFees(address receiver) external returns (uint256);\n}\n" + }, + "contracts/interfaces/IERC20.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ncontract IERC20 {\n string public name;\n uint8 public decimals;\n string public symbol;\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address _who) external view returns (uint256);\n\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/interfaces/IERC777.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777Token standard as defined in the EIP.\n *\n * This contract uses the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let\n * token holders and recipients react to token movements by using setting implementers\n * for the associated interfaces in said registry. See {IERC1820Registry} and\n * {ERC1820Implementer}.\n */\ninterface IERC777 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the smallest part of the token that is not divisible. This\n * means all token operations (creation, movement and destruction) must have\n * amounts that are a multiple of this number.\n *\n * For most token contracts, this value will equal 1.\n */\n function granularity() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by an account (`owner`).\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * If send or receive hooks are registered for the caller and `recipient`,\n * the corresponding functions will be called with `data` and empty\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes calldata data\n ) external;\n\n /**\n * @dev Destroys `amount` tokens from the caller's account, reducing the\n * total supply.\n *\n * If a send hook is registered for the caller, the corresponding function\n * will be called with `data` and empty `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n */\n function burn(uint256 amount, bytes calldata data) external;\n\n /**\n * @dev Returns true if an account is an operator of `tokenHolder`.\n * Operators can send and burn tokens on behalf of their owners. All\n * accounts are their own operator.\n *\n * See {operatorSend} and {operatorBurn}.\n */\n function isOperatorFor(address operator, address tokenHolder) external view returns (bool);\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor}.\n *\n * Emits an {AuthorizedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function authorizeOperator(address operator) external;\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor} and {defaultOperators}.\n *\n * Emits a {RevokedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function revokeOperator(address operator) external;\n\n /**\n * @dev Returns the list of default operators. These accounts are operators\n * for all token holders, even if {authorizeOperator} was never called on\n * them.\n *\n * This list is immutable, but individual holders may revoke these via\n * {revokeOperator}, in which case {isOperatorFor} will return false.\n */\n function defaultOperators() external view returns (address[] memory);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must\n * be an operator of `sender`.\n *\n * If send or receive hooks are registered for `sender` and `recipient`,\n * the corresponding functions will be called with `data` and\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - `sender` cannot be the zero address.\n * - `sender` must have at least `amount` tokens.\n * - the caller must be an operator for `sender`.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n /**\n * @dev Destoys `amount` tokens from `account`, reducing the total supply.\n * The caller must be an operator of `account`.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `data` and `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n * - the caller must be an operator for `account`.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n event Sent(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Minted(\n address indexed operator,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Burned(\n address indexed operator,\n address indexed from,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event AuthorizedOperator(address indexed operator, address indexed tokenHolder);\n\n event RevokedOperator(address indexed operator, address indexed tokenHolder);\n}\n" + }, + "contracts/interfaces/IERC777Recipient.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.\n *\n * Accounts can be notified of {IERC777} tokens being sent to them by having a\n * contract implement this interface (contract holders can be their own\n * implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Recipient {\n /**\n * @dev Called by an {IERC777} token contract whenever tokens are being\n * moved or created into a registered account (`to`). The type of operation\n * is conveyed by `from` being the zero address or not.\n *\n * This call occurs _after_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the post-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/IERC777Sender.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensSender standard as defined in the EIP.\n *\n * {IERC777} Token holders can be notified of operations performed on their\n * tokens by having a contract implement this interface (contract holders can be\n * their own implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Sender {\n /**\n * @dev Called by an {IERC777} token contract whenever a registered holder's\n * (`from`) tokens are about to be moved or destroyed. The type of operation\n * is conveyed by `to` being the zero address or not.\n *\n * This call occurs _before_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the pre-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/ILoanPool.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface ILoanPool {\n function tokenPrice() external view returns (uint256 price);\n\n function borrowInterestRate() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/ILoanTokenModules.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\ninterface ILoanTokenModules {\n /** EVENT */\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /// topic: 0x9bbd2de400810774339120e2f8a2b517ed748595e944529bba8ebabf314d0591\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n\n /** INTERFACE */\n\n /** START LOAN TOKEN SETTINGS LOWER ADMIN */\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n\n function setAdmin(address _admin) external;\n\n function setPauser(address _pauser) external;\n\n function setupLoanParams(LoanParams[] calldata loanParamsList, bool areTorqueLoans) external;\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external;\n\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) external;\n\n function toggleFunctionPause(\n string calldata funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) external;\n\n function setTransactionLimits(address[] calldata addresses, uint256[] calldata limits)\n external;\n\n function changeLoanTokenNameAndSymbol(string calldata _name, string calldata _symbol) external;\n\n /** END LOAN TOKEN SETTINGS LOWER ADMIN */\n\n /** START LOAN TOKEN LOGIC STANDARD */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n address affiliateReferrer, // The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes // Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function borrowInterestRate() external view returns (uint256);\n\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n\n function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid);\n\n function checkPause(string calldata funcId) external view returns (bool isPaused);\n\n function nextBorrowInterestRate(uint256 borrowAmount) external view returns (uint256);\n\n function totalAssetBorrow() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes calldata /// loanDataBytes: arbitrary order data (for future use).\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n );\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function setLiquidityMiningAddress(address LMAddress) external;\n\n function getLiquidityMiningAddress() external view returns (address);\n\n function setStakingContractAddress(address _stakingContractAddress) external;\n\n function getStakingContractAddress() external view returns (address);\n\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n external\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n );\n\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 depositAmount);\n\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 borrowAmount);\n\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) external view;\n\n function getMaxEscrowAmount(uint256 leverageAmount)\n external\n view\n returns (uint256 maxEscrowAmount);\n\n function checkpointPrice(address _user) external view returns (uint256 price);\n\n function assetBalanceOf(address _owner) external view returns (uint256);\n\n function profitOf(address user) external view returns (int256);\n\n function tokenPrice() external view returns (uint256 price);\n\n function avgBorrowInterestRate() external view returns (uint256);\n\n function supplyInterestRate() external view returns (uint256);\n\n function nextSupplyInterestRate(uint256 supplyAmount) external view returns (uint256);\n\n function totalSupplyInterestRate(uint256 assetSupply) external view returns (uint256);\n\n function loanTokenAddress() external view returns (address);\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n external\n view\n returns (uint256, uint256);\n\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external;\n\n /** START LOAN TOKEN BASE */\n function initialPrice() external view returns (uint256);\n\n /** START LOAN TOKEN LOGIC LM */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external returns (uint256 minted);\n\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 redeemed);\n\n /** START LOAN TOKEN LOGIC WRBTC */\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n returns (uint256 mintAmount);\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function marketLiquidity() external view returns (uint256);\n\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n external\n view\n returns (uint256);\n\n /** START LOAN TOKEN LOGIC STORAGE */\n function pauser() external view returns (address);\n\n function liquidityMiningAddress() external view returns (address);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n /** START ADVANCED TOKEN */\n function approve(address _spender, uint256 _value) external returns (bool);\n\n /** START ADVANCED TOKEN STORAGE */\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function balanceOf(address _owner) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function loanParamsIds(uint256) external view returns (bytes32);\n}\n" + }, + "contracts/interfaces/ISovryn.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\npragma experimental ABIEncoderV2;\n//TODO: stored in ./interfaces only while brownie isn't removed\n//TODO: move to contracts/interfaces after with brownie is removed\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\ncontract ISovryn is\n State,\n ProtocolSettingsEvents,\n LoanSettingsEvents,\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n LoanClosingsEvents,\n SwapsEvents,\n AffiliatesEvents,\n FeesEvents\n{\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n ////// Protocol //////\n\n function replaceContract(address target) external;\n\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\n\n function getTarget(string calldata sig) external view returns (address);\n\n ////// Protocol Settings //////\n\n function setSovrynProtocolAddress(address newProtocolAddress) external;\n\n function setSOVTokenAddress(address newSovTokenAddress) external;\n\n function setLockedSOVAddress(address newSOVLockedAddress) external;\n\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\n\n function setPriceFeedContract(address newContract) external;\n\n function setSwapsImplContract(address newContract) external;\n\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\n\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\n\n function setLendingFeePercent(uint256 newValue) external;\n\n function setTradingFeePercent(uint256 newValue) external;\n\n function setBorrowingFeePercent(uint256 newValue) external;\n\n function setSwapExternalFeePercent(uint256 newValue) external;\n\n function setAffiliateFeePercent(uint256 newValue) external;\n\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\n\n function setLiquidationIncentivePercent(uint256 newAmount) external;\n\n function setMaxDisagreement(uint256 newAmount) external;\n\n function setSourceBuffer(uint256 newAmount) external;\n\n function setMaxSwapSize(uint256 newAmount) external;\n\n function setFeesController(address newController) external;\n\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n returns (address, bool);\n\n function depositProtocolToken(uint256 amount) external;\n\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function setWrbtcToken(address wrbtcTokenAddress) external;\n\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\n\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\n\n function setRolloverBaseReward(uint256 transactionCost) external;\n\n function setRebatePercent(uint256 rebatePercent) external;\n\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external;\n\n function getSpecialRebates(address sourceToken, address destToken)\n external\n view\n returns (uint256 specialRebatesPercent);\n\n function togglePaused(bool paused) external;\n\n function isProtocolPaused() external view returns (bool);\n\n ////// SwapsImplSovrynSwapModule //////\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (address);\n\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\n\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn);\n\n ////// Loan Settings //////\n\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function getLoanParams(bytes32[] calldata loanParamsIdList)\n external\n view\n returns (LoanParams[] memory loanParamsList);\n\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n\n ////// Loan Openings //////\n\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external;\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n ////// Loan Closings //////\n\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n );\n\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata loanDataBytes\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n ////// Loan Maintenance //////\n\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount // must match msg.value if ether is sent\n ) external payable;\n\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 actualWithdrawAmount);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n );\n\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; // collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\n\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\n\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external returns (uint256 secondsExtended);\n\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 secondsReduced);\n\n ////// Swaps External //////\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view;\n\n ////// Affiliates Module //////\n\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\n\n function setUserNotFirstTradeFlag(address user) external;\n\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\n\n function getReferralsList(address referrer) external view returns (address[] memory refList);\n\n function getAffiliatesReferrerBalances(address referrer)\n external\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\n\n function getAffiliatesReferrerTokensList(address referrer)\n external\n view\n returns (address[] memory tokensList);\n\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n external\n view\n returns (uint256);\n\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) external;\n\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\n\n function getProtocolAddress() external view returns (address);\n\n function getSovTokenAddress() external view returns (address);\n\n function getLockedSOVAddress() external view returns (address);\n\n function getFeeRebatePercent() external view returns (uint256);\n\n function getMinReferralsToPayout() external view returns (uint256);\n\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\n\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\n\n function getAffiliateTradingTokenFeePercent()\n external\n view\n returns (uint256 affiliateTradingTokenFeePercent);\n\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount);\n\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\n\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\n\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\n\n function getDedicatedSOVRebate() external view returns (uint256);\n\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\n\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory);\n\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\n\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external;\n\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\n\n function setAdmin(address newAdmin) external;\n\n function getAdmin() external view returns (address);\n\n function setPauser(address newPauser) external;\n\n function getPauser() external view returns (address);\n}\n" + }, + "contracts/interfaces/IWrbtc.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface IWrbtc {\n function deposit() external payable;\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IWrbtcERC20.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IWrbtc.sol\";\nimport \"./IERC20.sol\";\n\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\n" + }, + "contracts/locked/ILockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title The Locked SOV Interface.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This interface is an incomplete yet useful for future migration of LockedSOV Contract.\n * @dev Only use it if you know what you are doing.\n */\ninterface ILockedSOV {\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external;\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external;\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external;\n\n function cliff() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function getLockedBalance(address _addr) external view returns (uint256 _balance);\n\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance);\n}\n" + }, + "contracts/locked/LockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../governance/Vesting/VestingRegistry.sol\";\nimport \"../governance/Vesting/VestingLogic.sol\";\nimport \"./ILockedSOV.sol\";\n\n/**\n * @title The Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This contract is used to receive reward from other contracts, Create Vesting and Stake Tokens.\n */\ncontract LockedSOV is ILockedSOV {\n using SafeMath for uint256;\n\n uint256 public constant MAX_BASIS_POINT = 10000;\n uint256 public constant MAX_DURATION = 37;\n\n /* Storage */\n\n /// @notice True if the migration to a new Locked SOV Contract has started.\n bool public migration;\n\n /// @notice The cliff is the time period after which the tokens begin to unlock.\n uint256 public cliff;\n /// @notice The duration is the time period after all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n /// @notice The Vesting registry contract.\n VestingRegistry public vestingRegistry;\n /// @notice The New (Future) Locked SOV.\n ILockedSOV public newLockedSOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) private lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) private unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) private isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /// @notice Emitted when Vesting Registry, Duration and/or Cliff is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vestingRegistry The Vesting Registry Contract.\n /// @param _cliff The time period after which the tokens begin to unlock.\n /// @param _duration The time period after all tokens will have been unlocked.\n event RegistryCliffAndDurationUpdated(\n address indexed _initiator,\n address indexed _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n );\n\n /// @notice Emitted when a new deposit is made.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user to whose un/locked balance a new deposit was made.\n /// @param _sovAmount The amount of SOV to be added to the un/locked balance.\n /// @param _basisPoint The % (in Basis Point) which determines how much will be unlocked immediately.\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n /// @notice Emitted when a user withdraws the fund.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _sovAmount The amount of SOV withdrawn from the unlocked balance.\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n /// @notice Emitted when a user creates a vesting for himself.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _vesting The Vesting Contract.\n event VestingCreated(\n address indexed _initiator,\n address indexed _userAddress,\n address indexed _vesting\n );\n\n /// @notice Emitted when a user stakes tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vesting The Vesting Contract.\n /// @param _amount The amount of locked tokens staked by the user.\n event TokenStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /// @notice Emitted when an admin initiates a migration to new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedSOV The address of the new Locked SOV Contract.\n event MigrationStarted(address indexed _initiator, address indexed _newLockedSOV);\n\n /// @notice Emitted when a user initiates the transfer to a new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of locked tokens to transfer from this contract to the new one.\n event UserTransfered(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n modifier migrationAllowed {\n require(migration, \"Migration has not yet started.\");\n _;\n }\n\n /* Constructor */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV Token Address.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @param _admins The list of Admins to be added.\n */\n constructor(\n address _SOV,\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration,\n address[] memory _admins\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_vestingRegistry != address(0), \"Vesting registry address is invalid.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n SOV = IERC20(_SOV);\n vestingRegistry = VestingRegistry(_vestingRegistry);\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /* Public or External Functions */\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n * @dev Only callable by an Admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address.\");\n require(!isAdmin[_newAdmin], \"Address is already admin.\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n * @dev Only callable by an Admin.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin.\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice The function to update the Vesting Registry, Duration and Cliff.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @dev IMPORTANT 1: You have to change Vesting Registry if you want to change Duration and/or Cliff.\n * IMPORTANT 2: `_cliff` and `_duration` is multiplied by 4 weeks in this function.\n */\n function changeRegistryCliffAndDuration(\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAdmin {\n require(\n address(vestingRegistry) != _vestingRegistry,\n \"Vesting Registry has to be different for changing duration and cliff.\"\n );\n /// If duration is also zero, then it is similar to Unlocked SOV.\n require(_duration != 0, \"Duration cannot be zero.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n vestingRegistry = VestingRegistry(_vestingRegistry);\n\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n emit RegistryCliffAndDurationUpdated(msg.sender, _vestingRegistry, _cliff, _duration);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // MAX_BASIS_POINT is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < MAX_BASIS_POINT, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(MAX_BASIS_POINT);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice A function to withdraw the unlocked balance.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdraw(address _receiverAddress) public {\n _withdraw(msg.sender, _receiverAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n /**\n * @notice Creates vesting if not already created and Stakes tokens for a user.\n * @dev Only use this function if the `duration` is small.\n */\n function createVestingAndStake() public {\n _createVestingAndStake(msg.sender);\n }\n\n function _createVestingAndStake(address _sender) private {\n address vestingAddr = _getVesting(_sender);\n\n if (vestingAddr == address(0)) {\n vestingAddr = _createVesting(_sender);\n }\n\n _stakeTokens(_sender, vestingAddr);\n }\n\n /**\n * @notice Creates vesting contract (if it hasn't been created yet) for the calling user.\n * @return _vestingAddress The New Vesting Contract Created.\n */\n function createVesting() public returns (address _vestingAddress) {\n _vestingAddress = _createVesting(msg.sender);\n }\n\n /**\n * @notice Stakes tokens for a user who already have a vesting created.\n * @dev The user should already have a vesting created, else this function will throw error.\n */\n function stakeTokens() public {\n VestingLogic vesting = VestingLogic(_getVesting(msg.sender));\n\n require(\n cliff == vesting.cliff() && duration == vesting.duration(),\n \"Wrong Vesting Schedule.\"\n );\n\n _stakeTokens(msg.sender, address(vesting));\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdrawAndStakeTokens(address _receiverAddress) external {\n _withdraw(msg.sender, _receiverAddress);\n _createVestingAndStake(msg.sender);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n /**\n * @notice Function to start the process of migration to new contract.\n * @param _newLockedSOV The new locked sov contract address.\n */\n function startMigration(address _newLockedSOV) external onlyAdmin {\n require(_newLockedSOV != address(0), \"New Locked SOV Address is Invalid.\");\n newLockedSOV = ILockedSOV(_newLockedSOV);\n SOV.approve(_newLockedSOV, SOV.balanceOf(address(this)));\n migration = true;\n\n emit MigrationStarted(msg.sender, _newLockedSOV);\n }\n\n /**\n * @notice Function to transfer the locked balance from this contract to new LockedSOV Contract.\n * @dev Address is not specified to discourage selling lockedSOV to other address.\n */\n function transfer() external migrationAllowed {\n uint256 amount = lockedBalances[msg.sender];\n lockedBalances[msg.sender] = 0;\n\n newLockedSOV.depositSOV(msg.sender, amount);\n\n emit UserTransfered(msg.sender, amount);\n }\n\n /* Internal Functions */\n\n /**\n * @notice Creates a Vesting Contract for a user.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n * @dev Does not do anything if Vesting Contract was already created.\n */\n function _createVesting(address _tokenOwner) internal returns (address _vestingAddress) {\n /// Here zero is given in place of amount, as amount is not really used in `vestingRegistry.createVesting()`.\n vestingRegistry.createVesting(_tokenOwner, 0, cliff, duration);\n _vestingAddress = _getVesting(_tokenOwner);\n emit VestingCreated(msg.sender, _tokenOwner, _vestingAddress);\n }\n\n /**\n * @notice Returns the Vesting Contract Address.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n */\n function _getVesting(address _tokenOwner) internal view returns (address _vestingAddress) {\n return vestingRegistry.getVesting(_tokenOwner);\n }\n\n /**\n * @notice Stakes the tokens in a particular vesting contract.\n * @param _vesting The Vesting Contract Address.\n */\n function _stakeTokens(address _sender, address _vesting) internal {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n require(SOV.approve(_vesting, amount), \"Approve failed.\");\n VestingLogic(_vesting).stakeTokens(amount);\n\n emit TokenStaked(_sender, _vesting, amount);\n }\n\n /* Getter or Read Functions */\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) external view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n\n /**\n * @notice The function to check is an address is admin or not.\n * @param _addr The address of the user to check the admin status.\n * @return _status True if admin, False otherwise.\n */\n function adminStatus(address _addr) external view returns (bool _status) {\n return isAdmin[_addr];\n }\n}\n" + }, + "contracts/mixins/EnumerableAddressSet.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Based on Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * As of v2.5.0, only `address` sets are supported.\n *\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\n *\n * _Available since v2.5.0._\n */\nlibrary EnumerableAddressSet {\n struct AddressSet {\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(address => uint256) index;\n address[] values;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n * Returns false if the value was already in the set.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n * Returns false if the value was not present in the set.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n // If the element we're deleting is the last one, we can just remove it without doing a swap\n if (lastIndex != toDeleteIndex) {\n address lastValue = set.values[lastIndex];\n\n // Move the last value to the index where the deleted value is\n set.values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n // Delete the index entry for the deleted value\n delete set.index[value];\n\n // Delete the old entry for the moved value\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns an array with all values in the set. O(N).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\n address[] memory output = new address[](set.values.length);\n for (uint256 i; i < set.values.length; i++) {\n output[i] = set.values[i];\n }\n return output;\n }\n\n /**\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n \n * @param start start index of chunk\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\n */\n function enumerateChunk(\n AddressSet storage set,\n uint256 start,\n uint256 count\n ) internal view returns (address[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = (set.values.length < end || count == 0) ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new address[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @dev Returns the number of elements on the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /** @dev Returns the element stored at position `index` in the set. O(1).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes32Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\n * */\nlibrary EnumerableBytes32Set {\n struct Bytes32Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes32 => uint256) index;\n bytes32[] values;\n }\n\n /**\n * @notice Add an address value to a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to add.\n *\n * @return False if the value was already in the set.\n */\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return addBytes32(set, value);\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove an address value from a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to remove.\n *\n * @return False if the address was not present in the set.\n */\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return removeBytes32(set, value);\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function containsAddress(Bytes32Set storage set, address addrvalue)\n internal\n view\n returns (bool)\n {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes32Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes32[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes32[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes4Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`.\n * */\nlibrary EnumerableBytes4Set {\n struct Bytes4Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes4 => uint256) index;\n bytes4[] values;\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes4 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes4Set storage set, bytes4 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes4Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes4[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes4[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes4Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes4Set storage set, uint256 index) internal view returns (bytes4) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/FeesHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ISovryn.sol\";\nimport \"../core/objects/LoanParamsStruct.sol\";\n\n/**\n * @title The Fees Helper contract.\n *\n * This contract calculates and pays lending/borrow fees and rewards.\n * */\ncontract FeesHelper is State, FeesEvents {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Calculate trading fee.\n * @param feeTokenAmount The amount of tokens to trade.\n * @return The fee of the trade.\n * */\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\n }\n\n /**\n * @notice Calculate swap external fee.\n * @param feeTokenAmount The amount of token to swap.\n * @return The fee of the swap.\n */\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\n }\n\n /*\n\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - tradingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);\n\t}*/\n\n /**\n * @notice Calculate the loan origination fee.\n * @param feeTokenAmount The amount of tokens to borrow.\n * @return The fee of the loan.\n * */\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\n /*\n\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - borrowingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);*/\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\n *\n * @param referrer The affiliate referrer address to send the reward to.\n * @param trader The account that performs this trade.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n *\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\n * */\n function _payTradingFeeToAffiliate(\n address referrer,\n address trader,\n address feeToken,\n uint256 tradingFee\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\n address(this)\n )\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n * */\n function _payTradingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 tradingFee\n ) internal {\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\n if (tradingFee != 0) {\n if (affiliatesUserReferrer[user] != address(0)) {\n _payTradingFeeToAffiliate(\n affiliatesUserReferrer[user],\n user,\n feeToken,\n protocolTradingFee\n );\n protocolTradingFee = (\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\n )\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\n }\n\n /// Increase the storage variable keeping track of the accumulated fees.\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\n protocolTradingFee\n );\n\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\n }\n }\n\n /**\n * @notice Settle the borrowing fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the borrowig fee is paid.\n * @param borrowingFee The height of the fee.\n * */\n function _payBorrowingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 borrowingFee\n ) internal {\n if (borrowingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\n\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\n }\n }\n\n /**\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\n * @param user The address to send the reward to.\n * @param feeToken The address of the token in which the lending fee is paid.\n * @param lendingFee The height of the fee.\n * */\n function _payLendingFee(\n address user,\n address feeToken,\n uint256 lendingFee\n ) internal {\n if (lendingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\n\n emit PayLendingFee(user, feeToken, lendingFee);\n\n //// NOTE: Lenders do not receive a fee reward ////\n }\n }\n\n /// Settle and pay borrowers based on the fees generated by their interest payments.\n function _settleFeeRewardForInterestExpense(\n LoanInterest storage loanInterestLocal,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n address user,\n uint256 interestTime\n ) internal {\n /// This represents the fee generated by a borrower's interest payment.\n uint256 interestExpenseFee =\n interestTime\n .sub(loanInterestLocal.updatedTimestamp)\n .mul(loanInterestLocal.owedPerDay)\n .mul(lendingFeePercent)\n .div(1 days * 10**20);\n\n loanInterestLocal.updatedTimestamp = interestTime;\n\n if (interestExpenseFee != 0) {\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\n }\n }\n\n /**\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associeated loan - used for logging only.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * */\n function _payFeeReward(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 feeAmount\n ) internal {\n uint256 rewardAmount;\n uint256 _feeRebatePercent = feeRebatePercent;\n address _priceFeeds = priceFeeds;\n\n if (specialRebates[feeToken][feeTokenPair] > 0) {\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\n }\n\n /// Note: this should be refactored.\n /// Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\n feeAmount.mul(_feeRebatePercent).div(10**20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n // Check the dedicated SOV that is used to pay trading rebate rewards\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"deposit(address,uint256,uint256)\",\n user,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n )\n );\n\n if (success) {\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\n\n emit EarnReward(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n } else {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n }\n}\n" + }, + "contracts/mixins/InterestUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"./FeesHelper.sol\";\n\n/**\n * @title The Interest User contract.\n *\n * This contract pays loan interests.\n * */\ncontract InterestUser is VaultController, FeesHelper {\n using SafeERC20 for IERC20;\n\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n /**\n * @notice Internal function to pay interest of a loan.\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * */\n function _payInterest(address lender, address interestToken) internal {\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\n\n uint256 interestOwedNow = 0;\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\n interestOwedNow = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(1 days);\n\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n\n if (interestOwedNow > lenderInterestLocal.owedTotal)\n interestOwedNow = lenderInterestLocal.owedTotal;\n\n if (interestOwedNow != 0) {\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\n\n _payInterestTransfer(lender, interestToken, interestOwedNow);\n }\n } else {\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n }\n }\n\n /**\n * @notice Internal function to transfer tokens for the interest of a loan.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * @param interestOwedNow The amount of interest to pay.\n * */\n function _payInterestTransfer(\n address lender,\n address interestToken,\n uint256 interestOwedNow\n ) internal {\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\n /// TODO: refactor: data incapsulation violation and DRY design principles\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\n\n _payLendingFee(lender, interestToken, lendingFee);\n\n /// Transfers the interest to the lender, less the interest fee.\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\n\n /// Event Log\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\n }\n}\n" + }, + "contracts/mixins/LiquidationHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\n/**\n * @title The Liquidation Helper contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract computes the liquidation amount.\n * */\ncontract LiquidationHelper is State {\n /**\n * @notice Compute how much needs to be liquidated in order to restore the\n * desired margin (maintenance + 5%).\n *\n * @param principal The total borrowed amount (in loan tokens).\n * @param collateral The collateral (in collateral tokens).\n * @param currentMargin The current margin.\n * @param maintenanceMargin The maintenance (minimum) margin.\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n *\n * @return maxLiquidatable The collateral you can get liquidating.\n * @return maxSeizable The loan you available for liquidation.\n * @return incentivePercent The discount on collateral.\n * */\n function _getLiquidationAmounts(\n uint256 principal,\n uint256 collateral,\n uint256 currentMargin,\n uint256 maintenanceMargin,\n uint256 collateralToLoanRate\n )\n internal\n view\n returns (\n uint256 maxLiquidatable,\n uint256 maxSeizable,\n uint256 incentivePercent\n )\n {\n incentivePercent = liquidationIncentivePercent;\n if (currentMargin > maintenanceMargin || collateralToLoanRate == 0) {\n return (maxLiquidatable, maxSeizable, incentivePercent);\n } else if (currentMargin <= incentivePercent) {\n return (principal, collateral, currentMargin);\n }\n\n /// 5 percentage points above maintenance.\n uint256 desiredMargin = maintenanceMargin.add(5 ether);\n\n /// maxLiquidatable = ((1 + desiredMargin)*principal - collateralToLoanRate*collateral) / (desiredMargin - 0.05)\n maxLiquidatable = desiredMargin.add(10**20).mul(principal).div(10**20);\n maxLiquidatable = maxLiquidatable.sub(collateral.mul(collateralToLoanRate).div(10**18));\n maxLiquidatable = maxLiquidatable.mul(10**20).div(desiredMargin.sub(incentivePercent));\n if (maxLiquidatable > principal) {\n maxLiquidatable = principal;\n }\n\n /// maxSeizable = maxLiquidatable * (1 + incentivePercent) / collateralToLoanRate\n maxSeizable = maxLiquidatable.mul(incentivePercent.add(10**20));\n maxSeizable = maxSeizable.div(collateralToLoanRate).div(100);\n if (maxSeizable > collateral) {\n maxSeizable = collateral;\n }\n\n return (maxLiquidatable, maxSeizable, incentivePercent);\n }\n}\n" + }, + "contracts/mixins/ModuleCommonFunctionalities.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\ncontract ModuleCommonFunctionalities is State {\n modifier whenNotPaused() {\n require(!pause, \"Paused\");\n _;\n }\n}\n" + }, + "contracts/mixins/ProtocolTokenUser.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\n\n/**\n * @title The Protocol Token User contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to withdraw protocol tokens.\n * */\ncontract ProtocolTokenUser is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Internal function to withdraw an amount of protocol tokens from this contract.\n *\n * @param receiver The address of the recipient.\n * @param amount The amount of tokens to withdraw.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function _withdrawProtocolToken(address receiver, uint256 amount)\n internal\n returns (address, bool)\n {\n uint256 withdrawAmount = amount;\n\n uint256 tokenBalance = protocolTokenHeld;\n if (withdrawAmount > tokenBalance) {\n withdrawAmount = tokenBalance;\n }\n if (withdrawAmount == 0) {\n return (protocolTokenAddress, false);\n }\n\n protocolTokenHeld = tokenBalance.sub(withdrawAmount);\n\n IERC20(protocolTokenAddress).safeTransfer(receiver, withdrawAmount);\n\n return (protocolTokenAddress, true);\n }\n}\n" + }, + "contracts/mixins/RewardHelper.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title The Reward Helper contract.\n * @notice This contract calculates the reward for rollover transactions.\n *\n * A rollover is a renewal of a deposit. Instead of liquidating a deposit\n * on maturity, you can roll it over into a new deposit. The outstanding\n * principal of the old deposit is rolled over with or without the interest\n * outstanding on it.\n * */\ncontract RewardHelper is State {\n using SafeMath for uint256;\n\n /**\n * @notice Calculate the reward of a rollover transaction.\n *\n * @param collateralToken The address of the collateral token.\n * @param loanToken The address of the loan token.\n * @param positionSize The amount of value of the position.\n *\n * @return The base fee + the flex fee.\n */\n function _getRolloverReward(\n address collateralToken,\n address loanToken,\n uint256 positionSize\n ) internal view returns (uint256 reward) {\n uint256 positionSizeInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(loanToken, collateralToken, positionSize);\n uint256 rolloverBaseRewardInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(\n address(wrbtcToken),\n collateralToken,\n rolloverBaseReward\n );\n\n return\n rolloverBaseRewardInCollateralToken\n .mul(2) /// baseFee\n .add(positionSizeInCollateralToken.mul(rolloverFlexFeePercent).div(10**20)); /// flexFee = 0.1% of position size\n }\n}\n" + }, + "contracts/mixins/VaultController.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\n\n/**\n * @title The Vault Controller contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to deposit and withdraw wrBTC and\n * other tokens from the vault.\n * */\ncontract VaultController is State {\n using SafeERC20 for IERC20;\n\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\n\n /**\n * @notice Deposit wrBTC into the vault.\n *\n * @param from The address of the account paying the deposit.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherDeposit(address from, uint256 value) internal {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n _wrbtcToken.deposit.value(value)();\n\n emit VaultDeposit(address(_wrbtcToken), from, value);\n }\n\n /**\n * @notice Withdraw wrBTC from the vault.\n *\n * @param to The address of the recipient.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherWithdraw(address to, uint256 value) internal {\n if (value != 0) {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n uint256 balance = address(this).balance;\n if (value > balance) {\n _wrbtcToken.withdraw(value - balance);\n }\n Address.sendValue(to, value);\n\n emit VaultWithdraw(address(_wrbtcToken), to, value);\n }\n }\n\n /**\n * @notice Deposit tokens into the vault.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying the deposit.\n * @param value The amount of tokens to transfer.\n */\n function vaultDeposit(\n address token,\n address from,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransferFrom(from, address(this), value);\n\n emit VaultDeposit(token, from, value);\n }\n }\n\n /**\n * @notice Withdraw tokens from the vault.\n *\n * @param token The address of the token instance.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultWithdraw(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransfer(to, value);\n\n emit VaultWithdraw(token, to, value);\n }\n }\n\n /**\n * @notice Transfer tokens from an account into another one.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultTransfer(\n address token,\n address from,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n if (from == address(this)) {\n IERC20(token).safeTransfer(to, value);\n } else {\n IERC20(token).safeTransferFrom(from, to, value);\n }\n }\n }\n\n /**\n * @notice Approve an allowance of tokens to be spent by an account.\n *\n * @param token The address of the token instance.\n * @param to The address of the spender.\n * @param value The amount of tokens to allow.\n */\n function vaultApprove(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\n IERC20(token).safeApprove(to, 0);\n }\n IERC20(token).safeApprove(to, value);\n }\n}\n" + }, + "contracts/mockup/BlockMockUp.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title Used to get and set mock block number.\n */\ncontract BlockMockUp {\n uint256 public blockNum;\n\n /**\n * @notice To get the `blockNum`.\n * @return _blockNum The block number.\n */\n function getBlockNum() public view returns (uint256 _blockNum) {\n return blockNum;\n }\n\n /**\n * @notice To set the `blockNum`.\n * @param _blockNum The block number.\n */\n function setBlockNum(uint256 _blockNum) public {\n blockNum = _blockNum;\n }\n}\n" + }, + "contracts/mockup/FeeSharingCollectorMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/FeeSharingCollector/FeeSharingCollector.sol\";\n\ncontract FeeSharingCollectorMockup is FeeSharingCollector {\n struct TestData {\n address loanPoolToken;\n uint32 maxCheckpoints;\n address receiver;\n }\n\n TestData public testData;\n\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n testData = TestData(_token, _maxCheckpoints, _receiver);\n }\n\n function trueWithdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function addCheckPoint(address loanPoolToken, uint256 poolTokenAmount) public {\n uint96 amount96 =\n safe96(\n poolTokenAmount,\n \"FeeSharingCollectorProxy::withdrawFees: pool token amount exceeds 96 bits\"\n );\n _addCheckpoint(loanPoolToken, amount96);\n }\n\n function setTotalTokenCheckpoints(address _token, uint256 qty) public {\n totalTokenCheckpoints[_token] = qty;\n }\n\n function setUserProcessedCheckpoints(\n address _user,\n address _token,\n uint256 num\n ) public {\n processedCheckpoints[_user][_token] = num;\n }\n\n function getFullAccumulatedFees(\n address _user,\n address _token,\n uint32 _maxCheckpoints\n ) public view returns (uint256 amount, uint256 end) {\n (amount, end) = _getAccumulatedFees(_user, _token, 0, _maxCheckpoints);\n }\n\n function endOfRangeWithZeroMaxCheckpoint(address _token) public view returns (uint256) {\n return _getEndOfRange(0, _token, 0);\n }\n\n function getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) public view returns (uint256 _tokenAmount, uint256 _endToken) {\n return _getRBTCBalance(_token, _user, _maxCheckpoints);\n }\n\n function testWithdrawReentrancy(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n}\n" + }, + "contracts/mockup/GovernorAlphaMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/GovernorAlpha.sol\";\n\ncontract GovernorAlphaMockup is GovernorAlpha {\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 quorumVotes_,\n uint96 _minPercentageVotes\n ) public GovernorAlpha(timelock_, staking_, guardian_, quorumVotes_, _minPercentageVotes) {}\n\n function votingPeriod() public pure returns (uint256) {\n return 10;\n }\n\n function queueProposals(uint256[] calldata proposalIds) external {\n for (uint256 i = 0; i < proposalIds.length; i++) {\n queue(proposalIds[i]);\n }\n }\n}\n" + }, + "contracts/mockup/LiquidityMiningMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract LiquidityMiningMockup is LiquidityMining {\n function getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n public\n view\n returns (uint256)\n {\n return _getPassedBlocksWithBonusMultiplier(_from, _to);\n }\n\n function getPoolAccumulatedReward(address _poolToken) public view returns (uint256, uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n return _getPoolAccumulatedReward(pool);\n }\n}\n" + }, + "contracts/mockup/LiquidityPoolV1ConverterMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/IERC20.sol\";\n\ncontract LiquidityPoolV1ConverterMockup {\n IERC20[] public reserveTokens;\n IERC20 wrbtcToken;\n uint256 totalFeeMockupValue;\n address feesController;\n\n constructor(IERC20 _token0, IERC20 _token1) public {\n reserveTokens.push(_token0);\n reserveTokens.push(_token1);\n }\n\n function setFeesController(address _feesController) public {\n feesController = _feesController;\n }\n\n function setWrbtcToken(IERC20 _wrbtcToken) public {\n wrbtcToken = _wrbtcToken;\n }\n\n function setTotalFeeMockupValue(uint256 _totalFeeMockupValue) public {\n totalFeeMockupValue = _totalFeeMockupValue;\n }\n\n function withdrawFees(address _receiver) external returns (uint256) {\n require(msg.sender == feesController, \"unauthorized\");\n\n // transfer wrbtc\n wrbtcToken.transfer(_receiver, totalFeeMockupValue);\n return totalFeeMockupValue;\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/LoanClosingsWith.sol\";\n\ncontract LoanClosingsWithMockup is LoanClosingsWith {\n function worthTheTransfer(address, uint256) internal returns (bool) {\n return true;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithoutInvariantCheck.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanClosingsWithMockup.sol\";\n\ncontract LoanClosingsWithoutInvariantCheck is LoanClosingsWithMockup {\n /** Override the modifier of invariant check so that we can test the shared reentrancy guard */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n _;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicLMMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\n\ncontract LoanTokenLogicLMMockup is LoanTokenLogicLM {\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n returns (uint256 loanAmountPaid)\n {\n _callOptionalReturn(\n 0x2c34D66a5ca8686330e100372Eb3FDFB5aEECD0B, //Random EOA for testing\n abi.encodeWithSelector(IERC20(receiver).transfer.selector, receiver, burnAmount),\n \"error\"\n );\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicV2Mockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicV1Mockup is LoanTokenLogicStandard {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](27);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n // res[31] = this.totalSupply.selector;\n res[25] = this.balanceOf.selector;\n res[26] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n\ncontract LoanTokenLogicV2Mockup is LoanTokenLogicStandard {\n function testNewFunction() external pure returns (bool) {\n return true;\n }\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](29);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mockup\n res[28] = this.testNewFunction.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/mockup/lockedSOVFailedMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An interface for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete interface of the Locked SOV Contract.\n */\ncontract LockedSOVFailedMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The user balances.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n revert(\"For testing purposes\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/LockedSOVMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An mockup for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete mockup of the Locked SOV Contract.\n */\ncontract LockedSOVMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n event TokensStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // 10000 is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < 10000, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(10000);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n function _createVestingAndStake(address _sender) private {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n emit TokensStaked(_sender, address(0), amount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/MockAffiliates.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/Affiliates.sol\";\n\ncontract MockAffiliates is Affiliates {\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n }\n}\n" + }, + "contracts/mockup/MockFourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/Vesting/fouryear/FourYearVestingLogic.sol\";\n\ncontract MockFourYearVestingLogic is FourYearVestingLogic {\n /**\n * @notice gets duration left\n */\n function getDurationLeft() external view returns (uint256) {\n return durationLeft;\n }\n}\n" + }, + "contracts/mockup/MockLoanTokenLogic.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogic is LoanTokenLogic {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](31);\n\n // Loan Token Logic\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mock\n res[28] = this.setAffiliatesReferrer.selector;\n res[29] = this.setUserNotFirstTradeFlag.selector;\n res[30] = this.getMarginBorrowAmountAndRate.selector;\n\n return (res, stringToBytes32(\"MockLoanTokenLogic\"));\n }\n\n function setAffiliatesReferrer(address user, address referrer) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(user, referrer);\n }\n\n function setUserNotFirstTradeFlag(address user) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(user);\n }\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n\n /*function initialize(address target) external onlyOwner {\n\t\t_setTarget(this.setAffiliatesUserReferrer.selector, target);\n\t}*/\n}\n\ncontract ILoanTokenModulesMock is ILoanTokenModules {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user) external;\n}\n" + }, + "contracts/mockup/MockLoanTokenLogicLM.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogicLM is LoanTokenLogicLM {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n /** LoanTokenLogicLM function signature */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\"));\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\"));\n res[2] = bytes4(keccak256(\"burn(address,uint256)\"));\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\"));\n\n return (res, stringToBytes32(\"MockLoanTokenLogicLM\"));\n }\n}\n" + }, + "contracts/mockup/modules/IWeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract IWeightedStakingModuleMockup {\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) external;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) external;\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external;\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) external;\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/mockup/modules/StakingModuleBlockMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/StakingGovernanceModule.sol\";\nimport \"../../governance/Staking/modules/StakingStakeModule.sol\";\nimport \"../../governance/Staking/modules/StakingVestingModule.sol\";\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../BlockMockUp.sol\";\n\ncontract StakingModuleBlockMockup is\n IFunctionsList,\n StakingGovernanceModule,\n StakingStakeModule,\n StakingVestingModule,\n WeightedStakingModule\n{\n uint96 public priorWeightedStake;\n mapping(uint256 => uint96) public priorWeightedStakeAtBlock;\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n function balanceOf_MultipliedByTwo(address account) external view returns (uint256) {\n return this.balanceOf(account) * 2;\n }\n\n uint96 priorTotalVotingPower;\n\n function MOCK_priorTotalVotingPower(uint96 _priorTotalVotingPower) public {\n priorTotalVotingPower = _priorTotalVotingPower;\n }\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n return\n priorTotalVotingPower != 0\n ? priorTotalVotingPower\n : super.getPriorTotalVotingPower(blockNumber, time);\n }\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) public view returns (bool) {\n bytes32 codeHash = _getCodeHash(stakerAddress);\n return vestingCodeHashes[codeHash];\n }\n\n function getPriorWeightedStakeAtBlock(uint256 blockNum) public view returns (uint256) {\n return uint256(priorWeightedStakeAtBlock[blockNum]);\n }\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n // StakingGovernanceModule\n bytes4[] memory functionsList = new bytes4[](31);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n\n // StakingStakeModule\n functionsList[6] = this.stake.selector;\n functionsList[7] = this.stakeWithApproval.selector;\n functionsList[8] = this.extendStakingDuration.selector;\n functionsList[9] = this.stakesBySchedule.selector;\n functionsList[10] = this.stakeBySchedule.selector;\n functionsList[11] = this.balanceOf.selector;\n functionsList[12] = this.getCurrentStakedUntil.selector;\n functionsList[13] = this.getStakes.selector;\n functionsList[14] = this.timestampToLockDate.selector;\n\n //StakingVestingModule\n functionsList[15] = this.setVestingRegistry.selector;\n functionsList[16] = this.setVestingStakes.selector;\n functionsList[17] = this.getPriorUserStakeByDate.selector;\n functionsList[18] = this.getPriorVestingWeightedStake.selector;\n functionsList[19] = this.getPriorVestingStakeByDate.selector;\n functionsList[20] = this.addContractCodeHash.selector;\n functionsList[21] = this.removeContractCodeHash.selector;\n functionsList[22] = this.isVestingContract.selector;\n\n //BlockMockup\n functionsList[23] = this.setBlockMockUpAddr.selector;\n functionsList[24] = this.MOCK_priorWeightedStake.selector;\n functionsList[25] = this.MOCK_priorWeightedStakeAtBlock.selector;\n\n //WeightedStakingModule\n functionsList[26] = this.getPriorWeightedStake.selector;\n functionsList[27] = this.weightedStakeByDate.selector;\n functionsList[28] = this.computeWeightByDate.selector;\n functionsList[29] = this.priorWeightedStakeAtBlock.selector;\n functionsList[30] = this.getPriorWeightedStakeAtBlock.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/modules/StakingSharedModuleMock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/shared/StakingShared.sol\";\nimport \"../BlockMockUp.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\n\ncontract StakingModuleMock is IFunctionsList, StakingShared {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](1);\n functionList[0] = this.setBlockMockUpAddr.selector;\n }\n}\n" + }, + "contracts/mockup/modules/StakingWrapperMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\ncontract StakingWrapperMockup {\n uint256 constant TWO_WEEKS = 1209600;\n\n IStaking staking;\n IERC20 token;\n\n constructor(IStaking _staking, IERC20 _token) public {\n staking = _staking;\n token = _token;\n }\n\n function stake2times(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stake(amount, until, stakeFor, delegatee);\n }\n\n function stakeAndExtend(uint96 amount, uint256 until) external {\n require(token.transferFrom(msg.sender, address(this), amount));\n token.approve(address(staking), amount);\n\n staking.stake(amount, until, address(this), address(this));\n staking.extendStakingDuration(until, until + TWO_WEEKS);\n }\n\n function stakeAndStakeBySchedule(\n uint96 amount,\n uint256 until,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n}\n" + }, + "contracts/mockup/modules/WeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract WeightedStakingModuleMockup is WeightedStakingModule {\n uint96 priorWeightedStake;\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n mapping(uint256 => uint96) priorWeightedStakeAtBlock;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n functionsList[3] = this.MOCK_priorWeightedStake.selector;\n functionsList[4] = this.MOCK_priorWeightedStakeAtBlock.selector;\n functionsList[5] = this.calculatePriorWeightedStake.selector;\n functionsList[6] = this.setDelegateStake.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n//@todo can I change this proxy to EIP-1822 proxy standard, please. https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\ncontract PreviousLoanToken is AdvancedTokenStorage {\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../connectors/loantoken/interfaces/ProtocolSettingsLike.sol\";\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n// It is a LoanToken implementation!\ncontract PreviousLoanTokenSettingsLowerAdmin is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress\n\n // ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n // ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n //@todo check for restrictions in this contract\n modifier onlyAdmin() {\n require(msg.sender == address(this) || msg.sender == owner(), \"unauthorized\");\n _;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function init(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans // isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n // These params should be percentages represented like so: 5% = 5000000000000000000\n // rateMultiplier + baseRate can't exceed 100%\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; // 80 ether\n kinkLevel = _kinkLevel; // 90 ether\n maxScaleRate = _maxScaleRate; // 100 ether\n }\n\n function toggleFunctionPause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyAdmin {\n // keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /**\n * sets the transaction limit per token address\n * @param addresses the token addresses\n * @param limits the limit denominated in the currency of the token address\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyOwner\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n}\n" + }, + "contracts/mockup/PriceFeedsMoCMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../feeds/testnet/PriceFeedsMoC.sol\";\n\n// This contract is only for test purposes\n// https://github.com/money-on-chain/Amphiraos-Oracle/blob/master/contracts/medianizer/medianizer.sol\ncontract PriceFeedsMoCMockup is Medianizer {\n uint256 public value;\n bool public has;\n\n function peek() external view returns (bytes32, bool) {\n return (bytes32(value), has);\n }\n\n function setValue(uint256 _value) public {\n value = _value;\n }\n\n function setHas(bool _has) public {\n has = _has;\n }\n}\n" + }, + "contracts/mockup/ProtocolSettingsMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/ProtocolSettings.sol\";\n\ncontract ProtocolSettingsMockup is ProtocolSettings {\n function setLendingFeeTokensHeld(address token, uint256 amout) public {\n lendingFeeTokensHeld[token] = amout;\n }\n\n function setTradingFeeTokensHeld(address token, uint256 amout) public {\n tradingFeeTokensHeld[token] = amout;\n }\n\n function setBorrowingFeeTokensHeld(address token, uint256 amout) public {\n borrowingFeeTokensHeld[token] = amout;\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n\n _setTarget(this.setLendingFeeTokensHeld.selector, target);\n _setTarget(this.setTradingFeeTokensHeld.selector, target);\n _setTarget(this.setBorrowingFeeTokensHeld.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n\n _setTarget(this.getDefaultPathConversion.selector, target);\n }\n}\n" + }, + "contracts/mockup/proxy/ImplementationMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\n\ncontract ImplementationMockup is StorageMockup {\n function setValue(uint256 _value) public {\n value = _value;\n emit ValueChanged(_value);\n }\n\n function getValue() public view returns (uint256) {\n return value;\n }\n}\n" + }, + "contracts/mockup/proxy/ProxyMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract ProxyMockup is StorageMockup, UpgradableProxy {}\n" + }, + "contracts/mockup/proxy/StorageMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\ncontract StorageMockup {\n uint256 value;\n\n event ValueChanged(uint256 value);\n}\n" + }, + "contracts/mockup/RBTCWrapperProxyMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract RBTCWrapperProxyMockup {\n LiquidityMining public liquidityMining;\n\n constructor(LiquidityMining _liquidityMining) public {\n liquidityMining = _liquidityMining;\n }\n\n function claimReward(address _poolToken) public {\n liquidityMining.claimReward(_poolToken, msg.sender);\n }\n\n function claimRewardFromAllPools() public {\n liquidityMining.claimRewardFromAllPools(msg.sender);\n }\n\n function withdraw(address _poolToken, uint256 _amount) public {\n liquidityMining.withdraw(_poolToken, _amount, msg.sender);\n }\n}\n" + }, + "contracts/mockup/StakingRewardsMockUp.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/StakingRewards/StakingRewards.sol\";\nimport \"./BlockMockUp.sol\";\n\n/**\n * @title Staking Rewards Contract MockUp\n * @notice This is used for Testing\n * */\ncontract StakingRewardsMockUp is StakingRewards {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n using SafeMath for uint256;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n}\n" + }, + "contracts/mockup/TimelockHarness.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"../governance/Timelock.sol\";\n\ninterface Administered {\n function _acceptAdmin() external returns (uint256);\n}\n\ncontract TimelockHarness is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, delay_) {}\n\n function setDelayWithoutChecking(uint256 delay_) public {\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function harnessSetPendingAdmin(address pendingAdmin_) public {\n pendingAdmin = pendingAdmin_;\n }\n\n function harnessSetAdmin(address admin_) public {\n admin = admin_;\n }\n}\n\ncontract TimelockTest is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, 2 days) {\n delay = delay_;\n }\n\n function harnessSetAdmin(address admin_) public {\n require(msg.sender == admin);\n admin = admin_;\n }\n\n function harnessAcceptAdmin(Administered administered) public {\n administered._acceptAdmin();\n }\n}\n" + }, + "contracts/mockup/VestingLogicMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/Vesting/VestingLogic.sol\";\n\ncontract VestingLogicMockup is VestingLogic {\n /**\n * @dev we had a bug in a loop: \"i < endDate\" instead of \"i <= endDate\"\n */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n}\n" + }, + "contracts/mockup/VestingRegistryLogicMockUp.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\nimport \"../governance/Vesting/VestingRegistryLogic.sol\";\n\ncontract VestingRegistryLogicMockup is VestingRegistryLogic {\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return true;\n }\n\n function setTeamVesting(address _vesting, uint256 _vestingCreationType) external {\n vestingCreationAndTypes[_vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(VestingType.TeamVesting),\n vestingCreationType: uint128(_vestingCreationType)\n });\n }\n}\n" + }, + "contracts/modules/Affiliates.sol": { + "content": "/**\n * Copyright 2017-2020, Sovryn, All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Affiliates contract.\n * @notice Track referrals and reward referrers (affiliates) with tokens.\n * In-detail specifications are found at https://wiki.sovryn.app/en/community/Affiliates\n * @dev Module: Affiliates upgradable\n * Storage: from State, functions called from Protocol by delegatecall\n */\ncontract Affiliates is State, AffiliatesEvents, ModuleCommonFunctionalities {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Void constructor.\n */\n // solhint-disable-next-line no-empty-blocks\n constructor() public {}\n\n /**\n * @notice Avoid calls to this contract except for those explicitly declared.\n */\n function() external {\n revert(\"Affiliates - fallback not allowed\");\n }\n\n /**\n * @notice Set delegate callable functions by proxy contract.\n * @dev This contract is designed as a module, this way logic can be\n * expanded and upgraded w/o losing storage that is kept in the protocol (State.sol)\n * initialize() is used to register in the proxy external (module) functions\n * to be called via the proxy.\n * @param target The address of a new logic implementation.\n */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setAffiliatesReferrer.selector];\n _setTarget(this.setAffiliatesReferrer.selector, target);\n _setTarget(this.getUserNotFirstTradeFlag.selector, target);\n _setTarget(this.getReferralsList.selector, target);\n _setTarget(this.setUserNotFirstTradeFlag.selector, target);\n _setTarget(this.payTradingFeeToAffiliatesReferrer.selector, target);\n _setTarget(this.getAffiliatesReferrerBalances.selector, target);\n _setTarget(this.getAffiliatesReferrerTokenBalance.selector, target);\n _setTarget(this.getAffiliatesReferrerTokensList.selector, target);\n _setTarget(this.withdrawAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.withdrawAllAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.getMinReferralsToPayout.selector, target);\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n _setTarget(this.getAffiliateRewardsHeld.selector, target);\n _setTarget(this.getAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.getAffiliatesTokenRewardsValueInRbtc.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"Affiliates\");\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from loan pools.\n */\n modifier onlyCallableByLoanPools() {\n require(loanPoolToUnderlying[msg.sender] != address(0), \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from within protocol functions.\n */\n modifier onlyCallableInternal() {\n require(msg.sender == protocolAddress, \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Data structure comprised of 3 flags to compute the result of setting a referrer.\n */\n struct SetAffiliatesReferrerResult {\n bool success;\n bool alreadySet;\n bool userNotFirstTradeFlag;\n }\n\n /**\n * @notice Loan pool calls this function to tell affiliates\n * a user coming from a referrer is trading and should be registered if not yet.\n * Taking into account some user status flags may lead to the user and referrer\n * become added or not to the affiliates record.\n *\n * @param user The address of the user that is trading on loan pools.\n * @param referrer The address of the referrer the user is coming from.\n */\n function setAffiliatesReferrer(address user, address referrer)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n SetAffiliatesReferrerResult memory result;\n\n result.userNotFirstTradeFlag = getUserNotFirstTradeFlag(user);\n result.alreadySet = affiliatesUserReferrer[user] != address(0);\n result.success = !(result.userNotFirstTradeFlag || result.alreadySet || user == referrer);\n if (result.success) {\n affiliatesUserReferrer[user] = referrer;\n referralsList[referrer].add(user);\n emit SetAffiliatesReferrer(user, referrer);\n } else {\n emit SetAffiliatesReferrerFail(\n user,\n referrer,\n result.alreadySet,\n result.userNotFirstTradeFlag\n );\n }\n }\n\n /**\n * @notice Getter to query the referrals coming from a referrer.\n * @param referrer The address of a given referrer.\n * @return The referralsList mapping value by referrer.\n */\n function getReferralsList(address referrer) external view returns (address[] memory refList) {\n refList = referralsList[referrer].enumerate();\n return refList;\n }\n\n /**\n * @notice Getter to query the not-first-trade flag of a user.\n * @param user The address of a given user.\n * @return The userNotFirstTradeFlag mapping value by user.\n */\n function getUserNotFirstTradeFlag(address user) public view returns (bool) {\n return userNotFirstTradeFlag[user];\n }\n\n /**\n * @notice Setter to toggle on the not-first-trade flag of a user.\n * @param user The address of a given user.\n */\n function setUserNotFirstTradeFlag(address user)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n if (!userNotFirstTradeFlag[user]) {\n userNotFirstTradeFlag[user] = true;\n emit SetUserNotFirstTradeFlag(user);\n }\n }\n\n /**\n * @notice Internal getter to query the fee share for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function _getAffiliatesTradingFeePercentForSOV() internal view returns (uint256) {\n return affiliateFeePercent;\n }\n\n /**\n * @notice Internal to calculate the affiliates trading token fee amount.\n * Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * This _getReferrerTradingFeeForToken calculates the first one\n * by applying a custom percentage multiplier.\n * @param feeTokenAmount The trading token fee amount.\n * @return The affiliates share of the trading token fee amount.\n */\n function _getReferrerTradingFeeForToken(uint256 feeTokenAmount)\n internal\n view\n returns (uint256)\n {\n return feeTokenAmount.mul(getAffiliateTradingTokenFeePercent()).div(10**20);\n }\n\n /**\n * @notice Getter to query the fee share of trading token fee for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function getAffiliateTradingTokenFeePercent() public view returns (uint256) {\n return affiliateTradingTokenFeePercent;\n }\n\n /**\n * @notice Getter to query referral threshold for paying out to the referrer.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The minimum number of referrals set by Protocol.\n */\n function getMinReferralsToPayout() public view returns (uint256) {\n return minReferralsToPayout;\n }\n\n /**\n * @notice Get the sovToken reward of a trade.\n * @dev The reward is worth x% of the trading fee.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * @return The reward amount.\n * */\n function _getSovBonusAmount(address feeToken, uint256 feeAmount)\n internal\n view\n returns (uint256)\n {\n uint256 rewardAmount;\n address _priceFeeds = priceFeeds;\n\n /// @dev Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// dest token = SOV\n feeAmount.mul(_getAffiliatesTradingFeePercentForSOV()).div(1e20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n return rewardAmount;\n }\n\n /**\n * @notice Protocol calls this function to pay the affiliates rewards to a user (referrer).\n *\n * @dev Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * Both are paid in this function.\n *\n * @dev Actually they are not paid, but just holded by protocol until user claims them by\n * actively calling withdrawAffiliatesReferrerTokenFees() function,\n * and/or when unvesting lockedSOV.\n *\n * @dev To be precise, what this function does is updating the registers of the rewards\n * for the referrer including the assignment of the SOV tokens as rewards to the\n * referrer's vesting contract.\n *\n * @param referrer The address of the referrer.\n * @param trader The address of the trader.\n * @param token The address of the token in which the trading/borrowing fee was paid.\n * @param tradingFeeTokenBaseAmount Total trading fee amount, the base for calculating referrer's fees.\n *\n * @return referrerBonusSovAmount The amount of SOV tokens paid to the referrer (through a vesting contract, lockedSOV).\n * @return referrerBonusTokenAmount The amount of trading tokens paid directly to the referrer.\n */\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n )\n external\n onlyCallableInternal\n whenNotPaused\n returns (uint256 referrerBonusSovAmount, uint256 referrerBonusTokenAmount)\n {\n bool isHeld = referralsList[referrer].length() < getMinReferralsToPayout();\n bool bonusPaymentIsSuccess = true;\n uint256 paidReferrerBonusSovAmount;\n\n /// Process token fee rewards first.\n referrerBonusTokenAmount = _getReferrerTradingFeeForToken(tradingFeeTokenBaseAmount);\n if (!affiliatesReferrerTokensList[referrer].contains(token))\n affiliatesReferrerTokensList[referrer].add(token);\n affiliatesReferrerBalances[referrer][token] = affiliatesReferrerBalances[referrer][token]\n .add(referrerBonusTokenAmount);\n\n /// Then process SOV rewards.\n referrerBonusSovAmount = _getSovBonusAmount(token, tradingFeeTokenBaseAmount);\n uint256 rewardsHeldByProtocol = affiliateRewardsHeld[referrer];\n\n if (isHeld) {\n /// If referrals less than minimum, temp the rewards SOV to the storage\n affiliateRewardsHeld[referrer] = rewardsHeldByProtocol.add(referrerBonusSovAmount);\n } else {\n /// If referrals >= minimum, directly send all of the remain rewards to locked sov\n /// Call depositSOV() in LockedSov contract\n /// Set the affiliaterewardsheld = 0\n if (affiliateRewardsHeld[referrer] > 0) {\n affiliateRewardsHeld[referrer] = 0;\n }\n\n paidReferrerBonusSovAmount = referrerBonusSovAmount.add(rewardsHeldByProtocol);\n IERC20(sovTokenAddress).approve(lockedSOVAddress, paidReferrerBonusSovAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"depositSOV(address,uint256)\",\n referrer,\n paidReferrerBonusSovAmount\n )\n );\n\n if (!success) {\n bonusPaymentIsSuccess = false;\n }\n }\n\n if (bonusPaymentIsSuccess) {\n emit PayTradingFeeToAffiliate(\n referrer,\n trader, // trader\n token,\n isHeld,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n } else {\n emit PayTradingFeeToAffiliateFail(\n referrer,\n trader, // trader\n token,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n }\n\n return (referrerBonusSovAmount, referrerBonusTokenAmount);\n }\n\n /**\n * @notice Referrer calls this function to receive its reward in a given token.\n * It will send the other (non-SOV) reward tokens from trading protocol fees,\n * to the referrer’s wallet.\n * @dev Rewards are held by protocol in different tokens coming from trading fees.\n * Referrer has to claim them one by one for every token with accumulated balance.\n * @param token The address of the token to withdraw.\n * @param receiver The address of the withdrawal beneficiary.\n * @param amount The amount of tokens to claim. If greater than balance, just sends balance.\n */\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) public whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n uint256 referrerTokenBalance = affiliatesReferrerBalances[referrer][token];\n uint256 withdrawAmount = referrerTokenBalance > amount ? amount : referrerTokenBalance;\n\n require(withdrawAmount > 0, \"Affiliates: cannot withdraw zero amount\");\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n uint256 newReferrerTokenBalance = referrerTokenBalance.sub(withdrawAmount);\n\n if (newReferrerTokenBalance == 0) {\n _removeAffiliatesReferrerToken(referrer, token);\n } else {\n affiliatesReferrerBalances[referrer][token] = newReferrerTokenBalance;\n }\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawAffiliatesReferrerTokenFees(referrer, receiver, token, withdrawAmount);\n }\n\n /**\n * @notice Withdraw to msg.sender all token fees for a referrer.\n * @dev It's done by looping through its available tokens.\n * @param receiver The address of the withdrawal beneficiary.\n */\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n (address[] memory tokenAddresses, uint256[] memory tokenBalances) =\n getAffiliatesReferrerBalances(referrer);\n for (uint256 i; i < tokenAddresses.length; i++) {\n withdrawAffiliatesReferrerTokenFees(tokenAddresses[i], receiver, tokenBalances[i]);\n }\n }\n\n /**\n * @notice Internal function to delete a referrer's token balance.\n * @param referrer The address of the referrer.\n * @param token The address of the token specifying the balance to remove.\n */\n function _removeAffiliatesReferrerToken(address referrer, address token) internal {\n delete affiliatesReferrerBalances[referrer][token];\n affiliatesReferrerTokensList[referrer].remove(token);\n }\n\n /**\n * @notice Get all token balances of a referrer.\n * @param referrer The address of the referrer.\n * @return referrerTokensList The array of available tokens (keys).\n * @return referrerTokensBalances The array of token balances (values).\n */\n function getAffiliatesReferrerBalances(address referrer)\n public\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances)\n {\n referrerTokensList = getAffiliatesReferrerTokensList(referrer);\n referrerTokensBalances = new uint256[](referrerTokensList.length);\n for (uint256 i; i < referrerTokensList.length; i++) {\n referrerTokensBalances[i] = getAffiliatesReferrerTokenBalance(\n referrer,\n referrerTokensList[i]\n );\n }\n return (referrerTokensList, referrerTokensBalances);\n }\n\n /**\n * @dev Get all token rewards estimation value in rbtc.\n *\n * @param referrer Address of referrer.\n *\n * @return The value estimation in rbtc.\n */\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount)\n {\n address[] memory tokensList = getAffiliatesReferrerTokensList(referrer);\n address _priceFeeds = priceFeeds;\n\n for (uint256 i; i < tokensList.length; i++) {\n // Get the value of each token in rbtc\n\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n tokensList[i], // source token\n address(wrbtcToken), // dest token = SOV\n affiliatesReferrerBalances[referrer][tokensList[i]] // total token rewards\n )\n );\n\n assembly {\n if eq(success, 1) {\n rbtcTotalAmount := add(rbtcTotalAmount, mload(add(data, 32)))\n }\n }\n }\n }\n\n /**\n * @notice Get all available tokens at the affiliates program for a given referrer.\n * @param referrer The address of a given referrer.\n * @return tokensList The list of available tokens.\n */\n function getAffiliatesReferrerTokensList(address referrer)\n public\n view\n returns (address[] memory tokensList)\n {\n tokensList = affiliatesReferrerTokensList[referrer].enumerate();\n return tokensList;\n }\n\n /**\n * @notice Getter to query the affiliate balance for a given referrer and token.\n * @param referrer The address of the referrer.\n * @param token The address of the token to get balance for.\n * @return The affiliatesReferrerBalances mapping value by referrer and token keys.\n */\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n public\n view\n returns (uint256)\n {\n return affiliatesReferrerBalances[referrer][token];\n }\n\n /**\n * @notice Getter to query the address of referrer for a given user.\n * @param user The address of the user.\n * @return The address on affiliatesUserReferrer mapping value by user key.\n */\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user];\n }\n\n /**\n * @notice Getter to query the reward amount held for a given referrer.\n * @param referrer The address of the referrer.\n * @return The affiliateRewardsHeld mapping value by referrer key.\n */\n function getAffiliateRewardsHeld(address referrer) public view returns (uint256) {\n return affiliateRewardsHeld[referrer];\n }\n}\n" + }, + "contracts/modules/interfaces/ProtocolAffiliatesInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolAffiliatesInterface {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user_) external;\n\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\n\n function payTradingFeeToAffiliatesReferrer(\n address affiliate,\n address trader,\n address token,\n uint256 amount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n}\n" + }, + "contracts/modules/interfaces/ProtocolSwapExternalInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolSwapExternalInterface {\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n}\n" + }, + "contracts/modules/LoanClosingsLiquidation.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsLiquidation contract.\n * @notice Ways to close a loan: liquidation. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsLiquidation is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.liquidate.selector];\n _setTarget(this.liquidate.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsLiquidation\"\n );\n }\n\n /**\n * @notice Liquidate an unhealty loan.\n *\n * @dev Public wrapper for _liquidate internal function.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * loanId is the ID of the loan, which is created on loan opening.\n * It can be obtained either by parsing the Trade event or by reading\n * the open loans from the contract by calling getActiveLoans or getUserLoans.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n return _liquidate(loanId, receiver, closeAmount);\n }\n\n /**\n * @notice Internal function for liquidating an unhealthy loan.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function _liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin <= loanParamsLocal.maintenanceMargin, \"healthy position\");\n\n loanCloseAmount = closeAmount;\n\n //amounts to restore the desired margin (maintencance + 5%)\n (uint256 maxLiquidatable, uint256 maxSeizable, ) =\n _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n\n if (loanCloseAmount < maxLiquidatable) {\n //close maxLiquidatable if tiny position will remain\n uint256 remainingAmount = maxLiquidatable - loanCloseAmount;\n remainingAmount = _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingAmount <= TINY_AMOUNT) {\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable.mul(loanCloseAmount).div(maxLiquidatable);\n }\n } else if (loanCloseAmount > maxLiquidatable) {\n // adjust down the close amount to the max\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable;\n }\n\n require(loanCloseAmount != 0, \"nothing to liquidate\");\n\n // liquidator deposits the principal being closed\n _returnPrincipalWithDeposit(loanParamsLocal.loanToken, address(this), loanCloseAmount);\n\n // a portion of the principal is repaid to the lender out of interest refunded\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n loanLocal.borrower\n );\n\n if (loanCloseAmount > loanCloseAmountLessInterest) {\n // full interest refund goes to the borrower\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanCloseAmount - loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmountLessInterest != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n seizedToken = loanParamsLocal.collateralToken;\n\n if (seizedAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(seizedAmount);\n\n _withdrawAsset(seizedToken, receiver, seizedAmount);\n }\n\n _closeLoan(loanLocal, loanCloseAmount);\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n seizedAmount,\n collateralToLoanRate,\n 0,\n currentMargin,\n CloseTypes.Liquidation\n );\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsRollover.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsRollover contract.\n * @notice Ways to close a loan: rollover. Margin trade\n * positions are always closed with a swap.\n *\n * */\ncontract LoanClosingsRollover is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.rollover.selector];\n _setTarget(this.rollover.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsRollover\"\n );\n }\n\n /**\n * @notice Roll over a loan.\n *\n * @dev Public wrapper for _rollover internal function.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * The function rollover on the protocol contract extends the loan\n * duration by the maximum term (28 days for margin trades at the moment\n * of writing), pays the interest to the lender and refunds the caller\n * for the gas cost by sending 2 * the gas cost using the fast gas price\n * as base for the calculation.\n *\n * @param loanId The ID of the loan to roll over.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n * */\n function rollover(\n bytes32 loanId,\n bytes calldata // for future use /*loanDataBytes*/\n ) external nonReentrant globallyNonReentrant iTokenSupplyUnchanged(loanId) whenNotPaused {\n // restrict to EOAs to prevent griefing attacks, during interest rate recalculation\n require(msg.sender == tx.origin, \"EOAs call\");\n\n return\n _rollover(\n loanId,\n \"\" // loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for roll over a loan.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * @param loanId The ID of the loan to roll over.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n * */\n function _rollover(bytes32 loanId, bytes memory loanDataBytes) internal {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n require(block.timestamp > loanLocal.endTimestamp.sub(3600), \"healthy position\");\n require(loanPoolToUnderlying[loanLocal.lender] != address(0), \"invalid lender\");\n\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n // Handle back interest: calculates interest owned since the loan endtime passed but the loan remained open\n uint256 backInterestTime;\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestTime = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestTime.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(1 days);\n }\n\n //note: to avoid code duplication, it would be nicer to store loanParamsLocal.maxLoanTerm in a local variable\n //however, we've got stack too deep issues if we do so.\n if (loanParamsLocal.maxLoanTerm != 0) {\n // fixed-term loan, so need to query iToken for latest variable rate\n uint256 owedPerDay =\n loanLocal.principal.mul(ILoanPool(loanLocal.lender).borrowInterestRate()).div(\n 365 * 10**20\n );\n\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(\n loanInterestLocal.owedPerDay\n );\n\n loanInterestLocal.owedPerDay = owedPerDay;\n\n //if the loan has been open for longer than an additional period, add at least 1 additional day\n if (backInterestTime >= loanParamsLocal.maxLoanTerm) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n }\n //extend by the max loan term\n else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(loanParamsLocal.maxLoanTerm);\n }\n } else {\n // loanInterestLocal.owedPerDay doesn't change\n if (backInterestTime >= MONTH) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n } else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(MONTH);\n }\n }\n\n uint256 interestAmountRequired = loanLocal.endTimestamp.sub(block.timestamp);\n interestAmountRequired = interestAmountRequired.mul(loanInterestLocal.owedPerDay);\n interestAmountRequired = interestAmountRequired.div(1 days);\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n\n // add backInterestOwed\n interestAmountRequired = interestAmountRequired.add(backInterestOwed);\n\n // collect interest (needs to be converted from the collateral)\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n 0, //min swap 0 -> swap connector estimates the amount of source tokens to use\n interestAmountRequired, //required destination tokens\n true, // returnTokenIsCollateral\n loanDataBytes\n );\n\n //received more tokens than needed to pay the interest\n if (destTokenAmountReceived > interestAmountRequired) {\n // swap rest back to collateral, if the amount is big enough to cover gas cost\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n )\n ) {\n (destTokenAmountReceived, , ) = _swapBackExcess(\n loanLocal,\n loanParamsLocal,\n destTokenAmountReceived - interestAmountRequired, //amount to be swapped\n loanDataBytes\n );\n sourceTokenAmountUsed = sourceTokenAmountUsed.sub(destTokenAmountReceived);\n }\n //else give it to the protocol as a lending fee\n else {\n _payLendingFee(\n loanLocal.borrower,\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n );\n }\n }\n\n //subtract the interest from the collateral\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n if (backInterestOwed != 0) {\n // pay out backInterestOwed\n\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n uint256 rolloverReward =\n _getRolloverReward(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.principal\n );\n\n if (rolloverReward != 0) {\n // if the reward > collateral:\n if (rolloverReward > loanLocal.collateral) {\n // 1. pay back the remaining loan to the lender\n // 2. pay the remaining collateral to msg.sender\n // 3. close the position & emit close event\n _closeWithSwap(\n loanLocal.id,\n msg.sender,\n loanLocal.collateral,\n false,\n \"\" // loanDataBytes\n );\n } else {\n // pay out reward to caller\n loanLocal.collateral = loanLocal.collateral.sub(rolloverReward);\n\n _withdrawAsset(loanParamsLocal.collateralToken, msg.sender, rolloverReward);\n }\n }\n\n if (loanLocal.collateral > 0) {\n //close whole loan if tiny position will remain\n if (_getAmountInRbtc(loanParamsLocal.loanToken, loanLocal.principal) <= TINY_AMOUNT) {\n _closeWithSwap(\n loanLocal.id,\n loanLocal.borrower,\n loanLocal.collateral, // swap all collaterals\n false,\n \"\" /// loanDataBytes\n );\n } else {\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n require(\n currentMargin > 3 ether, // ensure there's more than 3% margin remaining\n \"unhealthy position\"\n );\n }\n }\n\n if (loanLocal.active) {\n emit Rollover(\n loanLocal.borrower, // user (borrower)\n loanLocal.lender, // lender\n loanLocal.id, // loanId\n loanLocal.principal, // principal\n loanLocal.collateral, // collateral\n loanLocal.endTimestamp, // endTimestamp\n msg.sender, // rewardReceiver\n rolloverReward // reward\n );\n }\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsShared.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/RewardHelper.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\n/**\n * @title LoanClosingsShared contract.\n * @notice This contract should only contains the internal function that is being used / utilized by\n * LoanClosingsLiquidation, LoanClosingsRollover & LoanClosingsWith contract\n *\n * */\ncontract LoanClosingsShared is\n LoanClosingsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n RewardHelper,\n ModuleCommonFunctionalities\n{\n uint256 internal constant MONTH = 365 days / 12;\n //0.00001 BTC, would be nicer in State.sol, but would require a redeploy of the complete protocol, so adding it here instead\n //because it's not shared state anyway and only used by this contract\n uint256 public constant paySwapExcessToBorrowerThreshold = 10000000000000;\n\n uint256 public constant TINY_AMOUNT = 25e13;\n\n enum CloseTypes { Deposit, Swap, Liquidation }\n\n /** modifier for invariant check */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n Loan storage loanLocal = loans[loanId];\n\n require(loanLocal.lender != address(0), \"Invalid loan token pool address\");\n\n uint256 previousITokenSupply = ILoanTokenModules(loanLocal.lender).totalSupply();\n\n _;\n\n /// Validate iToken total supply\n require(\n previousITokenSupply == ILoanTokenModules(loanLocal.lender).totalSupply(),\n \"loan token supply invariant check failure\"\n );\n }\n\n /**\n * @dev computes the interest which needs to be refunded to the borrower based on the amount he's closing and either\n * subtracts it from the amount which still needs to be paid back (in case outstanding amount > interest) or withdraws the\n * excess to the borrower (in case interest > outstanding).\n * @param loanLocal the loan\n * @param loanParamsLocal the loan params\n * @param loanCloseAmount the amount to be closed (base for the computation)\n * @param receiver the address of the receiver (usually the borrower)\n * */\n function _settleInterestToPrincipal(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 loanCloseAmount,\n address receiver\n ) internal returns (uint256) {\n uint256 loanCloseAmountLessInterest = loanCloseAmount;\n\n //compute the interest which neeeds to be refunded to the borrower (because full interest is paid on loan )\n uint256 interestRefundToBorrower =\n _settleInterest(loanParamsLocal, loanLocal, loanCloseAmountLessInterest);\n\n uint256 interestAppliedToPrincipal;\n //if the outstanding loan is bigger than the interest to be refunded, reduce the amount to be paid back / closed by the interest\n if (loanCloseAmountLessInterest >= interestRefundToBorrower) {\n // apply all of borrower interest refund torwards principal\n interestAppliedToPrincipal = interestRefundToBorrower;\n\n // principal needed is reduced by this amount\n loanCloseAmountLessInterest -= interestRefundToBorrower;\n\n // no interest refund remaining\n interestRefundToBorrower = 0;\n } else {\n //if the interest refund is bigger than the outstanding loan, the user needs to get back the interest\n // principal fully covered by excess interest\n interestAppliedToPrincipal = loanCloseAmountLessInterest;\n\n // amount refunded is reduced by this amount\n interestRefundToBorrower -= loanCloseAmountLessInterest;\n\n // principal fully covered by excess interest\n loanCloseAmountLessInterest = 0;\n\n if (interestRefundToBorrower != 0) {\n // refund overage\n _withdrawAsset(loanParamsLocal.loanToken, receiver, interestRefundToBorrower);\n }\n }\n\n //pay the interest to the lender\n //note: this is a waste of gas, because the loanCloseAmountLessInterest is withdrawn to the lender, too. It could be done at once.\n if (interestAppliedToPrincipal != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, interestAppliedToPrincipal);\n }\n\n return loanCloseAmountLessInterest;\n }\n\n // The receiver always gets back an ERC20 (even wrbtc)\n function _returnPrincipalWithDeposit(\n address loanToken,\n address receiver,\n uint256 principalNeeded\n ) internal {\n if (principalNeeded != 0) {\n if (msg.value == 0) {\n vaultTransfer(loanToken, msg.sender, receiver, principalNeeded);\n } else {\n require(loanToken == address(wrbtcToken), \"wrong asset sent\");\n require(msg.value >= principalNeeded, \"not enough ether\");\n wrbtcToken.deposit.value(principalNeeded)();\n if (receiver != address(this)) {\n vaultTransfer(loanToken, address(this), receiver, principalNeeded);\n }\n if (msg.value > principalNeeded) {\n // refund overage\n Address.sendValue(msg.sender, msg.value - principalNeeded);\n }\n }\n } else {\n require(msg.value == 0, \"wrong asset sent\");\n }\n }\n\n /**\n * @dev checks if the amount of the asset to be transfered is worth the transfer fee\n * @param asset the asset to be transfered\n * @param amount the amount to be transfered\n * @return True if the amount is bigger than the threshold\n * */\n function worthTheTransfer(address asset, uint256 amount) internal returns (bool) {\n uint256 amountInRbtc = _getAmountInRbtc(asset, amount);\n emit swapExcess(\n amountInRbtc > paySwapExcessToBorrowerThreshold,\n amount,\n amountInRbtc,\n paySwapExcessToBorrowerThreshold\n );\n\n return amountInRbtc > paySwapExcessToBorrowerThreshold;\n }\n\n /**\n * swaps collateral tokens for loan tokens\n * @param loanLocal the loan object\n * @param loanParamsLocal the loan parameters\n * @param swapAmount the amount to be swapped\n * @param principalNeeded the required destination token amount\n * @param returnTokenIsCollateral if true -> required destination token amount will be passed on, else not\n * note: quite dirty. should be refactored.\n * @param loanDataBytes additional loan data (not in use for token swaps)\n * */\n function _doCollateralSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n loanLocal.collateral, // maxSourceTokenAmount\n returnTokenIsCollateral\n ? principalNeeded // requiredDestTokenAmount\n : 0,\n false, // bypassFee\n loanDataBytes\n );\n require(destTokenAmountReceived >= principalNeeded, \"insufficient dest amount\");\n require(sourceTokenAmountUsed <= loanLocal.collateral, \"excessive source amount\");\n }\n\n /**\n * @notice Withdraw asset to receiver.\n *\n * @param assetToken The loan token.\n * @param receiver The address of the receiver.\n * @param assetAmount The loan token amount.\n * */\n function _withdrawAsset(\n address assetToken,\n address receiver,\n uint256 assetAmount\n ) internal {\n if (assetAmount != 0) {\n if (assetToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, assetAmount);\n } else {\n vaultWithdraw(assetToken, receiver, assetAmount);\n }\n }\n }\n\n /**\n * @notice Internal function to close a loan.\n *\n * @param loanLocal The loan object.\n * @param loanCloseAmount The amount to close: principal or lower.\n *\n * */\n function _closeLoan(Loan storage loanLocal, uint256 loanCloseAmount) internal {\n require(loanCloseAmount != 0, \"nothing to close\");\n\n if (loanCloseAmount == loanLocal.principal) {\n loanLocal.principal = 0;\n loanLocal.active = false;\n loanLocal.endTimestamp = block.timestamp;\n loanLocal.pendingTradesId = 0;\n activeLoansSet.removeBytes32(loanLocal.id);\n lenderLoanSets[loanLocal.lender].removeBytes32(loanLocal.id);\n borrowerLoanSets[loanLocal.borrower].removeBytes32(loanLocal.id);\n } else {\n loanLocal.principal = loanLocal.principal.sub(loanCloseAmount);\n }\n }\n\n function _settleInterest(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 closePrincipal\n ) internal returns (uint256) {\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 interestTime = block.timestamp;\n if (interestTime > loanLocal.endTimestamp) {\n interestTime = loanLocal.endTimestamp;\n }\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n interestTime\n );\n\n uint256 owedPerDayRefund;\n if (closePrincipal < loanLocal.principal) {\n owedPerDayRefund = loanInterestLocal.owedPerDay.mul(closePrincipal).div(\n loanLocal.principal\n );\n } else {\n owedPerDayRefund = loanInterestLocal.owedPerDay;\n }\n\n // update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.sub(owedPerDayRefund);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(owedPerDayRefund);\n\n // update borrower interest\n uint256 interestRefundToBorrower = loanLocal.endTimestamp.sub(interestTime);\n interestRefundToBorrower = interestRefundToBorrower.mul(owedPerDayRefund);\n interestRefundToBorrower = interestRefundToBorrower.div(1 days);\n\n if (closePrincipal < loanLocal.principal) {\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(\n interestRefundToBorrower\n );\n } else {\n loanInterestLocal.depositTotal = 0;\n }\n\n // update remaining lender interest values\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.sub(\n closePrincipal\n );\n\n uint256 owedTotal = lenderInterestLocal.owedTotal;\n lenderInterestLocal.owedTotal = owedTotal > interestRefundToBorrower\n ? owedTotal - interestRefundToBorrower\n : 0;\n\n return interestRefundToBorrower;\n }\n\n /**\n * @notice Check sender is borrower or delegatee and loan id exists.\n *\n * @param loanId byte32 of the loan id.\n * */\n function _checkAuthorized(bytes32 loanId) internal view {\n Loan storage loanLocal = loans[loanId];\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n }\n\n /**\n * @notice Internal function for closing a position by swapping the\n * collateral back to loan tokens, paying the lender and withdrawing\n * the remainder.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collatral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid\n * out in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(swapAmount != 0, \"swapAmount == 0\");\n\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't swap more than collateral.\n swapAmount = swapAmount > loanLocal.collateral ? loanLocal.collateral : swapAmount;\n\n //close whole loan if tiny position will remain\n if (loanLocal.collateral - swapAmount > 0) {\n if (\n _getAmountInRbtc(\n loanParamsLocal.collateralToken,\n loanLocal.collateral - swapAmount\n ) <= TINY_AMOUNT\n ) {\n swapAmount = loanLocal.collateral;\n }\n }\n\n uint256 loanCloseAmountLessInterest;\n if (swapAmount == loanLocal.collateral || returnTokenIsCollateral) {\n /// loanCloseAmountLessInterest will be passed as required amount amount of destination tokens.\n /// this means, the actual swapAmount passed to the swap contract does not matter at all.\n /// the source token amount will be computed depending on the required amount amount of destination tokens.\n loanCloseAmount = swapAmount == loanLocal.collateral\n ? loanLocal.principal\n : loanLocal.principal.mul(swapAmount).div(loanLocal.collateral);\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Computes the interest refund for the borrower and sends it to the lender to cover part of the principal.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n } else {\n /// loanCloseAmount is calculated after swap; for this case we want to swap the entire source amount\n /// and determine the loanCloseAmount and withdraw amount based on that.\n loanCloseAmountLessInterest = 0;\n }\n\n uint256 coveredPrincipal;\n uint256 usedCollateral;\n\n /// swapAmount repurposed for collateralToLoanSwapRate to avoid stack too deep error.\n (coveredPrincipal, usedCollateral, withdrawAmount, swapAmount) = _coverPrincipalWithSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount, /// The amount of source tokens to swap (only matters if !returnTokenIsCollateral or loanCloseAmountLessInterest = 0)\n loanCloseAmountLessInterest, /// This is the amount of destination tokens we want to receive (only matters if returnTokenIsCollateral)\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (loanCloseAmountLessInterest == 0) {\n /// Condition prior to swap: swapAmount != loanLocal.collateral && !returnTokenIsCollateral\n\n /// Amounts that is closed.\n loanCloseAmount = coveredPrincipal;\n if (coveredPrincipal != loanLocal.principal) {\n loanCloseAmount = loanCloseAmount.mul(usedCollateral).div(loanLocal.collateral);\n }\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Amount that is returned to the lender.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n\n /// Remaining amount withdrawn to the receiver.\n withdrawAmount = withdrawAmount.add(coveredPrincipal).sub(loanCloseAmountLessInterest);\n } else {\n /// Pay back the amount which was covered by the swap.\n loanCloseAmountLessInterest = coveredPrincipal;\n }\n\n require(loanCloseAmountLessInterest != 0, \"closeAmount is 0 after swap\");\n\n /// Reduce the collateral by the amount which was swapped for the closure.\n if (usedCollateral != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(usedCollateral);\n }\n\n /// Repays principal to lender.\n /// The lender always gets back an ERC20 (even wrbtc), so we call\n /// withdraw directly rather than use the _withdrawAsset helper function.\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, loanCloseAmountLessInterest);\n\n withdrawToken = returnTokenIsCollateral\n ? loanParamsLocal.collateralToken\n : loanParamsLocal.loanToken;\n\n if (withdrawAmount != 0) {\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n usedCollateral,\n swapAmount, /// collateralToLoanSwapRate\n CloseTypes.Swap\n );\n }\n\n /**\n * @notice Close a loan.\n *\n * @dev Wrapper for _closeLoan internal function.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan params.\n * @param loanCloseAmount The amount to close: principal or lower.\n * @param collateralCloseAmount The amount of collateral to close.\n * @param collateralToLoanSwapRate The price rate collateral/loan token.\n * @param closeType The type of loan close.\n * */\n function _finalizeClose(\n Loan storage loanLocal,\n LoanParams storage loanParamsLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanSwapRate,\n CloseTypes closeType\n ) internal {\n _closeLoan(loanLocal, loanCloseAmount);\n\n address _priceFeeds = priceFeeds;\n uint256 currentMargin;\n uint256 collateralToLoanRate;\n\n /// This is still called even with full loan close to return collateralToLoanRate\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).getCurrentMargin.selector,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n )\n );\n assembly {\n if eq(success, 1) {\n currentMargin := mload(add(data, 32))\n collateralToLoanRate := mload(add(data, 64))\n }\n }\n /// Note: We can safely skip the margin check if closing\n /// via closeWithDeposit or if closing the loan in full by any method.\n require(\n closeType == CloseTypes.Deposit ||\n loanLocal.principal == 0 || /// loan fully closed\n currentMargin > loanParamsLocal.maintenanceMargin,\n \"unhealthy position\"\n );\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n collateralCloseAmount,\n collateralToLoanRate,\n collateralToLoanSwapRate,\n currentMargin,\n closeType\n );\n }\n\n /**\n * swaps a share of a loan's collateral or the complete collateral in order to cover the principle.\n * @param loanLocal the loan\n * @param loanParamsLocal the loan parameters\n * @param swapAmount in case principalNeeded == 0 or !returnTokenIsCollateral, this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens needed for the swap is estimated by the connector.\n * @param principalNeeded the required amount of destination tokens in order to cover the principle (only used if returnTokenIsCollateral)\n * @param returnTokenIsCollateral tells if the user wants to withdraw his remaining collateral + profit in collateral tokens\n * @notice Swaps a share of a loan's collateral or the complete collateral\n * in order to cover the principle.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount In case principalNeeded == 0 or !returnTokenIsCollateral,\n * this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens\n * needed for the swap is estimated by the connector.\n * @param principalNeeded The required amount of destination tokens in order to\n * cover the principle (only used if returnTokenIsCollateral).\n * @param returnTokenIsCollateral Tells if the user wants to withdraw his\n * remaining collateral + profit in collateral tokens.\n *\n * @return coveredPrincipal The amount of principal that is covered.\n * @return usedCollateral The amount of collateral used.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _coverPrincipalWithSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 coveredPrincipal,\n uint256 usedCollateral,\n uint256 withdrawAmount,\n uint256 collateralToLoanSwapRate\n )\n {\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n (\n destTokenAmountReceived,\n sourceTokenAmountUsed,\n collateralToLoanSwapRate\n ) = _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount,\n principalNeeded,\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (returnTokenIsCollateral) {\n coveredPrincipal = principalNeeded;\n\n /// Better fill than expected.\n if (destTokenAmountReceived > coveredPrincipal) {\n /// Send excess to borrower if the amount is big enough to be\n /// worth the gas fees.\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - coveredPrincipal\n )\n ) {\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n destTokenAmountReceived - coveredPrincipal\n );\n }\n /// Else, give the excess to the lender (if it goes to the\n /// borrower, they're very confused. causes more trouble than it's worth)\n else {\n coveredPrincipal = destTokenAmountReceived;\n }\n }\n withdrawAmount = swapAmount > sourceTokenAmountUsed\n ? swapAmount - sourceTokenAmountUsed\n : 0;\n } else {\n require(sourceTokenAmountUsed == swapAmount, \"swap error\");\n\n if (swapAmount == loanLocal.collateral) {\n /// sourceTokenAmountUsed == swapAmount == loanLocal.collateral\n\n coveredPrincipal = principalNeeded;\n withdrawAmount = destTokenAmountReceived - principalNeeded;\n } else {\n /// sourceTokenAmountUsed == swapAmount < loanLocal.collateral\n\n if (destTokenAmountReceived >= loanLocal.principal) {\n /// Edge case where swap covers full principal.\n\n coveredPrincipal = loanLocal.principal;\n withdrawAmount = destTokenAmountReceived - loanLocal.principal;\n\n /// Excess collateral refunds to the borrower.\n _withdrawAsset(\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n loanLocal.collateral - sourceTokenAmountUsed\n );\n sourceTokenAmountUsed = loanLocal.collateral;\n } else {\n coveredPrincipal = destTokenAmountReceived;\n withdrawAmount = 0;\n }\n }\n }\n\n usedCollateral = sourceTokenAmountUsed > swapAmount ? sourceTokenAmountUsed : swapAmount;\n }\n\n function _emitClosingEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanRate,\n uint256 collateralToLoanSwapRate,\n uint256 currentMargin,\n CloseTypes closeType\n ) internal {\n if (closeType == CloseTypes.Deposit) {\n emit CloseWithDeposit(\n loanLocal.borrower, /// user (borrower)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n msg.sender, /// closer\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n loanCloseAmount, /// loanCloseAmount\n collateralCloseAmount, /// collateralCloseAmount\n collateralToLoanRate, /// collateralToLoanRate\n currentMargin /// currentMargin\n );\n } else if (closeType == CloseTypes.Swap) {\n /// exitPrice = 1 / collateralToLoanSwapRate\n if (collateralToLoanSwapRate != 0) {\n collateralToLoanSwapRate = SafeMath.div(10**36, collateralToLoanSwapRate);\n }\n\n /// currentLeverage = 100 / currentMargin\n if (currentMargin != 0) {\n currentMargin = SafeMath.div(10**38, currentMargin);\n }\n\n emit CloseWithSwap(\n loanLocal.borrower, /// user (trader)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n msg.sender, /// closer\n collateralCloseAmount, /// positionCloseSize\n loanCloseAmount, /// loanCloseAmount\n collateralToLoanSwapRate, /// exitPrice (1 / collateralToLoanSwapRate)\n currentMargin /// currentLeverage\n );\n } else if (closeType == CloseTypes.Liquidation) {\n emit Liquidate(\n loanLocal.borrower, // user (borrower)\n msg.sender, // liquidator\n loanLocal.id, // loanId\n loanLocal.lender, // lender\n loanParamsLocal.loanToken, // loanToken\n loanParamsLocal.collateralToken, // collateralToken\n loanCloseAmount, // loanCloseAmount\n collateralCloseAmount, // collateralCloseAmount\n collateralToLoanRate, // collateralToLoanRate\n currentMargin // currentMargin\n );\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal view returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n IPriceFeeds(priceFeeds).queryRate(asset, address(wrbtcToken));\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /**\n * @dev private function which check the loanLocal & loanParamsLocal does exist\n *\n * @param loanId bytes32 of loanId\n *\n * @return Loan storage\n * @return LoanParams storage\n */\n function _checkLoan(bytes32 loanId) internal view returns (Loan storage, LoanParams storage) {\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n return (loanLocal, loanParamsLocal);\n }\n}\n" + }, + "contracts/modules/LoanClosingsWith.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsWith contract.\n * @notice Close a loan w/deposit, close w/swap. There are 2 functions for ending a loan on the\n * protocol contract: closeWithSwap and closeWithDeposit. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsWith is LoanClosingsShared {\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n\n /**\n * @notice Closes a loan by doing a deposit.\n *\n * @dev Public wrapper for _closeWithDeposit internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens. (e.g. rBTC on a iSUSD contract).\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n public\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return _closeWithDeposit(loanId, receiver, depositAmount);\n }\n\n /**\n * @notice Close a position by swapping the collateral back to loan tokens\n * paying the lender and withdrawing the remainder.\n *\n * @dev Public wrapper for _closeWithSwap internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collateral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid out\n * in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes memory // for future use /*loanDataBytes*/\n )\n public\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return\n _closeWithSwap(\n loanId,\n receiver,\n swapAmount,\n returnTokenIsCollateral,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for closing a loan by doing a deposit.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens.\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(depositAmount != 0, \"depositAmount == 0\");\n\n //TODO should we skip this check if invoked from rollover ?\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't close more than the full principal.\n loanCloseAmount = depositAmount > loanLocal.principal\n ? loanLocal.principal\n : depositAmount;\n\n //revert if tiny position remains\n uint256 remainingAmount = loanLocal.principal - loanCloseAmount;\n if (remainingAmount > 0) {\n require(\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount) > TINY_AMOUNT,\n \"Tiny amount when closing with deposit\"\n );\n }\n\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(loanLocal, loanParamsLocal, loanCloseAmount, receiver);\n\n if (loanCloseAmountLessInterest != 0) {\n _returnPrincipalWithDeposit(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmount == loanLocal.principal) {\n withdrawAmount = loanLocal.collateral;\n } else {\n withdrawAmount = loanLocal.collateral.mul(loanCloseAmount).div(loanLocal.principal);\n }\n\n withdrawToken = loanParamsLocal.collateralToken;\n\n if (withdrawAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(withdrawAmount);\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n withdrawAmount, /// collateralCloseAmount\n 0, /// collateralToLoanSwapRate\n CloseTypes.Deposit\n );\n }\n\n /**\n * @notice Function to check whether the given loanId & deposit amount when closing with deposit will cause the tiny position\n *\n * @param loanId The id of the loan.\n * @param depositAmount Defines how much the deposit amount to close the position.\n *\n * @return isTinyPosition true is indicating tiny position, false otherwise.\n * @return tinyPositionAmount will return 0 for non tiny position, and will return the amount of tiny position if true\n */\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount)\n {\n (Loan memory loanLocal, LoanParams memory loanParamsLocal) = _checkLoan(loanId);\n\n if (depositAmount < loanLocal.principal) {\n uint256 remainingAmount = loanLocal.principal - depositAmount;\n uint256 remainingRBTCAmount =\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingRBTCAmount < TINY_AMOUNT) {\n isTinyPosition = true;\n tinyPositionAmount = remainingRBTCAmount;\n }\n }\n\n return (isTinyPosition, tinyPositionAmount);\n }\n}\n" + }, + "contracts/modules/LoanMaintenance.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Maintenance contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to query loan data and to modify its status\n * by withdrawing or depositing collateral.\n * */\ncontract LoanMaintenance is\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n LiquidationHelper,\n ModuleCommonFunctionalities\n{\n // Keep the old LoanReturnData for backward compatibility (especially for the watcher)\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n // The new struct which contained borrower & creation time of a loan\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set initial values of proxy targets.\n *\n * @param target The address of the logic contract instance.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.depositCollateral.selector];\n _setTarget(this.depositCollateral.selector, target);\n _setTarget(this.withdrawCollateral.selector, target);\n _setTarget(this.withdrawAccruedInterest.selector, target);\n _setTarget(this.extendLoanDuration.selector, target);\n _setTarget(this.reduceLoanDuration.selector, target);\n _setTarget(this.getLenderInterestData.selector, target);\n _setTarget(this.getLoanInterestData.selector, target);\n _setTarget(this.getUserLoans.selector, target);\n _setTarget(this.getUserLoansV2.selector, target);\n _setTarget(this.getLoan.selector, target);\n _setTarget(this.getLoanV2.selector, target);\n _setTarget(this.getActiveLoans.selector, target);\n _setTarget(this.getActiveLoansV2.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanMaintenance\");\n }\n\n /**\n * @notice Increase the margin of a position by depositing additional collateral.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount /// must match msg.value if ether is sent\n ) external payable nonReentrant whenNotPaused {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.value == 0 || loanParamsLocal.collateralToken == address(wrbtcToken),\n \"wrong asset sent\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(depositAmount);\n\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.collateralToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n\n (uint256 collateralToLoanRate, ) =\n IPriceFeeds(priceFeeds).queryRate(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n\n emit DepositCollateral(loanId, depositAmount, collateralToLoanRate);\n }\n\n /**\n * @notice Withdraw from the collateral. This reduces the margin of a position.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 actualWithdrawAmount) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral,\n loanParamsLocal.maintenanceMargin\n );\n\n if (withdrawAmount > maxDrawdown) {\n actualWithdrawAmount = maxDrawdown;\n } else {\n actualWithdrawAmount = withdrawAmount;\n }\n\n loanLocal.collateral = loanLocal.collateral.sub(actualWithdrawAmount);\n\n if (loanParamsLocal.collateralToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, actualWithdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.collateralToken, receiver, actualWithdrawAmount);\n }\n }\n\n /**\n * @notice Withdraw accrued loan interest.\n *\n * @dev Wrapper for _payInterest internal function.\n *\n * @param loanToken The loan token address.\n * */\n function withdrawAccruedInterest(address loanToken) external whenNotPaused {\n /// Pay outstanding interest to lender.\n _payInterest(\n msg.sender, /// Lender.\n loanToken\n );\n }\n\n /**\n * @notice Extend the loan duration by as much time as depositAmount can buy.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in loan tokens. Used to pay the interest for the new duration.\n * @param useCollateral Whether pay interests w/ the collateral. If true, depositAmount of loan tokens\n *\t\t\t\t\t\twill be purchased with the collateral.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n *\n * @return secondsExtended The amount of time in seconds the loan is extended.\n * */\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external payable nonReentrant whenNotPaused returns (uint256 secondsExtended) {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n !useCollateral ||\n msg.sender == loanLocal.borrower ||\n delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(\n msg.value == 0 || (!useCollateral && loanParamsLocal.loanToken == address(wrbtcToken)),\n \"wrong asset sent\"\n );\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n /// Handle back interest: calculates interest owned since the loan\n /// endtime passed but the loan remained open.\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestOwed = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestOwed.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(86400);\n\n require(depositAmount > backInterestOwed, \"deposit cannot cover back interest\");\n }\n\n /// Deposit interest.\n if (useCollateral) {\n /// Used the whole converted loanToken to extend the loan duration\n depositAmount = _doCollateralSwap(loanLocal, loanParamsLocal, depositAmount);\n } else {\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.loanToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n }\n\n if (backInterestOwed != 0) {\n depositAmount = depositAmount.sub(backInterestOwed);\n\n /// Pay out backInterestOwed\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n secondsExtended = depositAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(secondsExtended);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(depositAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .add(depositAmount);\n }\n\n /**\n * @notice Reduce the loan duration by withdrawing from the deposited interest.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in loan tokens.\n *\n * @return secondsReduced The amount of time in seconds the loan is reduced.\n * */\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 secondsReduced) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(loanLocal.endTimestamp > block.timestamp, \"loan term has ended\");\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 interestDepositRemaining =\n loanLocal.endTimestamp.sub(block.timestamp).mul(loanInterestLocal.owedPerDay).div(\n 86400\n );\n require(withdrawAmount < interestDepositRemaining, \"withdraw amount too high\");\n\n /// Withdraw interest.\n if (loanParamsLocal.loanToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, withdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.loanToken, receiver, withdrawAmount);\n }\n\n secondsReduced = withdrawAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n require(loanLocal.endTimestamp > secondsReduced, \"loan too short\");\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.sub(secondsReduced);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(withdrawAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .sub(withdrawAmount);\n }\n\n /**\n * @notice Get current lender interest data totals for all loans\n * with a specific oracle and interest token.\n *\n * @param lender The lender address.\n * @param loanToken The loan token address.\n *\n * @return interestPaid The total amount of interest that has been paid to a lender so far.\n * @return interestPaidDate The date of the last interest pay out, or 0 if no interest has been withdrawn yet.\n * @return interestOwedPerDay The amount of interest the lender is earning per day.\n * @return interestUnPaid The total amount of interest the lender is owned and not yet withdrawn.\n * @return interestFeePercent The fee retained by the protocol before interest is paid to the lender.\n * @return principalTotal The total amount of outstanding principal the lender has loaned.\n * */\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n )\n {\n LenderInterest memory lenderInterestLocal = lenderInterest[lender][loanToken];\n\n interestUnPaid = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(86400);\n if (interestUnPaid > lenderInterestLocal.owedTotal)\n interestUnPaid = lenderInterestLocal.owedTotal;\n\n return (\n lenderInterestLocal.paidTotal,\n lenderInterestLocal.paidTotal != 0 ? lenderInterestLocal.updatedTimestamp : 0,\n lenderInterestLocal.owedPerDay,\n lenderInterestLocal.updatedTimestamp != 0 ? interestUnPaid : 0,\n lendingFeePercent,\n lenderInterestLocal.principalTotal\n );\n }\n\n /**\n * @notice Get current interest data for a loan.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loanToken The loan token that interest is paid in.\n * @return interestOwedPerDay The amount of interest the borrower is paying per day.\n * @return interestDepositTotal The total amount of interest the borrower has deposited.\n * @return interestDepositRemaining The amount of deposited interest that is not yet owed to a lender.\n * */\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n )\n {\n loanToken = loanParams[loans[loanId].loanParamsId].loanToken;\n interestOwedPerDay = loanInterest[loanId].owedPerDay;\n interestDepositTotal = loanInterest[loanId].depositTotal;\n\n uint256 endTimestamp = loans[loanId].endTimestamp;\n uint256 interestTime = block.timestamp > endTimestamp ? endTimestamp : block.timestamp;\n interestDepositRemaining = endTimestamp > interestTime\n ? endTimestamp.sub(interestTime).mul(interestOwedPerDay).div(86400)\n : 0;\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData) {\n return\n _getLoan(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2) {\n return\n _getLoanV2(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get all active loans.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @dev New view function which will return the loan data.\n * @dev This function was created to support backward compatibility\n * @dev As in we the old getActiveLoans function is not expected to be changed by the wathcers.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loanData The data structure\n * @return extendedLoanData The data structure which contained (borrower & creation time)\n */\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Internal function to get one loan data structure.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ the loan information.\n * */\n function _getLoan(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnData memory loanData) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanData;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanData;\n }\n\n return\n LoanReturnData({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable\n });\n }\n\n /**\n * @notice Internal function to get one loan data structure v2.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data v2 structure w/ the loan information.\n * */\n function _getLoanV2(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnDataV2 memory loanDataV2) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanDataV2;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanDataV2;\n }\n\n return\n LoanReturnDataV2({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n borrower: loanLocal.borrower,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable,\n creationTimestamp: loanLocal.startTimestamp\n });\n }\n\n /**\n * @notice Internal function to collect interest from the collateral.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param depositAmount The amount of underlying tokens provided on the loan.\n * */\n function _doCollateralSwap(\n Loan storage loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 depositAmount\n ) internal returns (uint256 purchasedLoanToken) {\n /// Reverts in _loanSwap if amountNeeded can't be bought.\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanLocal.collateral, /// minSourceTokenAmount\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n depositAmount, /// requiredDestTokenAmount (partial spend of loanLocal.collateral to fill this amount)\n true, /// bypassFee\n \"\" /// loanDataBytes\n );\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n /// Ensure the loan is still healthy.\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n return destTokenAmountReceived;\n }\n}\n" + }, + "contracts/modules/LoanOpenings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\n/**\n * @title Loan Openings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to borrow and trade.\n * */\ncontract LoanOpenings is\n LoanOpeningsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n ModuleCommonFunctionalities\n{\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\n _setTarget(this.borrowOrTradeFromPool.selector, target);\n _setTarget(this.setDelegatedManager.selector, target);\n _setTarget(this.getEstimatedMarginExposure.selector, target);\n _setTarget(this.getRequiredCollateral.selector, target);\n _setTarget(this.getBorrowAmount.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanOpenings\");\n }\n\n /**\n * @notice Borrow or trade from pool.\n *\n * @dev Note: Only callable by loan pools (iTokens).\n * Wrapper to _borrowOrTrade internal function.\n *\n * @param loanParamsId The ID of the loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return newPrincipal The new loan size.\n * @return newCollateral The new collateral amount.\n * */\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n bytes calldata loanDataBytes\n )\n external\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 newPrincipal, uint256 newCollateral)\n {\n require(msg.value == 0 || loanDataBytes.length != 0, \"loanDataBytes required with ether\");\n\n /// Only callable by loan pools.\n require(loanPoolToUnderlying[msg.sender] != address(0), \"not authorized\");\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n /// Get required collateral.\n uint256 collateralAmountRequired =\n _getRequiredCollateral(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentValues.newPrincipal,\n initialMargin,\n isTorqueLoan\n );\n require(collateralAmountRequired != 0, \"collateral is 0\");\n\n return\n _borrowOrTrade(\n loanParamsLocal,\n loanId,\n isTorqueLoan,\n collateralAmountRequired,\n initialMargin,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @dev Wrapper for _setDelegatedManager internal function.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external whenNotPaused {\n require(loans[loanId].borrower == msg.sender, \"unauthorized\");\n\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\n }\n\n /**\n * @notice Get the estimated margin exposure.\n *\n * Margin is the money borrowed from a broker to purchase an investment\n * and is the difference between the total value of investment and the\n * loan amount. Margin trading refers to the practice of using borrowed\n * funds from a broker to trade a financial asset, which forms the\n * collateral for the loan from the broker.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param loanTokenSent The amount of loan tokens sent.\n * @param collateralTokenSent The amount of collateral tokens sent.\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\n * @param newPrincipal The updated amount of principal (current debt).\n *\n * @return The margin exposure.\n * */\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256) {\n uint256 maxLoanTerm = 2419200; // 28 days\n\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\n\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\n\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\n uint256 tradingFee = _getTradingFee(swapAmount);\n if (tradingFee != 0) {\n swapAmount = swapAmount.sub(tradingFee);\n }\n\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\n if (receivedAmount == 0) {\n return 0;\n } else {\n return collateralTokenSent.add(receivedAmount);\n }\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Calls internal _getRequiredCollateral and add fees.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralAmountRequired The required collateral.\n * */\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 collateralAmountRequired) {\n if (marginAmount != 0) {\n collateralAmountRequired = _getRequiredCollateral(\n loanToken,\n collateralToken,\n newPrincipal,\n marginAmount,\n isTorqueLoan\n );\n\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n // cannot be applied solely as it drives to some other tests failure\n /*\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (collateralAmountRequired != 0 && feePercent != 0) {\n\t\t\t\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t);\n\t\t\t}*/\n\n uint256 fee =\n isTorqueLoan\n ? _getBorrowingFee(collateralAmountRequired)\n : _getTradingFee(collateralAmountRequired);\n if (fee != 0) {\n collateralAmountRequired = collateralAmountRequired.add(fee);\n }\n }\n }\n\n /**\n * @notice Get the borrow amount of a trade loan.\n *\n * @dev Basically borrowAmount = collateral / marginAmount\n *\n * Collateral is something that helps secure a loan. When you borrow money,\n * you agree that your lender can take something and sell it to get their\n * money back if you fail to repay the loan. That's the collateral.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param collateralTokenAmount The amount of collateral.\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return borrowAmount The borrow amount.\n * */\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 borrowAmount) {\n if (marginAmount != 0) {\n if (isTorqueLoan) {\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\n }\n uint256 collateral = collateralTokenAmount;\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\n if (fee != 0) {\n collateral = collateral.sub(fee);\n }\n if (loanToken == collateralToken) {\n borrowAmount = collateral.mul(10**20).div(marginAmount);\n } else {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestPrecision != 0) {\n borrowAmount = collateral\n .mul(10**20)\n .mul(sourceToDestRate)\n .div(marginAmount)\n .div(sourceToDestPrecision);\n }\n }\n /*\n\t\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t\t// cannot be applied solely as it drives to some other tests failure\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (borrowAmount != 0 && feePercent != 0) {\n\t\t\t\tborrowAmount = borrowAmount\n\t\t\t\t\t.mul(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t)\n\t\t\t\t\t.divCeil(10**20);\n\t\t\t}*/\n }\n }\n\n /**\n * @notice Borrow or trade.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param collateralAmountRequired The required amount of collateral.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return The new loan size.\n * @return The new collateral amount.\n * */\n function _borrowOrTrade(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 collateralAmountRequired,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n require(\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\n \"collateral/loan match\"\n );\n require(initialMargin >= loanParamsLocal.minInitialMargin, \"initialMargin too low\");\n\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\n require(\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\n \"invalid interest\"\n );\n\n // @note this fix is for borrowing only\n uint256 sentNewPrincipal = isTorqueLoan ? sentValues.newPrincipal : 0;\n\n /// Initialize loan.\n Loan storage loanLocal =\n loans[\n _initializeLoan(\n loanParamsLocal,\n loanId,\n initialMargin,\n sentAddresses,\n sentValues.newPrincipal\n )\n ];\n\n // Get required interest.\n uint256 amount =\n _initializeInterest(\n loanParamsLocal,\n loanLocal,\n sentValues.interestRate, /// newRate\n sentValues.newPrincipal, /// newPrincipal,\n sentValues.interestInitialAmount /// torqueInterest\n );\n\n /// substract out interest from usable loanToken sent.\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\n\n if (isTorqueLoan) {\n require(sentValues.loanTokenSent == 0, \"surplus loan token\");\n\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\n // need to temp into local state to avoid\n address _collateralToken = loanParamsLocal.collateralToken;\n address _loanToken = loanParamsLocal.loanToken;\n if (borrowingFee != 0) {\n _payBorrowingFee(\n sentAddresses.borrower, /// borrower\n loanLocal.id,\n _collateralToken, /// fee token\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n borrowingFee\n );\n\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\n }\n } else {\n /// Update collateral after trade.\n sentValues = _updateCollateralAfterTrade(\n loanId,\n loanParamsLocal,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /// Settle collateral.\n require(\n _isCollateralSatisfied(\n loanParamsLocal,\n loanLocal,\n initialMargin,\n sentValues.collateralTokenSent,\n collateralAmountRequired,\n sentNewPrincipal\n ),\n \"collateral insufficient\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\n\n if (isTorqueLoan) {\n /// reclaiming variable -> interestDuration\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\n } else {\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\n }\n\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\n\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\n }\n\n function _updateCollateralAfterTrade(\n bytes32 loanId,\n LoanParams memory loanParamsLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (MarginTradeStructHelpers.SentAmounts memory) {\n uint256 receivedAmount;\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\n loanId,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentAddresses.borrower, /// borrower\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\n false, /// bypassFee\n loanDataBytes\n );\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\n\n /// Check the minEntryPrice with the rate\n require(\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\n \"entry price above the minimum\"\n );\n\n return sentValues;\n }\n\n /**\n * @notice Finalize an open loan.\n *\n * @dev Finalize it by updating local parameters of the loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _finalizeOpen(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bool isTorqueLoan\n ) internal {\n /// @dev TODO: here the actual used rate and margin should go.\n (uint256 initialMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(initialMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n if (loanLocal.startTimestamp == block.timestamp) {\n uint256 loanToCollateralPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken\n );\n uint256 collateralToLoanPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\n loanLocal.startRate = isTorqueLoan\n ? collateralToLoanRate\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\n }\n\n _emitOpeningEvents(\n loanParamsLocal,\n loanLocal,\n sentAddresses,\n sentValues,\n collateralToLoanRate,\n initialMargin,\n isTorqueLoan\n );\n }\n\n /**\n * @notice Emit the opening events.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n * @param margin The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _emitOpeningEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n uint256 collateralToLoanRate,\n uint256 margin,\n bool isTorqueLoan\n ) internal {\n if (isTorqueLoan) {\n emit Borrow(\n sentAddresses.borrower, /// user (borrower)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n sentValues.newPrincipal, /// newPrincipal\n sentValues.collateralTokenSent, /// newCollateral\n sentValues.interestRate, /// interestRate\n sentValues.interestDuration, /// interestDuration\n collateralToLoanRate, /// collateralToLoanRate,\n margin /// currentMargin\n );\n } else {\n /// currentLeverage = 100 / currentMargin\n margin = SafeMath.div(10**38, margin);\n\n emit Trade(\n sentAddresses.borrower, /// user (trader)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n sentValues.collateralTokenSent, /// positionSize\n sentValues.newPrincipal, /// borrowedAmount\n sentValues.interestRate, /// interestRate,\n loanLocal.endTimestamp, /// settlementDate\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\n sentValues.entryLeverage, /// entryLeverage\n margin /// currentLeverage\n );\n }\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegator The address of previous manager.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function _setDelegatedManager(\n bytes32 loanId,\n address delegator,\n address delegated,\n bool toggle\n ) internal {\n delegatedManagers[loanId][delegated] = toggle;\n\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\n }\n\n /**\n * @notice Calculate whether the collateral is satisfied.\n *\n * @dev Basically check collateral + drawdown >= 98% of required.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param initialMargin The initial amount of margin.\n * @param newCollateral The amount of new collateral.\n * @param collateralAmountRequired The amount of required collateral.\n * @param newPrincipal The amount to borrow.\n *\n * @return Whether the collateral is satisfied.\n * */\n function _isCollateralSatisfied(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 initialMargin,\n uint256 newCollateral,\n uint256 collateralAmountRequired,\n uint256 newPrincipal\n ) internal view returns (bool) {\n /// Allow at most 2% under-collateralized.\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\n\n if (newCollateral < collateralAmountRequired) {\n /// Check that existing collateral is sufficient coverage.\n if (loanLocal.collateral != 0) {\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal.sub(newPrincipal), // sub(newPrincipal) to exclude the new borrowed amount from the total principal to calculate maxDrawdown for existing loan\n loanLocal.collateral,\n initialMargin\n );\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\n } else {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @notice Initialize a loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan.\n * @param initialMargin The amount of margin of the trade.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\n * @return The loanId.\n * */\n function _initializeLoan(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n uint256 newPrincipal\n ) internal returns (bytes32) {\n require(loanParamsLocal.active, \"loanParams disabled\");\n\n address lender = sentAddresses.lender;\n address borrower = sentAddresses.borrower;\n address manager = sentAddresses.manager;\n\n Loan memory loanLocal;\n\n if (loanId == 0) {\n borrowerNonce[borrower]++;\n loanId = keccak256(\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\n );\n require(loans[loanId].id == 0, \"loan exists\");\n\n loanLocal = Loan({\n id: loanId,\n loanParamsId: loanParamsLocal.id,\n pendingTradesId: 0,\n active: true,\n principal: newPrincipal,\n collateral: 0, /// calculated later\n startTimestamp: block.timestamp,\n endTimestamp: 0, /// calculated later\n startMargin: initialMargin,\n startRate: 0, /// queried later\n borrower: borrower,\n lender: lender\n });\n\n activeLoansSet.addBytes32(loanId);\n lenderLoanSets[lender].addBytes32(loanId);\n borrowerLoanSets[borrower].addBytes32(loanId);\n } else {\n loanLocal = loans[loanId];\n require(\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\n \"loan has ended\"\n );\n require(loanLocal.borrower == borrower, \"borrower mismatch\");\n require(loanLocal.lender == lender, \"lender mismatch\");\n require(loanLocal.loanParamsId == loanParamsLocal.id, \"loanParams mismatch\");\n\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\n }\n\n if (manager != address(0)) {\n _setDelegatedManager(loanId, borrower, manager, true);\n }\n\n loans[loanId] = loanLocal;\n\n return loanId;\n }\n\n /**\n * @notice Initialize a loan interest.\n *\n * @dev A Torque loan is an indefinite-term loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param newRate The new interest rate of the loan.\n * @param newPrincipal The new principal amount of the loan.\n * @param torqueInterest The interest rate of the Torque loan.\n *\n * @return interestAmountRequired The interest amount required.\n * */\n function _initializeInterest(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n uint256 newRate,\n uint256 newPrincipal,\n uint256 torqueInterest /// ignored for fixed-term loans\n ) internal returns (uint256 interestAmountRequired) {\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 previousDepositRemaining;\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\n previousDepositRemaining = loanLocal\n .endTimestamp\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\n .mul(loanInterestLocal.owedPerDay)\n .div(86400);\n }\n\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\n\n /// Update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n\n if (maxLoanTerm == 0) {\n /// Indefinite-term (Torque) loan.\n\n /// torqueInterest != 0 was confirmed earlier.\n loanLocal.endTimestamp = torqueInterest\n .add(previousDepositRemaining)\n .mul(86400)\n .div(loanInterestLocal.owedPerDay)\n .add(block.timestamp);\n\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxLoanTerm > 3600, \"loan too short\");\n\n interestAmountRequired = torqueInterest;\n } else {\n /// Fixed-term loan.\n\n if (loanLocal.endTimestamp == 0) {\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\n }\n\n interestAmountRequired = loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(owedPerDay)\n .div(86400);\n }\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n /// Update remaining lender interest values.\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Basically collateral = newPrincipal * marginAmount\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralTokenAmount The required collateral.\n * */\n function _getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) internal view returns (uint256 collateralTokenAmount) {\n if (loanToken == collateralToken) {\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\n } else {\n /// Using the price feed instead of the swap expected return\n /// because we need the rate in the inverse direction\n /// so the swap is probably farther off than the price feed.\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestRate != 0) {\n collateralTokenAmount = newPrincipal\n .mul(sourceToDestPrecision)\n .div(sourceToDestRate)\n .mul(marginAmount)\n .div(10**20);\n /*TODO: review\n\t\t\t\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\n }\n }\n // ./tests/loan-token/TradingTestToken.test.js\n if (isTorqueLoan && collateralTokenAmount != 0) {\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\n collateralTokenAmount\n );\n }\n }\n}\n" + }, + "contracts/modules/LoanSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to get and set loan parameters.\n * */\ncontract LoanSettings is State, LoanSettingsEvents, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"LoanSettings - fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setupLoanParams.selector];\n _setTarget(this.setupLoanParams.selector, target);\n _setTarget(this.disableLoanParams.selector, target);\n _setTarget(this.getLoanParams.selector, target);\n _setTarget(this.getLoanParamsList.selector, target);\n _setTarget(this.getTotalPrincipal.selector, target);\n _setTarget(this.minInitialMargin.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanSettings\");\n }\n\n /**\n * @notice Setup loan parameters, by looping every loan\n * and populating its parameters.\n *\n * @dev For each loan calls _setupLoanParams internal function.\n *\n * @param loanParamsList The array of loan parameters.\n *\n * @return loanParamsIdList The array of loan parameters IDs.\n * */\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n whenNotPaused\n returns (bytes32[] memory loanParamsIdList)\n {\n loanParamsIdList = new bytes32[](loanParamsList.length);\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsIdList[i] = _setupLoanParams(loanParamsList[i]);\n }\n }\n\n /**\n * @notice Deactivate LoanParams for future loans. Active loans\n * using it are unaffected.\n *\n * @param loanParamsIdList The array of loan parameters IDs to deactivate.\n * */\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external whenNotPaused {\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n require(msg.sender == loanParams[loanParamsIdList[i]].owner, \"unauthorized owner\");\n loanParams[loanParamsIdList[i]].active = false;\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n emit LoanParamsDisabled(\n loanParamsLocal.id,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdDisabled(loanParamsLocal.id, loanParamsLocal.owner);\n }\n }\n\n /**\n * @notice Get loan parameters for every matching IDs.\n *\n * @param loanParamsIdList The array of loan parameters IDs to match.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParams(bytes32[] memory loanParamsIdList)\n public\n view\n returns (LoanParams[] memory loanParamsList)\n {\n loanParamsList = new LoanParams[](loanParamsIdList.length);\n uint256 itemCount;\n\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n if (loanParamsLocal.id == 0) {\n continue;\n }\n loanParamsList[itemCount] = loanParamsLocal;\n itemCount++;\n }\n\n if (itemCount < loanParamsList.length) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get loan parameters for an owner and a given page\n * defined by an offset and a limit.\n *\n * @param owner The address of the loan owner.\n * @param start The page offset.\n * @param count The page limit.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList) {\n EnumerableBytes32Set.Bytes32Set storage set = userLoanParamSets[owner];\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loanParamsList;\n }\n\n loanParamsList = new bytes32[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n loanParamsList[itemCount] = set.get(i + start - 1);\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get the total principal of the loans by a lender.\n *\n * @param lender The address of the lender.\n * @param loanToken The address of the token instance.\n *\n * @return The total principal of the loans.\n * */\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256) {\n return lenderInterest[lender][loanToken].principalTotal;\n }\n\n /**\n * @notice Setup a loan parameters.\n *\n * @param loanParamsLocal The loan parameters.\n *\n * @return loanParamsId The loan parameters ID.\n * */\n function _setupLoanParams(LoanParams memory loanParamsLocal) internal returns (bytes32) {\n bytes32 loanParamsId =\n keccak256(\n abi.encodePacked(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm,\n block.timestamp\n )\n );\n require(loanParams[loanParamsId].id == 0, \"loanParams exists\");\n\n require(\n loanParamsLocal.loanToken != address(0) &&\n loanParamsLocal.collateralToken != address(0) &&\n loanParamsLocal.minInitialMargin > loanParamsLocal.maintenanceMargin &&\n (loanParamsLocal.maxLoanTerm == 0 || loanParamsLocal.maxLoanTerm > 3600), /// A defined maxLoanTerm has to be greater than one hour.\n \"invalid params\"\n );\n\n loanParamsLocal.id = loanParamsId;\n loanParamsLocal.active = true;\n loanParamsLocal.owner = msg.sender;\n\n loanParams[loanParamsId] = loanParamsLocal;\n userLoanParamSets[msg.sender].addBytes32(loanParamsId);\n\n emit LoanParamsSetup(\n loanParamsId,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdSetup(loanParamsId, loanParamsLocal.owner);\n\n return loanParamsId;\n }\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256) {\n return loanParams[loanParamsId].minInitialMargin;\n }\n}\n" + }, + "contracts/modules/ProtocolSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../mixins/ProtocolTokenUser.sol\";\nimport \"../modules/interfaces/ProtocolSwapExternalInterface.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../governance/IFeeSharingCollector.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title Protocol Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to customize protocol settings.\n * */\ncontract ProtocolSettings is\n State,\n ProtocolTokenUser,\n ProtocolSettingsEvents,\n ModuleCommonFunctionalities\n{\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyAdminOrOwner {\n address prevModuleContractAddress = logicTargets[this.setPriceFeedContract.selector];\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n _setTarget(this.setRebatePercent.selector, target);\n _setTarget(this.setSpecialRebates.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.togglePaused.selector, target);\n _setTarget(this.isProtocolPaused.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n _setTarget(this.setRolloverFlexFeePercent.selector, target);\n _setTarget(this.getDefaultPathConversion.selector, target);\n _setTarget(this.setDefaultPathConversion.selector, target);\n _setTarget(this.removeDefaultPathConversion.selector, target);\n _setTarget(this.setAdmin.selector, target);\n _setTarget(this.getAdmin.selector, target);\n _setTarget(this.setPauser.selector, target);\n _setTarget(this.getPauser.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"ProtocolSettings\");\n }\n\n /**\n * setting wrong address will break inter module functions calling\n * should be set once\n */\n function setSovrynProtocolAddress(address newProtocolAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address oldProtocolAddress = protocolAddress;\n protocolAddress = newProtocolAddress;\n\n emit SetProtocolAddress(msg.sender, oldProtocolAddress, newProtocolAddress);\n }\n\n function setSOVTokenAddress(address newSovTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newSovTokenAddress), \"newSovTokenAddress not a contract\");\n\n address oldTokenAddress = sovTokenAddress;\n sovTokenAddress = newSovTokenAddress;\n\n emit SetSOVTokenAddress(msg.sender, oldTokenAddress, newSovTokenAddress);\n }\n\n function setLockedSOVAddress(address newLockedSOVAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newLockedSOVAddress), \"newLockSOVAddress not a contract\");\n\n address oldLockedSOVAddress = lockedSOVAddress;\n lockedSOVAddress = newLockedSOVAddress;\n\n emit SetLockedSOVAddress(msg.sender, oldLockedSOVAddress, newLockedSOVAddress);\n }\n\n /**\n * @notice Set the basis point of trading rebate rewards (SOV), max value is 9999 (99.99% liquid, 0.01% vested).\n *\n * @param newBasisPoint Basis point value.\n */\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newBasisPoint <= 9999, \"value too high\");\n\n uint256 oldBasisPoint = tradingRebateRewardsBasisPoint;\n tradingRebateRewardsBasisPoint = newBasisPoint;\n\n emit SetTradingRebateRewardsBasisPoint(msg.sender, oldBasisPoint, newBasisPoint);\n }\n\n /**\n * @notice Update the minimum number of referrals to get affiliates rewards.\n *\n * @param newMinReferrals The new minimum number of referrals.\n * */\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n uint256 oldMinReferrals = minReferralsToPayout;\n minReferralsToPayout = newMinReferrals;\n\n emit SetMinReferralsToPayoutAffiliates(msg.sender, oldMinReferrals, newMinReferrals);\n }\n\n /**\n * @notice Set the address of the Price Feed instance.\n *\n * @param newContract The address of the Price Feed new instance.\n * */\n function setPriceFeedContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = priceFeeds;\n priceFeeds = newContract;\n\n emit SetPriceFeedContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set the address of the asset swapper instance.\n *\n * @param newContract The address of the asset swapper new instance.\n * */\n function setSwapsImplContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = swapsImpl;\n swapsImpl = newContract;\n\n emit SetSwapsImplContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set a list of loan pools and its tokens.\n *\n * @param pools The array of addresses of new loan pool instances.\n * @param assets The array of addresses of the corresponding underlying tokens.\n * */\n function setLoanPool(address[] calldata pools, address[] calldata assets)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(pools.length == assets.length, \"count mismatch\");\n\n for (uint256 i = 0; i < pools.length; i++) {\n require(pools[i] != assets[i], \"pool == asset\");\n require(pools[i] != address(0), \"pool == 0\");\n require(\n assets[i] != address(0) || loanPoolToUnderlying[pools[i]] != address(0),\n \"pool not exists\"\n );\n if (assets[i] == address(0)) {\n underlyingToLoanPool[loanPoolToUnderlying[pools[i]]] = address(0);\n loanPoolToUnderlying[pools[i]] = address(0);\n loanPoolsSet.removeAddress(pools[i]);\n } else {\n loanPoolToUnderlying[pools[i]] = assets[i];\n underlyingToLoanPool[assets[i]] = pools[i];\n loanPoolsSet.addAddress(pools[i]);\n }\n\n emit SetLoanPool(msg.sender, pools[i], assets[i]);\n }\n }\n\n /**\n * @notice Set a list of supported tokens by populating the\n * storage supportedTokens mapping.\n *\n * @param addrs The array of addresses of the tokens.\n * @param toggles The array of flags indicating whether\n * the corresponding token is supported or not.\n * */\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(addrs.length == toggles.length, \"count mismatch\");\n\n for (uint256 i = 0; i < addrs.length; i++) {\n supportedTokens[addrs[i]] = toggles[i];\n\n emit SetSupportedTokens(msg.sender, addrs[i], toggles[i]);\n }\n }\n\n /**\n * @notice Set the value of lendingFeePercent storage variable.\n *\n * @param newValue The new value for lendingFeePercent.\n * */\n function setLendingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = lendingFeePercent;\n lendingFeePercent = newValue;\n\n emit SetLendingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of tradingFeePercent storage variable.\n *\n * @param newValue The new value for tradingFeePercent.\n * */\n function setTradingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = tradingFeePercent;\n tradingFeePercent = newValue;\n\n emit SetTradingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of borrowingFeePercent storage variable.\n *\n * @param newValue The new value for borrowingFeePercent.\n * */\n function setBorrowingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = borrowingFeePercent;\n borrowingFeePercent = newValue;\n\n emit SetBorrowingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of swapExtrernalFeePercent storage variable\n *\n * @param newValue the new value for swapExternalFeePercent\n */\n function setSwapExternalFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = swapExtrernalFeePercent;\n swapExtrernalFeePercent = newValue;\n\n emit SetSwapExternalFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateFeePercent storage variable.\n *\n * @param newValue The new value for affiliateFeePercent.\n * */\n function setAffiliateFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateFeePercent;\n affiliateFeePercent = newValue;\n\n emit SetAffiliateFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateTradingTokenFeePercent storage variable.\n *\n * @param newValue The new value for affiliateTradingTokenFeePercent.\n * */\n function setAffiliateTradingTokenFeePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateTradingTokenFeePercent;\n affiliateTradingTokenFeePercent = newValue;\n\n emit SetAffiliateTradingTokenFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of liquidationIncentivePercent storage variable.\n *\n * @param newValue The new value for liquidationIncentivePercent.\n * */\n function setLiquidationIncentivePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = liquidationIncentivePercent;\n liquidationIncentivePercent = newValue;\n\n emit SetLiquidationIncentivePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of the maximum swap spread.\n *\n * @param newValue The new value for maxDisagreement.\n * */\n function setMaxDisagreement(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n maxDisagreement = newValue;\n }\n\n /**\n * @notice Set the value of the maximum source buffer.\n *\n * @dev To avoid rounding issues on the swap rate a small buffer is implemented.\n *\n * @param newValue The new value for the maximum source buffer.\n * */\n function setSourceBuffer(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n sourceBuffer = newValue;\n }\n\n /**\n * @notice Set the value of the swap size limit.\n *\n * @param newValue The new value for the maximum swap size.\n * */\n function setMaxSwapSize(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n uint256 oldValue = maxSwapSize;\n maxSwapSize = newValue;\n\n emit SetMaxSwapSize(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the address of the feesController instance.\n *\n * @dev The fee sharing proxy must be the feesController of the\n * protocol contract. This allows the fee sharing proxy\n * to withdraw the fees.\n *\n * @param newController The new address of the feesController.\n * */\n function setFeesController(address newController) external onlyAdminOrOwner whenNotPaused {\n address oldController = feesController;\n feesController = newController;\n\n emit SetFeesController(msg.sender, oldController, newController);\n }\n\n /**\n * @notice Set the pauser address of sovryn protocol.\n *\n * only pauser or owner can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Get pauser address.\n *\n *\n * @return pauser address.\n */\n function getPauser() external view returns (address) {\n return pauser;\n }\n\n /*\n * @notice Set the admin address of sovryn protocol.\n *\n * only owner can perform this action.\n *\n * @param newAdmin The new address of the admin.\n * */\n function setAdmin(address newAdmin) external onlyOwner {\n emit SetAdmin(msg.sender, admin, newAdmin);\n admin = newAdmin;\n }\n\n /**\n * @dev Get admin address.\n *\n *\n * @return admin address.\n */\n function getAdmin() external view returns (address) {\n return admin;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * from three sources: lending, trading and borrowing.\n * The fees (except SOV) will be converted to wRBTC.\n * For SOV, it will be deposited directly to feeSharingCollector from the protocol.\n *\n * @param tokens The array of address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n whenNotPaused\n returns (uint256 totalWRBTCWithdrawn)\n {\n require(msg.sender == feesController, \"unauthorized\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n uint256 lendingBalance = lendingFeeTokensHeld[tokens[i]];\n if (lendingBalance > 0) {\n lendingFeeTokensHeld[tokens[i]] = 0;\n lendingFeeTokensPaid[tokens[i]] = lendingFeeTokensPaid[tokens[i]].add(\n lendingBalance\n );\n }\n\n uint256 tradingBalance = tradingFeeTokensHeld[tokens[i]];\n if (tradingBalance > 0) {\n tradingFeeTokensHeld[tokens[i]] = 0;\n tradingFeeTokensPaid[tokens[i]] = tradingFeeTokensPaid[tokens[i]].add(\n tradingBalance\n );\n }\n\n uint256 borrowingBalance = borrowingFeeTokensHeld[tokens[i]];\n if (borrowingBalance > 0) {\n borrowingFeeTokensHeld[tokens[i]] = 0;\n borrowingFeeTokensPaid[tokens[i]] = borrowingFeeTokensPaid[tokens[i]].add(\n borrowingBalance\n );\n }\n\n uint256 tempAmount = lendingBalance.add(tradingBalance).add(borrowingBalance);\n\n if (tempAmount == 0) {\n continue;\n }\n\n uint256 amountConvertedToWRBTC;\n if (tokens[i] == address(sovTokenAddress)) {\n IERC20(tokens[i]).approve(feesController, tempAmount);\n IFeeSharingCollector(feesController).transferTokens(\n address(sovTokenAddress),\n uint96(tempAmount)\n );\n amountConvertedToWRBTC = 0;\n } else {\n if (tokens[i] == address(wrbtcToken)) {\n amountConvertedToWRBTC = tempAmount;\n\n IERC20(address(wrbtcToken)).safeTransfer(receiver, amountConvertedToWRBTC);\n } else {\n IERC20(tokens[i]).approve(protocolAddress, tempAmount);\n\n (amountConvertedToWRBTC, ) = ProtocolSwapExternalInterface(protocolAddress)\n .swapExternal(\n tokens[i], // source token address\n address(wrbtcToken), // dest token address\n feesController, // set feeSharingCollector as receiver\n protocolAddress, // protocol as the sender\n tempAmount, // source token amount\n 0, // reqDestToken\n 0, // minReturn\n \"\" // loan data bytes\n );\n\n /// Will revert if disagreement found.\n IPriceFeeds(priceFeeds).checkPriceDisagreement(\n tokens[i],\n address(wrbtcToken),\n tempAmount,\n amountConvertedToWRBTC,\n maxDisagreement\n );\n }\n\n totalWRBTCWithdrawn = totalWRBTCWithdrawn.add(amountConvertedToWRBTC);\n }\n\n emit WithdrawFees(\n msg.sender,\n tokens[i],\n receiver,\n lendingBalance,\n tradingBalance,\n borrowingBalance,\n amountConvertedToWRBTC\n );\n }\n\n return totalWRBTCWithdrawn;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from lending operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = lendingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n lendingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n lendingFeeTokensPaid[token] = lendingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawLendingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from trading operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = tradingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n tradingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n tradingFeeTokensPaid[token] = tradingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawTradingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from borrowing operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = borrowingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n borrowingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n borrowingFeeTokensPaid[token] = borrowingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawBorrowingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The owner calls this function to withdraw protocol tokens.\n *\n * @dev Wrapper for ProtocolTokenUser::_withdrawProtocolToken internal function.\n *\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of tokens to get.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n onlyAdminOrOwner\n whenNotPaused\n returns (address, bool)\n {\n return _withdrawProtocolToken(receiver, amount);\n }\n\n /**\n * @notice The owner calls this function to deposit protocol tokens.\n *\n * @param amount The tokens of fees to send.\n * */\n function depositProtocolToken(uint256 amount) external onlyAdminOrOwner whenNotPaused {\n /// @dev Update local balance\n protocolTokenHeld = protocolTokenHeld.add(amount);\n\n /// @dev Send the tokens\n IERC20(protocolTokenAddress).safeTransferFrom(msg.sender, address(this), amount);\n }\n\n /**\n * @notice Get a list of loan pools.\n *\n * @param start The offset.\n * @param count The limit.\n *\n * @return The array of loan pools.\n * */\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory)\n {\n return loanPoolsSet.enumerate(start, count);\n }\n\n /**\n * @notice Check whether a token is a pool token.\n *\n * @dev By querying its underlying token.\n *\n * @param loanPool The token address to check.\n * */\n function isLoanPool(address loanPool) external view returns (bool) {\n return loanPoolToUnderlying[loanPool] != address(0);\n }\n\n /**\n * @notice Set the contract registry address of the SovrynSwap network.\n *\n * @param registryAddress the address of the registry contract.\n * */\n function setSovrynSwapContractRegistryAddress(address registryAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(registryAddress), \"registryAddress not a contract\");\n\n address oldSovrynSwapContractRegistryAddress = sovrynSwapContractRegistryAddress;\n sovrynSwapContractRegistryAddress = registryAddress;\n\n emit SetSovrynSwapContractRegistryAddress(\n msg.sender,\n oldSovrynSwapContractRegistryAddress,\n sovrynSwapContractRegistryAddress\n );\n }\n\n /**\n * @notice Set the wrBTC contract address.\n *\n * @param wrbtcTokenAddress The address of the wrBTC contract.\n * */\n function setWrbtcToken(address wrbtcTokenAddress) external onlyAdminOrOwner whenNotPaused {\n require(Address.isContract(wrbtcTokenAddress), \"wrbtcTokenAddress not a contract\");\n\n address oldwrbtcToken = address(wrbtcToken);\n wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n emit SetWrbtcToken(msg.sender, oldwrbtcToken, wrbtcTokenAddress);\n }\n\n /**\n * @notice Set the protocol token contract address.\n *\n * @param _protocolTokenAddress The address of the protocol token contract.\n * */\n function setProtocolTokenAddress(address _protocolTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n\n address oldProtocolTokenAddress = protocolTokenAddress;\n protocolTokenAddress = _protocolTokenAddress;\n\n emit SetProtocolTokenAddress(msg.sender, oldProtocolTokenAddress, _protocolTokenAddress);\n }\n\n /**\n * @notice Set rollover base reward. It should be denominated in wrBTC.\n *\n * @param baseRewardValue The base reward.\n * */\n function setRolloverBaseReward(uint256 baseRewardValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(baseRewardValue > 0, \"Base reward is zero\");\n\n uint256 oldValue = rolloverBaseReward;\n rolloverBaseReward = baseRewardValue;\n\n emit SetRolloverBaseReward(msg.sender, oldValue, rolloverBaseReward);\n }\n\n /**\n * @notice Set the fee rebate percent.\n *\n * @param rebatePercent The fee rebate percent.\n * */\n function setRebatePercent(uint256 rebatePercent) external onlyAdminOrOwner whenNotPaused {\n require(rebatePercent <= 10**20, \"Fee rebate is too high\");\n\n uint256 oldRebatePercent = feeRebatePercent;\n feeRebatePercent = rebatePercent;\n\n emit SetRebatePercent(msg.sender, oldRebatePercent, rebatePercent);\n }\n\n /**\n * @notice Set the special fee rebate percent for specific pair\n *\n * @param specialRebatesPercent The new special fee rebate percent.\n * */\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external onlyAdminOrOwner whenNotPaused {\n // Set max special rebates to 1000%\n require(specialRebatesPercent <= 1000e18, \"Special fee rebate is too high\");\n\n uint256 oldSpecialRebatesPercent = specialRebates[sourceToken][destToken];\n specialRebates[sourceToken][destToken] = specialRebatesPercent;\n\n emit SetSpecialRebates(\n msg.sender,\n sourceToken,\n destToken,\n oldSpecialRebatesPercent,\n specialRebatesPercent\n );\n }\n\n /**\n * @notice Get a rebate percent of specific pairs.\n *\n * @param sourceTokenAddress The source of pairs.\n * @param destTokenAddress The dest of pairs.\n *\n * @return The percent rebates of the pairs.\n * */\n function getSpecialRebates(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 specialRebatesPercent)\n {\n return specialRebates[sourceTokenAddress][destTokenAddress];\n }\n\n function getProtocolAddress() external view returns (address) {\n return protocolAddress;\n }\n\n function getSovTokenAddress() external view returns (address) {\n return sovTokenAddress;\n }\n\n function getLockedSOVAddress() external view returns (address) {\n return lockedSOVAddress;\n }\n\n function getFeeRebatePercent() external view returns (uint256) {\n return feeRebatePercent;\n }\n\n function togglePaused(bool paused) external onlyPauserOrOwner {\n require(paused != pause, \"Can't toggle\");\n pause = paused;\n emit TogglePaused(msg.sender, !paused, paused);\n }\n\n function isProtocolPaused() external view returns (bool) {\n return pause;\n }\n\n function getSwapExternalFeePercent() external view returns (uint256) {\n return swapExtrernalFeePercent;\n }\n\n /**\n * @notice Get the basis point of trading rebate rewards.\n *\n * @return The basis point value.\n */\n function getTradingRebateRewardsBasisPoint() external view returns (uint256) {\n return tradingRebateRewardsBasisPoint;\n }\n\n /**\n * @dev Get how much SOV that is dedicated to pay the trading rebate rewards.\n * @notice If SOV balance is less than the fees held, it will return 0.\n *\n * @return total dedicated SOV.\n */\n function getDedicatedSOVRebate() public view returns (uint256) {\n uint256 sovProtocolBalance = IERC20(sovTokenAddress).balanceOf(address(this));\n uint256 sovFees =\n lendingFeeTokensHeld[sovTokenAddress].add(tradingFeeTokensHeld[sovTokenAddress]).add(\n borrowingFeeTokensHeld[sovTokenAddress]\n );\n\n return sovProtocolBalance >= sovFees ? sovProtocolBalance.sub(sovFees) : 0;\n }\n\n /**\n * @notice Set rolloverFlexFeePercent (max value is 1%)\n *\n * @param newRolloverFlexFeePercent uint256 value of new rollover flex fee percentage (0.1 ether = 0.1%)\n */\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newRolloverFlexFeePercent <= 1e18, \"value too high\");\n uint256 oldRolloverFlexFeePercent = rolloverFlexFeePercent;\n rolloverFlexFeePercent = newRolloverFlexFeePercent;\n\n emit SetRolloverFlexFeePercent(\n msg.sender,\n oldRolloverFlexFeePercent,\n newRolloverFlexFeePercent\n );\n }\n\n /**\n * @dev Get default path conversion for pairs.\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address.\n *\n * @return default path of the conversion.\n */\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory)\n {\n return defaultPathConversion[sourceTokenAddress][destTokenAddress];\n }\n\n /**\n * @dev Set default path conversion for pairs.\n *\n * @param defaultPath array of addresses for the default path.\n *\n */\n function setDefaultPathConversion(IERC20[] calldata defaultPath)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address sourceTokenAddress = address(defaultPath[0]);\n address destTokenAddress = address(defaultPath[defaultPath.length - 1]);\n\n uint256 defaultPathLength = defaultPath.length;\n require(defaultPathLength >= 3, \"ERR_PATH_LENGTH\");\n\n for (uint256 i = 0; i < defaultPathLength; i++) {\n require(Address.isContract(address(defaultPath[i])), \"ERR_PATH_NON_CONTRACT_ADDR\");\n }\n\n defaultPathConversion[sourceTokenAddress][destTokenAddress] = defaultPath;\n\n emit SetDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPath\n );\n }\n\n /**\n * @dev Remove the default path conversion for pairs\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address\n */\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(\n defaultPathConversion[sourceTokenAddress][destTokenAddress].length > 0,\n \"DEFAULT_PATH_EMPTY\"\n );\n\n IERC20[] memory defaultPathValue =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n delete defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n emit RemoveDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPathValue\n );\n }\n}\n" + }, + "contracts/modules/SwapsExternal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Swaps External contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to calculate and execute swaps.\n * */\ncontract SwapsExternal is VaultController, SwapsUser, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.swapExternal.selector];\n _setTarget(this.swapExternal.selector, target);\n _setTarget(this.getSwapExpectedReturn.selector, target);\n _setTarget(this.checkPriceDivergence.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"SwapsExternal\");\n }\n\n /**\n * @notice Perform a swap w/ tokens or rBTC as source currency.\n *\n * @dev External wrapper that calls SwapsUser::_swapsCall\n * after turning potential incoming rBTC into wrBTC tokens.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param receiver The address of the recipient account.\n * @param returnToSender The address of the sender account.\n * @param sourceTokenAmount The amount of source tokens.\n * @param requiredDestTokenAmount The amount of required destiny tokens.\n * @param minReturn Minimum amount (position size) in the collateral tokens.\n * @param swapData Additional swap data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes memory swapData\n )\n public\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(sourceTokenAmount != 0, \"sourceTokenAmount == 0\");\n checkPriceDivergence(sourceToken, destToken, sourceTokenAmount, minReturn);\n\n /// @dev Get payed value, be it rBTC or tokenized.\n if (msg.value != 0) {\n if (sourceToken == address(0)) {\n sourceToken = address(wrbtcToken);\n }\n require(sourceToken == address(wrbtcToken), \"sourceToken mismatch\");\n require(msg.value == sourceTokenAmount, \"sourceTokenAmount mismatch\");\n\n /// @dev Update wrBTC balance for this contract.\n wrbtcToken.deposit.value(sourceTokenAmount)();\n } else {\n if (address(this) != msg.sender) {\n IERC20(sourceToken).safeTransferFrom(msg.sender, address(this), sourceTokenAmount);\n }\n }\n\n /// @dev Perform the swap w/ tokens.\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n receiver,\n returnToSender,\n msg.sender /// user\n ],\n [\n sourceTokenAmount, /// minSourceTokenAmount\n sourceTokenAmount, /// maxSourceTokenAmount\n requiredDestTokenAmount\n ],\n 0, /// loanId (not tied to a specific loan)\n false, /// bypassFee\n swapData,\n true // the flag for swapExternal (so that it will use the swapExternalFeePercent)\n );\n\n emit ExternalSwap(\n msg.sender, /// user\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Get the swap expected return value.\n *\n * @dev External wrapper that calls SwapsUser::_swapsExpectedReturn\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n *\n * @return The expected return value.\n * */\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n }\n\n /**\n * @notice Check the slippage based on the swapExpectedReturn.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n * @param minReturn The amount (max slippage) that will be compared to the swapsExpectedReturn.\n *\n */\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view {\n uint256 destTokenAmount = _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n require(destTokenAmount >= minReturn, \"destTokenAmountReceived too low\");\n }\n}\n" + }, + "contracts/modules/SwapsImplSovrynSwapModule.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../swaps/connectors/SwapsImplSovrynSwapLib.sol\";\nimport \"../events/ModulesCommonEvents.sol\";\n\ncontract SwapsImplSovrynSwapModule is State, ModulesCommonEvents {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress =\n logicTargets[this.getSovrynSwapNetworkContract.selector];\n _setTarget(this.getSovrynSwapNetworkContract.selector, target);\n _setTarget(this.getContractHexName.selector, target);\n _setTarget(this.swapsImplExpectedRate.selector, target);\n _setTarget(this.swapsImplExpectedReturn.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"SwapsImplSovrynSwapModule\"\n );\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n return SwapsImplSovrynSwapLib.getContractHexName(source);\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n return SwapsImplSovrynSwapLib.getSovrynSwapNetworkContract(sovrynSwapRegistryAddress);\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return\n SwapsImplSovrynSwapLib.getExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn) {\n return\n SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n}\n" + }, + "contracts/multisig/MultiSigKeyHolders.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/Ownable.sol\";\n\n/**\n * @title Multi Signature Key Holders contract.\n *\n * This contract contains the implementation of functions to add and remove\n * key holders w/ rBTC and BTC addresses.\n * */\ncontract MultiSigKeyHolders is Ownable {\n /* Storage */\n\n uint256 public constant MAX_OWNER_COUNT = 50;\n\n string private constant ERROR_INVALID_ADDRESS = \"Invalid address\";\n string private constant ERROR_INVALID_REQUIRED = \"Invalid required\";\n\n /// Flag and index for Ethereum address.\n mapping(address => Data) private isEthereumAddressAdded;\n\n /// List of Ethereum addresses.\n address[] private ethereumAddresses;\n\n /// Required number of signatures for the Ethereum multisig.\n uint256 public ethereumRequired = 2;\n\n /// Flag and index for Bitcoin address.\n mapping(string => Data) private isBitcoinAddressAdded;\n\n /// List of Bitcoin addresses.\n string[] private bitcoinAddresses;\n\n /// Required number of signatures for the Bitcoin multisig.\n uint256 public bitcoinRequired = 2;\n\n /// Helps removing items from array.\n struct Data {\n bool added;\n uint248 index;\n }\n\n /* Events */\n\n event EthereumAddressAdded(address indexed account);\n event EthereumAddressRemoved(address indexed account);\n event EthereumRequirementChanged(uint256 required);\n event BitcoinAddressAdded(string account);\n event BitcoinAddressRemoved(string account);\n event BitcoinRequirementChanged(uint256 required);\n\n /* Modifiers */\n\n modifier validRequirement(uint256 ownerCount, uint256 _required) {\n require(\n ownerCount <= MAX_OWNER_COUNT &&\n _required <= ownerCount &&\n _required != 0 &&\n ownerCount != 0,\n ERROR_INVALID_REQUIRED\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function addEthereumAddress(address _address) public onlyOwner {\n _addEthereumAddress(_address);\n }\n\n /**\n * @notice Add rBTC addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function _addEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (!isEthereumAddressAdded[_address].added) {\n isEthereumAddressAdded[_address] = Data({\n added: true,\n index: uint248(ethereumAddresses.length)\n });\n ethereumAddresses.push(_address);\n }\n\n emit EthereumAddressAdded(_address);\n }\n\n /**\n * @notice Remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeEthereumAddress(address _address) public onlyOwner {\n _removeEthereumAddress(_address);\n }\n\n /**\n * @notice Remove rBTC addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (isEthereumAddressAdded[_address].added) {\n uint248 index = isEthereumAddressAdded[_address].index;\n if (index != ethereumAddresses.length - 1) {\n ethereumAddresses[index] = ethereumAddresses[ethereumAddresses.length - 1];\n isEthereumAddressAdded[ethereumAddresses[index]].index = index;\n }\n ethereumAddresses.length--;\n delete isEthereumAddressAdded[_address];\n }\n\n emit EthereumAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether rBTC address is a key holder.\n * @param _address The rBTC address to be checked.\n * */\n function isEthereumAddressOwner(address _address) public view returns (bool) {\n return isEthereumAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of rBTC key holders.\n * */\n function getEthereumAddresses() public view returns (address[] memory) {\n return ethereumAddresses;\n }\n\n /**\n * @notice Set flag ethereumRequired to true/false.\n * @param _required The new value of the ethereumRequired flag.\n * */\n function changeEthereumRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(ethereumAddresses.length, _required)\n {\n ethereumRequired = _required;\n emit EthereumRequirementChanged(_required);\n }\n\n /**\n * @notice Add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function addBitcoinAddress(string memory _address) public onlyOwner {\n _addBitcoinAddress(_address);\n }\n\n /**\n * @notice Add bitcoin addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function _addBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (!isBitcoinAddressAdded[_address].added) {\n isBitcoinAddressAdded[_address] = Data({\n added: true,\n index: uint248(bitcoinAddresses.length)\n });\n bitcoinAddresses.push(_address);\n }\n\n emit BitcoinAddressAdded(_address);\n }\n\n /**\n * @notice Remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeBitcoinAddress(string memory _address) public onlyOwner {\n _removeBitcoinAddress(_address);\n }\n\n /**\n * @notice Remove bitcoin addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (isBitcoinAddressAdded[_address].added) {\n uint248 index = isBitcoinAddressAdded[_address].index;\n if (index != bitcoinAddresses.length - 1) {\n bitcoinAddresses[index] = bitcoinAddresses[bitcoinAddresses.length - 1];\n isBitcoinAddressAdded[bitcoinAddresses[index]].index = index;\n }\n bitcoinAddresses.length--;\n delete isBitcoinAddressAdded[_address];\n }\n\n emit BitcoinAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether bitcoin address is a key holder.\n * @param _address The bitcoin address to be checked.\n * */\n function isBitcoinAddressOwner(string memory _address) public view returns (bool) {\n return isBitcoinAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of bitcoin key holders.\n * */\n function getBitcoinAddresses() public view returns (string[] memory) {\n return bitcoinAddresses;\n }\n\n /**\n * @notice Set flag bitcoinRequired to true/false.\n * @param _required The new value of the bitcoinRequired flag.\n * */\n function changeBitcoinRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(bitcoinAddresses.length, _required)\n {\n bitcoinRequired = _required;\n emit BitcoinRequirementChanged(_required);\n }\n\n /**\n * @notice Add rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress the rBTC addresses to be added.\n * @param _bitcoinAddress the bitcoin addresses to be added.\n * */\n function addEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _addEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _addBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n\n /**\n * @notice Remove rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress The rBTC addresses to be removed.\n * @param _bitcoinAddress The bitcoin addresses to be removed.\n * */\n function removeEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _removeEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _removeBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n}\n" + }, + "contracts/openzeppelin/Address.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256('')`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n codehash := extcodehash(account)\n }\n return (codehash != accountHash && codehash != 0x0);\n }\n\n /**\n * @dev Converts an `address` into `address payable`. Note that this is\n * simply a type cast: the actual underlying value is not changed.\n *\n * _Available since v2.4.0._\n */\n function toPayable(address account) internal pure returns (address payable) {\n return address(uint160(account));\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n *\n * _Available since v2.4.0._\n */\n function sendValue(address recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-call-value\n (bool success, ) = recipient.call.value(amount)(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n}\n" + }, + "contracts/openzeppelin/Context.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n // Empty internal constructor, to prevent people from mistakenly deploying\n // an instance of this contract, which should be used via inheritance.\n constructor() internal {}\n\n // solhint-disable-previous-line no-empty-blocks\n\n function _msgSender() internal view returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n" + }, + "contracts/openzeppelin/ERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./Context.sol\";\nimport \"./IERC20_.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20Mintable}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20_ {\n using SafeMath for uint256;\n\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20};\n *\n * Requirements:\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for `sender`'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n _allowances[sender][_msgSender()].sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n _approve(\n _msgSender(),\n spender,\n _allowances[_msgSender()][spender].sub(\n subtractedValue,\n \"ERC20: decreased allowance below zero\"\n )\n );\n return true;\n }\n\n /**\n * @dev Moves tokens `amount` from `sender` to `recipient`.\n *\n * This is internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _balances[sender] = _balances[sender].sub(\n amount,\n \"ERC20: transfer amount exceeds balance\"\n );\n _balances[recipient] = _balances[recipient].add(amount);\n emit Transfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n *\n * This is internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`.`amount` is then deducted\n * from the caller's allowance.\n *\n * See {_burn} and {_approve}.\n */\n function _burnFrom(address account, uint256 amount) internal {\n _burn(account, amount);\n _approve(\n account,\n _msgSender(),\n _allowances[account][_msgSender()].sub(amount, \"ERC20: burn amount exceeds allowance\")\n );\n }\n}\n" + }, + "contracts/openzeppelin/ERC20Detailed.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20_.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n */\ncontract ERC20Detailed is IERC20_ {\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n */\n constructor(\n string memory name,\n string memory symbol,\n uint8 decimals\n ) public {\n _name = name;\n _symbol = symbol;\n _decimals = decimals;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/openzeppelin/IERC20_.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20_ {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/openzeppelin/Initializable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n */\ncontract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(_initializing || !_initialized, \"Initializable: contract is already initialized\");\n\n bool isTopLevelCall = !_initializing;\n if (isTopLevelCall) {\n _initializing = true;\n _initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n _initializing = false;\n }\n }\n}\n" + }, + "contracts/openzeppelin/Ownable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() public view returns (bool) {\n return _msgSender() == _owner;\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public onlyOwner {\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n */\n function _transferOwnership(address newOwner) internal {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n}\n" + }, + "contracts/openzeppelin/PausableOz.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./Ownable.sol\";\n\ncontract PausableOz is Ownable {\n /**\n * @dev Emitted when the pause is triggered by the owner (`account`).\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by the owner (`account`).\n */\n event Unpaused(address account);\n\n bool internal _paused;\n\n constructor() internal {}\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n */\n modifier whenNotPaused() {\n require(!_paused, \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n */\n modifier whenPaused() {\n require(_paused, \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/openzeppelin/ReentrancyGuard.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title Helps contracts guard against reentrancy attacks.\n * @author Remco Bloemen , Eenae \n * @dev If you mark a function `nonReentrant`, you should also\n * mark it `external`.\n */\ncontract ReentrancyGuard {\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n" + }, + "contracts/openzeppelin/SafeERC20.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./SafeMath.sol\";\nimport \"./Address.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\n );\n }\n\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n // solhint-disable-next-line max-line-length\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance =\n token.allowance(address(this), spender).sub(\n value,\n \"SafeERC20: decreased allowance below zero\"\n );\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves.\n\n // A Solidity high level call has three parts:\n // 1. The target address is checked to verify it contains contract code\n // 2. The call itself is made, and success asserted\n // 3. The return value is decoded, which in turn checks the size of the returned data.\n // solhint-disable-next-line max-line-length\n require(address(token).isContract(), \"SafeERC20: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(data);\n require(success, \"SafeERC20: low-level call failed\");\n\n if (returndata.length > 0) {\n // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "contracts/openzeppelin/SafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n *\n * _Available since v2.4.0._\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\n return divCeil(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n\n if (a == 0) {\n return 0;\n }\n uint256 c = ((a - 1) / b) + 1;\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\n return _a < _b ? _a : _b;\n }\n}\n" + }, + "contracts/openzeppelin/SignedSafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title SignedSafeMath\n * @dev Signed math operations with safety checks that revert on error.\n */\nlibrary SignedSafeMath {\n int256 private constant _INT256_MIN = -2**255;\n\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n require(!(a == -1 && b == _INT256_MIN), \"SignedSafeMath: multiplication overflow\");\n\n int256 c = a * b;\n require(c / a == b, \"SignedSafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n require(b != 0, \"SignedSafeMath: division by zero\");\n require(!(b == -1 && a == _INT256_MIN), \"SignedSafeMath: division overflow\");\n\n int256 c = a / b;\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a - b;\n require((b >= 0 && c <= a) || (b < 0 && c > a), \"SignedSafeMath: subtraction overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a + b;\n require((b >= 0 && c >= a) || (b < 0 && c < a), \"SignedSafeMath: addition overflow\");\n\n return c;\n }\n}\n" + }, + "contracts/proxy/modules/interfaces/IFunctionsList.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\ninterface IFunctionsList {\n function getFunctionsList() external pure returns (bytes4[] memory functionSignatures);\n}\n" + }, + "contracts/proxy/modules/interfaces/IModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\n/**\n * ModulesProxyRegistry Interface\n */\n\ncontract IModulesProxyRegistry {\n event AddModule(address indexed moduleAddress);\n event ReplaceModule(address indexed oldAddress, address indexed newAddress);\n event RemoveModule(address indexed moduleAddress);\n event SetModuleFuncImplementation(\n bytes4 indexed _funcSig,\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use ReplaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external;\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl) external;\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external;\n\n /// @notice to disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external;\n\n /// @param _sig function signature to get impmementation address for\n /// @return function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address);\n\n /// @notice verifies if no functions from the module deployed already registered\n /// @param _impl module implementation address to verify\n /// @return true if module can be added\n function canAddModule(address _impl) external view returns (bool);\n\n /// @notice Multiple modules verification if no functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return True if all modules can be added, false otherwise\n function canNotAddModules(address[] calldata _implementations)\n external\n view\n returns (address[] memory modules);\n\n /// @notice used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n );\n}\n" + }, + "contracts/proxy/modules/ModulesProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"./ModulesProxyRegistry.sol\";\n\n/**\n * ModulesProxy serves as a storage processed by a set of logic contracts - modules\n * Modules functions are registered in the contract's slots generated per func sig\n * All the function calls except for own Proxy functions are delegated to\n * the registered functions\n * The ModulesProxy is designed as a universal solution for refactorig contracts\n * reaching a 24K size limit (EIP-170)\n *\n * Upgradability is implemented at a module level to provide consistency\n * It does not allow to replace separate functions - only the whole module\n * meaning that if a module being registered contains other modules function signatures\n * then these modulea should be replaced completely - all the functions should be removed\n * to avoid leftovers or accidental replacements and therefore functional inconsistency.\n *\n * A module is either a new non-overlapping with registered modules\n * or a complete replacement of another registered module\n * in which case all the old module functions are unregistered and then\n * the new module functions are registered\n * There is also a separate function to unregister a module which unregisters all the functions\n * There is no option to unregister a subset of module functions - one should use pausable functionality\n * to achieve this\n */\n\ncontract ModulesProxy is ModulesProxyRegistry {\n // Uncomment for using beforeFallback() hook\n /*\n bytes private constant BEFORE_FALLBACK_SIG = abi.encodeWithSignature(\"beforeFallback()\");\n bytes4 private constant BEFORE_FALLBACK_SIG_BYTES4 = bytes4(keccak256(abi.encodePacked(\"beforeFallback()\")));\n */\n\n /**\n * @notice Fallback function delegates calls to modules.\n * Returns whatever the implementation call returns.\n * Has a hook to execute before delegating calls\n * To activate register a module with beforeFallback() function\n */\n function() external payable {\n /*\n // Commented to safe gas by default\n // Uncomment for using beforeFallback() hook \n // Implement and register beforeFallback() function in a module\n address beforeFallback = _getFuncImplementation(BEFORE_FALLBACK_SIG_BYTES4);\n if (beforeFallback != address(0)) {\n (bool success, ) = beforeFallback.delegatecall(bytes(0x39b0111a)); // abi.encodeWithSignature(\"beforeFallback()\")\n require(success, \"ModulesProxy::fallback: beforeFallback() fail\"); //MP02\n }\n */\n\n address target = _getFuncImplementation(msg.sig);\n require(target != address(0), \"ModulesProxy:target module not registered\"); // MP03\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/modules/ModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"../../utils/Utils.sol\";\nimport \"../../utils/ProxyOwnable.sol\";\nimport \"../modules/interfaces/IFunctionsList.sol\";\nimport \"../modules/interfaces/IModulesProxyRegistry.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * ModulesProxyRegistry provides modules registration/removing/replacing functionality to ModulesProxy\n * Designed to be inherited\n */\n\ncontract ModulesProxyRegistry is IModulesProxyRegistry, ProxyOwnable {\n using Address for address;\n\n bytes32 internal constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n\n ///@notice Constructor is internal to make contract abstract\n constructor() internal {\n // abstract\n }\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use replaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external onlyProxyOwner {\n _addModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external onlyProxyOwner {\n _addModules(_implementations);\n }\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl)\n external\n onlyProxyOwner\n {\n _replaceModule(_oldModuleImpl, _newModuleImpl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external onlyProxyOwner {\n require(\n _implementationsFrom.length == _implementationsTo.length,\n \"ModulesProxyRegistry::replaceModules: arrays sizes must be equal\"\n ); //MR10\n\n // because the order of addresses is arbitrary, all modules are removed first to avoid collisions\n _removeModules(_implementationsFrom);\n _addModules(_implementationsTo);\n }\n\n /// @notice To disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external onlyProxyOwner {\n _removeModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external onlyProxyOwner {\n _removeModules(_implementations);\n }\n\n /// @param _sig Function signature to get impmementation address for\n /// @return Function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address) {\n return _getFuncImplementation(_sig);\n }\n\n /// @notice Verifies if no functions from the module already registered\n /// @param _impl Module implementation address to verify\n /// @return True if module can be added\n function canAddModule(address _impl) external view returns (bool) {\n return _canAddModule(_impl);\n }\n\n /// @notice Multiple modules verification if there are functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return addresses of registered modules\n function canNotAddModules(address[] memory _implementations)\n public\n view\n returns (address[] memory)\n {\n for (uint256 i = 0; i < _implementations.length; i++) {\n if (_canAddModule(_implementations[i])) {\n delete _implementations[i];\n }\n }\n return _implementations;\n }\n\n /// @notice Used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return Clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n )\n {\n require(\n _newModule.isContract(),\n \"ModulesProxyRegistry::checkClashingFuncSelectors: address is not a contract\"\n ); //MR06\n bytes4[] memory newModuleFunctions = IFunctionsList(_newModule).getFunctionsList();\n bytes4[] memory proxyRegistryFunctions = _getFunctionsList(); //registry functions list\n uint256 clashingProxyRegistryFuncsSize;\n uint256 clashingArraySize;\n uint256 clashingArrayIndex;\n uint256 clashingRegistryArrayIndex;\n\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0) && funcImpl != _newModule) {\n clashingArraySize++;\n } else if (_isFuncClashingWithProxyFunctions(newModuleFunctions[i]))\n clashingProxyRegistryFuncsSize++;\n }\n clashingModules = new address[](clashingArraySize);\n clashingModulesFuncSelectors = new bytes4[](clashingArraySize);\n clashingProxyRegistryFuncSelectors = new bytes4[](clashingProxyRegistryFuncsSize);\n\n if (clashingArraySize == 0 && clashingProxyRegistryFuncsSize == 0)\n //return empty arrays\n return (\n clashingModules,\n clashingModulesFuncSelectors,\n clashingProxyRegistryFuncSelectors\n );\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0)) {\n clashingModules[clashingArrayIndex] = funcImpl;\n clashingModulesFuncSelectors[clashingArrayIndex] = newModuleFunctions[i];\n clashingArrayIndex++;\n }\n for (uint256 j = 0; j < proxyRegistryFunctions.length; j++) {\n //ModulesProxyRegistry has a clashing function selector\n if (proxyRegistryFunctions[j] == newModuleFunctions[i]) {\n clashingProxyRegistryFuncSelectors[\n clashingRegistryArrayIndex\n ] = proxyRegistryFunctions[j];\n clashingRegistryArrayIndex++;\n }\n }\n }\n }\n\n /// Verifies the deployed contract address is a registered module contract\n /// @param _impl deployment address to verify\n /// @return true if _impl address is a registered module\n function isModuleRegistered(address _impl) external view returns (bool) {\n return _getFirstRegisteredModuleAddress(_impl) == _impl;\n }\n\n /****************** INTERNAL FUNCTIONS ******************/\n\n function _getFirstRegisteredModuleAddress(address _impl) internal view returns (address) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_getRegisteredModuleAddress: address is not a contract\"\n );\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n address _moduleImpl = _getFuncImplementation(functions[i]);\n if (_moduleImpl != address(0)) {\n return (_moduleImpl);\n }\n }\n return address(0);\n }\n\n function _getFuncImplementation(bytes4 _sig) internal view returns (address) {\n //TODO: add querying Registry for logic address and then delegate call to it OR use proxy memory slots like this:\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n address implementation;\n assembly {\n implementation := sload(key)\n }\n return implementation;\n }\n\n function _addModule(address _impl) internal {\n require(_impl.isContract(), \"ModulesProxyRegistry::_addModule: address is not a contract\"); //MR01\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n require(\n _getFuncImplementation(functions[i]) == address(0),\n \"ModulesProxyRegistry::_addModule: function already registered - use replaceModule function\"\n ); //MR02\n require(functions[i] != bytes4(0), \"does not allow empty function id\"); // MR03\n require(\n !_isFuncClashingWithProxyFunctions(functions[i]),\n \"ModulesProxyRegistry::_addModule: has a function with the same signature\"\n ); //MR09\n _setModuleFuncImplementation(functions[i], _impl);\n }\n emit AddModule(_impl);\n }\n\n function _addModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _addModule(_implementations[i]);\n }\n }\n\n function _removeModule(address _impl) internal onlyProxyOwner {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_removeModule: address is not a contract\"\n ); //MR07\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n _setModuleFuncImplementation(functions[i], address(0));\n\n emit RemoveModule(_impl);\n }\n\n function _removeModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _removeModule(_implementations[i]);\n }\n }\n\n function _replaceModule(address _oldModuleImpl, address _newModuleImpl) internal {\n if (_oldModuleImpl != _newModuleImpl) {\n require(\n _newModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _newModuleImpl is not a contract\"\n ); //MR03\n require(\n _oldModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _oldModuleImpl is not a contract\"\n ); //MR04\n _removeModule(_oldModuleImpl);\n _addModule(_newModuleImpl);\n\n emit ReplaceModule(_oldModuleImpl, _newModuleImpl);\n }\n }\n\n function _setModuleFuncImplementation(bytes4 _sig, address _impl) internal {\n emit SetModuleFuncImplementation(_sig, _getFuncImplementation(_sig), _impl);\n\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n assembly {\n sstore(key, _impl)\n }\n }\n\n function _isFuncClashingWithProxyFunctions(bytes4 _sig) internal pure returns (bool) {\n bytes4[] memory functionList = _getFunctionsList();\n for (uint256 i = 0; i < functionList.length; i++) {\n if (_sig == functionList[i])\n //ModulesProxyRegistry has function with the same id\n return true;\n }\n return false;\n }\n\n function _canAddModule(address _impl) internal view returns (bool) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_canAddModule: address is not a contract\"\n ); //MR06\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n if (_getFuncImplementation(functions[i]) != address(0)) return (false);\n return true;\n }\n\n function _getFunctionsList() internal pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](13);\n functionList[0] = this.getFuncImplementation.selector;\n functionList[1] = this.addModule.selector;\n functionList[2] = this.addModules.selector;\n functionList[3] = this.removeModule.selector;\n functionList[4] = this.removeModules.selector;\n functionList[5] = this.replaceModule.selector;\n functionList[6] = this.replaceModules.selector;\n functionList[7] = this.canAddModule.selector;\n functionList[8] = this.canNotAddModules.selector;\n functionList[9] = this.setProxyOwner.selector;\n functionList[10] = this.getProxyOwner.selector;\n functionList[11] = this.checkClashingFuncSelectors.selector;\n functionList[12] = this.isModuleRegistered.selector;\n return functionList;\n }\n}\n" + }, + "contracts/proxy/Proxy.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base Proxy contract.\n * @notice The proxy performs delegated calls to the contract implementation\n * it is pointing to. This way upgradable contracts are possible on blockchain.\n *\n * Delegating proxy contracts are widely used for both upgradeability and gas\n * savings. These proxies rely on a logic contract (also known as implementation\n * contract or master copy) that is called using delegatecall. This allows\n * proxies to keep a persistent state (storage and balance) while the code is\n * delegated to the logic contract.\n *\n * Proxy contract is meant to be inherited and its internal functions\n * _setImplementation and _setProxyOwner to be called when upgrades become\n * neccessary.\n *\n * The loan token (iToken) contract as well as the protocol contract act as\n * proxies, delegating all calls to underlying contracts. Therefore, if you\n * want to interact with them using web3, you need to use the ABIs from the\n * contracts containing the actual logic or the interface contract.\n * ABI for LoanToken contracts: LoanTokenLogicStandard\n * ABI for Protocol contract: ISovryn\n *\n * @dev UpgradableProxy is the contract that inherits Proxy and wraps these\n * functions.\n * */\ncontract Proxy {\n bytes32 private constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);\n event ImplementationChanged(\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /**\n * @notice Set sender as an owner.\n * */\n constructor() public {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @notice Throw error if called not by an owner.\n * */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Proxy:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the implementation.\n * @param _implementation Address of the implementation.\n * */\n function _setImplementation(address _implementation) internal {\n require(_implementation != address(0), \"Proxy::setImplementation: invalid address\");\n emit ImplementationChanged(getImplementation(), _implementation);\n\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n sstore(key, _implementation)\n }\n }\n\n /**\n * @notice Return address of the implementation.\n * @return Address of the implementation.\n * */\n function getImplementation() public view returns (address _implementation) {\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n _implementation := sload(key)\n }\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"Proxy::setProxyOwner: invalid address\");\n emit OwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Return address of the owner.\n * @return Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n address implementation = getImplementation();\n require(implementation != address(0), \"Proxy::(): implementation not found\");\n\n assembly {\n let pointer := mload(0x40)\n calldatacopy(pointer, 0, calldatasize)\n let result := delegatecall(gas, implementation, pointer, calldatasize, 0, 0)\n let size := returndatasize\n returndatacopy(pointer, 0, size)\n\n switch result\n case 0 {\n revert(pointer, size)\n }\n default {\n return(pointer, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/UpgradableProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Proxy.sol\";\n\n/**\n * @title Upgradable Proxy contract.\n * @notice A disadvantage of the immutable ledger is that nobody can change the\n * source code of a smart contract after it’s been deployed. In order to fix\n * bugs or introduce new features, smart contracts need to be upgradable somehow.\n *\n * Although it is not possible to upgrade the code of an already deployed smart\n * contract, it is possible to set-up a proxy contract architecture that will\n * allow to use new deployed contracts as if the main logic had been upgraded.\n *\n * A proxy architecture pattern is such that all message calls go through a\n * Proxy contract that will redirect them to the latest deployed contract logic.\n * To upgrade, a new version of the contract is deployed, and the Proxy is\n * updated to reference the new contract address.\n * */\ncontract UpgradableProxy is Proxy {\n /**\n * @notice Set address of the implementation.\n * @dev Wrapper for _setImplementation that exposes the function\n * as public for owner to be able to set a new version of the\n * contract as current pointing implementation.\n * @param _implementation Address of the implementation.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n _setImplementation(_implementation);\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n}\n" + }, + "contracts/reentrancy/Mutex.sol": { + "content": "pragma solidity ^0.5.17;\n\n/*\n * @title Global Mutex contract\n *\n * @notice A mutex contract that allows only one function to be called at a time out\n * of a large set of functions. *Anyone* in the network can freely use any instance\n * of this contract to add a universal mutex to any function in any contract.\n */\ncontract Mutex {\n /*\n * We use an uint to store the mutex state.\n */\n uint256 public value;\n\n /*\n * @notice Increment the mutex state and return the new value.\n *\n * @dev This is the function that will be called by anyone to change the mutex\n * state. It is purposely not protected by any access control\n */\n function incrementAndGetValue() external returns (uint256) {\n /*\n * increment value using unsafe math. This is safe because we are\n * pretty certain no one will ever increment the value 2^256 times\n * in a single transaction.\n */\n return ++value;\n }\n}\n" + }, + "contracts/reentrancy/SharedReentrancyGuard.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Mutex.sol\";\n\n/*\n * @title Abstract contract for shared reentrancy guards\n *\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\n * that there's no reentrancy between *any* functions marked with the modifier.\n *\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\n */\ncontract SharedReentrancyGuard {\n /*\n * This is the address of the mutex contract that will be used as the\n * reentrancy guard.\n *\n * The address is hardcoded to avoid changing the memory layout of\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\n * because the Mutex contract is always deployed to the same address, with the\n * same method used in the deployment of ERC1820Registry.\n */\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\n\n /*\n * This is the modifier that will be used to protect functions from\n * reentrancy. It will call the mutex contract to increment the mutex\n * state and then revert if the mutex state was changed by another\n * nested call.\n */\n modifier globallyNonReentrant() {\n uint256 previous = MUTEX.incrementAndGetValue();\n\n _;\n\n /*\n * If the mutex state was changed by a nested function call, then\n * the value of the state variable will be different from the previous value.\n */\n require(previous == MUTEX.value(), \"reentrancy violation\");\n }\n}\n" + }, + "contracts/rsk/RSKAddrValidator.sol": { + "content": "// SPDX-License-Identifier:MIT\npragma solidity ^0.5.17;\n\nlibrary RSKAddrValidator {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n * */\n function checkPKNotZero(address addr) internal pure returns (bool) {\n return (addr != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && addr != address(0));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key.\n * */\n function safeEquals(address addr1, address addr2) internal pure returns (bool) {\n return (addr1 == addr2 &&\n addr1 != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\n addr1 != address(0));\n }\n}\n" + }, + "contracts/swaps/connectors/interfaces/IContractRegistry.sol": { + "content": "pragma solidity 0.5.17;\n\ncontract IContractRegistry {\n function addressOf(bytes32 contractName) public view returns (address);\n}\n" + }, + "contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol": { + "content": "pragma solidity >=0.5.8 <=0.5.17;\n\nimport \"../../../interfaces/IERC20.sol\";\n\ncontract ISovrynSwapNetwork {\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256);\n\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\n\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory);\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwap.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../../core/State.sol\";\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\n\n/**\n * @dev WARNING: This contract is deprecated, all public functions are moved to the protocol modules.\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\ncontract SwapsImplSovrynSwap is State {\n using SafeERC20 for IERC20;\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n constructor() internal {\n // abstract\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destination tokens.\n * @param receiverAddress The address who will received the swap token results\n * @param returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * @param minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * @param maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address receiverAddress,\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n require(\n supportedTokens[sourceTokenAddress] && supportedTokens[destTokenAddress],\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = estimateSourceTokenAmount(\n sourceTokenAddress,\n destTokenAddress,\n requiredDestTokenAmount,\n maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n allowTransfer(sourceTokenAmountUsed, sourceTokenAddress, address(sovrynSwapNetwork));\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n uint256 sourceToDestPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n internalExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n maxSourceTokenAmount,\n sovrynSwapContractRegistryAddress\n );\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > sourceBuffer) buffer = sourceBuffer;\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistryAddress\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * @param sovrynSwapContractRegistry The sovryn swap contract reigstry address.\n * @param defaultPath The default path for specific pairs.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistry,\n IERC20[] memory defaultPath\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistry);\n\n IERC20[] memory path =\n defaultPath.length >= 3\n ? defaultPath\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\nimport \"../../interfaces/ISovryn.sol\";\n\n/**\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\nlibrary SwapsImplSovrynSwapLib {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n struct SwapParams {\n address sourceTokenAddress;\n address destTokenAddress;\n address receiverAddress;\n address returnToSenderAddress;\n uint256 minSourceTokenAmount;\n uint256 maxSourceTokenAmount;\n uint256 requiredDestTokenAmount;\n }\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param params SwapParams struct\n * sourceTokenAddress The address of the source tokens.\n * destTokenAddress The address of the destination tokens.\n * receiverAddress The address who will received the swap token results\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * requiredDestTokenAmount The required amount of destination tokens.\n * */\n function swap(SwapParams memory params)\n public\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(params.sourceTokenAddress != params.destTokenAddress, \"source == dest\");\n\n ISovryn iSovryn = ISovryn(address(this));\n require(\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\n iSovryn.supportedTokens(params.destTokenAddress),\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\n\n IERC20[] memory path =\n _getConversionPath(\n params.sourceTokenAddress,\n params.destTokenAddress,\n sovrynSwapNetwork\n );\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = params.minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (params.requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\n params.sourceTokenAddress,\n params.destTokenAddress,\n params.requiredDestTokenAmount,\n params.maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n params.requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = params.requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n _allowTransfer(\n sourceTokenAmountUsed,\n params.sourceTokenAddress,\n address(sovrynSwapNetwork)\n );\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n params.receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (params.returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(params.sourceTokenAddress).safeTransfer(\n params.returnToSenderAddress,\n params.maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function _allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function _estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n ISovryn iSovryn = ISovryn(address(this));\n uint256 sourceToDestPrecision =\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function getExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function getExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function _getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/testnet/SwapsImplLocal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../../core/State.sol\";\nimport \"../../../openzeppelin/SafeERC20.sol\";\nimport \"../../../feeds/IPriceFeeds.sol\";\nimport \"../../../testhelpers/TestToken.sol\";\n\n/**\n * @title Swaps Implementation Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate calculations.\n * */\ncontract SwapsImplLocal is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Swap two tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address, /*receiverAddress*/\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n\n (uint256 tradeRate, uint256 precision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n if (requiredDestTokenAmount == 0) {\n sourceTokenAmountUsed = minSourceTokenAmount;\n destTokenAmountReceived = minSourceTokenAmount.mul(tradeRate).div(precision);\n } else {\n destTokenAmountReceived = requiredDestTokenAmount;\n sourceTokenAmountUsed = requiredDestTokenAmount.mul(precision).div(tradeRate);\n require(sourceTokenAmountUsed <= minSourceTokenAmount, \"destAmount too great\");\n }\n\n TestToken(sourceTokenAddress).burn(address(this), sourceTokenAmountUsed);\n TestToken(destTokenAddress).mint(address(this), destTokenAmountReceived);\n\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Calculate the expected price rate of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n *\n * @return precision The expected price rate.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * @notice Calculate the expected return of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n * @param defaultPath defaultPath for swap.\n *\n * @return precision The expected return.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused,\n IERC20[] memory defaultPath\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n}\n" + }, + "contracts/swaps/SwapsUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../mixins/FeesHelper.sol\";\nimport \"./connectors/SwapsImplSovrynSwapLib.sol\";\n\n/**\n * @title Perform token swaps for loans and trades.\n * */\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\n /**\n * @notice Internal loan swap.\n *\n * @param loanId The ID of the loan.\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of destination tokens.\n * @param user The user address.\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * @param bypassFee To bypass or not the fee.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived\n * @return sourceTokenAmountUsed\n * @return sourceToDestSwapRate\n * */\n function _loanSwap(\n bytes32 loanId,\n address sourceToken,\n address destToken,\n address user,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount,\n bool bypassFee,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 sourceToDestSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n address(this), // receiver\n address(this), // returnToSender\n user\n ],\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\n loanId,\n bypassFee,\n loanDataBytes,\n false // swap external flag, set to false so that it will use the tradingFeePercent\n );\n\n /// Will revert if swap size too large.\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\n\n /// Will revert if disagreement found.\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived,\n maxDisagreement\n );\n\n emit LoanSwap(\n loanId,\n sourceToken,\n destToken,\n user,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Wrapper for _swapsCall_internal function.\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n * @param loanId The Id of the associated loan.\n * @param miscBool True/false to bypassFee.\n * @param loanDataBytes Additional loan data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall(\n address[5] memory addrs,\n uint256[3] memory vals,\n bytes32 loanId,\n bool miscBool, /// bypassFee\n bytes memory loanDataBytes,\n bool isSwapExternal\n ) internal returns (uint256, uint256) {\n /// addrs[0]: sourceToken\n /// addrs[1]: destToken\n /// addrs[2]: receiver\n /// addrs[3]: returnToSender\n /// addrs[4]: user\n /// vals[0]: minSourceTokenAmount\n /// vals[1]: maxSourceTokenAmount\n /// vals[2]: requiredDestTokenAmount\n\n require(vals[0] != 0 || vals[1] != 0, \"min or max source token amount needs to be set\");\n\n if (vals[1] == 0) {\n vals[1] = vals[0];\n }\n require(vals[0] <= vals[1], \"sourceAmount larger than max\");\n\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n\n uint256 tradingFee;\n if (!miscBool) {\n /// bypassFee\n if (vals[2] == 0) {\n /// condition: vals[0] will always be used as sourceAmount\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[0]);\n } else {\n tradingFee = _getTradingFee(vals[0]);\n }\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId,\n addrs[0], /// sourceToken (feeToken)\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n vals[0] = vals[0].sub(tradingFee);\n }\n } else {\n /// Condition: unknown sourceAmount will be used.\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[2]);\n } else {\n tradingFee = _getTradingFee(vals[2]);\n }\n\n if (tradingFee != 0) {\n vals[2] = vals[2].add(tradingFee);\n }\n }\n }\n\n require(loanDataBytes.length == 0, \"invalid state\");\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\n\n if (vals[2] == 0) {\n /// There's no minimum destTokenAmount, but all of vals[0]\n /// (minSourceTokenAmount) must be spent.\n require(sourceTokenAmountUsed == vals[0], \"swap too large to fill\");\n\n if (tradingFee != 0) {\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\n }\n } else {\n /// There's a minimum destTokenAmount required, but\n /// sourceTokenAmountUsed won't be greater\n /// than vals[1] (maxSourceTokenAmount)\n require(sourceTokenAmountUsed <= vals[1], \"swap fill too large\");\n require(destTokenAmountReceived >= vals[2], \"insufficient swap liquidity\");\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId, /// loanId,\n addrs[1], /// destToken (feeToken)\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\n }\n }\n\n return (destTokenAmountReceived, sourceTokenAmountUsed);\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Calls swapsImpl::internalSwap\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\n internal\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n SwapsImplSovrynSwapLib.SwapParams memory swapParams;\n\n swapParams.sourceTokenAddress = addrs[0];\n swapParams.destTokenAddress = addrs[1];\n swapParams.receiverAddress = addrs[2];\n swapParams.returnToSenderAddress = addrs[3];\n swapParams.minSourceTokenAmount = vals[0];\n swapParams.maxSourceTokenAmount = vals[1];\n swapParams.requiredDestTokenAmount = vals[2];\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = SwapsImplSovrynSwapLib.swap(swapParams);\n }\n\n /**\n * @notice Calculate expected amount of destination tokens.\n *\n * @dev Calls swapsImpl::internalExpectedReturn\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destination tokens.\n * @param sourceTokenAmount The amount of the source tokens.\n *\n * @param destTokenAmount The amount of destination tokens.\n * */\n function _swapsExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) internal view returns (uint256 destTokenAmount) {\n destTokenAmount = SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceToken,\n destToken,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Verify that the amount of tokens are under the swap limit.\n *\n * @dev Calls priceFeeds::amountInEth\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n * */\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\n uint256 _maxSwapSize = maxSwapSize;\n if (_maxSwapSize != 0) {\n uint256 amountInEth;\n if (tokenAddress == address(wrbtcToken)) {\n amountInEth = amount;\n } else {\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\n }\n require(amountInEth <= _maxSwapSize, \"swap too large\");\n }\n }\n}\n" + }, + "contracts/testhelpers/FlashLoanerTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n// \"SPDX-License-Identifier: Apache-2.0\"\n\nimport \"../interfaces/IERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./ITokenFlashLoanTest.sol\";\n\ncontract FlashLoanerTest is Ownable {\n function initiateFlashLoanTest(\n address loanToken,\n address iToken,\n uint256 flashLoanAmount\n ) internal returns (bytes memory success) {\n ITokenFlashLoanTest iTokenContract = ITokenFlashLoanTest(iToken);\n return\n iTokenContract.flashBorrow(\n flashLoanAmount,\n address(this),\n address(this),\n \"\",\n abi.encodeWithSignature(\n \"executeOperation(address,address,uint256)\",\n loanToken,\n iToken,\n flashLoanAmount\n )\n );\n }\n\n function repayFlashLoan(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) internal {\n IERC20(loanToken).transfer(iToken, loanAmount);\n }\n\n function executeOperation(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) external returns (bytes memory success) {\n emit BalanceOf(IERC20(loanToken).balanceOf(address(this)));\n emit ExecuteOperation(loanToken, iToken, loanAmount);\n repayFlashLoan(loanToken, iToken, loanAmount);\n return bytes(\"1\");\n }\n\n function doStuffWithFlashLoan(\n address token,\n address iToken,\n uint256 amount\n ) external onlyOwner {\n bytes memory result;\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n result = initiateFlashLoanTest(token, iToken, amount);\n\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n // after loan checks and what not.\n if (hashCompareWithLengthCheck(bytes(\"1\"), result)) {\n revert(\"failed executeOperation\");\n }\n }\n\n function hashCompareWithLengthCheck(bytes memory a, bytes memory b)\n internal\n pure\n returns (bool)\n {\n if (a.length != b.length) {\n return false;\n } else {\n return keccak256(a) == keccak256(b);\n }\n }\n\n event ExecuteOperation(address loanToken, address iToken, uint256 loanAmount);\n\n event BalanceOf(uint256 balance);\n}\n" + }, + "contracts/testhelpers/interfaces/IERC1820Registry.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the global ERC1820 Registry, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register\n * implementers for interfaces in this registry, as well as query support.\n *\n * Implementers may be shared by multiple accounts, and can also implement more\n * than a single interface for each account. Contracts can implement interfaces\n * for themselves, but externally-owned accounts (EOA) must delegate this to a\n * contract.\n *\n * {IERC165} interfaces can also be queried via the registry.\n *\n * For an in-depth explanation and source code analysis, see the EIP text.\n */\ninterface IERC1820Registry {\n /**\n * @dev Sets `newManager` as the manager for `account`. A manager of an\n * account is able to set interface implementers for it.\n *\n * By default, each account is its own manager. Passing a value of `0x0` in\n * `newManager` will reset the manager to this initial state.\n *\n * Emits a {ManagerChanged} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n */\n function setManager(address account, address newManager) external;\n\n /**\n * @dev Returns the manager for `account`.\n *\n * See {setManager}.\n */\n function getManager(address account) external view returns (address);\n\n /**\n * @dev Sets the `implementer` contract as `account`'s implementer for\n * `interfaceHash`.\n *\n * `account` being the zero address is an alias for the caller's address.\n * The zero address can also be used in `implementer` to remove an old one.\n *\n * See {interfaceHash} to learn how these are created.\n *\n * Emits an {InterfaceImplementerSet} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not\n * end in 28 zeroes).\n * - `implementer` must implement {IERC1820Implementer} and return true when\n * queried for support, unless `implementer` is the caller. See\n * {IERC1820Implementer-canImplementInterfaceForAddress}.\n */\n function setInterfaceImplementer(\n address account,\n bytes32 interfaceHash,\n address implementer\n ) external;\n\n /**\n * @dev Returns the implementer of `interfaceHash` for `account`. If no such\n * implementer is registered, returns the zero address.\n *\n * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28\n * zeroes), `account` will be queried for support of it.\n *\n * `account` being the zero address is an alias for the caller's address.\n */\n function getInterfaceImplementer(address account, bytes32 interfaceHash)\n external\n view\n returns (address);\n\n /**\n * @dev Returns the interface hash for an `interfaceName`, as defined in the\n * corresponding\n * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].\n */\n function interfaceHash(string calldata interfaceName) external pure returns (bytes32);\n\n /**\n * @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n * @param account Address of the contract for which to update the cache.\n * @param interfaceId ERC165 interface for which to update the cache.\n */\n function updateERC165Cache(address account, bytes4 interfaceId) external;\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not.\n * If the result is not cached a direct lookup on the contract address is performed.\n * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n * {updateERC165Cache} with the contract address.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165Interface(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n event InterfaceImplementerSet(\n address indexed account,\n bytes32 indexed interfaceHash,\n address indexed implementer\n );\n\n event ManagerChanged(address indexed account, address indexed newManager);\n}\n" + }, + "contracts/testhelpers/ITokenFlashLoanTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n// \"SPDX-License-Identifier: Apache-2.0\"\n\ninterface ITokenFlashLoanTest {\n function flashBorrow(\n uint256 borrowAmount,\n address borrower,\n address target,\n string calldata signature,\n bytes calldata data\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/testhelpers/LoanTokenLogicTest.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicTest is LoanTokenLogic {\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestNonReentrantValueSetter.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\ncontract TestNonReentrantValueSetter is SharedReentrancyGuard {\n uint256 public value;\n\n // This will fail if another globallyNonReentrant function has already been entered\n function setValue(uint256 newValue) public globallyNonReentrant {\n value = newValue;\n }\n\n // this will always fail if `other.setValue` is globallyNonReentrant\n function setOtherContractValueNonReentrant(address other, uint256 newValue)\n external\n globallyNonReentrant\n {\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n\n // this is intentionally not globallyNonReentrant and should work even if both contracts are non-reentrant\n function setThisAndOtherContractValue(address other, uint256 newValue) external {\n setValue(newValue);\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestValueSetterProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract TestValueSetterProxy is UpgradableProxy {\n // This is here for the memory layout\n uint256 public value;\n}\n" + }, + "contracts/testhelpers/staking/StakingTester.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../TestToken.sol\";\n\ncontract StakingTester {\n IStaking public staking;\n TestToken public token;\n\n constructor(address _staking, address _token) public {\n staking = IStaking(_staking);\n token = TestToken(_token);\n }\n\n function stakeAndWithdraw(uint96 _amount, uint256 _until) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _until, address(this), address(this));\n staking.withdraw(_amount, _until, address(this));\n }\n\n function stakeAndDelegate(\n uint96 _amount,\n address _delegatee,\n uint256 _lockDate\n ) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _lockDate, address(this), address(this));\n staking.delegate(_delegatee, _lockDate);\n }\n}\n" + }, + "contracts/testhelpers/TestCoverage.sol": { + "content": "/**\n * In order to test some functionalities like Pausable::pausable() modifier,\n * it is required to add a contract to invoke them and get a full coverage on tests.\n */\n\npragma solidity 0.5.17;\n\nimport \"../connectors/loantoken/Pausable.sol\";\nimport \"../governance/Staking/SafeMath96.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../connectors/loantoken/AdvancedToken.sol\";\nimport \"../connectors/loantoken/LoanTokenLogicStorage.sol\";\n\ncontract TestCoverage is\n Pausable,\n SafeMath96,\n VaultController,\n AdvancedToken,\n LoanTokenLogicStorage\n{\n /// @dev Pausable is currently an unused contract that still is operative\n /// because margin trade flashloan functionality has been commented out.\n /// In case it were restored, contract would become used again, so for a\n /// complete test coverage it is required to test it.\n\n function dummyPausableFunction() external pausable(msg.sig) {\n /// @dev do nothing, just to check if modifier is working\n }\n\n /// @dev This function should be located on Pausable contract in the case\n /// it has to be used again by flashloan restoration.\n function togglePause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047)\n )\n );\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /// @dev Testing internal functions of governance/Staking/SafeMath96.sol\n function testSafeMath96_safe32(uint256 n) public pure returns (uint32) {\n // Public wrapper for SafeMath96 internal function\n return safe32(n, \"overflow\");\n }\n\n function testSafeMath96_safe64(uint256 n) public pure returns (uint64) {\n // Public wrapper for SafeMath96 internal function\n return safe64(n, \"overflow\");\n }\n\n function testSafeMath96_safe96(uint256 n) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return safe96(n, \"overflow\");\n }\n\n function testSafeMath96_sub96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return sub96(a, b, \"underflow\");\n }\n\n function testSafeMath96_mul96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return mul96(a, b, \"overflow\");\n }\n\n function testSafeMath96_div96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return div96(a, b, \"division by 0\");\n }\n\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;\n EnumerableBytes32Set.Bytes32Set internal aSet;\n\n function testEnum_AddRemove(bytes32 a, bytes32 b) public returns (bool) {\n aSet.addBytes32(a);\n return aSet.removeBytes32(b);\n }\n\n function testEnum_AddAddress(address a, address b) public returns (bool) {\n aSet.addAddress(a);\n return aSet.containsAddress(b);\n }\n\n function testEnum_AddAddressesAndEnumerate(\n address a,\n address b,\n uint256 start,\n uint256 count\n ) public returns (bytes32[] memory) {\n aSet.addAddress(a);\n aSet.addAddress(b);\n return aSet.enumerate(start, count);\n }\n\n /// @dev Wrapper to test internal function never called along current codebase\n function testVaultController_vaultApprove(\n address token,\n address to,\n uint256 value\n ) public {\n vaultApprove(token, to, value);\n }\n\n /// @dev mint wrapper w/o previous checks\n function testMint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) public {\n _mint(_to, _tokenAmount, _assetAmount, _price);\n }\n\n /// @dev wrapper for a function unreachable to tests\n function testStringToBytes32(string memory source) public pure returns (bytes32 result) {\n return stringToBytes32(source);\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some ERC777 from the lending pool.\n * 2. Close the loan with closeWithDeposit function in the protocol.\n * 3. Burn all iERC777.\n *\n * The cross-reentrancy happened in step#3. It might happened through a hook function (tokensToSend) that is implemented in this contract to support the ERC777 transfer.\n * Inside the hook function, it will try to mint the iERC777.\n * The details about the hook functions can be found here: https://eips.ethereum.org/EIPS/eip-777#hooks\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithDeposit function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyERC777 {\n address public loanToken;\n address public WRBTC;\n address public SUSD; /// ERC777\n ProtocolLike public sovrynProtocol;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iUSDTBalance;\n }\n\n function() external payable {}\n\n constructor(\n address _loanToken,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanToken = _loanToken;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777TokensSender\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: WRBTC has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n });\n\n IERC20(WRBTC).approve(loanToken, initial.susdBalance);\n\n ILoanTokenModules(loanToken).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n WRBTC,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanToken).loanParamsIds(\n uint256(keccak256(abi.encodePacked(WRBTC, true)))\n );\n bytes32 loan_id =\n keccak256(abi.encodePacked(loanParamsLocalId, loanToken, _borrower, _borrowerNonce));\n\n // STEP 3 close the borrowed position with a deposit\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(address(sovrynProtocol), _SUSDBalance);\n sovrynProtocol.closeWithDeposit(\n loan_id,\n address(this),\n collateralTokenSent.mul(20).div(100) // make it 20% higher from initial borrow amount\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iSUSD\n uint256 _iSUSDBalance = ILoanTokenModules(loanToken).balanceOf(_borrower);\n ILoanTokenModules(loanToken).burn(_receiver, _iSUSDBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n // });\n }\n\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256,\n bytes calldata,\n bytes calldata\n ) external {\n if (operator == address(sovrynProtocol) && to == loanToken && from == address(this)) {\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(loanToken, _SUSDBalance);\n\n ILoanTokenModules(loanToken).mint(address(this), 1000000 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyRBTC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some WRBTC from the lending pool.\n * 2. Close the loan with closeWithSwap function in the protocol.\n * 3. Burn all iWRBTC.\n *\n * The refund happened in step #3, which will send back the RBTC back to this contract.\n * Then, this contract will try to do another iWRBTC minting to the loan token --> this is where the cross-reentrancy happened between the protocol & the loan token contract.\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithSwap function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyRBTC {\n address public loanTokenWRBTC;\n address public WRBTC;\n address public SUSD;\n ProtocolLike public sovrynProtocol;\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iWRBTCBalance;\n }\n\n function() external payable {\n if (msg.sender == address(sovrynProtocol)) {\n uint256 latestRBTCBalance = address(this).balance;\n IWrbtcERC20(WRBTC).deposit.value(14 ether)();\n uint256 _WRBTCBalance = IERC20(WRBTC).balanceOf(address(this));\n IERC20(WRBTC).approve(loanTokenWRBTC, _WRBTCBalance);\n\n ILoanTokenModules(loanTokenWRBTC).mint(address(this), 14 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n\n constructor(\n address _loanTokenWRBTC,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanTokenWRBTC = _loanTokenWRBTC;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: SUSD has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n });\n\n IERC20(SUSD).approve(loanTokenWRBTC, initial.susdBalance);\n\n ILoanTokenModules(loanTokenWRBTC).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n SUSD,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanTokenWRBTC).loanParamsIds(\n uint256(keccak256(abi.encodePacked(SUSD, true)))\n );\n bytes32 loan_id =\n keccak256(\n abi.encodePacked(loanParamsLocalId, loanTokenWRBTC, _borrower, _borrowerNonce)\n );\n\n // STEP 3 close the borrowed position with a swap (probably works just as well with deposit)\n sovrynProtocol.closeWithSwap(\n loan_id,\n msg.sender,\n collateralTokenSent.mul(200).div(100), // make it 20% higher from initial collateral sent to make sure whole position is closed\n true,\n \"\"\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iRBTC\n uint256 _iWRBTCBalance = ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower);\n ILoanTokenModules(loanTokenWRBTC).burn(_receiver, _iWRBTCBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n // });\n }\n}\n" + }, + "contracts/testhelpers/TestLibraries.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../rsk/RSKAddrValidator.sol\";\n\n// contract for testing libraries\ncontract TestLibraries {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n */\n function RSKAddrValidator_checkPKNotZero(address addr) public pure returns (bool) {\n return (RSKAddrValidator.checkPKNotZero(addr));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key\n */\n function RSKAddrValidator_safeEquals(address addr1, address addr2) public pure returns (bool) {\n return (RSKAddrValidator.safeEquals(addr1, addr2));\n }\n}\n" + }, + "contracts/testhelpers/TestSovrynSwap.sol": { + "content": "/**\n * Test file simulating the SovrynSwap network\n * */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"./TestToken.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestSovrynSwap {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n address public priceFeeds;\n\n constructor(address feed) public {\n priceFeeds = feed;\n }\n\n /**\n * simulating the contract registry. always returns the address of this contract\n * */\n function addressOf(bytes32 contractName) public view returns (address) {\n return address(this);\n }\n\n /**\n * calculates the return tokens when swapping _amount, makes sure the return is bigger than _minReturn,\n * mints and burns the test tokens accordingly.\n * */\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256) {\n //compute the return for the amount of tokens provided\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n uint256 actualReturn = _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n\n require(actualReturn >= _minReturn, \"insufficient source tokens provided\");\n\n TestToken(address(_path[0])).burn(address(msg.sender), _amount);\n TestToken(address(_path[1])).mint(address(_beneficiary), actualReturn);\n return actualReturn;\n }\n\n /**\n * queries the rate from the Price Feed contract and computes the expected return amount based on the\n * amout of source tokens to be swapped.\n * */\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n\n return _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * returns the conversion path -> always a direct path\n * */\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory)\n {\n IERC20[] memory path = new IERC20[](2);\n path[0] = _sourceToken;\n path[1] = _targetToken;\n return path;\n }\n}\n" + }, + "contracts/testhelpers/TestToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestToken {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balances[_who], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[_who] = balances[_who].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(_who, _value);\n emit Transfer(_who, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/testhelpers/TestTokenERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Context.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../interfaces/IERC777.sol\";\nimport \"../interfaces/IERC777Recipient.sol\";\nimport \"../interfaces/IERC777Sender.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\n\ncontract TestTokenERC777 is Context, IERC777, IERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n mapping(address => uint256) private _balances;\n\n uint256 private _totalSupply;\n\n // We inline the result of the following hashes because Solidity doesn't resolve them at compile time.\n // See https://github.com/ethereum/solidity/issues/4024.\n\n // keccak256(\"ERC777TokensSender\")\n bytes32 private constant TOKENS_SENDER_INTERFACE_HASH =\n 0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895;\n\n // keccak256(\"ERC777TokensRecipient\")\n bytes32 private constant TOKENS_RECIPIENT_INTERFACE_HASH =\n 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;\n\n // This isn't ever read from - it's only used to respond to the defaultOperators query.\n address[] private _defaultOperatorsArray;\n\n // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).\n mapping(address => bool) private _defaultOperators;\n\n // For each account, a mapping of its operators and revoked default operators.\n mapping(address => mapping(address => bool)) private _operators;\n mapping(address => mapping(address => bool)) private _revokedDefaultOperators;\n\n // ERC20-allowances\n mapping(address => mapping(address => uint256)) private _allowances;\n\n /**\n * @dev `defaultOperators` may be an empty array.\n */\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _initialSupply,\n uint8 _decimals,\n address[] memory defaultOperators\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n _defaultOperatorsArray = defaultOperators;\n for (uint256 i = 0; i < _defaultOperatorsArray.length; i++) {\n _defaultOperators[_defaultOperatorsArray[i]] = true;\n }\n\n _mint(msg.sender, msg.sender, _initialSupply, \"\", \"\");\n\n // register interfaces\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777Token\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n /**\n * @dev See {IERC777-granularity}.\n *\n * This implementation always returns `1`.\n */\n function granularity() public view returns (uint256) {\n return 1;\n }\n\n /**\n * @dev See {IERC777-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev Returns the amount of tokens owned by an account (`tokenHolder`).\n */\n function balanceOf(address tokenHolder) public view returns (uint256) {\n return _balances[tokenHolder];\n }\n\n /**\n * @dev See {IERC777-send}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes memory data\n ) public {\n _send(_msgSender(), _msgSender(), recipient, amount, data, \"\", true);\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient}\n * interface if it is a contract.\n *\n * Also emits a {Sent} event.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n\n address from = _msgSender();\n\n _callTokensToSend(from, from, recipient, amount, \"\", \"\");\n\n _move(from, from, recipient, amount, \"\", \"\");\n\n _callTokensReceived(from, from, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev See {IERC777-burn}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function burn(uint256 amount, bytes memory data) public {\n _burn(_msgSender(), _msgSender(), amount, data, \"\");\n }\n\n /**\n * @dev See {IERC777-isOperatorFor}.\n */\n function isOperatorFor(address operator, address tokenHolder) public view returns (bool) {\n return\n operator == tokenHolder ||\n (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||\n _operators[tokenHolder][operator];\n }\n\n /**\n * @dev See {IERC777-authorizeOperator}.\n */\n function authorizeOperator(address operator) public {\n require(_msgSender() != operator, \"ERC777: authorizing self as operator\");\n\n if (_defaultOperators[operator]) {\n delete _revokedDefaultOperators[_msgSender()][operator];\n } else {\n _operators[_msgSender()][operator] = true;\n }\n\n emit AuthorizedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-revokeOperator}.\n */\n function revokeOperator(address operator) public {\n require(operator != _msgSender(), \"ERC777: revoking self as operator\");\n\n if (_defaultOperators[operator]) {\n _revokedDefaultOperators[_msgSender()][operator] = true;\n } else {\n delete _operators[_msgSender()][operator];\n }\n\n emit RevokedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-defaultOperators}.\n */\n function defaultOperators() public view returns (address[] memory) {\n return _defaultOperatorsArray;\n }\n\n /**\n * @dev See {IERC777-operatorSend}.\n *\n * Emits {Sent} and {IERC20-Transfer} events.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), sender),\n \"ERC777: caller is not an operator for holder\"\n );\n _send(_msgSender(), sender, recipient, amount, data, operatorData, true);\n }\n\n /**\n * @dev See {IERC777-operatorBurn}.\n *\n * Emits {Burned} and {IERC20-Transfer} events.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), account),\n \"ERC777: caller is not an operator for holder\"\n );\n _burn(_msgSender(), account, amount, data, operatorData);\n }\n\n /**\n * @dev See {IERC20-allowance}.\n *\n * Note that operator and allowance concepts are orthogonal: operators may\n * not have allowance, and accounts with allowance may not be operators\n * themselves.\n */\n function allowance(address holder, address spender) public view returns (uint256) {\n return _allowances[holder][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Note that accounts cannot have allowance issued by their operators.\n */\n function approve(address spender, uint256 value) public returns (bool) {\n address holder = _msgSender();\n _approve(holder, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Note that operator and allowance concepts are orthogonal: operators cannot\n * call `transferFrom` (unless they have allowance), and accounts with\n * allowance cannot call `operatorSend` (unless they are operators).\n *\n * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.\n */\n function transferFrom(\n address holder,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n require(holder != address(0), \"ERC777: transfer from the zero address\");\n\n address spender = _msgSender();\n\n _callTokensToSend(spender, holder, recipient, amount, \"\", \"\");\n\n _move(spender, holder, recipient, amount, \"\", \"\");\n\n _approve(\n holder,\n spender,\n _allowances[holder][spender].sub(amount, \"ERC777: transfer amount exceeds allowance\")\n );\n\n _callTokensReceived(spender, holder, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `operator`, `data` and `operatorData`.\n *\n * See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits {Minted} and {IERC20-Transfer} events.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - if `account` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function _mint(\n address operator,\n address account,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n require(account != address(0), \"ERC777: mint to the zero address\");\n\n // Update state variables\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n\n _callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);\n\n emit Minted(operator, account, amount, userData, operatorData);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Send tokens\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _send(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n require(from != address(0), \"ERC777: send from the zero address\");\n require(to != address(0), \"ERC777: send to the zero address\");\n\n _callTokensToSend(operator, from, to, amount, userData, operatorData);\n\n _move(operator, from, to, amount, userData, operatorData);\n\n _callTokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData,\n requireReceptionAck\n );\n }\n\n /**\n * @dev Burn tokens\n * @param operator address operator requesting the operation\n * @param from address token holder address\n * @param amount uint256 amount of tokens to burn\n * @param data bytes extra information provided by the token holder\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _burn(\n address operator,\n address from,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) internal {\n require(from != address(0), \"ERC777: burn from the zero address\");\n\n _callTokensToSend(operator, from, address(0), amount, data, operatorData);\n\n // Update state variables\n _balances[from] = _balances[from].sub(amount, \"ERC777: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n\n emit Burned(operator, from, amount, data, operatorData);\n emit Transfer(from, address(0), amount);\n }\n\n function _move(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) private {\n _balances[from] = _balances[from].sub(amount, \"ERC777: transfer amount exceeds balance\");\n _balances[to] = _balances[to].add(amount);\n\n emit Sent(operator, from, to, amount, userData, operatorData);\n emit Transfer(from, to, amount);\n }\n\n function _approve(\n address holder,\n address spender,\n uint256 value\n ) internal {\n // TODO: restore this require statement if this function becomes internal, or is called at a new callsite. It is\n // currently unnecessary.\n //require(holder != address(0), \"ERC777: approve from the zero address\");\n require(spender != address(0), \"ERC777: approve to the zero address\");\n\n _allowances[holder][spender] = value;\n emit Approval(holder, spender, value);\n }\n\n /**\n * @dev Call from.tokensToSend() if the interface is registered\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _callTokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Sender(implementer).tokensToSend(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n }\n }\n\n /**\n * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but\n * tokensReceived() was not registered for the recipient\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _callTokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Recipient(implementer).tokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n } else if (requireReceptionAck) {\n require(\n !to.isContract(),\n \"ERC777: token recipient contract has no implementer for ERC777TokensRecipient\"\n );\n }\n }\n\n function mint(address _to, uint256 _value) public {\n // Update state variables\n _totalSupply = _totalSupply.add(_value);\n _balances[_to] = _balances[_to].add(_value);\n\n emit Minted(msg.sender, _to, _value, \"\", \"\");\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balanceOf(_who), \"balance too low\");\n\n _burn(msg.sender, _who, _value, \"\", \"\");\n }\n}\n" + }, + "contracts/testhelpers/TestTokenLimited.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestTokenLimited {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n require(_value <= 100000 ether, \"max mint amount exceeded\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(uint256 _value) public {\n require(_value <= balances[msg.sender], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(msg.sender, _value);\n emit Transfer(msg.sender, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/token/IApproveAndCall.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/ApprovalReceiver.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IApproveAndCall {\n /**\n * @notice Receives approval from SOV token.\n * @param _sender The sender of SOV.approveAndCall function.\n * @param _amount The amount was approved.\n * @param _token The address of token.\n * @param _data The data will be used for low level call.\n * */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/token/SOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/ERC20Detailed.sol\";\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./IApproveAndCall.sol\";\n\n/**\n * @title Sovryn Token: SOV is an ERC-20 token contract for Sovryn governance.\n *\n * @notice This contract accounts for all holders' balances.\n *\n * @dev This contract represents a token with dynamic supply.\n * The owner of the token contract can mint/burn tokens to/from any account\n * based upon previous governance voting and approval.\n * */\ncontract SOV is ERC20, ERC20Detailed, Ownable {\n string constant NAME = \"Sovryn Token\";\n string constant SYMBOL = \"SOV\";\n uint8 constant DECIMALS = 18;\n\n /**\n * @notice Constructor called on deployment, initiates the contract.\n * @dev On deployment, some amount of tokens will be minted for the owner.\n * @param _initialAmount The amount of tokens to be minted on contract creation.\n * */\n constructor(uint256 _initialAmount) public ERC20Detailed(NAME, SYMBOL, DECIMALS) {\n if (_initialAmount != 0) {\n _mint(msg.sender, _initialAmount);\n }\n }\n\n /**\n * @notice Creates new tokens and sends them to the recipient.\n * @dev Don't create more than 2^96/10 tokens before updating the governance first.\n * @param _account The recipient address to get the minted tokens.\n * @param _amount The amount of tokens to be minted.\n * */\n function mint(address _account, uint256 _amount) public onlyOwner {\n _mint(_account, _amount);\n }\n\n /**\n * @notice Approves and then calls the receiving contract.\n * Useful to encapsulate sending tokens to a contract in one call.\n * Solidity has no native way to send tokens to contracts.\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\n * @param _spender The contract address to spend the tokens.\n * @param _amount The amount of tokens to be sent.\n * @param _data Parameters for the contract call, such as endpoint signature.\n * */\n function approveAndCall(\n address _spender,\n uint256 _amount,\n bytes memory _data\n ) public {\n approve(_spender, _amount);\n IApproveAndCall(_spender).receiveApproval(msg.sender, _amount, address(this), _data);\n }\n}\n" + }, + "contracts/utils/AdminRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\n\ncontract AdminRole is Ownable {\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * or on our own overriding sovrynOwnable.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n}\n" + }, + "contracts/utils/PausableRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/PausableOz.sol\";\n\ncontract PausableRole is PausableOz {\n address public pauser;\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n\n /**\n * @dev Modifier to make a function callable only when the caller is pauser or owner\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"Pausable: unauthorized\"); // SS02\n _;\n }\n\n /**\n * @notice Set the pauser address.\n *\n * only pauser can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyPauserOrOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyPauserOrOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/utils/ProxyOwnable.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\n/**\n * Based on OpenZeppelin's Ownable contract:\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\n *\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract ProxyOwnable {\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Ownable:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"ProxyOwnable::setProxyOwner: invalid address\");\n emit ProxyOwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Set address of the owner (only owner can call this function)\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n\n /**\n * @notice Return address of the owner.\n * @return _owner Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n}\n" + }, + "contracts/utils/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\nlibrary Utils {\n function stringToBytes32(string memory source) internal pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + }, + "remappings": [ + "ds-test/=foundry/lib/forge-std/lib/ds-test/src/", + "forge-std/=foundry/lib/forge-std/src/" + ] + } +} \ No newline at end of file diff --git a/deployment/deployments/rskSovrynMainnet/solcInputs/aca886878e9e0827277d5a4711a5589b.json b/deployment/deployments/rskSovrynMainnet/solcInputs/aca886878e9e0827277d5a4711a5589b.json new file mode 100644 index 000000000..131856511 --- /dev/null +++ b/deployment/deployments/rskSovrynMainnet/solcInputs/aca886878e9e0827277d5a4711a5589b.json @@ -0,0 +1,708 @@ +{ + "language": "Solidity", + "sources": { + "contracts/connectors/loantoken/AdvancedToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Advanced Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedToken implements standard ERC-20 approval, mint and burn token functionality.\n * Logic (AdvancedToken) is kept aside from storage (AdvancedTokenStorage).\n *\n * For example, LoanTokenLogicDai contract uses AdvancedToken::_mint() to mint\n * its Loan Dai iTokens.\n * */\ncontract AdvancedToken is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n /**\n * @notice Set an amount as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n *\n * @param _spender The account address that will be able to spend the tokens.\n * @param _value The amount of tokens allowed to spend.\n * */\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @notice The iToken minting process. Meant to issue Loan iTokens.\n * Lenders are able to open an iToken position, by minting them.\n * This function is called by LoanTokenLogicStandard::_mintToken\n * @param _to The recipient of the minted tTokens.\n * @param _tokenAmount The amount of iTokens to be minted.\n * @param _assetAmount The amount of lended tokens (asset to lend).\n * @param _price The price of the lended tokens.\n * @return The updated balance of the recipient.\n * */\n function _mint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n require(_to != address(0), \"15\");\n\n uint256 _balance = balances[_to].add(_tokenAmount);\n balances[_to] = _balance;\n\n totalSupply_ = totalSupply_.add(_tokenAmount);\n\n emit Mint(_to, _tokenAmount, _assetAmount, _price);\n emit Transfer(address(0), _to, _tokenAmount);\n\n return _balance;\n }\n\n /**\n * @notice The iToken burning process. Meant to destroy Loan iTokens.\n * Lenders are able to close an iToken position, by burning them.\n * This function is called by LoanTokenLogicStandard::_burnToken\n * @param _who The owner of the iTokens to burn.\n * @param _tokenAmount The amount of iTokens to burn.\n * @param _assetAmount The amount of lended tokens.\n * @param _price The price of the lended tokens.\n * @return The updated balance of the iTokens owner.\n * */\n function _burn(\n address _who,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n //bzx compare\n //TODO: Unit test\n uint256 _balance = balances[_who].sub(_tokenAmount, \"16\");\n\n // a rounding error may leave dust behind, so we clear this out\n if (_balance <= 10) {\n // We can't leave such small balance quantities.\n _tokenAmount = _tokenAmount.add(_balance);\n _balance = 0;\n }\n balances[_who] = _balance;\n\n totalSupply_ = totalSupply_.sub(_tokenAmount);\n\n emit Burn(_who, _tokenAmount, _assetAmount, _price);\n emit Transfer(_who, address(0), _tokenAmount);\n return _balance;\n }\n}\n" + }, + "contracts/connectors/loantoken/AdvancedTokenStorage.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./LoanTokenBase.sol\";\n\n/**\n * @title Advanced Token Storage contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedTokenStorage implements standard ERC-20 getters functionality:\n * totalSupply, balanceOf, allowance and some events.\n * iToken logic is divided into several contracts AdvancedToken,\n * AdvancedTokenStorage and LoanTokenBase.\n * */\ncontract AdvancedTokenStorage is LoanTokenBase {\n using SafeMath for uint256;\n\n /* Events */\n\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /* Storage */\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n /* Functions */\n\n /**\n * @notice Get the total supply of iTokens.\n * @return The total number of iTokens in existence as of now.\n * */\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n /**\n * @notice Get the amount of iTokens owned by an account.\n * @param _owner The account owner of the iTokens.\n * @return The number of iTokens an account owns.\n * */\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n /**\n * @notice Get the amount of iTokens allowed to be spent by a\n * given account on behalf of the owner.\n * @param _owner The account owner of the iTokens.\n * @param _spender The account allowed to send the iTokens.\n * @return The number of iTokens an account is allowing the spender\n * to send on its behalf.\n * */\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/connectors/loantoken/interfaces/FeedsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface FeedsLike {\n function queryRate(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 rate, uint256 precision);\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../lib/MarginTradeStructHelpers.sol\";\n\ninterface ProtocolLike {\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function priceFeeds() external view returns (address);\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function lendingFeePercent() external view returns (uint256);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function borrowerNonce(address) external view returns (uint256);\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata // for future use /*loanDataBytes*/\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolSettingsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../core/objects/LoanParamsStruct.sol\";\n\ninterface ProtocolSettingsLike {\n function setupLoanParams(LoanParamsStruct.LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n}\n" + }, + "contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol": { + "content": "pragma solidity 0.5.17;\n\nlibrary MarginTradeStructHelpers {\n struct SentAddresses {\n address lender;\n address borrower;\n address receiver;\n address manager;\n }\n\n struct SentAmounts {\n uint256 interestRate;\n uint256 newPrincipal;\n uint256 interestInitialAmount;\n uint256 loanTokenSent;\n uint256 collateralTokenSent;\n uint256 minEntryPrice;\n uint256 loanToCollateralSwapRate;\n uint256 interestDuration;\n uint256 entryLeverage;\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Loan Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * A loan token (iToken) is created as a proxy to an upgradable token contract.\n *\n * Examples of loan tokens on Sovryn are iRBTC, iDOC, iUSDT, iBPro,\n * iSOV (near future).\n *\n * Lenders receive iTokens that collect interest from the lending pool\n * which they can redeem by withdrawing them. The i in iToken stands for interest.\n *\n * Do not confuse iTokens with underlying tokens. iDOC is an iToken (loan token)\n * whilest DOC is the underlying token (currency).\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\n * */\ncontract LoanToken is AdvancedTokenStorage {\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n address public admin;\n\n /**\n * @notice Deploy loan token proxy.\n * Sets ERC20 parameters of the token.\n *\n * @param _newOwner The address of the new owner.\n * @param _newTarget The address of the new target contract instance.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice Public owner setter for target address.\n * @dev Calls internal setter.\n * @param _newTarget The address of the new target contract instance.\n * */\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n /**\n * @notice Internal setter for target address.\n * @param _newTarget The address of the new target contract instance.\n * */\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n /**\n * @notice Internal setter for sovrynContract address.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * */\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n /**\n * @notice Internal setter for wrBTC address.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n /**\n * @notice Public owner cloner for pointed loan token.\n * Sets ERC20 parameters of the token.\n *\n * @dev TODO: add check for double init.\n * idk but init usually can be called only once.\n *\n * @param _loanTokenAddress The address of the pointed loan token instance.\n * @param _name The ERC20 token name.\n * @param _symbol The ERC20 token symbol.\n * */\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; /// starting price of 1\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenBase.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SignedSafeMath.sol\";\nimport \"../../openzeppelin/ReentrancyGuard.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\nimport \"./Pausable.sol\";\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title Loan Token Base contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Specific loan related storage for iTokens.\n *\n * An loan token or iToken is a representation of a user funds in the pool and the\n * interest they've earned. The redemption value of iTokens continually increase\n * from the accretion of interest paid into the lending pool by borrowers. The user\n * can sell iTokens to exit its position. The user might potentially use them as\n * collateral wherever applicable.\n *\n * There are three main tokens in the bZx system, iTokens, pTokens, and BZRX tokens.\n * The bZx system of lending and borrowing depends on iTokens and pTokens, and when\n * users lend or borrow money on bZx, their crypto assets go into or come out of\n * global liquidity pools, which are pools of funds shared between many different\n * exchanges. When lenders supply funds into the global liquidity pools, they\n * automatically receive iTokens; When users borrow money to open margin trading\n * positions, they automatically receive pTokens. The system is also designed to\n * use the BZRX tokens, which are only used to pay fees on the network currently.\n * */\ncontract LoanTokenBase is ReentrancyGuard, SharedReentrancyGuard, Ownable, Pausable {\n uint256 internal constant WEI_PRECISION = 10**18;\n uint256 internal constant WEI_PERCENT_PRECISION = 10**20;\n\n int256 internal constant sWEI_PRECISION = 10**18;\n\n /// @notice Standard ERC-20 properties\n string public name;\n string public symbol;\n uint8 public decimals;\n\n /// @notice The address of the loan token (asset to lend) instance.\n address public loanTokenAddress;\n\n uint256 public baseRate;\n uint256 public rateMultiplier;\n uint256 public lowUtilBaseRate;\n uint256 public lowUtilRateMultiplier;\n\n uint256 public targetLevel;\n uint256 public kinkLevel;\n uint256 public maxScaleRate;\n\n uint256 internal _flTotalAssetSupply;\n uint256 public checkpointSupply;\n uint256 public initialPrice;\n\n /// uint88 for tight packing -> 8 + 88 + 160 = 256\n uint88 internal lastSettleTime_;\n\n /// Mapping of keccak256(collateralToken, isTorqueLoan) to loanParamsId.\n mapping(uint256 => bytes32) public loanParamsIds;\n\n /// Price of token at last user checkpoint.\n mapping(address => uint256) internal checkpointPrices_;\n\n // the maximum trading/borrowing/lending limit per token address\n mapping(address => uint256) public transactionLimit;\n // 0 -> no limit\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicBeacon.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../mixins/EnumerableBytes32Set.sol\";\nimport \"../../mixins/EnumerableBytes4Set.sol\";\nimport \"../../utils/PausableRole.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Loan Token Logic Beacon contract.\n *\n * @notice This contract stored the target logic implementation of LoanTokens which has the same logic implementation (LoanTokenLogicLM / LoanTokenLogicWrbtc)\n * Apart from storing the target logic implementation, this contract also has a pause functionality.\n * By implementing pause/unpause functionality in this beacon contract, we can pause the loan token that has the same Logic (LoanTokenLogicLM / LoanTokenLogicWrbtc) at one call.\n * Meanwhile the pause/unpause function in the LoanTokenLogicProxy is used to pause/unpause specific LoanToken\n */\n\ncontract LoanTokenLogicBeacon is PausableRole {\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; // enumerable map of bytes4 or addresses\n\n mapping(bytes4 => address) private logicTargets;\n\n struct LoanTokenLogicModuleUpdate {\n address implementation; // address implementaion of the module\n uint256 updateTimestamp; // time of update\n }\n\n mapping(bytes32 => LoanTokenLogicModuleUpdate[]) public moduleUpgradeLog; /** the module name as the key */\n\n mapping(bytes32 => uint256) public activeModuleIndex; /** To store the current active index log for module */\n\n mapping(bytes32 => EnumerableBytes4Set.Bytes4Set) private activeFuncSignatureList; /** Store the current active function signature */\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n * This is the overriden function from the pausable contract, so that we can use custom error message.\n */\n modifier whenNotPaused() {\n require(!_paused, \"LoanTokenLogicBeacon:paused mode\");\n _;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This function will store the updated protocol module to the storage (For rollback purposes)\n *\n * @param loanTokenModuleAddress The module target address\n */\n function registerLoanTokenModule(address loanTokenModuleAddress) external onlyOwner {\n bytes32 moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n\n // Store the upgrade to the log\n moduleUpgradeLog[moduleName].push(\n LoanTokenLogicModuleUpdate(loanTokenModuleAddress, block.timestamp)\n );\n activeModuleIndex[moduleName] = moduleUpgradeLog[moduleName].length - 1;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This registration will require target contract to have the exact function getListFunctionSignatures() which will return functionSignatureList and the moduleName in bytes32\n *\n * @param loanTokenModuleAddress the target logic of the loan token module\n *\n * @return the module name\n */\n function _registerLoanTokenModule(address loanTokenModuleAddress) private returns (bytes32) {\n require(\n Address.isContract(loanTokenModuleAddress),\n \"LoanTokenModuleAddress is not a contract\"\n );\n\n // Get the list of function signature on this loanTokenModulesAddress\n (bytes4[] memory functionSignatureList, bytes32 moduleName) =\n ILoanTokenLogicModules(loanTokenModuleAddress).getListFunctionSignatures();\n\n /// register / update the module function signature address implementation\n for (uint256 i; i < functionSignatureList.length; i++) {\n require(functionSignatureList[i] != bytes4(0x0), \"ERR_EMPTY_FUNC_SIGNATURE\");\n logicTargets[functionSignatureList[i]] = loanTokenModuleAddress;\n if (!activeFuncSignatureList[moduleName].contains(functionSignatureList[i]))\n activeFuncSignatureList[moduleName].addBytes4(functionSignatureList[i]);\n }\n\n /// delete the \"removed\" module function signature in the current implementation\n bytes4[] memory activeSignatureListEnum =\n activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n for (uint256 i; i < activeSignatureListEnum.length; i++) {\n bytes4 activeSigBytes = activeSignatureListEnum[i];\n if (logicTargets[activeSigBytes] != loanTokenModuleAddress) {\n logicTargets[activeSigBytes] = address(0);\n activeFuncSignatureList[moduleName].removeBytes4(activeSigBytes);\n }\n }\n\n return moduleName;\n }\n\n /**\n * @dev get all active function signature list based on the module name.\n *\n * @param moduleName in bytes32.\n *\n * @return the array of function signature.\n */\n function getActiveFuncSignatureList(bytes32 moduleName)\n public\n view\n returns (bytes4[] memory signatureList)\n {\n signatureList = activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n return signatureList;\n }\n\n /**\n * @dev Get total length of the module upgrade log.\n *\n * @param moduleName in bytes32.\n *\n * @return length of module upgrade log.\n */\n function getModuleUpgradeLogLength(bytes32 moduleName) external view returns (uint256) {\n return moduleUpgradeLog[moduleName].length;\n }\n\n /**\n * @notice This function will rollback particular module to the spesific index / version of deployment\n *\n * @param moduleName Name of module in bytes32 format\n * @param index index / version of previous deployment\n */\n function rollback(bytes32 moduleName, uint256 index) external onlyOwner {\n address loanTokenModuleAddress = moduleUpgradeLog[moduleName][index].implementation;\n moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n activeModuleIndex[moduleName] = index;\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(bytes4 sig) external view whenNotPaused returns (address) {\n return logicTargets[sig];\n }\n}\n\ninterface ILoanTokenLogicModules {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory, bytes32 moduleName);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicProxy.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./AdvancedTokenStorage.sol\";\nimport \"../../openzeppelin/Initializable.sol\";\n\n/**\n * @title Loan Token Logic Proxy contract.\n *\n * @notice This contract contains the proxy functionality and it will query the logic target from LoanTokenLogicBeacon\n * This contract will also has the pause/unpause functionality. The purpose of this pausability is so that we can pause/unpause from the loan token level.\n *\n */\ncontract LoanTokenLogicProxy is AdvancedTokenStorage {\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT\n */\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT (CONSTANT / IMMUTABLE)\n */\n\n bytes32 internal constant LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT =\n keccak256(\"LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT\");\n\n modifier onlyAdmin() {\n require(isOwner(), \"LoanTokenLogicProxy:unauthorized\");\n _;\n }\n\n /**\n * @notice Fallback function performs a logic implementation address query to LoanTokenLogicBeacon and then do delegate call to that query result address.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n // query the logic target implementation address from the LoanTokenLogicBeacon\n address target = ILoanTokenLogicBeacon(_beaconAddress()).getTarget(msg.sig);\n require(target != address(0), \"LoanTokenLogicProxy:target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @dev Returns the current Loan Token logic Beacon.\n * @return Address of the current LoanTokenLogicBeacon.\n */\n function _beaconAddress() internal view returns (address beaconAddress) {\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n assembly {\n beaconAddress := sload(slot)\n }\n }\n\n /**\n * @return The address of the current LoanTokenLogicBeacon.\n */\n function beaconAddress() external view returns (address) {\n return _beaconAddress();\n }\n\n /**\n * @dev Set/update the new beacon address.\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon.\n */\n function _setBeaconAddress(address _newBeaconAddress) private {\n require(\n Address.isContract(_newBeaconAddress),\n \"Cannot set beacon address to a non-contract address\"\n );\n\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n\n assembly {\n sstore(slot, _newBeaconAddress)\n }\n }\n\n /**\n * @dev External function to set the new LoanTokenLogicBeacon Address\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon\n */\n function setBeaconAddress(address _newBeaconAddress) external onlyAdmin {\n _setBeaconAddress(_newBeaconAddress);\n }\n\n /**\n * @dev External function to return the LoanTokenLogicProxy of loan token (target of LoanToken contract).\n * Ideally this getter should be added in the LoanToken contract\n * but since LoanToken contract can't be changed, adding the getter in this contract will do\n * because it will use the context of LoanToken contract.\n *\n * @return target address of LoanToken contract\n */\n function getTarget() external view returns (address) {\n return target_;\n }\n}\n\ninterface ILoanTokenLogicBeacon {\n function getTarget(bytes4 functionSignature)\n external\n view\n returns (address logicTargetAddress);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicShared.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicStorage.sol\";\nimport \"./interfaces/ProtocolLike.sol\";\nimport \"./interfaces/FeedsLike.sol\";\nimport \"./interfaces/ProtocolSettingsLike.sol\";\nimport \"../../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../../farm/ILiquidityMining.sol\";\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../governance/Vesting/IVesting.sol\";\n\n/**\n * @dev This contract shares functions used by both LoanTokenLogicSplit and LoanTokenLogicStandard\n */\ncontract LoanTokenLogicShared is LoanTokenLogicStorage {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /**\n * @notice Update the user's checkpoint price and profit so far.\n * In this loan token contract, whenever some tokens are minted or burned,\n * the _updateCheckpoints() function is invoked to update the stats to\n * reflect the balance changes.\n *\n * @param _user The user address.\n * @param _oldBalance The user's previous balance.\n * @param _newBalance The user's updated balance.\n * @param _currentPrice The current loan token price.\n * */\n function _updateCheckpoints(\n address _user,\n uint256 _oldBalance,\n uint256 _newBalance,\n uint256 _currentPrice\n ) internal {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(_user, iToken_ProfitSoFar));\n\n int256 _currentProfit;\n if (_newBalance == 0) {\n _currentPrice = 0;\n } else if (_oldBalance != 0) {\n _currentProfit = _profitOf(slot, _oldBalance, _currentPrice, checkpointPrices_[_user]);\n }\n\n assembly {\n sstore(slot, _currentProfit)\n }\n\n checkpointPrices_[_user] = _currentPrice;\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice Transfer tokens, low level.\n * Checks allowance, updates sender and recipient balances\n * and updates checkpoints too.\n *\n * @param _from The tokens' owner.\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @param _allowanceAmount The amount of tokens allowed to transfer.\n *\n * @return Success true/false.\n * */\n function _internalTransferFrom(\n address _from,\n address _to,\n uint256 _value,\n uint256 _allowanceAmount\n ) internal returns (bool) {\n if (_allowanceAmount != uint256(-1)) {\n allowed[_from][msg.sender] = _allowanceAmount.sub(_value, \"14\");\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, _allowanceAmount, allowed[_from][msg.sender]);\n }\n\n require(_to != address(0), \"15\");\n\n uint256 _balancesFrom = balances[_from];\n uint256 _balancesFromNew = _balancesFrom.sub(_value, \"16\");\n balances[_from] = _balancesFromNew;\n\n uint256 _balancesTo = balances[_to];\n uint256 _balancesToNew = _balancesTo.add(_value);\n balances[_to] = _balancesToNew;\n\n /// @dev Handle checkpoint update.\n uint256 _currentPrice = tokenPrice();\n\n //checkpoints are not being used by the smart contract logic itself, but just for external use (query the profit)\n //only update the checkpoints of a user if he's not depositing to / withdrawing from the lending pool\n if (_from != liquidityMiningAddress && _to != liquidityMiningAddress) {\n _updateCheckpoints(_from, _balancesFrom, _balancesFromNew, _currentPrice);\n _updateCheckpoints(_to, _balancesTo, _balancesToNew, _currentPrice);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n /**\n * @notice Profit calculation based on checkpoints of price.\n * @param slot The user slot.\n * @param _balance The user balance.\n * @param _currentPrice The current price of the loan token.\n * @param _checkpointPrice The price of the loan token on checkpoint.\n * @return The profit of a user.\n * */\n function _profitOf(\n bytes32 slot,\n uint256 _balance,\n uint256 _currentPrice,\n uint256 _checkpointPrice\n ) internal view returns (int256 profitSoFar) {\n if (_checkpointPrice == 0) {\n return 0;\n }\n\n assembly {\n profitSoFar := sload(slot)\n }\n\n profitSoFar = int256(_currentPrice)\n .sub(int256(_checkpointPrice))\n .mul(int256(_balance))\n .div(sWEI_PRECISION)\n .add(profitSoFar);\n }\n\n /**\n * @notice Loan token price calculation considering unpaid interests.\n * @return The loan token price.\n * */\n function tokenPrice() public view returns (uint256 price) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _tokenPrice(_totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Get the total amount of loan tokens on debt.\n * Calls protocol getTotalPrincipal function.\n * In the context of borrowing, principal is the initial size of a loan.\n * It can also be the amount still owed on a loan. If you take out a\n * $50,000 mortgage, for example, the principal is $50,000. If you pay off\n * $30,000, the principal balance now consists of the remaining $20,000.\n *\n * @return The total amount of loan tokens on debt.\n * */\n function totalAssetBorrow() public view returns (uint256) {\n return\n ProtocolLike(sovrynContractAddress).getTotalPrincipal(address(this), loanTokenAddress);\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice .\n *\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param withdrawalAmount The amount of tokens to withdraw.\n *\n * @return msgValue The amount of rBTC sent minus the collateral on tokens.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = loanTokenAddress;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n _safeTransfer(_loanTokenAddress, sentAddresses.receiver, withdrawalAmount, \"\");\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n /**\n * This is a critical piece of code!\n * rBTC are supposed to be held by the contract itself, while other tokens are being transfered from the sender directly.\n * */\n if (collateralTokenSent != 0) {\n if (\n collateralTokenAddress == _wrbtcToken &&\n msgValue != 0 &&\n msgValue >= collateralTokenSent\n ) {\n IWrbtc(_wrbtcToken).deposit.value(collateralTokenSent)();\n _safeTransfer(\n collateralTokenAddress,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-a\"\n );\n msgValue -= collateralTokenSent;\n } else {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-b\"\n );\n }\n }\n\n if (loanTokenSent != 0) {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n\n /**\n * @notice Withdraw loan token interests from protocol.\n * This function only operates once per block.\n * It asks protocol to withdraw accrued interests for the loan token.\n *\n * @dev Internal sync required on every loan trade before starting.\n * */\n function _settleInterest() internal {\n uint88 ts = uint88(block.timestamp);\n if (lastSettleTime_ != ts) {\n ProtocolLike(sovrynContractAddress).withdrawAccruedInterest(loanTokenAddress);\n\n lastSettleTime_ = ts;\n }\n }\n\n /**\n * @notice Imitate a Solidity high-level call (i.e. a regular function\n * call to a contract), relaxing the requirement on the return value:\n * the return value is optional (but if data is returned, it must not be\n * false).\n *\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n * @param errorMsg The error message on failure.\n * */\n function _callOptionalReturn(\n address token,\n bytes memory data,\n string memory errorMsg\n ) internal {\n require(Address.isContract(token), \"call to a non-contract address\");\n (bool success, bytes memory returndata) = token.call(data);\n require(success, errorMsg);\n\n if (returndata.length != 0) {\n require(abi.decode(returndata, (bool)), errorMsg);\n }\n }\n\n /**\n * @notice Execute the ERC20 token's `transfer` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransfer(\n address token,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transfer.selector, to, amount),\n errorMsg\n );\n }\n\n /**\n * @notice Execute the ERC20 token's `transferFrom` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param from The source address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransferFrom(\n address token,\n address from,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transferFrom.selector, from, to, amount),\n errorMsg\n );\n }\n\n /** Internal view function */\n /**\n * @notice Compute the token price.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The token price.\n * */\n function _tokenPrice(uint256 assetSupply) internal view returns (uint256) {\n uint256 totalTokenSupply = totalSupply_;\n\n return\n totalTokenSupply != 0 ? assetSupply.mul(10**18).div(totalTokenSupply) : initialPrice;\n }\n\n /**\n * @notice Get two kind of interests: owed per day and yet to be paid.\n * @return interestOwedPerDay The interest per day.\n * @return interestUnPaid The interest not yet paid.\n * */\n function _getAllInterest()\n internal\n view\n returns (uint256 interestOwedPerDay, uint256 interestUnPaid)\n {\n /// interestPaid, interestPaidDate, interestOwedPerDay, interestUnPaid, interestFeePercent, principalTotal\n uint256 interestFeePercent;\n (, , interestOwedPerDay, interestUnPaid, interestFeePercent, ) = ProtocolLike(\n sovrynContractAddress\n )\n .getLenderInterestData(address(this), loanTokenAddress);\n\n interestUnPaid = interestUnPaid.mul(SafeMath.sub(10**20, interestFeePercent)).div(10**20);\n }\n\n /**\n * @notice Compute the total amount of loan tokens on supply.\n * @param interestUnPaid The interest not yet paid.\n * @return assetSupply The total amount of loan tokens on supply.\n * */\n function _totalAssetSupply(uint256 interestUnPaid)\n internal\n view\n returns (uint256 assetSupply)\n {\n if (totalSupply_ != 0) {\n uint256 assetsBalance = _flTotalAssetSupply; /// Temporary locked totalAssetSupply during a flash loan transaction.\n if (assetsBalance == 0) {\n assetsBalance = _underlyingBalance().add(totalAssetBorrow());\n }\n\n return assetsBalance.add(interestUnPaid);\n }\n }\n\n /**\n * @notice Get the loan contract balance.\n * @return The balance of the loan token for this contract.\n * */\n function _underlyingBalance() internal view returns (uint256) {\n return IERC20(loanTokenAddress).balanceOf(address(this));\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicSplit.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\n/**\n * @title Loan Token Logic Standard contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Logic around loan tokens (iTokens) required to operate borrowing,\n * and margin trading financial processes.\n *\n * The user provides funds to the lending pool using the mint function and\n * withdraws funds from the lending pool using the burn function. Mint and\n * burn refer to minting and burning loan tokens. Loan tokens represent a\n * share of the pool and gather interest over time.\n *\n * Interest rates are determined by supply and demand. When a lender deposits\n * funds, the interest rates go down. When a trader borrows funds, the\n * interest rates go up. Fulcrum uses a simple linear interest rate formula\n * of the form y = mx + b. The interest rate starts at 1% when loans aren't\n * being utilized and scales up to 40% when all the funds in the loan pool\n * are being borrowed.\n *\n * The borrow rate is determined at the time of the loan and represents the\n * net contribution of each borrower. Each borrower's interest contribution\n * is determined by the utilization rate of the pool and is netted against\n * all prior borrows. This means that the total amount of interest flowing\n * into the lending pool is not directly changed by lenders entering or\n * exiting the pool. The entrance or exit of lenders only impacts how the\n * interest payments are split up.\n *\n * For example, if there are 2 lenders with equal holdings each earning\n * 5% APR, but one of the lenders leave, then the remaining lender will earn\n * 10% APR since the interest payments don't have to be split between two\n * individuals.\n * */\ncontract LoanTokenLogicSplit is LoanTokenLogicShared {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /* Public functions */\n\n /**\n * @notice Mint loan token wrapper.\n * Adds a check before calling low level _mintToken function.\n * The function retrieves the tokens from the message sender, so make sure\n * to first approve the loan token contract to access your funds. This is\n * done by calling approve(address spender, uint amount) on the ERC20\n * token contract, where spender is the loan token contract address and\n * amount is the amount to be deposited.\n *\n * @param receiver The account getting the minted tokens.\n * @param depositAmount The amount of underlying tokens provided on the\n * loan. (Not the number of loan tokens to mint).\n *\n * @return The amount of loan tokens minted.\n * */\n function mint(address receiver, uint256 depositAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice Burn loan token wrapper.\n * Adds a pay-out transfer after calling low level _burnToken function.\n * In order to withdraw funds to the pool, call burn on the respective\n * loan token contract. This will burn your loan tokens and send you the\n * underlying token in exchange.\n *\n * @param receiver The account getting the minted tokens.\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 loanAmountPaid)\n {\n loanAmountPaid = _burnToken(burnAmount);\n\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (loanAmountPaid != 0) {\n _safeTransfer(loanTokenAddress, receiver, loanAmountPaid, \"5\");\n }\n }\n\n /**\n * @notice transfers the underlying asset from the msg.sender and mints tokens for the receiver\n * @param receiver the address of the iToken receiver\n * @param depositAmount the amount of underlying assets to be deposited\n * @return the amount of iTokens issued\n */\n function _mintToken(address receiver, uint256 depositAmount)\n internal\n returns (uint256 mintAmount)\n {\n uint256 currentPrice;\n\n //calculate amount to mint and transfer the underlying asset\n (mintAmount, currentPrice) = _prepareMinting(depositAmount);\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n receiver\n );\n uint256 oldBalance = balances[receiver].add(balanceOnLM);\n uint256 newBalance = oldBalance.add(mintAmount);\n\n //mint the tokens to the receiver\n _mint(receiver, mintAmount, depositAmount, currentPrice);\n\n //update the checkpoint of the receiver\n _updateCheckpoints(receiver, oldBalance, newBalance, currentPrice);\n }\n\n /**\n * calculates the amount of tokens to mint and transfers the underlying asset to this contract\n * @param depositAmount the amount of the underyling asset deposited\n * @return the amount to be minted\n */\n function _prepareMinting(uint256 depositAmount)\n internal\n returns (uint256 mintAmount, uint256 currentPrice)\n {\n require(depositAmount != 0, \"17\");\n\n _settleInterest();\n\n currentPrice = _tokenPrice(_totalAssetSupply(0));\n mintAmount = depositAmount.mul(10**18).div(currentPrice);\n\n if (msg.value == 0) {\n _safeTransferFrom(loanTokenAddress, msg.sender, address(this), depositAmount, \"18\");\n } else {\n IWrbtc(wrbtcTokenAddress).deposit.value(depositAmount)();\n }\n }\n\n /**\n * @notice A wrapper for AdvancedToken::_burn\n *\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function _burnToken(uint256 burnAmount) internal returns (uint256 loanAmountPaid) {\n require(burnAmount != 0, \"19\");\n\n if (burnAmount > balanceOf(msg.sender)) {\n require(burnAmount == uint256(-1), \"32\");\n burnAmount = balanceOf(msg.sender);\n }\n\n _settleInterest();\n\n uint256 currentPrice = _tokenPrice(_totalAssetSupply(0));\n\n uint256 loanAmountOwed = burnAmount.mul(currentPrice).div(10**18);\n uint256 loanAmountAvailableInContract = _underlyingBalance();\n\n loanAmountPaid = loanAmountOwed;\n require(loanAmountPaid <= loanAmountAvailableInContract, \"37\");\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n uint256 oldBalance = balances[msg.sender].add(balanceOnLM);\n uint256 newBalance = oldBalance.sub(burnAmount);\n\n _burn(msg.sender, burnAmount, loanAmountPaid, currentPrice);\n\n //this function does not only update the checkpoints but also the current profit of the user\n //all for external use only\n _updateCheckpoints(msg.sender, oldBalance, newBalance, currentPrice);\n }\n\n function _mintWithLM(address receiver, uint256 depositAmount)\n internal\n returns (uint256 minted)\n {\n //mint the tokens for the receiver\n minted = _mintToken(receiver, depositAmount);\n\n //transfer the tokens from the receiver to the LM address\n _internalTransferFrom(receiver, liquidityMiningAddress, minted, minted);\n\n //inform the LM mining contract\n ILiquidityMining(liquidityMiningAddress).onTokensDeposited(receiver, minted);\n }\n\n function _burnFromLM(uint256 burnAmount) internal returns (uint256) {\n uint256 balanceOnLM =\n ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n require(balanceOnLM.add(balanceOf(msg.sender)) >= burnAmount, \"not enough balance\");\n\n if (balanceOnLM > 0) {\n //withdraw pool tokens and LM rewards to the passed address\n if (balanceOnLM < burnAmount) {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n balanceOnLM,\n msg.sender\n );\n } else {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n burnAmount,\n msg.sender\n );\n }\n }\n //burn the tokens of the msg.sender\n return _burnToken(burnAmount);\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStandard.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\ncontract LoanTokenLogicStandard is LoanTokenLogicShared {\n /**\n * @notice Transfer tokens wrapper.\n * Sets token owner the msg.sender.\n * Sets maximun allowance uint256(-1) to ensure tokens are always transferred.\n *\n * If the recipient (_to) is a vesting contract address, transfer the token to the tokenOwner of the vesting contract itself.\n *\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @return Success true/false.\n * */\n function transfer(address _to, uint256 _value) external returns (bool) {\n /** need additional check address(0) here to support backward compatibility\n * in case we don't want to activate this check, just need to set the stakingContractAddress to 0 address\n */\n if (\n stakingContractAddress != address(0) &&\n IStaking(stakingContractAddress).isVestingContract(_to)\n ) {\n (bool success, bytes memory data) =\n _to.staticcall(abi.encodeWithSelector(IVesting(_to).tokenOwner.selector));\n\n if (success) _to = abi.decode(data, (address));\n }\n\n return _internalTransferFrom(msg.sender, _to, _value, uint256(-1));\n }\n\n /**\n * @notice Moves `_value` loan tokens from `_from` to `_to` using the\n * allowance mechanism. Calls internal _internalTransferFrom function.\n *\n * @return A boolean value indicating whether the operation succeeded.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool) {\n return\n _internalTransferFrom(\n _from,\n _to,\n _value,\n //allowed[_from][msg.sender]\n ProtocolLike(sovrynContractAddress).isLoanPool(msg.sender)\n ? uint256(-1)\n : allowed[_from][msg.sender]\n );\n }\n\n /**\n * @notice Borrow funds from the pool.\n * The underlying loan token may not be used as collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * (150% of the withdrawn amount worth in collateral tokens).\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param borrower The one paying for the collateral.\n * @param receiver The one receiving the withdrawn amount.\n *\n * @return New principal and new collateral added to loan.\n * */\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes memory /// loanDataBytes: arbitrary order data (for future use).\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n )\n {\n require(withdrawAmount != 0, \"6\");\n\n _checkPause();\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n\n require(\n (msg.value == 0 || msg.value == collateralTokenSent) &&\n (collateralTokenSent != 0 || loanId != 0) &&\n (collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0) &&\n (loanId == 0 || msg.sender == borrower),\n \"7\"\n );\n\n /// @dev We have an issue regarding contract size code is too big. 1 of the solution is need to keep the error message 32 bytes length\n // Temporarily, we combine this require to the above, so can save the contract size code\n // require(collateralTokenSent != 0 || loanId != 0, \"8\");\n // require(collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0, \"9\");\n\n /// @dev Ensure authorized use of existing loan.\n // require(loanId == 0 || msg.sender == borrower, \"401 use of existing loan\");\n\n /// @dev The condition is never met.\n /// Address zero is not allowed by previous require validation.\n /// This check is unneeded and was lowering the test coverage index.\n // if (collateralTokenAddress == address(0)) {\n // \tcollateralTokenAddress = wrbtcTokenAddress;\n // }\n\n require(collateralTokenAddress != loanTokenAddress, \"10\");\n\n _settleInterest();\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this); /// The lender.\n sentAddresses.borrower = borrower;\n sentAddresses.receiver = receiver;\n /// sentAddresses.manager = address(0); /// The manager.\n\n sentAmounts.newPrincipal = withdrawAmount;\n\n /// interestRate, interestInitialAmount, borrowAmount (newBorrowAmount).\n (\n sentAmounts.interestRate,\n sentAmounts.interestInitialAmount,\n sentAmounts.newPrincipal\n ) = _getInterestRateAndBorrowAmount(\n sentAmounts.newPrincipal,\n _totalAssetSupply(0), /// Interest is settled above.\n initialLoanDuration\n );\n\n /// sentAmounts.loanTokenSent = 0; /// loanTokenSent\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n return\n _borrowOrTrade(\n loanId,\n withdrawAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ]\n ),\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Borrow and immediately get into a position.\n *\n * Trading on margin is used to increase an investor's buying power.\n * Margin is the amount of money required to open a position, while\n * leverage is the multiple of exposure to account equity.\n *\n * Leverage allows you to trade positions LARGER than the amount\n * of money in your trading account. Leverage is expressed as a ratio.\n *\n * When trading on margin, investors first deposit some token that then\n * serves as collateral for the loan, and then pay ongoing interest\n * payments on the money they borrow.\n *\n * Margin trading = taking a loan and swapping it:\n * In order to open a margin trade position,\n * 1.- The user calls marginTrade on the loan token contract.\n * 2.- The loan token contract provides the loan and sends it for processing\n * to the protocol proxy contract.\n * 3.- The protocol proxy contract uses the module LoanOpening to create a\n * position and swaps the loan tokens to collateral tokens.\n * 4.- The Sovryn Swap network looks up the correct converter and swaps the\n * tokens.\n * If successful, the position is being held by the protocol proxy contract,\n * which is why positions need to be closed at the protocol proxy contract.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n * */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // value of loan token in collateral\n bytes memory loanDataBytes /// Arbitrary order data.\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n _checkPause();\n\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n require(collateralTokenAddress != loanTokenAddress, \"11\");\n\n /// @dev Ensure authorized use of existing loan.\n require(loanId == 0 || msg.sender == trader, \"401 use of existing loan\");\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n if (transactionLimit[loanTokenAddress] > 0)\n require(loanTokenSent <= transactionLimit[loanTokenAddress]);\n\n /// @dev Compute the worth of the total deposit in loan tokens.\n /// (loanTokenSent + convert(collateralTokenSent))\n /// No actual swap happening here.\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n require(totalDeposit != 0, \"12\");\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this);\n sentAddresses.borrower = trader;\n sentAddresses.receiver = trader;\n /// sentAddresses.manager = address(0); /// The manager.\n\n /// sentAmounts.interestRate = 0; /// interestRate (found later).\n sentAmounts.newPrincipal = totalDeposit;\n /// sentAmounts.interestInitialAmount = 0; /// interestInitialAmount (interest is calculated based on fixed-term loan).\n sentAmounts.loanTokenSent = loanTokenSent;\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n _settleInterest();\n\n (sentAmounts.newPrincipal, sentAmounts.interestRate) = _getMarginBorrowAmountAndRate( /// borrowAmount, interestRate\n leverageAmount,\n sentAmounts.newPrincipal /// depositAmount\n );\n\n require(\n _getAmountInRbtc(loanTokenAddress, sentAmounts.newPrincipal) > TINY_AMOUNT,\n \"principal too small\"\n );\n\n /// @dev Converting to initialMargin\n leverageAmount = SafeMath.div(10**38, leverageAmount);\n sentAmounts.minEntryPrice = minEntryPrice;\n return\n _borrowOrTrade(\n loanId,\n 0, /// withdrawAmount\n leverageAmount, //initial margin\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n );\n }\n\n /**\n * @notice Wrapper for marginTrade invoking setAffiliatesReferrer to track\n * referral trade by affiliates program.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param affiliateReferrer The address of the referrer from affiliates program.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n */\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, /// Value of loan token in collateral\n address affiliateReferrer, /// The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n if (affiliateReferrer != address(0))\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(\n trader,\n affiliateReferrer\n );\n return\n marginTrade(\n loanId,\n leverageAmount,\n loanTokenSent,\n collateralTokenSent,\n collateralTokenAddress,\n trader,\n minEntryPrice,\n loanDataBytes\n );\n }\n\n /* Public View functions */\n\n /**\n * @notice Wrapper for internal _profitOf low level function.\n * @param user The user address.\n * @return The profit of a user.\n * */\n function profitOf(address user) external view returns (int256) {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(user, iToken_ProfitSoFar));\n //TODO + LM balance\n return _profitOf(slot, balances[user], tokenPrice(), checkpointPrices_[user]);\n }\n\n /**\n * @notice Getter for the price checkpoint mapping.\n * @param _user The user account as the mapping index.\n * @return The price on the checkpoint for this user.\n * */\n function checkpointPrice(address _user) public view returns (uint256 price) {\n return checkpointPrices_[_user];\n }\n\n /**\n * @notice Get current liquidity.\n * A part of total funds supplied are borrowed. Liquidity = supply - borrow\n * @return The market liquidity.\n * */\n function marketLiquidity() public view returns (uint256) {\n uint256 totalSupply = _totalAssetSupply(0);\n uint256 totalBorrow = totalAssetBorrow();\n if (totalSupply > totalBorrow) {\n return totalSupply - totalBorrow;\n }\n }\n\n /**\n * @notice Wrapper for average borrow interest.\n * @return The average borrow interest.\n * */\n function avgBorrowInterestRate() public view returns (uint256) {\n return _avgBorrowInterestRate(totalAssetBorrow());\n }\n\n /**\n * @notice Get borrow interest rate.\n * The minimum rate the next base protocol borrower will receive\n * for variable-rate loans.\n * @return The borrow interest rate.\n * */\n function borrowInterestRate() public view returns (uint256) {\n return _nextBorrowInterestRate(0);\n }\n\n /**\n * @notice Public wrapper for internal call.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest rate.\n * */\n function nextBorrowInterestRate(uint256 borrowAmount) public view returns (uint256) {\n return _nextBorrowInterestRate(borrowAmount);\n }\n\n /**\n * @notice Get interest rate.\n *\n * @return Interest that lenders are currently receiving when supplying to\n * the pool.\n * */\n function supplyInterestRate() public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0));\n }\n\n /**\n * @notice Get interest rate w/ added supply.\n * @param supplyAmount The amount of tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of tokens to the pool.\n * */\n function nextSupplyInterestRate(uint256 supplyAmount) public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0).add(supplyAmount));\n }\n\n /**\n * @notice Get interest rate w/ added supply assets.\n * @param assetSupply The amount of loan tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of loan tokens to the pool.\n * */\n function totalSupplyInterestRate(uint256 assetSupply) public view returns (uint256) {\n uint256 assetBorrow = totalAssetBorrow();\n if (assetBorrow != 0) {\n return calculateSupplyInterestRate(assetBorrow, assetSupply);\n }\n }\n\n /**\n * @notice Get the total amount of loan tokens on supply.\n * @dev Wrapper for internal _totalAssetSupply function.\n * @return The total amount of loan tokens on supply.\n * */\n function totalAssetSupply() public view returns (uint256) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _totalAssetSupply(interestUnPaid);\n }\n\n /**\n * @notice Compute the maximum deposit amount under current market conditions.\n * @dev maxEscrowAmount = liquidity * (100 - interestForDuration) / 100\n * @param leverageAmount The chosen multiplier with 18 decimals.\n * */\n function getMaxEscrowAmount(uint256 leverageAmount)\n public\n view\n returns (uint256 maxEscrowAmount)\n {\n /**\n * @dev Mathematical imperfection: depending on liquidity we might be able\n * to borrow more if utilization is below the kink level.\n * */\n uint256 interestForDuration = maxScaleRate.mul(28).div(365);\n uint256 factor = uint256(10**20).sub(interestForDuration);\n uint256 maxLoanSize = marketLiquidity().mul(factor).div(10**20);\n maxEscrowAmount = maxLoanSize.mul(10**18).div(leverageAmount);\n }\n\n /**\n * @notice Get loan token balance.\n * @return The user's balance of underlying token.\n * */\n function assetBalanceOf(address _owner) public view returns (uint256) {\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0)) {\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n _owner\n );\n }\n return balanceOf(_owner).add(balanceOnLM).mul(tokenPrice()).div(10**18);\n }\n\n /**\n * @notice Get margin information on a trade.\n *\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The principal, the collateral and the interestRate.\n * */\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n public\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n )\n {\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n\n (principal, interestRate) = _getMarginBorrowAmountAndRate(leverageAmount, totalDeposit);\n if (principal > _underlyingBalance()) {\n return (0, 0, 0);\n }\n\n loanTokenSent = loanTokenSent.add(principal);\n\n collateral = ProtocolLike(sovrynContractAddress).getEstimatedMarginExposure(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent,\n collateralTokenSent,\n interestRate,\n principal\n );\n }\n\n /**\n * @notice Calculate the deposit required to a given borrow.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param borrowAmount The amount of borrow.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of deposit required.\n * */\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 depositAmount) {\n if (borrowAmount != 0) {\n (, , uint256 newBorrowAmount) =\n _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (newBorrowAmount <= _underlyingBalance()) {\n if (collateralTokenAddress == address(0))\n collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ];\n return\n ProtocolLike(sovrynContractAddress)\n .getRequiredCollateral(\n loanTokenAddress,\n collateralTokenAddress,\n newBorrowAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin\n true /// isTorqueLoan\n )\n .add(10); /// Some dust to compensate for rounding errors.\n }\n }\n }\n\n /**\n * @notice Calculate the borrow allowed for a given deposit.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param depositAmount The amount of deposit.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of borrow allowed.\n * */\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 borrowAmount) {\n if (depositAmount != 0) {\n if (collateralTokenAddress == address(0)) collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))];\n borrowAmount = ProtocolLike(sovrynContractAddress).getBorrowAmount(\n loanTokenAddress,\n collateralTokenAddress,\n depositAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin,\n true /// isTorqueLoan\n );\n\n (, , borrowAmount) = _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (borrowAmount > _underlyingBalance()) {\n borrowAmount = 0;\n }\n }\n }\n\n /**\n * @notice Check if entry price lies above a minimum\n *\n * @param loanTokenSent The amount of deposit.\n * @param collateralTokenAddress The token address of collateral.\n * @param minEntryPrice Value of loan token in collateral\n * */\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) public view {\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokensReceived =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent\n );\n uint256 collateralTokenPrice =\n (collateralTokensReceived.mul(WEI_PRECISION)).div(loanTokenSent);\n require(collateralTokenPrice >= minEntryPrice, \"entry price above the minimum\");\n }\n\n /**\n * @notice Compute the next supply interest adjustment.\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next supply interest adjustment.\n * */\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n public\n view\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply >= assetBorrow) {\n return\n _avgBorrowInterestRate(assetBorrow)\n .mul(_utilizationRate(assetBorrow, assetSupply))\n .mul(\n SafeMath.sub(10**20, ProtocolLike(sovrynContractAddress).lendingFeePercent())\n )\n .div(10**40);\n }\n }\n\n /* Internal functions */\n\n /**\n * @notice Compute what the deposit is worth in loan tokens using the swap rate\n * used for loan size computation.\n *\n * @param collateralTokenAddress The token address of the collateral.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param loanTokenSent The number of loan tokens provided by the user.\n *\n * @return The value of the deposit in loan tokens.\n * */\n function _totalDeposit(\n address collateralTokenAddress,\n uint256 collateralTokenSent,\n uint256 loanTokenSent\n ) internal view returns (uint256 totalDeposit) {\n totalDeposit = loanTokenSent;\n\n if (collateralTokenSent != 0) {\n /// @dev Get the oracle rate from collateral -> loan\n (uint256 collateralToLoanRate, uint256 collateralToLoanPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n collateralTokenAddress,\n loanTokenAddress\n );\n require(\n (collateralToLoanRate != 0) && (collateralToLoanPrecision != 0),\n \"invalid rate collateral token\"\n );\n\n /// @dev Compute the loan token amount with the oracle rate.\n uint256 loanTokenAmount =\n collateralTokenSent.mul(collateralToLoanRate).div(collateralToLoanPrecision);\n\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokenAmount =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenAmount\n );\n\n /// @dev Probably not the same due to the price difference.\n if (collateralTokenAmount != collateralTokenSent) {\n //scale the loan token amount accordingly, so we'll get the expected position size in the end\n loanTokenAmount = loanTokenAmount.mul(collateralTokenAmount).div(\n collateralTokenSent\n );\n }\n\n totalDeposit = loanTokenAmount.add(totalDeposit);\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n asset,\n wrbtcTokenAddress\n );\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /*\n * @notice Compute interest rate and other loan parameters.\n *\n * @param borrowAmount The amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n *\n * @return The interest rate, the interest calculated based on fixed-term\n * loan, and the new borrow amount.\n * */\n function _getInterestRateAndBorrowAmount(\n uint256 borrowAmount,\n uint256 assetSupply,\n uint256 initialLoanDuration /// Duration in seconds.\n )\n internal\n view\n returns (\n uint256 interestRate,\n uint256 interestInitialAmount,\n uint256 newBorrowAmount\n )\n {\n interestRate = _nextBorrowInterestRate2(borrowAmount, assetSupply);\n\n /// newBorrowAmount = borrowAmount * 10^18 / (10^18 - interestRate * 7884000 * 10^18 / 31536000 / 10^20)\n newBorrowAmount = borrowAmount.mul(10**18).div(\n SafeMath.sub(\n 10**18,\n interestRate.mul(initialLoanDuration).mul(10**18).div(31536000 * 10**20) /// 365 * 86400 * 10**20\n )\n );\n\n interestInitialAmount = newBorrowAmount.sub(borrowAmount);\n }\n\n /**\n * @notice Compute principal and collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialMargin The initial margin with 18 decimals\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return The new principal and the new collateral. Principal is the\n * complete borrowed amount (in loan tokens). Collateral is the complete\n * position size (loan + margin) (in collateral tokens).\n * */\n function _borrowOrTrade(\n bytes32 loanId,\n uint256 withdrawAmount,\n uint256 initialMargin,\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n _checkPause();\n require(\n sentAmounts.newPrincipal <= _underlyingBalance() && /// newPrincipal (borrowed amount + fees)\n sentAddresses.borrower != address(0), /// The borrower.\n \"24\"\n );\n\n if (sentAddresses.receiver == address(0)) {\n sentAddresses.receiver = sentAddresses.borrower; /// The receiver = the borrower.\n }\n\n /// @dev Handle transfers prior to adding newPrincipal to loanTokenSent\n uint256 msgValue =\n _verifyTransfers(collateralTokenAddress, sentAddresses, sentAmounts, withdrawAmount);\n\n /**\n * @dev Adding the loan token portion from the lender to loanTokenSent\n * (add the loan to the loan tokens sent from the user).\n * */\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.add(sentAmounts.newPrincipal); /// newPrincipal\n\n if (withdrawAmount != 0) {\n /// @dev withdrawAmount already sent to the borrower, so we aren't sending it to the protocol.\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.sub(withdrawAmount);\n }\n\n bool withdrawAmountExist = false; /// Default is false, but added just as to make sure.\n\n if (withdrawAmount != 0) {\n withdrawAmountExist = true;\n }\n\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, withdrawAmountExist)))\n ];\n\n (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent) = ProtocolLike(\n sovrynContractAddress\n )\n .borrowOrTradeFromPool\n .value(msgValue)(\n loanParamsId,\n loanId,\n withdrawAmountExist,\n initialMargin,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n ); /// newPrincipal, newCollateral\n require(sentAmounts.newPrincipal != 0, \"25\");\n\n /// @dev Setting not-first-trade flag to prevent binding to an affiliate existing users post factum.\n /// @dev REFACTOR: move to a general interface: ProtocolSettingsLike?\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(\n sentAddresses.borrower\n );\n\n return (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent); // newPrincipal, newCollateral\n }\n\n /* Internal View functions */\n\n /**\n * @notice Compute the average borrow interest rate.\n * @param assetBorrow The amount of loan tokens on debt.\n * @return The average borrow interest rate.\n * */\n function _avgBorrowInterestRate(uint256 assetBorrow) internal view returns (uint256) {\n if (assetBorrow != 0) {\n (uint256 interestOwedPerDay, ) = _getAllInterest();\n return interestOwedPerDay.mul(10**20).mul(365).div(assetBorrow);\n }\n }\n\n /**\n * @notice Compute the next borrow interest adjustment.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate(uint256 borrowAmount) internal view returns (uint256) {\n uint256 interestUnPaid;\n if (borrowAmount != 0) {\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n uint256 balance = _underlyingBalance().add(interestUnPaid);\n if (borrowAmount > balance) {\n borrowAmount = balance;\n }\n }\n\n return _nextBorrowInterestRate2(borrowAmount, _totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Compute the next borrow interest adjustment under target-kink\n * level analysis.\n *\n * The \"kink\" in the cDAI interest rate model reflects the utilization rate\n * at which the slope of the interest rate goes from \"gradual\" to \"steep\".\n * That is, below this utilization rate, the slope of the interest rate\n * curve is gradual. Above this utilization rate, it is steep.\n *\n * Because of this dynamic between the interest rate curves before and\n * after the \"kink\", the \"kink\" can be thought of as the target utilization\n * rate. Above that rate, it quickly becomes expensive to borrow (and\n * commensurately lucrative for suppliers).\n *\n * @param newBorrowAmount The new amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate2(uint256 newBorrowAmount, uint256 assetSupply)\n internal\n view\n returns (uint256 nextRate)\n {\n uint256 utilRate = _utilizationRate(totalAssetBorrow().add(newBorrowAmount), assetSupply);\n\n uint256 thisMinRate;\n uint256 thisRateAtKink;\n uint256 thisBaseRate = baseRate;\n uint256 thisRateMultiplier = rateMultiplier;\n uint256 thisTargetLevel = targetLevel;\n uint256 thisKinkLevel = kinkLevel;\n uint256 thisMaxScaleRate = maxScaleRate;\n\n if (utilRate < thisTargetLevel) {\n // target targetLevel utilization when utilization is under targetLevel\n utilRate = thisTargetLevel;\n }\n\n if (utilRate > thisKinkLevel) {\n /// @dev Scale rate proportionally up to 100%\n uint256 thisMaxRange = WEI_PERCENT_PRECISION - thisKinkLevel; /// Will not overflow.\n\n utilRate -= thisKinkLevel;\n if (utilRate > thisMaxRange) utilRate = thisMaxRange;\n\n // Modified the rate calculation as it is slightly exaggerated around kink level\n // thisRateAtKink = thisRateMultiplier.add(thisBaseRate).mul(thisKinkLevel).div(WEI_PERCENT_PRECISION);\n thisRateAtKink = thisKinkLevel.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n nextRate = utilRate\n .mul(SafeMath.sub(thisMaxScaleRate, thisRateAtKink))\n .div(thisMaxRange)\n .add(thisRateAtKink);\n } else {\n nextRate = utilRate.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n thisMinRate = thisBaseRate;\n thisRateAtKink = thisRateMultiplier.add(thisBaseRate);\n\n if (nextRate < thisMinRate) nextRate = thisMinRate;\n else if (nextRate > thisRateAtKink) nextRate = thisRateAtKink;\n }\n }\n\n /**\n * @notice Compute the loan size and interest rate.\n * @param leverageAmount The leverage with 18 decimals.\n * @param depositAmount The amount the user deposited in underlying loan tokens.\n * @return borrowAmount The amount of tokens to borrow.\n * @return interestRate The interest rate to pay on the position.\n * */\n function _getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n internal\n view\n returns (uint256 borrowAmount, uint256 interestRate)\n {\n uint256 loanSizeBeforeInterest = depositAmount.mul(leverageAmount).div(10**18);\n /**\n * @dev Mathematical imperfection. we calculate the interest rate based on\n * the loanSizeBeforeInterest, but the actual borrowed amount will be bigger.\n * */\n interestRate = _nextBorrowInterestRate2(loanSizeBeforeInterest, _totalAssetSupply(0));\n /// @dev Assumes that loan, collateral, and interest token are the same.\n borrowAmount = _adjustLoanSize(interestRate, 28 days, loanSizeBeforeInterest);\n }\n\n /**\n * @notice Make sure call is not paused.\n * @dev Used for internal verification if the called function is paused.\n * It throws an exception in case it's not.\n * */\n function _checkPause() internal view {\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n msg.sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n bool isPaused;\n assembly {\n isPaused := sload(slot)\n }\n require(!isPaused, \"unauthorized\");\n }\n\n /**\n * @notice Adjusts the loan size to make sure the expected exposure remains after prepaying the interest.\n * @dev loanSizeWithInterest = loanSizeBeforeInterest * 100 / (100 - interestForDuration)\n * @param interestRate The interest rate to pay on the position.\n * @param maxDuration The maximum duration of the position (until rollover).\n * @param loanSizeBeforeInterest The loan size before interest is added.\n * */\n function _adjustLoanSize(\n uint256 interestRate,\n uint256 maxDuration,\n uint256 loanSizeBeforeInterest\n ) internal pure returns (uint256 loanSizeWithInterest) {\n uint256 interestForDuration = interestRate.mul(maxDuration).div(365 days);\n uint256 divisor = uint256(10**20).sub(interestForDuration);\n loanSizeWithInterest = loanSizeBeforeInterest.mul(10**20).div(divisor);\n }\n\n /**\n * @notice Calculate the utilization rate.\n * @dev Utilization rate = assetBorrow / assetSupply\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The utilization rate.\n * */\n function _utilizationRate(uint256 assetBorrow, uint256 assetSupply)\n internal\n pure\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply != 0) {\n /// U = total_borrow / total_supply\n return assetBorrow.mul(10**20).div(assetSupply);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./AdvancedToken.sol\";\n\ncontract LoanTokenLogicStorage is AdvancedToken {\n /// DO NOT ADD VARIABLES HERE - SEE BELOW\n\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /// @dev Add new variables here on the bottom.\n address public earlyAccessToken; //not used anymore, but staying for upgradability\n address public pauser;\n /** The address of the liquidity mining contract */\n address public liquidityMiningAddress;\n\n /** The address of the staking contract */\n address public stakingContractAddress;\n\n /// @dev Used by flashBorrow function.\n uint256 public constant VERSION = 6;\n /// @dev Used by flashBorrow function.\n address internal constant arbitraryCaller = 0x000F400e6818158D541C3EBE45FE3AA0d47372FF;\n bytes32 internal constant iToken_ProfitSoFar =\n 0x37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb6; // keccak256(\"iToken_ProfitSoFar\")\n uint256 public constant TINY_AMOUNT = 25e13;\n\n function stringToBytes32(string memory source) public pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"unauthorized\"); // SS02\n _;\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogic is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenMintAndBurn also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenLogicStandard also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\")); /// LoanTokenLogicStandard\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\")); /// LoanTokenLogicLM\n res[2] = bytes4(keccak256(\"burn(address,uint256)\")); /// LoanTokenLogicStandard\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\")); /// LoanTokenLogicLM\n\n return (res, stringToBytes32(\"LoanTokenLogicLM\"));\n }\n\n /**\n * @notice deposit into the lending pool and optionally participate at the Liquidity Mining Program\n * @param receiver the receiver of the tokens\n * @param depositAmount The amount of underlying tokens provided on the loan.\n *\t\t\t\t\t\t(Not the number of loan tokens to mint).\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 minted) {\n if (useLM) return _mintWithLM(receiver, depositAmount);\n else return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice withdraws from the lending pool and optionally retrieves the pool tokens from the\n * Liquidity Mining Contract\n * @param receiver the receiver of the underlying tokens. note: potetial LM rewards are always sent to the msg.sender\n * @param burnAmount The amount of pool tokens to redeem.\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 redeemed) {\n if (useLM) redeemed = _burnFromLM(burnAmount);\n else redeemed = _burnToken(burnAmount);\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (redeemed != 0) {\n _safeTransfer(loanTokenAddress, receiver, redeemed, \"asset transfer failed\");\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtc.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogicWrbtc is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtc\"));\n }\n\n /**\n * @dev internal override functions\n * @dev Put all of internal override function dedicated to the loanTokenWrtbc module here\n * e.g: _verifyTransfers will override the implementation of _verifyTransfers in loanTokenLogicSplit\n */\n\n /**\n * @notice Handle transfers prior to adding newPrincipal to loanTokenSent.\n *\n * @param collateralTokenAddress The address of the collateral token.\n * @param sentAddresses The struct which contains addresses of\n * - lender\n * - borrower\n * - receiver\n * - manager\n *\n * @param sentAmounts The struct which contains uint256 of:\n * - interestRate\n * - newPrincipal\n * - interestInitialAmount\n * - loanTokenSent\n * - collateralTokenSent\n *\n * @param withdrawalAmount The amount to withdraw.\n *\n * @return msgValue The amount of value sent.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = _wrbtcToken;\n address receiver = sentAddresses.receiver;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n IWrbtcERC20(_wrbtcToken).withdraw(withdrawalAmount);\n Address.sendValue(receiver, withdrawalAmount);\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n\n if (collateralTokenSent != 0) {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28\"\n );\n }\n\n if (loanTokenSent != 0) {\n if (msgValue != 0 && msgValue >= loanTokenSent) {\n IWrbtc(_wrbtcToken).deposit.value(loanTokenSent)();\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, loanTokenSent, \"29\");\n msgValue -= loanTokenSent;\n } else {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtcLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicWrbtcLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token Mint and Burn.\n res[0] = this.mint.selector;\n res[1] = this.burn.selector;\n\n // Loan Token WRBTC\n res[2] = this.mintWithBTC.selector;\n res[3] = this.burnToBTC.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtcLM\"));\n }\n\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n if (useLM) return _mintWithLM(receiver, msg.value);\n else return _mintToken(receiver, msg.value);\n }\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 loanAmountPaid) {\n loanAmountPaid = useLM ? _burnFromLM(burnAmount) : _burnToken(burnAmount);\n\n if (loanAmountPaid != 0) {\n IWrbtcERC20(wrbtcTokenAddress).withdraw(loanAmountPaid);\n Address.sendValue(receiver, loanAmountPaid);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/shared/LoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../AdvancedToken.sol\";\nimport \"../../interfaces/ProtocolSettingsLike.sol\";\nimport \"../../LoanTokenLogicStorage.sol\";\n\ncontract LoanTokenSettingsLowerAdmin is LoanTokenLogicStorage {\n using SafeMath for uint256;\n\n /// @dev TODO: Check for restrictions in this contract.\n modifier onlyAdmin() {\n require(isOwner() || msg.sender == admin, \"unauthorized\");\n _;\n }\n\n /* Events */\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](15);\n res[0] = this.setAdmin.selector;\n res[1] = this.setPauser.selector;\n res[2] = this.setupLoanParams.selector;\n res[3] = this.disableLoanParams.selector;\n res[4] = this.setDemandCurve.selector;\n res[5] = this.toggleFunctionPause.selector;\n res[6] = this.setTransactionLimits.selector;\n res[7] = this.changeLoanTokenNameAndSymbol.selector;\n res[8] = this.pauser.selector;\n res[9] = this.setLiquidityMiningAddress.selector;\n res[10] = this.withdrawRBTCTo.selector;\n res[11] = this.getLiquidityMiningAddress.selector;\n res[12] = this.checkPause.selector;\n res[13] = this.setStakingContractAddress.selector;\n res[14] = this.getStakingContractAddress.selector;\n return (res, stringToBytes32(\"LoanTokenSettingsLowerAdmin\"));\n }\n\n /**\n * @notice Set admin account.\n * @param _admin The address of the account to grant admin permissions.\n * */\n function setAdmin(address _admin) public onlyOwner {\n admin = _admin;\n }\n\n /**\n * @notice Set pauser account.\n * @param _pauser The address of the account to grant pause permissions.\n * */\n function setPauser(address _pauser) public onlyOwner {\n pauser = _pauser;\n }\n\n /**\n * @notice Fallback function not allowed\n * */\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n /**\n * @notice Set loan token parameters.\n *\n * @param loanParamsList The array of loan parameters.\n * @param areTorqueLoans Whether the loan is a torque loan.\n * */\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans /// isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n /**\n * @notice Disable loan token parameters.\n *\n * @param collateralTokens The array of collateral tokens.\n * @param isTorqueLoans Whether the loan is a torque loan.\n * */\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n /**\n * @notice Set loan token parameters about the demand curve.\n *\n * @dev These params should be percentages represented\n * like so: 5% = 5000000000000000000 /// 18 digits precision.\n * rateMultiplier + baseRate can't exceed 100%\n *\n * To maintain a healthy credit score, it's important to keep your\n * credit utilization rate (CUR) low (_lowUtilBaseRate). In general\n * you don't want your CUR to exceed 30%, but increasingly financial\n * experts are recommending that you don't want to go above 10% if you\n * really want an excellent credit score.\n *\n * Interest rates tend to cluster around the kink level of a kinked\n * interest rate model. More info at https://arxiv.org/pdf/2006.13922.pdf\n * and https://compound.finance/governance/proposals/12\n *\n * @param _baseRate The interest rate.\n * @param _rateMultiplier The precision multiplier for base rate.\n * @param _lowUtilBaseRate The credit utilization rate (CUR) low value.\n * @param _lowUtilRateMultiplier The precision multiplier for low util base rate.\n * @param _targetLevel The target level.\n * @param _kinkLevel The level that interest rates cluster on kinked model.\n * @param _maxScaleRate The maximum rate of the scale.\n * */\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; /// 80 ether\n kinkLevel = _kinkLevel; /// 90 ether\n maxScaleRate = _maxScaleRate; /// 100 ether\n }\n\n /**\n * @notice Set the pause flag for a function to true or false.\n *\n * @dev Combining the hash of \"iToken_FunctionPause\" string and a function\n * selector gets a slot to write a flag for pause state.\n *\n * @param funcId The ID of a function, the selector.\n * @param isPaused true/false value of the flag.\n * */\n function toggleFunctionPause(\n string memory funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyPauserOrOwner {\n bool paused;\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n paused := sload(slot)\n }\n require(paused != isPaused, \"isPaused is already set to that value\");\n assembly {\n sstore(slot, isPaused)\n }\n emit ToggledFunctionPaused(funcId, !isPaused, isPaused);\n }\n\n /**\n * Set the transaction limit per token address.\n * @param addresses The token addresses.\n * @param limits The limit denominated in the currency of the token address.\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyAdmin\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n\n /**\n *\t@notice Update the loan token parameters.\n *\t@param _name The new name of the loan token.\n *\t@param _symbol The new symbol of the loan token.\n * */\n function changeLoanTokenNameAndSymbol(string memory _name, string memory _symbol)\n public\n onlyAdmin\n {\n name = _name;\n symbol = _symbol;\n }\n\n /**\n * @notice Withdraws RBTC from the contract by Multisig.\n * @param _receiverAddress The address where the rBTC has to be transferred.\n * @param _amount The amount of rBTC to be transferred.\n */\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external onlyOwner {\n require(_receiverAddress != address(0), \"receiver address invalid\");\n require(_amount > 0, \"non-zero withdraw amount expected\");\n require(_amount <= address(this).balance, \"withdraw amount cannot exceed balance\");\n _receiverAddress.transfer(_amount);\n emit WithdrawRBTCTo(_receiverAddress, _amount);\n }\n\n /**\n * @notice sets the liquidity mining contract address\n * @param LMAddress the address of the liquidity mining contract\n */\n function setLiquidityMiningAddress(address LMAddress) external onlyOwner {\n liquidityMiningAddress = LMAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for liquidityMiningAddress\n\n\t * @return liquidityMiningAddress\n\t */\n function getLiquidityMiningAddress() public view returns (address) {\n return liquidityMiningAddress;\n }\n\n /**\n * @notice sets the staking contract address\n * @param _stakingContractAddress the address of the staking contract\n */\n function setStakingContractAddress(address _stakingContractAddress) external onlyOwner {\n stakingContractAddress = _stakingContractAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for stakingContractAddress\n\n\t * @return stakingContractAddress\n\t */\n function getStakingContractAddress() public view returns (address) {\n return stakingContractAddress;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param funcId The function ID, the selector.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function checkPause(string memory funcId) public view returns (bool isPaused) {\n bytes4 sig = bytes4(keccak256(abi.encodePacked(funcId)));\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n isPaused := sload(slot)\n }\n return isPaused;\n }\n}\n" + }, + "contracts/connectors/loantoken/Pausable.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Pausable contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * The contract implements pausable functionality by reading on slots the\n * pause state of contract functions.\n * */\ncontract Pausable {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 internal constant Pausable_FunctionPause =\n 0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047;\n\n modifier pausable(bytes4 sig) {\n require(!_isPaused(sig), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param sig The function ID, the selector on bytes4.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function _isPaused(bytes4 sig) internal view returns (bool isPaused) {\n bytes32 slot = keccak256(abi.encodePacked(sig, Pausable_FunctionPause));\n assembly {\n isPaused := sload(slot)\n }\n }\n}\n" + }, + "contracts/core/Objects.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./objects/LoanStruct.sol\";\nimport \"./objects/LoanParamsStruct.sol\";\nimport \"./objects/OrderStruct.sol\";\nimport \"./objects/LenderInterestStruct.sol\";\nimport \"./objects/LoanInterestStruct.sol\";\n\n/**\n * @title Objects contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract inherints and aggregates several structures needed to handle\n * loans on the protocol.\n * */\ncontract Objects is\n LoanStruct,\n LoanParamsStruct,\n OrderStruct,\n LenderInterestStruct,\n LoanInterestStruct\n{\n\n}\n" + }, + "contracts/core/objects/LenderInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Lender Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Lender Interest.\n * */\ncontract LenderInterestStruct {\n struct LenderInterest {\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\n uint256 paidTotal; /// Total interest paid so far for asset.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Interest.\n * */\ncontract LoanInterestStruct {\n struct LoanInterest {\n uint256 owedPerDay; /// Interest owed per day for loan.\n uint256 depositTotal; /// Total escrowed interest for loan.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanParamsStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Parameters.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Parameters.\n * */\ncontract LoanParamsStruct {\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n}\n" + }, + "contracts/core/objects/LoanStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Object.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Object.\n * */\ncontract LoanStruct {\n struct Loan {\n bytes32 id; /// ID of the loan.\n bytes32 loanParamsId; /// The linked loan params ID.\n bytes32 pendingTradesId; /// The linked pending trades ID.\n bool active; /// If false, the loan has been fully closed.\n uint256 principal; /// Total borrowed amount outstanding.\n uint256 collateral; /// Total collateral escrowed for the loan.\n uint256 startTimestamp; /// Loan start time.\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\n uint256 startMargin; /// Initial margin when the loan opened.\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\n address borrower; /// Borrower of this loan.\n address lender; /// Lender of this loan.\n }\n}\n" + }, + "contracts/core/objects/OrderStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Order.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Order.\n * */\ncontract OrderStruct {\n struct Order {\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\n uint256 interestRate; /// Interest rate defined by the creator of this order.\n uint256 minLoanTerm; /// Minimum loan term allowed.\n uint256 maxLoanTerm; /// Maximum loan term allowed.\n uint256 createdTimestamp; /// Timestamp when this order was created.\n uint256 expirationTimestamp; /// Timestamp when this order expires.\n }\n}\n" + }, + "contracts/core/Protocol.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./State.sol\";\n\n/**\n * @title Sovryn Protocol contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the proxy functionality to deploy Protocol anchor\n * and logic apart, turning it upgradable.\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822\n * */\ncontract sovrynProtocol is State {\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = logicTargets[msg.sig];\n require(target != address(0), \"target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice External owner target initializer.\n * @param target The target addresses.\n * */\n function replaceContract(address target) external onlyOwner {\n (bool success, ) =\n target.delegatecall(abi.encodeWithSignature(\"initialize(address)\", target));\n require(success, \"setup failed\");\n }\n\n /**\n * @notice External owner setter for target addresses.\n * @param sigsArr The array of signatures.\n * @param targetsArr The array of addresses.\n * */\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr)\n external\n onlyOwner\n {\n require(sigsArr.length == targetsArr.length, \"count mismatch\");\n\n for (uint256 i = 0; i < sigsArr.length; i++) {\n _setTarget(bytes4(keccak256(abi.encodePacked(sigsArr[i]))), targetsArr[i]);\n }\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(string calldata sig) external view returns (address) {\n return logicTargets[bytes4(keccak256(abi.encodePacked(sig)))];\n }\n}\n" + }, + "contracts/core/State.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./Objects.sol\";\nimport \"../mixins/EnumerableAddressSet.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/ReentrancyGuard.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title State contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage values of the Protocol.\n * */\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\n using SafeMath for uint256;\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n\n /// Handles asset reference price lookups.\n address public priceFeeds;\n\n /// Handles asset swaps using dex liquidity.\n address public swapsImpl;\n\n /// Contract registry address of the Sovryn swap network.\n address public sovrynSwapContractRegistryAddress;\n\n /// Implementations of protocol functions.\n mapping(bytes4 => address) public logicTargets;\n\n /// Loans: loanId => Loan\n mapping(bytes32 => Loan) public loans;\n\n /// Loan parameters: loanParamsId => LoanParams\n mapping(bytes32 => LoanParams) public loanParams;\n\n /// lender => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\n\n /// borrower => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\n\n /// loanId => delegated => approved\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\n\n /**\n *** Interest ***\n **/\n\n /// lender => loanToken => LenderInterest object\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\n\n /// loanId => LoanInterest object\n mapping(bytes32 => LoanInterest) public loanInterest;\n\n /**\n *** Internals ***\n **/\n\n /// Implementations set.\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\n\n /// Active loans set.\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\n\n /// Lender loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\n\n /// Borrow loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\n\n /// User loan params set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\n\n /// Address controlling fee withdrawals.\n address public feesController;\n\n /// 10% fee /// Fee taken from lender interest payments.\n uint256 public lendingFeePercent = 10**19;\n\n /// Total interest fees received and not withdrawn per asset.\n mapping(address => uint256) public lendingFeeTokensHeld;\n\n /// Total interest fees withdraw per asset.\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\n mapping(address => uint256) public lendingFeeTokensPaid;\n\n /// 0.15% fee /// Fee paid for each trade.\n uint256 public tradingFeePercent = 15 * 10**16;\n\n /// Total trading fees received and not withdrawn per asset.\n mapping(address => uint256) public tradingFeeTokensHeld;\n\n /// Total trading fees withdraw per asset\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\n mapping(address => uint256) public tradingFeeTokensPaid;\n\n /// 0.09% fee /// Origination fee paid for each loan.\n uint256 public borrowingFeePercent = 9 * 10**16;\n\n /// Total borrowing fees received and not withdrawn per asset.\n mapping(address => uint256) public borrowingFeeTokensHeld;\n\n /// Total borrowing fees withdraw per asset.\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\n mapping(address => uint256) public borrowingFeeTokensPaid;\n\n /// Current protocol token deposit balance.\n uint256 public protocolTokenHeld;\n\n /// Lifetime total payout of protocol token.\n uint256 public protocolTokenPaid;\n\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\n uint256 public affiliateFeePercent = 5 * 10**18;\n\n /// 5% collateral discount /// Discount on collateral for liquidators.\n uint256 public liquidationIncentivePercent = 5 * 10**18;\n\n /// loanPool => underlying\n mapping(address => address) public loanPoolToUnderlying;\n\n /// underlying => loanPool\n mapping(address => address) public underlyingToLoanPool;\n\n /// Loan pools set.\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\n\n /// Supported tokens for swaps.\n mapping(address => bool) public supportedTokens;\n\n /// % disagreement between swap rate and reference rate.\n uint256 public maxDisagreement = 5 * 10**18;\n\n /// Used as buffer for swap source amount estimations.\n uint256 public sourceBuffer = 10000;\n\n /// Maximum support swap size in rBTC\n uint256 public maxSwapSize = 50 ether;\n\n /// Nonce per borrower. Used for loan id creation.\n mapping(address => uint256) public borrowerNonce;\n\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\n uint256 public rolloverBaseReward = 16800000000000;\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\n\n IWrbtcERC20 public wrbtcToken;\n address public protocolTokenAddress;\n\n /// 50% fee rebate\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\n uint256 public feeRebatePercent = 50 * 10**18;\n\n address public admin;\n\n /// For modules interaction.\n address public protocolAddress;\n\n /**\n *** Affiliates ***\n **/\n\n /// The flag is set on the user's first trade.\n mapping(address => bool) public userNotFirstTradeFlag;\n\n /// User => referrer (affiliate).\n mapping(address => address) public affiliatesUserReferrer;\n\n /// List of referral addresses affiliated to the referrer.\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\n\n /// @dev Referral threshold for paying out to the referrer.\n /// The referrer reward is being accumulated and locked until the threshold is passed.\n uint256 public minReferralsToPayout = 3;\n\n /// @dev Total affiliate SOV rewards that held in the protocol\n /// (Because the minimum referrals is less than the rule)\n mapping(address => uint256) public affiliateRewardsHeld;\n\n /// @dev For affiliates SOV Bonus proccess.\n address public sovTokenAddress;\n address public lockedSOVAddress;\n\n /// @dev 20% fee share of trading token fee.\n /// Fee share of trading token fee for affiliate program.\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\n\n /// @dev Addresses of tokens in which commissions were paid to referrers.\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\n\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\n\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\n bool public pause; //Flag to pause all protocol modules\n\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\n\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\n uint256 internal tradingRebateRewardsBasisPoint;\n\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\n /// Will be used in internal swap.\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\n\n address internal pauser;\n\n /**\n * @notice Add signature and target to storage.\n * @dev Protocol is a proxy and requires a way to add every\n * module function dynamically during deployment.\n * */\n function _setTarget(bytes4 sig, address target) internal {\n logicTargets[sig] = target;\n\n if (target != address(0)) {\n logicTargetsSet.addBytes32(bytes32(sig));\n } else {\n logicTargetsSet.removeBytes32(bytes32(sig));\n }\n }\n\n modifier onlyAdminOrOwner() {\n require(isOwner() || admin == (msg.sender), \"unauthorized\");\n _;\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || pauser == (msg.sender), \"unauthorized\");\n _;\n }\n}\n" + }, + "contracts/escrow/Escrow.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Ethereum Pool to accept SOV Token.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice You can use this contract for deposit of SOV tokens for some time and withdraw later.\n */\ncontract Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalDeposit;\n /// @notice The release timestamp for the tokens deposited.\n uint256 public releaseTime;\n /// @notice The amount of token we would be accepting as deposit at max.\n uint256 public depositLimit;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The multisig contract which handles the fund.\n address public multisig;\n\n /// @notice The user balances.\n mapping(address => uint256) userBalances;\n\n /// @notice The current contract status.\n /// @notice Deployed - Deployed the contract.\n /// @notice Deposit - Time to deposit in the contract by the users.\n /// @notice Holding - Deposit is closed and now the holding period starts.\n /// @notice Withdraw - Time to withdraw in the contract by the users.\n /// @notice Expired - The contract is now closed completely.\n enum Status { Deployed, Deposit, Holding, Withdraw, Expired }\n Status public status;\n\n /* Events */\n\n /// @notice Emitted when the contract deposit starts.\n event EscrowActivated();\n\n /// @notice Emitted when the contract is put in holding state. No new token deposit accepted by User.\n event EscrowInHoldingState();\n\n /// @notice Emitted when the contract is put in withdraw state. Users can now withdraw tokens.\n event EscrowInWithdrawState();\n\n /// @notice Emitted when the contract is expired after withdraws are made/total token transfer.\n event EscrowFundExpired();\n\n /// @notice Emitted when a new multisig is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newMultisig The address which is added as the new multisig.\n /// @dev Can only be initiated by the current multisig.\n event NewMultisig(address indexed _initiator, address indexed _newMultisig);\n\n /// @notice Emitted when the release timestamp is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseTimestamp The updated release timestamp for the withdraw.\n event TokenReleaseUpdated(address indexed _initiator, uint256 _releaseTimestamp);\n\n /// @notice Emitted when the deposit limit is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _depositLimit The updated deposit limit.\n event TokenDepositLimitUpdated(address indexed _initiator, uint256 _depositLimit);\n\n /// @notice Emitted when a new token deposit is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when we reach the token deposit limit.\n event DepositLimitReached();\n\n /// @notice Emitted when a token withdraw is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdrawByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyMultisig() {\n require(msg.sender == multisig, \"Only Multisig can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n modifier checkRelease() {\n require(\n releaseTime != 0 && releaseTime <= block.timestamp,\n \"The release time has not started yet.\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_multisig != address(0), \"Invalid Multisig Address.\");\n\n SOV = IERC20(_SOV);\n multisig = _multisig;\n\n emit NewMultisig(msg.sender, _multisig);\n\n releaseTime = _releaseTime;\n depositLimit = _depositLimit;\n\n status = Status.Deployed;\n }\n\n /**\n * @notice This function is called once after deployment for starting the deposit action.\n * @dev Without calling this function, the contract will not start accepting tokens.\n */\n function init() external onlyMultisig checkStatus(Status.Deployed) {\n status = Status.Deposit;\n\n emit EscrowActivated();\n }\n\n /**\n * @notice Update Multisig.\n * @param _newMultisig The new owner of the tokens & contract.\n */\n function updateMultisig(address _newMultisig) external onlyMultisig {\n require(_newMultisig != address(0), \"New Multisig address invalid.\");\n\n multisig = _newMultisig;\n\n emit NewMultisig(msg.sender, _newMultisig);\n }\n\n /**\n * @notice Update Release Timestamp.\n * @param _newReleaseTime The new release timestamp for token release.\n * @dev Zero is also a valid timestamp, if the release time is not scheduled yet.\n */\n function updateReleaseTimestamp(uint256 _newReleaseTime) external onlyMultisig {\n releaseTime = _newReleaseTime;\n\n emit TokenReleaseUpdated(msg.sender, _newReleaseTime);\n }\n\n /**\n * @notice Update Deposit Limit.\n * @param _newDepositLimit The new deposit limit.\n * @dev IMPORTANT: Should not decrease than already deposited.\n */\n function updateDepositLimit(uint256 _newDepositLimit) external onlyMultisig {\n require(\n _newDepositLimit >= totalDeposit,\n \"Deposit already higher than the limit trying to be set.\"\n );\n depositLimit = _newDepositLimit;\n\n emit TokenDepositLimitUpdated(msg.sender, _newDepositLimit);\n }\n\n /**\n * @notice Deposit tokens to this contract by User.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the user inorder for this function to work.\n * These tokens can be withdrawn/transferred during Holding State by the Multisig.\n */\n function depositTokens(uint256 _amount) external checkStatus(Status.Deposit) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n uint256 amount = _amount;\n\n if (totalDeposit.add(_amount) >= depositLimit) {\n amount = depositLimit.sub(totalDeposit);\n emit DepositLimitReached();\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n userBalances[msg.sender] = userBalances[msg.sender].add(amount);\n totalDeposit = totalDeposit.add(amount);\n\n emit TokenDeposit(msg.sender, amount);\n }\n\n /**\n * @notice Update contract state to Holding.\n * @dev Once called, the contract no longer accepts any more deposits.\n * The multisig can now withdraw tokens from the contract after the contract is in Holding State.\n */\n function changeStateToHolding() external onlyMultisig checkStatus(Status.Deposit) {\n status = Status.Holding;\n\n emit EscrowInHoldingState();\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred. Zero address if the withdraw is to be done in Multisig.\n * @dev Can only be called after the token state is changed to Holding.\n */\n function withdrawTokensByMultisig(address _receiverAddress)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n address receiverAddress = msg.sender;\n if (_receiverAddress != address(0)) {\n receiverAddress = _receiverAddress;\n }\n\n uint256 value = SOV.balanceOf(address(this));\n /// Sending the amount to multisig.\n bool txStatus = SOV.transfer(receiverAddress, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdrawByMultisig(msg.sender, value);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n * Once the token deposit is higher than the total deposits done, the contract state is changed to Withdraw.\n */\n function depositTokensByMultisig(uint256 _amount)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDepositByMultisig(msg.sender, _amount);\n\n if (SOV.balanceOf(address(this)) >= totalDeposit) {\n status = Status.Withdraw;\n emit EscrowInWithdrawState();\n }\n }\n\n /**\n * @notice Withdraws token from the contract by User.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokens() public checkRelease checkStatus(Status.Withdraw) {\n uint256 amount = userBalances[msg.sender];\n userBalances[msg.sender] = 0;\n bool txStatus = SOV.transfer(msg.sender, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdraw(msg.sender, amount);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token balance of a particular user.\n * @return _addr The user address whose balance has to be checked.\n */\n function getUserBalance(address _addr) external view returns (uint256 balance) {\n return userBalances[_addr];\n }\n}\n" + }, + "contracts/escrow/EscrowReward.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Escrow.sol\";\nimport \"../locked/ILockedSOV.sol\";\n\n/**\n * @title A reward distribution contract for Sovryn Ethereum Pool Escrow Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice Multisig can use this contract for depositing of Reward tokens based on the total token deposit.\n */\ncontract EscrowReward is Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total reward tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalRewardDeposit;\n\n /// @notice The Locked SOV contract.\n ILockedSOV public lockedSOV;\n\n /* Events */\n\n /// @notice Emitted when the Locked SOV Contract address is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _lockedSOV The address of the Locked SOV Contract.\n event LockedSOVUpdated(address indexed _initiator, address indexed _lockedSOV);\n\n /// @notice Emitted when a new reward token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event RewardDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a Reward token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event RewardTokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _lockedSOV The Locked SOV Contract address.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _lockedSOV,\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public Escrow(_SOV, _multisig, _releaseTime, _depositLimit) {\n if (_lockedSOV != address(0)) {\n lockedSOV = ILockedSOV(_lockedSOV);\n }\n }\n\n /**\n * @notice Set the Locked SOV Contract Address if not already done.\n * @param _lockedSOV The Locked SOV Contract address.\n */\n function updateLockedSOV(address _lockedSOV) external onlyMultisig {\n require(_lockedSOV != address(0), \"Invalid Reward Token Address.\");\n\n lockedSOV = ILockedSOV(_lockedSOV);\n\n emit LockedSOVUpdated(msg.sender, _lockedSOV);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n */\n function depositRewardByMultisig(uint256 _amount) external onlyMultisig {\n require(\n status != Status.Withdraw,\n \"Reward Token deposit is only allowed before User Withdraw starts.\"\n );\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n totalRewardDeposit = totalRewardDeposit.add(_amount);\n txStatus = SOV.approve(address(lockedSOV), totalRewardDeposit);\n require(txStatus, \"Token Approval was not successful.\");\n\n emit RewardDepositByMultisig(msg.sender, _amount);\n }\n\n /**\n * @notice Withdraws token and reward from the contract by User. Reward is gone to lockedSOV contract for future vesting.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokensAndReward() external checkRelease checkStatus(Status.Withdraw) {\n // Reward calculation have to be done initially as the User Balance is zeroed out .\n uint256 reward = userBalances[msg.sender].mul(totalRewardDeposit).div(totalDeposit);\n withdrawTokens();\n\n lockedSOV.depositSOV(msg.sender, reward);\n\n emit RewardTokenWithdraw(msg.sender, reward);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the reward a particular user can get.\n * @param _addr The address of the user whose reward is to be read.\n * @return reward The reward received by the user.\n */\n function getReward(address _addr) external view returns (uint256 reward) {\n if (userBalances[_addr].mul(totalRewardDeposit) == 0) {\n return 0;\n }\n return userBalances[_addr].mul(totalRewardDeposit).div(totalDeposit);\n }\n}\n" + }, + "contracts/events/AffiliatesEvents.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\ncontract AffiliatesEvents is ModulesCommonEvents {\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\n\n event SetAffiliatesReferrerFail(\n address indexed user,\n address indexed referrer,\n bool alreadySet,\n bool userNotFirstTrade\n );\n\n event SetUserNotFirstTradeFlag(address indexed user);\n\n event PayTradingFeeToAffiliate(\n address indexed referrer,\n address trader,\n address indexed token,\n bool indexed isHeld,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountPaid\n );\n\n event PayTradingFeeToAffiliateFail(\n address indexed referrer,\n address trader,\n address indexed token,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountTryingToPaid\n );\n\n event WithdrawAffiliatesReferrerTokenFees(\n address indexed referrer,\n address indexed receiver,\n address indexed tokenAddress,\n uint256 amount\n );\n}\n" + }, + "contracts/events/FeesEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Fees Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for fee payments.\n * */\ncontract FeesEvents {\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\n\n event PayTradingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event PayBorrowingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event EarnReward(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n\n event EarnRewardFail(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n}\n" + }, + "contracts/events/LoanClosingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Closing Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan closing operations.\n * */\ncontract LoanClosingsEvents is ModulesCommonEvents {\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\n event CloseWithDeposit(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address closer,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\n event CloseWithSwap(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n address closer,\n uint256 positionCloseSize,\n uint256 loanCloseAmount,\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\n uint256 currentLeverage\n );\n\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\n event Liquidate(\n address indexed user,\n address indexed liquidator,\n bytes32 indexed loanId,\n address lender,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n event Rollover(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n uint256 principal,\n uint256 collateral,\n uint256 endTimestamp,\n address rewardReceiver,\n uint256 reward\n );\n\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\n}\n" + }, + "contracts/events/LoanMaintenanceEvents.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Maintenance Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan maintenance operations.\n * */\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\n}\n" + }, + "contracts/events/LoanOpeningsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Openings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan openings operations.\n * */\ncontract LoanOpeningsEvents is ModulesCommonEvents {\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\n event Borrow(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 newCollateral,\n uint256 interestRate,\n uint256 interestDuration,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\n event Trade(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n uint256 positionSize,\n uint256 borrowedAmount,\n uint256 interestRate,\n uint256 settlementDate,\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\n uint256 entryLeverage,\n uint256 currentLeverage\n );\n\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\n event DelegatedManagerSet(\n bytes32 indexed loanId,\n address indexed delegator,\n address indexed delegated,\n bool isActive\n );\n}\n" + }, + "contracts/events/LoanSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan settings operations.\n * */\ncontract LoanSettingsEvents is ModulesCommonEvents {\n event LoanParamsSetup(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\n\n event LoanParamsDisabled(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\n}\n" + }, + "contracts/events/ModulesCommonEvents.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title The common events for all modules\n * @notice This contract contains the events which will be used by all modules\n **/\n\ncontract ModulesCommonEvents {\n event ProtocolModuleContractReplaced(\n address indexed prevModuleContractAddress,\n address indexed newModuleContractAddress,\n bytes32 indexed module\n );\n}\n" + }, + "contracts/events/ProtocolSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title The Protocol Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for protocol settings operations.\n * */\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\n\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\n\n event SetLoanPool(\n address indexed sender,\n address indexed loanPool,\n address indexed underlying\n );\n\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\n\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateTradingTokenFeePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetLiquidationIncentivePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetFeesController(\n address indexed sender,\n address indexed oldController,\n address indexed newController\n );\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWethToken,\n address indexed newWethToken\n );\n\n event SetSovrynSwapContractRegistryAddress(\n address indexed sender,\n address indexed oldSovrynSwapContractRegistryAddress,\n address indexed newSovrynSwapContractRegistryAddress\n );\n\n event SetProtocolTokenAddress(\n address indexed sender,\n address indexed oldProtocolToken,\n address indexed newProtocolToken\n );\n\n event WithdrawFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 lendingAmount,\n uint256 tradingAmount,\n uint256 borrowingAmount,\n uint256 wRBTCConverted\n );\n\n event WithdrawLendingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawTradingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawBorrowingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetRebatePercent(\n address indexed sender,\n uint256 oldRebatePercent,\n uint256 newRebatePercent\n );\n\n event SetSpecialRebates(\n address indexed sender,\n address indexed sourceToken,\n address indexed destToken,\n uint256 oldSpecialRebatesPercent,\n uint256 newSpecialRebatesPercent\n );\n\n event SetProtocolAddress(\n address indexed sender,\n address indexed oldProtocol,\n address indexed newProtocol\n );\n\n event SetMinReferralsToPayoutAffiliates(\n address indexed sender,\n uint256 oldMinReferrals,\n uint256 newMinReferrals\n );\n\n event SetSOVTokenAddress(\n address indexed sender,\n address indexed oldTokenAddress,\n address indexed newTokenAddress\n );\n\n event SetLockedSOVAddress(\n address indexed sender,\n address indexed oldAddress,\n address indexed newAddress\n );\n\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\n\n event SetTradingRebateRewardsBasisPoint(\n address indexed sender,\n uint256 oldBasisPoint,\n uint256 newBasisPoint\n );\n\n event SetRolloverFlexFeePercent(\n address indexed sender,\n uint256 oldRolloverFlexFeePercent,\n uint256 newRolloverFlexFeePercent\n );\n\n event SetDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event RemoveDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n}\n" + }, + "contracts/events/SwapsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Swaps Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for swap operations.\n * */\ncontract SwapsEvents is ModulesCommonEvents {\n event LoanSwap(\n bytes32 indexed loanId,\n address indexed sourceToken,\n address indexed destToken,\n address borrower,\n uint256 sourceAmount,\n uint256 destAmount\n );\n\n event ExternalSwap(\n address indexed user,\n address indexed sourceToken,\n address indexed destToken,\n uint256 sourceAmount,\n uint256 destAmount\n );\n}\n" + }, + "contracts/farm/ILiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\n\ninterface ILiquidityMining {\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external;\n\n function onTokensDeposited(address _user, uint256 _amount) external;\n\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/farm/LiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./LiquidityMiningStorage.sol\";\nimport \"./ILiquidityMining.sol\";\n\ncontract LiquidityMining is ILiquidityMining, LiquidityMiningStorage {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n /* Constants */\n\n uint256 public constant PRECISION = 1e12;\n // Bonus multiplier for early liquidity providers.\n // During bonus period each passed block will be calculated like N passed blocks, where N = BONUS_MULTIPLIER\n uint256 public constant BONUS_BLOCK_MULTIPLIER = 10;\n\n uint256 public constant SECONDS_PER_BLOCK = 30;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event PoolTokenAdded(address indexed user, address indexed poolToken, uint256 allocationPoint);\n event PoolTokenUpdated(\n address indexed user,\n address indexed poolToken,\n uint256 newAllocationPoint,\n uint256 oldAllocationPoint\n );\n event Deposit(address indexed user, address indexed poolToken, uint256 amount);\n event RewardClaimed(address indexed user, address indexed poolToken, uint256 amount);\n event Withdraw(address indexed user, address indexed poolToken, uint256 amount);\n event EmergencyWithdraw(\n address indexed user,\n address indexed poolToken,\n uint256 amount,\n uint256 accumulatedReward\n );\n\n /* Functions */\n\n /**\n * @notice Initialize mining.\n *\n * @param _SOV The SOV token.\n * @param _rewardTokensPerBlock The number of reward tokens per block.\n * @param _startDelayBlocks The number of blocks should be passed to start\n * mining.\n * @param _numberOfBonusBlocks The number of blocks when each block will\n * be calculated as N blocks (BONUS_BLOCK_MULTIPLIER).\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n * SOV rewards are not paid directly to liquidity providers. Instead they\n * are deposited into a lockedSOV vault contract.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n */\n function initialize(\n IERC20 _SOV,\n uint256 _rewardTokensPerBlock,\n uint256 _startDelayBlocks,\n uint256 _numberOfBonusBlocks,\n address _wrapper,\n ILockedSOV _lockedSOV,\n uint256 _unlockedImmediatelyPercent\n ) external onlyAuthorized {\n /// @dev Non-idempotent function. Must be called just once.\n require(address(SOV) == address(0), \"Already initialized\");\n require(address(_SOV) != address(0), \"Invalid token address\");\n require(_startDelayBlocks > 0, \"Invalid start block\");\n require(\n _unlockedImmediatelyPercent < 10000,\n \"Unlocked immediately percent has to be less than 10000.\"\n );\n\n SOV = _SOV;\n rewardTokensPerBlock = _rewardTokensPerBlock;\n startBlock = block.number + _startDelayBlocks;\n bonusEndBlock = startBlock + _numberOfBonusBlocks;\n wrapper = _wrapper;\n lockedSOV = _lockedSOV;\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets lockedSOV contract.\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n */\n function setLockedSOV(ILockedSOV _lockedSOV) external onlyAuthorized {\n require(address(_lockedSOV) != address(0), \"Invalid lockedSOV Address.\");\n lockedSOV = _lockedSOV;\n }\n\n /**\n * @notice Sets unlocked immediately percent.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setUnlockedImmediatelyPercent(uint256 _unlockedImmediatelyPercent)\n external\n onlyAuthorized\n {\n require(\n _unlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets unlocked immediately percent overwrite for specific pool token.\n * @param _poolToken the address of pool token\n * @param _poolTokenUnlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setPoolTokenUnlockedImmediatelyPercent(\n address _poolToken,\n uint256 _poolTokenUnlockedImmediatelyPercent\n ) external onlyAuthorized {\n require(\n _poolTokenUnlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n poolTokensUnlockedImmediatelyPercent[_poolToken] = _poolTokenUnlockedImmediatelyPercent;\n }\n\n /**\n * @notice sets wrapper proxy contract\n * @dev can be set to zero address to remove wrapper\n */\n function setWrapper(address _wrapper) external onlyAuthorized {\n wrapper = _wrapper;\n }\n\n /**\n * @notice stops mining by setting end block\n */\n function stopMining() external onlyAuthorized {\n require(endBlock == 0, \"Already stopped\");\n\n endBlock = block.number;\n }\n\n /**\n * @notice Transfers SOV tokens to given address.\n * Owner use this function to withdraw SOV from LM contract\n * into another account.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) external onlyAuthorized {\n require(_receiver != address(0), \"Receiver address invalid\");\n require(_amount != 0, \"Amount invalid\");\n\n /// @dev Do not transfer more SOV than available.\n uint256 SOVBal = SOV.balanceOf(address(this));\n if (_amount > SOVBal) {\n _amount = SOVBal;\n }\n\n /// @dev The actual transfer.\n require(SOV.transfer(_receiver, _amount), \"Transfer failed\");\n\n /// @dev Event log.\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Get the missed SOV balance of LM contract.\n *\n * @return The amount of SOV tokens according to totalUsersBalance\n * in excess of actual SOV balance of the LM contract.\n * */\n function getMissedBalance() external view returns (uint256) {\n uint256 balance = SOV.balanceOf(address(this));\n return balance >= totalUsersBalance ? 0 : totalUsersBalance.sub(balance);\n }\n\n /**\n * @notice adds a new lp to the pool. Can only be called by the owner or an admin\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _withUpdate the flag whether we need to update all pools\n */\n function add(\n address _poolToken,\n uint96 _allocationPoint,\n bool _withUpdate\n ) external onlyAuthorized {\n require(_allocationPoint > 0, \"Invalid allocation point\");\n require(_poolToken != address(0), \"Invalid token address\");\n require(poolIdList[_poolToken] == 0, \"Token already added\");\n\n if (_withUpdate) {\n updateAllPools();\n }\n\n uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;\n totalAllocationPoint = totalAllocationPoint.add(_allocationPoint);\n\n poolInfoList.push(\n PoolInfo({\n poolToken: IERC20(_poolToken),\n allocationPoint: _allocationPoint,\n lastRewardBlock: lastRewardBlock,\n accumulatedRewardPerShare: 0\n })\n );\n //indexing starts from 1 in order to check whether token was already added\n poolIdList[_poolToken] = poolInfoList.length;\n\n emit PoolTokenAdded(msg.sender, _poolToken, _allocationPoint);\n }\n\n /**\n * @notice updates the given pool's reward tokens allocation point\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function update(\n address _poolToken,\n uint96 _allocationPoint,\n bool _updateAllFlag\n ) external onlyAuthorized {\n if (_updateAllFlag) {\n updateAllPools();\n } else {\n updatePool(_poolToken);\n }\n _updateToken(_poolToken, _allocationPoint);\n }\n\n function _updateToken(address _poolToken, uint96 _allocationPoint) internal {\n uint256 poolId = _getPoolId(_poolToken);\n\n uint256 previousAllocationPoint = poolInfoList[poolId].allocationPoint;\n totalAllocationPoint = totalAllocationPoint.sub(previousAllocationPoint).add(\n _allocationPoint\n );\n poolInfoList[poolId].allocationPoint = _allocationPoint;\n\n emit PoolTokenUpdated(msg.sender, _poolToken, _allocationPoint, previousAllocationPoint);\n }\n\n /**\n * @notice updates the given pools' reward tokens allocation points\n * @param _poolTokens array of addresses of pool tokens\n * @param _allocationPoints array of allocation points (weight) for the given pools\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function updateTokens(\n address[] calldata _poolTokens,\n uint96[] calldata _allocationPoints,\n bool _updateAllFlag\n ) external onlyAuthorized {\n require(_poolTokens.length == _allocationPoints.length, \"Arrays mismatch\");\n\n if (_updateAllFlag) {\n updateAllPools();\n }\n uint256 length = _poolTokens.length;\n for (uint256 i = 0; i < length; i++) {\n if (!_updateAllFlag) {\n updatePool(_poolTokens[i]);\n }\n _updateToken(_poolTokens[i], _allocationPoints[i]);\n }\n }\n\n /**\n * @notice returns reward multiplier over the given _from to _to block\n * @param _from the first block for a calculation\n * @param _to the last block for a calculation\n */\n function _getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n internal\n view\n returns (uint256)\n {\n if (_from < startBlock) {\n _from = startBlock;\n }\n if (endBlock > 0 && _to > endBlock) {\n _to = endBlock;\n }\n if (_to <= bonusEndBlock) {\n return _to.sub(_from).mul(BONUS_BLOCK_MULTIPLIER);\n } else if (_from >= bonusEndBlock) {\n return _to.sub(_from);\n } else {\n return\n bonusEndBlock.sub(_from).mul(BONUS_BLOCK_MULTIPLIER).add(_to.sub(bonusEndBlock));\n }\n }\n\n function _getUserAccumulatedReward(uint256 _poolId, address _user)\n internal\n view\n returns (uint256)\n {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_user];\n\n uint256 accumulatedRewardPerShare = pool.accumulatedRewardPerShare;\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (block.number > pool.lastRewardBlock && poolTokenBalance != 0) {\n (, uint256 accumulatedRewardPerShare_) = _getPoolAccumulatedReward(pool);\n accumulatedRewardPerShare = accumulatedRewardPerShare.add(accumulatedRewardPerShare_);\n }\n\n return\n user.accumulatedReward.add(\n user.amount.mul(accumulatedRewardPerShare).div(PRECISION).sub(user.rewardDebt)\n );\n }\n\n /**\n * @notice returns accumulated reward\n * @param _poolToken the address of pool token\n * @param _user the user address\n */\n function getUserAccumulatedReward(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n uint256 poolId = _getPoolId(_poolToken);\n return _getUserAccumulatedReward(poolId, _user);\n }\n\n /**\n * @notice returns estimated reward\n * @param _poolToken the address of pool token\n * @param _amount the amount of tokens to be deposited\n * @param _duration the duration of liquidity providing in seconds\n */\n function getEstimatedReward(\n address _poolToken,\n uint256 _amount,\n uint256 _duration\n ) external view returns (uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n uint256 start = block.number;\n uint256 end = start.add(_duration.div(SECONDS_PER_BLOCK));\n (, uint256 accumulatedRewardPerShare) =\n _getPoolAccumulatedReward(pool, _amount, start, end);\n return _amount.mul(accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Updates reward variables for all pools.\n * @dev Be careful of gas spending!\n */\n function updateAllPools() public {\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n _updatePool(i);\n }\n }\n\n /**\n * @notice Updates reward variables of the given pool to be up-to-date\n * @param _poolToken the address of pool token\n */\n function updatePool(address _poolToken) public {\n uint256 poolId = _getPoolId(_poolToken);\n _updatePool(poolId);\n }\n\n function _updatePool(uint256 _poolId) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n\n //this pool has been updated recently\n if (block.number <= pool.lastRewardBlock) {\n return;\n }\n\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (poolTokenBalance == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n (uint256 accumulatedReward_, uint256 accumulatedRewardPerShare_) =\n _getPoolAccumulatedReward(pool);\n pool.accumulatedRewardPerShare = pool.accumulatedRewardPerShare.add(\n accumulatedRewardPerShare_\n );\n pool.lastRewardBlock = block.number;\n\n totalUsersBalance = totalUsersBalance.add(accumulatedReward_);\n }\n\n function _getPoolAccumulatedReward(PoolInfo storage _pool)\n internal\n view\n returns (uint256, uint256)\n {\n return _getPoolAccumulatedReward(_pool, 0, _pool.lastRewardBlock, block.number);\n }\n\n function _getPoolAccumulatedReward(\n PoolInfo storage _pool,\n uint256 _additionalAmount,\n uint256 _startBlock,\n uint256 _endBlock\n ) internal view returns (uint256, uint256) {\n uint256 passedBlocks = _getPassedBlocksWithBonusMultiplier(_startBlock, _endBlock);\n uint256 accumulatedReward =\n passedBlocks.mul(rewardTokensPerBlock).mul(_pool.allocationPoint).div(\n totalAllocationPoint\n );\n\n uint256 poolTokenBalance = _pool.poolToken.balanceOf(address(this));\n poolTokenBalance = poolTokenBalance.add(_additionalAmount);\n uint256 accumulatedRewardPerShare = accumulatedReward.mul(PRECISION).div(poolTokenBalance);\n return (accumulatedReward, accumulatedRewardPerShare);\n }\n\n /**\n * @notice deposits pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it or to msg.sender\n */\n function deposit(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n _deposit(_poolToken, _amount, _user, false);\n }\n\n /**\n * @notice if the lending pools directly mint/transfer tokens to this address, process it like a user deposit\n * @dev only callable by the pool which issues the tokens\n * @param _user the user address\n * @param _amount the minted amount\n */\n function onTokensDeposited(address _user, uint256 _amount) external {\n //the msg.sender is the pool token. if the msg.sender is not a valid pool token, _deposit will revert\n _deposit(msg.sender, _amount, _user, true);\n }\n\n /**\n * @notice internal function for depositing pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it\n * @param alreadyTransferred true if the pool tokens have already been transferred\n */\n function _deposit(\n address _poolToken,\n uint256 _amount,\n address _user,\n bool alreadyTransferred\n ) internal {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _user != address(0) ? _user : msg.sender;\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n\n _updatePool(poolId);\n //sends reward directly to the user\n _updateReward(pool, user);\n\n if (_amount > 0) {\n //receives pool tokens from msg.sender, it can be user or WrapperProxy contract\n if (!alreadyTransferred)\n pool.poolToken.safeTransferFrom(address(msg.sender), address(this), _amount);\n user.amount = user.amount.add(_amount);\n }\n _updateRewardDebt(pool, user);\n emit Deposit(userAddress, _poolToken, _amount);\n }\n\n /**\n * @notice transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimReward(address _poolToken, address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n _claimReward(poolId, userAddress, true);\n }\n\n function _claimReward(\n uint256 _poolId,\n address _userAddress,\n bool _isStakingTokens\n ) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_userAddress];\n\n _updatePool(_poolId);\n _updateReward(pool, user);\n _transferReward(address(pool.poolToken), user, _userAddress, _isStakingTokens, true);\n _updateRewardDebt(pool, user);\n }\n\n /**\n * @notice transfers reward tokens from all pools\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimRewardFromAllPools(address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n uint256 poolId = i;\n _claimReward(poolId, userAddress, false);\n }\n\n if (\n lockedSOV.getLockedBalance(userAddress) > 0 ||\n lockedSOV.getUnlockedBalance(userAddress) > 0\n ) {\n lockedSOV.withdrawAndStakeTokensFrom(userAddress);\n }\n }\n\n /**\n * @notice withdraws pool tokens and transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the user address will be used to process a withdrawal (can be passed only by wrapper contract)\n */\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n require(user.amount >= _amount, \"Not enough balance\");\n\n _updatePool(poolId);\n _updateReward(pool, user);\n _transferReward(_poolToken, user, userAddress, false, false);\n\n user.amount = user.amount.sub(_amount);\n\n //msg.sender is wrapper -> send to wrapper\n if (msg.sender == wrapper) {\n pool.poolToken.safeTransfer(address(msg.sender), _amount);\n }\n //msg.sender is user or pool token (lending pool) -> send to user\n else {\n pool.poolToken.safeTransfer(userAddress, _amount);\n }\n\n _updateRewardDebt(pool, user);\n emit Withdraw(userAddress, _poolToken, _amount);\n }\n\n function _getUserAddress(address _user) internal view returns (address) {\n address userAddress = msg.sender;\n if (_user != address(0)) {\n //only wrapper can pass _user parameter\n require(\n msg.sender == wrapper || poolIdList[msg.sender] != 0,\n \"only wrapper or pools may withdraw for a user\"\n );\n userAddress = _user;\n }\n return userAddress;\n }\n\n function _updateReward(PoolInfo storage pool, UserInfo storage user) internal {\n //update user accumulated reward\n if (user.amount > 0) {\n //add reward for the previous amount of deposited tokens\n uint256 accumulatedReward =\n user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION).sub(\n user.rewardDebt\n );\n user.accumulatedReward = user.accumulatedReward.add(accumulatedReward);\n }\n }\n\n function _updateRewardDebt(PoolInfo storage pool, UserInfo storage user) internal {\n //reward accumulated before amount update (should be subtracted during next reward calculation)\n user.rewardDebt = user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Send reward in SOV to the lockedSOV vault.\n * @param _user The user info, to get its reward share.\n * @param _userAddress The address of the user, to send SOV in its behalf.\n * @param _isStakingTokens The flag whether we need to stake tokens\n * @param _isCheckingBalance The flag whether we need to throw error or don't process reward if SOV balance isn't enough\n */\n function _transferReward(\n address _poolToken,\n UserInfo storage _user,\n address _userAddress,\n bool _isStakingTokens,\n bool _isCheckingBalance\n ) internal {\n uint256 userAccumulatedReward = _user.accumulatedReward;\n /// @dev get unlock immediate percent of the pool token.\n uint256 calculatedUnlockedImmediatelyPercent = calcUnlockedImmediatelyPercent(_poolToken);\n\n /// @dev Transfer if enough SOV balance on this LM contract.\n uint256 balance = SOV.balanceOf(address(this));\n if (balance >= userAccumulatedReward) {\n totalUsersBalance = totalUsersBalance.sub(userAccumulatedReward);\n _user.accumulatedReward = 0;\n\n /// @dev If calculatedUnlockedImmediatelyPercent is 100%, transfer the reward to the LP (user).\n /// else, deposit it into lockedSOV vault contract, but first\n /// SOV deposit must be approved to move the SOV tokens\n /// from this LM contract into the lockedSOV vault.\n if (calculatedUnlockedImmediatelyPercent == 10000) {\n SOV.transfer(_userAddress, userAccumulatedReward);\n } else {\n require(SOV.approve(address(lockedSOV), userAccumulatedReward), \"Approve failed\");\n lockedSOV.deposit(\n _userAddress,\n userAccumulatedReward,\n calculatedUnlockedImmediatelyPercent\n );\n\n if (_isStakingTokens) {\n lockedSOV.withdrawAndStakeTokensFrom(_userAddress);\n }\n }\n\n /// @dev Event log.\n emit RewardClaimed(_userAddress, _poolToken, userAccumulatedReward);\n } else {\n require(!_isCheckingBalance, \"Claiming reward failed\");\n }\n }\n\n /**\n * @notice withdraws pool tokens without transferring reward tokens\n * @param _poolToken the address of pool token\n * @dev EMERGENCY ONLY\n */\n function emergencyWithdraw(address _poolToken) external {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][msg.sender];\n\n _updatePool(poolId);\n _updateReward(pool, user);\n\n totalUsersBalance = totalUsersBalance.sub(user.accumulatedReward);\n uint256 userAmount = user.amount;\n uint256 userAccumulatedReward = user.accumulatedReward;\n user.amount = 0;\n user.rewardDebt = 0;\n user.accumulatedReward = 0;\n pool.poolToken.safeTransfer(address(msg.sender), userAmount);\n\n emit EmergencyWithdraw(msg.sender, _poolToken, userAmount, userAccumulatedReward);\n }\n\n /**\n * @notice returns pool id\n * @param _poolToken the address of pool token\n */\n function getPoolId(address _poolToken) external view returns (uint256) {\n return _getPoolId(_poolToken);\n }\n\n function _getPoolId(address _poolToken) internal view returns (uint256) {\n uint256 poolId = poolIdList[_poolToken];\n require(poolId > 0, \"Pool token not found\");\n return poolId - 1;\n }\n\n /**\n * @notice returns count of pool tokens\n */\n function getPoolLength() external view returns (uint256) {\n return poolInfoList.length;\n }\n\n /**\n * @notice returns list of pool token's info\n */\n function getPoolInfoList() external view returns (PoolInfo[] memory) {\n return poolInfoList;\n }\n\n /**\n * @notice returns pool info for the given token\n * @param _poolToken the address of pool token\n */\n function getPoolInfo(address _poolToken) external view returns (PoolInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return poolInfoList[poolId];\n }\n\n /**\n * @notice returns list of [amount, accumulatedReward] for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserBalanceList(address _user) external view returns (uint256[2][] memory) {\n uint256 length = poolInfoList.length;\n uint256[2][] memory userBalanceList = new uint256[2][](length);\n for (uint256 i = 0; i < length; i++) {\n userBalanceList[i][0] = userInfoMap[i][_user].amount;\n userBalanceList[i][1] = _getUserAccumulatedReward(i, _user);\n }\n return userBalanceList;\n }\n\n /**\n * @notice returns UserInfo for the given pool and user\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserInfo(address _poolToken, address _user) public view returns (UserInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return userInfoMap[poolId][_user];\n }\n\n /**\n * @notice returns list of UserInfo for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserInfoList(address _user) external view returns (UserInfo[] memory) {\n uint256 length = poolInfoList.length;\n UserInfo[] memory userInfoList = new UserInfo[](length);\n for (uint256 i = 0; i < length; i++) {\n userInfoList[i] = userInfoMap[i][_user];\n }\n return userInfoList;\n }\n\n /**\n * @notice returns accumulated reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardList(address _user) external view returns (uint256[] memory) {\n uint256 length = poolInfoList.length;\n uint256[] memory rewardList = new uint256[](length);\n for (uint256 i = 0; i < length; i++) {\n rewardList[i] = _getUserAccumulatedReward(i, _user);\n }\n return rewardList;\n }\n\n /**\n * @notice returns the pool token balance a user has on the contract\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n UserInfo memory ui = getUserInfo(_poolToken, _user);\n return ui.amount;\n }\n\n /**\n * @notice returns the accumulated liquid reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBePaidLiquid(address _user)\n external\n view\n returns (uint256)\n {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n calculatedUnlockedImmediatelyPercent.mul(_getUserAccumulatedReward(i, _user)).div(\n 10000\n )\n );\n }\n\n return result;\n }\n\n /**\n * @notice returns the accumulated vested reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBeVested(address _user) external view returns (uint256) {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n (10000 - calculatedUnlockedImmediatelyPercent)\n .mul(_getUserAccumulatedReward(i, _user))\n .div(10000)\n );\n }\n\n return result;\n }\n\n /**\n * @dev calculate the unlocked immediate percentage of specific pool token\n * use the poolTokensUnlockedImmediatelyPercent by default, if it is not set, then use the unlockedImmediatelyPercent\n */\n function calcUnlockedImmediatelyPercent(address _poolToken) public view returns (uint256) {\n uint256 poolTokenUnlockedImmediatelyPercent =\n poolTokensUnlockedImmediatelyPercent[_poolToken];\n return\n poolTokenUnlockedImmediatelyPercent > 0\n ? poolTokenUnlockedImmediatelyPercent\n : unlockedImmediatelyPercent;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningConfigToken.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/IERC20_.sol\";\n\n/**\n * @title Dummy token with 0 total supply.\n *\n * @dev We need this token for having a flexibility with LiquidityMining configuration\n */\ncontract LiquidityMiningConfigToken is IERC20_ {\n function totalSupply() external view returns (uint256) {\n return 0;\n }\n\n function balanceOf(address account) external view returns (uint256) {\n return 0;\n }\n\n function transfer(address recipient, uint256 amount) external returns (bool) {\n return false;\n }\n\n function allowance(address owner, address spender) external view returns (uint256) {\n return 0;\n }\n\n function approve(address spender, uint256 amount) external returns (bool) {\n return false;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool) {\n return false;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./LiquidityMiningStorage.sol\";\nimport \"../proxy/UpgradableProxy.sol\";\n\n/**\n * @dev LiquidityMining contract should be upgradable, use UpgradableProxy\n */\ncontract LiquidityMiningProxy is LiquidityMiningStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/farm/LiquidityMiningStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../utils/AdminRole.sol\";\n\ncontract LiquidityMiningStorage is AdminRole {\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many pool tokens the user has provided.\n uint256 rewardDebt; // Reward debt. See explanation below.\n uint256 accumulatedReward; //Reward that's ready to be transferred\n //\n // We do some fancy math here. Basically, any point in time, the amount of reward tokens\n // entitled to a user but is accumulated to be distributed is:\n //\n // accumulated reward = (user.amount * pool.accumulatedRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accumulatedRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the accumulated reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 poolToken; // Address of LP token contract.\n uint96 allocationPoint; // How many allocation points assigned to this pool. Amount of reward tokens to distribute per block.\n uint256 lastRewardBlock; // Last block number that reward tokens distribution occurs.\n uint256 accumulatedRewardPerShare; // Accumulated amount of reward tokens per share, times 1e12. See below.\n }\n\n // Rewards tokens created per block.\n uint256 public rewardTokensPerBlock;\n // The block number when reward token mining starts.\n uint256 public startBlock;\n // Block number when bonus reward token period ends.\n uint256 public bonusEndBlock;\n // Block number when reward token period ends.\n uint256 public endBlock;\n\n //Wrapper contract which will be a proxy between user and LM\n address public wrapper;\n\n // Info of each pool.\n PoolInfo[] public poolInfoList;\n // Mapping pool token address => pool id\n mapping(address => uint256) poolIdList;\n // Total allocation points. Must be the sum of all allocation points in all pools.\n uint256 public totalAllocationPoint;\n\n // Info of each user that stakes LP tokens.\n mapping(uint256 => mapping(address => UserInfo)) public userInfoMap;\n // Total balance this contract should have to handle withdrawal for all users\n uint256 public totalUsersBalance;\n\n /// @dev The SOV token\n IERC20 public SOV;\n\n /// @dev The locked vault contract to deposit LP's rewards into.\n ILockedSOV public lockedSOV;\n\n // The % which determines how much will be unlocked immediately.\n /// @dev 10000 is 100%\n uint256 public unlockedImmediatelyPercent;\n\n /// @dev overwrite the unlockedImmediatelyPercent for specific token.\n mapping(address => uint256) public poolTokensUnlockedImmediatelyPercent;\n}\n" + }, + "contracts/feeds/BProPriceFeed.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IMoCState.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The BPro Price Feed contract.\n *\n * This contract gets/sets the MoC (Money on Chain) address of its state\n * contract and queries its method bproUsdPrice to get bPro/USD valuation.\n * */\ncontract BProPriceFeed is IPriceFeedsExt, Ownable {\n address public mocStateAddress;\n\n event SetMoCStateAddress(address indexed mocStateAddress, address changerAddress);\n\n /**\n * @notice Initializes a new MoC state.\n *\n * @param _mocStateAddress MoC state address\n * */\n constructor(address _mocStateAddress) public {\n setMoCStateAddress(_mocStateAddress);\n }\n\n /**\n * @notice Get BPro USD price.\n *\n * @return the BPro USD Price [using mocPrecision]\n */\n function latestAnswer() external view returns (uint256) {\n IMoCState _mocState = IMoCState(mocStateAddress);\n return _mocState.bproUsdPrice();\n }\n\n /**\n * @notice Supposed to get the MoC update time, but instead\n * get the current timestamp.\n *\n * @return Always returns current block's timestamp.\n * */\n function latestTimestamp() external view returns (uint256) {\n return now; /// MoC state doesn't return update timestamp.\n }\n\n /**\n * @notice Set MoC state address.\n *\n * @param _mocStateAddress The MoC state address.\n * */\n function setMoCStateAddress(address _mocStateAddress) public onlyOwner {\n require(Address.isContract(_mocStateAddress), \"_mocStateAddress not a contract\");\n mocStateAddress = _mocStateAddress;\n emit SetMoCStateAddress(mocStateAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/IMoCState.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IMoCState {\n function getRbtcInBitPro(bytes32 bucket) external view returns (uint256);\n\n function globalMaxBPro() external view returns (uint256);\n\n function maxBPro(bytes32 bucket) external view returns (uint256);\n\n function absoluteMaxBPro() external view returns (uint256);\n\n function maxBProWithDiscount() external view returns (uint256);\n\n function bproTecPrice() external view returns (uint256);\n\n function bucketBProTecPrice(bytes32 bucket) external view returns (uint256);\n\n function bproDiscountPrice() external view returns (uint256);\n\n function bproUsdPrice() external view returns (uint256);\n\n function bproSpotDiscountRate() external view returns (uint256);\n\n function getBucketNBPro(bytes32 bucket) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IPriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface IPriceFeeds {\n function queryRate(address sourceToken, address destToken)\n external\n view\n returns (uint256 rate, uint256 precision);\n\n function queryPrecision(address sourceToken, address destToken)\n external\n view\n returns (uint256 precision);\n\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) external view returns (uint256 destAmount);\n\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) external view returns (uint256 sourceToDestSwapRate);\n\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\n\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (uint256);\n\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\n\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\n\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (bool);\n\n function getFastGasPrice(address payToken) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IRSKOracle {\n function updatePrice(uint256 price, uint256 timestamp) external;\n\n function getPricing() external view returns (uint256, uint256);\n\n function setOracleAddress(address addr) external;\n\n function clearOracleAddress() external;\n}\n" + }, + "contracts/feeds/IV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IV1PoolOracle {\n function read(uint256 price, uint256 timestamp)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function latestAnswer() external view returns (uint256);\n\n function liquidityPool() external view returns (address);\n\n function latestPrice(address _baseToken) external view returns (uint256 answer);\n}\n\ninterface ILiquidityPoolV1Converter {\n function reserveTokens(uint256 index) external view returns (address);\n}\n" + }, + "contracts/feeds/PriceFeedRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IRSKOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @notice The Price Feed RSK Oracle contract.\n *\n * This contract implements RSK Oracle query functionality,\n * getting the price and the last timestamp from an external oracle contract.\n * */\ncontract PriceFeedRSKOracle is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public rskOracleAddress;\n\n /* Events */\n\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new RSK Oracle.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _rskOracleAddress) public {\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256 _price) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (_price, ) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestTimestamp() external view returns (uint256 _timestamp) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (, _timestamp) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/PriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./PriceFeedsConstants.sol\";\n\ninterface IPriceFeedsExt {\n function latestAnswer() external view returns (uint256);\n}\n\n/**\n * @title The Price Feeds contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract queries the price feeds contracts where\n * oracles updates token prices computing relative token prices.\n * And besides it includes some calculations about loans such as\n * drawdown, margin and collateral.\n * */\ncontract PriceFeeds is Constants, Ownable {\n using SafeMath for uint256;\n\n /* Events */\n\n event GlobalPricingPaused(address indexed sender, bool indexed isPaused);\n\n /* Storage */\n\n /// Mapping of PriceFeedsExt instances.\n /// token => pricefeed\n mapping(address => IPriceFeedsExt) public pricesFeeds;\n\n /// Decimals of supported tokens.\n mapping(address => uint256) public decimals;\n\n /// Value on rBTC weis for the protocol token.\n uint256 public protocolTokenEthPrice = 0.0002 ether;\n\n /// Flag to pause pricings.\n bool public globalPricingPaused = false;\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires 3 parameters.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * @param _protocolTokenAddress The address of the protocol token.\n * @param _baseTokenAddress The address of the base token.\n * */\n constructor(\n address _wrbtcTokenAddress,\n address _protocolTokenAddress,\n address _baseTokenAddress\n ) public {\n /// Set decimals for this token.\n decimals[address(0)] = 18;\n decimals[_wrbtcTokenAddress] = 18;\n _setWrbtcToken(_wrbtcTokenAddress);\n _setProtocolTokenAddress(_protocolTokenAddress);\n _setBaseToken(_baseTokenAddress);\n }\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @dev Public wrapper for _queryRate internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function queryRate(address sourceToken, address destToken)\n public\n view\n returns (uint256 rate, uint256 precision)\n {\n return _queryRate(sourceToken, destToken);\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @dev Public wrapper for _getDecimalPrecision internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function queryPrecision(address sourceToken, address destToken) public view returns (uint256) {\n return sourceToken != destToken ? _getDecimalPrecision(sourceToken, destToken) : 10**18;\n }\n\n /**\n * @notice Price conversor: Calculate the price of an amount of source\n * tokens in destiny token units.\n *\n * @dev NOTE: This function returns 0 during a pause, rather than a revert.\n * Ensure calling contracts handle correctly.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of the source tokens.\n *\n * @return destAmount The amount of destiny tokens equivalent in price\n * to the amount of source tokens.\n * */\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) public view returns (uint256 destAmount) {\n if (globalPricingPaused) {\n return 0;\n }\n\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n destAmount = sourceAmount.mul(rate).div(precision);\n }\n\n /**\n * @notice Calculate the swap rate between two tokens.\n *\n * Regarding slippage, there is a hardcoded slippage limit of 5%, enforced\n * by this function for all borrowing, lending and margin trading\n * originated swaps performed in the Sovryn exchange.\n *\n * This means all operations in the Sovryn exchange are subject to losing\n * up to 5% from the internal swap performed.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of source tokens.\n * @param destAmount The amount of destiny tokens.\n * @param maxSlippage The maximum slippage limit.\n *\n * @return sourceToDestSwapRate The swap rate between tokens.\n * */\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) public view returns (uint256 sourceToDestSwapRate) {\n require(!globalPricingPaused, \"pricing is paused\");\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n sourceToDestSwapRate = destAmount.mul(precision).div(sourceAmount);\n\n if (rate > sourceToDestSwapRate) {\n uint256 spreadValue = rate - sourceToDestSwapRate;\n spreadValue = spreadValue.mul(10**20).div(sourceToDestSwapRate);\n require(spreadValue <= maxSlippage, \"price disagreement\");\n }\n }\n\n /**\n * @notice Calculate the rBTC amount equivalent to a given token amount.\n * Native coin on RSK is rBTC. This code comes from Ethereum applications,\n * so Eth refers to 10**18 weis of native coin, i.e.: 1 rBTC.\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n *\n * @return ethAmount The amount of rBTC equivalent.\n * */\n function amountInEth(address tokenAddress, uint256 amount)\n public\n view\n returns (uint256 ethAmount)\n {\n /// Token is wrBTC, amount in rBTC is the same.\n if (tokenAddress == address(wrbtcToken)) {\n ethAmount = amount;\n } else {\n (uint256 toEthRate, uint256 toEthPrecision) =\n queryRate(tokenAddress, address(wrbtcToken));\n ethAmount = amount.mul(toEthRate).div(toEthPrecision);\n }\n }\n\n /**\n * @notice Calculate the maximum drawdown of a loan.\n *\n * A drawdown is commonly defined as the decline from a high peak to a\n * pullback low of a specific investment or equity in an account.\n *\n * Drawdown magnitude refers to the amount of value that a user loses\n * during the drawdown period.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param margin The relation between the position size and the loan.\n * margin = (total position size - loan) / loan\n *\n * @return maxDrawdown The maximum drawdown.\n * */\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 margin\n ) public view returns (uint256 maxDrawdown) {\n uint256 loanToCollateralAmount;\n if (collateralToken == loanToken) {\n loanToCollateralAmount = loanAmount;\n } else {\n (uint256 rate, uint256 precision) = queryRate(loanToken, collateralToken);\n loanToCollateralAmount = loanAmount.mul(rate).div(precision);\n }\n\n uint256 combined =\n loanToCollateralAmount.add(loanToCollateralAmount.mul(margin).div(10**20));\n\n maxDrawdown = collateralAmount > combined ? collateralAmount - combined : 0;\n }\n\n /**\n * @notice Calculate the margin and the collateral on rBTC.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralInEthAmount The amount of collateral on rBTC.\n * */\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralInEthAmount) {\n (currentMargin, ) = getCurrentMargin(\n loanToken,\n collateralToken,\n loanAmount,\n collateralAmount\n );\n\n collateralInEthAmount = amountInEth(collateralToken, collateralAmount);\n }\n\n /**\n * @notice Calculate the margin of a loan.\n *\n * @dev current margin = (total position size - loan) / loan\n * The collateral amount passed as parameter equals the total position size.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralToLoanRate The price ratio between collateral and\n * loan tokens.\n * */\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralToLoanRate) {\n uint256 collateralToLoanAmount;\n if (collateralToken == loanToken) {\n collateralToLoanAmount = collateralAmount;\n collateralToLoanRate = 10**18;\n } else {\n uint256 collateralToLoanPrecision;\n (collateralToLoanRate, collateralToLoanPrecision) = queryRate(\n collateralToken,\n loanToken\n );\n\n collateralToLoanRate = collateralToLoanRate.mul(10**18).div(collateralToLoanPrecision);\n\n collateralToLoanAmount = collateralAmount.mul(collateralToLoanRate).div(10**18);\n }\n\n if (loanAmount != 0 && collateralToLoanAmount >= loanAmount) {\n return (\n collateralToLoanAmount.sub(loanAmount).mul(10**20).div(loanAmount),\n collateralToLoanRate\n );\n } else {\n return (0, collateralToLoanRate);\n }\n }\n\n /**\n * @notice Get assessment about liquidating a loan.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param maintenanceMargin The minimum margin before liquidation.\n *\n * @return True/false to liquidate the loan.\n * */\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) public view returns (bool) {\n (uint256 currentMargin, ) =\n getCurrentMargin(loanToken, collateralToken, loanAmount, collateralAmount);\n\n return currentMargin <= maintenanceMargin;\n }\n\n /*\n * Owner functions\n */\n\n /**\n * @notice Set new value for protocolTokenEthPrice\n *\n * @param newPrice The new value for protocolTokenEthPrice\n * */\n function setProtocolTokenEthPrice(uint256 newPrice) external onlyOwner {\n require(newPrice != 0, \"invalid price\");\n protocolTokenEthPrice = newPrice;\n }\n\n /**\n * @notice Populate pricesFeeds mapping w/ values from feeds[]\n *\n * @param tokens The array of tokens to loop and get addresses.\n * @param feeds The array of contract instances for every token.\n * */\n function setPriceFeed(address[] calldata tokens, IPriceFeedsExt[] calldata feeds)\n external\n onlyOwner\n {\n require(tokens.length == feeds.length, \"count mismatch\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n pricesFeeds[tokens[i]] = feeds[i];\n }\n }\n\n /**\n * @notice Populate decimals mapping w/ values from tokens[].decimals\n *\n * @param tokens The array of tokens to loop and get values from.\n * */\n function setDecimals(IERC20[] calldata tokens) external onlyOwner {\n for (uint256 i = 0; i < tokens.length; i++) {\n decimals[address(tokens[i])] = tokens[i].decimals();\n }\n }\n\n /**\n * @notice Set flag globalPricingPaused\n *\n * @param isPaused The new status of pause (true/false).\n * */\n function setGlobalPricingPaused(bool isPaused) external onlyOwner {\n if (globalPricingPaused != isPaused) {\n globalPricingPaused = isPaused;\n\n emit GlobalPricingPaused(msg.sender, isPaused);\n }\n }\n\n /*\n * Internal functions\n */\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n /// Different tokens, query prices and perform division.\n if (sourceToken != destToken) {\n uint256 sourceRate;\n if (sourceToken != address(baseToken) && sourceToken != protocolTokenAddress) {\n IPriceFeedsExt _sourceFeed = pricesFeeds[sourceToken];\n require(address(_sourceFeed) != address(0), \"unsupported src feed\");\n\n /// Query token price on priceFeedsExt instance.\n sourceRate = _sourceFeed.latestAnswer();\n require(sourceRate != 0 && (sourceRate >> 128) == 0, \"price error\");\n } else {\n sourceRate = sourceToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n uint256 destRate;\n if (destToken != address(baseToken) && destToken != protocolTokenAddress) {\n IPriceFeedsExt _destFeed = pricesFeeds[destToken];\n require(address(_destFeed) != address(0), \"unsupported dst feed\");\n\n /// Query token price on priceFeedsExt instance.\n destRate = _destFeed.latestAnswer();\n require(destRate != 0 && (destRate >> 128) == 0, \"price error\");\n } else {\n destRate = destToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n rate = sourceRate.mul(10**18).div(destRate);\n\n precision = _getDecimalPrecision(sourceToken, destToken);\n\n /// Same tokens, return 1 with decimals.\n } else {\n rate = 10**18;\n precision = 10**18;\n }\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function _getDecimalPrecision(address sourceToken, address destToken)\n internal\n view\n returns (uint256)\n {\n /// Same tokens, return 1 with decimals.\n if (sourceToken == destToken) {\n return 10**18;\n\n /// Different tokens, query ERC20 precisions and return 18 +- diff.\n } else {\n uint256 sourceTokenDecimals = decimals[sourceToken];\n if (sourceTokenDecimals == 0) sourceTokenDecimals = IERC20(sourceToken).decimals();\n\n uint256 destTokenDecimals = decimals[destToken];\n if (destTokenDecimals == 0) destTokenDecimals = IERC20(destToken).decimals();\n\n if (destTokenDecimals >= sourceTokenDecimals)\n return 10**(SafeMath.sub(18, destTokenDecimals - sourceTokenDecimals));\n else return 10**(SafeMath.add(18, sourceTokenDecimals - destTokenDecimals));\n }\n }\n}\n" + }, + "contracts/feeds/PriceFeedsConstants.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The Price Feeds Constants contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract keep the addresses of token instances for wrBTC, base token\n * and protocol token.\n * */\ncontract Constants {\n IWrbtcERC20 public wrbtcToken;\n IWrbtcERC20 public baseToken;\n address internal protocolTokenAddress;\n\n /**\n * @notice Set wrBTC token address.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * */\n function _setWrbtcToken(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"_wrbtcTokenAddress not a contract\");\n wrbtcToken = IWrbtcERC20(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Set protocol token address.\n *\n * @param _protocolTokenAddress The address of the protocol token.\n * */\n function _setProtocolTokenAddress(address _protocolTokenAddress) internal {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n protocolTokenAddress = _protocolTokenAddress;\n }\n\n /**\n * @notice Set base token address.\n *\n * @param _baseTokenAddress The address of the base token.\n * */\n function _setBaseToken(address _baseTokenAddress) internal {\n require(Address.isContract(_baseTokenAddress), \"_baseTokenAddress not a contract\");\n baseToken = IWrbtcERC20(_baseTokenAddress);\n }\n}\n" + }, + "contracts/feeds/PriceFeedV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IV1PoolOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./IPriceFeeds.sol\";\n\n/**\n * @notice The Price Feed V1 Pool Oracle contract.\n *\n * This contract implements V1 Pool Oracle query functionality,\n * getting the price from v1 pool oracle.\n * */\ncontract PriceFeedV1PoolOracle is IPriceFeedsExt, Ownable {\n using SafeMath for uint256;\n /* Storage */\n\n address public v1PoolOracleAddress;\n address public wRBTCAddress;\n address public docAddress;\n address public baseCurrency;\n\n /* Events */\n event SetV1PoolOracleAddress(address indexed v1PoolOracleAddress, address changerAddress);\n event SetWRBTCAddress(address indexed wRBTCAddress, address changerAddress);\n event SetDOCAddress(address indexed docAddress, address changerAddress);\n event SetBaseCurrency(address indexed baseCurrency, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new V1 Pool Oracle.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n * @param _wRBTCAddress The wrbtc token address.\n * @param _docAddress The doc token address.\n * */\n constructor(\n address _v1PoolOracleAddress,\n address _wRBTCAddress,\n address _docAddress,\n address _baseCurrency\n ) public {\n setRBTCAddress(_wRBTCAddress);\n setDOCAddress(_docAddress);\n setV1PoolOracleAddress(_v1PoolOracleAddress);\n setBaseCurrency(_baseCurrency);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256) {\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(v1PoolOracleAddress);\n\n uint256 _price = _v1PoolOracle.latestPrice(baseCurrency);\n\n // Need to convert to USD, since the V1 pool return value is based on BTC\n uint256 priceInUSD = _convertAnswerToUsd(_price);\n require(priceInUSD != 0, \"price error\");\n\n return priceInUSD;\n }\n\n function _convertAnswerToUsd(uint256 _valueInBTC) private view returns (uint256) {\n address _priceFeeds = msg.sender;\n\n uint256 precision = IPriceFeeds(_priceFeeds).queryPrecision(wRBTCAddress, docAddress);\n uint256 valueInUSD =\n IPriceFeeds(_priceFeeds).queryReturn(wRBTCAddress, docAddress, _valueInBTC);\n\n /// Need to multiply by query precision (doc's precision) and divide by 1*10^18 (Because the based price in v1 pool is using 18 decimals)\n return valueInUSD.mul(precision).div(1e18);\n }\n\n /**\n * @notice Set the V1 Pool Oracle address.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n */\n function setV1PoolOracleAddress(address _v1PoolOracleAddress) public onlyOwner {\n require(Address.isContract(_v1PoolOracleAddress), \"_v1PoolOracleAddress not a contract\");\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(_v1PoolOracleAddress);\n address liquidityPool = _v1PoolOracle.liquidityPool();\n require(\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(0) == wRBTCAddress ||\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(1) == wRBTCAddress,\n \"one of the two reserves needs to be wrbtc\"\n );\n v1PoolOracleAddress = _v1PoolOracleAddress;\n emit SetV1PoolOracleAddress(v1PoolOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the rBtc address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the rBtc\n *\n * @param _wRBTCAddress The rBTC address\n */\n function setRBTCAddress(address _wRBTCAddress) public onlyOwner {\n require(_wRBTCAddress != address(0), \"wRBTC address cannot be zero address\");\n wRBTCAddress = _wRBTCAddress;\n emit SetWRBTCAddress(wRBTCAddress, msg.sender);\n }\n\n /**\n * @notice Set the DoC address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the DoC\n *\n * @param _docAddress The DoC address\n */\n function setDOCAddress(address _docAddress) public onlyOwner {\n require(_docAddress != address(0), \"DOC address cannot be zero address\");\n docAddress = _docAddress;\n emit SetDOCAddress(_docAddress, msg.sender);\n }\n\n /**\n * @notice Set the base currency address. That's the reserve address which is not WRBTC\n *\n * @param _baseCurrency The base currency address\n */\n function setBaseCurrency(address _baseCurrency) public onlyOwner {\n require(_baseCurrency != address(0), \"Base currency address cannot be zero address\");\n baseCurrency = _baseCurrency;\n emit SetBaseCurrency(_baseCurrency, msg.sender);\n }\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsLocal.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\n\n/**\n * @title Price Feeds Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the logic of setting and getting rates between two tokens.\n * */\ncontract PriceFeedsLocal is PriceFeeds {\n mapping(address => mapping(address => uint256)) public rates;\n\n /// uint256 public slippageMultiplier = 100 ether;\n\n /**\n * @notice Deploy local price feed contract.\n *\n * @param _wrbtcTokenAddress The address of the wrBTC instance.\n * @param _protocolTokenAddress The address of the protocol token instance.\n * */\n constructor(address _wrbtcTokenAddress, address _protocolTokenAddress)\n public\n PriceFeeds(_wrbtcTokenAddress, _protocolTokenAddress, _wrbtcTokenAddress)\n {}\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n if (sourceToken == destToken) {\n rate = 10**18;\n precision = 10**18;\n } else {\n if (sourceToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = protocolTokenEthPrice;\n } else if (destToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = SafeMath.div(10**36, protocolTokenEthPrice);\n } else {\n if (rates[sourceToken][destToken] != 0) {\n rate = rates[sourceToken][destToken];\n } else {\n uint256 sourceToEther =\n rates[sourceToken][address(wrbtcToken)] != 0\n ? rates[sourceToken][address(wrbtcToken)]\n : 10**18;\n uint256 etherToDest =\n rates[address(wrbtcToken)][destToken] != 0\n ? rates[address(wrbtcToken)][destToken]\n : 10**18;\n\n rate = sourceToEther.mul(etherToDest).div(10**18);\n }\n }\n precision = _getDecimalPrecision(sourceToken, destToken);\n }\n }\n\n /**\n * @notice Owner set price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param rate The price ratio source/dest.\n * */\n function setRates(\n address sourceToken,\n address destToken,\n uint256 rate\n ) public onlyOwner {\n if (sourceToken != destToken) {\n rates[sourceToken][destToken] = rate;\n rates[destToken][sourceToken] = SafeMath.div(10**36, rate);\n }\n }\n\n /*function setSlippageMultiplier(\n uint256 _slippageMultiplier)\n public\n onlyOwner\n {\n require (slippageMultiplier != _slippageMultiplier && _slippageMultiplier <= 100 ether);\n slippageMultiplier = _slippageMultiplier;\n }*/\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsMoC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\nimport \"../IRSKOracle.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\ninterface Medianizer {\n function peek() external view returns (bytes32, bool);\n}\n\n/**\n * @title Price Feed of MoC (Money on Chain) contract.\n *\n * This contract contains the logic to set MoC oracles\n * and query last price update.\n * */\ncontract PriceFeedsMoC is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public mocOracleAddress;\n address public rskOracleAddress;\n\n /* Events */\n\n event SetMoCOracleAddress(address indexed mocOracleAddress, address changerAddress);\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new MoC Oracle.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _mocOracleAddress, address _rskOracleAddress) public {\n setMoCOracleAddress(_mocOracleAddress);\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestAnswer() external view returns (uint256) {\n (bytes32 value, bool hasValue) = Medianizer(mocOracleAddress).peek();\n if (hasValue) {\n return uint256(value);\n } else {\n (uint256 price, ) = IRSKOracle(rskOracleAddress).getPricing();\n return price;\n }\n }\n\n /**\n * @notice Set the MoC Oracle address.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n */\n function setMoCOracleAddress(address _mocOracleAddress) public onlyOwner {\n require(Address.isContract(_mocOracleAddress), \"_mocOracleAddress not a contract\");\n mocOracleAddress = _mocOracleAddress;\n emit SetMoCOracleAddress(mocOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/USDTPriceFeed.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./PriceFeeds.sol\";\n\n/**\n * @notice The Price Feed USDT contract.\n *\n * This contract implements USDT query functionality,\n * getting the price and the last timestamp from a\n * trivial formula, always returning 1 and now.\n * */\ncontract USDTPriceFeed is IPriceFeedsExt {\n uint256 private constant USDT_RATE = 1 ether;\n\n /**\n * @notice Get the USDT price.\n *\n * @return Always returns the trivial rate of 1.\n * */\n function latestAnswer() external view returns (uint256) {\n return USDT_RATE;\n }\n\n /**\n * @notice Get the las time the price was updated.\n * @return Always trivial current block's timestamp.\n */\n function latestTimestamp() external view returns (uint256) {\n return now;\n }\n}\n" + }, + "contracts/governance/ApprovalReceiver.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./ErrorDecoder.sol\";\nimport \"../token/IApproveAndCall.sol\";\n\n/**\n * @title Base contract for receiving approval from SOV token.\n */\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\n modifier onlyThisContract() {\n // Accepts calls only from receiveApproval function.\n require(msg.sender == address(this), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external {\n // Accepts calls only from SOV token.\n require(msg.sender == _getToken(), \"unauthorized\");\n require(msg.sender == _token, \"unauthorized\");\n\n // Only allowed methods.\n bool isAllowed = false;\n bytes4[] memory selectors = _getSelectors();\n bytes4 sig = _getSig(_data);\n for (uint256 i = 0; i < selectors.length; i++) {\n if (sig == selectors[i]) {\n isAllowed = true;\n break;\n }\n }\n require(isAllowed, \"method is not allowed\");\n\n // Check sender and amount.\n address sender;\n uint256 amount;\n (, sender, amount) = abi.decode(\n abi.encodePacked(bytes28(0), _data),\n (bytes32, address, uint256)\n );\n require(sender == _sender, \"sender mismatch\");\n require(amount == _amount, \"amount mismatch\");\n\n _call(_data);\n }\n\n /**\n * @notice Returns token address, only this address can be a sender for receiveApproval.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, 0x. When overriden, the token address making the call.\n */\n function _getToken() internal view returns (address) {\n return address(0);\n }\n\n /**\n * @notice Returns list of function selectors allowed to be invoked.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, empty array. When overriden, allowed selectors.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n return new bytes4[](0);\n }\n\n /**\n * @notice Makes call and reverts w/ enhanced error message.\n * @param _data Error message as bytes.\n */\n function _call(bytes memory _data) internal {\n (bool success, bytes memory returnData) = address(this).call(_data);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"receiveApproval: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"receiveApproval: \", string(returnData)));\n }\n }\n }\n\n /**\n * @notice Extracts the called function selector, a hash of the signature.\n * @dev The first four bytes of the call data for a function call specifies\n * the function to be called. It is the first (left, high-order in big-endian)\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\n * Example:\n * msg.data:\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\n * 000450000000000000000000000000000000000000000000000000000000000000001\n * selector (or method ID): 0xcdcd77c0\n * signature: baz(uint32,bool)\n * @param _data The msg.data from the low level call.\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\n */\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\n assembly {\n sig := mload(add(_data, 32))\n }\n }\n}\n" + }, + "contracts/governance/ErrorDecoder.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base contract to properly handle returned data on failed calls\n * @dev On EVM if the return data length of a call is less than 68,\n * then the transaction fails silently without a revert message!\n *\n * As described in the Solidity documentation\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\n * the revert reason is an ABI-encoded string consisting of:\n * 0x08c379a0 // Function selector (method id) for \"Error(string)\" signature\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\n *\n * Another example, debug data from test:\n * 0x08c379a0\n * 0000000000000000000000000000000000000000000000000000000000000020\n * 0000000000000000000000000000000000000000000000000000000000000034\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n *\n * Parsed into:\n * Data offset: 20\n * Length: 34\n * Error message:\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n */\ncontract ErrorDecoder {\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\n\n /**\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\n * @param str1 First string, usually a hardcoded context written by dev.\n * @param str2 Second string, usually the error message from the reverted call.\n * @return The concatenated error string\n */\n function _addErrorMessage(string memory str1, string memory str2)\n internal\n pure\n returns (string memory)\n {\n bytes memory bytesStr1 = bytes(str1);\n bytes memory bytesStr2 = bytes(str2);\n string memory str12 =\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\n bytes memory bytesStr12 = bytes(str12);\n uint256 j = 0;\n for (uint256 i = 0; i < bytesStr1.length; i++) {\n bytesStr12[j++] = bytesStr1[i];\n }\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\n bytesStr12[j++] = bytesStr2[i];\n }\n return string(bytesStr12);\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../Staking/SafeMath96.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../interfaces/IConverterAMM.sol\";\n\n/**\n * @title The FeeSharingCollector contract.\n * @notice This contract withdraws fees to be paid to SOV Stakers from the protocol.\n * Stakers call withdraw() to get their share of the fees.\n *\n * @notice Staking is not only granting voting rights, but also access to fee\n * sharing according to the own voting power in relation to the total. Whenever\n * somebody decides to collect the fees from the protocol, they get transferred\n * to a proxy contract which invests the funds in the lending pool and keeps\n * the pool tokens.\n *\n * The fee sharing proxy will be set as feesController of the protocol contract.\n * This allows the fee sharing proxy to withdraw the fees. The fee sharing\n * proxy holds the pool tokens and keeps track of which user owns how many\n * tokens. In order to know how many tokens a user owns, the fee sharing proxy\n * needs to know the user’s weighted stake in relation to the total weighted\n * stake (aka total voting power).\n *\n * Because both values are subject to change, they may be different on each fee\n * withdrawal. To be able to calculate a user’s share of tokens when he wants\n * to withdraw, we need checkpoints.\n *\n * This contract is intended to be set as the protocol fee collector.\n * Anybody can invoke the withdrawFees function which uses\n * protocol.withdrawFees to obtain available fees from operations on a\n * certain token. These fees are deposited in the corresponding loanPool.\n * Also, the staking contract sends slashed tokens to this contract.\n * When a user calls the withdraw function, the contract transfers the fee sharing\n * rewards in proportion to the user’s weighted stake since the last withdrawal.\n *\n * The protocol initially collects fees in all tokens.\n * Then the FeeSharingCollector wihtdraws fees from the protocol.\n * When the fees are withdrawn all the tokens except SOV will be converted to wRBTC\n * and then transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n * */\ncontract FeeSharingCollector is\n SafeMath96,\n IFeeSharingCollector,\n Ownable,\n FeeSharingCollectorStorage\n{\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n address constant ZERO_ADDRESS = address(0);\n address public constant RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT =\n address(uint160(uint256(keccak256(\"RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\"))));\n\n /* Events */\n\n /// @notice Deprecated event after the unification between wrbtc & rbtc\n // event FeeWithdrawn(address indexed sender, address indexed token, uint256 amount);\n event FeeWithdrawnInRBTC(address indexed sender, uint256 amount);\n\n /// @notice An event emitted when tokens transferred.\n event TokensTransferred(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when checkpoint added.\n event CheckpointAdded(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeWithdrawn(\n address indexed sender,\n address indexed receiver,\n address indexed token,\n uint256 amount\n );\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeProcessedNoWithdraw(\n address indexed sender,\n address indexed token,\n uint256 prevProcessedCheckpoints,\n uint256 newProcessedCheckpoints\n );\n\n /**\n * @notice An event emitted when fee from AMM get withdrawn.\n *\n * @param sender sender who initiate the withdrawn amm fees.\n * @param converter the converter address.\n * @param amount total amount of fee (Already converted to WRBTC).\n */\n event FeeAMMWithdrawn(address indexed sender, address indexed converter, uint256 amount);\n\n /// @notice An event emitted when converter address has been registered to be whitelisted.\n event WhitelistedConverter(address indexed sender, address converter);\n\n /// @notice An event emitted when converter address has been removed from whitelist.\n event UnwhitelistedConverter(address indexed sender, address converter);\n\n event RBTCWithdrawn(address indexed sender, address indexed receiver, uint256 amount);\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWrbtcToken,\n address indexed newWrbtcToken\n );\n\n event SetLoanTokenWrbtc(\n address indexed sender,\n address indexed oldLoanTokenWrbtc,\n address indexed newLoanTokenWrbtc\n );\n\n /* Modifier */\n modifier oneTimeExecution(bytes4 _funcSig) {\n require(\n !isFunctionExecuted[_funcSig],\n \"FeeSharingCollector: function can only be called once\"\n );\n _;\n isFunctionExecuted[_funcSig] = true;\n }\n\n /* Functions */\n\n /// @dev fallback function to support rbtc transfer when unwrap the wrbtc.\n function() external payable {}\n\n /**\n * @dev initialize function for fee sharing collector proxy\n * @param wrbtcToken wrbtc token address\n * @param loanWrbtcToken address of loan token wrbtc (IWrbtc)\n */\n function initialize(address wrbtcToken, address loanWrbtcToken)\n external\n onlyOwner\n oneTimeExecution(this.initialize.selector)\n {\n require(\n wrbtcTokenAddress == address(0) && loanTokenWrbtcAddress == address(0),\n \"wrbtcToken or loanWrbtcToken has been initialized\"\n );\n setWrbtcToken(wrbtcToken);\n setLoanTokenWrbtc(loanWrbtcToken);\n }\n\n /**\n * @notice Set the wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newWrbtcTokenAddress The new address of the wrbtc token.\n * */\n function setWrbtcToken(address newWrbtcTokenAddress) public onlyOwner {\n require(Address.isContract(newWrbtcTokenAddress), \"newWrbtcTokenAddress not a contract\");\n emit SetWrbtcToken(msg.sender, wrbtcTokenAddress, newWrbtcTokenAddress);\n wrbtcTokenAddress = newWrbtcTokenAddress;\n }\n\n /**\n * @notice Set the loan wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newLoanTokenWrbtcAddress The new address of the loan wrbtc token.\n * */\n function setLoanTokenWrbtc(address newLoanTokenWrbtcAddress) public onlyOwner {\n require(\n Address.isContract(newLoanTokenWrbtcAddress),\n \"newLoanTokenWrbtcAddress not a contract\"\n );\n emit SetLoanTokenWrbtc(msg.sender, loanTokenWrbtcAddress, newLoanTokenWrbtcAddress);\n loanTokenWrbtcAddress = newLoanTokenWrbtcAddress;\n }\n\n /**\n * @notice Withdraw fees for the given token:\n * lendingFee + tradingFee + borrowingFee\n * the fees (except SOV) will be converted in wRBTC form, and then will be transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n *\n * @param _tokens array address of the token\n * */\n function withdrawFees(address[] calldata _tokens) external {\n for (uint256 i = 0; i < _tokens.length; i++) {\n require(\n Address.isContract(_tokens[i]),\n \"FeeSharingCollector::withdrawFees: token is not a contract\"\n );\n }\n\n uint256 wrbtcAmountWithdrawn = protocol.withdrawFees(_tokens, address(this));\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap the wrbtc to rbtc, and hold the rbtc.\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFees: wrbtc token amount exceeds 96 bits\"\n );\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, amount96);\n }\n\n // note deprecated event since we unify the wrbtc & rbtc\n // emit FeeWithdrawn(msg.sender, RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, poolTokenAmount);\n\n // note new emitted event\n emit FeeWithdrawnInRBTC(msg.sender, wrbtcAmountWithdrawn);\n }\n\n /**\n * @notice Withdraw amm fees for the given converter addresses:\n * protocolFee from the conversion\n * the fees will be converted in wRBTC form, and then will be transferred to wRBTC loan pool\n *\n * @param _converters array addresses of the converters\n * */\n function withdrawFeesAMM(address[] memory _converters) public {\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n // Validate\n _validateWhitelistedConverter(_converters);\n\n uint96 totalPoolTokenAmount;\n for (uint256 i = 0; i < _converters.length; i++) {\n uint256 wrbtcAmountWithdrawn =\n IConverterAMM(_converters[i]).withdrawFees(address(this));\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap wrbtc to rbtc, and hold the rbtc\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFeesAMM: wrbtc token amount exceeds 96 bits\"\n );\n\n totalPoolTokenAmount = add96(\n totalPoolTokenAmount,\n amount96,\n \"FeeSharingCollector::withdrawFeesAMM: total wrbtc token amount exceeds 96 bits\"\n );\n\n emit FeeAMMWithdrawn(msg.sender, _converters[i], wrbtcAmountWithdrawn);\n }\n }\n\n if (totalPoolTokenAmount > 0) {\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, totalPoolTokenAmount);\n }\n }\n\n /**\n * @notice Transfer tokens to this contract.\n * @dev We just update amount of tokens here and write checkpoint in a separate methods\n * in order to prevent adding checkpoints too often.\n * @param _token Address of the token.\n * @param _amount Amount to be transferred.\n * */\n function transferTokens(address _token, uint96 _amount) public {\n require(_token != ZERO_ADDRESS, \"FeeSharingCollector::transferTokens: invalid address\");\n require(_amount > 0, \"FeeSharingCollector::transferTokens: invalid amount\");\n\n /// @notice Transfer tokens from msg.sender\n bool success = IERC20(_token).transferFrom(address(msg.sender), address(this), _amount);\n require(success, \"Staking::transferTokens: token transfer failed\");\n\n // if _token is wrbtc, need to unwrap it to rbtc\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n if (_token == address(wrbtcToken)) {\n wrbtcToken.withdraw(_amount);\n _token = RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT;\n }\n\n _addCheckpoint(_token, _amount);\n\n emit TokensTransferred(msg.sender, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC / native tokens to this contract.\n * @dev We just write checkpoint here (based on the rbtc value that is sent) in a separate methods\n * in order to prevent adding checkpoints too often.\n * */\n function transferRBTC() external payable {\n uint96 _amount = uint96(msg.value);\n require(_amount > 0, \"FeeSharingCollector::transferRBTC: invalid value\");\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, _amount);\n\n emit TokensTransferred(msg.sender, ZERO_ADDRESS, _amount);\n }\n\n /**\n * @notice Add checkpoint with accumulated amount by function invocation.\n * @param _token Address of the token.\n * */\n function _addCheckpoint(address _token, uint96 _amount) internal {\n if (block.timestamp - lastFeeWithdrawalTime[_token] >= FEE_WITHDRAWAL_INTERVAL) {\n lastFeeWithdrawalTime[_token] = block.timestamp;\n uint96 amount =\n add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: amount exceeds 96 bits\"\n );\n\n /// @notice Reset unprocessed amount of tokens to zero.\n unprocessedAmount[_token] = 0;\n\n /// @notice Write a regular checkpoint.\n _writeTokenCheckpoint(_token, amount);\n } else {\n unprocessedAmount[_token] = add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: unprocessedAmount exceeds 96 bits\"\n );\n }\n }\n\n function _withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n /// @dev Prevents block gas limit hit when processing checkpoints\n require(\n _maxCheckpoints > 0,\n \"FeeSharingCollector::withdraw: _maxCheckpoints should be positive\"\n );\n\n address user = msg.sender;\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n uint256 processedUserCheckpoints = processedCheckpoints[user][_token];\n (uint256 amount, uint256 end) =\n _getAccumulatedFees(user, _token, processedUserCheckpoints, _maxCheckpoints);\n if (amount == 0) {\n if (end > processedUserCheckpoints) {\n emit UserFeeProcessedNoWithdraw(msg.sender, _token, processedUserCheckpoints, end);\n processedCheckpoints[user][_token] = end;\n return (0, end);\n } else {\n // getting here most likely means smth wrong with the state\n revert(\"FeeSharingCollector::withdrawFees: no tokens for withdrawal\");\n }\n }\n\n processedCheckpoints[user][_token] = end;\n if (loanTokenWrbtcAddress == _token) {\n // We will change, so that feeSharingCollector will directly burn then loanToken (IWRBTC) to rbtc and send to the user --- by call burnToBTC function\n ILoanTokenWRBTC(_token).burnToBTC(_receiver, amount, false);\n } else {\n // Previously it directly send the loanToken to the user\n require(\n IERC20(_token).transfer(_receiver, amount),\n \"FeeSharingCollector::withdraw: withdrawal failed\"\n );\n }\n\n emit UserFeeWithdrawn(msg.sender, _receiver, _token, amount);\n\n return (amount, end);\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power. Therefore, staking more\n * SOV and/or staking for longer will increase your share of the fees\n * generated, meaning you will earn more from staking.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed. Must be positive value.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public nonReentrant {\n _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n /// @notice Validates if the checkpoint is payable for the user\n function validFromCheckpointsParam(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n address _user\n ) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n // _fromCheckpoint is checkpoint number, not array index, so should be > 1\n require(tokenData.fromCheckpoint > 1, \"_fromCheckpoint param must be > 1\");\n uint256 fromCheckpointIndex = tokenData.fromCheckpoint - 1;\n require(\n tokenData.fromCheckpoint > processedCheckpoints[_user][tokenData.tokenAddress],\n \"_fromCheckpoint param must be > userProcessedCheckpoints\"\n );\n require(\n tokenData.fromCheckpoint <= totalTokenCheckpoints[tokenData.tokenAddress],\n \"_fromCheckpoint should be <= totalTokenCheckpoints\"\n );\n\n Checkpoint memory prevCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex - 1];\n\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n prevCheckpoint.blockNumber - 1,\n prevCheckpoint.timestamp\n );\n require(\n weightedStake == 0,\n \"User weighted stake should be zero at previous checkpoint\"\n );\n\n Checkpoint memory fromCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex];\n weightedStake = staking.getPriorWeightedStake(\n _user,\n fromCheckpoint.blockNumber - 1,\n fromCheckpoint.timestamp\n );\n\n require(weightedStake > 0, \"User weighted stake should be > 0 at _fromCheckpoint\");\n }\n }\n\n function validRBTCBasedTokens(address[] memory _tokens) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n address _token = _tokens[i];\n if (\n _token != RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT &&\n _token != wrbtcTokenAddress &&\n _token != loanTokenWrbtcAddress\n ) {\n revert(\"only rbtc-based tokens are allowed\");\n }\n }\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender/receiver.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @dev WARNING! This function skips all the checkpoints before '_fromCheckpoint' irreversibly, use with care\n *\n * @param _tokens Array of TokenWithSkippedCheckpointsWithdraw struct, which contains the token address, and fromCheckpoiint\n * fromCheckpoints Skips all the checkpoints before '_fromCheckpoint'\n * should be calculated offchain with getNextPositiveUserCheckpoint function\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n *\n * @return total processed checkpoints\n * */\n function _withdrawStartingFromCheckpoints(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validFromCheckpointsParam(_tokens, msg.sender);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n if (_maxCheckpoints == 0) break;\n uint256 endToken;\n uint256 totalAmount;\n\n uint256 previousProcessedUserCheckpoints =\n processedCheckpoints[msg.sender][tokenData.tokenAddress];\n uint256 startingCheckpoint =\n tokenData.fromCheckpoint > previousProcessedUserCheckpoints\n ? tokenData.fromCheckpoint\n : previousProcessedUserCheckpoints;\n\n if (\n tokenData.tokenAddress == wrbtcTokenAddress ||\n tokenData.tokenAddress == loanTokenWrbtcAddress ||\n tokenData.tokenAddress == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\n ) {\n (totalAmount, endToken) = _withdrawRbtcTokenStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n } else {\n (, endToken) = _withdrawStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n }\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint).add(1);\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n if (rbtcAmountToSend > 0) {\n // send all rbtc withdrawal\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Function to wrap:\n * 1. regular withdrawal for both rbtc & non-rbtc token\n * 2. skipped checkpoints withdrawal for both rbtc & non-rbtc token\n *\n * @param _nonRbtcTokensRegularWithdraw array of non-rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _rbtcTokensRegularWithdraw array of rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _tokensWithSkippedCheckpoints array of rbtc & non-rbtc TokenWithSkippedCheckpointsWithdraw struct, which has skipped checkpoints that will be withdrawn\n *\n */\n function claimAllCollectedFees(\n address[] calldata _nonRbtcTokensRegularWithdraw,\n address[] calldata _rbtcTokensRegularWithdraw,\n TokenWithSkippedCheckpointsWithdraw[] calldata _tokensWithSkippedCheckpoints,\n uint32 _maxCheckpoints,\n address _receiver\n ) external nonReentrant {\n uint256 totalProcessedCheckpoints;\n\n /** Process normal multiple withdrawal for RBTC based tokens */\n if (_rbtcTokensRegularWithdraw.length > 0) {\n totalProcessedCheckpoints = _withdrawRbtcTokens(\n _rbtcTokensRegularWithdraw,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process normal non-rbtc token withdrawal */\n for (uint256 i = 0; i < _nonRbtcTokensRegularWithdraw.length; i++) {\n if (_maxCheckpoints == 0) break;\n uint256 endTokenCheckpoint;\n\n address _nonRbtcTokenAddress = _nonRbtcTokensRegularWithdraw[i];\n\n /** starting checkpoint is the previous processedCheckpoints for token */\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_nonRbtcTokenAddress];\n\n (, endTokenCheckpoint) = _withdraw(_nonRbtcTokenAddress, _maxCheckpoints, _receiver);\n\n uint256 _previousUsedCheckpoint = endTokenCheckpoint.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n _previousUsedCheckpoint.add(1);\n }\n\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process token with skipped checkpoints withdrawal */\n if (_tokensWithSkippedCheckpoints.length > 0) {\n totalProcessedCheckpoints = _withdrawStartingFromCheckpoints(\n _tokensWithSkippedCheckpoints,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n }\n\n function _withdrawStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10 meaning we should set 9 user's processed checkpoints\n // after _withdraw() the user's processedCheckpoints should be 10\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n (totalAmount, endTokenCheckpoint) = _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function _withdrawRbtcToken(address _token, uint32 _maxCheckpoints)\n internal\n returns (uint256 totalAmount, uint256 endTokenCheckpoint)\n {\n address user = msg.sender;\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n (totalAmount, endTokenCheckpoint) = _getRBTCBalance(_token, user, _maxCheckpoints);\n\n if (totalAmount > 0) {\n processedCheckpoints[user][_token] = endTokenCheckpoint;\n if (_token == address(wrbtcToken)) {\n // unwrap the wrbtc\n wrbtcToken.withdraw(totalAmount);\n } else if (_token == loanTokenWrbtcAddress) {\n // pull out the iWRBTC to rbtc to this feeSharingCollector contract\n /** @dev will use the burned result from IWRBTC to RBTC as return total amount */\n totalAmount = ILoanTokenWRBTC(loanTokenWrbtcAddress).burnToBTC(\n address(this),\n totalAmount,\n false\n );\n }\n }\n }\n\n /**\n * @dev withdraw all of the RBTC balance based on particular checkpoints\n *\n * This function will withdraw RBTC balance which is passed as _token param, so it could be either of these:\n * - rbtc balance or\n * - wrbtc balance which will be unwrapped to rbtc or\n * - iwrbtc balance which will be unwrapped to rbtc or\n *\n *\n * @param _tokens array of either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _maxCheckpoints Maximum number of checkpoints to be processed to workaround block gas limit\n * @param _receiver An optional tokens receiver (msg.sender used if 0)\n */\n function _withdrawRbtcTokens(\n address[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validRBTCBasedTokens(_tokens);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n if (_maxCheckpoints == 0) break;\n address _token = _tokens[i];\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_token];\n\n (uint256 totalAmount, uint256 endToken) =\n _withdrawRbtcToken(_tokens[i], _maxCheckpoints);\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n // we only need to add used checkpoint by 1 only if starting checkpoint > 0\n _previousUsedCheckpoint.add(1);\n }\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n // send all rbtc\n if (rbtcAmountToSend > 0) {\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Withdraw either specific RBTC related token balance or all RBTC related tokens balances.\n * RBTC related here means, it could be either rbtc, wrbtc, or iwrbtc, depends on the _token param.\n */\n function _withdrawRbtcTokenStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) private returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10\n // after _withdraw() user's processedCheckpoints should be 10 =>\n // set processed checkpoints = 9, next maping index = 9 (10th checkpoint)\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n return _withdrawRbtcToken(_token, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n external\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n return _getNextPositiveUserCheckpoint(_user, _token, _startFrom, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function _getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n internal\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n if (staking.isVestingContract(_user)) {\n return (0, false, false);\n }\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n\n if (processedUserCheckpoints >= totalCheckpoints || totalCheckpoints == 0) {\n return (totalCheckpoints, false, false);\n }\n\n uint256 startFrom =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n\n uint256 end = startFrom.add(_maxCheckpoints);\n if (end >= totalCheckpoints) {\n end = totalCheckpoints;\n }\n\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startFrom; i < end; i++) {\n Checkpoint storage tokenCheckpoint = tokenCheckpoints[_token][i];\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n tokenCheckpoint.blockNumber - 1,\n tokenCheckpoint.timestamp\n );\n if (weightedStake > 0) {\n // i is the index and we need to return checkpoint num which is i + 1\n return (i + 1, i > processedUserCheckpoints, true);\n }\n }\n return (end, end > processedUserCheckpoints, false);\n }\n\n /**\n * @notice Get the accumulated loan pool fee of the message sender.\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @return The accumulated fee for the message sender.\n * */\n function getAccumulatedFees(address _user, address _token) public view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: 0\n });\n return amount;\n }\n\n /**\n * @notice Get the accumulated fee rewards for the message sender for a checkpoints range\n *\n * @dev This function is required to keep consistent with caching of weighted voting power when claiming fees\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The accumulated fees rewards for the _user in the given checkpoints interval: [_startFrom, _startFrom + maxCheckpoints].\n * */\n function getAccumulatedFeesForCheckpointsRange(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees(_user, _token, _startFrom, _maxCheckpoints);\n return amount;\n }\n\n /**\n * @dev Get all user fees reward per maxCheckpoint starting from latest processed checkpoint\n *\n * @dev e.g: Total user checkpoint for the particualar token = 300,\n * when we call this function with 50 maxCheckpoint, it will return 6 fee values in array form.\n * if there is no more fees, it will return empty array.\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The next checkpoint num which is the starting point to fetch all of the fees, array of calculated fees.\n * */\n function getAllUserFeesPerMaxCheckpoints(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256[] memory fees) {\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 totalTokensCheckpointsIndex = totalCheckpoints > 0 ? totalCheckpoints - 1 : 0;\n\n if (totalTokensCheckpointsIndex < _startFrom) return fees;\n\n uint256 arrSize = totalTokensCheckpointsIndex.sub(_startFrom).div(_maxCheckpoints) + 1;\n\n fees = new uint256[](arrSize);\n\n for (uint256 i = 0; i < fees.length; i++) {\n (uint256 fee, ) =\n _getAccumulatedFees(\n _user,\n _token,\n _startFrom + i * _maxCheckpoints,\n _maxCheckpoints\n );\n fees[i] = fee;\n }\n\n return fees;\n }\n\n /**\n * @notice Gets accumulated fees for a user starting from a given checkpoint\n *\n * @param _user Address of the user's account.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Max checkpoints to process at once to fit into block gas limit\n * @param _startFrom Checkpoint num to start calculations from\n *\n * @return feesAmount - accumulated fees amount\n * @return endCheckpoint - last checkpoint of fees calculation\n * */\n function _getAccumulatedFees(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 feesAmount, uint256 endCheckpoint) {\n if (staking.isVestingContract(_user)) {\n return (0, 0);\n }\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n uint256 startOfRange =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n endCheckpoint = _maxCheckpoints > 0\n ? _getEndOfRange(startOfRange, _token, _maxCheckpoints)\n : totalTokenCheckpoints[_token];\n\n if (startOfRange >= totalTokenCheckpoints[_token]) {\n return (0, endCheckpoint);\n }\n\n uint256 cachedLockDate = 0;\n uint96 cachedWeightedStake = 0;\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startOfRange; i < endCheckpoint; i++) {\n Checkpoint memory checkpoint = tokenCheckpoints[_token][i];\n uint256 lockDate = staking.timestampToLockDate(checkpoint.timestamp);\n uint96 weightedStake;\n if (lockDate == cachedLockDate) {\n weightedStake = cachedWeightedStake;\n } else {\n /// @dev We need to use \"checkpoint.blockNumber - 1\" here to calculate weighted stake\n /// For the same block like we did for total voting power in _writeTokenCheckpoint\n weightedStake = staking.getPriorWeightedStake(\n _user,\n checkpoint.blockNumber - 1,\n checkpoint.timestamp\n );\n cachedWeightedStake = weightedStake;\n cachedLockDate = lockDate;\n }\n uint256 share =\n uint256(checkpoint.numTokens).mul(weightedStake).div(\n uint256(checkpoint.totalWeightedStake)\n );\n feesAmount = feesAmount.add(share);\n }\n return (feesAmount, endCheckpoint);\n }\n\n /**\n * @notice Withdrawal should only be possible for blocks which were already\n * mined. If the fees are withdrawn in the same block as the user withdrawal\n * they are not considered by the withdrawing logic (to avoid inconsistencies).\n *\n * @param _start Start of the range.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of a pool token.\n * @param _maxCheckpoints Checkpoint index incremental.\n * */\n function _getEndOfRange(\n uint256 _start,\n address _token,\n uint32 _maxCheckpoints\n ) internal view returns (uint256) {\n uint256 nextCheckpointIndex = totalTokenCheckpoints[_token];\n if (nextCheckpointIndex == 0) {\n return 0;\n }\n uint256 end;\n\n if (_maxCheckpoints == 0) {\n /// @dev All checkpoints will be processed (only for getter outside of a transaction).\n end = nextCheckpointIndex;\n } else {\n end = safe32(\n _start + _maxCheckpoints,\n \"FeeSharingCollector::withdraw: checkpoint index exceeds 32 bits\"\n );\n if (end > nextCheckpointIndex) {\n end = nextCheckpointIndex;\n }\n }\n\n /// @dev Withdrawal should only be possible for blocks which were already mined.\n uint32 lastBlockNumber = tokenCheckpoints[_token][end - 1].blockNumber;\n if (block.number == lastBlockNumber) {\n end--;\n }\n return end;\n }\n\n /**\n * @notice Write a regular checkpoint w/ the foolowing data:\n * block number, block timestamp, total weighted stake and num of tokens.\n * @param _token The pool token address.\n * @param _numTokens The amount of pool tokens.\n * */\n function _writeTokenCheckpoint(address _token, uint96 _numTokens) internal {\n uint32 blockNumber =\n safe32(\n block.number,\n \"FeeSharingCollector::_writeCheckpoint: block number exceeds 32 bits\"\n );\n uint32 blockTimestamp =\n safe32(\n block.timestamp,\n \"FeeSharingCollector::_writeCheckpoint: block timestamp exceeds 32 bits\"\n );\n uint256 nextCheckpointsIndex = totalTokenCheckpoints[_token];\n\n uint96 totalWeightedStake = _getVoluntaryWeightedStake(blockNumber - 1, block.timestamp);\n require(totalWeightedStake > 0, \"Invalid totalWeightedStake\");\n if (\n nextCheckpointsIndex > 0 &&\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].blockNumber == blockNumber\n ) {\n tokenCheckpoints[_token][nextCheckpointsIndex - 1]\n .totalWeightedStake = totalWeightedStake;\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].numTokens = _numTokens;\n } else {\n tokenCheckpoints[_token][nextCheckpointsIndex] = Checkpoint(\n blockNumber,\n blockTimestamp,\n totalWeightedStake,\n _numTokens\n );\n totalTokenCheckpoints[_token] = nextCheckpointsIndex + 1;\n }\n emit CheckpointAdded(msg.sender, _token, _numTokens);\n }\n\n /**\n * Queries the total weighted stake and the weighted stake of vesting contracts and returns the difference\n * @param blockNumber the blocknumber\n * @param timestamp the timestamp\n */\n function _getVoluntaryWeightedStake(uint32 blockNumber, uint256 timestamp)\n internal\n view\n returns (uint96 totalWeightedStake)\n {\n uint96 vestingWeightedStake = staking.getPriorVestingWeightedStake(blockNumber, timestamp);\n totalWeightedStake = staking.getPriorTotalVotingPower(blockNumber, timestamp);\n totalWeightedStake = sub96(\n totalWeightedStake,\n vestingWeightedStake,\n \"FeeSharingCollector::_getTotalVoluntaryWeightedStake: vested stake exceeds total stake\"\n );\n }\n\n /**\n * @dev Whitelisting converter address.\n *\n * @param converterAddress converter address to be whitelisted.\n */\n function addWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n require(Address.isContract(converterAddress), \"Non contract address given\");\n whitelistedConverterList.add(converterAddress);\n emit WhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @dev Removing converter address from whitelist.\n *\n * @param converterAddress converter address to be removed from whitelist.\n */\n function removeWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n whitelistedConverterList.remove(converterAddress);\n emit UnwhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @notice Getter to query all of the whitelisted converter.\n * @return All of the whitelisted converter list.\n */\n function getWhitelistedConverterList() external view returns (address[] memory converterList) {\n converterList = whitelistedConverterList.enumerate();\n }\n\n /**\n * @dev validate array of given address whether is whitelisted or not.\n * @dev if one of them is not whitelisted, then revert.\n *\n * @param converterAddresses array of converter addresses.\n */\n function _validateWhitelistedConverter(address[] memory converterAddresses) private view {\n for (uint256 i = 0; i < converterAddresses.length; i++) {\n require(whitelistedConverterList.contains(converterAddresses[i]), \"Invalid Converter\");\n }\n }\n\n function withdrawWRBTC(address receiver, uint256 wrbtcAmount) external onlyOwner {\n IERC20 wrbtcToken = IERC20(wrbtcTokenAddress);\n\n uint256 balance = wrbtcToken.balanceOf(address(this));\n require(wrbtcAmount <= balance, \"Insufficient balance\");\n\n wrbtcToken.safeTransfer(receiver, wrbtcAmount);\n }\n\n /**\n * @dev This function is dedicated to recover the wrong fee allocation for the 4 year vesting contracts.\n * This function can only be called once\n * The affected tokens to be withdrawn\n * 1. RBTC\n * 2. ZUSD\n * 3. SOV\n * The amount for all of the tokens above is hardcoded\n * The withdrawn tokens will be sent to the owner.\n */\n function recoverIncorrectAllocatedFees()\n external\n oneTimeExecution(this.recoverIncorrectAllocatedFees.selector)\n onlyOwner\n {\n uint256 rbtcAmount = 878778886164898400;\n uint256 zusdAmount = 16658600400155126000000;\n uint256 sovAmount = 6275898259771202000000;\n\n address zusdToken = 0xdB107FA69E33f05180a4C2cE9c2E7CB481645C2d;\n address sovToken = 0xEFc78fc7d48b64958315949279Ba181c2114ABBd;\n\n // Withdraw rbtc\n (bool success, ) = owner().call.value(rbtcAmount)(\"\");\n require(\n success,\n \"FeeSharingCollector::recoverIncorrectAllocatedFees: Withdrawal rbtc failed\"\n );\n\n // Withdraw ZUSD\n IERC20(zusdToken).safeTransfer(owner(), zusdAmount);\n\n // Withdraw SOV\n IERC20(sovToken).safeTransfer(owner(), sovAmount);\n }\n\n /**\n * @dev view function that calculate the total RBTC that includes:\n * - RBTC\n * - WRBTC\n * - iWRBTC * iWRBTC.tokenPrice()\n * @param _user address of the user.\n * @return rbtc balance of the given user's address.\n */\n function getAccumulatedRBTCFeeBalances(address _user) external view returns (uint256) {\n (uint256 _rbtcAmount, uint256 _wrbtcAmount, uint256 _iWrbtcAmount, , , ) =\n _getRBTCBalances(_user, 0);\n uint256 iWRBTCAmountInRBTC =\n _iWrbtcAmount.mul(ILoanTokenWRBTC(loanTokenWrbtcAddress).tokenPrice()).div(1e18);\n return _rbtcAmount.add(_wrbtcAmount).add(iWRBTCAmountInRBTC);\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _rbtcAmount rbtc amount\n * @return _wrbtcAmount wrbtc amount\n * @return _iWrbtcAmount iWrbtc (wrbtc lending pool token) amount * token price\n * @return _endRBTC end time of accumulated fee calculation for rbtc\n * @return _endWRBTC end time of accumulated fee calculation for wrbtc\n * @return _endIWRBTC end time of accumulated fee calculation for iwrbtc\n */\n function _getRBTCBalances(address _user, uint32 _maxCheckpoints)\n private\n view\n returns (\n uint256 _rbtcAmount,\n uint256 _wrbtcAmount,\n uint256 _iWrbtcAmount,\n uint256 _endRBTC,\n uint256 _endWRBTC,\n uint256 _endIWRBTC\n )\n {\n (_rbtcAmount, _endRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n\n (_wrbtcAmount, _endWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: wrbtcTokenAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n (_iWrbtcAmount, _endIWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: loanTokenWrbtcAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _token either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _tokenAmount token (rbtc, or wrbtc, or iwrbtc) amount\n * @return _endToken end time of accumulated fee calculation for token (rbtc, or wrbtc, or iwrbtc )\n */\n function _getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 _tokenAmount, uint256 _endToken) {\n if (\n _token == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT ||\n _token == wrbtcTokenAddress ||\n _token == loanTokenWrbtcAddress\n ) {\n (_tokenAmount, _endToken) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n } else {\n revert(\"FeeSharingCollector::_getRBTCBalance: only rbtc-based tokens are allowed\");\n }\n }\n\n // @todo update dependency `numTokenCheckpoints` -> `totalTokenCheckpoints` and deprecate numTokenCheckpoints function\n /**\n * @dev This getter function `numTokenCheckpoints` is added for backwards compatibility\n * broken when renamed `numTokenCheckpoints` storage variable to `totalTokenCheckpoints`.\n *\n * @param _token token address to get checkpoints for\n *\n * @return Total token checkpoints\n */\n function numTokenCheckpoints(address _token) external view returns (uint256) {\n return totalTokenCheckpoints[_token];\n }\n}\n\n/* Interfaces */\ninterface ILoanToken {\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n}\n\ninterface ILoanTokenWRBTC {\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function tokenPrice() external view returns (uint256 price);\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title FeeSharingCollectorProxy contract.\n * @dev FeeSharingCollectorProxy contract should be upgradable, use UpgradableProxy.\n * FeeSharingCollectorStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract FeeSharingCollectorProxy is FeeSharingCollectorStorage, UpgradableProxy {\n /**\n * @notice Construct a new feeSharingCollectorProxy contract.\n * @param _protocol The address of the sovryn protocol.\n * @param _staking The address of the staking\n */\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorStorage.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../mixins/EnumerableAddressSet.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\n\n/**\n * @title FeeSharingCollectorStorage contact\n * @notice Just the storage part of FeeSharingCollector contract, and FeeSharingCollectorProxy. No functions,\n * only constant, variables and required structures (mappings)\n * */\ncontract FeeSharingCollectorStorage is Ownable {\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet;\n uint256 constant FEE_WITHDRAWAL_INTERVAL = 172800;\n\n IProtocol public protocol;\n IStaking public staking;\n\n /// @notice Checkpoints by index per pool token address\n mapping(address => mapping(uint256 => Checkpoint)) public tokenCheckpoints;\n\n /// @notice The number of checkpoints for each token address.\n mapping(address => uint256) public totalTokenCheckpoints;\n\n /// @notice\n /// user => token => processed checkpoints\n mapping(address => mapping(address => uint256)) public processedCheckpoints;\n\n /// @notice Last time fees were withdrawn per pool token address:\n /// token => time\n mapping(address => uint256) public lastFeeWithdrawalTime;\n\n /// @notice Amount of tokens that were transferred, but not saved in checkpoints.\n /// token => amount\n mapping(address => uint96) public unprocessedAmount;\n\n struct Checkpoint {\n uint32 blockNumber;\n uint32 timestamp;\n uint96 totalWeightedStake;\n uint96 numTokens;\n }\n\n struct TokenWithSkippedCheckpointsWithdraw {\n address tokenAddress;\n uint256 fromCheckpoint;\n }\n\n /**\n * @dev Add extra modifier (Reentrancy) below.\n * Because we cannot add any additional storage slot before this storage contract after initial deployment\n */\n\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Additional storage for converter whitelist mechanism.\n * @dev Initialization here does not works. We need to create a separate setter & getter.\n * @dev Just set the visibility to internal should be fine.\n */\n EnumerableAddressSet.AddressSet internal whitelistedConverterList;\n\n mapping(bytes4 => bool) public isFunctionExecuted;\n\n /**\n * @dev Wrbtc token address\n */\n address public wrbtcTokenAddress;\n\n /**\n * @dev iWrbtc loan token address\n */\n address public loanTokenWrbtcAddress;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n\n/* Interfaces */\n\ninterface IProtocol {\n /**\n *\n * @param tokens The array address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function underlyingToLoanPool(address token) external view returns (address);\n\n function wrbtcToken() external view returns (IWrbtcERC20);\n\n function getSovTokenAddress() external view returns (address);\n}\n" + }, + "contracts/governance/GovernorAlpha.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./Staking/SafeMath96.sol\";\nimport \"./Timelock.sol\";\nimport \"./Staking/interfaces/IStaking.sol\";\nimport \"../rsk/RSKAddrValidator.sol\";\n\n/**\n * @title Governance Contract.\n * @notice This is an adapted clone of compound’s governance model. In general,\n * the process is the same: Token holders can make (executable) proposals if\n * they possess enough voting power, vote on proposals during a predefined\n * voting period and in the end evaluate the outcome. If successful, the\n * proposal will be scheduled on the timelock contract. Only after sufficient\n * time passed, it can be executed. A minimum voting power is required for\n * making a proposal as well as a minimum quorum.\n *\n * Voting power in the Bitocracy:\n * Stakers will receive voting power in the Bitocracy in return for their\n * staking commitment. This voting power is weighted by how much SOV is staked\n * and for how long the staking period is - staking more SOV over longer staking\n * periods results in higher voting power. With this voting power, users can\n * vote for or against any SIP in bitocracy.sovryn.app.\n * */\ncontract GovernorAlpha is SafeMath96 {\n /* Storage */\n\n /// @notice The name of this contract.\n string public constant NAME = \"Sovryn Governor Alpha\";\n\n /// @notice The maximum number of actions that can be included in a proposal.\n function proposalMaxOperations() public pure returns (uint256) {\n return 10;\n } // 10 actions\n\n /// @notice The delay before voting on a proposal may take place, once proposed.\n function votingDelay() public pure returns (uint256) {\n return 1;\n } // 1 block\n\n /// @notice The duration of voting on a proposal, in blocks.\n function votingPeriod() public pure returns (uint256) {\n return 2880;\n } // ~1 day in blocks (assuming 30s blocks)\n\n /// @notice The address of the Sovryn Protocol Timelock.\n ITimelock public timelock;\n\n /// @notice The address of the Sovryn staking contract.\n IStaking public staking;\n\n /// @notice The address of the Governor Guardian.\n address public guardian;\n\n /// @notice The total number of proposals.\n uint256 public proposalCount;\n\n /// @notice Percentage of current total voting power require to vote.\n uint96 public quorumPercentageVotes;\n\n // @notice Majority percentage.\n uint96 public majorityPercentageVotes;\n\n struct Proposal {\n /// @notice Unique id for looking up a proposal.\n uint256 id;\n /// @notice The block at which voting begins: holders must delegate their votes prior to this block.\n uint32 startBlock;\n /// @notice The block at which voting ends: votes must be cast prior to this block.\n uint32 endBlock;\n /// @notice Current number of votes in favor of this proposal.\n uint96 forVotes;\n /// @notice Current number of votes in opposition to this proposal.\n uint96 againstVotes;\n ///@notice the quorum required for this proposal.\n uint96 quorum;\n ///@notice the majority percentage required for this proposal.\n uint96 majorityPercentage;\n /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds.\n uint64 eta;\n /// @notice the start time is required for the staking contract.\n uint64 startTime;\n /// @notice Flag marking whether the proposal has been canceled.\n bool canceled;\n /// @notice Flag marking whether the proposal has been executed.\n bool executed;\n /// @notice Creator of the proposal.\n address proposer;\n /// @notice the ordered list of target addresses for calls to be made.\n address[] targets;\n /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made.\n uint256[] values;\n /// @notice The ordered list of function signatures to be called.\n string[] signatures;\n /// @notice The ordered list of calldata to be passed to each call.\n bytes[] calldatas;\n /// @notice Receipts of ballots for the entire set of voters.\n mapping(address => Receipt) receipts;\n }\n\n /// @notice Ballot receipt record for a voter\n struct Receipt {\n /// @notice Whether or not a vote has been cast.\n bool hasVoted;\n /// @notice Whether or not the voter supports the proposal.\n bool support;\n /// @notice The number of votes the voter had, which were cast.\n uint96 votes;\n }\n\n /// @notice Possible states that a proposal may be in.\n enum ProposalState {\n Pending,\n Active,\n Canceled,\n Defeated,\n Succeeded,\n Queued,\n Expired,\n Executed\n }\n\n /// @notice The official record of all proposals ever proposed.\n mapping(uint256 => Proposal) public proposals;\n\n /// @notice The latest proposal for each proposer.\n mapping(address => uint256) public latestProposalIds;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the ballot struct used by the contract.\n bytes32 public constant BALLOT_TYPEHASH = keccak256(\"Ballot(uint256 proposalId,bool support)\");\n\n /* Events */\n\n /// @notice An event emitted when a new proposal is created.\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint256 startBlock,\n uint256 endBlock,\n string description\n );\n\n /// @notice An event emitted when a vote has been cast on a proposal.\n event VoteCast(address voter, uint256 proposalId, bool support, uint256 votes);\n\n /// @notice An event emitted when a proposal has been canceled.\n event ProposalCanceled(uint256 id);\n\n /// @notice An event emitted when a proposal has been queued in the Timelock.\n event ProposalQueued(uint256 id, uint256 eta);\n\n /// @notice An event emitted when a proposal has been executed in the Timelock.\n event ProposalExecuted(uint256 id);\n\n /* Functions */\n\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 _quorumPercentageVotes,\n uint96 _majorityPercentageVotes\n ) public {\n timelock = ITimelock(timelock_);\n staking = IStaking(staking_);\n guardian = guardian_;\n quorumPercentageVotes = _quorumPercentageVotes;\n majorityPercentageVotes = _majorityPercentageVotes;\n }\n\n /// @notice The number of votes required in order for a voter to become a proposer.\n function proposalThreshold() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(\n block.number - 1,\n \"GovernorAlpha::proposalThreshold: block number overflow\"\n ),\n block.timestamp\n );\n // 1% of current total voting power.\n return totalVotingPower / 100;\n }\n\n /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.\n function quorumVotes() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(block.number - 1, \"GovernorAlpha::quorumVotes: block number overflow\"),\n block.timestamp\n );\n // 4% of current total voting power.\n return\n mul96(\n quorumPercentageVotes,\n totalVotingPower,\n \"GovernorAlpha::quorumVotes:multiplication overflow\"\n ) / 100;\n }\n\n /**\n * @notice Create a new proposal.\n * @param targets Array of contract addresses to perform proposal execution.\n * @param values Array of rBTC amounts to send on proposal execution.\n * @param signatures Array of function signatures to call on proposal execution.\n * @param calldatas Array of payloads for the calls on proposal execution.\n * @param description Text describing the purpose of the proposal.\n * */\n function propose(\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // note: passing this block's timestamp, but the number of the previous block.\n // todo: think if it would be better to pass block.timestamp - 30 (average block time)\n // (probably not because proposal starts in 1 block from now).\n uint96 threshold = proposalThreshold();\n require(\n staking.getPriorVotes(msg.sender, sub256(block.number, 1), block.timestamp) >\n threshold,\n \"GovernorAlpha::propose: proposer votes below proposal threshold\"\n );\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"GovernorAlpha::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"GovernorAlpha::propose: must provide actions\");\n require(\n targets.length <= proposalMaxOperations(),\n \"GovernorAlpha::propose: too many actions\"\n );\n\n uint256 latestProposalId = latestProposalIds[msg.sender];\n if (latestProposalId != 0) {\n ProposalState proposersLatestProposalState = state(latestProposalId);\n require(\n proposersLatestProposalState != ProposalState.Active,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already active proposal\"\n );\n require(\n proposersLatestProposalState != ProposalState.Pending,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal\"\n );\n }\n\n uint256 startBlock = add256(block.number, votingDelay());\n uint256 endBlock = add256(startBlock, votingPeriod());\n\n proposalCount++;\n\n /// @dev quorum: proposalThreshold is 1% of total votes, we can save gas using this pre calculated value.\n /// @dev startTime: Required by the staking contract. not used by the governance contract itself.\n Proposal memory newProposal =\n Proposal({\n id: proposalCount,\n startBlock: safe32(\n startBlock,\n \"GovernorAlpha::propose: start block number overflow\"\n ),\n endBlock: safe32(endBlock, \"GovernorAlpha::propose: end block number overflow\"),\n forVotes: 0,\n againstVotes: 0,\n quorum: mul96(\n quorumPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on quorum computation\"\n ),\n majorityPercentage: mul96(\n majorityPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on majorityPercentage computation\"\n ),\n eta: 0,\n startTime: safe64(block.timestamp, \"GovernorAlpha::propose: startTime overflow\"),\n canceled: false,\n executed: false,\n proposer: msg.sender,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas\n });\n\n proposals[newProposal.id] = newProposal;\n latestProposalIds[newProposal.proposer] = newProposal.id;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n values,\n signatures,\n calldatas,\n startBlock,\n endBlock,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Enqueue a proposal and everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function queue(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Succeeded,\n \"GovernorAlpha::queue: proposal can only be queued if it is succeeded\"\n );\n Proposal storage proposal = proposals[proposalId];\n uint256 eta = add256(block.timestamp, timelock.delay());\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n proposal.eta = safe64(eta, \"GovernorAlpha::queue: ETA overflow\");\n emit ProposalQueued(proposalId, eta);\n }\n\n /**\n * @notice Tries to enqueue a proposal, verifying it has not been previously queued.\n * @param target Contract addresses to perform proposal execution.\n * @param value rBTC amount to send on proposal execution.\n * @param signature Function signature to call on proposal execution.\n * @param data Payload for the call on proposal execution.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function _queueOrRevert(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !timelock.queuedTransactions(\n keccak256(abi.encode(target, value, signature, data, eta))\n ),\n \"GovernorAlpha::_queueOrRevert: proposal action already queued at eta\"\n );\n timelock.queueTransaction(target, value, signature, data, eta);\n }\n\n /**\n * @notice Execute a proposal by looping and performing everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function execute(uint256 proposalId) public payable {\n require(\n state(proposalId) == ProposalState.Queued,\n \"GovernorAlpha::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.executeTransaction.value(proposal.values[i])(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal by looping and cancelling everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function cancel(uint256 proposalId) public {\n ProposalState state = state(proposalId);\n require(\n state != ProposalState.Executed,\n \"GovernorAlpha::cancel: cannot cancel executed proposal\"\n );\n\n Proposal storage proposal = proposals[proposalId];\n /// @notice Cancel only if sent by the guardian.\n require(msg.sender == guardian, \"GovernorAlpha::cancel: sender isn't a guardian\");\n\n proposal.canceled = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalCanceled(proposalId);\n }\n\n /**\n * @notice Get a proposal list of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return Arrays of the 4 call parameters: targets, values, signatures, calldatas.\n * */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.values, p.signatures, p.calldatas);\n }\n\n /**\n * @notice Get a proposal receipt.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param voter A governance stakeholder with voting power.\n * @return The voter receipt of the proposal.\n * */\n function getReceipt(uint256 proposalId, address voter) public view returns (Receipt memory) {\n return proposals[proposalId].receipts[voter];\n }\n\n /**\n * @notice Casts a vote by sender.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function castVote(uint256 proposalId, bool support) public {\n return _castVote(msg.sender, proposalId, support);\n }\n\n /**\n * @notice Voting with EIP-712 Signatures.\n *\n * Voting power can be delegated to any address, and then can be used to\n * vote on proposals. A key benefit to users of by-signature functionality\n * is that they can create a signed vote transaction for free, and have a\n * trusted third-party spend rBTC(or ETH) on gas fees and write it to the\n * blockchain for them.\n *\n * The third party in this scenario, submitting the SOV-holder’s signed\n * transaction holds a voting power that is for only a single proposal.\n * The signatory still holds the power to vote on their own behalf in\n * the proposal if the third party has not yet published the signed\n * transaction that was given to them.\n *\n * @dev The signature needs to be broken up into 3 parameters, known as\n * v, r and s:\n * const r = '0x' + sig.substring(2).substring(0, 64);\n * const s = '0x' + sig.substring(2).substring(64, 128);\n * const v = '0x' + sig.substring(2).substring(128, 130);\n *\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * @param v The recovery byte of the signature.\n * @param r Half of the ECDSA signature pair.\n * @param s Half of the ECDSA signature pair.\n * */\n function castVoteBySig(\n uint256 proposalId,\n bool support,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public {\n /**\n * @dev The DOMAIN_SEPARATOR is a hash that uniquely identifies a\n * smart contract. It is built from a string denoting it as an\n * EIP712 Domain, the name of the token contract, the version,\n * the chainId in case it changes, and the address that the\n * contract is deployed at.\n * */\n bytes32 domainSeparator =\n keccak256(\n abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this))\n );\n\n /// @dev GovernorAlpha uses BALLOT_TYPEHASH, while Staking uses DELEGATION_TYPEHASH\n bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support));\n\n bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n address signatory = ecrecover(digest, v, r, s);\n\n /// @dev Verify address is not null and PK is not null either.\n require(\n RSKAddrValidator.checkPKNotZero(signatory),\n \"GovernorAlpha::castVoteBySig: invalid signature\"\n );\n return _castVote(signatory, proposalId, support);\n }\n\n /**\n * @notice Cast a vote, adding it to the total counting.\n * @param voter A governance stakeholder with voting power that is casting the vote.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function _castVote(\n address voter,\n uint256 proposalId,\n bool support\n ) internal {\n require(\n state(proposalId) == ProposalState.Active,\n \"GovernorAlpha::_castVote: voting is closed\"\n );\n Proposal storage proposal = proposals[proposalId];\n Receipt storage receipt = proposal.receipts[voter];\n require(receipt.hasVoted == false, \"GovernorAlpha::_castVote: voter already voted\");\n uint96 votes = staking.getPriorVotes(voter, proposal.startBlock, proposal.startTime);\n\n if (support) {\n proposal.forVotes = add96(\n proposal.forVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n } else {\n proposal.againstVotes = add96(\n proposal.againstVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n }\n\n receipt.hasVoted = true;\n receipt.support = support;\n receipt.votes = votes;\n\n emit VoteCast(voter, proposalId, support, votes);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __acceptAdmin() public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__acceptAdmin: sender must be gov guardian\"\n );\n timelock.acceptAdmin();\n }\n\n /// @notice Sets guardian address to zero.\n function __abdicate() public {\n require(msg.sender == guardian, \"GovernorAlpha::__abdicate: sender must be gov guardian\");\n guardian = address(0);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.queueTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.executeTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /**\n * @notice Get a proposal state.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return The state of the proposal: Canceled, Pending, Active, Defeated,\n * Succeeded, Executed, Expired.\n * */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"GovernorAlpha::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n\n if (proposal.canceled) {\n return ProposalState.Canceled;\n }\n\n if (block.number <= proposal.startBlock) {\n return ProposalState.Pending;\n }\n\n if (block.number <= proposal.endBlock) {\n return ProposalState.Active;\n }\n\n uint96 totalVotes =\n add96(\n proposal.forVotes,\n proposal.againstVotes,\n \"GovernorAlpha:: state: forVotes + againstVotes > uint96\"\n );\n uint96 totalVotesMajorityPercentage =\n div96(totalVotes, 100, \"GovernorAlpha:: state: division error\");\n totalVotesMajorityPercentage = mul96(\n totalVotesMajorityPercentage,\n majorityPercentageVotes,\n \"GovernorAlpha:: state: totalVotes * majorityPercentage > uint96\"\n );\n if (proposal.forVotes <= totalVotesMajorityPercentage || totalVotes < proposal.quorum) {\n return ProposalState.Defeated;\n }\n\n if (proposal.eta == 0) {\n return ProposalState.Succeeded;\n }\n\n if (proposal.executed) {\n return ProposalState.Executed;\n }\n\n if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) {\n return ProposalState.Expired;\n }\n\n return ProposalState.Queued;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function add256(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"addition overflow\");\n return c;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function sub256(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b <= a, \"subtraction underflow\");\n return a - b;\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n}\n\n/* Interfaces */\n\ninterface TimelockInterface {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\ninterface StakingInterface {\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n}\n" + }, + "contracts/governance/GovernorVault.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title Governance Vault.\n * @notice This contract stores tokens and rBTC only transfereble by owner,\n * i.e. Sovryn governance.\n * */\ncontract GovernorVault is Ownable {\n /* Events */\n\n event Deposited(address indexed sender, uint256 amount);\n event TokensTransferred(address indexed receiver, address indexed token, uint256 amount);\n event RbtcTransferred(address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer tokens.\n * @param _receiver The receiver of tokens.\n * @param _token The address of token contract.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _receiver,\n address _token,\n uint256 _amount\n ) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n require(_token != address(0), \"Invalid token address\");\n\n require(IERC20(_token).transfer(_receiver, _amount), \"Transfer failed\");\n emit TokensTransferred(_receiver, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC.\n * @param _receiver The receiver of RBTC.\n * @param _amount The amount to be transferred.\n * */\n function transferRbtc(address payable _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n\n address(_receiver).transfer(_amount);\n emit RbtcTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {\n if (msg.value > 0) {\n emit Deposited(msg.sender, msg.value);\n }\n }\n}\n" + }, + "contracts/governance/IFeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * */\ninterface IFeeSharingCollector {\n function withdrawFees(address[] calldata _token) external;\n\n function transferTokens(address _token, uint96 _amount) external;\n\n function withdraw(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external;\n}\n" + }, + "contracts/governance/Staking/interfaces/IStaking.sol": { + "content": "pragma solidity ^0.5.17;\n\npragma experimental ABIEncoderV2;\n\n/**\n * @title Interface for Staking modules governance/Staking/modules\n */\n\ninterface IStaking {\n /*************************** StakingAdminModule ***************************/\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external;\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external;\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external;\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external;\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) external;\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external;\n\n /**\n * @notice Allows the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external;\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external;\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external;\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\n\n /*************************** StakingGovernanceModule ***************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\n * be internal instead of a public function.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external;\n\n /*************************** StakingStakeModule ***************************/\n\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance);\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes);\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\n\n /*************************** StakingStorageModule ***************************/\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n /// @return uint256(MAX_VOTING_WEIGHT);\n function getStorageMaxVotingWeight() external pure returns (uint256);\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n /// @return uint256(WEIGHT_FACTOR);\n function getStorageWeightFactor() external pure returns (uint256);\n\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\n function getStorageDefaultWeightScaling() external pure returns (uint256);\n\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\n\n /// @notice The EIP-712 typehash for the contract's domain.\n /// @return uint256(DOMAIN_TYPEHASH);\n function getStorageDomainTypehash() external pure returns (uint256);\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n /// @return uint256(DELEGATION_TYPEHASH);\n function getStorageDelegationTypehash() external pure returns (uint256);\n\n /// @return name;\n function getStorageName() external view returns (string memory);\n\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n function kickoffTS() external view returns (uint256);\n\n /// @notice The token to be staked\n function SOVToken() external view returns (address);\n\n /// @notice Stakers delegated voting power\n /// @param staker - the delegating address\n /// @param until - delegated voting\n /// @return _delegate - voting power delegated to address\n function delegates(address staker, uint256 until) external view returns (address _delegate);\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately\n /// see function unlockAllTokens() for details\n function allUnlocked() external view returns (bool);\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\n function newStakingContract() external view returns (address);\n\n /// CHECKPOINTS\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\n function totalStakingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n function numTotalStakingCheckpoints(uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n function delegateStakingCheckpoints(\n address delagatee,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n function userStakingCheckpoints(\n address user,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number\n function numUserStakingCheckpoints(address user, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n function nonces(address user) external view returns (uint256 nonce);\n\n /// SLASHING ///\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n function feeSharing() external view returns (address);\n\n /// @notice used for weight scaling when unstaking with slashing.\n /// @return uint96 DEFAULT_WEIGHT_SCALING\n function weightScaling() external view returns (uint96);\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n function admins(address isAdmin) external view returns (bool);\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n function vestingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\n\n ///@notice vesting registry contract PROXY address\n function vestingRegistryLogic() external view returns (address);\n\n /// @dev user => flag whether user has pauser role.\n function pausers(address isPauser) external view returns (bool);\n\n /// @dev Staking contract is paused\n function paused() external view returns (bool);\n\n /// @dev Staking contract is frozen\n function frozen() external view returns (bool);\n\n /*************************** StakingVestingModule ***************************/\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool);\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external;\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external;\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes);\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n /*************************** StakingWithdrawModule ***************************/\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * */\n function governanceWithdrawVesting(address vesting, address receiver) external;\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96);\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external;\n\n /*************************** WeightedStakingModule ***************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The date/timestamp of the unstaking time.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * TODO: WeightedStaking::weightedStakeByDate should probably better\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Returns public constant MAX_DURATION\n * preserved for backwards compatibility\n * Use getStorageMaxDurationToStakeTokens()\n * @return uint96 MAX_DURATION for staking\n **/\n function MAX_DURATION() external view returns (uint256);\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() external view returns (address);\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() external view returns (bool);\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) external;\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external;\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() external view returns (uint256);\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param maxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\n}\n" + }, + "contracts/governance/Staking/modules/shared/CheckpointsShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\n\n/**\n * @title Checkpoints contract.\n * @notice Increases and decreases storage values for users, delegatees and\n * total daily stake.\n * */\ncontract CheckpointsShared is StakingStorageShared, SafeMath96 {\n /// @notice An event emitted when an account changes its delegate.\n event DelegateChanged(\n address indexed delegator,\n uint256 lockedUntil,\n address indexed fromDelegate,\n address indexed toDelegate\n );\n\n /// @notice An event emitted when a delegate account's stake balance changes.\n event DelegateStakeChanged(\n address indexed delegate,\n uint256 lockedUntil,\n uint256 previousBalance,\n uint256 newBalance\n );\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n event ContractCodeHashAdded(bytes32 hash);\n\n event ContractCodeHashRemoved(bytes32 hash);\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n event TeamVestingCancelled(address indexed caller, address receiver);\n\n event TeamVestingPartiallyCancelled(\n address indexed caller,\n address receiver,\n uint256 nextStartFrom\n );\n\n constructor() internal {\n // abstract\n }\n\n /**\n * @notice Increases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = add96(vested, value, \"CP01\"); // vested overflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Decreases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = sub96(vested, value, \"CP02\"); // vested underflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Writes on storage the user vested amount.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newVest The new vest balance.\n * */\n function _writeVestingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newVest\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP03\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n vestingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n vestingCheckpoints[lockedTS][nCheckpoints - 1].stake = newVest;\n } else {\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newVest);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP04\"); // staked overflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP05\"); // staked underflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the user stake.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeUserCheckpoint(\n address account,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP06\"); // block number > 32 bits\n\n if (\n nCheckpoints > 0 &&\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n userStakingCheckpoints[account][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numUserStakingCheckpoints[account][lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP07\"); // block number > 32 bits\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = 0;\n // @dev We need to check delegate checkpoint value here,\n //\t\tbecause we had an issue in `stake` function:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n // @dev It can be greater than 0, but inconsistent after 3 transactions\n if (staked > value) {\n newStake = sub96(staked, value, \"CP08\"); // staked underflow\n }\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the delegate stake.\n * @param delegatee The delegate address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeDelegateCheckpoint(\n address delegatee,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP09\"); // block numb > 32 bits\n uint96 oldStake = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n\n if (\n nCheckpoints > 0 &&\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].fromBlock ==\n blockNumber\n ) {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numDelegateStakingCheckpoints[delegatee][lockedTS] = nCheckpoints + 1;\n }\n emit DelegateStakeChanged(delegatee, lockedTS, oldStake, newStake);\n }\n\n /**\n * @notice Increases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP10\"); // staked overflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP11\"); // staked underflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the total stake.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeStakingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP12\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n totalStakingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newStake);\n numTotalStakingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Get the current balance of an account locked until a certain date.\n * @param account The user address.\n * @param lockDate The lock date.\n * @return The stake amount.\n * */\n function _currentBalance(address account, uint256 lockDate) internal view returns (uint96) {\n uint32 _numUnserStakingCheckpoints = numUserStakingCheckpoints[account][lockDate] - 1;\n return userStakingCheckpoints[account][lockDate][_numUnserStakingCheckpoints].stake;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\nimport \"../../../../openzeppelin/SafeMath.sol\";\nimport \"../../../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking modules shared functionality\n */\ncontract StakingShared is StakingStorageShared, SafeMath96 {\n using SafeMath for uint256;\n\n uint256 internal constant FOUR_WEEKS = 4 weeks;\n\n /**\n * @dev Throws if paused.\n */\n modifier whenNotPaused() {\n require(!paused, \"paused\"); // SS03\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\"); // SS01\n _;\n }\n\n /**\n\t * @dev Throws if called by any account other than the owner or admin or pauser.\n\t \n\tmodifier onlyAuthorizedOrPauser() {\n\t\trequire(isOwner() || admins[msg.sender] || pausers[msg.sender], \"unauthorized\"); // WS02\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if called by any account other than the owner or pauser.\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || pausers[msg.sender], \"unauthorized\"); // SS02\n _;\n }\n\n /**\n * @dev Throws if called by any account other than pauser.\n * @notice Uncomment when needed\n */\n /*\n\tmodifier onlyPauser() {\n\t\trequire(pausers[msg.sender], \"Not pauser\");\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if frozen.\n */\n modifier whenNotFrozen() {\n require(!frozen, \"paused\"); // SS04\n _;\n }\n\n constructor() internal {\n // abstract\n }\n\n function _notSameBlockAsStakingCheckpoint(uint256 lockDate, address stakeFor) internal view {\n uint32 nCheckpoints = numUserStakingCheckpoints[stakeFor][lockDate];\n bool notSameBlock =\n userStakingCheckpoints[stakeFor][lockDate][nCheckpoints - 1].fromBlock != block.number;\n require(notSameBlock, \"cannot be mined in the same block as last stake\"); // S20\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = kickoffTS;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / TWO_WEEKS;\n lockDate = periodFromKickoff * TWO_WEEKS + start;\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS14\n\n date = _adjustDateForOrigin(date);\n uint32 nCheckpoints = numUserStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (userStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return userStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (userStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = userStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return userStakingCheckpoints[account][date][lower].stake;\n }\n\n /**\n * @dev origin vesting contracts have different dates\n * we need to add 2 weeks to get end of period (by default, it's start)\n * @param date The staking date to compute the power for.\n * @return unlocking date.\n */\n function _adjustDateForOrigin(uint256 date) internal view returns (uint256) {\n uint256 adjustedDate = _timestampToLockDate(date);\n //origin vesting contracts have different dates\n //we need to add 2 weeks to get end of period (by default, it's start)\n if (adjustedDate != date) {\n date = adjustedDate + TWO_WEEKS;\n }\n return date;\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function _computeWeightByDate(uint256 date, uint256 startDate)\n internal\n pure\n returns (uint96 weight)\n {\n require(date >= startDate, \"date < startDate\"); // WS18\n uint256 remainingTime = (date - startDate);\n require(MAX_DURATION >= remainingTime, \"remaining time > max duration\"); // WS19\n /// @dev x = max days - remaining days\n uint96 x = uint96(MAX_DURATION - remainingTime) / (1 days);\n /// @dev w = (m^2 - x^2)/m^2 +1 (multiplied by the weight factor)\n weight = add96(\n WEIGHT_FACTOR,\n mul96(\n MAX_VOTING_WEIGHT * WEIGHT_FACTOR,\n sub96(\n MAX_DURATION_POW_2,\n x * x,\n \"weight underflow\" // WS20\n ),\n \"weight mul overflow\" // WS21\n ) / MAX_DURATION_POW_2,\n \"overflow on weight\" // WS22\n );\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function _isVestingContract(address stakerAddress) internal view returns (bool) {\n bool isVesting;\n bytes32 codeHash;\n\n assembly {\n codeHash := extcodehash(stakerAddress)\n }\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingStorageShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../../openzeppelin/Ownable.sol\";\nimport \"../../../../interfaces/IERC20.sol\";\nimport \"../../../IFeeSharingCollector.sol\";\nimport \"../../../Vesting/IVestingRegistry.sol\";\n\n/**\n * @title StakingStorageShared contract is inherited by Staking modules.\n * @notice Just the storage part of stacking contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingProxy and Checkpoints contracts.\n *\n * What is SOV staking?\n * The purpose of the SOV token is to provide a pseudonymous,\n * censorship-resistant mechanism for governing the parameters of the Sovryn\n * protocol, while aligning the incentives of protocol governors with the\n * long-term success of the protocol. Any SOV token holder can choose to\n * stake (lock up) their tokens for a fixed period of time in return for\n * voting rights in the Bitocracy. Stakers are further incentivised through\n * fee and slashing rewards.\n * */\ncontract StakingStorageShared is Ownable {\n /// @notice 2 weeks in seconds.\n uint256 constant TWO_WEEKS = 1209600;\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n uint96 public constant MAX_VOTING_WEIGHT = 9;\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n uint96 public constant WEIGHT_FACTOR = 10;\n\n /// @notice The maximum duration to stake tokens for.\n uint256 public constant MAX_DURATION = 1092 days;\n\n /// @notice The maximum duration ^2\n uint96 constant MAX_DURATION_POW_2 = 1092 * 1092;\n\n /// @notice Default weight scaling.\n uint96 constant DEFAULT_WEIGHT_SCALING = 3;\n\n /// @notice Range for weight scaling.\n uint96 constant MIN_WEIGHT_SCALING = 1;\n uint96 constant MAX_WEIGHT_SCALING = 9;\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n uint256 public kickoffTS;\n\n string name = \"SOVStaking\";\n\n /// @notice The token to be staked.\n IERC20 public SOVToken;\n\n /// @notice A record of each accounts delegate.\n mapping(address => mapping(uint256 => address)) public delegates;\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately.\n bool public allUnlocked = false;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n bytes32 public constant DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 lockDate,uint256 nonce,uint256 expiry)\");\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure.\n address public newStakingContract;\n\n /*************************** Checkpoints *******************************/\n\n /// @notice A checkpoint for marking the stakes from a given block\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public totalStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numTotalStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public delegateStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numDelegateStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public userStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numUserStakingCheckpoints;\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n mapping(address => uint256) public nonces;\n\n /*************************** Slashing *******************************/\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n IFeeSharingCollector public feeSharing;\n\n /// @notice used for weight scaling when unstaking with slashing.\n uint96 public weightScaling = DEFAULT_WEIGHT_SCALING;\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n mapping(address => bool) public vestingWhitelist;\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n mapping(address => bool) public admins;\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n mapping(bytes32 => bool) public vestingCodeHashes;\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public vestingCheckpoints;\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numVestingCheckpoints;\n\n ///@notice vesting registry contract\n IVestingRegistry public vestingRegistryLogic;\n\n /// @dev user => flag whether user has pauser role.\n mapping(address => bool) public pausers;\n\n /// @dev Staking contract is paused\n bool public paused;\n\n /// @dev Staking contract is frozen\n bool public frozen;\n\n /// @dev max iterations that can be supported in 1 tx for the withdrawal\n uint256 internal maxVestingWithdrawIterations;\n\n constructor() internal {\n //abstract\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingAdminModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Admin Module.\n * @notice Implements administrative functionality pause, freeze and setting addresses and parameters\n * related to staking\n * */\ncontract StakingAdminModule is IFunctionsList, StakingShared {\n using Address for address payable;\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(_admin != address(0), \"cannot add the zero address as an admin\");\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(admins[_admin], \"address is not an admin\");\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external onlyOwner whenNotFrozen {\n require(_pauser != address(0), \"cannot add the zero address as a pauser\");\n pausers[_pauser] = true;\n emit PauserAddedOrRemoved(_pauser, true);\n }\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external onlyOwner whenNotFrozen {\n require(pausers[_pauser], \"address is not a pauser\");\n delete pausers[_pauser];\n emit PauserAddedOrRemoved(_pauser, false);\n }\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) public onlyPauserOrOwner whenNotFrozen {\n paused = _pause;\n emit StakingPaused(_pause);\n }\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external onlyPauserOrOwner {\n require(_freeze != frozen, \"Cannot freeze/unfreeze to the same state\"); // WS25\n if (_freeze) pauseUnpause(true);\n frozen = _freeze;\n emit StakingFrozen(_freeze);\n }\n\n /**\n * @notice Allow the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external onlyOwner whenNotFrozen {\n require(_feeSharing != address(0), \"FeeSharing address shouldn't be 0\"); // S17\n feeSharing = IFeeSharingCollector(_feeSharing);\n }\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external onlyOwner whenNotFrozen {\n require(\n MIN_WEIGHT_SCALING <= _weightScaling && _weightScaling <= MAX_WEIGHT_SCALING,\n \"scaling doesn't belong to range [1, 9]\" // S18\n );\n weightScaling = _weightScaling;\n }\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external onlyOwner whenNotFrozen {\n require(_newStakingContract != address(0), \"can't reset the new staking contract to 0\"); // S16\n newStakingContract = _newStakingContract;\n }\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external whenNotFrozen {\n require(newStakingContract != address(0), \"there is no new staking contract set\"); // S19\n revert(\"not implemented\");\n /// @dev implementation:\n /// @dev Iterate over all possible lock dates from now until now + MAX_DURATION.\n /// @dev Read the stake & delegate of the msg.sender\n /// @dev If stake > 0, stake it at the new contract until the lock date with the current delegate.\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](13);\n functionsList[0] = this.addAdmin.selector;\n functionsList[1] = this.removeAdmin.selector;\n functionsList[2] = this.addPauser.selector;\n functionsList[3] = this.removePauser.selector;\n functionsList[4] = this.pauseUnpause.selector;\n functionsList[5] = this.freezeUnfreeze.selector;\n functionsList[6] = this.setFeeSharing.selector;\n functionsList[7] = this.setWeightScaling.selector;\n functionsList[8] = this.setNewStakingContract.selector;\n functionsList[9] = this.owner.selector;\n functionsList[10] = this.isOwner.selector;\n functionsList[11] = this.transferOwnership.selector;\n functionsList[12] = this.migrateToNewStakingContract.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingGovernanceModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/IVesting.sol\";\n\n/**\n * @title Staking Governance Module contract\n * @notice Implements voting power and delegation functionality\n * */\ncontract StakingGovernanceModule is IFunctionsList, StakingShared, CheckpointsShared {\n using Address for address payable;\n\n /************* TOTAL VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n /// @dev Start the computation with the exact or previous unlocking date (voting weight remians the same until the next break point).\n uint256 start = _timestampToLockDate(time);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n totalVotingPower = add96(\n totalVotingPower,\n _totalPowerByDate(i, start, blockNumber),\n \"arrays mismatch\"\n ); // WS06\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorTotalStakesForDate(date, blockNumber);\n /// @dev weight is multiplied by some factor to allow decimals.\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS07\n }\n\n /****************************** DELEGATED VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96) {\n return getPriorVotes(account, block.number - 1, block.timestamp);\n }\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96 votes) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n votes = add96(\n votes,\n _totalPowerByDateForDelegatee(account, i, start, blockNumber),\n \"overflow - total VP\"\n ); // WS09\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDateForDelegatee(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS10\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n date = _adjustDateForOrigin(date);\n return _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined yet\"); // WS11\n\n uint32 nCheckpoints = numDelegateStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (delegateStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return delegateStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (delegateStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = delegateStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return delegateStakingCheckpoints[account][date][lower].stake;\n }\n\n /**************** SHARED FUNCTIONS *********************/\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for. Adjusted to the next valid lock date, as necessary\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n public\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorTotalStakesForDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function _getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS08\n\n uint32 nCheckpoints = numTotalStakingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (totalStakingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return totalStakingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n // Next check implicit zero balance\n if (totalStakingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Checkpoint memory cp = totalStakingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return totalStakingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Set new delegatee. Move from user's current delegate to a new\n * delegatee the stake balance.\n * @param delegator The user address to move stake balance from its current delegatee.\n * @param delegatee The new delegatee. The address to move stake balance to.\n * @param lockedTS The lock date.\n * @dev Reverts if delegator balance or delegatee is not valid, unless the sender is a vesting contract.\n * */\n function _delegate(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n address currentDelegate = delegates[delegator][lockedTS];\n uint96 delegatorBalance = _currentBalance(delegator, lockedTS);\n\n // vesting contracts will in multiple cases try to delegate a zero balance\n // or to the existing delegatee\n if (_isVestingContract(msg.sender)) {\n if (delegatorBalance == 0 || currentDelegate == delegatee) {\n return;\n }\n } else {\n require(delegatorBalance > 0, \"no stake to delegate\");\n require(currentDelegate != delegatee, \"cannot delegate to the existing delegatee\");\n }\n\n delegates[delegator][lockedTS] = delegatee;\n\n emit DelegateChanged(delegator, lockedTS, currentDelegate, delegatee);\n\n _moveDelegates(currentDelegate, delegatee, delegatorBalance, lockedTS);\n }\n\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n function _delegateNext(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n if (_isVestingContract(msg.sender)) {\n uint256 nextLock = lockedTS.add(TWO_WEEKS);\n address currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n\n // @dev workaround for the issue with a delegation of the latest stake\n uint256 endDate = IVesting(msg.sender).endDate();\n nextLock = lockedTS.add(FOUR_WEEKS);\n if (nextLock == endDate) {\n currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n }\n }\n }\n\n /**\n * @notice Move an amount of delegate stake from a source address to a\n * destination address.\n * @param srcRep The address to get the staked amount from.\n * @param dstRep The address to send the staked amount to.\n * @param amount The staked amount to move.\n * @param lockedTS The lock date.\n * */\n function _moveDelegates(\n address srcRep,\n address dstRep,\n uint96 amount,\n uint256 lockedTS\n ) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) _decreaseDelegateStake(srcRep, lockedTS, amount);\n\n if (dstRep != address(0)) _increaseDelegateStake(dstRep, lockedTS, amount);\n }\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function _getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external whenNotPaused {\n require(delegatee != address(0), \"cannot delegate to the zero address\");\n _notSameBlockAsStakingCheckpoint(lockDate, msg.sender);\n\n _delegate(msg.sender, delegatee, lockDate);\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n _delegateNext(msg.sender, delegatee, lockDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](6);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStakeModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking contract staking functionality module\n * @notice Implements staking functionality\n **/\ncontract StakingStakeModule is IFunctionsList, StakingShared, CheckpointsShared, ApprovalReceiver {\n using SafeMath for uint256;\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stake(msg.sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external onlyThisContract whenNotPaused whenNotFrozen {\n _stake(sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * */\n function _stake(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted\n ) internal {\n _stakeOptionalTokenTransfer(\n sender,\n amount,\n until,\n stakeFor,\n delegatee,\n timeAdjusted,\n true // transfer SOV\n );\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * @param transferToken Should transfer SOV - false for multiple iterations like in stakeBySchedule\n * */\n function _stakeOptionalTokenTransfer(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted,\n bool transferToken\n ) internal {\n require(amount > 0, \"amount needs to be bigger than 0\"); // S01\n\n if (!timeAdjusted) {\n until = _timestampToLockDate(until);\n }\n require(\n until > block.timestamp,\n \"Staking::_timestampToLockDate: staking period too short\"\n ); // S02\n\n /// @dev Stake for the sender if not specified otherwise.\n if (stakeFor == address(0)) {\n stakeFor = sender;\n }\n // must wait a block before staking again for that same deadline\n _notSameBlockAsStakingCheckpoint(until, stakeFor);\n\n /// @dev Delegate for stakeFor if not specified otherwise.\n if (delegatee == address(0)) {\n delegatee = stakeFor;\n }\n\n /// @dev Do not stake longer than the max duration.\n if (!timeAdjusted) {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n }\n\n uint96 previousBalance = _currentBalance(stakeFor, until);\n\n /// @dev Increase stake.\n _increaseStake(sender, amount, stakeFor, until, transferToken);\n\n // @dev Previous version wasn't working properly for the following case:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n address previousDelegatee = delegates[stakeFor][until];\n\n if (previousDelegatee != delegatee) {\n // @dev only the user that stakes for himself is allowed to delegate VP to another address\n // which works with vesting stakes and prevents vulnerability of delegating VP to an arbitrary address from\n // any address\n\n if (delegatee != stakeFor) {\n require(\n stakeFor == sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n } else if (sender != stakeFor && previousDelegatee != address(0)) {\n require(stakeFor == sender, \"Only sender is allowed to change delegatee\");\n }\n\n /// @dev Update delegatee.\n delegates[stakeFor][until] = delegatee;\n\n /// @dev Decrease stake on previous balance for previous delegatee.\n _decreaseDelegateStake(previousDelegatee, until, previousBalance);\n\n /// @dev Add previousBalance to amount.\n amount = add96(previousBalance, amount, \"add amounts failed\");\n }\n\n /// @dev Increase stake.\n _increaseDelegateStake(delegatee, until, amount);\n emit DelegateChanged(stakeFor, until, previousDelegatee, delegatee);\n }\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until)\n external\n whenNotPaused\n whenNotFrozen\n {\n previousLock = _timestampToLockDate(previousLock);\n until = _timestampToLockDate(until);\n\n _notSameBlockAsStakingCheckpoint(previousLock, msg.sender);\n\n /// @dev Do not exceed the max duration, no overflow possible.\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n\n require(previousLock < until, \"must increase staking duration\"); // S04\n\n /// @dev Update checkpoints.\n /// @dev TODO James: Can reading stake at block.number -1 cause trouble with multiple tx in a block?\n uint96 amount = _getPriorUserStakeByDate(msg.sender, previousLock, block.number - 1);\n require(amount > 0, \"no stakes till the prev lock date\"); // S05\n _decreaseUserStake(msg.sender, previousLock, amount);\n _increaseUserStake(msg.sender, until, amount);\n\n if (_isVestingContract(msg.sender)) {\n _decreaseVestingStake(previousLock, amount);\n _increaseVestingStake(until, amount);\n }\n\n _decreaseDailyStake(previousLock, amount);\n _increaseDailyStake(until, amount);\n\n /// @dev Delegate might change: if there is already a delegate set for the until date, it will remain the delegate for this position\n address delegateFrom = delegates[msg.sender][previousLock];\n delegates[msg.sender][previousLock] = address(0); //the previousLock delegates nullifying before reading that form `until` guards in case delegateTo == until\n address delegateTo = delegates[msg.sender][until];\n if (delegateTo == address(0)) {\n delegateTo = delegateFrom;\n delegates[msg.sender][until] = delegateFrom;\n }\n _decreaseDelegateStake(delegateFrom, previousLock, amount);\n _increaseDelegateStake(delegateTo, until, amount);\n\n emit ExtendedStakingDuration(msg.sender, previousLock, until, amount);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param until The date until which the tokens will be staked.\n * @param transferToken if false - token transfer should be handled separately\n * */\n function _increaseStake(\n address sender,\n uint96 amount,\n address stakeFor,\n uint256 until,\n bool transferToken\n ) internal {\n /// @dev Retrieve the SOV tokens.\n if (transferToken)\n require(\n SOVToken.transferFrom(sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // IS10\n\n /// @dev Increase staked balance.\n uint96 balance = _currentBalance(stakeFor, until);\n balance = add96(balance, amount, \"increaseStake: overflow\"); // IS20\n\n /// @dev Update checkpoints.\n _increaseDailyStake(until, amount);\n _increaseUserStake(stakeFor, until, amount);\n\n if (_isVestingContract(stakeFor)) _increaseVestingStake(until, amount);\n\n emit TokensStaked(stakeFor, amount, until, balance);\n }\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function _stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) internal {\n require(amount > 0, \"Invalid amount\");\n require(duration <= MAX_DURATION, \"Invalid duration\");\n require(intervalLength > 0, \"Invalid interval length\");\n require(intervalLength % TWO_WEEKS == 0, \"Invalid interval length\");\n if (delegatee != stakeFor && delegatee != address(0)) {\n require(\n stakeFor == msg.sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n }\n /**\n * @dev Stake them until lock dates according to the vesting schedule.\n * Note: because staking is only possible in periods of 2 weeks,\n * the total duration might end up a bit shorter than specified\n * depending on the date of staking.\n * */\n uint256 start = _timestampToLockDate(block.timestamp + cliff);\n uint256 end = _timestampToLockDate(block.timestamp + duration);\n require(start <= end, \"Invalid schedule\");\n uint256 numIntervals;\n if (start < end) {\n numIntervals = (end - start) / intervalLength + 1;\n } else {\n numIntervals = 1;\n }\n uint256 stakedPerInterval = amount / numIntervals;\n\n /// @dev transferring total SOV amount before staking\n require(\n SOVToken.transferFrom(msg.sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // SS10\n /// @dev stakedPerInterval might lose some dust on rounding. Add it to the first staking date.\n if (numIntervals >= 1) {\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(amount - stakedPerInterval * (numIntervals - 1)),\n start,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n /// @dev Stake the rest in 4 week intervals.\n for (uint256 i = start + intervalLength; i <= end; i += intervalLength) {\n /// @dev Stakes for itself, delegates to the owner.\n _notSameBlockAsStakingCheckpoint(i, stakeFor); // must wait a block before staking again for that same deadline\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(stakedPerInterval),\n i,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n }\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance) {\n for (uint256 i = kickoffTS; i <= block.timestamp + MAX_DURATION; i += TWO_WEEKS) {\n balance = add96(balance, _currentBalance(account, i), \"Staking::balanceOf: overflow\"); // S12\n }\n }\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96) {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n return nCheckpoints > 0 ? totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake : 0;\n }\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes)\n {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n\n /// @dev Calculate stakes.\n uint256 count = 0;\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n if (_currentBalance(account, i) > 0) {\n count++;\n }\n }\n dates = new uint256[](count);\n stakes = new uint96[](count);\n\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n uint256 j = 0;\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n uint96 balance = _currentBalance(account, i);\n if (balance > 0) {\n dates[j] = i;\n stakes[j] = balance;\n j++;\n }\n }\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOVToken);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeWithApproval.selector;\n return selectors;\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256) {\n return _timestampToLockDate(timestamp);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](10);\n functionsList[0] = this.stake.selector;\n functionsList[1] = this.stakeWithApproval.selector;\n functionsList[2] = this.extendStakingDuration.selector;\n functionsList[3] = this.stakesBySchedule.selector;\n functionsList[4] = this.stakeBySchedule.selector;\n functionsList[5] = this.balanceOf.selector;\n functionsList[6] = this.getCurrentStakedUntil.selector;\n functionsList[7] = this.getStakes.selector;\n functionsList[8] = this.timestampToLockDate.selector;\n functionsList[9] = this.receiveApproval.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStorageModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/StakingStorageShared.sol\";\n\n/**\n * @title Staking Storage Module\n * @notice Provides getters for public storage variables\n **/\ncontract StakingStorageModule is IFunctionsList, StakingStorageShared {\n function getStorageDefaultWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256) {\n return MAX_DURATION;\n }\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n function getStorageMaxVotingWeight() external pure returns (uint256) {\n return uint256(MAX_VOTING_WEIGHT);\n }\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n function getStorageWeightFactor() external pure returns (uint256) {\n return uint256(WEIGHT_FACTOR);\n }\n\n /// @notice Default weight scaling.\n function getStorageDefaulWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling)\n {\n return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING));\n }\n\n /// @notice The EIP-712 typehash for the contract's domain.\n function getStorageDomainTypehash() external pure returns (uint256) {\n return uint256(DOMAIN_TYPEHASH);\n }\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n function getStorageDelegationTypehash() external pure returns (uint256) {\n return uint256(DELEGATION_TYPEHASH);\n }\n\n function getStorageName() external view returns (string memory) {\n return name;\n }\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() public view returns (uint256) {\n return maxVestingWithdrawIterations;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](32);\n functionsList[0] = this.getStorageMaxDurationToStakeTokens.selector;\n functionsList[1] = this.getStorageMaxVotingWeight.selector;\n functionsList[2] = this.getStorageWeightFactor.selector;\n functionsList[3] = this.getStorageDefaulWeightScaling.selector;\n functionsList[4] = this.getStorageRangeForWeightScaling.selector;\n functionsList[5] = this.getStorageDomainTypehash.selector;\n functionsList[6] = this.getStorageDelegationTypehash.selector;\n functionsList[7] = this.getStorageName.selector;\n functionsList[8] = this.kickoffTS.selector;\n functionsList[9] = this.SOVToken.selector;\n functionsList[10] = this.delegates.selector;\n functionsList[11] = this.allUnlocked.selector;\n functionsList[12] = this.newStakingContract.selector;\n functionsList[13] = this.totalStakingCheckpoints.selector;\n functionsList[14] = this.numTotalStakingCheckpoints.selector;\n functionsList[15] = this.delegateStakingCheckpoints.selector;\n functionsList[16] = this.numDelegateStakingCheckpoints.selector;\n functionsList[17] = this.userStakingCheckpoints.selector;\n functionsList[18] = this.numUserStakingCheckpoints.selector;\n functionsList[19] = this.nonces.selector;\n functionsList[20] = this.feeSharing.selector;\n functionsList[21] = this.weightScaling.selector;\n functionsList[22] = this.vestingWhitelist.selector;\n functionsList[23] = this.admins.selector;\n functionsList[24] = this.vestingCodeHashes.selector;\n functionsList[25] = this.vestingCheckpoints.selector;\n functionsList[26] = this.numVestingCheckpoints.selector;\n functionsList[27] = this.vestingRegistryLogic.selector;\n functionsList[28] = this.pausers.selector;\n functionsList[29] = this.paused.selector;\n functionsList[30] = this.frozen.selector;\n functionsList[31] = this.getMaxVestingWithdrawIterations.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingVestingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Vesting Module contract\n * @notice Implements interaction with Vesting functionality: vesting registry, vesting staking\n * */\ncontract StakingVestingModule is IFunctionsList, StakingShared {\n event ContractCodeHashAdded(bytes32 hash);\n event ContractCodeHashRemoved(bytes32 hash);\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external onlyOwner whenNotFrozen {\n vestingRegistryLogic = IVestingRegistry(_vestingRegistryProxy);\n }\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(lockedDates.length == values.length, \"arrays mismatch\"); // WS05\n\n uint256 length = lockedDates.length;\n for (uint256 i = 0; i < length; i++) {\n _setVestingStake(lockedDates[i], values[i]);\n }\n }\n\n /**\n * @notice Sets the users' vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to be set.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function _setVestingStake(uint256 lockedTS, uint96 value) internal {\n require(\n lockedTS > kickoffTS,\n \"Invalid lock dates: must greater than contract creation timestamp\"\n );\n\n // locked date must be multiples of 14 days / TWO_WEEKS\n require(\n (lockedTS - kickoffTS) % TWO_WEEKS == 0,\n \"Invalid lock dates: not multiples of 14 days\"\n );\n\n // locked date must not exceed the MAX_DURATION\n if (lockedTS > block.timestamp) {\n require(\n lockedTS - block.timestamp <= MAX_DURATION,\n \"Invalid lock dates: exceed max duration\"\n );\n }\n\n // the value must not exceed the total staked at the given locked date\n uint32 nStakeCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 totalStaked = totalStakingCheckpoints[lockedTS][nStakeCheckpoints - 1].stake;\n require(\n value <= totalStaked,\n \"Invalid stake amount: greater than the total staked for given date\"\n );\n\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint32 blockNumber;\n\n Checkpoint memory recentCP = vestingCheckpoints[lockedTS][nCheckpoints - 1];\n if (nCheckpoints == 0) blockNumber = uint32(block.number) - 1;\n else blockNumber = recentCP.fromBlock + 1;\n\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, value);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n\n emit VestingStakeSet(lockedTS, value);\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n uint96 priorStake = _getPriorUserStakeByDate(account, date, blockNumber);\n // @dev we need to modify function in order to workaround issue with Vesting.withdrawTokens:\n //\t\treturn 1 instead of 0 if message sender is a contract.\n if (priorStake == 0 && _isVestingContract(msg.sender)) {\n priorStake = 1;\n }\n return priorStake;\n }\n\n /*************************** Weighted Vesting Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes)\n {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedVestingStakeByDate(i, start, blockNumber);\n if (weightedStake > 0) {\n votes = add96(votes, weightedStake, \"overflow on total weight\"); // WS15\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n power = _weightedVestingStakeByDate(date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorVestingStakeByDate(date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul oveflow\") / WEIGHT_FACTOR; // WS16\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorVestingStakeByDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS17\n\n uint32 nCheckpoints = numVestingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (vestingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return vestingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (vestingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = vestingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return vestingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n require(vestingCodeHashes[codeHash], \"not a registered vesting code hash\");\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool) {\n bool isVesting;\n bytes32 codeHash = _getCodeHash(stakerAddress);\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](9);\n functionsList[0] = this.setVestingRegistry.selector;\n functionsList[1] = this.setVestingStakes.selector;\n functionsList[2] = this.getPriorUserStakeByDate.selector;\n functionsList[3] = this.getPriorVestingWeightedStake.selector;\n functionsList[4] = this.getPriorVestingStakeByDate.selector;\n functionsList[5] = this.addContractCodeHash.selector;\n functionsList[6] = this.removeContractCodeHash.selector;\n functionsList[7] = this.isVestingContract.selector;\n functionsList[8] = this.weightedVestingStakeByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingWithdrawModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/ITeamVesting.sol\";\nimport \"../../Vesting/IVesting.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking withdrawal functionality module\n **/\ncontract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShared {\n using SafeMath for uint256;\n\n event MaxVestingWithdrawIterationsUpdated(uint256 oldMaxIterations, uint256 newMaxIterations);\n\n /// @dev Struct for direct withdraw function -- to avoid stack too deep issue\n struct VestingConfig {\n address vestingAddress;\n uint256 startDate;\n uint256 endDate;\n uint256 cliff;\n uint256 duration;\n address tokenOwner;\n }\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev If until is not a valid lock date, the next lock date after until is used.\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n // adjust until here to avoid adjusting multiple times, and to make sure an adjusted date is passed to\n // _notSameBlockAsStakingCheckpoint\n until = _adjustDateForOrigin(until);\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, false);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe need to check block.timestamp here\n _withdrawNext(until, receiver, false);\n }\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external onlyAuthorized whenNotFrozen {\n /// require the caller only for team vesting contract.\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n _cancelTeamVesting(vesting, receiver, startFrom);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param _vesting The vesting address.\n * @param _receiver The receiving address.\n * @param _startFrom The start value for the iterations.\n * or just unlocked tokens (false).\n *\n * @return nextStartFrom is a timestamp to be used for next withdrawal.\n * @return notCompleted flag that indicates that the cancel team vesting is not completely done.\n * */\n function _cancelTeamVesting(\n address _vesting,\n address _receiver,\n uint256 _startFrom\n ) private returns (uint256 nextStartFrom, bool notCompleted) {\n require(_receiver != address(0), \"receiver address invalid\");\n\n ITeamVesting teamVesting = ITeamVesting(_vesting);\n\n VestingConfig memory vestingConfig =\n VestingConfig(\n _vesting,\n teamVesting.startDate(),\n teamVesting.endDate(),\n teamVesting.cliff(),\n teamVesting.duration(),\n teamVesting.tokenOwner()\n );\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them, as long as the itrations less than maxVestingWithdrawIterations.\n uint256 end = vestingConfig.endDate;\n\n uint256 defaultStart = vestingConfig.startDate + vestingConfig.cliff;\n\n _startFrom = _startFrom >= defaultStart ? _startFrom : defaultStart;\n\n /// @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 totalIterationValue =\n (_startFrom + (TWO_WEEKS * (maxVestingWithdrawIterations - 1)));\n uint256 adjustedEnd = end < totalIterationValue ? end : totalIterationValue;\n\n /// @dev Withdraw for each unlocked position.\n for (uint256 i = _startFrom; i <= adjustedEnd; i += TWO_WEEKS) {\n /// @dev Read amount to withdraw.\n uint96 tempStake = _getPriorUserStakeByDate(_vesting, i, block.number - 1);\n\n if (tempStake > 0) {\n /// @dev do governance direct withdraw for team vesting\n _withdrawFromTeamVesting(tempStake, i, _receiver, vestingConfig);\n }\n }\n\n if (adjustedEnd < end) {\n nextStartFrom = adjustedEnd + TWO_WEEKS;\n emit TeamVestingPartiallyCancelled(msg.sender, _receiver, nextStartFrom);\n return (nextStartFrom, true);\n } else {\n emit TeamVestingCancelled(msg.sender, _receiver);\n return (end, false);\n }\n }\n\n /**\n * @notice Send user' staked tokens to a receiver taking into account punishments.\n * Sovryn encourages long-term commitment and thinking. When/if you unstake before\n * the end of the staking period, a percentage of the original staking amount will\n * be slashed. This amount is also added to the reward pool and is distributed\n * between all other stakers.\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * Needs to be adjusted to the next valid lock date before calling this function.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdraw(\n uint96 amount,\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n // @dev it's very unlikely some one will have 1/10**18 SOV staked in Vesting contract\n //\t\tthis check is a part of workaround for Vesting.withdrawTokens issue\n if (amount == 1 && _isVestingContract(msg.sender)) {\n return;\n }\n _validateWithdrawParams(msg.sender, amount, until);\n\n /// @dev Determine the receiver.\n if (receiver == address(0)) receiver = msg.sender;\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(msg.sender, until, amount);\n if (_isVestingContract(msg.sender)) _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[msg.sender][until], until, amount);\n\n /// @dev Early unstaking should be punished.\n if (block.timestamp < until && !allUnlocked && !isGovernance) {\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n amount -= punishedAmount;\n\n /// @dev punishedAmount can be 0 if block.timestamp are very close to 'until'\n if (punishedAmount > 0) {\n require(address(feeSharing) != address(0), \"FeeSharing address wasn't set\"); // S08\n /// @dev Move punished amount to fee sharing.\n /// @dev Approve transfer here and let feeSharing do transfer and write checkpoint.\n SOVToken.approve(address(feeSharing), punishedAmount);\n feeSharing.transferTokens(address(SOVToken), punishedAmount);\n }\n }\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(msg.sender, amount, until, receiver, isGovernance);\n }\n\n /**\n * @notice Send user' staked tokens to a receiver.\n * This function is dedicated only for direct withdrawal from staking contract.\n * Currently only being used by cancelTeamVesting()\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender.\n * @param vestingConfig The vesting config.\n * @dev VestingConfig struct intended to avoid stack too deep issue, and it contains this properties:\n address vestingAddress; // vesting contract address\n uint256 startDate; //start date of vesting\n uint256 endDate; // end date of vesting\n uint256 cliff; // after this time period the tokens begin to unlock\n uint256 duration; // after this period all the tokens will be unlocked\n address tokenOwner; // owner of the vested tokens\n * */\n function _withdrawFromTeamVesting(\n uint96 amount,\n uint256 until,\n address receiver,\n VestingConfig memory vestingConfig\n ) internal {\n address vesting = vestingConfig.vestingAddress;\n\n until = _timestampToLockDate(until);\n _validateWithdrawParams(vesting, amount, until);\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(vesting, until, amount);\n\n _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[vesting][until], until, amount);\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(vesting, amount, until, receiver, true);\n }\n\n // @dev withdraws tokens for lock date 2 weeks later than given lock date\n function _withdrawNext(\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n if (_isVestingContract(msg.sender)) {\n // nextLock needs to be adjusted to the next valid lock date to make sure we don't accidentally\n // withdraw stakes that are in the future and would get slashed (if until is not\n // a valid lock date). but until is already handled in the withdraw function\n uint256 nextLock = until.add(TWO_WEEKS);\n if (isGovernance || block.timestamp >= nextLock) {\n uint96 stakes = _getPriorUserStakeByDate(msg.sender, nextLock, block.number - 1);\n if (stakes > 0) {\n _withdraw(stakes, nextLock, receiver, isGovernance);\n }\n }\n }\n }\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked. Adjusted to the next valid lock date, if necessary.\n * @return Amount to withraw and penalty amount\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96)\n {\n until = _adjustDateForOrigin(until);\n _validateWithdrawParams(msg.sender, amount, until);\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n return (amount - punishedAmount, punishedAmount);\n }\n\n /**\n * @notice Get punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _getPunishedAmount(uint96 amount, uint256 until) internal view returns (uint96) {\n uint256 date = _timestampToLockDate(block.timestamp);\n uint96 weight = _computeWeightByDate(until, date); /// @dev (10 - 1) * WEIGHT_FACTOR\n weight = weight * weightScaling;\n return (amount * weight) / WEIGHT_FACTOR / 100;\n }\n\n /**\n * @notice Validate withdraw parameters.\n * @param account Address to be validated.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _validateWithdrawParams(\n address account,\n uint96 amount,\n uint256 until\n ) internal view {\n require(amount > 0, \"Amount of tokens to withdraw must be > 0\"); // S10\n uint96 balance = _getPriorUserStakeByDate(account, until, block.number - 1);\n require(amount <= balance, \"Staking::withdraw: not enough balance\"); // S11\n }\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external onlyOwner whenNotFrozen {\n allUnlocked = true;\n emit TokensUnlocked(SOVToken.balanceOf(address(this)));\n }\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param newMaxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 newMaxIterations)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(newMaxIterations > 0, \"Invalid max iterations\");\n emit MaxVestingWithdrawIterationsUpdated(maxVestingWithdrawIterations, newMaxIterations);\n maxVestingWithdrawIterations = newMaxIterations;\n }\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev This function is dedicated only to support backward compatibility for sovryn ecosystem that has been implementing this staking contract.\n * @dev Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/4bbfe5bd0311ca71e4ef0e3af810d3791d8e4061/contracts/governance/Staking/modules/StakingWithdrawModule.sol#L78\n * */\n function governanceWithdrawVesting(address vesting, address receiver)\n public\n onlyAuthorized\n whenNotFrozen\n {\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n ITeamVesting teamVesting = ITeamVesting(vesting);\n uint256 teamVestingStartDate = teamVesting.startDate();\n uint256 teamVestingCliff = teamVesting.cliff();\n\n uint256 nextStartFrom = teamVestingStartDate + teamVestingCliff;\n bool withdrawFlag = true;\n\n bool notCompleted;\n\n /**\n * The withdrawal is limited to certain iterations (set in maxVestingWithdrawIterations), so in order to withdraw all, we need to iterate until it is fully withdrawn.\n */\n while (withdrawFlag) {\n /**\n * notCompleted is the flag whether the withdrawal is fully withdrawn or not.\n * As long as the notCompleted is true, we will keep the iteration using the nextStartFrom.\n */\n (nextStartFrom, notCompleted) = _cancelTeamVesting(vesting, receiver, nextStartFrom);\n withdrawFlag = notCompleted ? true : false;\n }\n\n emit VestingTokensWithdrawn(vesting, receiver);\n }\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n require(vestingWhitelist[msg.sender], \"unauthorized\"); // S07\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, true);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe don't need to check block.timestamp here\n _withdrawNext(until, receiver, true);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.withdraw.selector;\n functionsList[1] = this.cancelTeamVesting.selector;\n functionsList[2] = this.getWithdrawAmounts.selector;\n functionsList[3] = this.unlockAllTokens.selector;\n functionsList[4] = this.setMaxVestingWithdrawIterations.selector;\n functionsList[5] = this.governanceWithdraw.selector;\n functionsList[6] = this.governanceWithdrawVesting.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/WeightedStakingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Weighted Staking module contract.\n * @notice Implements getters for weighted staking functionality\n * */\ncontract WeightedStakingModule is IFunctionsList, StakingShared, CheckpointsShared {\n /*************************** User Weighted Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The start date/timestamp from which to calculate the weighted stake.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake) {\n return _getPriorWeightedStake(account, blockNumber, date);\n }\n\n function _getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) internal view returns (uint96 priorWeightedStake) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedStakeByDate(account, i, start, blockNumber);\n if (weightedStake > 0) {\n priorWeightedStake = add96(\n priorWeightedStake,\n weightedStake,\n \"overflow on total weight calc\"\n ); // WS12\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n return _weightedStakeByDate(account, date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function _weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorUserStakeByDate(account, date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS13\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight)\n {\n return _computeWeightByDate(date, startDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](3);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/SafeMath96.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n/**\n * @title SafeMath96 contract.\n * @notice Improved Solidity's arithmetic operations with added overflow checks.\n * @dev SafeMath96 uses uint96, unsigned integers of 96 bits length, so every\n * integer from 0 to 2^96-1 can be operated.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * SafeMath restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this contract instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n * */\ncontract SafeMath96 {\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function safe64(uint256 n, string memory errorMessage) internal pure returns (uint64) {\n require(n < 2**64, errorMessage);\n return uint64(n);\n }\n\n function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) {\n require(n < 2**96, errorMessage);\n return uint96(n);\n }\n\n /**\n * @notice Adds two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `+` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe addition a+b.\n * */\n function add96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n uint96 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n /**\n * @notice Substracts two unsigned integers, reverting on underflow.\n * @dev Counterpart to Solidity's `-` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on underflow.\n * @return The safe substraction a-b.\n * */\n function sub96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n require(b <= a, errorMessage);\n return a - b;\n }\n\n /**\n * @notice Multiplies two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `*` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe product a*b.\n * */\n function mul96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n if (a == 0) {\n return 0;\n }\n\n uint96 c = a * b;\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @notice Divides two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `/` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe division a/b.\n * */\n function div96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint96 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n}\n" + }, + "contracts/governance/Staking/StakingProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./modules/shared/StakingStorageShared.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Staking Proxy contract.\n * @dev Staking contract should be upgradable, use UpgradableProxy.\n * StakingStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingProxy is StakingStorageShared, UpgradableProxy {\n /**\n * @notice Construct a new staking contract.\n * @param SOV The address of the SOV token address.\n */\n constructor(address SOV) public {\n SOVToken = IERC20(SOV);\n kickoffTS = block.timestamp;\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewards.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Staking Rewards Contract.\n * @notice This is a trial incentive program.\n * In this, the SOV emitted and becoming liquid from the Adoption Fund could be utilized\n * to offset the higher APY's offered for Liquidity Mining events.\n * Vesting contract stakes are excluded from these rewards.\n * Only wallets which have staked previously liquid SOV are eligible for these rewards.\n * Tokenholders who stake their SOV receive staking rewards, a pro-rata share\n * of the revenue that the platform generates from various transaction fees\n * plus revenues from stakers who have a portion of their SOV slashed for\n * early unstaking.\n * */\ncontract StakingRewards is StakingRewardsStorage {\n using SafeMath for uint256;\n\n /// @notice Emitted when SOV is withdrawn\n /// @param receiver The address which recieves the SOV\n /// @param amount The amount withdrawn from the Smart Contract\n event RewardWithdrawn(address indexed receiver, uint256 amount);\n\n /**\n * @notice Replacement of constructor by initialize function for Upgradable Contracts\n * This function will be called only once by the owner.\n * @param _SOV SOV token address\n * @param _staking StakingProxy address should be passed\n * */\n function initialize(address _SOV, IStaking _staking) external onlyOwner {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n SOV = IERC20(_SOV);\n staking = _staking;\n startTime = staking.timestampToLockDate(block.timestamp);\n setMaxDuration(15 * TWO_WEEKS);\n deploymentBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Stops the current rewards program.\n * @dev All stakes existing on the contract at the point in time of\n * cancellation continue accruing rewards until the end of the staking\n * period being rewarded\n * */\n function stop() external onlyOwner {\n require(stopBlock == 0, \"Already stopped\");\n stopBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Collect rewards\n * @dev User calls this function to collect SOV staking rewards as per the SIP-0024 program.\n * The weighted stake is calculated using getPriorWeightedStake. Block number sent to the functon\n * must be a finalised block, hence we deduct 1 from the current block. User is only allowed to withdraw\n * after intervals of 14 days.\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * The issue is that we can only run for a max duration and if someone stakes for the\n * first time after the max duration is over, the reward will always return 0. Thus, we need to restart\n * from the duration that elapsed without generating rewards.\n * */\n function collectReward(uint256 restartTime) external {\n (uint256 withdrawalTime, uint256 amount) = getStakerCurrentReward(true, restartTime);\n require(withdrawalTime > 0 && amount > 0, \"no valid reward\");\n withdrawals[msg.sender] = withdrawalTime;\n _payReward(msg.sender, amount);\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred.\n */\n function withdrawTokensByOwner(address _receiverAddress) external onlyOwner {\n uint256 value = SOV.balanceOf(address(this));\n _transferSOV(_receiverAddress, value);\n }\n\n /**\n * @notice Changes average block time - based on blockchain\n * @dev If average block time significantly changes, we can update it here and use for block number calculation\n */\n function setAverageBlockTime(uint256 _averageBlockTime) external onlyOwner {\n averageBlockTime = _averageBlockTime;\n }\n\n /**\n * @notice This function computes the last staking checkpoint and calculates the corresponding\n * block number using the average block time which is then added to the mapping `checkpointBlockDetails`.\n */\n function setBlock() external {\n uint256 lastCheckpointTime = staking.timestampToLockDate(block.timestamp);\n _setBlock(lastCheckpointTime);\n }\n\n /**\n * @notice This function computes the block number using the average block time for a given historical\n * checkpoint which is added to the mapping `checkpointBlockDetails`.\n * @param _time Exact staking checkpoint time\n */\n function setHistoricalBlock(uint256 _time) external {\n _setBlock(_time);\n }\n\n /**\n * @notice Sets the max duration\n * @dev Rewards can be collected for a maximum duration at a time. This\n * is to avoid Block Gas Limit failures. Setting it zero would mean that it will loop\n * through the entire duration since the start of rewards program.\n * It should ideally be set to a value, for which the rewards can be easily processed.\n * @param _duration Max duration for which rewards can be collected at a go (in seconds)\n * */\n function setMaxDuration(uint256 _duration) public onlyOwner {\n maxDuration = _duration;\n }\n\n /**\n * @notice Internal function to calculate weighted stake\n * @dev If the rewards program is stopped, the user will still continue to\n * earn till the end of staking period based on the stop block.\n * @param _staker Staker address\n * @param _block Last finalised block\n * @param _date The date to compute prior weighted stakes\n * @return The weighted stake\n * */\n function _computeRewardForDate(\n address _staker,\n uint256 _block,\n uint256 _date\n ) internal view returns (uint256 weightedStake) {\n weightedStake = staking.getPriorWeightedStake(_staker, _block, _date);\n if (stopBlock > 0 && stopBlock < _block) {\n uint256 previousWeightedStake =\n staking.getPriorWeightedStake(_staker, stopBlock, _date);\n if (previousWeightedStake < weightedStake) {\n weightedStake = previousWeightedStake;\n }\n }\n }\n\n /**\n * @notice Internal function to pay rewards\n * @dev Base rate is annual, but we pay interest for 14 days,\n * which is 1/26 of one staking year (1092 days)\n * @param _staker User address\n * @param amount the reward amount\n * */\n function _payReward(address _staker, uint256 amount) internal {\n require(SOV.balanceOf(address(this)) >= amount, \"not enough funds to reward user\");\n claimedBalances[_staker] = claimedBalances[_staker].add(amount);\n _transferSOV(_staker, amount);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit RewardWithdrawn(_receiver, _amount);\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Internal function to calculate and set block\n * */\n function _setBlock(uint256 _checkpointTime) internal {\n uint256 currentTS = block.timestamp;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n require(checkpointBlockDetails[_checkpointTime] == 0, \"block number already set\");\n uint256 checkpointBlock =\n lastFinalisedBlock.sub(((currentTS.sub(_checkpointTime)).div(averageBlockTime)));\n checkpointBlockDetails[_checkpointTime] = checkpointBlock;\n }\n\n /**\n * @notice Get staker's current accumulated reward\n * @dev The collectReward() function internally calls this function to calculate reward amount\n * @param considerMaxDuration True: Runs for the maximum duration - used in tx not to run out of gas\n * False - to query total rewards\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * @return The timestamp of last withdrawal\n * @return The accumulated reward\n */\n function getStakerCurrentReward(bool considerMaxDuration, uint256 restartTime)\n public\n view\n returns (uint256 lastWithdrawalInterval, uint256 amount)\n {\n uint256 weightedStake;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n uint256 currentTS = block.timestamp;\n uint256 duration;\n address staker = msg.sender;\n uint256 lastWithdrawal = withdrawals[staker];\n\n uint256 lastStakingInterval = staking.timestampToLockDate(currentTS);\n lastWithdrawalInterval = lastWithdrawal > 0 ? lastWithdrawal : startTime;\n if (lastStakingInterval <= lastWithdrawalInterval) return (0, 0);\n /* Normally the restart time is 0. If this function returns a valid lastWithdrawalInterval\n\t\tand zero amount - that means there were no valid rewards for that period. So the new period must start\n\t\tfrom the end of the last interval or till the time no rewards are accumulated i.e. restartTime */\n if (restartTime >= lastWithdrawalInterval) {\n uint256 latestRestartTime = staking.timestampToLockDate(restartTime);\n lastWithdrawalInterval = latestRestartTime;\n }\n\n if (considerMaxDuration) {\n uint256 addedMaxDuration = lastWithdrawalInterval.add(maxDuration);\n duration = addedMaxDuration < currentTS\n ? staking.timestampToLockDate(addedMaxDuration)\n : lastStakingInterval;\n } else {\n duration = lastStakingInterval;\n }\n for (uint256 i = lastWithdrawalInterval; i < duration; i += TWO_WEEKS) {\n uint256 referenceBlock = checkpointBlockDetails[i];\n if (referenceBlock == 0) {\n referenceBlock = lastFinalisedBlock.sub(\n ((currentTS.sub(i)).div(averageBlockTime))\n );\n }\n if (referenceBlock < deploymentBlock) referenceBlock = deploymentBlock;\n weightedStake = weightedStake.add(_computeRewardForDate(staker, referenceBlock, i));\n }\n lastWithdrawalInterval = duration;\n amount = weightedStake.mul(BASE_RATE).div(DIVISOR);\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title StakingRewards Proxy contract.\n * @dev StakingRewards contract should be upgradable. Used UpgradableProxy.\n * StakingRewardsStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy with\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingRewardsProxy is StakingRewardsStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking Rewards Storage Contract.\n * @notice Just the storage part of staking rewards contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingRewardsProxy.\n *\n * What is SOV staking rewards - SIP-0024?\n * The purpose of the SOV staking rewards - SIP-0024 is to reward,\n * \"marginal stakers\" (ie, stakers by choice, not currently vesting) with liquid SOV\n * at the beginning of each new staking interval.\n * */\ncontract StakingRewardsStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n ///@notice the staking proxy contract address\n IStaking public staking;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 1209600;\n\n /// @notice Annual Base Rate - it is the maximum interest rate(APY)\n uint256 public constant BASE_RATE = 2975;\n\n /// @notice DIVISOR is set as 2600000 = 26 (num periods per year) * 10 (max voting weight) * 10000 (2975 -> 0.2975)\n uint256 public constant DIVISOR = 2600000;\n\n /// @notice Maximum duration to collect rewards at one go\n uint256 public maxDuration;\n\n /// @notice Represents the time when the contract is deployed\n uint256 public startTime;\n\n /// @notice Represents the block when the Staking Rewards pogram is stopped\n uint256 public stopBlock;\n\n /// @notice User Address -> Last Withdrawn Timestamp\n mapping(address => uint256) public withdrawals;\n\n /// @notice User Address -> Claimed Balance\n mapping(address => uint256) public claimedBalances;\n\n /// @notice Represents the block when the StakingRwards Program is started\n uint256 public deploymentBlock;\n\n /// Moved the variables from Initializable contract to resolve issue caused by incorrect Inheritance Order\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /// @notice BlockTime -> BlockNumber for a Staking Checkpoint\n mapping(uint256 => uint256) public checkpointBlockDetails;\n\n /// @notice Average Block Time - making it flexible\n uint256 public averageBlockTime;\n}\n" + }, + "contracts/governance/Timelock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./ErrorDecoder.sol\";\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\n/**\n * @title Sovryn Protocol Timelock contract, based on Compound system.\n *\n * @notice This contract lets Sovryn governance system set up its\n * own Time Lock instance to execute transactions proposed through the\n * GovernorAlpha contract instance.\n *\n * The Timelock contract allows its admin (Sovryn governance on\n * GovernorAlpha contract) to add arbitrary function calls to a\n * queue. This contract can only execute a function call if the\n * function call has been in the queue for at least 3 hours.\n *\n * Anytime the Timelock contract makes a function call, it must be the\n * case that the function call was first made public by having been publicly\n * added to the queue at least 3 hours prior.\n *\n * The intention is to provide GovernorAlpha contract the functionality to\n * queue proposal actions. This would mean that any changes made by Sovryn\n * governance of any contract would necessarily come with at least an\n * advanced warning. This makes the Sovryn system follow a “time-delayed,\n * opt-out” upgrade pattern (rather than an “instant, forced” upgrade pattern).\n *\n * Time-delaying admin actions gives users a chance to exit system if its\n * admins become malicious or compromised (or make a change that the users\n * do not like). Downside is that honest admins would be unable\n * to lock down functionality to protect users if a critical bug was found.\n *\n * Delayed transactions reduce the amount of trust required by users of Sovryn\n * and the overall risk for contracts building on top of it, as GovernorAlpha.\n * */\ncontract Timelock is ErrorDecoder, ITimelock {\n using SafeMath for uint256;\n\n uint256 public constant GRACE_PERIOD = 14 days;\n uint256 public constant MINIMUM_DELAY = 3 hours;\n uint256 public constant MAXIMUM_DELAY = 30 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /**\n * @notice Function called on instance deployment of the contract.\n * @param admin_ Governance contract address.\n * @param delay_ Time to wait for queued transactions to be executed.\n * */\n constructor(address admin_, uint256 delay_) public {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {}\n\n /**\n * @notice Set a new delay when executing the contract calls.\n * @param delay_ The amount of time to wait until execution.\n * */\n function setDelay(uint256 delay_) public {\n require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n require(delay_ >= MINIMUM_DELAY, \"Timelock::setDelay: Delay must exceed minimum delay.\");\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n /**\n * @notice Accept a new admin for the timelock.\n * */\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n /**\n * @notice Set a new pending admin for the timelock.\n * @param pendingAdmin_ The new pending admin address.\n * */\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n /**\n * @notice Queue a new transaction from the governance contract.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function queueTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public returns (bytes32) {\n require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n /**\n * @notice Cancel a transaction.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function cancelTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public {\n require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n /**\n * @notice Executes a previously queued transaction from the governance.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function executeTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public payable returns (bytes memory) {\n require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call.value(value)(callData);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"Timelock::executeTransaction: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"Timelock::executeTransaction: \", string(returnData)));\n }\n }\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n /**\n * @notice A function used to get the current Block Timestamp.\n * @dev Timestamp of the current block in seconds since the epoch.\n * It is a Unix time stamp. So, it has the complete information about\n * the date, hours, minutes, and seconds (in UTC) when the block was\n * created.\n * */\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" + }, + "contracts/governance/Vesting/DevelopmentFund.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Development Fund.\n * @author Franklin Richards\n * @notice You can use this contract for timed token release from Dev Fund.\n */\ncontract DevelopmentFund {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The current contract status.\n enum Status { Deployed, Active, Expired }\n Status public status;\n\n /// @notice The owner of the locked tokens (usually Governance).\n address public lockedTokenOwner;\n /// @notice The owner of the unlocked tokens (usually MultiSig).\n address public unlockedTokenOwner;\n /// @notice The emergency transfer wallet/contract.\n address public safeVault;\n /// @notice The new locked token owner waiting to be approved.\n address public newLockedTokenOwner;\n\n /// @notice The last token release timestamp or the time of contract creation.\n uint256 public lastReleaseTime;\n\n /// @notice The release duration array in seconds.\n uint256[] public releaseDuration;\n /// @notice The release token amount.\n uint256[] public releaseTokenAmount;\n\n /* Events */\n\n /// @notice Emitted when the contract is activated.\n event DevelopmentFundActivated();\n\n /// @notice Emitted when the contract is expired due to total token transfer.\n event DevelopmentFundExpired();\n\n /// @notice Emitted when a new locked owner is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current locked owner.\n event NewLockedOwnerAdded(address indexed _initiator, address indexed _newLockedOwner);\n\n /// @notice Emitted when a new locked owner is approved to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _oldLockedOwner The address of the previous locked owner.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current unlocked owner.\n event NewLockedOwnerApproved(\n address indexed _initiator,\n address indexed _oldLockedOwner,\n address indexed _newLockedOwner\n );\n\n /// @notice Emitted when a new unlocked owner is updated in the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newUnlockedOwner The address which is updated as the new unlocked owner.\n /// @dev Can only be initiated by the current locked owner.\n event UnlockedOwnerUpdated(address indexed _initiator, address indexed _newUnlockedOwner);\n\n /// @notice Emitted when a new token deposit is done.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new release schedule is created.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseCount The number of releases planned in the schedule.\n event TokenReleaseChanged(address indexed _initiator, uint256 _releaseCount);\n\n /// @notice Emitted when a unlocked owner transfers all the tokens to a safe vault.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token withdrawn.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done in an emergency situation only to a predetermined wallet by locked token owner.\n event LockedTokenTransferByUnlockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /// @notice Emitted when a unlocked owner withdraws the released tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token withdrawn.\n /// @param _releaseCount The total number of releases done based on duration.\n event UnlockedTokenWithdrawalByUnlockedOwner(\n address indexed _initiator,\n uint256 _amount,\n uint256 _releaseCount\n );\n\n /// @notice Emitted when a locked owner transfers all the tokens to a receiver.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token transfer.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done only by locked token owner.\n event LockedTokenTransferByLockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /* Modifiers */\n\n modifier onlyLockedTokenOwner() {\n require(msg.sender == lockedTokenOwner, \"Only Locked Token Owner can call this.\");\n _;\n }\n\n modifier onlyUnlockedTokenOwner() {\n require(msg.sender == unlockedTokenOwner, \"Only Unlocked Token Owner can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _lockedTokenOwner The owner of the locked tokens & contract.\n * @param _safeVault The emergency wallet/contract to transfer token.\n * @param _unlockedTokenOwner The owner of the unlocked tokens.\n * @param _lastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev Initial release schedule should be verified, error will result in either redeployment or calling changeTokenReleaseSchedule() after init() along with token transfer.\n */\n constructor(\n address _SOV,\n address _lockedTokenOwner,\n address _safeVault,\n address _unlockedTokenOwner,\n uint256 _lastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_lockedTokenOwner != address(0), \"Locked token & contract owner address invalid.\");\n require(_safeVault != address(0), \"Safe Vault address invalid.\");\n require(_unlockedTokenOwner != address(0), \"Unlocked token address invalid.\");\n\n SOV = IERC20(_SOV);\n lockedTokenOwner = _lockedTokenOwner;\n safeVault = _safeVault;\n unlockedTokenOwner = _unlockedTokenOwner;\n\n lastReleaseTime = _lastReleaseTime;\n /// If last release time passed is zero, then current time stamp will be used as the last release time.\n if (_lastReleaseTime == 0) {\n lastReleaseTime = block.timestamp;\n }\n\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n }\n\n /**\n * @notice This function is called once after deployment for token transfer based on schedule.\n * @dev Without calling this function, the contract will not work.\n */\n function init() public checkStatus(Status.Deployed) {\n uint256[] memory _releaseTokenAmount = releaseTokenAmount;\n require(_releaseTokenAmount.length != 0, \"Release Schedule not set.\");\n\n /// Getting the current release schedule total token amount.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _releaseTotalTokenAmount);\n require(txStatus, \"Not enough token sent to change release schedule.\");\n\n status = Status.Active;\n\n emit DevelopmentFundActivated();\n }\n\n /**\n * @notice Update Locked Token Owner.\n * @param _newLockedTokenOwner The owner of the locked tokens & contract.\n */\n function updateLockedTokenOwner(address _newLockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newLockedTokenOwner != address(0), \"New locked token owner address invalid.\");\n\n newLockedTokenOwner = _newLockedTokenOwner;\n\n emit NewLockedOwnerAdded(msg.sender, _newLockedTokenOwner);\n }\n\n /**\n * @notice Approve Locked Token Owner.\n * @dev This approval is an added security to avoid development fund takeover by a compromised locked token owner.\n */\n function approveLockedTokenOwner() public onlyUnlockedTokenOwner checkStatus(Status.Active) {\n require(newLockedTokenOwner != address(0), \"No new locked owner added.\");\n\n emit NewLockedOwnerApproved(msg.sender, lockedTokenOwner, newLockedTokenOwner);\n\n lockedTokenOwner = newLockedTokenOwner;\n\n newLockedTokenOwner = address(0);\n }\n\n /**\n * @notice Update Unlocked Token Owner.\n * @param _newUnlockedTokenOwner The new unlocked token owner.\n */\n function updateUnlockedTokenOwner(address _newUnlockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newUnlockedTokenOwner != address(0), \"New unlocked token owner address invalid.\");\n\n unlockedTokenOwner = _newUnlockedTokenOwner;\n\n emit UnlockedOwnerUpdated(msg.sender, _newUnlockedTokenOwner);\n }\n\n /**\n * @notice Deposit tokens to this contract.\n * @param _amount the amount of tokens deposited.\n * @dev These tokens can be withdrawn/transferred any time by the lockedTokenOwner.\n */\n function depositTokens(uint256 _amount) public checkStatus(Status.Active) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDeposit(msg.sender, _amount);\n }\n\n /**\n * @notice Change the Token release schedule. It creates a completely new schedule, and does not append on the previous one.\n * @param _newLastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev _releaseDuration and _releaseTokenAmount should be specified in reverse order of release.\n */\n function changeTokenReleaseSchedule(\n uint256 _newLastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public onlyLockedTokenOwner checkStatus(Status.Active) {\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// If the last release time has to be changed, then you can pass a new one here.\n /// Or else, the duration of release will be calculated based on this timestamp.\n /// Even a future timestamp can be mentioned here.\n if (_newLastReleaseTime != 0) {\n lastReleaseTime = _newLastReleaseTime;\n }\n\n /// Checking if the contract have enough token balance for the release.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n /// Getting the current token balance of the contract.\n uint256 remainingTokens = SOV.balanceOf(address(this));\n\n /// If the token balance is not sufficient, then we transfer the change to contract.\n if (remainingTokens < _releaseTotalTokenAmount) {\n bool txStatus =\n SOV.transferFrom(\n msg.sender,\n address(this),\n _releaseTotalTokenAmount.sub(remainingTokens)\n );\n require(txStatus, \"Not enough token sent to change release schedule.\");\n } else if (remainingTokens > _releaseTotalTokenAmount) {\n /// If there are more tokens than required, send the extra tokens back.\n bool txStatus =\n SOV.transfer(msg.sender, remainingTokens.sub(_releaseTotalTokenAmount));\n require(txStatus, \"Token not received by the Locked Owner.\");\n }\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n\n emit TokenReleaseChanged(msg.sender, _releaseDuration.length);\n }\n\n /**\n * @notice Transfers all of the remaining tokens in an emergency situation.\n * @dev This could be called when governance or development fund might be compromised.\n */\n function transferTokensByUnlockedTokenOwner()\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(safeVault, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByUnlockedOwner(msg.sender, safeVault, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /**\n * @notice Withdraws all unlocked/released token.\n * @param _amount The amount to be withdrawn.\n */\n function withdrawTokensByUnlockedTokenOwner(uint256 _amount)\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_amount > 0, \"Zero can't be withdrawn.\");\n\n uint256 count; /// To know how many elements to be removed from the release schedule.\n uint256 amount = _amount; /// To know the total amount to be transferred.\n uint256 newLastReleaseTimeMemory = lastReleaseTime; /// Better to use memory than storage.\n uint256 releaseLength = releaseDuration.length.sub(1); /// Also checks if there are any elements in the release schedule.\n\n /// Getting the amount of tokens, the number of releases and calculating the total duration.\n while (\n amount > 0 &&\n newLastReleaseTimeMemory.add(releaseDuration[releaseLength]) < block.timestamp\n ) {\n if (amount >= releaseTokenAmount[releaseLength]) {\n amount = amount.sub(releaseTokenAmount[releaseLength]);\n newLastReleaseTimeMemory = newLastReleaseTimeMemory.add(\n releaseDuration[releaseLength]\n );\n count++;\n } else {\n /// This will be the last case, if correct amount is passed.\n releaseTokenAmount[releaseLength] = releaseTokenAmount[releaseLength].sub(amount);\n amount = 0;\n }\n releaseLength--;\n }\n\n /// Checking to see if atleast a single schedule was reached or not.\n require(count > 0 || amount == 0, \"No release schedule reached.\");\n\n /// If locked token owner tries to send a higher amount that schedule\n uint256 value = _amount.sub(amount);\n\n /// Now clearing up the release schedule.\n releaseDuration.length -= count;\n releaseTokenAmount.length -= count;\n\n /// Updating the last release time.\n lastReleaseTime = newLastReleaseTimeMemory;\n\n /// Sending the amount to unlocked token owner.\n bool txStatus = SOV.transfer(msg.sender, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit UnlockedTokenWithdrawalByUnlockedOwner(msg.sender, value, count);\n }\n\n /**\n * @notice Transfers all of the remaining tokens by the owner maybe for an upgrade.\n * @dev This could be called when the current development fund has to be upgraded.\n * @param _receiver The address which receives this token transfer.\n */\n function transferTokensByLockedTokenOwner(address _receiver)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(_receiver, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByLockedOwner(msg.sender, _receiver, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token release duration.\n * @return _currentReleaseDuration The current release duration.\n */\n function getReleaseDuration() public view returns (uint256[] memory _releaseTokenDuration) {\n return releaseDuration;\n }\n\n /**\n * @notice Function to read the current token release amount.\n * @return _currentReleaseTokenAmount The current release token amount.\n */\n function getReleaseTokenAmount()\n public\n view\n returns (uint256[] memory _currentReleaseTokenAmount)\n {\n return releaseTokenAmount;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../IFeeSharingCollector.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../proxy/UpgradableProxy.sol\";\nimport \"../../../openzeppelin/Address.sol\";\n\n/**\n * @title Four Year Vesting Contract.\n *\n * @notice A four year vesting contract.\n *\n * @dev Vesting contract is upgradable,\n * Make sure the vesting owner is multisig otherwise it will be\n * catastrophic.\n * */\ncontract FourYearVesting is FourYearVestingStorage, UpgradableProxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharingCollector Fee sharing proxy address.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n address _feeSharingCollector,\n uint256 _extendDurationFor\n ) public {\n require(Address.isContract(_logic), \"_logic not a contract\");\n require(_SOV != address(0), \"SOV address invalid\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(Address.isContract(_stakingAddress), \"_stakingAddress not a contract\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(Address.isContract(_feeSharingCollector), \"_feeSharingCollector not a contract\");\n require((_extendDurationFor % FOUR_WEEKS) == 0, \"invalid duration\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n tokenOwner = _tokenOwner;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n maxInterval = 18 * FOUR_WEEKS;\n extendDurationFor = _extendDurationFor;\n }\n\n /**\n * @notice Set address of the implementation - vesting owner.\n * @dev Overriding setImplementation function of UpgradableProxy. The logic can only be\n * modified when both token owner and veting owner approve. Since\n * setImplementation can only be called by vesting owner, we also need to check\n * if the new logic is already approved by the token owner.\n * @param _implementation Address of the implementation. Must match with what is set by token owner.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n require(Address.isContract(_implementation), \"_implementation not a contract\");\n require(newImplementation == _implementation, \"address mismatch\");\n _setImplementation(_implementation);\n newImplementation = address(0);\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"./FourYearVesting.sol\";\nimport \"./IFourYearVestingFactory.sol\";\n\n/**\n * @title Four Year Vesting Factory: Contract to deploy four year vesting contracts.\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract FourYearVestingFactory is IFourYearVestingFactory, Ownable {\n /// @dev Added an event to keep track of the vesting contract created for a token owner\n event FourYearVestingCreated(address indexed tokenOwner, address indexed vestingAddress);\n\n /**\n * @notice Deploys four year vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwnerMultisig The address of an owner of vesting contract.\n * @dev _vestingOwnerMultisig should ALWAYS be multisig.\n * @param _fourYearVestingLogic The implementation contract.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * @return The four year vesting contract address.\n * */\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external onlyOwner returns (address) {\n address fourYearVesting =\n address(\n new FourYearVesting(\n _fourYearVestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _feeSharing,\n _extendDurationFor\n )\n );\n Ownable(fourYearVesting).transferOwnership(_vestingOwnerMultisig);\n emit FourYearVestingCreated(_tokenOwner, fourYearVesting);\n return fourYearVesting;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./IFourYearVesting.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Four Year Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by FourYearVestingFactory contract.\n * */\ncontract FourYearVestingLogic is IFourYearVesting, FourYearVestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n\n /* Events */\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n event TokenOwnerChanged(address indexed newOwner, address indexed oldOwner);\n\n /* Modifiers */\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Sets the max interval.\n * @param _interval Max interval for which tokens scheduled shall be staked.\n * */\n function setMaxInterval(uint256 _interval) external onlyOwner {\n require(_interval.mod(FOUR_WEEKS) == 0, \"invalid interval\");\n maxInterval = _interval;\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount)\n {\n (lastSchedule, remainingAmount) = _stakeTokens(msg.sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokensWithApproval(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) external onlyThisContract returns (uint256 lastSchedule, uint256 remainingAmount) {\n (lastSchedule, remainingAmount) = _stakeTokens(_sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) external onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n uint256 stakingEndDate = endDate;\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate.add(cliff); i <= stakingEndDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) external onlyTokenOwner {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external onlyTokenOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Change token owner - only vesting owner is allowed to change.\n * @dev Modifies token owner. This must be followed by approval\n * from token owner.\n * @param _newTokenOwner Address of new token owner.\n * */\n function changeTokenOwner(address _newTokenOwner) public onlyOwner {\n require(_newTokenOwner != address(0), \"invalid new token owner address\");\n require(_newTokenOwner != tokenOwner, \"same owner not allowed\");\n newTokenOwner = _newTokenOwner;\n }\n\n /**\n * @notice Approve token owner change - only token Owner.\n * @dev Token owner can only be modified\n * when both vesting owner and token owner have approved. This\n * function ascertains the approval of token owner.\n * */\n function approveOwnershipTransfer() public onlyTokenOwner {\n require(newTokenOwner != address(0), \"invalid address\");\n tokenOwner = newTokenOwner;\n newTokenOwner = address(0);\n emit TokenOwnerChanged(tokenOwner, msg.sender);\n }\n\n /**\n * @notice Set address of the implementation - only Token Owner.\n * @dev This function sets the new implementation address.\n * It must also be approved by the Vesting owner.\n * @param _newImplementation Address of the new implementation.\n * */\n function setImpl(address _newImplementation) public onlyTokenOwner {\n require(_newImplementation != address(0), \"invalid new implementation address\");\n newImplementation = _newImplementation;\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() external onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Extends stakes(unlocked till timeDuration) for four year vesting contracts.\n * @dev Tokens are vested for 4 years. Since the max staking\n * period is 3 years and the tokens are unlocked only after the first year(timeDuration) is\n * passed, hence, we usually extend the duration of staking for all unlocked tokens for the first\n * year by 3 years. In some cases, the timeDuration can differ.\n * */\n function extendStaking() external {\n uint256 timeDuration = startDate.add(extendDurationFor);\n uint256[] memory dates;\n uint96[] memory stakes;\n (dates, stakes) = staking.getStakes(address(this));\n\n for (uint256 i = 0; i < dates.length; i++) {\n if ((dates[i] < block.timestamp) && (dates[i] <= timeDuration) && (stakes[i] > 0)) {\n staking.extendStakingDuration(dates[i], dates[i].add(156 weeks));\n endDate = dates[i].add(156 weeks);\n } else {\n break;\n }\n }\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function _stakeTokens(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) internal returns (uint256 lastSchedule, uint256 remainingAmount) {\n // Creating a new staking schedule for the same vesting contract is disallowed unlike normal vesting\n require(\n (startDate == 0) ||\n (startDate > 0 && remainingStakeAmount > 0 && _restartStakeSchedule > 0),\n \"create new vesting address\"\n );\n uint256 restartDate;\n uint256 relativeAmount;\n // Calling the _stakeTokens function first time for the vesting contract\n // Runs for maxInterval only (consider maxInterval = 18 * 4 = 72 weeks)\n if (startDate == 0 && _restartStakeSchedule == 0) {\n startDate = staking.timestampToLockDate(block.timestamp); // Set only once\n durationLeft = duration; // We do not touch duration and cliff as they are used throughout\n cliffAdded = cliff; // Hence, durationLeft and cliffAdded is created\n }\n // Calling the _stakeTokens second/third time - we start from the end of previous interval\n // and the remaining amount(amount left after tokens are staked in the previous interval)\n if (_restartStakeSchedule > 0) {\n require(\n _restartStakeSchedule == lastStakingSchedule && _amount == remainingStakeAmount,\n \"invalid params\"\n );\n restartDate = _restartStakeSchedule;\n } else {\n restartDate = startDate;\n }\n // Runs only once when the _stakeTokens is called for the first time\n if (endDate == 0) {\n endDate = staking.timestampToLockDate(block.timestamp.add(duration));\n }\n uint256 addedMaxInterval = restartDate.add(maxInterval); // run for maxInterval\n if (addedMaxInterval < endDate) {\n // Runs for max interval\n lastStakingSchedule = addedMaxInterval;\n relativeAmount = (_amount.mul(maxInterval)).div(durationLeft); // (_amount * 18) / 39\n durationLeft = durationLeft.sub(maxInterval); // durationLeft - 18 periods(72 weeks)\n remainingStakeAmount = _amount.sub(relativeAmount); // Amount left to be staked in subsequent intervals\n } else {\n // Normal run\n lastStakingSchedule = endDate; // if staking intervals left < 18 periods(72 weeks)\n remainingStakeAmount = 0;\n durationLeft = 0;\n relativeAmount = _amount; // Stake all amount left\n }\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), relativeAmount);\n require(success, \"transfer failed\");\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), relativeAmount);\n\n staking.stakesBySchedule(\n relativeAmount,\n cliffAdded,\n duration.sub(durationLeft),\n FOUR_WEEKS,\n address(this),\n tokenOwner\n );\n if (durationLeft == 0) {\n // All tokens staked\n cliffAdded = 0;\n } else {\n cliffAdded = cliffAdded.add(maxInterval); // Add cliff to the end of previous maxInterval\n }\n\n emit TokensStaked(_sender, relativeAmount);\n return (lastStakingSchedule, remainingStakeAmount);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n /// @dev For four year vesting, withdrawal of stakes for the first year is not allowed. These\n /// stakes are extended for three years. In some cases the withdrawal may be allowed at a different\n /// time and hence we use extendDurationFor.\n for (uint256 i = startDate.add(extendDurationFor); i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number.sub(1));\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../Staking/interfaces/IStaking.sol\";\nimport \"../../IFeeSharingCollector.sol\";\n\n/**\n * @title Four Year Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for four year vesting.\n * It is parent of FourYearVestingLogic and FourYearVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract FourYearVestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n // Used lower case for cliff and duration to maintain consistency with normal vesting\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public constant cliff = 4 weeks;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public constant duration = 156 weeks;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n /// @notice Maximum interval to stake tokens at one go\n uint256 public maxInterval;\n\n /// @notice End of previous staking schedule.\n uint256 public lastStakingSchedule;\n\n /// @notice Amount of shares left to be staked.\n uint256 public remainingStakeAmount;\n\n /// @notice Durations left.\n uint256 public durationLeft;\n\n /// @notice Cliffs added.\n uint256 public cliffAdded;\n\n /// @notice Address of new token owner.\n address public newTokenOwner;\n\n /// @notice Address of new implementation.\n address public newImplementation;\n\n /// @notice Duration(from start) till the time unlocked tokens are extended(for 3 years)\n uint256 public extendDurationFor;\n\n /// @dev Please add new state variables below this line. Mark them internal and\n /// add a getter function while upgrading the contracts.\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IFourYearVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IFourYearVesting {\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount);\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingFactory contract to override empty\n * implemention of deployFourYearVesting function\n * and use an instance of FourYearVestingFactory.\n */\ninterface IFourYearVestingFactory {\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/GenericTokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\n\n/**\n * @title Token sender contract.\n *\n * @notice This contract includes functions to transfer tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract GenericTokenSender is AdminRole {\n /* Events */\n\n event TokensTransferred(address indexed token, address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer given amounts of tokens to the given addresses.\n * @param _token The address of the token.\n * @param _receivers The addresses of the receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferTokensUsingList(\n address _token,\n address[] calldata _receivers,\n uint256[] calldata _amounts\n ) external onlyAuthorized {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferTokens(_token, _receivers[i], _amounts[i]);\n }\n }\n\n function() external payable {}\n\n /**\n * @notice Transfer tokens to given address.\n * @param _token The address of the token.\n * @param _receiver The address of the token receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) external onlyAuthorized {\n _transferTokens(_token, _receiver, _amount);\n }\n\n function _transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n if (_token != address(0)) {\n require(IERC20(_token).transfer(_receiver, _amount), \"transfer failed\");\n } else {\n (bool success, ) = _receiver.call.value(_amount)(\"\");\n require(success, \"RBTC transfer failed\");\n }\n emit TokensTransferred(_token, _receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/ITeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for TeamVesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by Staking contract to cancel the team vesting\n * function having the vesting contract instance address.\n */\ninterface ITeamVesting {\n function startDate() external view returns (uint256);\n\n function cliff() external view returns (uint256);\n\n function endDate() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function tokenOwner() external view returns (address);\n\n function governanceWithdrawTokens(address receiver) external;\n}\n" + }, + "contracts/governance/Vesting/IVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IVesting {\n function duration() external returns (uint256);\n\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 amount) external;\n\n function tokenOwner() external view returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingFactory contract to override empty\n * implemention of deployVesting and deployTeamVesting functions\n * and on VestingRegistry contract to use an instance of VestingFactory.\n */\ninterface IVestingFactory {\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for upgradable Vesting Registry contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IVestingRegistry {\n function getVesting(address _tokenOwner) external view returns (address);\n\n function getTeamVesting(address _tokenOwner) external view returns (address);\n\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n function isVestingAddress(address _vestingAddress) external view returns (bool);\n\n function isTeamVesting(address _vestingAddress) external view returns (bool);\n}\n" + }, + "contracts/governance/Vesting/OrigingVestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./VestingRegistry.sol\";\n\n/**\n * @title Temp contract for checking address, creating and staking tokens.\n * @notice It casts an instance of vestingRegistry and by using createVesting\n * function it creates a vesting, gets it and stakes some tokens w/ this vesting.\n * */\ncontract OrigingVestingCreator is Ownable {\n VestingRegistry public vestingRegistry;\n\n mapping(address => bool) processedList;\n\n constructor(address _vestingRegistry) public {\n vestingRegistry = VestingRegistry(_vestingRegistry);\n }\n\n /**\n * @notice Create a vesting, get it and stake some tokens w/ this vesting.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount of tokens to be vested.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyOwner {\n require(_tokenOwner != address(0), \"Invalid address\");\n require(!processedList[_tokenOwner], \"Already processed\");\n\n processedList[_tokenOwner] = true;\n\n vestingRegistry.createVesting(_tokenOwner, _amount, _cliff, _duration);\n address vesting = vestingRegistry.getVesting(_tokenOwner);\n vestingRegistry.stakeTokens(vesting, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/OriginInvestorsClaim.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./VestingRegistry.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\n\n/**\n * @title Origin investors claim vested cSOV tokens.\n * @notice // TODO: fund this contract with a total amount of SOV needed to distribute.\n * */\ncontract OriginInvestorsClaim is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// VestingRegistry public constant vestingRegistry = VestingRegistry(0x80B036ae59B3e38B573837c01BB1DB95515b7E6B);\n\n uint256 public totalAmount;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant SOV_VESTING_CLIFF = 6 weeks;\n\n uint256 public kickoffTS;\n uint256 public vestingTerm;\n uint256 public investorsQty;\n bool public investorsListInitialized;\n VestingRegistry public vestingRegistry;\n IStaking public staking;\n IERC20 public SOVToken;\n\n /// @dev user => flag : Whether user has admin role.\n mapping(address => bool) public admins;\n\n /// @dev investor => Amount : Origin investors entitled to claim SOV.\n mapping(address => uint256) public investorsAmountsList;\n\n /* Events */\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n event InvestorsAmountsListAppended(uint256 qty, uint256 amount);\n event ClaimVested(address indexed investor, uint256 amount);\n event ClaimTransferred(address indexed investor, uint256 amount);\n event InvestorsAmountsListInitialized(uint256 qty, uint256 totalAmount);\n\n /* Modifiers */\n\n /// @dev Throws if called by any account other than the owner or admin.\n modifier onlyAuthorized() {\n require(\n isOwner() || admins[msg.sender],\n \"OriginInvestorsClaim::onlyAuthorized: should be authorized\"\n );\n _;\n }\n\n /// @dev Throws if called by any account not whitelisted.\n modifier onlyWhitelisted() {\n require(\n investorsAmountsList[msg.sender] != 0,\n \"OriginInvestorsClaim::onlyWhitelisted: not whitelisted or already claimed\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an initialized investors list.\n modifier notInitialized() {\n require(\n !investorsListInitialized,\n \"OriginInvestorsClaim::notInitialized: the investors list should not be set as initialized\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an uninitialized investors list.\n modifier initialized() {\n require(\n investorsListInitialized,\n \"OriginInvestorsClaim::initialized: the investors list has not been set yet\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires one parameter:\n * @param vestingRegistryAddress The vestingRegistry contract instance address.\n * */\n constructor(address vestingRegistryAddress) public {\n vestingRegistry = VestingRegistry(vestingRegistryAddress);\n staking = IStaking(vestingRegistry.staking());\n kickoffTS = staking.kickoffTS();\n SOVToken = IERC20(staking.SOVToken());\n vestingTerm = kickoffTS + SOV_VESTING_CLIFF;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice In case we have unclaimed tokens or in emergency case\n * this function transfers all SOV tokens to a given address.\n * @param toAddress The recipient address of all this contract tokens.\n * */\n function authorizedBalanceWithdraw(address toAddress) public onlyAuthorized {\n require(\n SOVToken.transfer(toAddress, SOVToken.balanceOf(address(this))),\n \"OriginInvestorsClaim::authorizedTransferBalance: transfer failed\"\n );\n }\n\n /**\n * @notice Should be called after the investors list setup completed.\n * This function checks whether the SOV token balance of the contract is\n * enough and sets status list to initialized.\n * */\n function setInvestorsAmountsListInitialized() public onlyAuthorized notInitialized {\n require(\n SOVToken.balanceOf(address(this)) >= totalAmount,\n \"OriginInvestorsClaim::setInvestorsAmountsList: the contract is not enough financed\"\n );\n\n investorsListInitialized = true;\n\n emit InvestorsAmountsListInitialized(investorsQty, totalAmount);\n }\n\n /**\n * @notice The contract should be approved or transferred necessary\n * amount of SOV prior to calling the function.\n * @param investors The list of investors addresses to add to the list.\n * Duplicates will be skipped.\n * @param claimAmounts The list of amounts for investors investors[i]\n * will receive claimAmounts[i] of SOV.\n * */\n function appendInvestorsAmountsList(\n address[] calldata investors,\n uint256[] calldata claimAmounts\n ) external onlyAuthorized notInitialized {\n uint256 subQty;\n uint256 sumAmount;\n require(\n investors.length == claimAmounts.length,\n \"OriginInvestorsClaim::appendInvestorsAmountsList: investors.length != claimAmounts.length\"\n );\n\n for (uint256 i = 0; i < investors.length; i++) {\n if (investorsAmountsList[investors[i]] == 0) {\n investorsAmountsList[investors[i]] = claimAmounts[i];\n sumAmount = sumAmount.add(claimAmounts[i]);\n } else {\n subQty = subQty.add(1);\n }\n }\n\n investorsQty = investorsQty.add(investors.length.sub(subQty));\n totalAmount = totalAmount.add(sumAmount);\n emit InvestorsAmountsListAppended(investors.length.sub(subQty), sumAmount);\n }\n\n /**\n * @notice Claim tokens from this contract.\n * If vestingTerm is not yet achieved a vesting is created.\n * Otherwise tokens are tranferred.\n * */\n function claim() external onlyWhitelisted initialized {\n if (now < vestingTerm) {\n createVesting();\n } else {\n transfer();\n }\n }\n\n /**\n * @notice Transfer tokens from this contract to a vestingRegistry contract.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to vesting contract.\n * */\n function createVesting() internal {\n uint256 cliff = vestingTerm.sub(now);\n uint256 duration = cliff;\n uint256 amount = investorsAmountsList[msg.sender];\n address vestingContractAddress;\n\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n vestingContractAddress == address(0),\n \"OriginInvestorsClaim::withdraw: the claimer has an active vesting contract\"\n );\n\n delete investorsAmountsList[msg.sender];\n\n vestingRegistry.createVesting(msg.sender, amount, cliff, duration);\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n SOVToken.transfer(address(vestingRegistry), amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n vestingRegistry.stakeTokens(vestingContractAddress, amount);\n\n emit ClaimVested(msg.sender, amount);\n }\n\n /**\n * @notice Transfer tokens from this contract to the sender.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to its account.\n * */\n function transfer() internal {\n uint256 amount = investorsAmountsList[msg.sender];\n\n delete investorsAmountsList[msg.sender];\n\n /**\n * @dev Withdraw only for those claiming after the cliff, i.e. without vesting contracts.\n * Those with vestingContracts should withdraw using Vesting.withdrawTokens\n * from Vesting (VestingLogic) contract.\n * */\n require(\n SOVToken.transfer(msg.sender, amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n\n emit ClaimTransferred(msg.sender, amount);\n }\n}\n" + }, + "contracts/governance/Vesting/TeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n//import \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../proxy/Proxy.sol\";\n\n/**\n * @title Team Vesting Contract.\n *\n * @notice A regular vesting contract, but the owner (governance) is able to\n * withdraw earlier without a slashing.\n *\n * @dev Vesting contracts shouldn't be upgradable,\n * use Proxy instead of UpgradableProxy.\n * */\ncontract TeamVesting is VestingStorage, Proxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollector\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_duration >= _cliff, \"duration must be bigger than or equal to the cliff\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n require(_duration <= staking.MAX_DURATION(), \"duration may not exceed the max duration\");\n tokenOwner = _tokenOwner;\n cliff = _cliff;\n duration = _duration;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n }\n}\n" + }, + "contracts/governance/Vesting/TokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title SOV Token sender contract.\n *\n * @notice This contract includes functions to transfer SOV tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract TokenSender is Ownable {\n /* Storage */\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @dev user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n constructor(address _SOV) public {\n require(_SOV != address(0), \"SOV address invalid\");\n\n SOV = _SOV;\n }\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Transfer given amounts of SOV to the given addresses.\n * @param _receivers The addresses of the SOV receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferSOVusingList(address[] memory _receivers, uint256[] memory _amounts)\n public\n onlyAuthorized\n {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferSOV(_receivers[i], _amounts[i]);\n }\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyAuthorized {\n _transferSOV(_receiver, _amount);\n }\n\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/Vesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./TeamVesting.sol\";\n\n/**\n * @title Vesting Contract.\n * @notice Team tokens and investor tokens are vested. Therefore, a smart\n * contract needs to be developed to enforce the vesting schedule.\n *\n * */\ncontract Vesting is TeamVesting {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollectorProxy\n )\n public\n TeamVesting(\n _logic,\n _SOV,\n _stakingAddress,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharingCollectorProxy\n )\n {}\n\n /**\n * @dev We need to add this implementation to prevent proxy call VestingLogic.governanceWithdrawTokens\n * @param receiver The receiver of the token withdrawal.\n * */\n function governanceWithdrawTokens(address receiver) public {\n revert(\"operation not supported\");\n }\n}\n" + }, + "contracts/governance/Vesting/VestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"./VestingRegistryLogic.sol\";\nimport \"./VestingLogic.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingCreator is AdminRole {\n using SafeMath for uint256;\n\n ///@notice Boolean to check both vesting creation and staking is completed for a record\n bool vestingCreated;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 2 weeks;\n\n ///@notice the SOV token contract\n IERC20 public SOV;\n\n ///@notice the vesting registry contract\n VestingRegistryLogic public vestingRegistryLogic;\n\n ///@notice Holds Vesting Data\n struct VestingData {\n uint256 amount;\n uint256 cliff;\n uint256 duration;\n bool governanceControl; ///@dev true - tokens can be withdrawn by governance\n address tokenOwner;\n uint256 vestingCreationType;\n }\n\n ///@notice list of vesting to be processed\n VestingData[] public vestingDataList;\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event TokensStaked(address indexed vesting, address indexed tokenOwner, uint256 amount);\n event VestingDataRemoved(address indexed caller, address indexed tokenOwner);\n event DataCleared(address indexed caller);\n\n constructor(address _SOV, address _vestingRegistryProxy) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_vestingRegistryProxy != address(0), \"Vesting registry address invalid\");\n\n SOV = IERC20(_SOV);\n vestingRegistryLogic = VestingRegistryLogic(_vestingRegistryProxy);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings to be processed to the list\n */\n function addVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _amounts,\n uint256[] calldata _cliffs,\n uint256[] calldata _durations,\n bool[] calldata _governanceControls,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n require(\n _tokenOwners.length == _amounts.length &&\n _tokenOwners.length == _cliffs.length &&\n _tokenOwners.length == _durations.length &&\n _tokenOwners.length == _governanceControls.length,\n \"arrays mismatch\"\n );\n\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(\n _durations[i] >= _cliffs[i],\n \"duration must be bigger than or equal to the cliff\"\n );\n require(_amounts[i] > 0, \"vesting amount cannot be 0\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_cliffs[i].mod(TWO_WEEKS) == 0, \"cliffs should have intervals of two weeks\");\n require(\n _durations[i].mod(TWO_WEEKS) == 0,\n \"durations should have intervals of two weeks\"\n );\n VestingData memory vestingData =\n VestingData({\n amount: _amounts[i],\n cliff: _cliffs[i],\n duration: _durations[i],\n governanceControl: _governanceControls[i],\n tokenOwner: _tokenOwners[i],\n vestingCreationType: _vestingCreationTypes[i]\n });\n vestingDataList.push(vestingData);\n }\n }\n\n /**\n * @notice Creates vesting contract and stakes tokens\n * @dev Vesting and Staking are merged for calls that fits the gas limit\n */\n function processNextVesting() external {\n processVestingCreation();\n processStaking();\n }\n\n /**\n * @notice Creates vesting contract without staking any tokens\n * @dev Separating the Vesting and Staking to tackle Block Gas Limit\n */\n function processVestingCreation() public {\n require(!vestingCreated, \"staking not done for the previous vesting\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n _createAndGetVesting(vestingData);\n vestingCreated = true;\n }\n }\n\n /**\n * @notice Staking vested tokens\n * @dev it can be the case when vesting creation and tokens staking can't be done in one transaction because of block gas limit\n */\n function processStaking() public {\n require(vestingCreated, \"cannot stake without vesting creation\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n address vestingAddress =\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n require(SOV.approve(address(vesting), vestingData.amount), \"Approve failed\");\n vesting.stakeTokens(vestingData.amount);\n emit TokensStaked(vestingAddress, vestingData.tokenOwner, vestingData.amount);\n address tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n vestingCreated = false;\n }\n\n /**\n * @notice removes next vesting data from the list\n * @dev we process inverted list\n * @dev we should be able to remove incorrect vesting data that can't be processed\n */\n function removeNextVesting() external onlyAuthorized {\n address tokenOwnerDetails;\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n\n /**\n * @notice removes all data about unprocessed vestings to be processed\n */\n function clearVestingDataList() public onlyAuthorized {\n delete vestingDataList;\n emit DataCleared(msg.sender);\n }\n\n /**\n * @notice returns address after vesting creation\n */\n function getVestingAddress() external view returns (address) {\n return\n _getVesting(\n vestingDataList[vestingDataList.length - 1].tokenOwner,\n vestingDataList[vestingDataList.length - 1].cliff,\n vestingDataList[vestingDataList.length - 1].duration,\n vestingDataList[vestingDataList.length - 1].governanceControl,\n vestingDataList[vestingDataList.length - 1].vestingCreationType\n );\n }\n\n /**\n * @notice returns period i.e. ((duration - cliff) / 4 WEEKS)\n * @dev will be used for deciding if vesting and staking needs to be processed\n * in a single transaction or separate transactions\n */\n function getVestingPeriod() external view returns (uint256) {\n uint256 duration = vestingDataList[vestingDataList.length - 1].duration;\n uint256 cliff = vestingDataList[vestingDataList.length - 1].cliff;\n uint256 fourWeeks = TWO_WEEKS.mul(2);\n uint256 period = duration.sub(cliff).div(fourWeeks);\n return period;\n }\n\n /**\n * @notice returns count of vestings to be processed\n */\n function getUnprocessedCount() external view returns (uint256) {\n return vestingDataList.length;\n }\n\n /**\n * @notice returns total amount of vestings to be processed\n */\n function getUnprocessedAmount() public view returns (uint256) {\n uint256 amount = 0;\n uint256 length = vestingDataList.length;\n for (uint256 i = 0; i < length; i++) {\n amount = amount.add(vestingDataList[i].amount);\n }\n return amount;\n }\n\n /**\n * @notice checks if contract balance is enough to process all vestings\n */\n function isEnoughBalance() public view returns (bool) {\n return SOV.balanceOf(address(this)) >= getUnprocessedAmount();\n }\n\n /**\n * @notice returns missed balance to process all vestings\n */\n function getMissingBalance() external view returns (uint256) {\n if (isEnoughBalance()) {\n return 0;\n }\n return getUnprocessedAmount() - SOV.balanceOf(address(this));\n }\n\n /**\n * @notice creates TeamVesting or Vesting contract\n * @dev new contract won't be created if account already has contract of the same type\n */\n function _createAndGetVesting(VestingData memory vestingData)\n internal\n returns (address vesting)\n {\n if (vestingData.governanceControl) {\n vestingRegistryLogic.createTeamVesting(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n } else {\n vestingRegistryLogic.createVestingAddr(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n }\n return\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n }\n\n /**\n * @notice returns an address of TeamVesting or Vesting contract (depends on a governance control)\n */\n function _getVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n bool _governanceControl,\n uint256 _vestingCreationType\n ) internal view returns (address vestingAddress) {\n if (_governanceControl) {\n vestingAddress = vestingRegistryLogic.getTeamVesting(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n } else {\n vestingAddress = vestingRegistryLogic.getVestingAddr(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n }\n }\n}\n" + }, + "contracts/governance/Vesting/VestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./Vesting.sol\";\nimport \"./TeamVesting.sol\";\nimport \"./IVestingFactory.sol\";\n\n/**\n * @title Vesting Factory: Contract to deploy vesting contracts\n * of two types: vesting (TokenHolder) and team vesting (Multisig).\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract VestingFactory is IVestingFactory, Ownable {\n address public vestingLogic;\n\n constructor(address _vestingLogic) public {\n require(_vestingLogic != address(0), \"invalid vesting logic address\");\n vestingLogic = _vestingLogic;\n }\n\n /**\n * @notice Deploys Vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner /// @dev owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new Vesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n\n /**\n * @notice Deploys Team Vesting contract.\n * @param _SOV The address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner //owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new TeamVesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by a VestingFactory contract.\n * */\ncontract VestingLogic is IVesting, VestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n /* Events */\n\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(\n address indexed caller,\n address receiver,\n uint256 startFrom,\n uint256 end\n );\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(uint256 _amount) public {\n _stakeTokens(msg.sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokensWithApproval(address _sender, uint256 _amount) public onlyThisContract {\n _stakeTokens(_sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * */\n function _stakeTokens(address _sender, uint256 _amount) internal {\n /// @dev Maybe better to allow staking unil the cliff was reached.\n if (startDate == 0) {\n startDate = staking.timestampToLockDate(block.timestamp);\n }\n endDate = staking.timestampToLockDate(block.timestamp + duration);\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), _amount);\n require(success);\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), _amount);\n\n staking.stakeBySchedule(_amount, cliff, duration, FOUR_WEEKS, address(this), tokenOwner);\n\n emit TokensStaked(_sender, _amount);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) public onlyOwners {\n uint256 startFrom = startDate + cliff;\n _withdrawTokens(receiver, startFrom, block.timestamp);\n }\n\n /**\n * @notice Withdraws unlocked tokens partially (based on the max withdraw iteration that has been set) from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n * @param maxWithdrawIterations max withdrawal iteration to work around block gas limit issue.\n * */\n function withdrawTokensStartingFrom(\n address receiver,\n uint256 startFrom,\n uint256 maxWithdrawIterations\n ) public onlyOwners {\n uint256 defaultStartFrom = startDate + cliff;\n\n startFrom = _timestampToLockDate(startFrom);\n startFrom = startFrom < defaultStartFrom ? defaultStartFrom : startFrom;\n\n // @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 maxWithdrawDate = (startFrom + (FOUR_WEEKS * (maxWithdrawIterations.sub(1))));\n uint256 endAt = endDate < maxWithdrawDate ? endDate : maxWithdrawDate;\n _withdrawTokens(receiver, startFrom, endAt);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param startFrom start withdrawal from date.\n * @param endAt end time for regular withdrawal\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(\n address receiver,\n uint256 startFrom,\n uint256 endAt\n ) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n if (staking.allUnlocked()) {\n end = endAt < endDate ? endAt : endDate;\n } else {\n end = endAt < block.timestamp ? endAt : block.timestamp;\n if (end > endDate) end = endDate;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startFrom; i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number - 1);\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver, startFrom, end);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) public onlyOwners {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() public onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = startDate + cliff;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / FOUR_WEEKS;\n lockDate = periodFromKickoff * FOUR_WEEKS + start;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Registry contract.\n *\n * @notice On January 25, 2020, Sovryn launched the Genesis Reservation system.\n * Sovryn community members who controlled a special NFT were granted access to\n * stake BTC or rBTC for cSOV tokens at a rate of 2500 satoshis per cSOV. Per\n * SIP-0003, up to 2,000,000 cSOV were made available in the Genesis event,\n * which will be redeemable on a 1:1 basis for cSOV, subject to approval by\n * existing SOV holders.\n *\n * On 15 Feb 2021 Sovryn is taking another step in its journey to decentralized\n * financial sovereignty with the vote on SIP 0005. This proposal will enable\n * participants of the Genesis Reservation system to redeem their reserved cSOV\n * tokens for SOV. They will also have the choice to redeem cSOV for rBTC if\n * they decide to exit the system.\n *\n * This contract deals with the vesting and redemption of cSOV tokens.\n * */\ncontract VestingRegistry is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The cSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract.\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVReImburse(address from, uint256 CSOVamount, uint256 reImburseAmount);\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing collector proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n //---ACL------------------------------------------------------------------\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * TODO: This ACL logic should be available on OpenZeppeling Ownable.sol\n * or on our own overriding sovrynOwnable. This same logic is repeated\n * on OriginInvestorsClaim.sol, TokenSender.sol and VestingRegistry2.sol\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice cSOV payout to sender with rBTC currency.\n * 1.- Check holder cSOV balance by adding up every cSOV token balance.\n * 2.- ReImburse rBTC if funds available.\n * 3.- And store holder address in processedList.\n */\n function reImburse() public isNotProcessed isNotBlacklisted {\n uint256 CSOVAmountWei = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n CSOVAmountWei = CSOVAmountWei.add(balance);\n }\n\n require(CSOVAmountWei > lockedAmount[msg.sender], \"holder has no CSOV\");\n CSOVAmountWei -= lockedAmount[msg.sender];\n processedList[msg.sender] = true;\n\n /**\n * @dev Found and fixed the SIP-0007 bug on VestingRegistry::reImburse formula.\n * More details at Documenting Code issues at point 11 in\n * https://docs.google.com/document/d/10idTD1K6JvoBmtPKGuJ2Ub_mMh6qTLLlTP693GQKMyU/\n * Previous buggy code: uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**10);\n * */\n uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**8);\n require(address(this).balance >= reImburseAmount, \"Not enough funds to reimburse\");\n msg.sender.transfer(reImburseAmount);\n\n emit CSOVReImburse(msg.sender, CSOVAmountWei, reImburseAmount);\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Exchange cSOV to SOV with 1:1 rate\n */\n function exchangeAllCSOV() public isNotProcessed isNotBlacklisted {\n processedList[msg.sender] = true;\n\n uint256 amount = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n amount += balance;\n }\n\n require(amount > lockedAmount[msg.sender], \"amount invalid\");\n amount -= lockedAmount[msg.sender];\n\n _createVestingForCSOV(amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param _vesting The address of Vesting contract.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n /// @dev TODO: Owner of OwnerVesting contracts - the same address as tokenOwner.\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry2.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title VestingRegistry 2 contract.\n * @notice One time contract needed to distribute tokens to origin sales investors.\n * */\ncontract VestingRegistry2 is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The CSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry3.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingRegistry3 is Ownable {\n using SafeMath for uint256;\n\n IVestingFactory public vestingFactory;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n //@notice fee sharing proxy\n address public feeSharingCollector;\n //@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n //TODO add to the documentation: address can have only one vesting of each type\n //user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n //user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n constructor(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"./VestingRegistryStorage.sol\";\n\ncontract VestingRegistryLogic is VestingRegistryStorage {\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event VestingCreationAndTypesSet(\n address indexed vesting,\n VestingCreationAndTypeDetails vestingCreationAndType\n );\n\n /**\n * @notice Replace constructor with initialize function for Upgradable Contracts\n * This function will be called only once by the owner\n * */\n function initialize(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner,\n address _lockedSOV,\n address[] calldata _vestingRegistries\n ) external onlyOwner initializer {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n require(_lockedSOV != address(0), \"LockedSOV address invalid\");\n\n _setVestingFactory(_vestingFactory);\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n lockedSOV = LockedSOV(_lockedSOV);\n for (uint256 i = 0; i < _vestingRegistries.length; i++) {\n require(_vestingRegistries[i] != address(0), \"Vesting registry address invalid\");\n vestingRegistries.push(IVestingRegistry(_vestingRegistries[i]));\n }\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) external onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Internal function that sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings that were deployed in previous vesting registries\n * @dev migration of data from previous vesting registy contracts\n */\n function addDeployedVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingCreationTypes[i] > 0, \"vesting creation type must be greater than 0\");\n _addDeployedVestings(_tokenOwners[i], _vestingCreationTypes[i]);\n }\n }\n\n /**\n * @notice adds four year vestings to vesting registry logic\n * @param _tokenOwners array of token owners\n * @param _vestingAddresses array of vesting addresses\n */\n function addFourYearVestings(\n address[] calldata _tokenOwners,\n address[] calldata _vestingAddresses\n ) external onlyAuthorized {\n require(_tokenOwners.length == _vestingAddresses.length, \"arrays mismatch\");\n uint256 vestingCreationType = 4;\n uint256 cliff = 4 weeks;\n uint256 duration = 156 weeks;\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(!isVesting[_vestingAddresses[i]], \"vesting exists\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingAddresses[i] != address(0), \"vesting cannot be 0 address\");\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwners[i],\n uint256(VestingType.Vesting),\n cliff,\n duration,\n vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n vestingCreationType,\n _vestingAddresses[i]\n );\n vestingsOf[_tokenOwners[i]].push(uid);\n isVesting[_vestingAddresses[i]] = true;\n }\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @dev Calls a public createVestingAddr function with vestingCreationType. This is to accomodate the existing logic for LockedSOV\n * @dev vestingCreationType 0 = LockedSOV\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAuthorized {\n createVestingAddr(_tokenOwner, _amount, _cliff, _duration, 3);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createVestingAddr(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.Vesting),\n _vestingCreationType\n );\n\n emit VestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) external onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.TeamVesting),\n _vestingCreationType\n );\n\n emit TeamVestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) external onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n * @dev Calls a public getVestingAddr function with cliff and duration. This is to accomodate the existing logic for LockedSOV\n * @dev We need to use LockedSOV.changeRegistryCliffAndDuration function very judiciously\n * @dev vestingCreationType 0 - LockedSOV\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return getVestingAddr(_tokenOwner, lockedSOV.cliff(), lockedSOV.duration(), 3);\n }\n\n /**\n * @notice public function that returns vesting contract address for the given token owner, cliff, duration\n * @dev Important: Please use this instead of getVesting function\n */\n function getVestingAddr(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner, cliff, duration\n */\n function getTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @dev check if the specific vesting address is team vesting or not\n * @dev read the vestingType from vestingCreationAndTypes storage\n *\n * @param _vestingAddress address of vesting contract\n *\n * @return true for teamVesting, false for normal vesting\n */\n function isTeamVesting(address _vestingAddress) external view returns (bool) {\n return (vestingCreationAndTypes[_vestingAddress].isSet &&\n vestingCreationAndTypes[_vestingAddress].vestingType ==\n uint32(VestingType.TeamVesting));\n }\n\n /**\n * @dev setter function to register existing vesting contract to vestingCreationAndTypes storage\n * @dev need to set the function visilibty to public to support VestingCreationAndTypeDetails struct as parameter\n *\n * @param _vestingAddresses array of vesting address\n * @param _vestingCreationAndTypes array for VestingCreationAndTypeDetails struct\n */\n function registerVestingToVestingCreationAndTypes(\n address[] memory _vestingAddresses,\n VestingCreationAndTypeDetails[] memory _vestingCreationAndTypes\n ) public onlyAuthorized {\n require(_vestingAddresses.length == _vestingCreationAndTypes.length, \"Unmatched length\");\n for (uint256 i = 0; i < _vestingCreationAndTypes.length; i++) {\n VestingCreationAndTypeDetails memory _vestingCreationAndType =\n _vestingCreationAndTypes[i];\n address _vestingAddress = _vestingAddresses[i];\n\n vestingCreationAndTypes[_vestingAddress] = _vestingCreationAndType;\n\n emit VestingCreationAndTypesSet(\n _vestingAddress,\n vestingCreationAndTypes[_vestingAddress]\n );\n }\n }\n\n /**\n * @notice Internal function to deploy Vesting/Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _type the type of vesting\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _type,\n uint256 _vestingCreationType\n ) internal returns (address) {\n address vesting;\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, _type, _cliff, _duration, _vestingCreationType)\n )\n );\n if (vestings[uid].vestingAddress == address(0)) {\n if (_type == 1) {\n vesting = vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n } else {\n vesting = vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n }\n vestings[uid] = Vesting(_type, _vestingCreationType, vesting);\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vesting] = true;\n\n vestingCreationAndTypes[vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(_type),\n vestingCreationType: uint128(_vestingCreationType)\n });\n\n emit VestingCreationAndTypesSet(vesting, vestingCreationAndTypes[vesting]);\n }\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice stores the addresses of Vesting contracts from all three previous versions of Vesting Registry\n */\n function _addDeployedVestings(address _tokenOwner, uint256 _vestingCreationType) internal {\n uint256 uid;\n uint256 i = _vestingCreationType - 1;\n\n address vestingAddress = vestingRegistries[i].getVesting(_tokenOwner);\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.Vesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n _vestingCreationType,\n vestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vestingAddress] = true;\n }\n\n address teamVestingAddress = vestingRegistries[i].getTeamVesting(_tokenOwner);\n if (teamVestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(teamVestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.TeamVesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.TeamVesting),\n _vestingCreationType,\n teamVestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[teamVestingAddress] = true;\n }\n }\n\n /**\n * @notice returns all vesting details for the given token owner\n */\n function getVestingsOf(address _tokenOwner) external view returns (Vesting[] memory) {\n uint256[] memory vestingIds = vestingsOf[_tokenOwner];\n uint256 length = vestingIds.length;\n Vesting[] memory _vestings = new Vesting[](vestingIds.length);\n for (uint256 i = 0; i < length; i++) {\n _vestings[i] = vestings[vestingIds[i]];\n }\n return _vestings;\n }\n\n /**\n * @notice returns cliff and duration for Vesting & TeamVesting contracts\n */\n function getVestingDetails(address _vestingAddress)\n external\n view\n returns (uint256 cliff, uint256 duration)\n {\n VestingLogic vesting = VestingLogic(_vestingAddress);\n return (vesting.cliff(), vesting.duration());\n }\n\n /**\n * @notice returns if the address is a vesting address\n */\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return isVesting[_vestingAddress];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./VestingRegistryStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Vesting Registry Proxy contract.\n * @dev Vesting Registry contract should be upgradable, use UpgradableProxy.\n * VestingRegistryStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract VestingRegistryProxy is VestingRegistryStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Initializable.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"../../locked/LockedSOV.sol\";\nimport \"./IVestingRegistry.sol\";\n\n/**\n * @title Vesting Registry Storage Contract.\n *\n * @notice This contract is just the storage required for vesting registry.\n * It is parent of VestingRegistryProxy and VestingRegistryLogic.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\n\ncontract VestingRegistryStorage is Initializable, AdminRole {\n ///@notice the vesting factory contract\n IVestingFactory public vestingFactory;\n\n ///@notice the Locked SOV contract\n ///@dev NOTES: No need to update lockedSOV in this contract, since it might break the vestingRegistry if the new lockedSOV does not have the same value of cliff & duration.\n ILockedSOV public lockedSOV;\n\n ///@notice the list of vesting registries\n IVestingRegistry[] public vestingRegistries;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n\n ///@notice fee sharing proxy\n address public feeSharingCollector;\n\n ///@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n ///@notice Vesting details\n struct Vesting {\n uint256 vestingType;\n uint256 vestingCreationType;\n address vestingAddress;\n }\n\n ///@notice A record of vesting details for a unique id\n ///@dev vestings[uid] returns vesting data\n mapping(uint256 => Vesting) public vestings;\n\n ///@notice A record of all unique ids for a particular token owner\n ///@dev vestingsOf[tokenOwner] returns array of unique ids\n mapping(address => uint256[]) public vestingsOf;\n\n ///@notice A record of all vesting addresses\n ///@dev isVesting[address] returns if the address is a vesting address\n mapping(address => bool) public isVesting;\n\n /// @notice Store vesting creation type & vesting type information\n /// @dev it is packed into 1 single storage slot for cheaper gas usage\n struct VestingCreationAndTypeDetails {\n bool isSet;\n uint32 vestingType;\n uint128 vestingCreationType;\n }\n\n ///@notice A record of all vesting addresses with the detail\n ///@dev vestingDetail[vestingAddress] returns Vesting struct data\n ///@dev can be used to easily check the vesting type / creation type based on the vesting address itself\n mapping(address => VestingCreationAndTypeDetails) public vestingCreationAndTypes;\n}\n" + }, + "contracts/governance/Vesting/VestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\n\n/**\n * @title Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for vesting.\n * It is parent of VestingLogic and TeamVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract VestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public cliff;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 constant FOUR_WEEKS = 4 weeks;\n}\n" + }, + "contracts/interfaces/IChai.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IERC20.sol\";\n\ninterface IPot {\n function dsr() external view returns (uint256);\n\n function chi() external view returns (uint256);\n\n function rho() external view returns (uint256);\n}\n\ncontract IChai is IERC20 {\n function move(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function join(address dst, uint256 wad) external;\n\n function draw(address src, uint256 wad) external;\n\n function exit(address src, uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IConverterAMM.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IConverterAMM {\n function withdrawFees(address receiver) external returns (uint256);\n}\n" + }, + "contracts/interfaces/IERC20.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ncontract IERC20 {\n string public name;\n uint8 public decimals;\n string public symbol;\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address _who) external view returns (uint256);\n\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/interfaces/IERC777.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777Token standard as defined in the EIP.\n *\n * This contract uses the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let\n * token holders and recipients react to token movements by using setting implementers\n * for the associated interfaces in said registry. See {IERC1820Registry} and\n * {ERC1820Implementer}.\n */\ninterface IERC777 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the smallest part of the token that is not divisible. This\n * means all token operations (creation, movement and destruction) must have\n * amounts that are a multiple of this number.\n *\n * For most token contracts, this value will equal 1.\n */\n function granularity() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by an account (`owner`).\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * If send or receive hooks are registered for the caller and `recipient`,\n * the corresponding functions will be called with `data` and empty\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes calldata data\n ) external;\n\n /**\n * @dev Destroys `amount` tokens from the caller's account, reducing the\n * total supply.\n *\n * If a send hook is registered for the caller, the corresponding function\n * will be called with `data` and empty `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n */\n function burn(uint256 amount, bytes calldata data) external;\n\n /**\n * @dev Returns true if an account is an operator of `tokenHolder`.\n * Operators can send and burn tokens on behalf of their owners. All\n * accounts are their own operator.\n *\n * See {operatorSend} and {operatorBurn}.\n */\n function isOperatorFor(address operator, address tokenHolder) external view returns (bool);\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor}.\n *\n * Emits an {AuthorizedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function authorizeOperator(address operator) external;\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor} and {defaultOperators}.\n *\n * Emits a {RevokedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function revokeOperator(address operator) external;\n\n /**\n * @dev Returns the list of default operators. These accounts are operators\n * for all token holders, even if {authorizeOperator} was never called on\n * them.\n *\n * This list is immutable, but individual holders may revoke these via\n * {revokeOperator}, in which case {isOperatorFor} will return false.\n */\n function defaultOperators() external view returns (address[] memory);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must\n * be an operator of `sender`.\n *\n * If send or receive hooks are registered for `sender` and `recipient`,\n * the corresponding functions will be called with `data` and\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - `sender` cannot be the zero address.\n * - `sender` must have at least `amount` tokens.\n * - the caller must be an operator for `sender`.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n /**\n * @dev Destoys `amount` tokens from `account`, reducing the total supply.\n * The caller must be an operator of `account`.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `data` and `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n * - the caller must be an operator for `account`.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n event Sent(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Minted(\n address indexed operator,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Burned(\n address indexed operator,\n address indexed from,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event AuthorizedOperator(address indexed operator, address indexed tokenHolder);\n\n event RevokedOperator(address indexed operator, address indexed tokenHolder);\n}\n" + }, + "contracts/interfaces/IERC777Recipient.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.\n *\n * Accounts can be notified of {IERC777} tokens being sent to them by having a\n * contract implement this interface (contract holders can be their own\n * implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Recipient {\n /**\n * @dev Called by an {IERC777} token contract whenever tokens are being\n * moved or created into a registered account (`to`). The type of operation\n * is conveyed by `from` being the zero address or not.\n *\n * This call occurs _after_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the post-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/IERC777Sender.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensSender standard as defined in the EIP.\n *\n * {IERC777} Token holders can be notified of operations performed on their\n * tokens by having a contract implement this interface (contract holders can be\n * their own implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Sender {\n /**\n * @dev Called by an {IERC777} token contract whenever a registered holder's\n * (`from`) tokens are about to be moved or destroyed. The type of operation\n * is conveyed by `to` being the zero address or not.\n *\n * This call occurs _before_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the pre-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/ILoanPool.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface ILoanPool {\n function tokenPrice() external view returns (uint256 price);\n\n function borrowInterestRate() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/ILoanTokenModules.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\ninterface ILoanTokenModules {\n /** EVENT */\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /// topic: 0x9bbd2de400810774339120e2f8a2b517ed748595e944529bba8ebabf314d0591\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n\n /** INTERFACE */\n\n /** START LOAN TOKEN SETTINGS LOWER ADMIN */\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n\n function setAdmin(address _admin) external;\n\n function setPauser(address _pauser) external;\n\n function setupLoanParams(LoanParams[] calldata loanParamsList, bool areTorqueLoans) external;\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external;\n\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) external;\n\n function toggleFunctionPause(\n string calldata funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) external;\n\n function setTransactionLimits(address[] calldata addresses, uint256[] calldata limits)\n external;\n\n function changeLoanTokenNameAndSymbol(string calldata _name, string calldata _symbol) external;\n\n /** END LOAN TOKEN SETTINGS LOWER ADMIN */\n\n /** START LOAN TOKEN LOGIC STANDARD */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n address affiliateReferrer, // The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes // Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function borrowInterestRate() external view returns (uint256);\n\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n\n function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid);\n\n function checkPause(string calldata funcId) external view returns (bool isPaused);\n\n function nextBorrowInterestRate(uint256 borrowAmount) external view returns (uint256);\n\n function totalAssetBorrow() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes calldata /// loanDataBytes: arbitrary order data (for future use).\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n );\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function setLiquidityMiningAddress(address LMAddress) external;\n\n function getLiquidityMiningAddress() external view returns (address);\n\n function setStakingContractAddress(address _stakingContractAddress) external;\n\n function getStakingContractAddress() external view returns (address);\n\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n external\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n );\n\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 depositAmount);\n\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 borrowAmount);\n\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) external view;\n\n function getMaxEscrowAmount(uint256 leverageAmount)\n external\n view\n returns (uint256 maxEscrowAmount);\n\n function checkpointPrice(address _user) external view returns (uint256 price);\n\n function assetBalanceOf(address _owner) external view returns (uint256);\n\n function profitOf(address user) external view returns (int256);\n\n function tokenPrice() external view returns (uint256 price);\n\n function avgBorrowInterestRate() external view returns (uint256);\n\n function supplyInterestRate() external view returns (uint256);\n\n function nextSupplyInterestRate(uint256 supplyAmount) external view returns (uint256);\n\n function totalSupplyInterestRate(uint256 assetSupply) external view returns (uint256);\n\n function loanTokenAddress() external view returns (address);\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n external\n view\n returns (uint256, uint256);\n\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external;\n\n /** START LOAN TOKEN BASE */\n function initialPrice() external view returns (uint256);\n\n /** START LOAN TOKEN LOGIC LM */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external returns (uint256 minted);\n\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 redeemed);\n\n /** START LOAN TOKEN LOGIC WRBTC */\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n returns (uint256 mintAmount);\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function marketLiquidity() external view returns (uint256);\n\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n external\n view\n returns (uint256);\n\n /** START LOAN TOKEN LOGIC STORAGE */\n function pauser() external view returns (address);\n\n function liquidityMiningAddress() external view returns (address);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n /** START ADVANCED TOKEN */\n function approve(address _spender, uint256 _value) external returns (bool);\n\n /** START ADVANCED TOKEN STORAGE */\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function balanceOf(address _owner) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function loanParamsIds(uint256) external view returns (bytes32);\n}\n" + }, + "contracts/interfaces/ISovryn.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\npragma experimental ABIEncoderV2;\n//TODO: stored in ./interfaces only while brownie isn't removed\n//TODO: move to contracts/interfaces after with brownie is removed\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\ncontract ISovryn is\n State,\n ProtocolSettingsEvents,\n LoanSettingsEvents,\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n LoanClosingsEvents,\n SwapsEvents,\n AffiliatesEvents,\n FeesEvents\n{\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n ////// Protocol //////\n\n function replaceContract(address target) external;\n\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\n\n function getTarget(string calldata sig) external view returns (address);\n\n ////// Protocol Settings //////\n\n function setSovrynProtocolAddress(address newProtocolAddress) external;\n\n function setSOVTokenAddress(address newSovTokenAddress) external;\n\n function setLockedSOVAddress(address newSOVLockedAddress) external;\n\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\n\n function setPriceFeedContract(address newContract) external;\n\n function setSwapsImplContract(address newContract) external;\n\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\n\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\n\n function setLendingFeePercent(uint256 newValue) external;\n\n function setTradingFeePercent(uint256 newValue) external;\n\n function setBorrowingFeePercent(uint256 newValue) external;\n\n function setSwapExternalFeePercent(uint256 newValue) external;\n\n function setAffiliateFeePercent(uint256 newValue) external;\n\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\n\n function setLiquidationIncentivePercent(uint256 newAmount) external;\n\n function setMaxDisagreement(uint256 newAmount) external;\n\n function setSourceBuffer(uint256 newAmount) external;\n\n function setMaxSwapSize(uint256 newAmount) external;\n\n function setFeesController(address newController) external;\n\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n returns (address, bool);\n\n function depositProtocolToken(uint256 amount) external;\n\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function setWrbtcToken(address wrbtcTokenAddress) external;\n\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\n\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\n\n function setRolloverBaseReward(uint256 transactionCost) external;\n\n function setRebatePercent(uint256 rebatePercent) external;\n\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external;\n\n function getSpecialRebates(address sourceToken, address destToken)\n external\n view\n returns (uint256 specialRebatesPercent);\n\n function togglePaused(bool paused) external;\n\n function isProtocolPaused() external view returns (bool);\n\n ////// SwapsImplSovrynSwapModule //////\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (address);\n\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\n\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn);\n\n ////// Loan Settings //////\n\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function getLoanParams(bytes32[] calldata loanParamsIdList)\n external\n view\n returns (LoanParams[] memory loanParamsList);\n\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n\n ////// Loan Openings //////\n\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external;\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n ////// Loan Closings //////\n\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n );\n\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata loanDataBytes\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n ////// Loan Maintenance //////\n\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount // must match msg.value if ether is sent\n ) external payable;\n\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 actualWithdrawAmount);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n );\n\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; // collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\n\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\n\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external returns (uint256 secondsExtended);\n\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 secondsReduced);\n\n ////// Swaps External //////\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view;\n\n ////// Affiliates Module //////\n\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\n\n function setUserNotFirstTradeFlag(address user) external;\n\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\n\n function getReferralsList(address referrer) external view returns (address[] memory refList);\n\n function getAffiliatesReferrerBalances(address referrer)\n external\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\n\n function getAffiliatesReferrerTokensList(address referrer)\n external\n view\n returns (address[] memory tokensList);\n\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n external\n view\n returns (uint256);\n\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) external;\n\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\n\n function getProtocolAddress() external view returns (address);\n\n function getSovTokenAddress() external view returns (address);\n\n function getLockedSOVAddress() external view returns (address);\n\n function getFeeRebatePercent() external view returns (uint256);\n\n function getMinReferralsToPayout() external view returns (uint256);\n\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\n\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\n\n function getAffiliateTradingTokenFeePercent()\n external\n view\n returns (uint256 affiliateTradingTokenFeePercent);\n\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount);\n\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\n\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\n\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\n\n function getDedicatedSOVRebate() external view returns (uint256);\n\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\n\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory);\n\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\n\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external;\n\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\n\n function setAdmin(address newAdmin) external;\n\n function getAdmin() external view returns (address);\n\n function setPauser(address newPauser) external;\n\n function getPauser() external view returns (address);\n}\n" + }, + "contracts/interfaces/IWrbtc.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface IWrbtc {\n function deposit() external payable;\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IWrbtcERC20.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IWrbtc.sol\";\nimport \"./IERC20.sol\";\n\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\n" + }, + "contracts/locked/ILockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title The Locked SOV Interface.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This interface is an incomplete yet useful for future migration of LockedSOV Contract.\n * @dev Only use it if you know what you are doing.\n */\ninterface ILockedSOV {\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external;\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external;\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external;\n\n function cliff() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function getLockedBalance(address _addr) external view returns (uint256 _balance);\n\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance);\n}\n" + }, + "contracts/locked/LockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../governance/Vesting/VestingRegistry.sol\";\nimport \"../governance/Vesting/VestingLogic.sol\";\nimport \"./ILockedSOV.sol\";\n\n/**\n * @title The Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This contract is used to receive reward from other contracts, Create Vesting and Stake Tokens.\n */\ncontract LockedSOV is ILockedSOV {\n using SafeMath for uint256;\n\n uint256 public constant MAX_BASIS_POINT = 10000;\n uint256 public constant MAX_DURATION = 37;\n\n /* Storage */\n\n /// @notice True if the migration to a new Locked SOV Contract has started.\n bool public migration;\n\n /// @notice The cliff is the time period after which the tokens begin to unlock.\n uint256 public cliff;\n /// @notice The duration is the time period after all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n /// @notice The Vesting registry contract.\n VestingRegistry public vestingRegistry;\n /// @notice The New (Future) Locked SOV.\n ILockedSOV public newLockedSOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) private lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) private unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) private isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /// @notice Emitted when Vesting Registry, Duration and/or Cliff is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vestingRegistry The Vesting Registry Contract.\n /// @param _cliff The time period after which the tokens begin to unlock.\n /// @param _duration The time period after all tokens will have been unlocked.\n event RegistryCliffAndDurationUpdated(\n address indexed _initiator,\n address indexed _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n );\n\n /// @notice Emitted when a new deposit is made.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user to whose un/locked balance a new deposit was made.\n /// @param _sovAmount The amount of SOV to be added to the un/locked balance.\n /// @param _basisPoint The % (in Basis Point) which determines how much will be unlocked immediately.\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n /// @notice Emitted when a user withdraws the fund.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _sovAmount The amount of SOV withdrawn from the unlocked balance.\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n /// @notice Emitted when a user creates a vesting for himself.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _vesting The Vesting Contract.\n event VestingCreated(\n address indexed _initiator,\n address indexed _userAddress,\n address indexed _vesting\n );\n\n /// @notice Emitted when a user stakes tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vesting The Vesting Contract.\n /// @param _amount The amount of locked tokens staked by the user.\n event TokenStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /// @notice Emitted when an admin initiates a migration to new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedSOV The address of the new Locked SOV Contract.\n event MigrationStarted(address indexed _initiator, address indexed _newLockedSOV);\n\n /// @notice Emitted when a user initiates the transfer to a new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of locked tokens to transfer from this contract to the new one.\n event UserTransfered(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n modifier migrationAllowed {\n require(migration, \"Migration has not yet started.\");\n _;\n }\n\n /* Constructor */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV Token Address.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @param _admins The list of Admins to be added.\n */\n constructor(\n address _SOV,\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration,\n address[] memory _admins\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_vestingRegistry != address(0), \"Vesting registry address is invalid.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n SOV = IERC20(_SOV);\n vestingRegistry = VestingRegistry(_vestingRegistry);\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /* Public or External Functions */\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n * @dev Only callable by an Admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address.\");\n require(!isAdmin[_newAdmin], \"Address is already admin.\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n * @dev Only callable by an Admin.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin.\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice The function to update the Vesting Registry, Duration and Cliff.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @dev IMPORTANT 1: You have to change Vesting Registry if you want to change Duration and/or Cliff.\n * IMPORTANT 2: `_cliff` and `_duration` is multiplied by 4 weeks in this function.\n */\n function changeRegistryCliffAndDuration(\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAdmin {\n require(\n address(vestingRegistry) != _vestingRegistry,\n \"Vesting Registry has to be different for changing duration and cliff.\"\n );\n /// If duration is also zero, then it is similar to Unlocked SOV.\n require(_duration != 0, \"Duration cannot be zero.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n vestingRegistry = VestingRegistry(_vestingRegistry);\n\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n emit RegistryCliffAndDurationUpdated(msg.sender, _vestingRegistry, _cliff, _duration);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // MAX_BASIS_POINT is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < MAX_BASIS_POINT, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(MAX_BASIS_POINT);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice A function to withdraw the unlocked balance.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdraw(address _receiverAddress) public {\n _withdraw(msg.sender, _receiverAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n /**\n * @notice Creates vesting if not already created and Stakes tokens for a user.\n * @dev Only use this function if the `duration` is small.\n */\n function createVestingAndStake() public {\n _createVestingAndStake(msg.sender);\n }\n\n function _createVestingAndStake(address _sender) private {\n address vestingAddr = _getVesting(_sender);\n\n if (vestingAddr == address(0)) {\n vestingAddr = _createVesting(_sender);\n }\n\n _stakeTokens(_sender, vestingAddr);\n }\n\n /**\n * @notice Creates vesting contract (if it hasn't been created yet) for the calling user.\n * @return _vestingAddress The New Vesting Contract Created.\n */\n function createVesting() public returns (address _vestingAddress) {\n _vestingAddress = _createVesting(msg.sender);\n }\n\n /**\n * @notice Stakes tokens for a user who already have a vesting created.\n * @dev The user should already have a vesting created, else this function will throw error.\n */\n function stakeTokens() public {\n VestingLogic vesting = VestingLogic(_getVesting(msg.sender));\n\n require(\n cliff == vesting.cliff() && duration == vesting.duration(),\n \"Wrong Vesting Schedule.\"\n );\n\n _stakeTokens(msg.sender, address(vesting));\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdrawAndStakeTokens(address _receiverAddress) external {\n _withdraw(msg.sender, _receiverAddress);\n _createVestingAndStake(msg.sender);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n /**\n * @notice Function to start the process of migration to new contract.\n * @param _newLockedSOV The new locked sov contract address.\n */\n function startMigration(address _newLockedSOV) external onlyAdmin {\n require(_newLockedSOV != address(0), \"New Locked SOV Address is Invalid.\");\n newLockedSOV = ILockedSOV(_newLockedSOV);\n SOV.approve(_newLockedSOV, SOV.balanceOf(address(this)));\n migration = true;\n\n emit MigrationStarted(msg.sender, _newLockedSOV);\n }\n\n /**\n * @notice Function to transfer the locked balance from this contract to new LockedSOV Contract.\n * @dev Address is not specified to discourage selling lockedSOV to other address.\n */\n function transfer() external migrationAllowed {\n uint256 amount = lockedBalances[msg.sender];\n lockedBalances[msg.sender] = 0;\n\n newLockedSOV.depositSOV(msg.sender, amount);\n\n emit UserTransfered(msg.sender, amount);\n }\n\n /* Internal Functions */\n\n /**\n * @notice Creates a Vesting Contract for a user.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n * @dev Does not do anything if Vesting Contract was already created.\n */\n function _createVesting(address _tokenOwner) internal returns (address _vestingAddress) {\n /// Here zero is given in place of amount, as amount is not really used in `vestingRegistry.createVesting()`.\n vestingRegistry.createVesting(_tokenOwner, 0, cliff, duration);\n _vestingAddress = _getVesting(_tokenOwner);\n emit VestingCreated(msg.sender, _tokenOwner, _vestingAddress);\n }\n\n /**\n * @notice Returns the Vesting Contract Address.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n */\n function _getVesting(address _tokenOwner) internal view returns (address _vestingAddress) {\n return vestingRegistry.getVesting(_tokenOwner);\n }\n\n /**\n * @notice Stakes the tokens in a particular vesting contract.\n * @param _vesting The Vesting Contract Address.\n */\n function _stakeTokens(address _sender, address _vesting) internal {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n require(SOV.approve(_vesting, amount), \"Approve failed.\");\n VestingLogic(_vesting).stakeTokens(amount);\n\n emit TokenStaked(_sender, _vesting, amount);\n }\n\n /* Getter or Read Functions */\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) external view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n\n /**\n * @notice The function to check is an address is admin or not.\n * @param _addr The address of the user to check the admin status.\n * @return _status True if admin, False otherwise.\n */\n function adminStatus(address _addr) external view returns (bool _status) {\n return isAdmin[_addr];\n }\n}\n" + }, + "contracts/mixins/EnumerableAddressSet.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Based on Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * As of v2.5.0, only `address` sets are supported.\n *\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\n *\n * _Available since v2.5.0._\n */\nlibrary EnumerableAddressSet {\n struct AddressSet {\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(address => uint256) index;\n address[] values;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n * Returns false if the value was already in the set.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n * Returns false if the value was not present in the set.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n // If the element we're deleting is the last one, we can just remove it without doing a swap\n if (lastIndex != toDeleteIndex) {\n address lastValue = set.values[lastIndex];\n\n // Move the last value to the index where the deleted value is\n set.values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n // Delete the index entry for the deleted value\n delete set.index[value];\n\n // Delete the old entry for the moved value\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns an array with all values in the set. O(N).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\n address[] memory output = new address[](set.values.length);\n for (uint256 i; i < set.values.length; i++) {\n output[i] = set.values[i];\n }\n return output;\n }\n\n /**\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n \n * @param start start index of chunk\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\n */\n function enumerateChunk(\n AddressSet storage set,\n uint256 start,\n uint256 count\n ) internal view returns (address[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = (set.values.length < end || count == 0) ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new address[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @dev Returns the number of elements on the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /** @dev Returns the element stored at position `index` in the set. O(1).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes32Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\n * */\nlibrary EnumerableBytes32Set {\n struct Bytes32Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes32 => uint256) index;\n bytes32[] values;\n }\n\n /**\n * @notice Add an address value to a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to add.\n *\n * @return False if the value was already in the set.\n */\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return addBytes32(set, value);\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove an address value from a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to remove.\n *\n * @return False if the address was not present in the set.\n */\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return removeBytes32(set, value);\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function containsAddress(Bytes32Set storage set, address addrvalue)\n internal\n view\n returns (bool)\n {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes32Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes32[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes32[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes4Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`.\n * */\nlibrary EnumerableBytes4Set {\n struct Bytes4Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes4 => uint256) index;\n bytes4[] values;\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes4 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes4Set storage set, bytes4 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes4Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes4[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes4[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes4Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes4Set storage set, uint256 index) internal view returns (bytes4) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/FeesHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ISovryn.sol\";\nimport \"../core/objects/LoanParamsStruct.sol\";\n\n/**\n * @title The Fees Helper contract.\n *\n * This contract calculates and pays lending/borrow fees and rewards.\n * */\ncontract FeesHelper is State, FeesEvents {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Calculate trading fee.\n * @param feeTokenAmount The amount of tokens to trade.\n * @return The fee of the trade.\n * */\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\n }\n\n /**\n * @notice Calculate swap external fee.\n * @param feeTokenAmount The amount of token to swap.\n * @return The fee of the swap.\n */\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\n }\n\n /*\n\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - tradingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);\n\t}*/\n\n /**\n * @notice Calculate the loan origination fee.\n * @param feeTokenAmount The amount of tokens to borrow.\n * @return The fee of the loan.\n * */\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\n /*\n\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - borrowingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);*/\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\n *\n * @param referrer The affiliate referrer address to send the reward to.\n * @param trader The account that performs this trade.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n *\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\n * */\n function _payTradingFeeToAffiliate(\n address referrer,\n address trader,\n address feeToken,\n uint256 tradingFee\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\n address(this)\n )\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n * */\n function _payTradingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 tradingFee\n ) internal {\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\n if (tradingFee != 0) {\n if (affiliatesUserReferrer[user] != address(0)) {\n _payTradingFeeToAffiliate(\n affiliatesUserReferrer[user],\n user,\n feeToken,\n protocolTradingFee\n );\n protocolTradingFee = (\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\n )\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\n }\n\n /// Increase the storage variable keeping track of the accumulated fees.\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\n protocolTradingFee\n );\n\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\n }\n }\n\n /**\n * @notice Settle the borrowing fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the borrowig fee is paid.\n * @param borrowingFee The height of the fee.\n * */\n function _payBorrowingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 borrowingFee\n ) internal {\n if (borrowingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\n\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\n }\n }\n\n /**\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\n * @param user The address to send the reward to.\n * @param feeToken The address of the token in which the lending fee is paid.\n * @param lendingFee The height of the fee.\n * */\n function _payLendingFee(\n address user,\n address feeToken,\n uint256 lendingFee\n ) internal {\n if (lendingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\n\n emit PayLendingFee(user, feeToken, lendingFee);\n\n //// NOTE: Lenders do not receive a fee reward ////\n }\n }\n\n /// Settle and pay borrowers based on the fees generated by their interest payments.\n function _settleFeeRewardForInterestExpense(\n LoanInterest storage loanInterestLocal,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n address user,\n uint256 interestTime\n ) internal {\n /// This represents the fee generated by a borrower's interest payment.\n uint256 interestExpenseFee =\n interestTime\n .sub(loanInterestLocal.updatedTimestamp)\n .mul(loanInterestLocal.owedPerDay)\n .mul(lendingFeePercent)\n .div(1 days * 10**20);\n\n loanInterestLocal.updatedTimestamp = interestTime;\n\n if (interestExpenseFee != 0) {\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\n }\n }\n\n /**\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associeated loan - used for logging only.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * */\n function _payFeeReward(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 feeAmount\n ) internal {\n uint256 rewardAmount;\n uint256 _feeRebatePercent = feeRebatePercent;\n address _priceFeeds = priceFeeds;\n\n if (specialRebates[feeToken][feeTokenPair] > 0) {\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\n }\n\n /// Note: this should be refactored.\n /// Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\n feeAmount.mul(_feeRebatePercent).div(10**20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n // Check the dedicated SOV that is used to pay trading rebate rewards\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"deposit(address,uint256,uint256)\",\n user,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n )\n );\n\n if (success) {\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\n\n emit EarnReward(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n } else {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n }\n}\n" + }, + "contracts/mixins/InterestUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"./FeesHelper.sol\";\n\n/**\n * @title The Interest User contract.\n *\n * This contract pays loan interests.\n * */\ncontract InterestUser is VaultController, FeesHelper {\n using SafeERC20 for IERC20;\n\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n /**\n * @notice Internal function to pay interest of a loan.\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * */\n function _payInterest(address lender, address interestToken) internal {\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\n\n uint256 interestOwedNow = 0;\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\n interestOwedNow = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(1 days);\n\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n\n if (interestOwedNow > lenderInterestLocal.owedTotal)\n interestOwedNow = lenderInterestLocal.owedTotal;\n\n if (interestOwedNow != 0) {\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\n\n _payInterestTransfer(lender, interestToken, interestOwedNow);\n }\n } else {\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n }\n }\n\n /**\n * @notice Internal function to transfer tokens for the interest of a loan.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * @param interestOwedNow The amount of interest to pay.\n * */\n function _payInterestTransfer(\n address lender,\n address interestToken,\n uint256 interestOwedNow\n ) internal {\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\n /// TODO: refactor: data incapsulation violation and DRY design principles\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\n\n _payLendingFee(lender, interestToken, lendingFee);\n\n /// Transfers the interest to the lender, less the interest fee.\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\n\n /// Event Log\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\n }\n}\n" + }, + "contracts/mixins/LiquidationHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\n/**\n * @title The Liquidation Helper contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract computes the liquidation amount.\n * */\ncontract LiquidationHelper is State {\n /**\n * @notice Compute how much needs to be liquidated in order to restore the\n * desired margin (maintenance + 5%).\n *\n * @param principal The total borrowed amount (in loan tokens).\n * @param collateral The collateral (in collateral tokens).\n * @param currentMargin The current margin.\n * @param maintenanceMargin The maintenance (minimum) margin.\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n *\n * @return maxLiquidatable The collateral you can get liquidating.\n * @return maxSeizable The loan you available for liquidation.\n * @return incentivePercent The discount on collateral.\n * */\n function _getLiquidationAmounts(\n uint256 principal,\n uint256 collateral,\n uint256 currentMargin,\n uint256 maintenanceMargin,\n uint256 collateralToLoanRate\n )\n internal\n view\n returns (\n uint256 maxLiquidatable,\n uint256 maxSeizable,\n uint256 incentivePercent\n )\n {\n incentivePercent = liquidationIncentivePercent;\n if (currentMargin > maintenanceMargin || collateralToLoanRate == 0) {\n return (maxLiquidatable, maxSeizable, incentivePercent);\n } else if (currentMargin <= incentivePercent) {\n return (principal, collateral, currentMargin);\n }\n\n /// 5 percentage points above maintenance.\n uint256 desiredMargin = maintenanceMargin.add(5 ether);\n\n /// maxLiquidatable = ((1 + desiredMargin)*principal - collateralToLoanRate*collateral) / (desiredMargin - 0.05)\n maxLiquidatable = desiredMargin.add(10**20).mul(principal).div(10**20);\n maxLiquidatable = maxLiquidatable.sub(collateral.mul(collateralToLoanRate).div(10**18));\n maxLiquidatable = maxLiquidatable.mul(10**20).div(desiredMargin.sub(incentivePercent));\n if (maxLiquidatable > principal) {\n maxLiquidatable = principal;\n }\n\n /// maxSeizable = maxLiquidatable * (1 + incentivePercent) / collateralToLoanRate\n maxSeizable = maxLiquidatable.mul(incentivePercent.add(10**20));\n maxSeizable = maxSeizable.div(collateralToLoanRate).div(100);\n if (maxSeizable > collateral) {\n maxSeizable = collateral;\n }\n\n return (maxLiquidatable, maxSeizable, incentivePercent);\n }\n}\n" + }, + "contracts/mixins/ModuleCommonFunctionalities.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\ncontract ModuleCommonFunctionalities is State {\n modifier whenNotPaused() {\n require(!pause, \"Paused\");\n _;\n }\n}\n" + }, + "contracts/mixins/ProtocolTokenUser.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\n\n/**\n * @title The Protocol Token User contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to withdraw protocol tokens.\n * */\ncontract ProtocolTokenUser is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Internal function to withdraw an amount of protocol tokens from this contract.\n *\n * @param receiver The address of the recipient.\n * @param amount The amount of tokens to withdraw.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function _withdrawProtocolToken(address receiver, uint256 amount)\n internal\n returns (address, bool)\n {\n uint256 withdrawAmount = amount;\n\n uint256 tokenBalance = protocolTokenHeld;\n if (withdrawAmount > tokenBalance) {\n withdrawAmount = tokenBalance;\n }\n if (withdrawAmount == 0) {\n return (protocolTokenAddress, false);\n }\n\n protocolTokenHeld = tokenBalance.sub(withdrawAmount);\n\n IERC20(protocolTokenAddress).safeTransfer(receiver, withdrawAmount);\n\n return (protocolTokenAddress, true);\n }\n}\n" + }, + "contracts/mixins/RewardHelper.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title The Reward Helper contract.\n * @notice This contract calculates the reward for rollover transactions.\n *\n * A rollover is a renewal of a deposit. Instead of liquidating a deposit\n * on maturity, you can roll it over into a new deposit. The outstanding\n * principal of the old deposit is rolled over with or without the interest\n * outstanding on it.\n * */\ncontract RewardHelper is State {\n using SafeMath for uint256;\n\n /**\n * @notice Calculate the reward of a rollover transaction.\n *\n * @param collateralToken The address of the collateral token.\n * @param loanToken The address of the loan token.\n * @param positionSize The amount of value of the position.\n *\n * @return The base fee + the flex fee.\n */\n function _getRolloverReward(\n address collateralToken,\n address loanToken,\n uint256 positionSize\n ) internal view returns (uint256 reward) {\n uint256 positionSizeInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(loanToken, collateralToken, positionSize);\n uint256 rolloverBaseRewardInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(\n address(wrbtcToken),\n collateralToken,\n rolloverBaseReward\n );\n\n return\n rolloverBaseRewardInCollateralToken\n .mul(2) /// baseFee\n .add(positionSizeInCollateralToken.mul(rolloverFlexFeePercent).div(10**20)); /// flexFee = 0.1% of position size\n }\n}\n" + }, + "contracts/mixins/VaultController.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\n\n/**\n * @title The Vault Controller contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to deposit and withdraw wrBTC and\n * other tokens from the vault.\n * */\ncontract VaultController is State {\n using SafeERC20 for IERC20;\n\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\n\n /**\n * @notice Deposit wrBTC into the vault.\n *\n * @param from The address of the account paying the deposit.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherDeposit(address from, uint256 value) internal {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n _wrbtcToken.deposit.value(value)();\n\n emit VaultDeposit(address(_wrbtcToken), from, value);\n }\n\n /**\n * @notice Withdraw wrBTC from the vault.\n *\n * @param to The address of the recipient.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherWithdraw(address to, uint256 value) internal {\n if (value != 0) {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n uint256 balance = address(this).balance;\n if (value > balance) {\n _wrbtcToken.withdraw(value - balance);\n }\n Address.sendValue(to, value);\n\n emit VaultWithdraw(address(_wrbtcToken), to, value);\n }\n }\n\n /**\n * @notice Deposit tokens into the vault.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying the deposit.\n * @param value The amount of tokens to transfer.\n */\n function vaultDeposit(\n address token,\n address from,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransferFrom(from, address(this), value);\n\n emit VaultDeposit(token, from, value);\n }\n }\n\n /**\n * @notice Withdraw tokens from the vault.\n *\n * @param token The address of the token instance.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultWithdraw(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransfer(to, value);\n\n emit VaultWithdraw(token, to, value);\n }\n }\n\n /**\n * @notice Transfer tokens from an account into another one.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultTransfer(\n address token,\n address from,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n if (from == address(this)) {\n IERC20(token).safeTransfer(to, value);\n } else {\n IERC20(token).safeTransferFrom(from, to, value);\n }\n }\n }\n\n /**\n * @notice Approve an allowance of tokens to be spent by an account.\n *\n * @param token The address of the token instance.\n * @param to The address of the spender.\n * @param value The amount of tokens to allow.\n */\n function vaultApprove(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\n IERC20(token).safeApprove(to, 0);\n }\n IERC20(token).safeApprove(to, value);\n }\n}\n" + }, + "contracts/mockup/BlockMockUp.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title Used to get and set mock block number.\n */\ncontract BlockMockUp {\n uint256 public blockNum;\n\n /**\n * @notice To get the `blockNum`.\n * @return _blockNum The block number.\n */\n function getBlockNum() public view returns (uint256 _blockNum) {\n return blockNum;\n }\n\n /**\n * @notice To set the `blockNum`.\n * @param _blockNum The block number.\n */\n function setBlockNum(uint256 _blockNum) public {\n blockNum = _blockNum;\n }\n}\n" + }, + "contracts/mockup/FeeSharingCollectorMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/FeeSharingCollector/FeeSharingCollector.sol\";\n\ncontract FeeSharingCollectorMockup is FeeSharingCollector {\n struct TestData {\n address loanPoolToken;\n uint32 maxCheckpoints;\n address receiver;\n }\n\n TestData public testData;\n\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n testData = TestData(_token, _maxCheckpoints, _receiver);\n }\n\n function trueWithdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function addCheckPoint(address loanPoolToken, uint256 poolTokenAmount) public {\n uint96 amount96 =\n safe96(\n poolTokenAmount,\n \"FeeSharingCollectorProxy::withdrawFees: pool token amount exceeds 96 bits\"\n );\n _addCheckpoint(loanPoolToken, amount96);\n }\n\n function setTotalTokenCheckpoints(address _token, uint256 qty) public {\n totalTokenCheckpoints[_token] = qty;\n }\n\n function setUserProcessedCheckpoints(\n address _user,\n address _token,\n uint256 num\n ) public {\n processedCheckpoints[_user][_token] = num;\n }\n\n function getFullAccumulatedFees(\n address _user,\n address _token,\n uint32 _maxCheckpoints\n ) public view returns (uint256 amount, uint256 end) {\n (amount, end) = _getAccumulatedFees(_user, _token, 0, _maxCheckpoints);\n }\n\n function endOfRangeWithZeroMaxCheckpoint(address _token) public view returns (uint256) {\n return _getEndOfRange(0, _token, 0);\n }\n\n function getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) public view returns (uint256 _tokenAmount, uint256 _endToken) {\n return _getRBTCBalance(_token, _user, _maxCheckpoints);\n }\n\n function testWithdrawReentrancy(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n}\n" + }, + "contracts/mockup/GovernorAlphaMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/GovernorAlpha.sol\";\n\ncontract GovernorAlphaMockup is GovernorAlpha {\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 quorumVotes_,\n uint96 _minPercentageVotes\n ) public GovernorAlpha(timelock_, staking_, guardian_, quorumVotes_, _minPercentageVotes) {}\n\n function votingPeriod() public pure returns (uint256) {\n return 10;\n }\n\n function queueProposals(uint256[] calldata proposalIds) external {\n for (uint256 i = 0; i < proposalIds.length; i++) {\n queue(proposalIds[i]);\n }\n }\n}\n" + }, + "contracts/mockup/LiquidityMiningMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract LiquidityMiningMockup is LiquidityMining {\n function getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n public\n view\n returns (uint256)\n {\n return _getPassedBlocksWithBonusMultiplier(_from, _to);\n }\n\n function getPoolAccumulatedReward(address _poolToken) public view returns (uint256, uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n return _getPoolAccumulatedReward(pool);\n }\n}\n" + }, + "contracts/mockup/LiquidityPoolV1ConverterMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/IERC20.sol\";\n\ncontract LiquidityPoolV1ConverterMockup {\n IERC20[] public reserveTokens;\n IERC20 wrbtcToken;\n uint256 totalFeeMockupValue;\n address feesController;\n\n constructor(IERC20 _token0, IERC20 _token1) public {\n reserveTokens.push(_token0);\n reserveTokens.push(_token1);\n }\n\n function setFeesController(address _feesController) public {\n feesController = _feesController;\n }\n\n function setWrbtcToken(IERC20 _wrbtcToken) public {\n wrbtcToken = _wrbtcToken;\n }\n\n function setTotalFeeMockupValue(uint256 _totalFeeMockupValue) public {\n totalFeeMockupValue = _totalFeeMockupValue;\n }\n\n function withdrawFees(address _receiver) external returns (uint256) {\n require(msg.sender == feesController, \"unauthorized\");\n\n // transfer wrbtc\n wrbtcToken.transfer(_receiver, totalFeeMockupValue);\n return totalFeeMockupValue;\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/LoanClosingsWith.sol\";\n\ncontract LoanClosingsWithMockup is LoanClosingsWith {\n function worthTheTransfer(address, uint256) internal returns (bool) {\n return true;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithoutInvariantCheck.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanClosingsWithMockup.sol\";\n\ncontract LoanClosingsWithoutInvariantCheck is LoanClosingsWithMockup {\n /** Override the modifier of invariant check so that we can test the shared reentrancy guard */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n _;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicLMMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\n\ncontract LoanTokenLogicLMMockup is LoanTokenLogicLM {\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n returns (uint256 loanAmountPaid)\n {\n _callOptionalReturn(\n 0x2c34D66a5ca8686330e100372Eb3FDFB5aEECD0B, //Random EOA for testing\n abi.encodeWithSelector(IERC20(receiver).transfer.selector, receiver, burnAmount),\n \"error\"\n );\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicV2Mockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicV1Mockup is LoanTokenLogicStandard {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](27);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n // res[31] = this.totalSupply.selector;\n res[25] = this.balanceOf.selector;\n res[26] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n\ncontract LoanTokenLogicV2Mockup is LoanTokenLogicStandard {\n function testNewFunction() external pure returns (bool) {\n return true;\n }\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](29);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mockup\n res[28] = this.testNewFunction.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/mockup/lockedSOVFailedMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An interface for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete interface of the Locked SOV Contract.\n */\ncontract LockedSOVFailedMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The user balances.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n revert(\"For testing purposes\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/LockedSOVMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An mockup for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete mockup of the Locked SOV Contract.\n */\ncontract LockedSOVMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n event TokensStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // 10000 is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < 10000, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(10000);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n function _createVestingAndStake(address _sender) private {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n emit TokensStaked(_sender, address(0), amount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/MockAffiliates.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/Affiliates.sol\";\n\ncontract MockAffiliates is Affiliates {\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n }\n}\n" + }, + "contracts/mockup/MockFourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/Vesting/fouryear/FourYearVestingLogic.sol\";\n\ncontract MockFourYearVestingLogic is FourYearVestingLogic {\n /**\n * @notice gets duration left\n */\n function getDurationLeft() external view returns (uint256) {\n return durationLeft;\n }\n}\n" + }, + "contracts/mockup/MockLoanTokenLogic.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogic is LoanTokenLogic {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](31);\n\n // Loan Token Logic\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mock\n res[28] = this.setAffiliatesReferrer.selector;\n res[29] = this.setUserNotFirstTradeFlag.selector;\n res[30] = this.getMarginBorrowAmountAndRate.selector;\n\n return (res, stringToBytes32(\"MockLoanTokenLogic\"));\n }\n\n function setAffiliatesReferrer(address user, address referrer) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(user, referrer);\n }\n\n function setUserNotFirstTradeFlag(address user) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(user);\n }\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n\n /*function initialize(address target) external onlyOwner {\n\t\t_setTarget(this.setAffiliatesUserReferrer.selector, target);\n\t}*/\n}\n\ncontract ILoanTokenModulesMock is ILoanTokenModules {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user) external;\n}\n" + }, + "contracts/mockup/MockLoanTokenLogicLM.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogicLM is LoanTokenLogicLM {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n /** LoanTokenLogicLM function signature */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\"));\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\"));\n res[2] = bytes4(keccak256(\"burn(address,uint256)\"));\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\"));\n\n return (res, stringToBytes32(\"MockLoanTokenLogicLM\"));\n }\n}\n" + }, + "contracts/mockup/modules/IWeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract IWeightedStakingModuleMockup {\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) external;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) external;\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external;\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) external;\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/mockup/modules/StakingModuleBlockMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/StakingGovernanceModule.sol\";\nimport \"../../governance/Staking/modules/StakingStakeModule.sol\";\nimport \"../../governance/Staking/modules/StakingVestingModule.sol\";\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../BlockMockUp.sol\";\n\ncontract StakingModuleBlockMockup is\n IFunctionsList,\n StakingGovernanceModule,\n StakingStakeModule,\n StakingVestingModule,\n WeightedStakingModule\n{\n uint96 public priorWeightedStake;\n mapping(uint256 => uint96) public priorWeightedStakeAtBlock;\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n function balanceOf_MultipliedByTwo(address account) external view returns (uint256) {\n return this.balanceOf(account) * 2;\n }\n\n uint96 priorTotalVotingPower;\n\n function MOCK_priorTotalVotingPower(uint96 _priorTotalVotingPower) public {\n priorTotalVotingPower = _priorTotalVotingPower;\n }\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n return\n priorTotalVotingPower != 0\n ? priorTotalVotingPower\n : super.getPriorTotalVotingPower(blockNumber, time);\n }\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) public view returns (bool) {\n bytes32 codeHash = _getCodeHash(stakerAddress);\n return vestingCodeHashes[codeHash];\n }\n\n function getPriorWeightedStakeAtBlock(uint256 blockNum) public view returns (uint256) {\n return uint256(priorWeightedStakeAtBlock[blockNum]);\n }\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n // StakingGovernanceModule\n bytes4[] memory functionsList = new bytes4[](31);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n\n // StakingStakeModule\n functionsList[6] = this.stake.selector;\n functionsList[7] = this.stakeWithApproval.selector;\n functionsList[8] = this.extendStakingDuration.selector;\n functionsList[9] = this.stakesBySchedule.selector;\n functionsList[10] = this.stakeBySchedule.selector;\n functionsList[11] = this.balanceOf.selector;\n functionsList[12] = this.getCurrentStakedUntil.selector;\n functionsList[13] = this.getStakes.selector;\n functionsList[14] = this.timestampToLockDate.selector;\n\n //StakingVestingModule\n functionsList[15] = this.setVestingRegistry.selector;\n functionsList[16] = this.setVestingStakes.selector;\n functionsList[17] = this.getPriorUserStakeByDate.selector;\n functionsList[18] = this.getPriorVestingWeightedStake.selector;\n functionsList[19] = this.getPriorVestingStakeByDate.selector;\n functionsList[20] = this.addContractCodeHash.selector;\n functionsList[21] = this.removeContractCodeHash.selector;\n functionsList[22] = this.isVestingContract.selector;\n\n //BlockMockup\n functionsList[23] = this.setBlockMockUpAddr.selector;\n functionsList[24] = this.MOCK_priorWeightedStake.selector;\n functionsList[25] = this.MOCK_priorWeightedStakeAtBlock.selector;\n\n //WeightedStakingModule\n functionsList[26] = this.getPriorWeightedStake.selector;\n functionsList[27] = this.weightedStakeByDate.selector;\n functionsList[28] = this.computeWeightByDate.selector;\n functionsList[29] = this.priorWeightedStakeAtBlock.selector;\n functionsList[30] = this.getPriorWeightedStakeAtBlock.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/modules/StakingSharedModuleMock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/shared/StakingShared.sol\";\nimport \"../BlockMockUp.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\n\ncontract StakingModuleMock is IFunctionsList, StakingShared {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](1);\n functionList[0] = this.setBlockMockUpAddr.selector;\n }\n}\n" + }, + "contracts/mockup/modules/StakingWrapperMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\ncontract StakingWrapperMockup {\n uint256 constant TWO_WEEKS = 1209600;\n\n IStaking staking;\n IERC20 token;\n\n constructor(IStaking _staking, IERC20 _token) public {\n staking = _staking;\n token = _token;\n }\n\n function stake2times(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stake(amount, until, stakeFor, delegatee);\n }\n\n function stakeAndExtend(uint96 amount, uint256 until) external {\n require(token.transferFrom(msg.sender, address(this), amount));\n token.approve(address(staking), amount);\n\n staking.stake(amount, until, address(this), address(this));\n staking.extendStakingDuration(until, until + TWO_WEEKS);\n }\n\n function stakeAndStakeBySchedule(\n uint96 amount,\n uint256 until,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n}\n" + }, + "contracts/mockup/modules/WeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract WeightedStakingModuleMockup is WeightedStakingModule {\n uint96 priorWeightedStake;\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n mapping(uint256 => uint96) priorWeightedStakeAtBlock;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n functionsList[3] = this.MOCK_priorWeightedStake.selector;\n functionsList[4] = this.MOCK_priorWeightedStakeAtBlock.selector;\n functionsList[5] = this.calculatePriorWeightedStake.selector;\n functionsList[6] = this.setDelegateStake.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n//@todo can I change this proxy to EIP-1822 proxy standard, please. https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\ncontract PreviousLoanToken is AdvancedTokenStorage {\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../connectors/loantoken/interfaces/ProtocolSettingsLike.sol\";\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n// It is a LoanToken implementation!\ncontract PreviousLoanTokenSettingsLowerAdmin is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress\n\n // ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n // ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n //@todo check for restrictions in this contract\n modifier onlyAdmin() {\n require(msg.sender == address(this) || msg.sender == owner(), \"unauthorized\");\n _;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function init(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans // isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n // These params should be percentages represented like so: 5% = 5000000000000000000\n // rateMultiplier + baseRate can't exceed 100%\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; // 80 ether\n kinkLevel = _kinkLevel; // 90 ether\n maxScaleRate = _maxScaleRate; // 100 ether\n }\n\n function toggleFunctionPause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyAdmin {\n // keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /**\n * sets the transaction limit per token address\n * @param addresses the token addresses\n * @param limits the limit denominated in the currency of the token address\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyOwner\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n}\n" + }, + "contracts/mockup/PriceFeedsMoCMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../feeds/testnet/PriceFeedsMoC.sol\";\n\n// This contract is only for test purposes\n// https://github.com/money-on-chain/Amphiraos-Oracle/blob/master/contracts/medianizer/medianizer.sol\ncontract PriceFeedsMoCMockup is Medianizer {\n uint256 public value;\n bool public has;\n\n function peek() external view returns (bytes32, bool) {\n return (bytes32(value), has);\n }\n\n function setValue(uint256 _value) public {\n value = _value;\n }\n\n function setHas(bool _has) public {\n has = _has;\n }\n}\n" + }, + "contracts/mockup/ProtocolSettingsMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/ProtocolSettings.sol\";\n\ncontract ProtocolSettingsMockup is ProtocolSettings {\n function setLendingFeeTokensHeld(address token, uint256 amout) public {\n lendingFeeTokensHeld[token] = amout;\n }\n\n function setTradingFeeTokensHeld(address token, uint256 amout) public {\n tradingFeeTokensHeld[token] = amout;\n }\n\n function setBorrowingFeeTokensHeld(address token, uint256 amout) public {\n borrowingFeeTokensHeld[token] = amout;\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n\n _setTarget(this.setLendingFeeTokensHeld.selector, target);\n _setTarget(this.setTradingFeeTokensHeld.selector, target);\n _setTarget(this.setBorrowingFeeTokensHeld.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n\n _setTarget(this.getDefaultPathConversion.selector, target);\n }\n}\n" + }, + "contracts/mockup/proxy/ImplementationMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\n\ncontract ImplementationMockup is StorageMockup {\n function setValue(uint256 _value) public {\n value = _value;\n emit ValueChanged(_value);\n }\n\n function getValue() public view returns (uint256) {\n return value;\n }\n}\n" + }, + "contracts/mockup/proxy/ProxyMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract ProxyMockup is StorageMockup, UpgradableProxy {}\n" + }, + "contracts/mockup/proxy/StorageMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\ncontract StorageMockup {\n uint256 value;\n\n event ValueChanged(uint256 value);\n}\n" + }, + "contracts/mockup/RBTCWrapperProxyMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract RBTCWrapperProxyMockup {\n LiquidityMining public liquidityMining;\n\n constructor(LiquidityMining _liquidityMining) public {\n liquidityMining = _liquidityMining;\n }\n\n function claimReward(address _poolToken) public {\n liquidityMining.claimReward(_poolToken, msg.sender);\n }\n\n function claimRewardFromAllPools() public {\n liquidityMining.claimRewardFromAllPools(msg.sender);\n }\n\n function withdraw(address _poolToken, uint256 _amount) public {\n liquidityMining.withdraw(_poolToken, _amount, msg.sender);\n }\n}\n" + }, + "contracts/mockup/StakingRewardsMockUp.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/StakingRewards/StakingRewards.sol\";\nimport \"./BlockMockUp.sol\";\n\n/**\n * @title Staking Rewards Contract MockUp\n * @notice This is used for Testing\n * */\ncontract StakingRewardsMockUp is StakingRewards {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n using SafeMath for uint256;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n}\n" + }, + "contracts/mockup/TimelockHarness.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"../governance/Timelock.sol\";\n\ninterface Administered {\n function _acceptAdmin() external returns (uint256);\n}\n\ncontract TimelockHarness is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, delay_) {}\n\n function setDelayWithoutChecking(uint256 delay_) public {\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function harnessSetPendingAdmin(address pendingAdmin_) public {\n pendingAdmin = pendingAdmin_;\n }\n\n function harnessSetAdmin(address admin_) public {\n admin = admin_;\n }\n}\n\ncontract TimelockTest is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, 2 days) {\n delay = delay_;\n }\n\n function harnessSetAdmin(address admin_) public {\n require(msg.sender == admin);\n admin = admin_;\n }\n\n function harnessAcceptAdmin(Administered administered) public {\n administered._acceptAdmin();\n }\n}\n" + }, + "contracts/mockup/VestingLogicMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/Vesting/VestingLogic.sol\";\n\ncontract VestingLogicMockup is VestingLogic {\n /**\n * @dev we had a bug in a loop: \"i < endDate\" instead of \"i <= endDate\"\n */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n}\n" + }, + "contracts/mockup/VestingRegistryLogicMockUp.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\nimport \"../governance/Vesting/VestingRegistryLogic.sol\";\n\ncontract VestingRegistryLogicMockup is VestingRegistryLogic {\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return true;\n }\n\n function setTeamVesting(address _vesting, uint256 _vestingCreationType) external {\n vestingCreationAndTypes[_vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(VestingType.TeamVesting),\n vestingCreationType: uint128(_vestingCreationType)\n });\n }\n}\n" + }, + "contracts/modules/Affiliates.sol": { + "content": "/**\n * Copyright 2017-2020, Sovryn, All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Affiliates contract.\n * @notice Track referrals and reward referrers (affiliates) with tokens.\n * In-detail specifications are found at https://wiki.sovryn.app/en/community/Affiliates\n * @dev Module: Affiliates upgradable\n * Storage: from State, functions called from Protocol by delegatecall\n */\ncontract Affiliates is State, AffiliatesEvents, ModuleCommonFunctionalities {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Void constructor.\n */\n // solhint-disable-next-line no-empty-blocks\n constructor() public {}\n\n /**\n * @notice Avoid calls to this contract except for those explicitly declared.\n */\n function() external {\n revert(\"Affiliates - fallback not allowed\");\n }\n\n /**\n * @notice Set delegate callable functions by proxy contract.\n * @dev This contract is designed as a module, this way logic can be\n * expanded and upgraded w/o losing storage that is kept in the protocol (State.sol)\n * initialize() is used to register in the proxy external (module) functions\n * to be called via the proxy.\n * @param target The address of a new logic implementation.\n */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setAffiliatesReferrer.selector];\n _setTarget(this.setAffiliatesReferrer.selector, target);\n _setTarget(this.getUserNotFirstTradeFlag.selector, target);\n _setTarget(this.getReferralsList.selector, target);\n _setTarget(this.setUserNotFirstTradeFlag.selector, target);\n _setTarget(this.payTradingFeeToAffiliatesReferrer.selector, target);\n _setTarget(this.getAffiliatesReferrerBalances.selector, target);\n _setTarget(this.getAffiliatesReferrerTokenBalance.selector, target);\n _setTarget(this.getAffiliatesReferrerTokensList.selector, target);\n _setTarget(this.withdrawAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.withdrawAllAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.getMinReferralsToPayout.selector, target);\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n _setTarget(this.getAffiliateRewardsHeld.selector, target);\n _setTarget(this.getAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.getAffiliatesTokenRewardsValueInRbtc.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"Affiliates\");\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from loan pools.\n */\n modifier onlyCallableByLoanPools() {\n require(loanPoolToUnderlying[msg.sender] != address(0), \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from within protocol functions.\n */\n modifier onlyCallableInternal() {\n require(msg.sender == protocolAddress, \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Data structure comprised of 3 flags to compute the result of setting a referrer.\n */\n struct SetAffiliatesReferrerResult {\n bool success;\n bool alreadySet;\n bool userNotFirstTradeFlag;\n }\n\n /**\n * @notice Loan pool calls this function to tell affiliates\n * a user coming from a referrer is trading and should be registered if not yet.\n * Taking into account some user status flags may lead to the user and referrer\n * become added or not to the affiliates record.\n *\n * @param user The address of the user that is trading on loan pools.\n * @param referrer The address of the referrer the user is coming from.\n */\n function setAffiliatesReferrer(address user, address referrer)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n SetAffiliatesReferrerResult memory result;\n\n result.userNotFirstTradeFlag = getUserNotFirstTradeFlag(user);\n result.alreadySet = affiliatesUserReferrer[user] != address(0);\n result.success = !(result.userNotFirstTradeFlag || result.alreadySet || user == referrer);\n if (result.success) {\n affiliatesUserReferrer[user] = referrer;\n referralsList[referrer].add(user);\n emit SetAffiliatesReferrer(user, referrer);\n } else {\n emit SetAffiliatesReferrerFail(\n user,\n referrer,\n result.alreadySet,\n result.userNotFirstTradeFlag\n );\n }\n }\n\n /**\n * @notice Getter to query the referrals coming from a referrer.\n * @param referrer The address of a given referrer.\n * @return The referralsList mapping value by referrer.\n */\n function getReferralsList(address referrer) external view returns (address[] memory refList) {\n refList = referralsList[referrer].enumerate();\n return refList;\n }\n\n /**\n * @notice Getter to query the not-first-trade flag of a user.\n * @param user The address of a given user.\n * @return The userNotFirstTradeFlag mapping value by user.\n */\n function getUserNotFirstTradeFlag(address user) public view returns (bool) {\n return userNotFirstTradeFlag[user];\n }\n\n /**\n * @notice Setter to toggle on the not-first-trade flag of a user.\n * @param user The address of a given user.\n */\n function setUserNotFirstTradeFlag(address user)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n if (!userNotFirstTradeFlag[user]) {\n userNotFirstTradeFlag[user] = true;\n emit SetUserNotFirstTradeFlag(user);\n }\n }\n\n /**\n * @notice Internal getter to query the fee share for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function _getAffiliatesTradingFeePercentForSOV() internal view returns (uint256) {\n return affiliateFeePercent;\n }\n\n /**\n * @notice Internal to calculate the affiliates trading token fee amount.\n * Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * This _getReferrerTradingFeeForToken calculates the first one\n * by applying a custom percentage multiplier.\n * @param feeTokenAmount The trading token fee amount.\n * @return The affiliates share of the trading token fee amount.\n */\n function _getReferrerTradingFeeForToken(uint256 feeTokenAmount)\n internal\n view\n returns (uint256)\n {\n return feeTokenAmount.mul(getAffiliateTradingTokenFeePercent()).div(10**20);\n }\n\n /**\n * @notice Getter to query the fee share of trading token fee for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function getAffiliateTradingTokenFeePercent() public view returns (uint256) {\n return affiliateTradingTokenFeePercent;\n }\n\n /**\n * @notice Getter to query referral threshold for paying out to the referrer.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The minimum number of referrals set by Protocol.\n */\n function getMinReferralsToPayout() public view returns (uint256) {\n return minReferralsToPayout;\n }\n\n /**\n * @notice Get the sovToken reward of a trade.\n * @dev The reward is worth x% of the trading fee.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * @return The reward amount.\n * */\n function _getSovBonusAmount(address feeToken, uint256 feeAmount)\n internal\n view\n returns (uint256)\n {\n uint256 rewardAmount;\n address _priceFeeds = priceFeeds;\n\n /// @dev Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// dest token = SOV\n feeAmount.mul(_getAffiliatesTradingFeePercentForSOV()).div(1e20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n return rewardAmount;\n }\n\n /**\n * @notice Protocol calls this function to pay the affiliates rewards to a user (referrer).\n *\n * @dev Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * Both are paid in this function.\n *\n * @dev Actually they are not paid, but just holded by protocol until user claims them by\n * actively calling withdrawAffiliatesReferrerTokenFees() function,\n * and/or when unvesting lockedSOV.\n *\n * @dev To be precise, what this function does is updating the registers of the rewards\n * for the referrer including the assignment of the SOV tokens as rewards to the\n * referrer's vesting contract.\n *\n * @param referrer The address of the referrer.\n * @param trader The address of the trader.\n * @param token The address of the token in which the trading/borrowing fee was paid.\n * @param tradingFeeTokenBaseAmount Total trading fee amount, the base for calculating referrer's fees.\n *\n * @return referrerBonusSovAmount The amount of SOV tokens paid to the referrer (through a vesting contract, lockedSOV).\n * @return referrerBonusTokenAmount The amount of trading tokens paid directly to the referrer.\n */\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n )\n external\n onlyCallableInternal\n whenNotPaused\n returns (uint256 referrerBonusSovAmount, uint256 referrerBonusTokenAmount)\n {\n bool isHeld = referralsList[referrer].length() < getMinReferralsToPayout();\n bool bonusPaymentIsSuccess = true;\n uint256 paidReferrerBonusSovAmount;\n\n /// Process token fee rewards first.\n referrerBonusTokenAmount = _getReferrerTradingFeeForToken(tradingFeeTokenBaseAmount);\n if (!affiliatesReferrerTokensList[referrer].contains(token))\n affiliatesReferrerTokensList[referrer].add(token);\n affiliatesReferrerBalances[referrer][token] = affiliatesReferrerBalances[referrer][token]\n .add(referrerBonusTokenAmount);\n\n /// Then process SOV rewards.\n referrerBonusSovAmount = _getSovBonusAmount(token, tradingFeeTokenBaseAmount);\n uint256 rewardsHeldByProtocol = affiliateRewardsHeld[referrer];\n\n if (isHeld) {\n /// If referrals less than minimum, temp the rewards SOV to the storage\n affiliateRewardsHeld[referrer] = rewardsHeldByProtocol.add(referrerBonusSovAmount);\n } else {\n /// If referrals >= minimum, directly send all of the remain rewards to locked sov\n /// Call depositSOV() in LockedSov contract\n /// Set the affiliaterewardsheld = 0\n if (affiliateRewardsHeld[referrer] > 0) {\n affiliateRewardsHeld[referrer] = 0;\n }\n\n paidReferrerBonusSovAmount = referrerBonusSovAmount.add(rewardsHeldByProtocol);\n IERC20(sovTokenAddress).approve(lockedSOVAddress, paidReferrerBonusSovAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"depositSOV(address,uint256)\",\n referrer,\n paidReferrerBonusSovAmount\n )\n );\n\n if (!success) {\n bonusPaymentIsSuccess = false;\n }\n }\n\n if (bonusPaymentIsSuccess) {\n emit PayTradingFeeToAffiliate(\n referrer,\n trader, // trader\n token,\n isHeld,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n } else {\n emit PayTradingFeeToAffiliateFail(\n referrer,\n trader, // trader\n token,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n }\n\n return (referrerBonusSovAmount, referrerBonusTokenAmount);\n }\n\n /**\n * @notice Referrer calls this function to receive its reward in a given token.\n * It will send the other (non-SOV) reward tokens from trading protocol fees,\n * to the referrer’s wallet.\n * @dev Rewards are held by protocol in different tokens coming from trading fees.\n * Referrer has to claim them one by one for every token with accumulated balance.\n * @param token The address of the token to withdraw.\n * @param receiver The address of the withdrawal beneficiary.\n * @param amount The amount of tokens to claim. If greater than balance, just sends balance.\n */\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) public whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n uint256 referrerTokenBalance = affiliatesReferrerBalances[referrer][token];\n uint256 withdrawAmount = referrerTokenBalance > amount ? amount : referrerTokenBalance;\n\n require(withdrawAmount > 0, \"Affiliates: cannot withdraw zero amount\");\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n uint256 newReferrerTokenBalance = referrerTokenBalance.sub(withdrawAmount);\n\n if (newReferrerTokenBalance == 0) {\n _removeAffiliatesReferrerToken(referrer, token);\n } else {\n affiliatesReferrerBalances[referrer][token] = newReferrerTokenBalance;\n }\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawAffiliatesReferrerTokenFees(referrer, receiver, token, withdrawAmount);\n }\n\n /**\n * @notice Withdraw to msg.sender all token fees for a referrer.\n * @dev It's done by looping through its available tokens.\n * @param receiver The address of the withdrawal beneficiary.\n */\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n (address[] memory tokenAddresses, uint256[] memory tokenBalances) =\n getAffiliatesReferrerBalances(referrer);\n for (uint256 i; i < tokenAddresses.length; i++) {\n withdrawAffiliatesReferrerTokenFees(tokenAddresses[i], receiver, tokenBalances[i]);\n }\n }\n\n /**\n * @notice Internal function to delete a referrer's token balance.\n * @param referrer The address of the referrer.\n * @param token The address of the token specifying the balance to remove.\n */\n function _removeAffiliatesReferrerToken(address referrer, address token) internal {\n delete affiliatesReferrerBalances[referrer][token];\n affiliatesReferrerTokensList[referrer].remove(token);\n }\n\n /**\n * @notice Get all token balances of a referrer.\n * @param referrer The address of the referrer.\n * @return referrerTokensList The array of available tokens (keys).\n * @return referrerTokensBalances The array of token balances (values).\n */\n function getAffiliatesReferrerBalances(address referrer)\n public\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances)\n {\n referrerTokensList = getAffiliatesReferrerTokensList(referrer);\n referrerTokensBalances = new uint256[](referrerTokensList.length);\n for (uint256 i; i < referrerTokensList.length; i++) {\n referrerTokensBalances[i] = getAffiliatesReferrerTokenBalance(\n referrer,\n referrerTokensList[i]\n );\n }\n return (referrerTokensList, referrerTokensBalances);\n }\n\n /**\n * @dev Get all token rewards estimation value in rbtc.\n *\n * @param referrer Address of referrer.\n *\n * @return The value estimation in rbtc.\n */\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount)\n {\n address[] memory tokensList = getAffiliatesReferrerTokensList(referrer);\n address _priceFeeds = priceFeeds;\n\n for (uint256 i; i < tokensList.length; i++) {\n // Get the value of each token in rbtc\n\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n tokensList[i], // source token\n address(wrbtcToken), // dest token = SOV\n affiliatesReferrerBalances[referrer][tokensList[i]] // total token rewards\n )\n );\n\n assembly {\n if eq(success, 1) {\n rbtcTotalAmount := add(rbtcTotalAmount, mload(add(data, 32)))\n }\n }\n }\n }\n\n /**\n * @notice Get all available tokens at the affiliates program for a given referrer.\n * @param referrer The address of a given referrer.\n * @return tokensList The list of available tokens.\n */\n function getAffiliatesReferrerTokensList(address referrer)\n public\n view\n returns (address[] memory tokensList)\n {\n tokensList = affiliatesReferrerTokensList[referrer].enumerate();\n return tokensList;\n }\n\n /**\n * @notice Getter to query the affiliate balance for a given referrer and token.\n * @param referrer The address of the referrer.\n * @param token The address of the token to get balance for.\n * @return The affiliatesReferrerBalances mapping value by referrer and token keys.\n */\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n public\n view\n returns (uint256)\n {\n return affiliatesReferrerBalances[referrer][token];\n }\n\n /**\n * @notice Getter to query the address of referrer for a given user.\n * @param user The address of the user.\n * @return The address on affiliatesUserReferrer mapping value by user key.\n */\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user];\n }\n\n /**\n * @notice Getter to query the reward amount held for a given referrer.\n * @param referrer The address of the referrer.\n * @return The affiliateRewardsHeld mapping value by referrer key.\n */\n function getAffiliateRewardsHeld(address referrer) public view returns (uint256) {\n return affiliateRewardsHeld[referrer];\n }\n}\n" + }, + "contracts/modules/interfaces/ProtocolAffiliatesInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolAffiliatesInterface {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user_) external;\n\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\n\n function payTradingFeeToAffiliatesReferrer(\n address affiliate,\n address trader,\n address token,\n uint256 amount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n}\n" + }, + "contracts/modules/interfaces/ProtocolSwapExternalInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolSwapExternalInterface {\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n}\n" + }, + "contracts/modules/LoanClosingsLiquidation.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsLiquidation contract.\n * @notice Ways to close a loan: liquidation. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsLiquidation is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.liquidate.selector];\n _setTarget(this.liquidate.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsLiquidation\"\n );\n }\n\n /**\n * @notice Liquidate an unhealty loan.\n *\n * @dev Public wrapper for _liquidate internal function.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * loanId is the ID of the loan, which is created on loan opening.\n * It can be obtained either by parsing the Trade event or by reading\n * the open loans from the contract by calling getActiveLoans or getUserLoans.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n return _liquidate(loanId, receiver, closeAmount);\n }\n\n /**\n * @notice Internal function for liquidating an unhealthy loan.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function _liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin <= loanParamsLocal.maintenanceMargin, \"healthy position\");\n\n loanCloseAmount = closeAmount;\n\n //amounts to restore the desired margin (maintencance + 5%)\n (uint256 maxLiquidatable, uint256 maxSeizable, ) =\n _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n\n if (loanCloseAmount < maxLiquidatable) {\n //close maxLiquidatable if tiny position will remain\n uint256 remainingAmount = maxLiquidatable - loanCloseAmount;\n remainingAmount = _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingAmount <= TINY_AMOUNT) {\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable.mul(loanCloseAmount).div(maxLiquidatable);\n }\n } else if (loanCloseAmount > maxLiquidatable) {\n // adjust down the close amount to the max\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable;\n }\n\n require(loanCloseAmount != 0, \"nothing to liquidate\");\n\n // liquidator deposits the principal being closed\n _returnPrincipalWithDeposit(loanParamsLocal.loanToken, address(this), loanCloseAmount);\n\n // a portion of the principal is repaid to the lender out of interest refunded\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n loanLocal.borrower\n );\n\n if (loanCloseAmount > loanCloseAmountLessInterest) {\n // full interest refund goes to the borrower\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanCloseAmount - loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmountLessInterest != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n seizedToken = loanParamsLocal.collateralToken;\n\n if (seizedAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(seizedAmount);\n\n _withdrawAsset(seizedToken, receiver, seizedAmount);\n }\n\n _closeLoan(loanLocal, loanCloseAmount);\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n seizedAmount,\n collateralToLoanRate,\n 0,\n currentMargin,\n CloseTypes.Liquidation\n );\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsRollover.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsRollover contract.\n * @notice Ways to close a loan: rollover. Margin trade\n * positions are always closed with a swap.\n *\n * */\ncontract LoanClosingsRollover is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.rollover.selector];\n _setTarget(this.rollover.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsRollover\"\n );\n }\n\n /**\n * @notice Roll over a loan.\n *\n * @dev Public wrapper for _rollover internal function.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * The function rollover on the protocol contract extends the loan\n * duration by the maximum term (28 days for margin trades at the moment\n * of writing), pays the interest to the lender and refunds the caller\n * for the gas cost by sending 2 * the gas cost using the fast gas price\n * as base for the calculation.\n *\n * @param loanId The ID of the loan to roll over.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n * */\n function rollover(\n bytes32 loanId,\n bytes calldata // for future use /*loanDataBytes*/\n ) external nonReentrant globallyNonReentrant iTokenSupplyUnchanged(loanId) whenNotPaused {\n // restrict to EOAs to prevent griefing attacks, during interest rate recalculation\n require(msg.sender == tx.origin, \"EOAs call\");\n\n return\n _rollover(\n loanId,\n \"\" // loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for roll over a loan.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * @param loanId The ID of the loan to roll over.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n * */\n function _rollover(bytes32 loanId, bytes memory loanDataBytes) internal {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n require(block.timestamp > loanLocal.endTimestamp.sub(3600), \"healthy position\");\n require(loanPoolToUnderlying[loanLocal.lender] != address(0), \"invalid lender\");\n\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n // Handle back interest: calculates interest owned since the loan endtime passed but the loan remained open\n uint256 backInterestTime;\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestTime = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestTime.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(1 days);\n }\n\n //note: to avoid code duplication, it would be nicer to store loanParamsLocal.maxLoanTerm in a local variable\n //however, we've got stack too deep issues if we do so.\n if (loanParamsLocal.maxLoanTerm != 0) {\n // fixed-term loan, so need to query iToken for latest variable rate\n uint256 owedPerDay =\n loanLocal.principal.mul(ILoanPool(loanLocal.lender).borrowInterestRate()).div(\n 365 * 10**20\n );\n\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(\n loanInterestLocal.owedPerDay\n );\n\n loanInterestLocal.owedPerDay = owedPerDay;\n\n //if the loan has been open for longer than an additional period, add at least 1 additional day\n if (backInterestTime >= loanParamsLocal.maxLoanTerm) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n }\n //extend by the max loan term\n else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(loanParamsLocal.maxLoanTerm);\n }\n } else {\n // loanInterestLocal.owedPerDay doesn't change\n if (backInterestTime >= MONTH) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n } else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(MONTH);\n }\n }\n\n uint256 interestAmountRequired = loanLocal.endTimestamp.sub(block.timestamp);\n interestAmountRequired = interestAmountRequired.mul(loanInterestLocal.owedPerDay);\n interestAmountRequired = interestAmountRequired.div(1 days);\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n\n // add backInterestOwed\n interestAmountRequired = interestAmountRequired.add(backInterestOwed);\n\n // collect interest (needs to be converted from the collateral)\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n 0, //min swap 0 -> swap connector estimates the amount of source tokens to use\n interestAmountRequired, //required destination tokens\n true, // returnTokenIsCollateral\n loanDataBytes\n );\n\n //received more tokens than needed to pay the interest\n if (destTokenAmountReceived > interestAmountRequired) {\n // swap rest back to collateral, if the amount is big enough to cover gas cost\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n )\n ) {\n (destTokenAmountReceived, , ) = _swapBackExcess(\n loanLocal,\n loanParamsLocal,\n destTokenAmountReceived - interestAmountRequired, //amount to be swapped\n loanDataBytes\n );\n sourceTokenAmountUsed = sourceTokenAmountUsed.sub(destTokenAmountReceived);\n }\n //else give it to the protocol as a lending fee\n else {\n _payLendingFee(\n loanLocal.borrower,\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n );\n }\n }\n\n //subtract the interest from the collateral\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n if (backInterestOwed != 0) {\n // pay out backInterestOwed\n\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n uint256 rolloverReward =\n _getRolloverReward(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.principal\n );\n\n if (rolloverReward != 0) {\n // if the reward > collateral:\n if (rolloverReward > loanLocal.collateral) {\n // 1. pay back the remaining loan to the lender\n // 2. pay the remaining collateral to msg.sender\n // 3. close the position & emit close event\n _closeWithSwap(\n loanLocal.id,\n msg.sender,\n loanLocal.collateral,\n false,\n \"\" // loanDataBytes\n );\n } else {\n // pay out reward to caller\n loanLocal.collateral = loanLocal.collateral.sub(rolloverReward);\n\n _withdrawAsset(loanParamsLocal.collateralToken, msg.sender, rolloverReward);\n }\n }\n\n if (loanLocal.collateral > 0) {\n //close whole loan if tiny position will remain\n if (_getAmountInRbtc(loanParamsLocal.loanToken, loanLocal.principal) <= TINY_AMOUNT) {\n _closeWithSwap(\n loanLocal.id,\n loanLocal.borrower,\n loanLocal.collateral, // swap all collaterals\n false,\n \"\" /// loanDataBytes\n );\n } else {\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n require(\n currentMargin > 3 ether, // ensure there's more than 3% margin remaining\n \"unhealthy position\"\n );\n }\n }\n\n if (loanLocal.active) {\n emit Rollover(\n loanLocal.borrower, // user (borrower)\n loanLocal.lender, // lender\n loanLocal.id, // loanId\n loanLocal.principal, // principal\n loanLocal.collateral, // collateral\n loanLocal.endTimestamp, // endTimestamp\n msg.sender, // rewardReceiver\n rolloverReward // reward\n );\n }\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsShared.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/RewardHelper.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\n/**\n * @title LoanClosingsShared contract.\n * @notice This contract should only contains the internal function that is being used / utilized by\n * LoanClosingsLiquidation, LoanClosingsRollover & LoanClosingsWith contract\n *\n * */\ncontract LoanClosingsShared is\n LoanClosingsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n RewardHelper,\n ModuleCommonFunctionalities\n{\n uint256 internal constant MONTH = 365 days / 12;\n //0.00001 BTC, would be nicer in State.sol, but would require a redeploy of the complete protocol, so adding it here instead\n //because it's not shared state anyway and only used by this contract\n uint256 public constant paySwapExcessToBorrowerThreshold = 10000000000000;\n\n uint256 public constant TINY_AMOUNT = 25e13;\n\n enum CloseTypes { Deposit, Swap, Liquidation }\n\n /** modifier for invariant check */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n Loan storage loanLocal = loans[loanId];\n\n require(loanLocal.lender != address(0), \"Invalid loan token pool address\");\n\n uint256 previousITokenSupply = ILoanTokenModules(loanLocal.lender).totalSupply();\n\n _;\n\n /// Validate iToken total supply\n require(\n previousITokenSupply == ILoanTokenModules(loanLocal.lender).totalSupply(),\n \"loan token supply invariant check failure\"\n );\n }\n\n /**\n * @dev computes the interest which needs to be refunded to the borrower based on the amount he's closing and either\n * subtracts it from the amount which still needs to be paid back (in case outstanding amount > interest) or withdraws the\n * excess to the borrower (in case interest > outstanding).\n * @param loanLocal the loan\n * @param loanParamsLocal the loan params\n * @param loanCloseAmount the amount to be closed (base for the computation)\n * @param receiver the address of the receiver (usually the borrower)\n * */\n function _settleInterestToPrincipal(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 loanCloseAmount,\n address receiver\n ) internal returns (uint256) {\n uint256 loanCloseAmountLessInterest = loanCloseAmount;\n\n //compute the interest which neeeds to be refunded to the borrower (because full interest is paid on loan )\n uint256 interestRefundToBorrower =\n _settleInterest(loanParamsLocal, loanLocal, loanCloseAmountLessInterest);\n\n uint256 interestAppliedToPrincipal;\n //if the outstanding loan is bigger than the interest to be refunded, reduce the amount to be paid back / closed by the interest\n if (loanCloseAmountLessInterest >= interestRefundToBorrower) {\n // apply all of borrower interest refund torwards principal\n interestAppliedToPrincipal = interestRefundToBorrower;\n\n // principal needed is reduced by this amount\n loanCloseAmountLessInterest -= interestRefundToBorrower;\n\n // no interest refund remaining\n interestRefundToBorrower = 0;\n } else {\n //if the interest refund is bigger than the outstanding loan, the user needs to get back the interest\n // principal fully covered by excess interest\n interestAppliedToPrincipal = loanCloseAmountLessInterest;\n\n // amount refunded is reduced by this amount\n interestRefundToBorrower -= loanCloseAmountLessInterest;\n\n // principal fully covered by excess interest\n loanCloseAmountLessInterest = 0;\n\n if (interestRefundToBorrower != 0) {\n // refund overage\n _withdrawAsset(loanParamsLocal.loanToken, receiver, interestRefundToBorrower);\n }\n }\n\n //pay the interest to the lender\n //note: this is a waste of gas, because the loanCloseAmountLessInterest is withdrawn to the lender, too. It could be done at once.\n if (interestAppliedToPrincipal != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, interestAppliedToPrincipal);\n }\n\n return loanCloseAmountLessInterest;\n }\n\n // The receiver always gets back an ERC20 (even wrbtc)\n function _returnPrincipalWithDeposit(\n address loanToken,\n address receiver,\n uint256 principalNeeded\n ) internal {\n if (principalNeeded != 0) {\n if (msg.value == 0) {\n vaultTransfer(loanToken, msg.sender, receiver, principalNeeded);\n } else {\n require(loanToken == address(wrbtcToken), \"wrong asset sent\");\n require(msg.value >= principalNeeded, \"not enough ether\");\n wrbtcToken.deposit.value(principalNeeded)();\n if (receiver != address(this)) {\n vaultTransfer(loanToken, address(this), receiver, principalNeeded);\n }\n if (msg.value > principalNeeded) {\n // refund overage\n Address.sendValue(msg.sender, msg.value - principalNeeded);\n }\n }\n } else {\n require(msg.value == 0, \"wrong asset sent\");\n }\n }\n\n /**\n * @dev checks if the amount of the asset to be transfered is worth the transfer fee\n * @param asset the asset to be transfered\n * @param amount the amount to be transfered\n * @return True if the amount is bigger than the threshold\n * */\n function worthTheTransfer(address asset, uint256 amount) internal returns (bool) {\n uint256 amountInRbtc = _getAmountInRbtc(asset, amount);\n emit swapExcess(\n amountInRbtc > paySwapExcessToBorrowerThreshold,\n amount,\n amountInRbtc,\n paySwapExcessToBorrowerThreshold\n );\n\n return amountInRbtc > paySwapExcessToBorrowerThreshold;\n }\n\n /**\n * swaps collateral tokens for loan tokens\n * @param loanLocal the loan object\n * @param loanParamsLocal the loan parameters\n * @param swapAmount the amount to be swapped\n * @param principalNeeded the required destination token amount\n * @param returnTokenIsCollateral if true -> required destination token amount will be passed on, else not\n * note: quite dirty. should be refactored.\n * @param loanDataBytes additional loan data (not in use for token swaps)\n * */\n function _doCollateralSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n loanLocal.collateral, // maxSourceTokenAmount\n returnTokenIsCollateral\n ? principalNeeded // requiredDestTokenAmount\n : 0,\n false, // bypassFee\n loanDataBytes\n );\n require(destTokenAmountReceived >= principalNeeded, \"insufficient dest amount\");\n require(sourceTokenAmountUsed <= loanLocal.collateral, \"excessive source amount\");\n }\n\n /**\n * @notice Withdraw asset to receiver.\n *\n * @param assetToken The loan token.\n * @param receiver The address of the receiver.\n * @param assetAmount The loan token amount.\n * */\n function _withdrawAsset(\n address assetToken,\n address receiver,\n uint256 assetAmount\n ) internal {\n if (assetAmount != 0) {\n if (assetToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, assetAmount);\n } else {\n vaultWithdraw(assetToken, receiver, assetAmount);\n }\n }\n }\n\n /**\n * @notice Internal function to close a loan.\n *\n * @param loanLocal The loan object.\n * @param loanCloseAmount The amount to close: principal or lower.\n *\n * */\n function _closeLoan(Loan storage loanLocal, uint256 loanCloseAmount) internal {\n require(loanCloseAmount != 0, \"nothing to close\");\n\n if (loanCloseAmount == loanLocal.principal) {\n loanLocal.principal = 0;\n loanLocal.active = false;\n loanLocal.endTimestamp = block.timestamp;\n loanLocal.pendingTradesId = 0;\n activeLoansSet.removeBytes32(loanLocal.id);\n lenderLoanSets[loanLocal.lender].removeBytes32(loanLocal.id);\n borrowerLoanSets[loanLocal.borrower].removeBytes32(loanLocal.id);\n } else {\n loanLocal.principal = loanLocal.principal.sub(loanCloseAmount);\n }\n }\n\n function _settleInterest(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 closePrincipal\n ) internal returns (uint256) {\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 interestTime = block.timestamp;\n if (interestTime > loanLocal.endTimestamp) {\n interestTime = loanLocal.endTimestamp;\n }\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n interestTime\n );\n\n uint256 owedPerDayRefund;\n if (closePrincipal < loanLocal.principal) {\n owedPerDayRefund = loanInterestLocal.owedPerDay.mul(closePrincipal).div(\n loanLocal.principal\n );\n } else {\n owedPerDayRefund = loanInterestLocal.owedPerDay;\n }\n\n // update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.sub(owedPerDayRefund);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(owedPerDayRefund);\n\n // update borrower interest\n uint256 interestRefundToBorrower = loanLocal.endTimestamp.sub(interestTime);\n interestRefundToBorrower = interestRefundToBorrower.mul(owedPerDayRefund);\n interestRefundToBorrower = interestRefundToBorrower.div(1 days);\n\n if (closePrincipal < loanLocal.principal) {\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(\n interestRefundToBorrower\n );\n } else {\n loanInterestLocal.depositTotal = 0;\n }\n\n // update remaining lender interest values\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.sub(\n closePrincipal\n );\n\n uint256 owedTotal = lenderInterestLocal.owedTotal;\n lenderInterestLocal.owedTotal = owedTotal > interestRefundToBorrower\n ? owedTotal - interestRefundToBorrower\n : 0;\n\n return interestRefundToBorrower;\n }\n\n /**\n * @notice Check sender is borrower or delegatee and loan id exists.\n *\n * @param loanId byte32 of the loan id.\n * */\n function _checkAuthorized(bytes32 loanId) internal view {\n Loan storage loanLocal = loans[loanId];\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n }\n\n /**\n * @notice Internal function for closing a position by swapping the\n * collateral back to loan tokens, paying the lender and withdrawing\n * the remainder.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collatral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid\n * out in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(swapAmount != 0, \"swapAmount == 0\");\n\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't swap more than collateral.\n swapAmount = swapAmount > loanLocal.collateral ? loanLocal.collateral : swapAmount;\n\n //close whole loan if tiny position will remain\n if (loanLocal.collateral - swapAmount > 0) {\n if (\n _getAmountInRbtc(\n loanParamsLocal.collateralToken,\n loanLocal.collateral - swapAmount\n ) <= TINY_AMOUNT\n ) {\n swapAmount = loanLocal.collateral;\n }\n }\n\n uint256 loanCloseAmountLessInterest;\n if (swapAmount == loanLocal.collateral || returnTokenIsCollateral) {\n /// loanCloseAmountLessInterest will be passed as required amount amount of destination tokens.\n /// this means, the actual swapAmount passed to the swap contract does not matter at all.\n /// the source token amount will be computed depending on the required amount amount of destination tokens.\n loanCloseAmount = swapAmount == loanLocal.collateral\n ? loanLocal.principal\n : loanLocal.principal.mul(swapAmount).div(loanLocal.collateral);\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Computes the interest refund for the borrower and sends it to the lender to cover part of the principal.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n } else {\n /// loanCloseAmount is calculated after swap; for this case we want to swap the entire source amount\n /// and determine the loanCloseAmount and withdraw amount based on that.\n loanCloseAmountLessInterest = 0;\n }\n\n uint256 coveredPrincipal;\n uint256 usedCollateral;\n\n /// swapAmount repurposed for collateralToLoanSwapRate to avoid stack too deep error.\n (coveredPrincipal, usedCollateral, withdrawAmount, swapAmount) = _coverPrincipalWithSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount, /// The amount of source tokens to swap (only matters if !returnTokenIsCollateral or loanCloseAmountLessInterest = 0)\n loanCloseAmountLessInterest, /// This is the amount of destination tokens we want to receive (only matters if returnTokenIsCollateral)\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (loanCloseAmountLessInterest == 0) {\n /// Condition prior to swap: swapAmount != loanLocal.collateral && !returnTokenIsCollateral\n\n /// Amounts that is closed.\n loanCloseAmount = coveredPrincipal;\n if (coveredPrincipal != loanLocal.principal) {\n loanCloseAmount = loanCloseAmount.mul(usedCollateral).div(loanLocal.collateral);\n }\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Amount that is returned to the lender.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n\n /// Remaining amount withdrawn to the receiver.\n withdrawAmount = withdrawAmount.add(coveredPrincipal).sub(loanCloseAmountLessInterest);\n } else {\n /// Pay back the amount which was covered by the swap.\n loanCloseAmountLessInterest = coveredPrincipal;\n }\n\n require(loanCloseAmountLessInterest != 0, \"closeAmount is 0 after swap\");\n\n /// Reduce the collateral by the amount which was swapped for the closure.\n if (usedCollateral != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(usedCollateral);\n }\n\n /// Repays principal to lender.\n /// The lender always gets back an ERC20 (even wrbtc), so we call\n /// withdraw directly rather than use the _withdrawAsset helper function.\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, loanCloseAmountLessInterest);\n\n withdrawToken = returnTokenIsCollateral\n ? loanParamsLocal.collateralToken\n : loanParamsLocal.loanToken;\n\n if (withdrawAmount != 0) {\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n usedCollateral,\n swapAmount, /// collateralToLoanSwapRate\n CloseTypes.Swap\n );\n }\n\n /**\n * @notice Close a loan.\n *\n * @dev Wrapper for _closeLoan internal function.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan params.\n * @param loanCloseAmount The amount to close: principal or lower.\n * @param collateralCloseAmount The amount of collateral to close.\n * @param collateralToLoanSwapRate The price rate collateral/loan token.\n * @param closeType The type of loan close.\n * */\n function _finalizeClose(\n Loan storage loanLocal,\n LoanParams storage loanParamsLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanSwapRate,\n CloseTypes closeType\n ) internal {\n _closeLoan(loanLocal, loanCloseAmount);\n\n address _priceFeeds = priceFeeds;\n uint256 currentMargin;\n uint256 collateralToLoanRate;\n\n /// This is still called even with full loan close to return collateralToLoanRate\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).getCurrentMargin.selector,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n )\n );\n assembly {\n if eq(success, 1) {\n currentMargin := mload(add(data, 32))\n collateralToLoanRate := mload(add(data, 64))\n }\n }\n /// Note: We can safely skip the margin check if closing\n /// via closeWithDeposit or if closing the loan in full by any method.\n require(\n closeType == CloseTypes.Deposit ||\n loanLocal.principal == 0 || /// loan fully closed\n currentMargin > loanParamsLocal.maintenanceMargin,\n \"unhealthy position\"\n );\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n collateralCloseAmount,\n collateralToLoanRate,\n collateralToLoanSwapRate,\n currentMargin,\n closeType\n );\n }\n\n /**\n * swaps a share of a loan's collateral or the complete collateral in order to cover the principle.\n * @param loanLocal the loan\n * @param loanParamsLocal the loan parameters\n * @param swapAmount in case principalNeeded == 0 or !returnTokenIsCollateral, this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens needed for the swap is estimated by the connector.\n * @param principalNeeded the required amount of destination tokens in order to cover the principle (only used if returnTokenIsCollateral)\n * @param returnTokenIsCollateral tells if the user wants to withdraw his remaining collateral + profit in collateral tokens\n * @notice Swaps a share of a loan's collateral or the complete collateral\n * in order to cover the principle.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount In case principalNeeded == 0 or !returnTokenIsCollateral,\n * this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens\n * needed for the swap is estimated by the connector.\n * @param principalNeeded The required amount of destination tokens in order to\n * cover the principle (only used if returnTokenIsCollateral).\n * @param returnTokenIsCollateral Tells if the user wants to withdraw his\n * remaining collateral + profit in collateral tokens.\n *\n * @return coveredPrincipal The amount of principal that is covered.\n * @return usedCollateral The amount of collateral used.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _coverPrincipalWithSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 coveredPrincipal,\n uint256 usedCollateral,\n uint256 withdrawAmount,\n uint256 collateralToLoanSwapRate\n )\n {\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n (\n destTokenAmountReceived,\n sourceTokenAmountUsed,\n collateralToLoanSwapRate\n ) = _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount,\n principalNeeded,\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (returnTokenIsCollateral) {\n coveredPrincipal = principalNeeded;\n\n /// Better fill than expected.\n if (destTokenAmountReceived > coveredPrincipal) {\n /// Send excess to borrower if the amount is big enough to be\n /// worth the gas fees.\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - coveredPrincipal\n )\n ) {\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n destTokenAmountReceived - coveredPrincipal\n );\n }\n /// Else, give the excess to the lender (if it goes to the\n /// borrower, they're very confused. causes more trouble than it's worth)\n else {\n coveredPrincipal = destTokenAmountReceived;\n }\n }\n withdrawAmount = swapAmount > sourceTokenAmountUsed\n ? swapAmount - sourceTokenAmountUsed\n : 0;\n } else {\n require(sourceTokenAmountUsed == swapAmount, \"swap error\");\n\n if (swapAmount == loanLocal.collateral) {\n /// sourceTokenAmountUsed == swapAmount == loanLocal.collateral\n\n coveredPrincipal = principalNeeded;\n withdrawAmount = destTokenAmountReceived - principalNeeded;\n } else {\n /// sourceTokenAmountUsed == swapAmount < loanLocal.collateral\n\n if (destTokenAmountReceived >= loanLocal.principal) {\n /// Edge case where swap covers full principal.\n\n coveredPrincipal = loanLocal.principal;\n withdrawAmount = destTokenAmountReceived - loanLocal.principal;\n\n /// Excess collateral refunds to the borrower.\n _withdrawAsset(\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n loanLocal.collateral - sourceTokenAmountUsed\n );\n sourceTokenAmountUsed = loanLocal.collateral;\n } else {\n coveredPrincipal = destTokenAmountReceived;\n withdrawAmount = 0;\n }\n }\n }\n\n usedCollateral = sourceTokenAmountUsed > swapAmount ? sourceTokenAmountUsed : swapAmount;\n }\n\n function _emitClosingEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanRate,\n uint256 collateralToLoanSwapRate,\n uint256 currentMargin,\n CloseTypes closeType\n ) internal {\n if (closeType == CloseTypes.Deposit) {\n emit CloseWithDeposit(\n loanLocal.borrower, /// user (borrower)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n msg.sender, /// closer\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n loanCloseAmount, /// loanCloseAmount\n collateralCloseAmount, /// collateralCloseAmount\n collateralToLoanRate, /// collateralToLoanRate\n currentMargin /// currentMargin\n );\n } else if (closeType == CloseTypes.Swap) {\n /// exitPrice = 1 / collateralToLoanSwapRate\n if (collateralToLoanSwapRate != 0) {\n collateralToLoanSwapRate = SafeMath.div(10**36, collateralToLoanSwapRate);\n }\n\n /// currentLeverage = 100 / currentMargin\n if (currentMargin != 0) {\n currentMargin = SafeMath.div(10**38, currentMargin);\n }\n\n emit CloseWithSwap(\n loanLocal.borrower, /// user (trader)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n msg.sender, /// closer\n collateralCloseAmount, /// positionCloseSize\n loanCloseAmount, /// loanCloseAmount\n collateralToLoanSwapRate, /// exitPrice (1 / collateralToLoanSwapRate)\n currentMargin /// currentLeverage\n );\n } else if (closeType == CloseTypes.Liquidation) {\n emit Liquidate(\n loanLocal.borrower, // user (borrower)\n msg.sender, // liquidator\n loanLocal.id, // loanId\n loanLocal.lender, // lender\n loanParamsLocal.loanToken, // loanToken\n loanParamsLocal.collateralToken, // collateralToken\n loanCloseAmount, // loanCloseAmount\n collateralCloseAmount, // collateralCloseAmount\n collateralToLoanRate, // collateralToLoanRate\n currentMargin // currentMargin\n );\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal view returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n IPriceFeeds(priceFeeds).queryRate(asset, address(wrbtcToken));\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /**\n * @dev private function which check the loanLocal & loanParamsLocal does exist\n *\n * @param loanId bytes32 of loanId\n *\n * @return Loan storage\n * @return LoanParams storage\n */\n function _checkLoan(bytes32 loanId) internal view returns (Loan storage, LoanParams storage) {\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n return (loanLocal, loanParamsLocal);\n }\n}\n" + }, + "contracts/modules/LoanClosingsWith.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsWith contract.\n * @notice Close a loan w/deposit, close w/swap. There are 2 functions for ending a loan on the\n * protocol contract: closeWithSwap and closeWithDeposit. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsWith is LoanClosingsShared {\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n\n /**\n * @notice Closes a loan by doing a deposit.\n *\n * @dev Public wrapper for _closeWithDeposit internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens. (e.g. rBTC on a iSUSD contract).\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n public\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return _closeWithDeposit(loanId, receiver, depositAmount);\n }\n\n /**\n * @notice Close a position by swapping the collateral back to loan tokens\n * paying the lender and withdrawing the remainder.\n *\n * @dev Public wrapper for _closeWithSwap internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collateral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid out\n * in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes memory // for future use /*loanDataBytes*/\n )\n public\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return\n _closeWithSwap(\n loanId,\n receiver,\n swapAmount,\n returnTokenIsCollateral,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for closing a loan by doing a deposit.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens.\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(depositAmount != 0, \"depositAmount == 0\");\n\n //TODO should we skip this check if invoked from rollover ?\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't close more than the full principal.\n loanCloseAmount = depositAmount > loanLocal.principal\n ? loanLocal.principal\n : depositAmount;\n\n //revert if tiny position remains\n uint256 remainingAmount = loanLocal.principal - loanCloseAmount;\n if (remainingAmount > 0) {\n require(\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount) > TINY_AMOUNT,\n \"Tiny amount when closing with deposit\"\n );\n }\n\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(loanLocal, loanParamsLocal, loanCloseAmount, receiver);\n\n if (loanCloseAmountLessInterest != 0) {\n _returnPrincipalWithDeposit(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmount == loanLocal.principal) {\n withdrawAmount = loanLocal.collateral;\n } else {\n withdrawAmount = loanLocal.collateral.mul(loanCloseAmount).div(loanLocal.principal);\n }\n\n withdrawToken = loanParamsLocal.collateralToken;\n\n if (withdrawAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(withdrawAmount);\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n withdrawAmount, /// collateralCloseAmount\n 0, /// collateralToLoanSwapRate\n CloseTypes.Deposit\n );\n }\n\n /**\n * @notice Function to check whether the given loanId & deposit amount when closing with deposit will cause the tiny position\n *\n * @param loanId The id of the loan.\n * @param depositAmount Defines how much the deposit amount to close the position.\n *\n * @return isTinyPosition true is indicating tiny position, false otherwise.\n * @return tinyPositionAmount will return 0 for non tiny position, and will return the amount of tiny position if true\n */\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount)\n {\n (Loan memory loanLocal, LoanParams memory loanParamsLocal) = _checkLoan(loanId);\n\n if (depositAmount < loanLocal.principal) {\n uint256 remainingAmount = loanLocal.principal - depositAmount;\n uint256 remainingRBTCAmount =\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingRBTCAmount < TINY_AMOUNT) {\n isTinyPosition = true;\n tinyPositionAmount = remainingRBTCAmount;\n }\n }\n\n return (isTinyPosition, tinyPositionAmount);\n }\n}\n" + }, + "contracts/modules/LoanMaintenance.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Maintenance contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to query loan data and to modify its status\n * by withdrawing or depositing collateral.\n * */\ncontract LoanMaintenance is\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n LiquidationHelper,\n ModuleCommonFunctionalities\n{\n // Keep the old LoanReturnData for backward compatibility (especially for the watcher)\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n // The new struct which contained borrower & creation time of a loan\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set initial values of proxy targets.\n *\n * @param target The address of the logic contract instance.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.depositCollateral.selector];\n _setTarget(this.depositCollateral.selector, target);\n _setTarget(this.withdrawCollateral.selector, target);\n _setTarget(this.withdrawAccruedInterest.selector, target);\n _setTarget(this.extendLoanDuration.selector, target);\n _setTarget(this.reduceLoanDuration.selector, target);\n _setTarget(this.getLenderInterestData.selector, target);\n _setTarget(this.getLoanInterestData.selector, target);\n _setTarget(this.getUserLoans.selector, target);\n _setTarget(this.getUserLoansV2.selector, target);\n _setTarget(this.getLoan.selector, target);\n _setTarget(this.getLoanV2.selector, target);\n _setTarget(this.getActiveLoans.selector, target);\n _setTarget(this.getActiveLoansV2.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanMaintenance\");\n }\n\n /**\n * @notice Increase the margin of a position by depositing additional collateral.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount /// must match msg.value if ether is sent\n ) external payable nonReentrant whenNotPaused {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.value == 0 || loanParamsLocal.collateralToken == address(wrbtcToken),\n \"wrong asset sent\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(depositAmount);\n\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.collateralToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n\n (uint256 collateralToLoanRate, ) =\n IPriceFeeds(priceFeeds).queryRate(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n\n emit DepositCollateral(loanId, depositAmount, collateralToLoanRate);\n }\n\n /**\n * @notice Withdraw from the collateral. This reduces the margin of a position.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 actualWithdrawAmount) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral,\n loanParamsLocal.maintenanceMargin\n );\n\n if (withdrawAmount > maxDrawdown) {\n actualWithdrawAmount = maxDrawdown;\n } else {\n actualWithdrawAmount = withdrawAmount;\n }\n\n loanLocal.collateral = loanLocal.collateral.sub(actualWithdrawAmount);\n\n if (loanParamsLocal.collateralToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, actualWithdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.collateralToken, receiver, actualWithdrawAmount);\n }\n }\n\n /**\n * @notice Withdraw accrued loan interest.\n *\n * @dev Wrapper for _payInterest internal function.\n *\n * @param loanToken The loan token address.\n * */\n function withdrawAccruedInterest(address loanToken) external whenNotPaused {\n /// Pay outstanding interest to lender.\n _payInterest(\n msg.sender, /// Lender.\n loanToken\n );\n }\n\n /**\n * @notice Extend the loan duration by as much time as depositAmount can buy.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in loan tokens. Used to pay the interest for the new duration.\n * @param useCollateral Whether pay interests w/ the collateral. If true, depositAmount of loan tokens\n *\t\t\t\t\t\twill be purchased with the collateral.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n *\n * @return secondsExtended The amount of time in seconds the loan is extended.\n * */\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external payable nonReentrant whenNotPaused returns (uint256 secondsExtended) {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n !useCollateral ||\n msg.sender == loanLocal.borrower ||\n delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(\n msg.value == 0 || (!useCollateral && loanParamsLocal.loanToken == address(wrbtcToken)),\n \"wrong asset sent\"\n );\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n /// Handle back interest: calculates interest owned since the loan\n /// endtime passed but the loan remained open.\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestOwed = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestOwed.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(86400);\n\n require(depositAmount > backInterestOwed, \"deposit cannot cover back interest\");\n }\n\n /// Deposit interest.\n if (useCollateral) {\n /// Used the whole converted loanToken to extend the loan duration\n depositAmount = _doCollateralSwap(loanLocal, loanParamsLocal, depositAmount);\n } else {\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.loanToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n }\n\n if (backInterestOwed != 0) {\n depositAmount = depositAmount.sub(backInterestOwed);\n\n /// Pay out backInterestOwed\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n secondsExtended = depositAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(secondsExtended);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(depositAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .add(depositAmount);\n }\n\n /**\n * @notice Reduce the loan duration by withdrawing from the deposited interest.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in loan tokens.\n *\n * @return secondsReduced The amount of time in seconds the loan is reduced.\n * */\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 secondsReduced) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(loanLocal.endTimestamp > block.timestamp, \"loan term has ended\");\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 interestDepositRemaining =\n loanLocal.endTimestamp.sub(block.timestamp).mul(loanInterestLocal.owedPerDay).div(\n 86400\n );\n require(withdrawAmount < interestDepositRemaining, \"withdraw amount too high\");\n\n /// Withdraw interest.\n if (loanParamsLocal.loanToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, withdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.loanToken, receiver, withdrawAmount);\n }\n\n secondsReduced = withdrawAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n require(loanLocal.endTimestamp > secondsReduced, \"loan too short\");\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.sub(secondsReduced);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(withdrawAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .sub(withdrawAmount);\n }\n\n /**\n * @notice Get current lender interest data totals for all loans\n * with a specific oracle and interest token.\n *\n * @param lender The lender address.\n * @param loanToken The loan token address.\n *\n * @return interestPaid The total amount of interest that has been paid to a lender so far.\n * @return interestPaidDate The date of the last interest pay out, or 0 if no interest has been withdrawn yet.\n * @return interestOwedPerDay The amount of interest the lender is earning per day.\n * @return interestUnPaid The total amount of interest the lender is owned and not yet withdrawn.\n * @return interestFeePercent The fee retained by the protocol before interest is paid to the lender.\n * @return principalTotal The total amount of outstanding principal the lender has loaned.\n * */\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n )\n {\n LenderInterest memory lenderInterestLocal = lenderInterest[lender][loanToken];\n\n interestUnPaid = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(86400);\n if (interestUnPaid > lenderInterestLocal.owedTotal)\n interestUnPaid = lenderInterestLocal.owedTotal;\n\n return (\n lenderInterestLocal.paidTotal,\n lenderInterestLocal.paidTotal != 0 ? lenderInterestLocal.updatedTimestamp : 0,\n lenderInterestLocal.owedPerDay,\n lenderInterestLocal.updatedTimestamp != 0 ? interestUnPaid : 0,\n lendingFeePercent,\n lenderInterestLocal.principalTotal\n );\n }\n\n /**\n * @notice Get current interest data for a loan.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loanToken The loan token that interest is paid in.\n * @return interestOwedPerDay The amount of interest the borrower is paying per day.\n * @return interestDepositTotal The total amount of interest the borrower has deposited.\n * @return interestDepositRemaining The amount of deposited interest that is not yet owed to a lender.\n * */\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n )\n {\n loanToken = loanParams[loans[loanId].loanParamsId].loanToken;\n interestOwedPerDay = loanInterest[loanId].owedPerDay;\n interestDepositTotal = loanInterest[loanId].depositTotal;\n\n uint256 endTimestamp = loans[loanId].endTimestamp;\n uint256 interestTime = block.timestamp > endTimestamp ? endTimestamp : block.timestamp;\n interestDepositRemaining = endTimestamp > interestTime\n ? endTimestamp.sub(interestTime).mul(interestOwedPerDay).div(86400)\n : 0;\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData) {\n return\n _getLoan(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2) {\n return\n _getLoanV2(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get all active loans.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @dev New view function which will return the loan data.\n * @dev This function was created to support backward compatibility\n * @dev As in we the old getActiveLoans function is not expected to be changed by the wathcers.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loanData The data structure\n * @return extendedLoanData The data structure which contained (borrower & creation time)\n */\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Internal function to get one loan data structure.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ the loan information.\n * */\n function _getLoan(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnData memory loanData) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanData;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanData;\n }\n\n return\n LoanReturnData({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable\n });\n }\n\n /**\n * @notice Internal function to get one loan data structure v2.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data v2 structure w/ the loan information.\n * */\n function _getLoanV2(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnDataV2 memory loanDataV2) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanDataV2;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanDataV2;\n }\n\n return\n LoanReturnDataV2({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n borrower: loanLocal.borrower,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable,\n creationTimestamp: loanLocal.startTimestamp\n });\n }\n\n /**\n * @notice Internal function to collect interest from the collateral.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param depositAmount The amount of underlying tokens provided on the loan.\n * */\n function _doCollateralSwap(\n Loan storage loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 depositAmount\n ) internal returns (uint256 purchasedLoanToken) {\n /// Reverts in _loanSwap if amountNeeded can't be bought.\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanLocal.collateral, /// minSourceTokenAmount\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n depositAmount, /// requiredDestTokenAmount (partial spend of loanLocal.collateral to fill this amount)\n true, /// bypassFee\n \"\" /// loanDataBytes\n );\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n /// Ensure the loan is still healthy.\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n return destTokenAmountReceived;\n }\n}\n" + }, + "contracts/modules/LoanOpenings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\n/**\n * @title Loan Openings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to borrow and trade.\n * */\ncontract LoanOpenings is\n LoanOpeningsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n ModuleCommonFunctionalities\n{\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\n _setTarget(this.borrowOrTradeFromPool.selector, target);\n _setTarget(this.setDelegatedManager.selector, target);\n _setTarget(this.getEstimatedMarginExposure.selector, target);\n _setTarget(this.getRequiredCollateral.selector, target);\n _setTarget(this.getBorrowAmount.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanOpenings\");\n }\n\n /**\n * @notice Borrow or trade from pool.\n *\n * @dev Note: Only callable by loan pools (iTokens).\n * Wrapper to _borrowOrTrade internal function.\n *\n * @param loanParamsId The ID of the loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return newPrincipal The new loan size.\n * @return newCollateral The new collateral amount.\n * */\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n bytes calldata loanDataBytes\n )\n external\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 newPrincipal, uint256 newCollateral)\n {\n require(msg.value == 0 || loanDataBytes.length != 0, \"loanDataBytes required with ether\");\n\n /// Only callable by loan pools.\n require(loanPoolToUnderlying[msg.sender] != address(0), \"not authorized\");\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n /// Get required collateral.\n uint256 collateralAmountRequired =\n _getRequiredCollateral(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentValues.newPrincipal,\n initialMargin,\n isTorqueLoan\n );\n require(collateralAmountRequired != 0, \"collateral is 0\");\n\n return\n _borrowOrTrade(\n loanParamsLocal,\n loanId,\n isTorqueLoan,\n collateralAmountRequired,\n initialMargin,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @dev Wrapper for _setDelegatedManager internal function.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external whenNotPaused {\n require(loans[loanId].borrower == msg.sender, \"unauthorized\");\n\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\n }\n\n /**\n * @notice Get the estimated margin exposure.\n *\n * Margin is the money borrowed from a broker to purchase an investment\n * and is the difference between the total value of investment and the\n * loan amount. Margin trading refers to the practice of using borrowed\n * funds from a broker to trade a financial asset, which forms the\n * collateral for the loan from the broker.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param loanTokenSent The amount of loan tokens sent.\n * @param collateralTokenSent The amount of collateral tokens sent.\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\n * @param newPrincipal The updated amount of principal (current debt).\n *\n * @return The margin exposure.\n * */\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256) {\n uint256 maxLoanTerm = 2419200; // 28 days\n\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\n\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\n\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\n uint256 tradingFee = _getTradingFee(swapAmount);\n if (tradingFee != 0) {\n swapAmount = swapAmount.sub(tradingFee);\n }\n\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\n if (receivedAmount == 0) {\n return 0;\n } else {\n return collateralTokenSent.add(receivedAmount);\n }\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Calls internal _getRequiredCollateral and add fees.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralAmountRequired The required collateral.\n * */\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 collateralAmountRequired) {\n if (marginAmount != 0) {\n collateralAmountRequired = _getRequiredCollateral(\n loanToken,\n collateralToken,\n newPrincipal,\n marginAmount,\n isTorqueLoan\n );\n\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n // cannot be applied solely as it drives to some other tests failure\n /*\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (collateralAmountRequired != 0 && feePercent != 0) {\n\t\t\t\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t);\n\t\t\t}*/\n\n uint256 fee =\n isTorqueLoan\n ? _getBorrowingFee(collateralAmountRequired)\n : _getTradingFee(collateralAmountRequired);\n if (fee != 0) {\n collateralAmountRequired = collateralAmountRequired.add(fee);\n }\n }\n }\n\n /**\n * @notice Get the borrow amount of a trade loan.\n *\n * @dev Basically borrowAmount = collateral / marginAmount\n *\n * Collateral is something that helps secure a loan. When you borrow money,\n * you agree that your lender can take something and sell it to get their\n * money back if you fail to repay the loan. That's the collateral.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param collateralTokenAmount The amount of collateral.\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return borrowAmount The borrow amount.\n * */\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 borrowAmount) {\n if (marginAmount != 0) {\n if (isTorqueLoan) {\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\n }\n uint256 collateral = collateralTokenAmount;\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\n if (fee != 0) {\n collateral = collateral.sub(fee);\n }\n if (loanToken == collateralToken) {\n borrowAmount = collateral.mul(10**20).div(marginAmount);\n } else {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestPrecision != 0) {\n borrowAmount = collateral\n .mul(10**20)\n .mul(sourceToDestRate)\n .div(marginAmount)\n .div(sourceToDestPrecision);\n }\n }\n /*\n\t\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t\t// cannot be applied solely as it drives to some other tests failure\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (borrowAmount != 0 && feePercent != 0) {\n\t\t\t\tborrowAmount = borrowAmount\n\t\t\t\t\t.mul(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t)\n\t\t\t\t\t.divCeil(10**20);\n\t\t\t}*/\n }\n }\n\n /**\n * @notice Borrow or trade.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param collateralAmountRequired The required amount of collateral.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return The new loan size.\n * @return The new collateral amount.\n * */\n function _borrowOrTrade(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 collateralAmountRequired,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n require(\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\n \"collateral/loan match\"\n );\n require(initialMargin >= loanParamsLocal.minInitialMargin, \"initialMargin too low\");\n\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\n require(\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\n \"invalid interest\"\n );\n\n /// Initialize loan.\n Loan storage loanLocal =\n loans[\n _initializeLoan(\n loanParamsLocal,\n loanId,\n initialMargin,\n sentAddresses,\n sentValues.newPrincipal\n )\n ];\n\n // Get required interest.\n uint256 amount =\n _initializeInterest(\n loanParamsLocal,\n loanLocal,\n sentValues.interestRate, /// newRate\n sentValues.newPrincipal, /// newPrincipal,\n sentValues.interestInitialAmount /// torqueInterest\n );\n\n /// substract out interest from usable loanToken sent.\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\n\n if (isTorqueLoan) {\n require(sentValues.loanTokenSent == 0, \"surplus loan token\");\n\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\n // need to temp into local state to avoid\n address _collateralToken = loanParamsLocal.collateralToken;\n address _loanToken = loanParamsLocal.loanToken;\n if (borrowingFee != 0) {\n _payBorrowingFee(\n sentAddresses.borrower, /// borrower\n loanLocal.id,\n _collateralToken, /// fee token\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n borrowingFee\n );\n\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\n }\n } else {\n /// Update collateral after trade.\n uint256 receivedAmount;\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\n loanId,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentAddresses.borrower, /// borrower\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\n false, /// bypassFee\n loanDataBytes\n );\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\n\n /// Check the minEntryPrice with the rate\n require(\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\n \"entry price above the minimum\"\n );\n }\n\n /// Settle collateral.\n require(\n _isCollateralSatisfied(\n loanParamsLocal,\n loanLocal,\n initialMargin,\n sentValues.collateralTokenSent,\n collateralAmountRequired\n ),\n \"collateral insufficient\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\n\n if (isTorqueLoan) {\n /// reclaiming variable -> interestDuration\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\n } else {\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\n }\n\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\n\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\n }\n\n /**\n * @notice Finalize an open loan.\n *\n * @dev Finalize it by updating local parameters of the loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _finalizeOpen(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bool isTorqueLoan\n ) internal {\n /// @dev TODO: here the actual used rate and margin should go.\n (uint256 initialMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(initialMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n if (loanLocal.startTimestamp == block.timestamp) {\n uint256 loanToCollateralPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken\n );\n uint256 collateralToLoanPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\n loanLocal.startRate = isTorqueLoan\n ? collateralToLoanRate\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\n }\n\n _emitOpeningEvents(\n loanParamsLocal,\n loanLocal,\n sentAddresses,\n sentValues,\n collateralToLoanRate,\n initialMargin,\n isTorqueLoan\n );\n }\n\n /**\n * @notice Emit the opening events.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n * @param margin The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _emitOpeningEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n uint256 collateralToLoanRate,\n uint256 margin,\n bool isTorqueLoan\n ) internal {\n if (isTorqueLoan) {\n emit Borrow(\n sentAddresses.borrower, /// user (borrower)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n sentValues.newPrincipal, /// newPrincipal\n sentValues.collateralTokenSent, /// newCollateral\n sentValues.interestRate, /// interestRate\n sentValues.interestDuration, /// interestDuration\n collateralToLoanRate, /// collateralToLoanRate,\n margin /// currentMargin\n );\n } else {\n /// currentLeverage = 100 / currentMargin\n margin = SafeMath.div(10**38, margin);\n\n emit Trade(\n sentAddresses.borrower, /// user (trader)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n sentValues.collateralTokenSent, /// positionSize\n sentValues.newPrincipal, /// borrowedAmount\n sentValues.interestRate, /// interestRate,\n loanLocal.endTimestamp, /// settlementDate\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\n sentValues.entryLeverage, /// entryLeverage\n margin /// currentLeverage\n );\n }\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegator The address of previous manager.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function _setDelegatedManager(\n bytes32 loanId,\n address delegator,\n address delegated,\n bool toggle\n ) internal {\n delegatedManagers[loanId][delegated] = toggle;\n\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\n }\n\n /**\n * @notice Calculate whether the collateral is satisfied.\n *\n * @dev Basically check collateral + drawdown >= 98% of required.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param initialMargin The initial amount of margin.\n * @param newCollateral The amount of new collateral.\n * @param collateralAmountRequired The amount of required collateral.\n *\n * @return Whether the collateral is satisfied.\n * */\n function _isCollateralSatisfied(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 initialMargin,\n uint256 newCollateral,\n uint256 collateralAmountRequired\n ) internal view returns (bool) {\n /// Allow at most 2% under-collateralized.\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\n\n if (newCollateral < collateralAmountRequired) {\n /// Check that existing collateral is sufficient coverage.\n if (loanLocal.collateral != 0) {\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral,\n initialMargin\n );\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\n } else {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @notice Initialize a loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan.\n * @param initialMargin The amount of margin of the trade.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\n * @return The loanId.\n * */\n function _initializeLoan(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n uint256 newPrincipal\n ) internal returns (bytes32) {\n require(loanParamsLocal.active, \"loanParams disabled\");\n\n address lender = sentAddresses.lender;\n address borrower = sentAddresses.borrower;\n address manager = sentAddresses.manager;\n\n Loan memory loanLocal;\n\n if (loanId == 0) {\n borrowerNonce[borrower]++;\n loanId = keccak256(\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\n );\n require(loans[loanId].id == 0, \"loan exists\");\n\n loanLocal = Loan({\n id: loanId,\n loanParamsId: loanParamsLocal.id,\n pendingTradesId: 0,\n active: true,\n principal: newPrincipal,\n collateral: 0, /// calculated later\n startTimestamp: block.timestamp,\n endTimestamp: 0, /// calculated later\n startMargin: initialMargin,\n startRate: 0, /// queried later\n borrower: borrower,\n lender: lender\n });\n\n activeLoansSet.addBytes32(loanId);\n lenderLoanSets[lender].addBytes32(loanId);\n borrowerLoanSets[borrower].addBytes32(loanId);\n } else {\n loanLocal = loans[loanId];\n require(\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\n \"loan has ended\"\n );\n require(loanLocal.borrower == borrower, \"borrower mismatch\");\n require(loanLocal.lender == lender, \"lender mismatch\");\n require(loanLocal.loanParamsId == loanParamsLocal.id, \"loanParams mismatch\");\n\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\n }\n\n if (manager != address(0)) {\n _setDelegatedManager(loanId, borrower, manager, true);\n }\n\n loans[loanId] = loanLocal;\n\n return loanId;\n }\n\n /**\n * @notice Initialize a loan interest.\n *\n * @dev A Torque loan is an indefinite-term loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param newRate The new interest rate of the loan.\n * @param newPrincipal The new principal amount of the loan.\n * @param torqueInterest The interest rate of the Torque loan.\n *\n * @return interestAmountRequired The interest amount required.\n * */\n function _initializeInterest(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n uint256 newRate,\n uint256 newPrincipal,\n uint256 torqueInterest /// ignored for fixed-term loans\n ) internal returns (uint256 interestAmountRequired) {\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 previousDepositRemaining;\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\n previousDepositRemaining = loanLocal\n .endTimestamp\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\n .mul(loanInterestLocal.owedPerDay)\n .div(86400);\n }\n\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\n\n /// Update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n\n if (maxLoanTerm == 0) {\n /// Indefinite-term (Torque) loan.\n\n /// torqueInterest != 0 was confirmed earlier.\n loanLocal.endTimestamp = torqueInterest\n .add(previousDepositRemaining)\n .mul(86400)\n .div(loanInterestLocal.owedPerDay)\n .add(block.timestamp);\n\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxLoanTerm > 3600, \"loan too short\");\n\n interestAmountRequired = torqueInterest;\n } else {\n /// Fixed-term loan.\n\n if (loanLocal.endTimestamp == 0) {\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\n }\n\n interestAmountRequired = loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(owedPerDay)\n .div(86400);\n }\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n /// Update remaining lender interest values.\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Basically collateral = newPrincipal * marginAmount\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralTokenAmount The required collateral.\n * */\n function _getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) internal view returns (uint256 collateralTokenAmount) {\n if (loanToken == collateralToken) {\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\n } else {\n /// Using the price feed instead of the swap expected return\n /// because we need the rate in the inverse direction\n /// so the swap is probably farther off than the price feed.\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestRate != 0) {\n collateralTokenAmount = newPrincipal\n .mul(sourceToDestPrecision)\n .div(sourceToDestRate)\n .mul(marginAmount)\n .div(10**20);\n /*TODO: review\n\t\t\t\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\n }\n }\n // ./tests/loan-token/TradingTestToken.test.js\n if (isTorqueLoan && collateralTokenAmount != 0) {\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\n collateralTokenAmount\n );\n }\n }\n}\n" + }, + "contracts/modules/LoanSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to get and set loan parameters.\n * */\ncontract LoanSettings is State, LoanSettingsEvents, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"LoanSettings - fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setupLoanParams.selector];\n _setTarget(this.setupLoanParams.selector, target);\n _setTarget(this.disableLoanParams.selector, target);\n _setTarget(this.getLoanParams.selector, target);\n _setTarget(this.getLoanParamsList.selector, target);\n _setTarget(this.getTotalPrincipal.selector, target);\n _setTarget(this.minInitialMargin.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanSettings\");\n }\n\n /**\n * @notice Setup loan parameters, by looping every loan\n * and populating its parameters.\n *\n * @dev For each loan calls _setupLoanParams internal function.\n *\n * @param loanParamsList The array of loan parameters.\n *\n * @return loanParamsIdList The array of loan parameters IDs.\n * */\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n whenNotPaused\n returns (bytes32[] memory loanParamsIdList)\n {\n loanParamsIdList = new bytes32[](loanParamsList.length);\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsIdList[i] = _setupLoanParams(loanParamsList[i]);\n }\n }\n\n /**\n * @notice Deactivate LoanParams for future loans. Active loans\n * using it are unaffected.\n *\n * @param loanParamsIdList The array of loan parameters IDs to deactivate.\n * */\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external whenNotPaused {\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n require(msg.sender == loanParams[loanParamsIdList[i]].owner, \"unauthorized owner\");\n loanParams[loanParamsIdList[i]].active = false;\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n emit LoanParamsDisabled(\n loanParamsLocal.id,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdDisabled(loanParamsLocal.id, loanParamsLocal.owner);\n }\n }\n\n /**\n * @notice Get loan parameters for every matching IDs.\n *\n * @param loanParamsIdList The array of loan parameters IDs to match.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParams(bytes32[] memory loanParamsIdList)\n public\n view\n returns (LoanParams[] memory loanParamsList)\n {\n loanParamsList = new LoanParams[](loanParamsIdList.length);\n uint256 itemCount;\n\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n if (loanParamsLocal.id == 0) {\n continue;\n }\n loanParamsList[itemCount] = loanParamsLocal;\n itemCount++;\n }\n\n if (itemCount < loanParamsList.length) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get loan parameters for an owner and a given page\n * defined by an offset and a limit.\n *\n * @param owner The address of the loan owner.\n * @param start The page offset.\n * @param count The page limit.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList) {\n EnumerableBytes32Set.Bytes32Set storage set = userLoanParamSets[owner];\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loanParamsList;\n }\n\n loanParamsList = new bytes32[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n loanParamsList[itemCount] = set.get(i + start - 1);\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get the total principal of the loans by a lender.\n *\n * @param lender The address of the lender.\n * @param loanToken The address of the token instance.\n *\n * @return The total principal of the loans.\n * */\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256) {\n return lenderInterest[lender][loanToken].principalTotal;\n }\n\n /**\n * @notice Setup a loan parameters.\n *\n * @param loanParamsLocal The loan parameters.\n *\n * @return loanParamsId The loan parameters ID.\n * */\n function _setupLoanParams(LoanParams memory loanParamsLocal) internal returns (bytes32) {\n bytes32 loanParamsId =\n keccak256(\n abi.encodePacked(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm,\n block.timestamp\n )\n );\n require(loanParams[loanParamsId].id == 0, \"loanParams exists\");\n\n require(\n loanParamsLocal.loanToken != address(0) &&\n loanParamsLocal.collateralToken != address(0) &&\n loanParamsLocal.minInitialMargin > loanParamsLocal.maintenanceMargin &&\n (loanParamsLocal.maxLoanTerm == 0 || loanParamsLocal.maxLoanTerm > 3600), /// A defined maxLoanTerm has to be greater than one hour.\n \"invalid params\"\n );\n\n loanParamsLocal.id = loanParamsId;\n loanParamsLocal.active = true;\n loanParamsLocal.owner = msg.sender;\n\n loanParams[loanParamsId] = loanParamsLocal;\n userLoanParamSets[msg.sender].addBytes32(loanParamsId);\n\n emit LoanParamsSetup(\n loanParamsId,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdSetup(loanParamsId, loanParamsLocal.owner);\n\n return loanParamsId;\n }\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256) {\n return loanParams[loanParamsId].minInitialMargin;\n }\n}\n" + }, + "contracts/modules/ProtocolSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../mixins/ProtocolTokenUser.sol\";\nimport \"../modules/interfaces/ProtocolSwapExternalInterface.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../governance/IFeeSharingCollector.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title Protocol Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to customize protocol settings.\n * */\ncontract ProtocolSettings is\n State,\n ProtocolTokenUser,\n ProtocolSettingsEvents,\n ModuleCommonFunctionalities\n{\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyAdminOrOwner {\n address prevModuleContractAddress = logicTargets[this.setPriceFeedContract.selector];\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n _setTarget(this.setRebatePercent.selector, target);\n _setTarget(this.setSpecialRebates.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.togglePaused.selector, target);\n _setTarget(this.isProtocolPaused.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n _setTarget(this.setRolloverFlexFeePercent.selector, target);\n _setTarget(this.getDefaultPathConversion.selector, target);\n _setTarget(this.setDefaultPathConversion.selector, target);\n _setTarget(this.removeDefaultPathConversion.selector, target);\n _setTarget(this.setAdmin.selector, target);\n _setTarget(this.getAdmin.selector, target);\n _setTarget(this.setPauser.selector, target);\n _setTarget(this.getPauser.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"ProtocolSettings\");\n }\n\n /**\n * setting wrong address will break inter module functions calling\n * should be set once\n */\n function setSovrynProtocolAddress(address newProtocolAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address oldProtocolAddress = protocolAddress;\n protocolAddress = newProtocolAddress;\n\n emit SetProtocolAddress(msg.sender, oldProtocolAddress, newProtocolAddress);\n }\n\n function setSOVTokenAddress(address newSovTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newSovTokenAddress), \"newSovTokenAddress not a contract\");\n\n address oldTokenAddress = sovTokenAddress;\n sovTokenAddress = newSovTokenAddress;\n\n emit SetSOVTokenAddress(msg.sender, oldTokenAddress, newSovTokenAddress);\n }\n\n function setLockedSOVAddress(address newLockedSOVAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newLockedSOVAddress), \"newLockSOVAddress not a contract\");\n\n address oldLockedSOVAddress = lockedSOVAddress;\n lockedSOVAddress = newLockedSOVAddress;\n\n emit SetLockedSOVAddress(msg.sender, oldLockedSOVAddress, newLockedSOVAddress);\n }\n\n /**\n * @notice Set the basis point of trading rebate rewards (SOV), max value is 9999 (99.99% liquid, 0.01% vested).\n *\n * @param newBasisPoint Basis point value.\n */\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newBasisPoint <= 9999, \"value too high\");\n\n uint256 oldBasisPoint = tradingRebateRewardsBasisPoint;\n tradingRebateRewardsBasisPoint = newBasisPoint;\n\n emit SetTradingRebateRewardsBasisPoint(msg.sender, oldBasisPoint, newBasisPoint);\n }\n\n /**\n * @notice Update the minimum number of referrals to get affiliates rewards.\n *\n * @param newMinReferrals The new minimum number of referrals.\n * */\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n uint256 oldMinReferrals = minReferralsToPayout;\n minReferralsToPayout = newMinReferrals;\n\n emit SetMinReferralsToPayoutAffiliates(msg.sender, oldMinReferrals, newMinReferrals);\n }\n\n /**\n * @notice Set the address of the Price Feed instance.\n *\n * @param newContract The address of the Price Feed new instance.\n * */\n function setPriceFeedContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = priceFeeds;\n priceFeeds = newContract;\n\n emit SetPriceFeedContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set the address of the asset swapper instance.\n *\n * @param newContract The address of the asset swapper new instance.\n * */\n function setSwapsImplContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = swapsImpl;\n swapsImpl = newContract;\n\n emit SetSwapsImplContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set a list of loan pools and its tokens.\n *\n * @param pools The array of addresses of new loan pool instances.\n * @param assets The array of addresses of the corresponding underlying tokens.\n * */\n function setLoanPool(address[] calldata pools, address[] calldata assets)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(pools.length == assets.length, \"count mismatch\");\n\n for (uint256 i = 0; i < pools.length; i++) {\n require(pools[i] != assets[i], \"pool == asset\");\n require(pools[i] != address(0), \"pool == 0\");\n require(\n assets[i] != address(0) || loanPoolToUnderlying[pools[i]] != address(0),\n \"pool not exists\"\n );\n if (assets[i] == address(0)) {\n underlyingToLoanPool[loanPoolToUnderlying[pools[i]]] = address(0);\n loanPoolToUnderlying[pools[i]] = address(0);\n loanPoolsSet.removeAddress(pools[i]);\n } else {\n loanPoolToUnderlying[pools[i]] = assets[i];\n underlyingToLoanPool[assets[i]] = pools[i];\n loanPoolsSet.addAddress(pools[i]);\n }\n\n emit SetLoanPool(msg.sender, pools[i], assets[i]);\n }\n }\n\n /**\n * @notice Set a list of supported tokens by populating the\n * storage supportedTokens mapping.\n *\n * @param addrs The array of addresses of the tokens.\n * @param toggles The array of flags indicating whether\n * the corresponding token is supported or not.\n * */\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(addrs.length == toggles.length, \"count mismatch\");\n\n for (uint256 i = 0; i < addrs.length; i++) {\n supportedTokens[addrs[i]] = toggles[i];\n\n emit SetSupportedTokens(msg.sender, addrs[i], toggles[i]);\n }\n }\n\n /**\n * @notice Set the value of lendingFeePercent storage variable.\n *\n * @param newValue The new value for lendingFeePercent.\n * */\n function setLendingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = lendingFeePercent;\n lendingFeePercent = newValue;\n\n emit SetLendingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of tradingFeePercent storage variable.\n *\n * @param newValue The new value for tradingFeePercent.\n * */\n function setTradingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = tradingFeePercent;\n tradingFeePercent = newValue;\n\n emit SetTradingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of borrowingFeePercent storage variable.\n *\n * @param newValue The new value for borrowingFeePercent.\n * */\n function setBorrowingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = borrowingFeePercent;\n borrowingFeePercent = newValue;\n\n emit SetBorrowingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of swapExtrernalFeePercent storage variable\n *\n * @param newValue the new value for swapExternalFeePercent\n */\n function setSwapExternalFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = swapExtrernalFeePercent;\n swapExtrernalFeePercent = newValue;\n\n emit SetSwapExternalFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateFeePercent storage variable.\n *\n * @param newValue The new value for affiliateFeePercent.\n * */\n function setAffiliateFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateFeePercent;\n affiliateFeePercent = newValue;\n\n emit SetAffiliateFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateTradingTokenFeePercent storage variable.\n *\n * @param newValue The new value for affiliateTradingTokenFeePercent.\n * */\n function setAffiliateTradingTokenFeePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateTradingTokenFeePercent;\n affiliateTradingTokenFeePercent = newValue;\n\n emit SetAffiliateTradingTokenFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of liquidationIncentivePercent storage variable.\n *\n * @param newValue The new value for liquidationIncentivePercent.\n * */\n function setLiquidationIncentivePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = liquidationIncentivePercent;\n liquidationIncentivePercent = newValue;\n\n emit SetLiquidationIncentivePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of the maximum swap spread.\n *\n * @param newValue The new value for maxDisagreement.\n * */\n function setMaxDisagreement(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n maxDisagreement = newValue;\n }\n\n /**\n * @notice Set the value of the maximum source buffer.\n *\n * @dev To avoid rounding issues on the swap rate a small buffer is implemented.\n *\n * @param newValue The new value for the maximum source buffer.\n * */\n function setSourceBuffer(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n sourceBuffer = newValue;\n }\n\n /**\n * @notice Set the value of the swap size limit.\n *\n * @param newValue The new value for the maximum swap size.\n * */\n function setMaxSwapSize(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n uint256 oldValue = maxSwapSize;\n maxSwapSize = newValue;\n\n emit SetMaxSwapSize(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the address of the feesController instance.\n *\n * @dev The fee sharing proxy must be the feesController of the\n * protocol contract. This allows the fee sharing proxy\n * to withdraw the fees.\n *\n * @param newController The new address of the feesController.\n * */\n function setFeesController(address newController) external onlyAdminOrOwner whenNotPaused {\n address oldController = feesController;\n feesController = newController;\n\n emit SetFeesController(msg.sender, oldController, newController);\n }\n\n /**\n * @notice Set the pauser address of sovryn protocol.\n *\n * only pauser or owner can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Get pauser address.\n *\n *\n * @return pauser address.\n */\n function getPauser() external view returns (address) {\n return pauser;\n }\n\n /*\n * @notice Set the admin address of sovryn protocol.\n *\n * only owner can perform this action.\n *\n * @param newAdmin The new address of the admin.\n * */\n function setAdmin(address newAdmin) external onlyOwner {\n emit SetAdmin(msg.sender, admin, newAdmin);\n admin = newAdmin;\n }\n\n /**\n * @dev Get admin address.\n *\n *\n * @return admin address.\n */\n function getAdmin() external view returns (address) {\n return admin;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * from three sources: lending, trading and borrowing.\n * The fees (except SOV) will be converted to wRBTC.\n * For SOV, it will be deposited directly to feeSharingCollector from the protocol.\n *\n * @param tokens The array of address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n whenNotPaused\n returns (uint256 totalWRBTCWithdrawn)\n {\n require(msg.sender == feesController, \"unauthorized\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n uint256 lendingBalance = lendingFeeTokensHeld[tokens[i]];\n if (lendingBalance > 0) {\n lendingFeeTokensHeld[tokens[i]] = 0;\n lendingFeeTokensPaid[tokens[i]] = lendingFeeTokensPaid[tokens[i]].add(\n lendingBalance\n );\n }\n\n uint256 tradingBalance = tradingFeeTokensHeld[tokens[i]];\n if (tradingBalance > 0) {\n tradingFeeTokensHeld[tokens[i]] = 0;\n tradingFeeTokensPaid[tokens[i]] = tradingFeeTokensPaid[tokens[i]].add(\n tradingBalance\n );\n }\n\n uint256 borrowingBalance = borrowingFeeTokensHeld[tokens[i]];\n if (borrowingBalance > 0) {\n borrowingFeeTokensHeld[tokens[i]] = 0;\n borrowingFeeTokensPaid[tokens[i]] = borrowingFeeTokensPaid[tokens[i]].add(\n borrowingBalance\n );\n }\n\n uint256 tempAmount = lendingBalance.add(tradingBalance).add(borrowingBalance);\n\n if (tempAmount == 0) {\n continue;\n }\n\n uint256 amountConvertedToWRBTC;\n if (tokens[i] == address(sovTokenAddress)) {\n IERC20(tokens[i]).approve(feesController, tempAmount);\n IFeeSharingCollector(feesController).transferTokens(\n address(sovTokenAddress),\n uint96(tempAmount)\n );\n amountConvertedToWRBTC = 0;\n } else {\n if (tokens[i] == address(wrbtcToken)) {\n amountConvertedToWRBTC = tempAmount;\n\n IERC20(address(wrbtcToken)).safeTransfer(receiver, amountConvertedToWRBTC);\n } else {\n IERC20(tokens[i]).approve(protocolAddress, tempAmount);\n\n (amountConvertedToWRBTC, ) = ProtocolSwapExternalInterface(protocolAddress)\n .swapExternal(\n tokens[i], // source token address\n address(wrbtcToken), // dest token address\n feesController, // set feeSharingCollector as receiver\n protocolAddress, // protocol as the sender\n tempAmount, // source token amount\n 0, // reqDestToken\n 0, // minReturn\n \"\" // loan data bytes\n );\n\n /// Will revert if disagreement found.\n IPriceFeeds(priceFeeds).checkPriceDisagreement(\n tokens[i],\n address(wrbtcToken),\n tempAmount,\n amountConvertedToWRBTC,\n maxDisagreement\n );\n }\n\n totalWRBTCWithdrawn = totalWRBTCWithdrawn.add(amountConvertedToWRBTC);\n }\n\n emit WithdrawFees(\n msg.sender,\n tokens[i],\n receiver,\n lendingBalance,\n tradingBalance,\n borrowingBalance,\n amountConvertedToWRBTC\n );\n }\n\n return totalWRBTCWithdrawn;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from lending operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = lendingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n lendingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n lendingFeeTokensPaid[token] = lendingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawLendingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from trading operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = tradingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n tradingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n tradingFeeTokensPaid[token] = tradingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawTradingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from borrowing operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = borrowingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n borrowingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n borrowingFeeTokensPaid[token] = borrowingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawBorrowingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The owner calls this function to withdraw protocol tokens.\n *\n * @dev Wrapper for ProtocolTokenUser::_withdrawProtocolToken internal function.\n *\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of tokens to get.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n onlyAdminOrOwner\n whenNotPaused\n returns (address, bool)\n {\n return _withdrawProtocolToken(receiver, amount);\n }\n\n /**\n * @notice The owner calls this function to deposit protocol tokens.\n *\n * @param amount The tokens of fees to send.\n * */\n function depositProtocolToken(uint256 amount) external onlyAdminOrOwner whenNotPaused {\n /// @dev Update local balance\n protocolTokenHeld = protocolTokenHeld.add(amount);\n\n /// @dev Send the tokens\n IERC20(protocolTokenAddress).safeTransferFrom(msg.sender, address(this), amount);\n }\n\n /**\n * @notice Get a list of loan pools.\n *\n * @param start The offset.\n * @param count The limit.\n *\n * @return The array of loan pools.\n * */\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory)\n {\n return loanPoolsSet.enumerate(start, count);\n }\n\n /**\n * @notice Check whether a token is a pool token.\n *\n * @dev By querying its underlying token.\n *\n * @param loanPool The token address to check.\n * */\n function isLoanPool(address loanPool) external view returns (bool) {\n return loanPoolToUnderlying[loanPool] != address(0);\n }\n\n /**\n * @notice Set the contract registry address of the SovrynSwap network.\n *\n * @param registryAddress the address of the registry contract.\n * */\n function setSovrynSwapContractRegistryAddress(address registryAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(registryAddress), \"registryAddress not a contract\");\n\n address oldSovrynSwapContractRegistryAddress = sovrynSwapContractRegistryAddress;\n sovrynSwapContractRegistryAddress = registryAddress;\n\n emit SetSovrynSwapContractRegistryAddress(\n msg.sender,\n oldSovrynSwapContractRegistryAddress,\n sovrynSwapContractRegistryAddress\n );\n }\n\n /**\n * @notice Set the wrBTC contract address.\n *\n * @param wrbtcTokenAddress The address of the wrBTC contract.\n * */\n function setWrbtcToken(address wrbtcTokenAddress) external onlyAdminOrOwner whenNotPaused {\n require(Address.isContract(wrbtcTokenAddress), \"wrbtcTokenAddress not a contract\");\n\n address oldwrbtcToken = address(wrbtcToken);\n wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n emit SetWrbtcToken(msg.sender, oldwrbtcToken, wrbtcTokenAddress);\n }\n\n /**\n * @notice Set the protocol token contract address.\n *\n * @param _protocolTokenAddress The address of the protocol token contract.\n * */\n function setProtocolTokenAddress(address _protocolTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n\n address oldProtocolTokenAddress = protocolTokenAddress;\n protocolTokenAddress = _protocolTokenAddress;\n\n emit SetProtocolTokenAddress(msg.sender, oldProtocolTokenAddress, _protocolTokenAddress);\n }\n\n /**\n * @notice Set rollover base reward. It should be denominated in wrBTC.\n *\n * @param baseRewardValue The base reward.\n * */\n function setRolloverBaseReward(uint256 baseRewardValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(baseRewardValue > 0, \"Base reward is zero\");\n\n uint256 oldValue = rolloverBaseReward;\n rolloverBaseReward = baseRewardValue;\n\n emit SetRolloverBaseReward(msg.sender, oldValue, rolloverBaseReward);\n }\n\n /**\n * @notice Set the fee rebate percent.\n *\n * @param rebatePercent The fee rebate percent.\n * */\n function setRebatePercent(uint256 rebatePercent) external onlyAdminOrOwner whenNotPaused {\n require(rebatePercent <= 10**20, \"Fee rebate is too high\");\n\n uint256 oldRebatePercent = feeRebatePercent;\n feeRebatePercent = rebatePercent;\n\n emit SetRebatePercent(msg.sender, oldRebatePercent, rebatePercent);\n }\n\n /**\n * @notice Set the special fee rebate percent for specific pair\n *\n * @param specialRebatesPercent The new special fee rebate percent.\n * */\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external onlyAdminOrOwner whenNotPaused {\n // Set max special rebates to 1000%\n require(specialRebatesPercent <= 1000e18, \"Special fee rebate is too high\");\n\n uint256 oldSpecialRebatesPercent = specialRebates[sourceToken][destToken];\n specialRebates[sourceToken][destToken] = specialRebatesPercent;\n\n emit SetSpecialRebates(\n msg.sender,\n sourceToken,\n destToken,\n oldSpecialRebatesPercent,\n specialRebatesPercent\n );\n }\n\n /**\n * @notice Get a rebate percent of specific pairs.\n *\n * @param sourceTokenAddress The source of pairs.\n * @param destTokenAddress The dest of pairs.\n *\n * @return The percent rebates of the pairs.\n * */\n function getSpecialRebates(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 specialRebatesPercent)\n {\n return specialRebates[sourceTokenAddress][destTokenAddress];\n }\n\n function getProtocolAddress() external view returns (address) {\n return protocolAddress;\n }\n\n function getSovTokenAddress() external view returns (address) {\n return sovTokenAddress;\n }\n\n function getLockedSOVAddress() external view returns (address) {\n return lockedSOVAddress;\n }\n\n function getFeeRebatePercent() external view returns (uint256) {\n return feeRebatePercent;\n }\n\n function togglePaused(bool paused) external onlyPauserOrOwner {\n require(paused != pause, \"Can't toggle\");\n pause = paused;\n emit TogglePaused(msg.sender, !paused, paused);\n }\n\n function isProtocolPaused() external view returns (bool) {\n return pause;\n }\n\n function getSwapExternalFeePercent() external view returns (uint256) {\n return swapExtrernalFeePercent;\n }\n\n /**\n * @notice Get the basis point of trading rebate rewards.\n *\n * @return The basis point value.\n */\n function getTradingRebateRewardsBasisPoint() external view returns (uint256) {\n return tradingRebateRewardsBasisPoint;\n }\n\n /**\n * @dev Get how much SOV that is dedicated to pay the trading rebate rewards.\n * @notice If SOV balance is less than the fees held, it will return 0.\n *\n * @return total dedicated SOV.\n */\n function getDedicatedSOVRebate() public view returns (uint256) {\n uint256 sovProtocolBalance = IERC20(sovTokenAddress).balanceOf(address(this));\n uint256 sovFees =\n lendingFeeTokensHeld[sovTokenAddress].add(tradingFeeTokensHeld[sovTokenAddress]).add(\n borrowingFeeTokensHeld[sovTokenAddress]\n );\n\n return sovProtocolBalance >= sovFees ? sovProtocolBalance.sub(sovFees) : 0;\n }\n\n /**\n * @notice Set rolloverFlexFeePercent (max value is 1%)\n *\n * @param newRolloverFlexFeePercent uint256 value of new rollover flex fee percentage (0.1 ether = 0.1%)\n */\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newRolloverFlexFeePercent <= 1e18, \"value too high\");\n uint256 oldRolloverFlexFeePercent = rolloverFlexFeePercent;\n rolloverFlexFeePercent = newRolloverFlexFeePercent;\n\n emit SetRolloverFlexFeePercent(\n msg.sender,\n oldRolloverFlexFeePercent,\n newRolloverFlexFeePercent\n );\n }\n\n /**\n * @dev Get default path conversion for pairs.\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address.\n *\n * @return default path of the conversion.\n */\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory)\n {\n return defaultPathConversion[sourceTokenAddress][destTokenAddress];\n }\n\n /**\n * @dev Set default path conversion for pairs.\n *\n * @param defaultPath array of addresses for the default path.\n *\n */\n function setDefaultPathConversion(IERC20[] calldata defaultPath)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address sourceTokenAddress = address(defaultPath[0]);\n address destTokenAddress = address(defaultPath[defaultPath.length - 1]);\n\n uint256 defaultPathLength = defaultPath.length;\n require(defaultPathLength >= 3, \"ERR_PATH_LENGTH\");\n\n for (uint256 i = 0; i < defaultPathLength; i++) {\n require(Address.isContract(address(defaultPath[i])), \"ERR_PATH_NON_CONTRACT_ADDR\");\n }\n\n defaultPathConversion[sourceTokenAddress][destTokenAddress] = defaultPath;\n\n emit SetDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPath\n );\n }\n\n /**\n * @dev Remove the default path conversion for pairs\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address\n */\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(\n defaultPathConversion[sourceTokenAddress][destTokenAddress].length > 0,\n \"DEFAULT_PATH_EMPTY\"\n );\n\n IERC20[] memory defaultPathValue =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n delete defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n emit RemoveDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPathValue\n );\n }\n}\n" + }, + "contracts/modules/SwapsExternal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Swaps External contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to calculate and execute swaps.\n * */\ncontract SwapsExternal is VaultController, SwapsUser, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.swapExternal.selector];\n _setTarget(this.swapExternal.selector, target);\n _setTarget(this.getSwapExpectedReturn.selector, target);\n _setTarget(this.checkPriceDivergence.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"SwapsExternal\");\n }\n\n /**\n * @notice Perform a swap w/ tokens or rBTC as source currency.\n *\n * @dev External wrapper that calls SwapsUser::_swapsCall\n * after turning potential incoming rBTC into wrBTC tokens.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param receiver The address of the recipient account.\n * @param returnToSender The address of the sender account.\n * @param sourceTokenAmount The amount of source tokens.\n * @param requiredDestTokenAmount The amount of required destiny tokens.\n * @param minReturn Minimum amount (position size) in the collateral tokens.\n * @param swapData Additional swap data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes memory swapData\n )\n public\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(sourceTokenAmount != 0, \"sourceTokenAmount == 0\");\n checkPriceDivergence(sourceToken, destToken, sourceTokenAmount, minReturn);\n\n /// @dev Get payed value, be it rBTC or tokenized.\n if (msg.value != 0) {\n if (sourceToken == address(0)) {\n sourceToken = address(wrbtcToken);\n }\n require(sourceToken == address(wrbtcToken), \"sourceToken mismatch\");\n require(msg.value == sourceTokenAmount, \"sourceTokenAmount mismatch\");\n\n /// @dev Update wrBTC balance for this contract.\n wrbtcToken.deposit.value(sourceTokenAmount)();\n } else {\n if (address(this) != msg.sender) {\n IERC20(sourceToken).safeTransferFrom(msg.sender, address(this), sourceTokenAmount);\n }\n }\n\n /// @dev Perform the swap w/ tokens.\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n receiver,\n returnToSender,\n msg.sender /// user\n ],\n [\n sourceTokenAmount, /// minSourceTokenAmount\n sourceTokenAmount, /// maxSourceTokenAmount\n requiredDestTokenAmount\n ],\n 0, /// loanId (not tied to a specific loan)\n false, /// bypassFee\n swapData,\n true // the flag for swapExternal (so that it will use the swapExternalFeePercent)\n );\n\n emit ExternalSwap(\n msg.sender, /// user\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Get the swap expected return value.\n *\n * @dev External wrapper that calls SwapsUser::_swapsExpectedReturn\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n *\n * @return The expected return value.\n * */\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n }\n\n /**\n * @notice Check the slippage based on the swapExpectedReturn.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n * @param minReturn The amount (max slippage) that will be compared to the swapsExpectedReturn.\n *\n */\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view {\n uint256 destTokenAmount = _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n require(destTokenAmount >= minReturn, \"destTokenAmountReceived too low\");\n }\n}\n" + }, + "contracts/modules/SwapsImplSovrynSwapModule.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../swaps/connectors/SwapsImplSovrynSwapLib.sol\";\nimport \"../events/ModulesCommonEvents.sol\";\n\ncontract SwapsImplSovrynSwapModule is State, ModulesCommonEvents {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress =\n logicTargets[this.getSovrynSwapNetworkContract.selector];\n _setTarget(this.getSovrynSwapNetworkContract.selector, target);\n _setTarget(this.getContractHexName.selector, target);\n _setTarget(this.swapsImplExpectedRate.selector, target);\n _setTarget(this.swapsImplExpectedReturn.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"SwapsImplSovrynSwapModule\"\n );\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n return SwapsImplSovrynSwapLib.getContractHexName(source);\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n return SwapsImplSovrynSwapLib.getSovrynSwapNetworkContract(sovrynSwapRegistryAddress);\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return\n SwapsImplSovrynSwapLib.getExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn) {\n return\n SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n}\n" + }, + "contracts/multisig/MultiSigKeyHolders.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/Ownable.sol\";\n\n/**\n * @title Multi Signature Key Holders contract.\n *\n * This contract contains the implementation of functions to add and remove\n * key holders w/ rBTC and BTC addresses.\n * */\ncontract MultiSigKeyHolders is Ownable {\n /* Storage */\n\n uint256 public constant MAX_OWNER_COUNT = 50;\n\n string private constant ERROR_INVALID_ADDRESS = \"Invalid address\";\n string private constant ERROR_INVALID_REQUIRED = \"Invalid required\";\n\n /// Flag and index for Ethereum address.\n mapping(address => Data) private isEthereumAddressAdded;\n\n /// List of Ethereum addresses.\n address[] private ethereumAddresses;\n\n /// Required number of signatures for the Ethereum multisig.\n uint256 public ethereumRequired = 2;\n\n /// Flag and index for Bitcoin address.\n mapping(string => Data) private isBitcoinAddressAdded;\n\n /// List of Bitcoin addresses.\n string[] private bitcoinAddresses;\n\n /// Required number of signatures for the Bitcoin multisig.\n uint256 public bitcoinRequired = 2;\n\n /// Helps removing items from array.\n struct Data {\n bool added;\n uint248 index;\n }\n\n /* Events */\n\n event EthereumAddressAdded(address indexed account);\n event EthereumAddressRemoved(address indexed account);\n event EthereumRequirementChanged(uint256 required);\n event BitcoinAddressAdded(string account);\n event BitcoinAddressRemoved(string account);\n event BitcoinRequirementChanged(uint256 required);\n\n /* Modifiers */\n\n modifier validRequirement(uint256 ownerCount, uint256 _required) {\n require(\n ownerCount <= MAX_OWNER_COUNT &&\n _required <= ownerCount &&\n _required != 0 &&\n ownerCount != 0,\n ERROR_INVALID_REQUIRED\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function addEthereumAddress(address _address) public onlyOwner {\n _addEthereumAddress(_address);\n }\n\n /**\n * @notice Add rBTC addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function _addEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (!isEthereumAddressAdded[_address].added) {\n isEthereumAddressAdded[_address] = Data({\n added: true,\n index: uint248(ethereumAddresses.length)\n });\n ethereumAddresses.push(_address);\n }\n\n emit EthereumAddressAdded(_address);\n }\n\n /**\n * @notice Remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeEthereumAddress(address _address) public onlyOwner {\n _removeEthereumAddress(_address);\n }\n\n /**\n * @notice Remove rBTC addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (isEthereumAddressAdded[_address].added) {\n uint248 index = isEthereumAddressAdded[_address].index;\n if (index != ethereumAddresses.length - 1) {\n ethereumAddresses[index] = ethereumAddresses[ethereumAddresses.length - 1];\n isEthereumAddressAdded[ethereumAddresses[index]].index = index;\n }\n ethereumAddresses.length--;\n delete isEthereumAddressAdded[_address];\n }\n\n emit EthereumAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether rBTC address is a key holder.\n * @param _address The rBTC address to be checked.\n * */\n function isEthereumAddressOwner(address _address) public view returns (bool) {\n return isEthereumAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of rBTC key holders.\n * */\n function getEthereumAddresses() public view returns (address[] memory) {\n return ethereumAddresses;\n }\n\n /**\n * @notice Set flag ethereumRequired to true/false.\n * @param _required The new value of the ethereumRequired flag.\n * */\n function changeEthereumRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(ethereumAddresses.length, _required)\n {\n ethereumRequired = _required;\n emit EthereumRequirementChanged(_required);\n }\n\n /**\n * @notice Add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function addBitcoinAddress(string memory _address) public onlyOwner {\n _addBitcoinAddress(_address);\n }\n\n /**\n * @notice Add bitcoin addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function _addBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (!isBitcoinAddressAdded[_address].added) {\n isBitcoinAddressAdded[_address] = Data({\n added: true,\n index: uint248(bitcoinAddresses.length)\n });\n bitcoinAddresses.push(_address);\n }\n\n emit BitcoinAddressAdded(_address);\n }\n\n /**\n * @notice Remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeBitcoinAddress(string memory _address) public onlyOwner {\n _removeBitcoinAddress(_address);\n }\n\n /**\n * @notice Remove bitcoin addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (isBitcoinAddressAdded[_address].added) {\n uint248 index = isBitcoinAddressAdded[_address].index;\n if (index != bitcoinAddresses.length - 1) {\n bitcoinAddresses[index] = bitcoinAddresses[bitcoinAddresses.length - 1];\n isBitcoinAddressAdded[bitcoinAddresses[index]].index = index;\n }\n bitcoinAddresses.length--;\n delete isBitcoinAddressAdded[_address];\n }\n\n emit BitcoinAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether bitcoin address is a key holder.\n * @param _address The bitcoin address to be checked.\n * */\n function isBitcoinAddressOwner(string memory _address) public view returns (bool) {\n return isBitcoinAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of bitcoin key holders.\n * */\n function getBitcoinAddresses() public view returns (string[] memory) {\n return bitcoinAddresses;\n }\n\n /**\n * @notice Set flag bitcoinRequired to true/false.\n * @param _required The new value of the bitcoinRequired flag.\n * */\n function changeBitcoinRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(bitcoinAddresses.length, _required)\n {\n bitcoinRequired = _required;\n emit BitcoinRequirementChanged(_required);\n }\n\n /**\n * @notice Add rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress the rBTC addresses to be added.\n * @param _bitcoinAddress the bitcoin addresses to be added.\n * */\n function addEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _addEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _addBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n\n /**\n * @notice Remove rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress The rBTC addresses to be removed.\n * @param _bitcoinAddress The bitcoin addresses to be removed.\n * */\n function removeEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _removeEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _removeBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n}\n" + }, + "contracts/openzeppelin/Address.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256('')`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n codehash := extcodehash(account)\n }\n return (codehash != accountHash && codehash != 0x0);\n }\n\n /**\n * @dev Converts an `address` into `address payable`. Note that this is\n * simply a type cast: the actual underlying value is not changed.\n *\n * _Available since v2.4.0._\n */\n function toPayable(address account) internal pure returns (address payable) {\n return address(uint160(account));\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n *\n * _Available since v2.4.0._\n */\n function sendValue(address recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-call-value\n (bool success, ) = recipient.call.value(amount)(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n}\n" + }, + "contracts/openzeppelin/Context.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n // Empty internal constructor, to prevent people from mistakenly deploying\n // an instance of this contract, which should be used via inheritance.\n constructor() internal {}\n\n // solhint-disable-previous-line no-empty-blocks\n\n function _msgSender() internal view returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n" + }, + "contracts/openzeppelin/ERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./Context.sol\";\nimport \"./IERC20_.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20Mintable}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20_ {\n using SafeMath for uint256;\n\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20};\n *\n * Requirements:\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for `sender`'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n _allowances[sender][_msgSender()].sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n _approve(\n _msgSender(),\n spender,\n _allowances[_msgSender()][spender].sub(\n subtractedValue,\n \"ERC20: decreased allowance below zero\"\n )\n );\n return true;\n }\n\n /**\n * @dev Moves tokens `amount` from `sender` to `recipient`.\n *\n * This is internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _balances[sender] = _balances[sender].sub(\n amount,\n \"ERC20: transfer amount exceeds balance\"\n );\n _balances[recipient] = _balances[recipient].add(amount);\n emit Transfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n *\n * This is internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`.`amount` is then deducted\n * from the caller's allowance.\n *\n * See {_burn} and {_approve}.\n */\n function _burnFrom(address account, uint256 amount) internal {\n _burn(account, amount);\n _approve(\n account,\n _msgSender(),\n _allowances[account][_msgSender()].sub(amount, \"ERC20: burn amount exceeds allowance\")\n );\n }\n}\n" + }, + "contracts/openzeppelin/ERC20Detailed.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20_.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n */\ncontract ERC20Detailed is IERC20_ {\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n */\n constructor(\n string memory name,\n string memory symbol,\n uint8 decimals\n ) public {\n _name = name;\n _symbol = symbol;\n _decimals = decimals;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/openzeppelin/IERC20_.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20_ {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/openzeppelin/Initializable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n */\ncontract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(_initializing || !_initialized, \"Initializable: contract is already initialized\");\n\n bool isTopLevelCall = !_initializing;\n if (isTopLevelCall) {\n _initializing = true;\n _initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n _initializing = false;\n }\n }\n}\n" + }, + "contracts/openzeppelin/Ownable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() public view returns (bool) {\n return _msgSender() == _owner;\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public onlyOwner {\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n */\n function _transferOwnership(address newOwner) internal {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n}\n" + }, + "contracts/openzeppelin/PausableOz.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./Ownable.sol\";\n\ncontract PausableOz is Ownable {\n /**\n * @dev Emitted when the pause is triggered by the owner (`account`).\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by the owner (`account`).\n */\n event Unpaused(address account);\n\n bool internal _paused;\n\n constructor() internal {}\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n */\n modifier whenNotPaused() {\n require(!_paused, \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n */\n modifier whenPaused() {\n require(_paused, \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/openzeppelin/ReentrancyGuard.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title Helps contracts guard against reentrancy attacks.\n * @author Remco Bloemen , Eenae \n * @dev If you mark a function `nonReentrant`, you should also\n * mark it `external`.\n */\ncontract ReentrancyGuard {\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n" + }, + "contracts/openzeppelin/SafeERC20.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./SafeMath.sol\";\nimport \"./Address.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\n );\n }\n\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n // solhint-disable-next-line max-line-length\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance =\n token.allowance(address(this), spender).sub(\n value,\n \"SafeERC20: decreased allowance below zero\"\n );\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves.\n\n // A Solidity high level call has three parts:\n // 1. The target address is checked to verify it contains contract code\n // 2. The call itself is made, and success asserted\n // 3. The return value is decoded, which in turn checks the size of the returned data.\n // solhint-disable-next-line max-line-length\n require(address(token).isContract(), \"SafeERC20: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(data);\n require(success, \"SafeERC20: low-level call failed\");\n\n if (returndata.length > 0) {\n // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "contracts/openzeppelin/SafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n *\n * _Available since v2.4.0._\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\n return divCeil(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n\n if (a == 0) {\n return 0;\n }\n uint256 c = ((a - 1) / b) + 1;\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\n return _a < _b ? _a : _b;\n }\n}\n" + }, + "contracts/openzeppelin/SignedSafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title SignedSafeMath\n * @dev Signed math operations with safety checks that revert on error.\n */\nlibrary SignedSafeMath {\n int256 private constant _INT256_MIN = -2**255;\n\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n require(!(a == -1 && b == _INT256_MIN), \"SignedSafeMath: multiplication overflow\");\n\n int256 c = a * b;\n require(c / a == b, \"SignedSafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n require(b != 0, \"SignedSafeMath: division by zero\");\n require(!(b == -1 && a == _INT256_MIN), \"SignedSafeMath: division overflow\");\n\n int256 c = a / b;\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a - b;\n require((b >= 0 && c <= a) || (b < 0 && c > a), \"SignedSafeMath: subtraction overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a + b;\n require((b >= 0 && c >= a) || (b < 0 && c < a), \"SignedSafeMath: addition overflow\");\n\n return c;\n }\n}\n" + }, + "contracts/proxy/modules/interfaces/IFunctionsList.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\ninterface IFunctionsList {\n function getFunctionsList() external pure returns (bytes4[] memory functionSignatures);\n}\n" + }, + "contracts/proxy/modules/interfaces/IModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\n/**\n * ModulesProxyRegistry Interface\n */\n\ncontract IModulesProxyRegistry {\n event AddModule(address indexed moduleAddress);\n event ReplaceModule(address indexed oldAddress, address indexed newAddress);\n event RemoveModule(address indexed moduleAddress);\n event SetModuleFuncImplementation(\n bytes4 indexed _funcSig,\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use ReplaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external;\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl) external;\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external;\n\n /// @notice to disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external;\n\n /// @param _sig function signature to get impmementation address for\n /// @return function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address);\n\n /// @notice verifies if no functions from the module deployed already registered\n /// @param _impl module implementation address to verify\n /// @return true if module can be added\n function canAddModule(address _impl) external view returns (bool);\n\n /// @notice Multiple modules verification if no functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return True if all modules can be added, false otherwise\n function canNotAddModules(address[] calldata _implementations)\n external\n view\n returns (address[] memory modules);\n\n /// @notice used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n );\n}\n" + }, + "contracts/proxy/modules/ModulesProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"./ModulesProxyRegistry.sol\";\n\n/**\n * ModulesProxy serves as a storage processed by a set of logic contracts - modules\n * Modules functions are registered in the contract's slots generated per func sig\n * All the function calls except for own Proxy functions are delegated to\n * the registered functions\n * The ModulesProxy is designed as a universal solution for refactorig contracts\n * reaching a 24K size limit (EIP-170)\n *\n * Upgradability is implemented at a module level to provide consistency\n * It does not allow to replace separate functions - only the whole module\n * meaning that if a module being registered contains other modules function signatures\n * then these modulea should be replaced completely - all the functions should be removed\n * to avoid leftovers or accidental replacements and therefore functional inconsistency.\n *\n * A module is either a new non-overlapping with registered modules\n * or a complete replacement of another registered module\n * in which case all the old module functions are unregistered and then\n * the new module functions are registered\n * There is also a separate function to unregister a module which unregisters all the functions\n * There is no option to unregister a subset of module functions - one should use pausable functionality\n * to achieve this\n */\n\ncontract ModulesProxy is ModulesProxyRegistry {\n // Uncomment for using beforeFallback() hook\n /*\n bytes private constant BEFORE_FALLBACK_SIG = abi.encodeWithSignature(\"beforeFallback()\");\n bytes4 private constant BEFORE_FALLBACK_SIG_BYTES4 = bytes4(keccak256(abi.encodePacked(\"beforeFallback()\")));\n */\n\n /**\n * @notice Fallback function delegates calls to modules.\n * Returns whatever the implementation call returns.\n * Has a hook to execute before delegating calls\n * To activate register a module with beforeFallback() function\n */\n function() external payable {\n /*\n // Commented to safe gas by default\n // Uncomment for using beforeFallback() hook \n // Implement and register beforeFallback() function in a module\n address beforeFallback = _getFuncImplementation(BEFORE_FALLBACK_SIG_BYTES4);\n if (beforeFallback != address(0)) {\n (bool success, ) = beforeFallback.delegatecall(bytes(0x39b0111a)); // abi.encodeWithSignature(\"beforeFallback()\")\n require(success, \"ModulesProxy::fallback: beforeFallback() fail\"); //MP02\n }\n */\n\n address target = _getFuncImplementation(msg.sig);\n require(target != address(0), \"ModulesProxy:target module not registered\"); // MP03\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/modules/ModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"../../utils/Utils.sol\";\nimport \"../../utils/ProxyOwnable.sol\";\nimport \"../modules/interfaces/IFunctionsList.sol\";\nimport \"../modules/interfaces/IModulesProxyRegistry.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * ModulesProxyRegistry provides modules registration/removing/replacing functionality to ModulesProxy\n * Designed to be inherited\n */\n\ncontract ModulesProxyRegistry is IModulesProxyRegistry, ProxyOwnable {\n using Address for address;\n\n bytes32 internal constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n\n ///@notice Constructor is internal to make contract abstract\n constructor() internal {\n // abstract\n }\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use replaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external onlyProxyOwner {\n _addModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external onlyProxyOwner {\n _addModules(_implementations);\n }\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl)\n external\n onlyProxyOwner\n {\n _replaceModule(_oldModuleImpl, _newModuleImpl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external onlyProxyOwner {\n require(\n _implementationsFrom.length == _implementationsTo.length,\n \"ModulesProxyRegistry::replaceModules: arrays sizes must be equal\"\n ); //MR10\n\n // because the order of addresses is arbitrary, all modules are removed first to avoid collisions\n _removeModules(_implementationsFrom);\n _addModules(_implementationsTo);\n }\n\n /// @notice To disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external onlyProxyOwner {\n _removeModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external onlyProxyOwner {\n _removeModules(_implementations);\n }\n\n /// @param _sig Function signature to get impmementation address for\n /// @return Function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address) {\n return _getFuncImplementation(_sig);\n }\n\n /// @notice Verifies if no functions from the module already registered\n /// @param _impl Module implementation address to verify\n /// @return True if module can be added\n function canAddModule(address _impl) external view returns (bool) {\n return _canAddModule(_impl);\n }\n\n /// @notice Multiple modules verification if there are functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return addresses of registered modules\n function canNotAddModules(address[] memory _implementations)\n public\n view\n returns (address[] memory)\n {\n for (uint256 i = 0; i < _implementations.length; i++) {\n if (_canAddModule(_implementations[i])) {\n delete _implementations[i];\n }\n }\n return _implementations;\n }\n\n /// @notice Used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return Clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n )\n {\n require(\n _newModule.isContract(),\n \"ModulesProxyRegistry::checkClashingFuncSelectors: address is not a contract\"\n ); //MR06\n bytes4[] memory newModuleFunctions = IFunctionsList(_newModule).getFunctionsList();\n bytes4[] memory proxyRegistryFunctions = _getFunctionsList(); //registry functions list\n uint256 clashingProxyRegistryFuncsSize;\n uint256 clashingArraySize;\n uint256 clashingArrayIndex;\n uint256 clashingRegistryArrayIndex;\n\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0) && funcImpl != _newModule) {\n clashingArraySize++;\n } else if (_isFuncClashingWithProxyFunctions(newModuleFunctions[i]))\n clashingProxyRegistryFuncsSize++;\n }\n clashingModules = new address[](clashingArraySize);\n clashingModulesFuncSelectors = new bytes4[](clashingArraySize);\n clashingProxyRegistryFuncSelectors = new bytes4[](clashingProxyRegistryFuncsSize);\n\n if (clashingArraySize == 0 && clashingProxyRegistryFuncsSize == 0)\n //return empty arrays\n return (\n clashingModules,\n clashingModulesFuncSelectors,\n clashingProxyRegistryFuncSelectors\n );\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0)) {\n clashingModules[clashingArrayIndex] = funcImpl;\n clashingModulesFuncSelectors[clashingArrayIndex] = newModuleFunctions[i];\n clashingArrayIndex++;\n }\n for (uint256 j = 0; j < proxyRegistryFunctions.length; j++) {\n //ModulesProxyRegistry has a clashing function selector\n if (proxyRegistryFunctions[j] == newModuleFunctions[i]) {\n clashingProxyRegistryFuncSelectors[\n clashingRegistryArrayIndex\n ] = proxyRegistryFunctions[j];\n clashingRegistryArrayIndex++;\n }\n }\n }\n }\n\n /// Verifies the deployed contract address is a registered module contract\n /// @param _impl deployment address to verify\n /// @return true if _impl address is a registered module\n function isModuleRegistered(address _impl) external view returns (bool) {\n return _getFirstRegisteredModuleAddress(_impl) == _impl;\n }\n\n /****************** INTERNAL FUNCTIONS ******************/\n\n function _getFirstRegisteredModuleAddress(address _impl) internal view returns (address) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_getRegisteredModuleAddress: address is not a contract\"\n );\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n address _moduleImpl = _getFuncImplementation(functions[i]);\n if (_moduleImpl != address(0)) {\n return (_moduleImpl);\n }\n }\n return address(0);\n }\n\n function _getFuncImplementation(bytes4 _sig) internal view returns (address) {\n //TODO: add querying Registry for logic address and then delegate call to it OR use proxy memory slots like this:\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n address implementation;\n assembly {\n implementation := sload(key)\n }\n return implementation;\n }\n\n function _addModule(address _impl) internal {\n require(_impl.isContract(), \"ModulesProxyRegistry::_addModule: address is not a contract\"); //MR01\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n require(\n _getFuncImplementation(functions[i]) == address(0),\n \"ModulesProxyRegistry::_addModule: function already registered - use replaceModule function\"\n ); //MR02\n require(functions[i] != bytes4(0), \"does not allow empty function id\"); // MR03\n require(\n !_isFuncClashingWithProxyFunctions(functions[i]),\n \"ModulesProxyRegistry::_addModule: has a function with the same signature\"\n ); //MR09\n _setModuleFuncImplementation(functions[i], _impl);\n }\n emit AddModule(_impl);\n }\n\n function _addModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _addModule(_implementations[i]);\n }\n }\n\n function _removeModule(address _impl) internal onlyProxyOwner {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_removeModule: address is not a contract\"\n ); //MR07\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n _setModuleFuncImplementation(functions[i], address(0));\n\n emit RemoveModule(_impl);\n }\n\n function _removeModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _removeModule(_implementations[i]);\n }\n }\n\n function _replaceModule(address _oldModuleImpl, address _newModuleImpl) internal {\n if (_oldModuleImpl != _newModuleImpl) {\n require(\n _newModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _newModuleImpl is not a contract\"\n ); //MR03\n require(\n _oldModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _oldModuleImpl is not a contract\"\n ); //MR04\n _removeModule(_oldModuleImpl);\n _addModule(_newModuleImpl);\n\n emit ReplaceModule(_oldModuleImpl, _newModuleImpl);\n }\n }\n\n function _setModuleFuncImplementation(bytes4 _sig, address _impl) internal {\n emit SetModuleFuncImplementation(_sig, _getFuncImplementation(_sig), _impl);\n\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n assembly {\n sstore(key, _impl)\n }\n }\n\n function _isFuncClashingWithProxyFunctions(bytes4 _sig) internal pure returns (bool) {\n bytes4[] memory functionList = _getFunctionsList();\n for (uint256 i = 0; i < functionList.length; i++) {\n if (_sig == functionList[i])\n //ModulesProxyRegistry has function with the same id\n return true;\n }\n return false;\n }\n\n function _canAddModule(address _impl) internal view returns (bool) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_canAddModule: address is not a contract\"\n ); //MR06\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n if (_getFuncImplementation(functions[i]) != address(0)) return (false);\n return true;\n }\n\n function _getFunctionsList() internal pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](13);\n functionList[0] = this.getFuncImplementation.selector;\n functionList[1] = this.addModule.selector;\n functionList[2] = this.addModules.selector;\n functionList[3] = this.removeModule.selector;\n functionList[4] = this.removeModules.selector;\n functionList[5] = this.replaceModule.selector;\n functionList[6] = this.replaceModules.selector;\n functionList[7] = this.canAddModule.selector;\n functionList[8] = this.canNotAddModules.selector;\n functionList[9] = this.setProxyOwner.selector;\n functionList[10] = this.getProxyOwner.selector;\n functionList[11] = this.checkClashingFuncSelectors.selector;\n functionList[12] = this.isModuleRegistered.selector;\n return functionList;\n }\n}\n" + }, + "contracts/proxy/Proxy.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base Proxy contract.\n * @notice The proxy performs delegated calls to the contract implementation\n * it is pointing to. This way upgradable contracts are possible on blockchain.\n *\n * Delegating proxy contracts are widely used for both upgradeability and gas\n * savings. These proxies rely on a logic contract (also known as implementation\n * contract or master copy) that is called using delegatecall. This allows\n * proxies to keep a persistent state (storage and balance) while the code is\n * delegated to the logic contract.\n *\n * Proxy contract is meant to be inherited and its internal functions\n * _setImplementation and _setProxyOwner to be called when upgrades become\n * neccessary.\n *\n * The loan token (iToken) contract as well as the protocol contract act as\n * proxies, delegating all calls to underlying contracts. Therefore, if you\n * want to interact with them using web3, you need to use the ABIs from the\n * contracts containing the actual logic or the interface contract.\n * ABI for LoanToken contracts: LoanTokenLogicStandard\n * ABI for Protocol contract: ISovryn\n *\n * @dev UpgradableProxy is the contract that inherits Proxy and wraps these\n * functions.\n * */\ncontract Proxy {\n bytes32 private constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);\n event ImplementationChanged(\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /**\n * @notice Set sender as an owner.\n * */\n constructor() public {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @notice Throw error if called not by an owner.\n * */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Proxy:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the implementation.\n * @param _implementation Address of the implementation.\n * */\n function _setImplementation(address _implementation) internal {\n require(_implementation != address(0), \"Proxy::setImplementation: invalid address\");\n emit ImplementationChanged(getImplementation(), _implementation);\n\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n sstore(key, _implementation)\n }\n }\n\n /**\n * @notice Return address of the implementation.\n * @return Address of the implementation.\n * */\n function getImplementation() public view returns (address _implementation) {\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n _implementation := sload(key)\n }\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"Proxy::setProxyOwner: invalid address\");\n emit OwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Return address of the owner.\n * @return Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n address implementation = getImplementation();\n require(implementation != address(0), \"Proxy::(): implementation not found\");\n\n assembly {\n let pointer := mload(0x40)\n calldatacopy(pointer, 0, calldatasize)\n let result := delegatecall(gas, implementation, pointer, calldatasize, 0, 0)\n let size := returndatasize\n returndatacopy(pointer, 0, size)\n\n switch result\n case 0 {\n revert(pointer, size)\n }\n default {\n return(pointer, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/UpgradableProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Proxy.sol\";\n\n/**\n * @title Upgradable Proxy contract.\n * @notice A disadvantage of the immutable ledger is that nobody can change the\n * source code of a smart contract after it’s been deployed. In order to fix\n * bugs or introduce new features, smart contracts need to be upgradable somehow.\n *\n * Although it is not possible to upgrade the code of an already deployed smart\n * contract, it is possible to set-up a proxy contract architecture that will\n * allow to use new deployed contracts as if the main logic had been upgraded.\n *\n * A proxy architecture pattern is such that all message calls go through a\n * Proxy contract that will redirect them to the latest deployed contract logic.\n * To upgrade, a new version of the contract is deployed, and the Proxy is\n * updated to reference the new contract address.\n * */\ncontract UpgradableProxy is Proxy {\n /**\n * @notice Set address of the implementation.\n * @dev Wrapper for _setImplementation that exposes the function\n * as public for owner to be able to set a new version of the\n * contract as current pointing implementation.\n * @param _implementation Address of the implementation.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n _setImplementation(_implementation);\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n}\n" + }, + "contracts/reentrancy/Mutex.sol": { + "content": "pragma solidity ^0.5.17;\n\n/*\n * @title Global Mutex contract\n *\n * @notice A mutex contract that allows only one function to be called at a time out\n * of a large set of functions. *Anyone* in the network can freely use any instance\n * of this contract to add a universal mutex to any function in any contract.\n */\ncontract Mutex {\n /*\n * We use an uint to store the mutex state.\n */\n uint256 public value;\n\n /*\n * @notice Increment the mutex state and return the new value.\n *\n * @dev This is the function that will be called by anyone to change the mutex\n * state. It is purposely not protected by any access control\n */\n function incrementAndGetValue() external returns (uint256) {\n /*\n * increment value using unsafe math. This is safe because we are\n * pretty certain no one will ever increment the value 2^256 times\n * in a single transaction.\n */\n return ++value;\n }\n}\n" + }, + "contracts/reentrancy/SharedReentrancyGuard.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Mutex.sol\";\n\n/*\n * @title Abstract contract for shared reentrancy guards\n *\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\n * that there's no reentrancy between *any* functions marked with the modifier.\n *\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\n */\ncontract SharedReentrancyGuard {\n /*\n * This is the address of the mutex contract that will be used as the\n * reentrancy guard.\n *\n * The address is hardcoded to avoid changing the memory layout of\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\n * because the Mutex contract is always deployed to the same address, with the\n * same method used in the deployment of ERC1820Registry.\n */\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\n\n /*\n * This is the modifier that will be used to protect functions from\n * reentrancy. It will call the mutex contract to increment the mutex\n * state and then revert if the mutex state was changed by another\n * nested call.\n */\n modifier globallyNonReentrant() {\n uint256 previous = MUTEX.incrementAndGetValue();\n\n _;\n\n /*\n * If the mutex state was changed by a nested function call, then\n * the value of the state variable will be different from the previous value.\n */\n require(previous == MUTEX.value(), \"reentrancy violation\");\n }\n}\n" + }, + "contracts/rsk/RSKAddrValidator.sol": { + "content": "// SPDX-License-Identifier:MIT\npragma solidity ^0.5.17;\n\nlibrary RSKAddrValidator {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n * */\n function checkPKNotZero(address addr) internal pure returns (bool) {\n return (addr != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && addr != address(0));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key.\n * */\n function safeEquals(address addr1, address addr2) internal pure returns (bool) {\n return (addr1 == addr2 &&\n addr1 != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\n addr1 != address(0));\n }\n}\n" + }, + "contracts/swaps/connectors/interfaces/IContractRegistry.sol": { + "content": "pragma solidity 0.5.17;\n\ncontract IContractRegistry {\n function addressOf(bytes32 contractName) public view returns (address);\n}\n" + }, + "contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol": { + "content": "pragma solidity >=0.5.8 <=0.5.17;\n\nimport \"../../../interfaces/IERC20.sol\";\n\ncontract ISovrynSwapNetwork {\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256);\n\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\n\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory);\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwap.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../../core/State.sol\";\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\n\n/**\n * @dev WARNING: This contract is deprecated, all public functions are moved to the protocol modules.\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\ncontract SwapsImplSovrynSwap is State {\n using SafeERC20 for IERC20;\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n constructor() internal {\n // abstract\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destination tokens.\n * @param receiverAddress The address who will received the swap token results\n * @param returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * @param minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * @param maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address receiverAddress,\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n require(\n supportedTokens[sourceTokenAddress] && supportedTokens[destTokenAddress],\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = estimateSourceTokenAmount(\n sourceTokenAddress,\n destTokenAddress,\n requiredDestTokenAmount,\n maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n allowTransfer(sourceTokenAmountUsed, sourceTokenAddress, address(sovrynSwapNetwork));\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n uint256 sourceToDestPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n internalExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n maxSourceTokenAmount,\n sovrynSwapContractRegistryAddress\n );\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > sourceBuffer) buffer = sourceBuffer;\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistryAddress\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * @param sovrynSwapContractRegistry The sovryn swap contract reigstry address.\n * @param defaultPath The default path for specific pairs.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistry,\n IERC20[] memory defaultPath\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistry);\n\n IERC20[] memory path =\n defaultPath.length >= 3\n ? defaultPath\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\nimport \"../../interfaces/ISovryn.sol\";\n\n/**\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\nlibrary SwapsImplSovrynSwapLib {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n struct SwapParams {\n address sourceTokenAddress;\n address destTokenAddress;\n address receiverAddress;\n address returnToSenderAddress;\n uint256 minSourceTokenAmount;\n uint256 maxSourceTokenAmount;\n uint256 requiredDestTokenAmount;\n }\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param params SwapParams struct\n * sourceTokenAddress The address of the source tokens.\n * destTokenAddress The address of the destination tokens.\n * receiverAddress The address who will received the swap token results\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * requiredDestTokenAmount The required amount of destination tokens.\n * */\n function swap(SwapParams memory params)\n public\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(params.sourceTokenAddress != params.destTokenAddress, \"source == dest\");\n\n ISovryn iSovryn = ISovryn(address(this));\n require(\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\n iSovryn.supportedTokens(params.destTokenAddress),\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\n\n IERC20[] memory path =\n _getConversionPath(\n params.sourceTokenAddress,\n params.destTokenAddress,\n sovrynSwapNetwork\n );\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = params.minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (params.requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\n params.sourceTokenAddress,\n params.destTokenAddress,\n params.requiredDestTokenAmount,\n params.maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n params.requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = params.requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n _allowTransfer(\n sourceTokenAmountUsed,\n params.sourceTokenAddress,\n address(sovrynSwapNetwork)\n );\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n params.receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (params.returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(params.sourceTokenAddress).safeTransfer(\n params.returnToSenderAddress,\n params.maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function _allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function _estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n ISovryn iSovryn = ISovryn(address(this));\n uint256 sourceToDestPrecision =\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function getExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function getExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function _getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/testnet/SwapsImplLocal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../../core/State.sol\";\nimport \"../../../openzeppelin/SafeERC20.sol\";\nimport \"../../../feeds/IPriceFeeds.sol\";\nimport \"../../../testhelpers/TestToken.sol\";\n\n/**\n * @title Swaps Implementation Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate calculations.\n * */\ncontract SwapsImplLocal is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Swap two tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address, /*receiverAddress*/\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n\n (uint256 tradeRate, uint256 precision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n if (requiredDestTokenAmount == 0) {\n sourceTokenAmountUsed = minSourceTokenAmount;\n destTokenAmountReceived = minSourceTokenAmount.mul(tradeRate).div(precision);\n } else {\n destTokenAmountReceived = requiredDestTokenAmount;\n sourceTokenAmountUsed = requiredDestTokenAmount.mul(precision).div(tradeRate);\n require(sourceTokenAmountUsed <= minSourceTokenAmount, \"destAmount too great\");\n }\n\n TestToken(sourceTokenAddress).burn(address(this), sourceTokenAmountUsed);\n TestToken(destTokenAddress).mint(address(this), destTokenAmountReceived);\n\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Calculate the expected price rate of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n *\n * @return precision The expected price rate.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * @notice Calculate the expected return of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n * @param defaultPath defaultPath for swap.\n *\n * @return precision The expected return.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused,\n IERC20[] memory defaultPath\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n}\n" + }, + "contracts/swaps/SwapsUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../mixins/FeesHelper.sol\";\nimport \"./connectors/SwapsImplSovrynSwapLib.sol\";\n\n/**\n * @title Perform token swaps for loans and trades.\n * */\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\n /**\n * @notice Internal loan swap.\n *\n * @param loanId The ID of the loan.\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of destination tokens.\n * @param user The user address.\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * @param bypassFee To bypass or not the fee.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived\n * @return sourceTokenAmountUsed\n * @return sourceToDestSwapRate\n * */\n function _loanSwap(\n bytes32 loanId,\n address sourceToken,\n address destToken,\n address user,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount,\n bool bypassFee,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 sourceToDestSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n address(this), // receiver\n address(this), // returnToSender\n user\n ],\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\n loanId,\n bypassFee,\n loanDataBytes,\n false // swap external flag, set to false so that it will use the tradingFeePercent\n );\n\n /// Will revert if swap size too large.\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\n\n /// Will revert if disagreement found.\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived,\n maxDisagreement\n );\n\n emit LoanSwap(\n loanId,\n sourceToken,\n destToken,\n user,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Wrapper for _swapsCall_internal function.\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n * @param loanId The Id of the associated loan.\n * @param miscBool True/false to bypassFee.\n * @param loanDataBytes Additional loan data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall(\n address[5] memory addrs,\n uint256[3] memory vals,\n bytes32 loanId,\n bool miscBool, /// bypassFee\n bytes memory loanDataBytes,\n bool isSwapExternal\n ) internal returns (uint256, uint256) {\n /// addrs[0]: sourceToken\n /// addrs[1]: destToken\n /// addrs[2]: receiver\n /// addrs[3]: returnToSender\n /// addrs[4]: user\n /// vals[0]: minSourceTokenAmount\n /// vals[1]: maxSourceTokenAmount\n /// vals[2]: requiredDestTokenAmount\n\n require(vals[0] != 0 || vals[1] != 0, \"min or max source token amount needs to be set\");\n\n if (vals[1] == 0) {\n vals[1] = vals[0];\n }\n require(vals[0] <= vals[1], \"sourceAmount larger than max\");\n\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n\n uint256 tradingFee;\n if (!miscBool) {\n /// bypassFee\n if (vals[2] == 0) {\n /// condition: vals[0] will always be used as sourceAmount\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[0]);\n } else {\n tradingFee = _getTradingFee(vals[0]);\n }\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId,\n addrs[0], /// sourceToken (feeToken)\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n vals[0] = vals[0].sub(tradingFee);\n }\n } else {\n /// Condition: unknown sourceAmount will be used.\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[2]);\n } else {\n tradingFee = _getTradingFee(vals[2]);\n }\n\n if (tradingFee != 0) {\n vals[2] = vals[2].add(tradingFee);\n }\n }\n }\n\n require(loanDataBytes.length == 0, \"invalid state\");\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\n\n if (vals[2] == 0) {\n /// There's no minimum destTokenAmount, but all of vals[0]\n /// (minSourceTokenAmount) must be spent.\n require(sourceTokenAmountUsed == vals[0], \"swap too large to fill\");\n\n if (tradingFee != 0) {\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\n }\n } else {\n /// There's a minimum destTokenAmount required, but\n /// sourceTokenAmountUsed won't be greater\n /// than vals[1] (maxSourceTokenAmount)\n require(sourceTokenAmountUsed <= vals[1], \"swap fill too large\");\n require(destTokenAmountReceived >= vals[2], \"insufficient swap liquidity\");\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId, /// loanId,\n addrs[1], /// destToken (feeToken)\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\n }\n }\n\n return (destTokenAmountReceived, sourceTokenAmountUsed);\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Calls swapsImpl::internalSwap\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\n internal\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n SwapsImplSovrynSwapLib.SwapParams memory swapParams;\n\n swapParams.sourceTokenAddress = addrs[0];\n swapParams.destTokenAddress = addrs[1];\n swapParams.receiverAddress = addrs[2];\n swapParams.returnToSenderAddress = addrs[3];\n swapParams.minSourceTokenAmount = vals[0];\n swapParams.maxSourceTokenAmount = vals[1];\n swapParams.requiredDestTokenAmount = vals[2];\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = SwapsImplSovrynSwapLib.swap(swapParams);\n }\n\n /**\n * @notice Calculate expected amount of destination tokens.\n *\n * @dev Calls swapsImpl::internalExpectedReturn\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destination tokens.\n * @param sourceTokenAmount The amount of the source tokens.\n *\n * @param destTokenAmount The amount of destination tokens.\n * */\n function _swapsExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) internal view returns (uint256 destTokenAmount) {\n destTokenAmount = SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceToken,\n destToken,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Verify that the amount of tokens are under the swap limit.\n *\n * @dev Calls priceFeeds::amountInEth\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n * */\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\n uint256 _maxSwapSize = maxSwapSize;\n if (_maxSwapSize != 0) {\n uint256 amountInEth;\n if (tokenAddress == address(wrbtcToken)) {\n amountInEth = amount;\n } else {\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\n }\n require(amountInEth <= _maxSwapSize, \"swap too large\");\n }\n }\n}\n" + }, + "contracts/testhelpers/FlashLoanerTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n// \"SPDX-License-Identifier: Apache-2.0\"\n\nimport \"../interfaces/IERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./ITokenFlashLoanTest.sol\";\n\ncontract FlashLoanerTest is Ownable {\n function initiateFlashLoanTest(\n address loanToken,\n address iToken,\n uint256 flashLoanAmount\n ) internal returns (bytes memory success) {\n ITokenFlashLoanTest iTokenContract = ITokenFlashLoanTest(iToken);\n return\n iTokenContract.flashBorrow(\n flashLoanAmount,\n address(this),\n address(this),\n \"\",\n abi.encodeWithSignature(\n \"executeOperation(address,address,uint256)\",\n loanToken,\n iToken,\n flashLoanAmount\n )\n );\n }\n\n function repayFlashLoan(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) internal {\n IERC20(loanToken).transfer(iToken, loanAmount);\n }\n\n function executeOperation(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) external returns (bytes memory success) {\n emit BalanceOf(IERC20(loanToken).balanceOf(address(this)));\n emit ExecuteOperation(loanToken, iToken, loanAmount);\n repayFlashLoan(loanToken, iToken, loanAmount);\n return bytes(\"1\");\n }\n\n function doStuffWithFlashLoan(\n address token,\n address iToken,\n uint256 amount\n ) external onlyOwner {\n bytes memory result;\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n result = initiateFlashLoanTest(token, iToken, amount);\n\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n // after loan checks and what not.\n if (hashCompareWithLengthCheck(bytes(\"1\"), result)) {\n revert(\"failed executeOperation\");\n }\n }\n\n function hashCompareWithLengthCheck(bytes memory a, bytes memory b)\n internal\n pure\n returns (bool)\n {\n if (a.length != b.length) {\n return false;\n } else {\n return keccak256(a) == keccak256(b);\n }\n }\n\n event ExecuteOperation(address loanToken, address iToken, uint256 loanAmount);\n\n event BalanceOf(uint256 balance);\n}\n" + }, + "contracts/testhelpers/interfaces/IERC1820Registry.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the global ERC1820 Registry, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register\n * implementers for interfaces in this registry, as well as query support.\n *\n * Implementers may be shared by multiple accounts, and can also implement more\n * than a single interface for each account. Contracts can implement interfaces\n * for themselves, but externally-owned accounts (EOA) must delegate this to a\n * contract.\n *\n * {IERC165} interfaces can also be queried via the registry.\n *\n * For an in-depth explanation and source code analysis, see the EIP text.\n */\ninterface IERC1820Registry {\n /**\n * @dev Sets `newManager` as the manager for `account`. A manager of an\n * account is able to set interface implementers for it.\n *\n * By default, each account is its own manager. Passing a value of `0x0` in\n * `newManager` will reset the manager to this initial state.\n *\n * Emits a {ManagerChanged} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n */\n function setManager(address account, address newManager) external;\n\n /**\n * @dev Returns the manager for `account`.\n *\n * See {setManager}.\n */\n function getManager(address account) external view returns (address);\n\n /**\n * @dev Sets the `implementer` contract as `account`'s implementer for\n * `interfaceHash`.\n *\n * `account` being the zero address is an alias for the caller's address.\n * The zero address can also be used in `implementer` to remove an old one.\n *\n * See {interfaceHash} to learn how these are created.\n *\n * Emits an {InterfaceImplementerSet} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not\n * end in 28 zeroes).\n * - `implementer` must implement {IERC1820Implementer} and return true when\n * queried for support, unless `implementer` is the caller. See\n * {IERC1820Implementer-canImplementInterfaceForAddress}.\n */\n function setInterfaceImplementer(\n address account,\n bytes32 interfaceHash,\n address implementer\n ) external;\n\n /**\n * @dev Returns the implementer of `interfaceHash` for `account`. If no such\n * implementer is registered, returns the zero address.\n *\n * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28\n * zeroes), `account` will be queried for support of it.\n *\n * `account` being the zero address is an alias for the caller's address.\n */\n function getInterfaceImplementer(address account, bytes32 interfaceHash)\n external\n view\n returns (address);\n\n /**\n * @dev Returns the interface hash for an `interfaceName`, as defined in the\n * corresponding\n * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].\n */\n function interfaceHash(string calldata interfaceName) external pure returns (bytes32);\n\n /**\n * @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n * @param account Address of the contract for which to update the cache.\n * @param interfaceId ERC165 interface for which to update the cache.\n */\n function updateERC165Cache(address account, bytes4 interfaceId) external;\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not.\n * If the result is not cached a direct lookup on the contract address is performed.\n * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n * {updateERC165Cache} with the contract address.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165Interface(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n event InterfaceImplementerSet(\n address indexed account,\n bytes32 indexed interfaceHash,\n address indexed implementer\n );\n\n event ManagerChanged(address indexed account, address indexed newManager);\n}\n" + }, + "contracts/testhelpers/ITokenFlashLoanTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n// \"SPDX-License-Identifier: Apache-2.0\"\n\ninterface ITokenFlashLoanTest {\n function flashBorrow(\n uint256 borrowAmount,\n address borrower,\n address target,\n string calldata signature,\n bytes calldata data\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/testhelpers/LoanTokenLogicTest.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicTest is LoanTokenLogic {\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestNonReentrantValueSetter.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\ncontract TestNonReentrantValueSetter is SharedReentrancyGuard {\n uint256 public value;\n\n // This will fail if another globallyNonReentrant function has already been entered\n function setValue(uint256 newValue) public globallyNonReentrant {\n value = newValue;\n }\n\n // this will always fail if `other.setValue` is globallyNonReentrant\n function setOtherContractValueNonReentrant(address other, uint256 newValue)\n external\n globallyNonReentrant\n {\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n\n // this is intentionally not globallyNonReentrant and should work even if both contracts are non-reentrant\n function setThisAndOtherContractValue(address other, uint256 newValue) external {\n setValue(newValue);\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestValueSetterProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract TestValueSetterProxy is UpgradableProxy {\n // This is here for the memory layout\n uint256 public value;\n}\n" + }, + "contracts/testhelpers/staking/StakingTester.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../TestToken.sol\";\n\ncontract StakingTester {\n IStaking public staking;\n TestToken public token;\n\n constructor(address _staking, address _token) public {\n staking = IStaking(_staking);\n token = TestToken(_token);\n }\n\n function stakeAndWithdraw(uint96 _amount, uint256 _until) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _until, address(this), address(this));\n staking.withdraw(_amount, _until, address(this));\n }\n\n function stakeAndDelegate(\n uint96 _amount,\n address _delegatee,\n uint256 _lockDate\n ) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _lockDate, address(this), address(this));\n staking.delegate(_delegatee, _lockDate);\n }\n}\n" + }, + "contracts/testhelpers/TestCoverage.sol": { + "content": "/**\n * In order to test some functionalities like Pausable::pausable() modifier,\n * it is required to add a contract to invoke them and get a full coverage on tests.\n */\n\npragma solidity 0.5.17;\n\nimport \"../connectors/loantoken/Pausable.sol\";\nimport \"../governance/Staking/SafeMath96.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../connectors/loantoken/AdvancedToken.sol\";\nimport \"../connectors/loantoken/LoanTokenLogicStorage.sol\";\n\ncontract TestCoverage is\n Pausable,\n SafeMath96,\n VaultController,\n AdvancedToken,\n LoanTokenLogicStorage\n{\n /// @dev Pausable is currently an unused contract that still is operative\n /// because margin trade flashloan functionality has been commented out.\n /// In case it were restored, contract would become used again, so for a\n /// complete test coverage it is required to test it.\n\n function dummyPausableFunction() external pausable(msg.sig) {\n /// @dev do nothing, just to check if modifier is working\n }\n\n /// @dev This function should be located on Pausable contract in the case\n /// it has to be used again by flashloan restoration.\n function togglePause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047)\n )\n );\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /// @dev Testing internal functions of governance/Staking/SafeMath96.sol\n function testSafeMath96_safe32(uint256 n) public pure returns (uint32) {\n // Public wrapper for SafeMath96 internal function\n return safe32(n, \"overflow\");\n }\n\n function testSafeMath96_safe64(uint256 n) public pure returns (uint64) {\n // Public wrapper for SafeMath96 internal function\n return safe64(n, \"overflow\");\n }\n\n function testSafeMath96_safe96(uint256 n) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return safe96(n, \"overflow\");\n }\n\n function testSafeMath96_sub96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return sub96(a, b, \"underflow\");\n }\n\n function testSafeMath96_mul96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return mul96(a, b, \"overflow\");\n }\n\n function testSafeMath96_div96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return div96(a, b, \"division by 0\");\n }\n\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;\n EnumerableBytes32Set.Bytes32Set internal aSet;\n\n function testEnum_AddRemove(bytes32 a, bytes32 b) public returns (bool) {\n aSet.addBytes32(a);\n return aSet.removeBytes32(b);\n }\n\n function testEnum_AddAddress(address a, address b) public returns (bool) {\n aSet.addAddress(a);\n return aSet.containsAddress(b);\n }\n\n function testEnum_AddAddressesAndEnumerate(\n address a,\n address b,\n uint256 start,\n uint256 count\n ) public returns (bytes32[] memory) {\n aSet.addAddress(a);\n aSet.addAddress(b);\n return aSet.enumerate(start, count);\n }\n\n /// @dev Wrapper to test internal function never called along current codebase\n function testVaultController_vaultApprove(\n address token,\n address to,\n uint256 value\n ) public {\n vaultApprove(token, to, value);\n }\n\n /// @dev mint wrapper w/o previous checks\n function testMint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) public {\n _mint(_to, _tokenAmount, _assetAmount, _price);\n }\n\n /// @dev wrapper for a function unreachable to tests\n function testStringToBytes32(string memory source) public pure returns (bytes32 result) {\n return stringToBytes32(source);\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some ERC777 from the lending pool.\n * 2. Close the loan with closeWithDeposit function in the protocol.\n * 3. Burn all iERC777.\n *\n * The cross-reentrancy happened in step#3. It might happened through a hook function (tokensToSend) that is implemented in this contract to support the ERC777 transfer.\n * Inside the hook function, it will try to mint the iERC777.\n * The details about the hook functions can be found here: https://eips.ethereum.org/EIPS/eip-777#hooks\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithDeposit function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyERC777 {\n address public loanToken;\n address public WRBTC;\n address public SUSD; /// ERC777\n ProtocolLike public sovrynProtocol;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iUSDTBalance;\n }\n\n function() external payable {}\n\n constructor(\n address _loanToken,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanToken = _loanToken;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777TokensSender\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: WRBTC has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n });\n\n IERC20(WRBTC).approve(loanToken, initial.susdBalance);\n\n ILoanTokenModules(loanToken).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n WRBTC,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanToken).loanParamsIds(\n uint256(keccak256(abi.encodePacked(WRBTC, true)))\n );\n bytes32 loan_id =\n keccak256(abi.encodePacked(loanParamsLocalId, loanToken, _borrower, _borrowerNonce));\n\n // STEP 3 close the borrowed position with a deposit\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(address(sovrynProtocol), _SUSDBalance);\n sovrynProtocol.closeWithDeposit(\n loan_id,\n address(this),\n collateralTokenSent.mul(20).div(100) // make it 20% higher from initial borrow amount\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iSUSD\n uint256 _iSUSDBalance = ILoanTokenModules(loanToken).balanceOf(_borrower);\n ILoanTokenModules(loanToken).burn(_receiver, _iSUSDBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n // });\n }\n\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256,\n bytes calldata,\n bytes calldata\n ) external {\n if (operator == address(sovrynProtocol) && to == loanToken && from == address(this)) {\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(loanToken, _SUSDBalance);\n\n ILoanTokenModules(loanToken).mint(address(this), 1000000 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyRBTC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some WRBTC from the lending pool.\n * 2. Close the loan with closeWithSwap function in the protocol.\n * 3. Burn all iWRBTC.\n *\n * The refund happened in step #3, which will send back the RBTC back to this contract.\n * Then, this contract will try to do another iWRBTC minting to the loan token --> this is where the cross-reentrancy happened between the protocol & the loan token contract.\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithSwap function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyRBTC {\n address public loanTokenWRBTC;\n address public WRBTC;\n address public SUSD;\n ProtocolLike public sovrynProtocol;\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iWRBTCBalance;\n }\n\n function() external payable {\n if (msg.sender == address(sovrynProtocol)) {\n uint256 latestRBTCBalance = address(this).balance;\n IWrbtcERC20(WRBTC).deposit.value(14 ether)();\n uint256 _WRBTCBalance = IERC20(WRBTC).balanceOf(address(this));\n IERC20(WRBTC).approve(loanTokenWRBTC, _WRBTCBalance);\n\n ILoanTokenModules(loanTokenWRBTC).mint(address(this), 14 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n\n constructor(\n address _loanTokenWRBTC,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanTokenWRBTC = _loanTokenWRBTC;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: SUSD has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n });\n\n IERC20(SUSD).approve(loanTokenWRBTC, initial.susdBalance);\n\n ILoanTokenModules(loanTokenWRBTC).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n SUSD,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanTokenWRBTC).loanParamsIds(\n uint256(keccak256(abi.encodePacked(SUSD, true)))\n );\n bytes32 loan_id =\n keccak256(\n abi.encodePacked(loanParamsLocalId, loanTokenWRBTC, _borrower, _borrowerNonce)\n );\n\n // STEP 3 close the borrowed position with a swap (probably works just as well with deposit)\n sovrynProtocol.closeWithSwap(\n loan_id,\n msg.sender,\n collateralTokenSent.mul(200).div(100), // make it 20% higher from initial collateral sent to make sure whole position is closed\n true,\n \"\"\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iRBTC\n uint256 _iWRBTCBalance = ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower);\n ILoanTokenModules(loanTokenWRBTC).burn(_receiver, _iWRBTCBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n // });\n }\n}\n" + }, + "contracts/testhelpers/TestLibraries.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../rsk/RSKAddrValidator.sol\";\n\n// contract for testing libraries\ncontract TestLibraries {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n */\n function RSKAddrValidator_checkPKNotZero(address addr) public pure returns (bool) {\n return (RSKAddrValidator.checkPKNotZero(addr));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key\n */\n function RSKAddrValidator_safeEquals(address addr1, address addr2) public pure returns (bool) {\n return (RSKAddrValidator.safeEquals(addr1, addr2));\n }\n}\n" + }, + "contracts/testhelpers/TestSovrynSwap.sol": { + "content": "/**\n * Test file simulating the SovrynSwap network\n * */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"./TestToken.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestSovrynSwap {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n address public priceFeeds;\n\n constructor(address feed) public {\n priceFeeds = feed;\n }\n\n /**\n * simulating the contract registry. always returns the address of this contract\n * */\n function addressOf(bytes32 contractName) public view returns (address) {\n return address(this);\n }\n\n /**\n * calculates the return tokens when swapping _amount, makes sure the return is bigger than _minReturn,\n * mints and burns the test tokens accordingly.\n * */\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256) {\n //compute the return for the amount of tokens provided\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n uint256 actualReturn = _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n\n require(actualReturn >= _minReturn, \"insufficient source tokens provided\");\n\n TestToken(address(_path[0])).burn(address(msg.sender), _amount);\n TestToken(address(_path[1])).mint(address(_beneficiary), actualReturn);\n return actualReturn;\n }\n\n /**\n * queries the rate from the Price Feed contract and computes the expected return amount based on the\n * amout of source tokens to be swapped.\n * */\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n\n return _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * returns the conversion path -> always a direct path\n * */\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory)\n {\n IERC20[] memory path = new IERC20[](2);\n path[0] = _sourceToken;\n path[1] = _targetToken;\n return path;\n }\n}\n" + }, + "contracts/testhelpers/TestToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestToken {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balances[_who], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[_who] = balances[_who].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(_who, _value);\n emit Transfer(_who, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/testhelpers/TestTokenERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Context.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../interfaces/IERC777.sol\";\nimport \"../interfaces/IERC777Recipient.sol\";\nimport \"../interfaces/IERC777Sender.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\n\ncontract TestTokenERC777 is Context, IERC777, IERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n mapping(address => uint256) private _balances;\n\n uint256 private _totalSupply;\n\n // We inline the result of the following hashes because Solidity doesn't resolve them at compile time.\n // See https://github.com/ethereum/solidity/issues/4024.\n\n // keccak256(\"ERC777TokensSender\")\n bytes32 private constant TOKENS_SENDER_INTERFACE_HASH =\n 0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895;\n\n // keccak256(\"ERC777TokensRecipient\")\n bytes32 private constant TOKENS_RECIPIENT_INTERFACE_HASH =\n 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;\n\n // This isn't ever read from - it's only used to respond to the defaultOperators query.\n address[] private _defaultOperatorsArray;\n\n // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).\n mapping(address => bool) private _defaultOperators;\n\n // For each account, a mapping of its operators and revoked default operators.\n mapping(address => mapping(address => bool)) private _operators;\n mapping(address => mapping(address => bool)) private _revokedDefaultOperators;\n\n // ERC20-allowances\n mapping(address => mapping(address => uint256)) private _allowances;\n\n /**\n * @dev `defaultOperators` may be an empty array.\n */\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _initialSupply,\n uint8 _decimals,\n address[] memory defaultOperators\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n _defaultOperatorsArray = defaultOperators;\n for (uint256 i = 0; i < _defaultOperatorsArray.length; i++) {\n _defaultOperators[_defaultOperatorsArray[i]] = true;\n }\n\n _mint(msg.sender, msg.sender, _initialSupply, \"\", \"\");\n\n // register interfaces\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777Token\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n /**\n * @dev See {IERC777-granularity}.\n *\n * This implementation always returns `1`.\n */\n function granularity() public view returns (uint256) {\n return 1;\n }\n\n /**\n * @dev See {IERC777-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev Returns the amount of tokens owned by an account (`tokenHolder`).\n */\n function balanceOf(address tokenHolder) public view returns (uint256) {\n return _balances[tokenHolder];\n }\n\n /**\n * @dev See {IERC777-send}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes memory data\n ) public {\n _send(_msgSender(), _msgSender(), recipient, amount, data, \"\", true);\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient}\n * interface if it is a contract.\n *\n * Also emits a {Sent} event.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n\n address from = _msgSender();\n\n _callTokensToSend(from, from, recipient, amount, \"\", \"\");\n\n _move(from, from, recipient, amount, \"\", \"\");\n\n _callTokensReceived(from, from, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev See {IERC777-burn}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function burn(uint256 amount, bytes memory data) public {\n _burn(_msgSender(), _msgSender(), amount, data, \"\");\n }\n\n /**\n * @dev See {IERC777-isOperatorFor}.\n */\n function isOperatorFor(address operator, address tokenHolder) public view returns (bool) {\n return\n operator == tokenHolder ||\n (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||\n _operators[tokenHolder][operator];\n }\n\n /**\n * @dev See {IERC777-authorizeOperator}.\n */\n function authorizeOperator(address operator) public {\n require(_msgSender() != operator, \"ERC777: authorizing self as operator\");\n\n if (_defaultOperators[operator]) {\n delete _revokedDefaultOperators[_msgSender()][operator];\n } else {\n _operators[_msgSender()][operator] = true;\n }\n\n emit AuthorizedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-revokeOperator}.\n */\n function revokeOperator(address operator) public {\n require(operator != _msgSender(), \"ERC777: revoking self as operator\");\n\n if (_defaultOperators[operator]) {\n _revokedDefaultOperators[_msgSender()][operator] = true;\n } else {\n delete _operators[_msgSender()][operator];\n }\n\n emit RevokedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-defaultOperators}.\n */\n function defaultOperators() public view returns (address[] memory) {\n return _defaultOperatorsArray;\n }\n\n /**\n * @dev See {IERC777-operatorSend}.\n *\n * Emits {Sent} and {IERC20-Transfer} events.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), sender),\n \"ERC777: caller is not an operator for holder\"\n );\n _send(_msgSender(), sender, recipient, amount, data, operatorData, true);\n }\n\n /**\n * @dev See {IERC777-operatorBurn}.\n *\n * Emits {Burned} and {IERC20-Transfer} events.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), account),\n \"ERC777: caller is not an operator for holder\"\n );\n _burn(_msgSender(), account, amount, data, operatorData);\n }\n\n /**\n * @dev See {IERC20-allowance}.\n *\n * Note that operator and allowance concepts are orthogonal: operators may\n * not have allowance, and accounts with allowance may not be operators\n * themselves.\n */\n function allowance(address holder, address spender) public view returns (uint256) {\n return _allowances[holder][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Note that accounts cannot have allowance issued by their operators.\n */\n function approve(address spender, uint256 value) public returns (bool) {\n address holder = _msgSender();\n _approve(holder, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Note that operator and allowance concepts are orthogonal: operators cannot\n * call `transferFrom` (unless they have allowance), and accounts with\n * allowance cannot call `operatorSend` (unless they are operators).\n *\n * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.\n */\n function transferFrom(\n address holder,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n require(holder != address(0), \"ERC777: transfer from the zero address\");\n\n address spender = _msgSender();\n\n _callTokensToSend(spender, holder, recipient, amount, \"\", \"\");\n\n _move(spender, holder, recipient, amount, \"\", \"\");\n\n _approve(\n holder,\n spender,\n _allowances[holder][spender].sub(amount, \"ERC777: transfer amount exceeds allowance\")\n );\n\n _callTokensReceived(spender, holder, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `operator`, `data` and `operatorData`.\n *\n * See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits {Minted} and {IERC20-Transfer} events.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - if `account` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function _mint(\n address operator,\n address account,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n require(account != address(0), \"ERC777: mint to the zero address\");\n\n // Update state variables\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n\n _callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);\n\n emit Minted(operator, account, amount, userData, operatorData);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Send tokens\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _send(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n require(from != address(0), \"ERC777: send from the zero address\");\n require(to != address(0), \"ERC777: send to the zero address\");\n\n _callTokensToSend(operator, from, to, amount, userData, operatorData);\n\n _move(operator, from, to, amount, userData, operatorData);\n\n _callTokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData,\n requireReceptionAck\n );\n }\n\n /**\n * @dev Burn tokens\n * @param operator address operator requesting the operation\n * @param from address token holder address\n * @param amount uint256 amount of tokens to burn\n * @param data bytes extra information provided by the token holder\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _burn(\n address operator,\n address from,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) internal {\n require(from != address(0), \"ERC777: burn from the zero address\");\n\n _callTokensToSend(operator, from, address(0), amount, data, operatorData);\n\n // Update state variables\n _balances[from] = _balances[from].sub(amount, \"ERC777: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n\n emit Burned(operator, from, amount, data, operatorData);\n emit Transfer(from, address(0), amount);\n }\n\n function _move(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) private {\n _balances[from] = _balances[from].sub(amount, \"ERC777: transfer amount exceeds balance\");\n _balances[to] = _balances[to].add(amount);\n\n emit Sent(operator, from, to, amount, userData, operatorData);\n emit Transfer(from, to, amount);\n }\n\n function _approve(\n address holder,\n address spender,\n uint256 value\n ) internal {\n // TODO: restore this require statement if this function becomes internal, or is called at a new callsite. It is\n // currently unnecessary.\n //require(holder != address(0), \"ERC777: approve from the zero address\");\n require(spender != address(0), \"ERC777: approve to the zero address\");\n\n _allowances[holder][spender] = value;\n emit Approval(holder, spender, value);\n }\n\n /**\n * @dev Call from.tokensToSend() if the interface is registered\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _callTokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Sender(implementer).tokensToSend(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n }\n }\n\n /**\n * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but\n * tokensReceived() was not registered for the recipient\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _callTokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Recipient(implementer).tokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n } else if (requireReceptionAck) {\n require(\n !to.isContract(),\n \"ERC777: token recipient contract has no implementer for ERC777TokensRecipient\"\n );\n }\n }\n\n function mint(address _to, uint256 _value) public {\n // Update state variables\n _totalSupply = _totalSupply.add(_value);\n _balances[_to] = _balances[_to].add(_value);\n\n emit Minted(msg.sender, _to, _value, \"\", \"\");\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balanceOf(_who), \"balance too low\");\n\n _burn(msg.sender, _who, _value, \"\", \"\");\n }\n}\n" + }, + "contracts/testhelpers/TestTokenLimited.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestTokenLimited {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n require(_value <= 100000 ether, \"max mint amount exceeded\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(uint256 _value) public {\n require(_value <= balances[msg.sender], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(msg.sender, _value);\n emit Transfer(msg.sender, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/token/IApproveAndCall.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/ApprovalReceiver.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IApproveAndCall {\n /**\n * @notice Receives approval from SOV token.\n * @param _sender The sender of SOV.approveAndCall function.\n * @param _amount The amount was approved.\n * @param _token The address of token.\n * @param _data The data will be used for low level call.\n * */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/token/SOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/ERC20Detailed.sol\";\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./IApproveAndCall.sol\";\n\n/**\n * @title Sovryn Token: SOV is an ERC-20 token contract for Sovryn governance.\n *\n * @notice This contract accounts for all holders' balances.\n *\n * @dev This contract represents a token with dynamic supply.\n * The owner of the token contract can mint/burn tokens to/from any account\n * based upon previous governance voting and approval.\n * */\ncontract SOV is ERC20, ERC20Detailed, Ownable {\n string constant NAME = \"Sovryn Token\";\n string constant SYMBOL = \"SOV\";\n uint8 constant DECIMALS = 18;\n\n /**\n * @notice Constructor called on deployment, initiates the contract.\n * @dev On deployment, some amount of tokens will be minted for the owner.\n * @param _initialAmount The amount of tokens to be minted on contract creation.\n * */\n constructor(uint256 _initialAmount) public ERC20Detailed(NAME, SYMBOL, DECIMALS) {\n if (_initialAmount != 0) {\n _mint(msg.sender, _initialAmount);\n }\n }\n\n /**\n * @notice Creates new tokens and sends them to the recipient.\n * @dev Don't create more than 2^96/10 tokens before updating the governance first.\n * @param _account The recipient address to get the minted tokens.\n * @param _amount The amount of tokens to be minted.\n * */\n function mint(address _account, uint256 _amount) public onlyOwner {\n _mint(_account, _amount);\n }\n\n /**\n * @notice Approves and then calls the receiving contract.\n * Useful to encapsulate sending tokens to a contract in one call.\n * Solidity has no native way to send tokens to contracts.\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\n * @param _spender The contract address to spend the tokens.\n * @param _amount The amount of tokens to be sent.\n * @param _data Parameters for the contract call, such as endpoint signature.\n * */\n function approveAndCall(\n address _spender,\n uint256 _amount,\n bytes memory _data\n ) public {\n approve(_spender, _amount);\n IApproveAndCall(_spender).receiveApproval(msg.sender, _amount, address(this), _data);\n }\n}\n" + }, + "contracts/utils/AdminRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\n\ncontract AdminRole is Ownable {\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * or on our own overriding sovrynOwnable.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n}\n" + }, + "contracts/utils/PausableRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/PausableOz.sol\";\n\ncontract PausableRole is PausableOz {\n address public pauser;\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n\n /**\n * @dev Modifier to make a function callable only when the caller is pauser or owner\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"Pausable: unauthorized\"); // SS02\n _;\n }\n\n /**\n * @notice Set the pauser address.\n *\n * only pauser can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyPauserOrOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyPauserOrOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/utils/ProxyOwnable.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\n/**\n * Based on OpenZeppelin's Ownable contract:\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\n *\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract ProxyOwnable {\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Ownable:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"ProxyOwnable::setProxyOwner: invalid address\");\n emit ProxyOwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Set address of the owner (only owner can call this function)\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n\n /**\n * @notice Return address of the owner.\n * @return _owner Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n}\n" + }, + "contracts/utils/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\nlibrary Utils {\n function stringToBytes32(string memory source) internal pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + }, + "remappings": [] + } +} \ No newline at end of file diff --git a/deployment/deployments/rskSovrynMainnet/solcInputs/f540a853a80d796e3963ceeb76f3366c.json b/deployment/deployments/rskSovrynMainnet/solcInputs/f540a853a80d796e3963ceeb76f3366c.json new file mode 100644 index 000000000..20767e449 --- /dev/null +++ b/deployment/deployments/rskSovrynMainnet/solcInputs/f540a853a80d796e3963ceeb76f3366c.json @@ -0,0 +1,708 @@ +{ + "language": "Solidity", + "sources": { + "contracts/connectors/loantoken/AdvancedToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Advanced Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedToken implements standard ERC-20 approval, mint and burn token functionality.\n * Logic (AdvancedToken) is kept aside from storage (AdvancedTokenStorage).\n *\n * For example, LoanTokenLogicDai contract uses AdvancedToken::_mint() to mint\n * its Loan Dai iTokens.\n * */\ncontract AdvancedToken is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n /**\n * @notice Set an amount as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n *\n * @param _spender The account address that will be able to spend the tokens.\n * @param _value The amount of tokens allowed to spend.\n * */\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @notice The iToken minting process. Meant to issue Loan iTokens.\n * Lenders are able to open an iToken position, by minting them.\n * This function is called by LoanTokenLogicStandard::_mintToken\n * @param _to The recipient of the minted tTokens.\n * @param _tokenAmount The amount of iTokens to be minted.\n * @param _assetAmount The amount of lended tokens (asset to lend).\n * @param _price The price of the lended tokens.\n * @return The updated balance of the recipient.\n * */\n function _mint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n require(_to != address(0), \"15\");\n\n uint256 _balance = balances[_to].add(_tokenAmount);\n balances[_to] = _balance;\n\n totalSupply_ = totalSupply_.add(_tokenAmount);\n\n emit Mint(_to, _tokenAmount, _assetAmount, _price);\n emit Transfer(address(0), _to, _tokenAmount);\n\n return _balance;\n }\n\n /**\n * @notice The iToken burning process. Meant to destroy Loan iTokens.\n * Lenders are able to close an iToken position, by burning them.\n * This function is called by LoanTokenLogicStandard::_burnToken\n * @param _who The owner of the iTokens to burn.\n * @param _tokenAmount The amount of iTokens to burn.\n * @param _assetAmount The amount of lended tokens.\n * @param _price The price of the lended tokens.\n * @return The updated balance of the iTokens owner.\n * */\n function _burn(\n address _who,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n //bzx compare\n //TODO: Unit test\n uint256 _balance = balances[_who].sub(_tokenAmount, \"16\");\n\n // a rounding error may leave dust behind, so we clear this out\n if (_balance <= 10) {\n // We can't leave such small balance quantities.\n _tokenAmount = _tokenAmount.add(_balance);\n _balance = 0;\n }\n balances[_who] = _balance;\n\n totalSupply_ = totalSupply_.sub(_tokenAmount);\n\n emit Burn(_who, _tokenAmount, _assetAmount, _price);\n emit Transfer(_who, address(0), _tokenAmount);\n return _balance;\n }\n}\n" + }, + "contracts/connectors/loantoken/AdvancedTokenStorage.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./LoanTokenBase.sol\";\n\n/**\n * @title Advanced Token Storage contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedTokenStorage implements standard ERC-20 getters functionality:\n * totalSupply, balanceOf, allowance and some events.\n * iToken logic is divided into several contracts AdvancedToken,\n * AdvancedTokenStorage and LoanTokenBase.\n * */\ncontract AdvancedTokenStorage is LoanTokenBase {\n using SafeMath for uint256;\n\n /* Events */\n\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /* Storage */\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n /* Functions */\n\n /**\n * @notice Get the total supply of iTokens.\n * @return The total number of iTokens in existence as of now.\n * */\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n /**\n * @notice Get the amount of iTokens owned by an account.\n * @param _owner The account owner of the iTokens.\n * @return The number of iTokens an account owns.\n * */\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n /**\n * @notice Get the amount of iTokens allowed to be spent by a\n * given account on behalf of the owner.\n * @param _owner The account owner of the iTokens.\n * @param _spender The account allowed to send the iTokens.\n * @return The number of iTokens an account is allowing the spender\n * to send on its behalf.\n * */\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/connectors/loantoken/interfaces/FeedsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface FeedsLike {\n function queryRate(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 rate, uint256 precision);\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../lib/MarginTradeStructHelpers.sol\";\n\ninterface ProtocolLike {\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function priceFeeds() external view returns (address);\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function lendingFeePercent() external view returns (uint256);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function borrowerNonce(address) external view returns (uint256);\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata // for future use /*loanDataBytes*/\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolSettingsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../core/objects/LoanParamsStruct.sol\";\n\ninterface ProtocolSettingsLike {\n function setupLoanParams(LoanParamsStruct.LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n}\n" + }, + "contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol": { + "content": "pragma solidity 0.5.17;\n\nlibrary MarginTradeStructHelpers {\n struct SentAddresses {\n address lender;\n address borrower;\n address receiver;\n address manager;\n }\n\n struct SentAmounts {\n uint256 interestRate;\n uint256 newPrincipal;\n uint256 interestInitialAmount;\n uint256 loanTokenSent;\n uint256 collateralTokenSent;\n uint256 minEntryPrice;\n uint256 loanToCollateralSwapRate;\n uint256 interestDuration;\n uint256 entryLeverage;\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Loan Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * A loan token (iToken) is created as a proxy to an upgradable token contract.\n *\n * Examples of loan tokens on Sovryn are iRBTC, iDOC, iUSDT, iBPro,\n * iSOV (near future).\n *\n * Lenders receive iTokens that collect interest from the lending pool\n * which they can redeem by withdrawing them. The i in iToken stands for interest.\n *\n * Do not confuse iTokens with underlying tokens. iDOC is an iToken (loan token)\n * whilest DOC is the underlying token (currency).\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\n * */\ncontract LoanToken is AdvancedTokenStorage {\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n address public admin;\n\n /**\n * @notice Deploy loan token proxy.\n * Sets ERC20 parameters of the token.\n *\n * @param _newOwner The address of the new owner.\n * @param _newTarget The address of the new target contract instance.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice Public owner setter for target address.\n * @dev Calls internal setter.\n * @param _newTarget The address of the new target contract instance.\n * */\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n /**\n * @notice Internal setter for target address.\n * @param _newTarget The address of the new target contract instance.\n * */\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n /**\n * @notice Internal setter for sovrynContract address.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * */\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n /**\n * @notice Internal setter for wrBTC address.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n /**\n * @notice Public owner cloner for pointed loan token.\n * Sets ERC20 parameters of the token.\n *\n * @dev TODO: add check for double init.\n * idk but init usually can be called only once.\n *\n * @param _loanTokenAddress The address of the pointed loan token instance.\n * @param _name The ERC20 token name.\n * @param _symbol The ERC20 token symbol.\n * */\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; /// starting price of 1\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenBase.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SignedSafeMath.sol\";\nimport \"../../openzeppelin/ReentrancyGuard.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\nimport \"./Pausable.sol\";\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title Loan Token Base contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Specific loan related storage for iTokens.\n *\n * An loan token or iToken is a representation of a user funds in the pool and the\n * interest they've earned. The redemption value of iTokens continually increase\n * from the accretion of interest paid into the lending pool by borrowers. The user\n * can sell iTokens to exit its position. The user might potentially use them as\n * collateral wherever applicable.\n *\n * There are three main tokens in the bZx system, iTokens, pTokens, and BZRX tokens.\n * The bZx system of lending and borrowing depends on iTokens and pTokens, and when\n * users lend or borrow money on bZx, their crypto assets go into or come out of\n * global liquidity pools, which are pools of funds shared between many different\n * exchanges. When lenders supply funds into the global liquidity pools, they\n * automatically receive iTokens; When users borrow money to open margin trading\n * positions, they automatically receive pTokens. The system is also designed to\n * use the BZRX tokens, which are only used to pay fees on the network currently.\n * */\ncontract LoanTokenBase is ReentrancyGuard, SharedReentrancyGuard, Ownable, Pausable {\n uint256 internal constant WEI_PRECISION = 10**18;\n uint256 internal constant WEI_PERCENT_PRECISION = 10**20;\n\n int256 internal constant sWEI_PRECISION = 10**18;\n\n /// @notice Standard ERC-20 properties\n string public name;\n string public symbol;\n uint8 public decimals;\n\n /// @notice The address of the loan token (asset to lend) instance.\n address public loanTokenAddress;\n\n uint256 public baseRate;\n uint256 public rateMultiplier;\n uint256 public lowUtilBaseRate;\n uint256 public lowUtilRateMultiplier;\n\n uint256 public targetLevel;\n uint256 public kinkLevel;\n uint256 public maxScaleRate;\n\n uint256 internal _flTotalAssetSupply;\n uint256 public checkpointSupply;\n uint256 public initialPrice;\n\n /// uint88 for tight packing -> 8 + 88 + 160 = 256\n uint88 internal lastSettleTime_;\n\n /// Mapping of keccak256(collateralToken, isTorqueLoan) to loanParamsId.\n mapping(uint256 => bytes32) public loanParamsIds;\n\n /// Price of token at last user checkpoint.\n mapping(address => uint256) internal checkpointPrices_;\n\n // the maximum trading/borrowing/lending limit per token address\n mapping(address => uint256) public transactionLimit;\n // 0 -> no limit\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicBeacon.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../mixins/EnumerableBytes32Set.sol\";\nimport \"../../mixins/EnumerableBytes4Set.sol\";\nimport \"../../utils/PausableRole.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Loan Token Logic Beacon contract.\n *\n * @notice This contract stored the target logic implementation of LoanTokens which has the same logic implementation (LoanTokenLogicLM / LoanTokenLogicWrbtc)\n * Apart from storing the target logic implementation, this contract also has a pause functionality.\n * By implementing pause/unpause functionality in this beacon contract, we can pause the loan token that has the same Logic (LoanTokenLogicLM / LoanTokenLogicWrbtc) at one call.\n * Meanwhile the pause/unpause function in the LoanTokenLogicProxy is used to pause/unpause specific LoanToken\n */\n\ncontract LoanTokenLogicBeacon is PausableRole {\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; // enumerable map of bytes4 or addresses\n\n mapping(bytes4 => address) private logicTargets;\n\n struct LoanTokenLogicModuleUpdate {\n address implementation; // address implementaion of the module\n uint256 updateTimestamp; // time of update\n }\n\n mapping(bytes32 => LoanTokenLogicModuleUpdate[]) public moduleUpgradeLog; /** the module name as the key */\n\n mapping(bytes32 => uint256) public activeModuleIndex; /** To store the current active index log for module */\n\n mapping(bytes32 => EnumerableBytes4Set.Bytes4Set) private activeFuncSignatureList; /** Store the current active function signature */\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n * This is the overriden function from the pausable contract, so that we can use custom error message.\n */\n modifier whenNotPaused() {\n require(!_paused, \"LoanTokenLogicBeacon:paused mode\");\n _;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This function will store the updated protocol module to the storage (For rollback purposes)\n *\n * @param loanTokenModuleAddress The module target address\n */\n function registerLoanTokenModule(address loanTokenModuleAddress) external onlyOwner {\n bytes32 moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n\n // Store the upgrade to the log\n moduleUpgradeLog[moduleName].push(\n LoanTokenLogicModuleUpdate(loanTokenModuleAddress, block.timestamp)\n );\n activeModuleIndex[moduleName] = moduleUpgradeLog[moduleName].length - 1;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This registration will require target contract to have the exact function getListFunctionSignatures() which will return functionSignatureList and the moduleName in bytes32\n *\n * @param loanTokenModuleAddress the target logic of the loan token module\n *\n * @return the module name\n */\n function _registerLoanTokenModule(address loanTokenModuleAddress) private returns (bytes32) {\n require(\n Address.isContract(loanTokenModuleAddress),\n \"LoanTokenModuleAddress is not a contract\"\n );\n\n // Get the list of function signature on this loanTokenModulesAddress\n (bytes4[] memory functionSignatureList, bytes32 moduleName) =\n ILoanTokenLogicModules(loanTokenModuleAddress).getListFunctionSignatures();\n\n /// register / update the module function signature address implementation\n for (uint256 i; i < functionSignatureList.length; i++) {\n require(functionSignatureList[i] != bytes4(0x0), \"ERR_EMPTY_FUNC_SIGNATURE\");\n logicTargets[functionSignatureList[i]] = loanTokenModuleAddress;\n if (!activeFuncSignatureList[moduleName].contains(functionSignatureList[i]))\n activeFuncSignatureList[moduleName].addBytes4(functionSignatureList[i]);\n }\n\n /// delete the \"removed\" module function signature in the current implementation\n bytes4[] memory activeSignatureListEnum =\n activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n for (uint256 i; i < activeSignatureListEnum.length; i++) {\n bytes4 activeSigBytes = activeSignatureListEnum[i];\n if (logicTargets[activeSigBytes] != loanTokenModuleAddress) {\n logicTargets[activeSigBytes] = address(0);\n activeFuncSignatureList[moduleName].removeBytes4(activeSigBytes);\n }\n }\n\n return moduleName;\n }\n\n /**\n * @dev get all active function signature list based on the module name.\n *\n * @param moduleName in bytes32.\n *\n * @return the array of function signature.\n */\n function getActiveFuncSignatureList(bytes32 moduleName)\n public\n view\n returns (bytes4[] memory signatureList)\n {\n signatureList = activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n return signatureList;\n }\n\n /**\n * @dev Get total length of the module upgrade log.\n *\n * @param moduleName in bytes32.\n *\n * @return length of module upgrade log.\n */\n function getModuleUpgradeLogLength(bytes32 moduleName) external view returns (uint256) {\n return moduleUpgradeLog[moduleName].length;\n }\n\n /**\n * @notice This function will rollback particular module to the spesific index / version of deployment\n *\n * @param moduleName Name of module in bytes32 format\n * @param index index / version of previous deployment\n */\n function rollback(bytes32 moduleName, uint256 index) external onlyOwner {\n address loanTokenModuleAddress = moduleUpgradeLog[moduleName][index].implementation;\n moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n activeModuleIndex[moduleName] = index;\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(bytes4 sig) external view whenNotPaused returns (address) {\n return logicTargets[sig];\n }\n}\n\ninterface ILoanTokenLogicModules {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory, bytes32 moduleName);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicProxy.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./AdvancedTokenStorage.sol\";\nimport \"../../openzeppelin/Initializable.sol\";\n\n/**\n * @title Loan Token Logic Proxy contract.\n *\n * @notice This contract contains the proxy functionality and it will query the logic target from LoanTokenLogicBeacon\n * This contract will also has the pause/unpause functionality. The purpose of this pausability is so that we can pause/unpause from the loan token level.\n *\n */\ncontract LoanTokenLogicProxy is AdvancedTokenStorage {\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT\n */\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT (CONSTANT / IMMUTABLE)\n */\n\n bytes32 internal constant LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT =\n keccak256(\"LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT\");\n\n modifier onlyAdmin() {\n require(isOwner(), \"LoanTokenLogicProxy:unauthorized\");\n _;\n }\n\n /**\n * @notice Fallback function performs a logic implementation address query to LoanTokenLogicBeacon and then do delegate call to that query result address.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n // query the logic target implementation address from the LoanTokenLogicBeacon\n address target = ILoanTokenLogicBeacon(_beaconAddress()).getTarget(msg.sig);\n require(target != address(0), \"LoanTokenLogicProxy:target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @dev Returns the current Loan Token logic Beacon.\n * @return Address of the current LoanTokenLogicBeacon.\n */\n function _beaconAddress() internal view returns (address beaconAddress) {\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n assembly {\n beaconAddress := sload(slot)\n }\n }\n\n /**\n * @return The address of the current LoanTokenLogicBeacon.\n */\n function beaconAddress() external view returns (address) {\n return _beaconAddress();\n }\n\n /**\n * @dev Set/update the new beacon address.\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon.\n */\n function _setBeaconAddress(address _newBeaconAddress) private {\n require(\n Address.isContract(_newBeaconAddress),\n \"Cannot set beacon address to a non-contract address\"\n );\n\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n\n assembly {\n sstore(slot, _newBeaconAddress)\n }\n }\n\n /**\n * @dev External function to set the new LoanTokenLogicBeacon Address\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon\n */\n function setBeaconAddress(address _newBeaconAddress) external onlyAdmin {\n _setBeaconAddress(_newBeaconAddress);\n }\n\n /**\n * @dev External function to return the LoanTokenLogicProxy of loan token (target of LoanToken contract).\n * Ideally this getter should be added in the LoanToken contract\n * but since LoanToken contract can't be changed, adding the getter in this contract will do\n * because it will use the context of LoanToken contract.\n *\n * @return target address of LoanToken contract\n */\n function getTarget() external view returns (address) {\n return target_;\n }\n}\n\ninterface ILoanTokenLogicBeacon {\n function getTarget(bytes4 functionSignature)\n external\n view\n returns (address logicTargetAddress);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicShared.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicStorage.sol\";\nimport \"./interfaces/ProtocolLike.sol\";\nimport \"./interfaces/FeedsLike.sol\";\nimport \"./interfaces/ProtocolSettingsLike.sol\";\nimport \"../../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../../farm/ILiquidityMining.sol\";\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../governance/Vesting/IVesting.sol\";\n\n/**\n * @dev This contract shares functions used by both LoanTokenLogicSplit and LoanTokenLogicStandard\n */\ncontract LoanTokenLogicShared is LoanTokenLogicStorage {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /**\n * @notice Update the user's checkpoint price and profit so far.\n * In this loan token contract, whenever some tokens are minted or burned,\n * the _updateCheckpoints() function is invoked to update the stats to\n * reflect the balance changes.\n *\n * @param _user The user address.\n * @param _oldBalance The user's previous balance.\n * @param _newBalance The user's updated balance.\n * @param _currentPrice The current loan token price.\n * */\n function _updateCheckpoints(\n address _user,\n uint256 _oldBalance,\n uint256 _newBalance,\n uint256 _currentPrice\n ) internal {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(_user, iToken_ProfitSoFar));\n\n int256 _currentProfit;\n if (_newBalance == 0) {\n _currentPrice = 0;\n } else if (_oldBalance != 0) {\n _currentProfit = _profitOf(slot, _oldBalance, _currentPrice, checkpointPrices_[_user]);\n }\n\n assembly {\n sstore(slot, _currentProfit)\n }\n\n checkpointPrices_[_user] = _currentPrice;\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice Transfer tokens, low level.\n * Checks allowance, updates sender and recipient balances\n * and updates checkpoints too.\n *\n * @param _from The tokens' owner.\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @param _allowanceAmount The amount of tokens allowed to transfer.\n *\n * @return Success true/false.\n * */\n function _internalTransferFrom(\n address _from,\n address _to,\n uint256 _value,\n uint256 _allowanceAmount\n ) internal returns (bool) {\n if (_allowanceAmount != uint256(-1)) {\n allowed[_from][msg.sender] = _allowanceAmount.sub(_value, \"14\");\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, _allowanceAmount, allowed[_from][msg.sender]);\n }\n\n require(_to != address(0), \"15\");\n\n uint256 _balancesFrom = balances[_from];\n uint256 _balancesFromNew = _balancesFrom.sub(_value, \"16\");\n balances[_from] = _balancesFromNew;\n\n uint256 _balancesTo = balances[_to];\n uint256 _balancesToNew = _balancesTo.add(_value);\n balances[_to] = _balancesToNew;\n\n /// @dev Handle checkpoint update.\n uint256 _currentPrice = tokenPrice();\n\n //checkpoints are not being used by the smart contract logic itself, but just for external use (query the profit)\n //only update the checkpoints of a user if he's not depositing to / withdrawing from the lending pool\n if (_from != liquidityMiningAddress && _to != liquidityMiningAddress) {\n _updateCheckpoints(_from, _balancesFrom, _balancesFromNew, _currentPrice);\n _updateCheckpoints(_to, _balancesTo, _balancesToNew, _currentPrice);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n /**\n * @notice Profit calculation based on checkpoints of price.\n * @param slot The user slot.\n * @param _balance The user balance.\n * @param _currentPrice The current price of the loan token.\n * @param _checkpointPrice The price of the loan token on checkpoint.\n * @return The profit of a user.\n * */\n function _profitOf(\n bytes32 slot,\n uint256 _balance,\n uint256 _currentPrice,\n uint256 _checkpointPrice\n ) internal view returns (int256 profitSoFar) {\n if (_checkpointPrice == 0) {\n return 0;\n }\n\n assembly {\n profitSoFar := sload(slot)\n }\n\n profitSoFar = int256(_currentPrice)\n .sub(int256(_checkpointPrice))\n .mul(int256(_balance))\n .div(sWEI_PRECISION)\n .add(profitSoFar);\n }\n\n /**\n * @notice Loan token price calculation considering unpaid interests.\n * @return The loan token price.\n * */\n function tokenPrice() public view returns (uint256 price) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _tokenPrice(_totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Get the total amount of loan tokens on debt.\n * Calls protocol getTotalPrincipal function.\n * In the context of borrowing, principal is the initial size of a loan.\n * It can also be the amount still owed on a loan. If you take out a\n * $50,000 mortgage, for example, the principal is $50,000. If you pay off\n * $30,000, the principal balance now consists of the remaining $20,000.\n *\n * @return The total amount of loan tokens on debt.\n * */\n function totalAssetBorrow() public view returns (uint256) {\n return\n ProtocolLike(sovrynContractAddress).getTotalPrincipal(address(this), loanTokenAddress);\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice .\n *\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param withdrawalAmount The amount of tokens to withdraw.\n *\n * @return msgValue The amount of rBTC sent minus the collateral on tokens.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = loanTokenAddress;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n _safeTransfer(_loanTokenAddress, sentAddresses.receiver, withdrawalAmount, \"\");\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n /**\n * This is a critical piece of code!\n * rBTC are supposed to be held by the contract itself, while other tokens are being transfered from the sender directly.\n * */\n if (collateralTokenSent != 0) {\n if (\n collateralTokenAddress == _wrbtcToken &&\n msgValue != 0 &&\n msgValue >= collateralTokenSent\n ) {\n IWrbtc(_wrbtcToken).deposit.value(collateralTokenSent)();\n _safeTransfer(\n collateralTokenAddress,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-a\"\n );\n msgValue -= collateralTokenSent;\n } else {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-b\"\n );\n }\n }\n\n if (loanTokenSent != 0) {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n\n /**\n * @notice Withdraw loan token interests from protocol.\n * This function only operates once per block.\n * It asks protocol to withdraw accrued interests for the loan token.\n *\n * @dev Internal sync required on every loan trade before starting.\n * */\n function _settleInterest() internal {\n uint88 ts = uint88(block.timestamp);\n if (lastSettleTime_ != ts) {\n ProtocolLike(sovrynContractAddress).withdrawAccruedInterest(loanTokenAddress);\n\n lastSettleTime_ = ts;\n }\n }\n\n /**\n * @notice Imitate a Solidity high-level call (i.e. a regular function\n * call to a contract), relaxing the requirement on the return value:\n * the return value is optional (but if data is returned, it must not be\n * false).\n *\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n * @param errorMsg The error message on failure.\n * */\n function _callOptionalReturn(\n address token,\n bytes memory data,\n string memory errorMsg\n ) internal {\n require(Address.isContract(token), \"call to a non-contract address\");\n (bool success, bytes memory returndata) = token.call(data);\n require(success, errorMsg);\n\n if (returndata.length != 0) {\n require(abi.decode(returndata, (bool)), errorMsg);\n }\n }\n\n /**\n * @notice Execute the ERC20 token's `transfer` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransfer(\n address token,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transfer.selector, to, amount),\n errorMsg\n );\n }\n\n /**\n * @notice Execute the ERC20 token's `transferFrom` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param from The source address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransferFrom(\n address token,\n address from,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transferFrom.selector, from, to, amount),\n errorMsg\n );\n }\n\n /** Internal view function */\n /**\n * @notice Compute the token price.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The token price.\n * */\n function _tokenPrice(uint256 assetSupply) internal view returns (uint256) {\n uint256 totalTokenSupply = totalSupply_;\n\n return\n totalTokenSupply != 0 ? assetSupply.mul(10**18).div(totalTokenSupply) : initialPrice;\n }\n\n /**\n * @notice Get two kind of interests: owed per day and yet to be paid.\n * @return interestOwedPerDay The interest per day.\n * @return interestUnPaid The interest not yet paid.\n * */\n function _getAllInterest()\n internal\n view\n returns (uint256 interestOwedPerDay, uint256 interestUnPaid)\n {\n /// interestPaid, interestPaidDate, interestOwedPerDay, interestUnPaid, interestFeePercent, principalTotal\n uint256 interestFeePercent;\n (, , interestOwedPerDay, interestUnPaid, interestFeePercent, ) = ProtocolLike(\n sovrynContractAddress\n )\n .getLenderInterestData(address(this), loanTokenAddress);\n\n interestUnPaid = interestUnPaid.mul(SafeMath.sub(10**20, interestFeePercent)).div(10**20);\n }\n\n /**\n * @notice Compute the total amount of loan tokens on supply.\n * @param interestUnPaid The interest not yet paid.\n * @return assetSupply The total amount of loan tokens on supply.\n * */\n function _totalAssetSupply(uint256 interestUnPaid)\n internal\n view\n returns (uint256 assetSupply)\n {\n if (totalSupply_ != 0) {\n uint256 assetsBalance = _flTotalAssetSupply; /// Temporary locked totalAssetSupply during a flash loan transaction.\n if (assetsBalance == 0) {\n assetsBalance = _underlyingBalance().add(totalAssetBorrow());\n }\n\n return assetsBalance.add(interestUnPaid);\n }\n }\n\n /**\n * @notice Get the loan contract balance.\n * @return The balance of the loan token for this contract.\n * */\n function _underlyingBalance() internal view returns (uint256) {\n return IERC20(loanTokenAddress).balanceOf(address(this));\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicSplit.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\n/**\n * @title Loan Token Logic Standard contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Logic around loan tokens (iTokens) required to operate borrowing,\n * and margin trading financial processes.\n *\n * The user provides funds to the lending pool using the mint function and\n * withdraws funds from the lending pool using the burn function. Mint and\n * burn refer to minting and burning loan tokens. Loan tokens represent a\n * share of the pool and gather interest over time.\n *\n * Interest rates are determined by supply and demand. When a lender deposits\n * funds, the interest rates go down. When a trader borrows funds, the\n * interest rates go up. Fulcrum uses a simple linear interest rate formula\n * of the form y = mx + b. The interest rate starts at 1% when loans aren't\n * being utilized and scales up to 40% when all the funds in the loan pool\n * are being borrowed.\n *\n * The borrow rate is determined at the time of the loan and represents the\n * net contribution of each borrower. Each borrower's interest contribution\n * is determined by the utilization rate of the pool and is netted against\n * all prior borrows. This means that the total amount of interest flowing\n * into the lending pool is not directly changed by lenders entering or\n * exiting the pool. The entrance or exit of lenders only impacts how the\n * interest payments are split up.\n *\n * For example, if there are 2 lenders with equal holdings each earning\n * 5% APR, but one of the lenders leave, then the remaining lender will earn\n * 10% APR since the interest payments don't have to be split between two\n * individuals.\n * */\ncontract LoanTokenLogicSplit is LoanTokenLogicShared {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /* Public functions */\n\n /**\n * @notice Mint loan token wrapper.\n * Adds a check before calling low level _mintToken function.\n * The function retrieves the tokens from the message sender, so make sure\n * to first approve the loan token contract to access your funds. This is\n * done by calling approve(address spender, uint amount) on the ERC20\n * token contract, where spender is the loan token contract address and\n * amount is the amount to be deposited.\n *\n * @param receiver The account getting the minted tokens.\n * @param depositAmount The amount of underlying tokens provided on the\n * loan. (Not the number of loan tokens to mint).\n *\n * @return The amount of loan tokens minted.\n * */\n function mint(address receiver, uint256 depositAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice Burn loan token wrapper.\n * Adds a pay-out transfer after calling low level _burnToken function.\n * In order to withdraw funds to the pool, call burn on the respective\n * loan token contract. This will burn your loan tokens and send you the\n * underlying token in exchange.\n *\n * @param receiver The account getting the minted tokens.\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 loanAmountPaid)\n {\n loanAmountPaid = _burnToken(burnAmount);\n\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (loanAmountPaid != 0) {\n _safeTransfer(loanTokenAddress, receiver, loanAmountPaid, \"5\");\n }\n }\n\n /**\n * @notice transfers the underlying asset from the msg.sender and mints tokens for the receiver\n * @param receiver the address of the iToken receiver\n * @param depositAmount the amount of underlying assets to be deposited\n * @return the amount of iTokens issued\n */\n function _mintToken(address receiver, uint256 depositAmount)\n internal\n returns (uint256 mintAmount)\n {\n uint256 currentPrice;\n\n //calculate amount to mint and transfer the underlying asset\n (mintAmount, currentPrice) = _prepareMinting(depositAmount);\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n receiver\n );\n uint256 oldBalance = balances[receiver].add(balanceOnLM);\n uint256 newBalance = oldBalance.add(mintAmount);\n\n //mint the tokens to the receiver\n _mint(receiver, mintAmount, depositAmount, currentPrice);\n\n //update the checkpoint of the receiver\n _updateCheckpoints(receiver, oldBalance, newBalance, currentPrice);\n }\n\n /**\n * calculates the amount of tokens to mint and transfers the underlying asset to this contract\n * @param depositAmount the amount of the underyling asset deposited\n * @return the amount to be minted\n */\n function _prepareMinting(uint256 depositAmount)\n internal\n returns (uint256 mintAmount, uint256 currentPrice)\n {\n require(depositAmount != 0, \"17\");\n\n _settleInterest();\n\n currentPrice = _tokenPrice(_totalAssetSupply(0));\n mintAmount = depositAmount.mul(10**18).div(currentPrice);\n\n if (msg.value == 0) {\n _safeTransferFrom(loanTokenAddress, msg.sender, address(this), depositAmount, \"18\");\n } else {\n IWrbtc(wrbtcTokenAddress).deposit.value(depositAmount)();\n }\n }\n\n /**\n * @notice A wrapper for AdvancedToken::_burn\n *\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function _burnToken(uint256 burnAmount) internal returns (uint256 loanAmountPaid) {\n require(burnAmount != 0, \"19\");\n\n if (burnAmount > balanceOf(msg.sender)) {\n require(burnAmount == uint256(-1), \"32\");\n burnAmount = balanceOf(msg.sender);\n }\n\n _settleInterest();\n\n uint256 currentPrice = _tokenPrice(_totalAssetSupply(0));\n\n uint256 loanAmountOwed = burnAmount.mul(currentPrice).div(10**18);\n uint256 loanAmountAvailableInContract = _underlyingBalance();\n\n loanAmountPaid = loanAmountOwed;\n require(loanAmountPaid <= loanAmountAvailableInContract, \"37\");\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n uint256 oldBalance = balances[msg.sender].add(balanceOnLM);\n uint256 newBalance = oldBalance.sub(burnAmount);\n\n _burn(msg.sender, burnAmount, loanAmountPaid, currentPrice);\n\n //this function does not only update the checkpoints but also the current profit of the user\n //all for external use only\n _updateCheckpoints(msg.sender, oldBalance, newBalance, currentPrice);\n }\n\n function _mintWithLM(address receiver, uint256 depositAmount)\n internal\n returns (uint256 minted)\n {\n //mint the tokens for the receiver\n minted = _mintToken(receiver, depositAmount);\n\n //transfer the tokens from the receiver to the LM address\n _internalTransferFrom(receiver, liquidityMiningAddress, minted, minted);\n\n //inform the LM mining contract\n ILiquidityMining(liquidityMiningAddress).onTokensDeposited(receiver, minted);\n }\n\n function _burnFromLM(uint256 burnAmount) internal returns (uint256) {\n uint256 balanceOnLM =\n ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n require(balanceOnLM.add(balanceOf(msg.sender)) >= burnAmount, \"not enough balance\");\n\n if (balanceOnLM > 0) {\n //withdraw pool tokens and LM rewards to the passed address\n if (balanceOnLM < burnAmount) {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n balanceOnLM,\n msg.sender\n );\n } else {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n burnAmount,\n msg.sender\n );\n }\n }\n //burn the tokens of the msg.sender\n return _burnToken(burnAmount);\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStandard.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\ncontract LoanTokenLogicStandard is LoanTokenLogicShared {\n /**\n * @notice Transfer tokens wrapper.\n * Sets token owner the msg.sender.\n * Sets maximun allowance uint256(-1) to ensure tokens are always transferred.\n *\n * If the recipient (_to) is a vesting contract address, transfer the token to the tokenOwner of the vesting contract itself.\n *\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @return Success true/false.\n * */\n function transfer(address _to, uint256 _value) external returns (bool) {\n /** need additional check address(0) here to support backward compatibility\n * in case we don't want to activate this check, just need to set the stakingContractAddress to 0 address\n */\n if (\n stakingContractAddress != address(0) &&\n IStaking(stakingContractAddress).isVestingContract(_to)\n ) {\n (bool success, bytes memory data) =\n _to.staticcall(abi.encodeWithSelector(IVesting(_to).tokenOwner.selector));\n\n if (success) _to = abi.decode(data, (address));\n }\n\n return _internalTransferFrom(msg.sender, _to, _value, uint256(-1));\n }\n\n /**\n * @notice Moves `_value` loan tokens from `_from` to `_to` using the\n * allowance mechanism. Calls internal _internalTransferFrom function.\n *\n * @return A boolean value indicating whether the operation succeeded.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool) {\n return\n _internalTransferFrom(\n _from,\n _to,\n _value,\n //allowed[_from][msg.sender]\n ProtocolLike(sovrynContractAddress).isLoanPool(msg.sender)\n ? uint256(-1)\n : allowed[_from][msg.sender]\n );\n }\n\n /**\n * @notice Borrow funds from the pool.\n * The underlying loan token may not be used as collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * (150% of the withdrawn amount worth in collateral tokens).\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param borrower The one paying for the collateral.\n * @param receiver The one receiving the withdrawn amount.\n *\n * @return New principal and new collateral added to loan.\n * */\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes memory /// loanDataBytes: arbitrary order data (for future use).\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n )\n {\n require(withdrawAmount != 0, \"6\");\n\n _checkPause();\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n\n require(\n (msg.value == 0 || msg.value == collateralTokenSent) &&\n (collateralTokenSent != 0 || loanId != 0) &&\n (collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0) &&\n (loanId == 0 || msg.sender == borrower),\n \"7\"\n );\n\n /// @dev We have an issue regarding contract size code is too big. 1 of the solution is need to keep the error message 32 bytes length\n // Temporarily, we combine this require to the above, so can save the contract size code\n // require(collateralTokenSent != 0 || loanId != 0, \"8\");\n // require(collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0, \"9\");\n\n /// @dev Ensure authorized use of existing loan.\n // require(loanId == 0 || msg.sender == borrower, \"401 use of existing loan\");\n\n /// @dev The condition is never met.\n /// Address zero is not allowed by previous require validation.\n /// This check is unneeded and was lowering the test coverage index.\n // if (collateralTokenAddress == address(0)) {\n // \tcollateralTokenAddress = wrbtcTokenAddress;\n // }\n\n require(collateralTokenAddress != loanTokenAddress, \"10\");\n\n _settleInterest();\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this); /// The lender.\n sentAddresses.borrower = borrower;\n sentAddresses.receiver = receiver;\n /// sentAddresses.manager = address(0); /// The manager.\n\n sentAmounts.newPrincipal = withdrawAmount;\n\n /// interestRate, interestInitialAmount, borrowAmount (newBorrowAmount).\n (\n sentAmounts.interestRate,\n sentAmounts.interestInitialAmount,\n sentAmounts.newPrincipal\n ) = _getInterestRateAndBorrowAmount(\n sentAmounts.newPrincipal,\n _totalAssetSupply(0), /// Interest is settled above.\n initialLoanDuration\n );\n\n /// sentAmounts.loanTokenSent = 0; /// loanTokenSent\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n return\n _borrowOrTrade(\n loanId,\n withdrawAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ]\n ),\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Borrow and immediately get into a position.\n *\n * Trading on margin is used to increase an investor's buying power.\n * Margin is the amount of money required to open a position, while\n * leverage is the multiple of exposure to account equity.\n *\n * Leverage allows you to trade positions LARGER than the amount\n * of money in your trading account. Leverage is expressed as a ratio.\n *\n * When trading on margin, investors first deposit some token that then\n * serves as collateral for the loan, and then pay ongoing interest\n * payments on the money they borrow.\n *\n * Margin trading = taking a loan and swapping it:\n * In order to open a margin trade position,\n * 1.- The user calls marginTrade on the loan token contract.\n * 2.- The loan token contract provides the loan and sends it for processing\n * to the protocol proxy contract.\n * 3.- The protocol proxy contract uses the module LoanOpening to create a\n * position and swaps the loan tokens to collateral tokens.\n * 4.- The Sovryn Swap network looks up the correct converter and swaps the\n * tokens.\n * If successful, the position is being held by the protocol proxy contract,\n * which is why positions need to be closed at the protocol proxy contract.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n * */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // value of loan token in collateral\n bytes memory loanDataBytes /// Arbitrary order data.\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n _checkPause();\n\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n require(collateralTokenAddress != loanTokenAddress, \"11\");\n\n /// @dev Ensure authorized use of existing loan.\n require(loanId == 0 || msg.sender == trader, \"401 use of existing loan\");\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n if (transactionLimit[loanTokenAddress] > 0)\n require(loanTokenSent <= transactionLimit[loanTokenAddress]);\n\n /// @dev Compute the worth of the total deposit in loan tokens.\n /// (loanTokenSent + convert(collateralTokenSent))\n /// No actual swap happening here.\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n require(totalDeposit != 0, \"12\");\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this);\n sentAddresses.borrower = trader;\n sentAddresses.receiver = trader;\n /// sentAddresses.manager = address(0); /// The manager.\n\n /// sentAmounts.interestRate = 0; /// interestRate (found later).\n sentAmounts.newPrincipal = totalDeposit;\n /// sentAmounts.interestInitialAmount = 0; /// interestInitialAmount (interest is calculated based on fixed-term loan).\n sentAmounts.loanTokenSent = loanTokenSent;\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n _settleInterest();\n\n (sentAmounts.newPrincipal, sentAmounts.interestRate) = _getMarginBorrowAmountAndRate( /// borrowAmount, interestRate\n leverageAmount,\n sentAmounts.newPrincipal /// depositAmount\n );\n\n require(\n _getAmountInRbtc(loanTokenAddress, sentAmounts.newPrincipal) > TINY_AMOUNT,\n \"principal too small\"\n );\n\n /// @dev Converting to initialMargin\n leverageAmount = SafeMath.div(10**38, leverageAmount);\n sentAmounts.minEntryPrice = minEntryPrice;\n return\n _borrowOrTrade(\n loanId,\n 0, /// withdrawAmount\n leverageAmount, //initial margin\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n );\n }\n\n /**\n * @notice Wrapper for marginTrade invoking setAffiliatesReferrer to track\n * referral trade by affiliates program.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param affiliateReferrer The address of the referrer from affiliates program.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n */\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, /// Value of loan token in collateral\n address affiliateReferrer, /// The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n if (affiliateReferrer != address(0))\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(\n trader,\n affiliateReferrer\n );\n return\n marginTrade(\n loanId,\n leverageAmount,\n loanTokenSent,\n collateralTokenSent,\n collateralTokenAddress,\n trader,\n minEntryPrice,\n loanDataBytes\n );\n }\n\n /* Public View functions */\n\n /**\n * @notice Wrapper for internal _profitOf low level function.\n * @param user The user address.\n * @return The profit of a user.\n * */\n function profitOf(address user) external view returns (int256) {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(user, iToken_ProfitSoFar));\n //TODO + LM balance\n return _profitOf(slot, balances[user], tokenPrice(), checkpointPrices_[user]);\n }\n\n /**\n * @notice Getter for the price checkpoint mapping.\n * @param _user The user account as the mapping index.\n * @return The price on the checkpoint for this user.\n * */\n function checkpointPrice(address _user) public view returns (uint256 price) {\n return checkpointPrices_[_user];\n }\n\n /**\n * @notice Get current liquidity.\n * A part of total funds supplied are borrowed. Liquidity = supply - borrow\n * @return The market liquidity.\n * */\n function marketLiquidity() public view returns (uint256) {\n uint256 totalSupply = _totalAssetSupply(0);\n uint256 totalBorrow = totalAssetBorrow();\n if (totalSupply > totalBorrow) {\n return totalSupply - totalBorrow;\n }\n }\n\n /**\n * @notice Wrapper for average borrow interest.\n * @return The average borrow interest.\n * */\n function avgBorrowInterestRate() public view returns (uint256) {\n return _avgBorrowInterestRate(totalAssetBorrow());\n }\n\n /**\n * @notice Get borrow interest rate.\n * The minimum rate the next base protocol borrower will receive\n * for variable-rate loans.\n * @return The borrow interest rate.\n * */\n function borrowInterestRate() public view returns (uint256) {\n return _nextBorrowInterestRate(0);\n }\n\n /**\n * @notice Public wrapper for internal call.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest rate.\n * */\n function nextBorrowInterestRate(uint256 borrowAmount) public view returns (uint256) {\n return _nextBorrowInterestRate(borrowAmount);\n }\n\n /**\n * @notice Get interest rate.\n *\n * @return Interest that lenders are currently receiving when supplying to\n * the pool.\n * */\n function supplyInterestRate() public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0));\n }\n\n /**\n * @notice Get interest rate w/ added supply.\n * @param supplyAmount The amount of tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of tokens to the pool.\n * */\n function nextSupplyInterestRate(uint256 supplyAmount) public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0).add(supplyAmount));\n }\n\n /**\n * @notice Get interest rate w/ added supply assets.\n * @param assetSupply The amount of loan tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of loan tokens to the pool.\n * */\n function totalSupplyInterestRate(uint256 assetSupply) public view returns (uint256) {\n uint256 assetBorrow = totalAssetBorrow();\n if (assetBorrow != 0) {\n return calculateSupplyInterestRate(assetBorrow, assetSupply);\n }\n }\n\n /**\n * @notice Get the total amount of loan tokens on supply.\n * @dev Wrapper for internal _totalAssetSupply function.\n * @return The total amount of loan tokens on supply.\n * */\n function totalAssetSupply() public view returns (uint256) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _totalAssetSupply(interestUnPaid);\n }\n\n /**\n * @notice Compute the maximum deposit amount under current market conditions.\n * @dev maxEscrowAmount = liquidity * (100 - interestForDuration) / 100\n * @param leverageAmount The chosen multiplier with 18 decimals.\n * */\n function getMaxEscrowAmount(uint256 leverageAmount)\n public\n view\n returns (uint256 maxEscrowAmount)\n {\n /**\n * @dev Mathematical imperfection: depending on liquidity we might be able\n * to borrow more if utilization is below the kink level.\n * */\n uint256 interestForDuration = maxScaleRate.mul(28).div(365);\n uint256 factor = uint256(10**20).sub(interestForDuration);\n uint256 maxLoanSize = marketLiquidity().mul(factor).div(10**20);\n maxEscrowAmount = maxLoanSize.mul(10**18).div(leverageAmount);\n }\n\n /**\n * @notice Get loan token balance.\n * @return The user's balance of underlying token.\n * */\n function assetBalanceOf(address _owner) public view returns (uint256) {\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0)) {\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n _owner\n );\n }\n return balanceOf(_owner).add(balanceOnLM).mul(tokenPrice()).div(10**18);\n }\n\n /**\n * @notice Get margin information on a trade.\n *\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The principal, the collateral and the interestRate.\n * */\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n public\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n )\n {\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n\n (principal, interestRate) = _getMarginBorrowAmountAndRate(leverageAmount, totalDeposit);\n if (principal > _underlyingBalance()) {\n return (0, 0, 0);\n }\n\n loanTokenSent = loanTokenSent.add(principal);\n\n collateral = ProtocolLike(sovrynContractAddress).getEstimatedMarginExposure(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent,\n collateralTokenSent,\n interestRate,\n principal\n );\n }\n\n /**\n * @notice Calculate the deposit required to a given borrow.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param borrowAmount The amount of borrow.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of deposit required.\n * */\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 depositAmount) {\n if (borrowAmount != 0) {\n (, , uint256 newBorrowAmount) =\n _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (newBorrowAmount <= _underlyingBalance()) {\n if (collateralTokenAddress == address(0))\n collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ];\n return\n ProtocolLike(sovrynContractAddress)\n .getRequiredCollateral(\n loanTokenAddress,\n collateralTokenAddress,\n newBorrowAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin\n true /// isTorqueLoan\n )\n .add(10); /// Some dust to compensate for rounding errors.\n }\n }\n }\n\n /**\n * @notice Calculate the borrow allowed for a given deposit.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param depositAmount The amount of deposit.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of borrow allowed.\n * */\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 borrowAmount) {\n if (depositAmount != 0) {\n if (collateralTokenAddress == address(0)) collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))];\n borrowAmount = ProtocolLike(sovrynContractAddress).getBorrowAmount(\n loanTokenAddress,\n collateralTokenAddress,\n depositAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin,\n true /// isTorqueLoan\n );\n\n (, , borrowAmount) = _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (borrowAmount > _underlyingBalance()) {\n borrowAmount = 0;\n }\n }\n }\n\n /**\n * @notice Check if entry price lies above a minimum\n *\n * @param loanTokenSent The amount of deposit.\n * @param collateralTokenAddress The token address of collateral.\n * @param minEntryPrice Value of loan token in collateral\n * */\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) public view {\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokensReceived =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent\n );\n uint256 collateralTokenPrice =\n (collateralTokensReceived.mul(WEI_PRECISION)).div(loanTokenSent);\n require(collateralTokenPrice >= minEntryPrice, \"entry price above the minimum\");\n }\n\n /**\n * @notice Compute the next supply interest adjustment.\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next supply interest adjustment.\n * */\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n public\n view\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply >= assetBorrow) {\n return\n _avgBorrowInterestRate(assetBorrow)\n .mul(_utilizationRate(assetBorrow, assetSupply))\n .mul(\n SafeMath.sub(10**20, ProtocolLike(sovrynContractAddress).lendingFeePercent())\n )\n .div(10**40);\n }\n }\n\n /* Internal functions */\n\n /**\n * @notice Compute what the deposit is worth in loan tokens using the swap rate\n * used for loan size computation.\n *\n * @param collateralTokenAddress The token address of the collateral.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param loanTokenSent The number of loan tokens provided by the user.\n *\n * @return The value of the deposit in loan tokens.\n * */\n function _totalDeposit(\n address collateralTokenAddress,\n uint256 collateralTokenSent,\n uint256 loanTokenSent\n ) internal view returns (uint256 totalDeposit) {\n totalDeposit = loanTokenSent;\n\n if (collateralTokenSent != 0) {\n /// @dev Get the oracle rate from collateral -> loan\n (uint256 collateralToLoanRate, uint256 collateralToLoanPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n collateralTokenAddress,\n loanTokenAddress\n );\n require(\n (collateralToLoanRate != 0) && (collateralToLoanPrecision != 0),\n \"invalid rate collateral token\"\n );\n\n /// @dev Compute the loan token amount with the oracle rate.\n uint256 loanTokenAmount =\n collateralTokenSent.mul(collateralToLoanRate).div(collateralToLoanPrecision);\n\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokenAmount =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenAmount\n );\n\n /// @dev Probably not the same due to the price difference.\n if (collateralTokenAmount != collateralTokenSent) {\n //scale the loan token amount accordingly, so we'll get the expected position size in the end\n loanTokenAmount = loanTokenAmount.mul(collateralTokenAmount).div(\n collateralTokenSent\n );\n }\n\n totalDeposit = loanTokenAmount.add(totalDeposit);\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n asset,\n wrbtcTokenAddress\n );\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /*\n * @notice Compute interest rate and other loan parameters.\n *\n * @param borrowAmount The amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n *\n * @return The interest rate, the interest calculated based on fixed-term\n * loan, and the new borrow amount.\n * */\n function _getInterestRateAndBorrowAmount(\n uint256 borrowAmount,\n uint256 assetSupply,\n uint256 initialLoanDuration /// Duration in seconds.\n )\n internal\n view\n returns (\n uint256 interestRate,\n uint256 interestInitialAmount,\n uint256 newBorrowAmount\n )\n {\n interestRate = _nextBorrowInterestRate2(borrowAmount, assetSupply);\n\n /// newBorrowAmount = borrowAmount * 10^18 / (10^18 - interestRate * 7884000 * 10^18 / 31536000 / 10^20)\n newBorrowAmount = borrowAmount.mul(10**18).div(\n SafeMath.sub(\n 10**18,\n interestRate.mul(initialLoanDuration).mul(10**18).div(31536000 * 10**20) /// 365 * 86400 * 10**20\n )\n );\n\n interestInitialAmount = newBorrowAmount.sub(borrowAmount);\n }\n\n /**\n * @notice Compute principal and collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialMargin The initial margin with 18 decimals\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return The new principal and the new collateral. Principal is the\n * complete borrowed amount (in loan tokens). Collateral is the complete\n * position size (loan + margin) (in collateral tokens).\n * */\n function _borrowOrTrade(\n bytes32 loanId,\n uint256 withdrawAmount,\n uint256 initialMargin,\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n _checkPause();\n require(\n sentAmounts.newPrincipal <= _underlyingBalance() && /// newPrincipal (borrowed amount + fees)\n sentAddresses.borrower != address(0), /// The borrower.\n \"24\"\n );\n\n if (sentAddresses.receiver == address(0)) {\n sentAddresses.receiver = sentAddresses.borrower; /// The receiver = the borrower.\n }\n\n /// @dev Handle transfers prior to adding newPrincipal to loanTokenSent\n uint256 msgValue =\n _verifyTransfers(collateralTokenAddress, sentAddresses, sentAmounts, withdrawAmount);\n\n /**\n * @dev Adding the loan token portion from the lender to loanTokenSent\n * (add the loan to the loan tokens sent from the user).\n * */\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.add(sentAmounts.newPrincipal); /// newPrincipal\n\n if (withdrawAmount != 0) {\n /// @dev withdrawAmount already sent to the borrower, so we aren't sending it to the protocol.\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.sub(withdrawAmount);\n }\n\n bool withdrawAmountExist = false; /// Default is false, but added just as to make sure.\n\n if (withdrawAmount != 0) {\n withdrawAmountExist = true;\n }\n\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, withdrawAmountExist)))\n ];\n\n (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent) = ProtocolLike(\n sovrynContractAddress\n )\n .borrowOrTradeFromPool\n .value(msgValue)(\n loanParamsId,\n loanId,\n withdrawAmountExist,\n initialMargin,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n ); /// newPrincipal, newCollateral\n require(sentAmounts.newPrincipal != 0, \"25\");\n\n /// @dev Setting not-first-trade flag to prevent binding to an affiliate existing users post factum.\n /// @dev REFACTOR: move to a general interface: ProtocolSettingsLike?\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(\n sentAddresses.borrower\n );\n\n return (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent); // newPrincipal, newCollateral\n }\n\n /* Internal View functions */\n\n /**\n * @notice Compute the average borrow interest rate.\n * @param assetBorrow The amount of loan tokens on debt.\n * @return The average borrow interest rate.\n * */\n function _avgBorrowInterestRate(uint256 assetBorrow) internal view returns (uint256) {\n if (assetBorrow != 0) {\n (uint256 interestOwedPerDay, ) = _getAllInterest();\n return interestOwedPerDay.mul(10**20).mul(365).div(assetBorrow);\n }\n }\n\n /**\n * @notice Compute the next borrow interest adjustment.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate(uint256 borrowAmount) internal view returns (uint256) {\n uint256 interestUnPaid;\n if (borrowAmount != 0) {\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n uint256 balance = _underlyingBalance().add(interestUnPaid);\n if (borrowAmount > balance) {\n borrowAmount = balance;\n }\n }\n\n return _nextBorrowInterestRate2(borrowAmount, _totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Compute the next borrow interest adjustment under target-kink\n * level analysis.\n *\n * The \"kink\" in the cDAI interest rate model reflects the utilization rate\n * at which the slope of the interest rate goes from \"gradual\" to \"steep\".\n * That is, below this utilization rate, the slope of the interest rate\n * curve is gradual. Above this utilization rate, it is steep.\n *\n * Because of this dynamic between the interest rate curves before and\n * after the \"kink\", the \"kink\" can be thought of as the target utilization\n * rate. Above that rate, it quickly becomes expensive to borrow (and\n * commensurately lucrative for suppliers).\n *\n * @param newBorrowAmount The new amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate2(uint256 newBorrowAmount, uint256 assetSupply)\n internal\n view\n returns (uint256 nextRate)\n {\n uint256 utilRate = _utilizationRate(totalAssetBorrow().add(newBorrowAmount), assetSupply);\n\n uint256 thisMinRate;\n uint256 thisRateAtKink;\n uint256 thisBaseRate = baseRate;\n uint256 thisRateMultiplier = rateMultiplier;\n uint256 thisTargetLevel = targetLevel;\n uint256 thisKinkLevel = kinkLevel;\n uint256 thisMaxScaleRate = maxScaleRate;\n\n if (utilRate < thisTargetLevel) {\n // target targetLevel utilization when utilization is under targetLevel\n utilRate = thisTargetLevel;\n }\n\n if (utilRate > thisKinkLevel) {\n /// @dev Scale rate proportionally up to 100%\n uint256 thisMaxRange = WEI_PERCENT_PRECISION - thisKinkLevel; /// Will not overflow.\n\n utilRate -= thisKinkLevel;\n if (utilRate > thisMaxRange) utilRate = thisMaxRange;\n\n // Modified the rate calculation as it is slightly exaggerated around kink level\n // thisRateAtKink = thisRateMultiplier.add(thisBaseRate).mul(thisKinkLevel).div(WEI_PERCENT_PRECISION);\n thisRateAtKink = thisKinkLevel.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n nextRate = utilRate\n .mul(SafeMath.sub(thisMaxScaleRate, thisRateAtKink))\n .div(thisMaxRange)\n .add(thisRateAtKink);\n } else {\n nextRate = utilRate.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n thisMinRate = thisBaseRate;\n thisRateAtKink = thisRateMultiplier.add(thisBaseRate);\n\n if (nextRate < thisMinRate) nextRate = thisMinRate;\n else if (nextRate > thisRateAtKink) nextRate = thisRateAtKink;\n }\n }\n\n /**\n * @notice Compute the loan size and interest rate.\n * @param leverageAmount The leverage with 18 decimals.\n * @param depositAmount The amount the user deposited in underlying loan tokens.\n * @return borrowAmount The amount of tokens to borrow.\n * @return interestRate The interest rate to pay on the position.\n * */\n function _getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n internal\n view\n returns (uint256 borrowAmount, uint256 interestRate)\n {\n uint256 loanSizeBeforeInterest = depositAmount.mul(leverageAmount).div(10**18);\n /**\n * @dev Mathematical imperfection. we calculate the interest rate based on\n * the loanSizeBeforeInterest, but the actual borrowed amount will be bigger.\n * */\n interestRate = _nextBorrowInterestRate2(loanSizeBeforeInterest, _totalAssetSupply(0));\n /// @dev Assumes that loan, collateral, and interest token are the same.\n borrowAmount = _adjustLoanSize(interestRate, 28 days, loanSizeBeforeInterest);\n }\n\n /**\n * @notice Make sure call is not paused.\n * @dev Used for internal verification if the called function is paused.\n * It throws an exception in case it's not.\n * */\n function _checkPause() internal view {\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n msg.sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n bool isPaused;\n assembly {\n isPaused := sload(slot)\n }\n require(!isPaused, \"unauthorized\");\n }\n\n /**\n * @notice Adjusts the loan size to make sure the expected exposure remains after prepaying the interest.\n * @dev loanSizeWithInterest = loanSizeBeforeInterest * 100 / (100 - interestForDuration)\n * @param interestRate The interest rate to pay on the position.\n * @param maxDuration The maximum duration of the position (until rollover).\n * @param loanSizeBeforeInterest The loan size before interest is added.\n * */\n function _adjustLoanSize(\n uint256 interestRate,\n uint256 maxDuration,\n uint256 loanSizeBeforeInterest\n ) internal pure returns (uint256 loanSizeWithInterest) {\n uint256 interestForDuration = interestRate.mul(maxDuration).div(365 days);\n uint256 divisor = uint256(10**20).sub(interestForDuration);\n loanSizeWithInterest = loanSizeBeforeInterest.mul(10**20).div(divisor);\n }\n\n /**\n * @notice Calculate the utilization rate.\n * @dev Utilization rate = assetBorrow / assetSupply\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The utilization rate.\n * */\n function _utilizationRate(uint256 assetBorrow, uint256 assetSupply)\n internal\n pure\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply != 0) {\n /// U = total_borrow / total_supply\n return assetBorrow.mul(10**20).div(assetSupply);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./AdvancedToken.sol\";\n\ncontract LoanTokenLogicStorage is AdvancedToken {\n /// DO NOT ADD VARIABLES HERE - SEE BELOW\n\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /// @dev Add new variables here on the bottom.\n address public earlyAccessToken; //not used anymore, but staying for upgradability\n address public pauser;\n /** The address of the liquidity mining contract */\n address public liquidityMiningAddress;\n\n /** The address of the staking contract */\n address public stakingContractAddress;\n\n /// @dev Used by flashBorrow function.\n uint256 public constant VERSION = 6;\n /// @dev Used by flashBorrow function.\n address internal constant arbitraryCaller = 0x000F400e6818158D541C3EBE45FE3AA0d47372FF;\n bytes32 internal constant iToken_ProfitSoFar =\n 0x37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb6; // keccak256(\"iToken_ProfitSoFar\")\n uint256 public constant TINY_AMOUNT = 25e13;\n\n function stringToBytes32(string memory source) public pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"unauthorized\"); // SS02\n _;\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogic is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenMintAndBurn also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenLogicStandard also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\")); /// LoanTokenLogicStandard\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\")); /// LoanTokenLogicLM\n res[2] = bytes4(keccak256(\"burn(address,uint256)\")); /// LoanTokenLogicStandard\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\")); /// LoanTokenLogicLM\n\n return (res, stringToBytes32(\"LoanTokenLogicLM\"));\n }\n\n /**\n * @notice deposit into the lending pool and optionally participate at the Liquidity Mining Program\n * @param receiver the receiver of the tokens\n * @param depositAmount The amount of underlying tokens provided on the loan.\n *\t\t\t\t\t\t(Not the number of loan tokens to mint).\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 minted) {\n if (useLM) return _mintWithLM(receiver, depositAmount);\n else return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice withdraws from the lending pool and optionally retrieves the pool tokens from the\n * Liquidity Mining Contract\n * @param receiver the receiver of the underlying tokens. note: potetial LM rewards are always sent to the msg.sender\n * @param burnAmount The amount of pool tokens to redeem.\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 redeemed) {\n if (useLM) redeemed = _burnFromLM(burnAmount);\n else redeemed = _burnToken(burnAmount);\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (redeemed != 0) {\n _safeTransfer(loanTokenAddress, receiver, redeemed, \"asset transfer failed\");\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtc.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogicWrbtc is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtc\"));\n }\n\n /**\n * @dev internal override functions\n * @dev Put all of internal override function dedicated to the loanTokenWrtbc module here\n * e.g: _verifyTransfers will override the implementation of _verifyTransfers in loanTokenLogicSplit\n */\n\n /**\n * @notice Handle transfers prior to adding newPrincipal to loanTokenSent.\n *\n * @param collateralTokenAddress The address of the collateral token.\n * @param sentAddresses The struct which contains addresses of\n * - lender\n * - borrower\n * - receiver\n * - manager\n *\n * @param sentAmounts The struct which contains uint256 of:\n * - interestRate\n * - newPrincipal\n * - interestInitialAmount\n * - loanTokenSent\n * - collateralTokenSent\n *\n * @param withdrawalAmount The amount to withdraw.\n *\n * @return msgValue The amount of value sent.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = _wrbtcToken;\n address receiver = sentAddresses.receiver;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n IWrbtcERC20(_wrbtcToken).withdraw(withdrawalAmount);\n Address.sendValue(receiver, withdrawalAmount);\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n\n if (collateralTokenSent != 0) {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28\"\n );\n }\n\n if (loanTokenSent != 0) {\n if (msgValue != 0 && msgValue >= loanTokenSent) {\n IWrbtc(_wrbtcToken).deposit.value(loanTokenSent)();\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, loanTokenSent, \"29\");\n msgValue -= loanTokenSent;\n } else {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtcLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicWrbtcLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token Mint and Burn.\n res[0] = this.mint.selector;\n res[1] = this.burn.selector;\n\n // Loan Token WRBTC\n res[2] = this.mintWithBTC.selector;\n res[3] = this.burnToBTC.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtcLM\"));\n }\n\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n if (useLM) return _mintWithLM(receiver, msg.value);\n else return _mintToken(receiver, msg.value);\n }\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 loanAmountPaid) {\n loanAmountPaid = useLM ? _burnFromLM(burnAmount) : _burnToken(burnAmount);\n\n if (loanAmountPaid != 0) {\n IWrbtcERC20(wrbtcTokenAddress).withdraw(loanAmountPaid);\n Address.sendValue(receiver, loanAmountPaid);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/shared/LoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../AdvancedToken.sol\";\nimport \"../../interfaces/ProtocolSettingsLike.sol\";\nimport \"../../LoanTokenLogicStorage.sol\";\n\ncontract LoanTokenSettingsLowerAdmin is LoanTokenLogicStorage {\n using SafeMath for uint256;\n\n /// @dev TODO: Check for restrictions in this contract.\n modifier onlyAdmin() {\n require(isOwner() || msg.sender == admin, \"unauthorized\");\n _;\n }\n\n /* Events */\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](15);\n res[0] = this.setAdmin.selector;\n res[1] = this.setPauser.selector;\n res[2] = this.setupLoanParams.selector;\n res[3] = this.disableLoanParams.selector;\n res[4] = this.setDemandCurve.selector;\n res[5] = this.toggleFunctionPause.selector;\n res[6] = this.setTransactionLimits.selector;\n res[7] = this.changeLoanTokenNameAndSymbol.selector;\n res[8] = this.pauser.selector;\n res[9] = this.setLiquidityMiningAddress.selector;\n res[10] = this.withdrawRBTCTo.selector;\n res[11] = this.getLiquidityMiningAddress.selector;\n res[12] = this.checkPause.selector;\n res[13] = this.setStakingContractAddress.selector;\n res[14] = this.getStakingContractAddress.selector;\n return (res, stringToBytes32(\"LoanTokenSettingsLowerAdmin\"));\n }\n\n /**\n * @notice Set admin account.\n * @param _admin The address of the account to grant admin permissions.\n * */\n function setAdmin(address _admin) public onlyOwner {\n admin = _admin;\n }\n\n /**\n * @notice Set pauser account.\n * @param _pauser The address of the account to grant pause permissions.\n * */\n function setPauser(address _pauser) public onlyOwner {\n pauser = _pauser;\n }\n\n /**\n * @notice Fallback function not allowed\n * */\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n /**\n * @notice Set loan token parameters.\n *\n * @param loanParamsList The array of loan parameters.\n * @param areTorqueLoans Whether the loan is a torque loan.\n * */\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans /// isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n /**\n * @notice Disable loan token parameters.\n *\n * @param collateralTokens The array of collateral tokens.\n * @param isTorqueLoans Whether the loan is a torque loan.\n * */\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n /**\n * @notice Set loan token parameters about the demand curve.\n *\n * @dev These params should be percentages represented\n * like so: 5% = 5000000000000000000 /// 18 digits precision.\n * rateMultiplier + baseRate can't exceed 100%\n *\n * To maintain a healthy credit score, it's important to keep your\n * credit utilization rate (CUR) low (_lowUtilBaseRate). In general\n * you don't want your CUR to exceed 30%, but increasingly financial\n * experts are recommending that you don't want to go above 10% if you\n * really want an excellent credit score.\n *\n * Interest rates tend to cluster around the kink level of a kinked\n * interest rate model. More info at https://arxiv.org/pdf/2006.13922.pdf\n * and https://compound.finance/governance/proposals/12\n *\n * @param _baseRate The interest rate.\n * @param _rateMultiplier The precision multiplier for base rate.\n * @param _lowUtilBaseRate The credit utilization rate (CUR) low value.\n * @param _lowUtilRateMultiplier The precision multiplier for low util base rate.\n * @param _targetLevel The target level.\n * @param _kinkLevel The level that interest rates cluster on kinked model.\n * @param _maxScaleRate The maximum rate of the scale.\n * */\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; /// 80 ether\n kinkLevel = _kinkLevel; /// 90 ether\n maxScaleRate = _maxScaleRate; /// 100 ether\n }\n\n /**\n * @notice Set the pause flag for a function to true or false.\n *\n * @dev Combining the hash of \"iToken_FunctionPause\" string and a function\n * selector gets a slot to write a flag for pause state.\n *\n * @param funcId The ID of a function, the selector.\n * @param isPaused true/false value of the flag.\n * */\n function toggleFunctionPause(\n string memory funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyPauserOrOwner {\n bool paused;\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n paused := sload(slot)\n }\n require(paused != isPaused, \"isPaused is already set to that value\");\n assembly {\n sstore(slot, isPaused)\n }\n emit ToggledFunctionPaused(funcId, !isPaused, isPaused);\n }\n\n /**\n * Set the transaction limit per token address.\n * @param addresses The token addresses.\n * @param limits The limit denominated in the currency of the token address.\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyAdmin\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n\n /**\n *\t@notice Update the loan token parameters.\n *\t@param _name The new name of the loan token.\n *\t@param _symbol The new symbol of the loan token.\n * */\n function changeLoanTokenNameAndSymbol(string memory _name, string memory _symbol)\n public\n onlyAdmin\n {\n name = _name;\n symbol = _symbol;\n }\n\n /**\n * @notice Withdraws RBTC from the contract by Multisig.\n * @param _receiverAddress The address where the rBTC has to be transferred.\n * @param _amount The amount of rBTC to be transferred.\n */\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external onlyOwner {\n require(_receiverAddress != address(0), \"receiver address invalid\");\n require(_amount > 0, \"non-zero withdraw amount expected\");\n require(_amount <= address(this).balance, \"withdraw amount cannot exceed balance\");\n _receiverAddress.transfer(_amount);\n emit WithdrawRBTCTo(_receiverAddress, _amount);\n }\n\n /**\n * @notice sets the liquidity mining contract address\n * @param LMAddress the address of the liquidity mining contract\n */\n function setLiquidityMiningAddress(address LMAddress) external onlyOwner {\n liquidityMiningAddress = LMAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for liquidityMiningAddress\n\n\t * @return liquidityMiningAddress\n\t */\n function getLiquidityMiningAddress() public view returns (address) {\n return liquidityMiningAddress;\n }\n\n /**\n * @notice sets the staking contract address\n * @param _stakingContractAddress the address of the staking contract\n */\n function setStakingContractAddress(address _stakingContractAddress) external onlyOwner {\n stakingContractAddress = _stakingContractAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for stakingContractAddress\n\n\t * @return stakingContractAddress\n\t */\n function getStakingContractAddress() public view returns (address) {\n return stakingContractAddress;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param funcId The function ID, the selector.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function checkPause(string memory funcId) public view returns (bool isPaused) {\n bytes4 sig = bytes4(keccak256(abi.encodePacked(funcId)));\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n isPaused := sload(slot)\n }\n return isPaused;\n }\n}\n" + }, + "contracts/connectors/loantoken/Pausable.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Pausable contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * The contract implements pausable functionality by reading on slots the\n * pause state of contract functions.\n * */\ncontract Pausable {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 internal constant Pausable_FunctionPause =\n 0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047;\n\n modifier pausable(bytes4 sig) {\n require(!_isPaused(sig), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param sig The function ID, the selector on bytes4.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function _isPaused(bytes4 sig) internal view returns (bool isPaused) {\n bytes32 slot = keccak256(abi.encodePacked(sig, Pausable_FunctionPause));\n assembly {\n isPaused := sload(slot)\n }\n }\n}\n" + }, + "contracts/core/Objects.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./objects/LoanStruct.sol\";\nimport \"./objects/LoanParamsStruct.sol\";\nimport \"./objects/OrderStruct.sol\";\nimport \"./objects/LenderInterestStruct.sol\";\nimport \"./objects/LoanInterestStruct.sol\";\n\n/**\n * @title Objects contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract inherints and aggregates several structures needed to handle\n * loans on the protocol.\n * */\ncontract Objects is\n LoanStruct,\n LoanParamsStruct,\n OrderStruct,\n LenderInterestStruct,\n LoanInterestStruct\n{\n\n}\n" + }, + "contracts/core/objects/LenderInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Lender Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Lender Interest.\n * */\ncontract LenderInterestStruct {\n struct LenderInterest {\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\n uint256 paidTotal; /// Total interest paid so far for asset.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Interest.\n * */\ncontract LoanInterestStruct {\n struct LoanInterest {\n uint256 owedPerDay; /// Interest owed per day for loan.\n uint256 depositTotal; /// Total escrowed interest for loan.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanParamsStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Parameters.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Parameters.\n * */\ncontract LoanParamsStruct {\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n}\n" + }, + "contracts/core/objects/LoanStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Object.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Object.\n * */\ncontract LoanStruct {\n struct Loan {\n bytes32 id; /// ID of the loan.\n bytes32 loanParamsId; /// The linked loan params ID.\n bytes32 pendingTradesId; /// The linked pending trades ID.\n bool active; /// If false, the loan has been fully closed.\n uint256 principal; /// Total borrowed amount outstanding.\n uint256 collateral; /// Total collateral escrowed for the loan.\n uint256 startTimestamp; /// Loan start time.\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\n uint256 startMargin; /// Initial margin when the loan opened.\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\n address borrower; /// Borrower of this loan.\n address lender; /// Lender of this loan.\n }\n}\n" + }, + "contracts/core/objects/OrderStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Order.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Order.\n * */\ncontract OrderStruct {\n struct Order {\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\n uint256 interestRate; /// Interest rate defined by the creator of this order.\n uint256 minLoanTerm; /// Minimum loan term allowed.\n uint256 maxLoanTerm; /// Maximum loan term allowed.\n uint256 createdTimestamp; /// Timestamp when this order was created.\n uint256 expirationTimestamp; /// Timestamp when this order expires.\n }\n}\n" + }, + "contracts/core/Protocol.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./State.sol\";\n\n/**\n * @title Sovryn Protocol contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the proxy functionality to deploy Protocol anchor\n * and logic apart, turning it upgradable.\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822\n * */\ncontract sovrynProtocol is State {\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = logicTargets[msg.sig];\n require(target != address(0), \"target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice External owner target initializer.\n * @param target The target addresses.\n * */\n function replaceContract(address target) external onlyOwner {\n (bool success, ) =\n target.delegatecall(abi.encodeWithSignature(\"initialize(address)\", target));\n require(success, \"setup failed\");\n }\n\n /**\n * @notice External owner setter for target addresses.\n * @param sigsArr The array of signatures.\n * @param targetsArr The array of addresses.\n * */\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr)\n external\n onlyOwner\n {\n require(sigsArr.length == targetsArr.length, \"count mismatch\");\n\n for (uint256 i = 0; i < sigsArr.length; i++) {\n _setTarget(bytes4(keccak256(abi.encodePacked(sigsArr[i]))), targetsArr[i]);\n }\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(string calldata sig) external view returns (address) {\n return logicTargets[bytes4(keccak256(abi.encodePacked(sig)))];\n }\n}\n" + }, + "contracts/core/State.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./Objects.sol\";\nimport \"../mixins/EnumerableAddressSet.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/ReentrancyGuard.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title State contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage values of the Protocol.\n * */\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\n using SafeMath for uint256;\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n\n /// Handles asset reference price lookups.\n address public priceFeeds;\n\n /// Handles asset swaps using dex liquidity.\n address public swapsImpl;\n\n /// Contract registry address of the Sovryn swap network.\n address public sovrynSwapContractRegistryAddress;\n\n /// Implementations of protocol functions.\n mapping(bytes4 => address) public logicTargets;\n\n /// Loans: loanId => Loan\n mapping(bytes32 => Loan) public loans;\n\n /// Loan parameters: loanParamsId => LoanParams\n mapping(bytes32 => LoanParams) public loanParams;\n\n /// lender => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\n\n /// borrower => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\n\n /// loanId => delegated => approved\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\n\n /**\n *** Interest ***\n **/\n\n /// lender => loanToken => LenderInterest object\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\n\n /// loanId => LoanInterest object\n mapping(bytes32 => LoanInterest) public loanInterest;\n\n /**\n *** Internals ***\n **/\n\n /// Implementations set.\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\n\n /// Active loans set.\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\n\n /// Lender loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\n\n /// Borrow loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\n\n /// User loan params set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\n\n /// Address controlling fee withdrawals.\n address public feesController;\n\n /// 10% fee /// Fee taken from lender interest payments.\n uint256 public lendingFeePercent = 10**19;\n\n /// Total interest fees received and not withdrawn per asset.\n mapping(address => uint256) public lendingFeeTokensHeld;\n\n /// Total interest fees withdraw per asset.\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\n mapping(address => uint256) public lendingFeeTokensPaid;\n\n /// 0.15% fee /// Fee paid for each trade.\n uint256 public tradingFeePercent = 15 * 10**16;\n\n /// Total trading fees received and not withdrawn per asset.\n mapping(address => uint256) public tradingFeeTokensHeld;\n\n /// Total trading fees withdraw per asset\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\n mapping(address => uint256) public tradingFeeTokensPaid;\n\n /// 0.09% fee /// Origination fee paid for each loan.\n uint256 public borrowingFeePercent = 9 * 10**16;\n\n /// Total borrowing fees received and not withdrawn per asset.\n mapping(address => uint256) public borrowingFeeTokensHeld;\n\n /// Total borrowing fees withdraw per asset.\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\n mapping(address => uint256) public borrowingFeeTokensPaid;\n\n /// Current protocol token deposit balance.\n uint256 public protocolTokenHeld;\n\n /// Lifetime total payout of protocol token.\n uint256 public protocolTokenPaid;\n\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\n uint256 public affiliateFeePercent = 5 * 10**18;\n\n /// 5% collateral discount /// Discount on collateral for liquidators.\n uint256 public liquidationIncentivePercent = 5 * 10**18;\n\n /// loanPool => underlying\n mapping(address => address) public loanPoolToUnderlying;\n\n /// underlying => loanPool\n mapping(address => address) public underlyingToLoanPool;\n\n /// Loan pools set.\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\n\n /// Supported tokens for swaps.\n mapping(address => bool) public supportedTokens;\n\n /// % disagreement between swap rate and reference rate.\n uint256 public maxDisagreement = 5 * 10**18;\n\n /// Used as buffer for swap source amount estimations.\n uint256 public sourceBuffer = 10000;\n\n /// Maximum support swap size in rBTC\n uint256 public maxSwapSize = 50 ether;\n\n /// Nonce per borrower. Used for loan id creation.\n mapping(address => uint256) public borrowerNonce;\n\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\n uint256 public rolloverBaseReward = 16800000000000;\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\n\n IWrbtcERC20 public wrbtcToken;\n address public protocolTokenAddress;\n\n /// 50% fee rebate\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\n uint256 public feeRebatePercent = 50 * 10**18;\n\n address public admin;\n\n /// For modules interaction.\n address public protocolAddress;\n\n /**\n *** Affiliates ***\n **/\n\n /// The flag is set on the user's first trade.\n mapping(address => bool) public userNotFirstTradeFlag;\n\n /// User => referrer (affiliate).\n mapping(address => address) public affiliatesUserReferrer;\n\n /// List of referral addresses affiliated to the referrer.\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\n\n /// @dev Referral threshold for paying out to the referrer.\n /// The referrer reward is being accumulated and locked until the threshold is passed.\n uint256 public minReferralsToPayout = 3;\n\n /// @dev Total affiliate SOV rewards that held in the protocol\n /// (Because the minimum referrals is less than the rule)\n mapping(address => uint256) public affiliateRewardsHeld;\n\n /// @dev For affiliates SOV Bonus proccess.\n address public sovTokenAddress;\n address public lockedSOVAddress;\n\n /// @dev 20% fee share of trading token fee.\n /// Fee share of trading token fee for affiliate program.\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\n\n /// @dev Addresses of tokens in which commissions were paid to referrers.\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\n\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\n\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\n bool public pause; //Flag to pause all protocol modules\n\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\n\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\n uint256 internal tradingRebateRewardsBasisPoint;\n\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\n /// Will be used in internal swap.\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\n\n address internal pauser;\n\n /**\n * @notice Add signature and target to storage.\n * @dev Protocol is a proxy and requires a way to add every\n * module function dynamically during deployment.\n * */\n function _setTarget(bytes4 sig, address target) internal {\n logicTargets[sig] = target;\n\n if (target != address(0)) {\n logicTargetsSet.addBytes32(bytes32(sig));\n } else {\n logicTargetsSet.removeBytes32(bytes32(sig));\n }\n }\n\n modifier onlyAdminOrOwner() {\n require(isOwner() || admin == (msg.sender), \"unauthorized\");\n _;\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || pauser == (msg.sender), \"unauthorized\");\n _;\n }\n}\n" + }, + "contracts/escrow/Escrow.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Ethereum Pool to accept SOV Token.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice You can use this contract for deposit of SOV tokens for some time and withdraw later.\n */\ncontract Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalDeposit;\n /// @notice The release timestamp for the tokens deposited.\n uint256 public releaseTime;\n /// @notice The amount of token we would be accepting as deposit at max.\n uint256 public depositLimit;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The multisig contract which handles the fund.\n address public multisig;\n\n /// @notice The user balances.\n mapping(address => uint256) userBalances;\n\n /// @notice The current contract status.\n /// @notice Deployed - Deployed the contract.\n /// @notice Deposit - Time to deposit in the contract by the users.\n /// @notice Holding - Deposit is closed and now the holding period starts.\n /// @notice Withdraw - Time to withdraw in the contract by the users.\n /// @notice Expired - The contract is now closed completely.\n enum Status { Deployed, Deposit, Holding, Withdraw, Expired }\n Status public status;\n\n /* Events */\n\n /// @notice Emitted when the contract deposit starts.\n event EscrowActivated();\n\n /// @notice Emitted when the contract is put in holding state. No new token deposit accepted by User.\n event EscrowInHoldingState();\n\n /// @notice Emitted when the contract is put in withdraw state. Users can now withdraw tokens.\n event EscrowInWithdrawState();\n\n /// @notice Emitted when the contract is expired after withdraws are made/total token transfer.\n event EscrowFundExpired();\n\n /// @notice Emitted when a new multisig is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newMultisig The address which is added as the new multisig.\n /// @dev Can only be initiated by the current multisig.\n event NewMultisig(address indexed _initiator, address indexed _newMultisig);\n\n /// @notice Emitted when the release timestamp is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseTimestamp The updated release timestamp for the withdraw.\n event TokenReleaseUpdated(address indexed _initiator, uint256 _releaseTimestamp);\n\n /// @notice Emitted when the deposit limit is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _depositLimit The updated deposit limit.\n event TokenDepositLimitUpdated(address indexed _initiator, uint256 _depositLimit);\n\n /// @notice Emitted when a new token deposit is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when we reach the token deposit limit.\n event DepositLimitReached();\n\n /// @notice Emitted when a token withdraw is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdrawByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyMultisig() {\n require(msg.sender == multisig, \"Only Multisig can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n modifier checkRelease() {\n require(\n releaseTime != 0 && releaseTime <= block.timestamp,\n \"The release time has not started yet.\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_multisig != address(0), \"Invalid Multisig Address.\");\n\n SOV = IERC20(_SOV);\n multisig = _multisig;\n\n emit NewMultisig(msg.sender, _multisig);\n\n releaseTime = _releaseTime;\n depositLimit = _depositLimit;\n\n status = Status.Deployed;\n }\n\n /**\n * @notice This function is called once after deployment for starting the deposit action.\n * @dev Without calling this function, the contract will not start accepting tokens.\n */\n function init() external onlyMultisig checkStatus(Status.Deployed) {\n status = Status.Deposit;\n\n emit EscrowActivated();\n }\n\n /**\n * @notice Update Multisig.\n * @param _newMultisig The new owner of the tokens & contract.\n */\n function updateMultisig(address _newMultisig) external onlyMultisig {\n require(_newMultisig != address(0), \"New Multisig address invalid.\");\n\n multisig = _newMultisig;\n\n emit NewMultisig(msg.sender, _newMultisig);\n }\n\n /**\n * @notice Update Release Timestamp.\n * @param _newReleaseTime The new release timestamp for token release.\n * @dev Zero is also a valid timestamp, if the release time is not scheduled yet.\n */\n function updateReleaseTimestamp(uint256 _newReleaseTime) external onlyMultisig {\n releaseTime = _newReleaseTime;\n\n emit TokenReleaseUpdated(msg.sender, _newReleaseTime);\n }\n\n /**\n * @notice Update Deposit Limit.\n * @param _newDepositLimit The new deposit limit.\n * @dev IMPORTANT: Should not decrease than already deposited.\n */\n function updateDepositLimit(uint256 _newDepositLimit) external onlyMultisig {\n require(\n _newDepositLimit >= totalDeposit,\n \"Deposit already higher than the limit trying to be set.\"\n );\n depositLimit = _newDepositLimit;\n\n emit TokenDepositLimitUpdated(msg.sender, _newDepositLimit);\n }\n\n /**\n * @notice Deposit tokens to this contract by User.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the user inorder for this function to work.\n * These tokens can be withdrawn/transferred during Holding State by the Multisig.\n */\n function depositTokens(uint256 _amount) external checkStatus(Status.Deposit) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n uint256 amount = _amount;\n\n if (totalDeposit.add(_amount) >= depositLimit) {\n amount = depositLimit.sub(totalDeposit);\n emit DepositLimitReached();\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n userBalances[msg.sender] = userBalances[msg.sender].add(amount);\n totalDeposit = totalDeposit.add(amount);\n\n emit TokenDeposit(msg.sender, amount);\n }\n\n /**\n * @notice Update contract state to Holding.\n * @dev Once called, the contract no longer accepts any more deposits.\n * The multisig can now withdraw tokens from the contract after the contract is in Holding State.\n */\n function changeStateToHolding() external onlyMultisig checkStatus(Status.Deposit) {\n status = Status.Holding;\n\n emit EscrowInHoldingState();\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred. Zero address if the withdraw is to be done in Multisig.\n * @dev Can only be called after the token state is changed to Holding.\n */\n function withdrawTokensByMultisig(address _receiverAddress)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n address receiverAddress = msg.sender;\n if (_receiverAddress != address(0)) {\n receiverAddress = _receiverAddress;\n }\n\n uint256 value = SOV.balanceOf(address(this));\n /// Sending the amount to multisig.\n bool txStatus = SOV.transfer(receiverAddress, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdrawByMultisig(msg.sender, value);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n * Once the token deposit is higher than the total deposits done, the contract state is changed to Withdraw.\n */\n function depositTokensByMultisig(uint256 _amount)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDepositByMultisig(msg.sender, _amount);\n\n if (SOV.balanceOf(address(this)) >= totalDeposit) {\n status = Status.Withdraw;\n emit EscrowInWithdrawState();\n }\n }\n\n /**\n * @notice Withdraws token from the contract by User.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokens() public checkRelease checkStatus(Status.Withdraw) {\n uint256 amount = userBalances[msg.sender];\n userBalances[msg.sender] = 0;\n bool txStatus = SOV.transfer(msg.sender, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdraw(msg.sender, amount);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token balance of a particular user.\n * @return _addr The user address whose balance has to be checked.\n */\n function getUserBalance(address _addr) external view returns (uint256 balance) {\n return userBalances[_addr];\n }\n}\n" + }, + "contracts/escrow/EscrowReward.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Escrow.sol\";\nimport \"../locked/ILockedSOV.sol\";\n\n/**\n * @title A reward distribution contract for Sovryn Ethereum Pool Escrow Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice Multisig can use this contract for depositing of Reward tokens based on the total token deposit.\n */\ncontract EscrowReward is Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total reward tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalRewardDeposit;\n\n /// @notice The Locked SOV contract.\n ILockedSOV public lockedSOV;\n\n /* Events */\n\n /// @notice Emitted when the Locked SOV Contract address is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _lockedSOV The address of the Locked SOV Contract.\n event LockedSOVUpdated(address indexed _initiator, address indexed _lockedSOV);\n\n /// @notice Emitted when a new reward token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event RewardDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a Reward token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event RewardTokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _lockedSOV The Locked SOV Contract address.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _lockedSOV,\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public Escrow(_SOV, _multisig, _releaseTime, _depositLimit) {\n if (_lockedSOV != address(0)) {\n lockedSOV = ILockedSOV(_lockedSOV);\n }\n }\n\n /**\n * @notice Set the Locked SOV Contract Address if not already done.\n * @param _lockedSOV The Locked SOV Contract address.\n */\n function updateLockedSOV(address _lockedSOV) external onlyMultisig {\n require(_lockedSOV != address(0), \"Invalid Reward Token Address.\");\n\n lockedSOV = ILockedSOV(_lockedSOV);\n\n emit LockedSOVUpdated(msg.sender, _lockedSOV);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n */\n function depositRewardByMultisig(uint256 _amount) external onlyMultisig {\n require(\n status != Status.Withdraw,\n \"Reward Token deposit is only allowed before User Withdraw starts.\"\n );\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n totalRewardDeposit = totalRewardDeposit.add(_amount);\n txStatus = SOV.approve(address(lockedSOV), totalRewardDeposit);\n require(txStatus, \"Token Approval was not successful.\");\n\n emit RewardDepositByMultisig(msg.sender, _amount);\n }\n\n /**\n * @notice Withdraws token and reward from the contract by User. Reward is gone to lockedSOV contract for future vesting.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokensAndReward() external checkRelease checkStatus(Status.Withdraw) {\n // Reward calculation have to be done initially as the User Balance is zeroed out .\n uint256 reward = userBalances[msg.sender].mul(totalRewardDeposit).div(totalDeposit);\n withdrawTokens();\n\n lockedSOV.depositSOV(msg.sender, reward);\n\n emit RewardTokenWithdraw(msg.sender, reward);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the reward a particular user can get.\n * @param _addr The address of the user whose reward is to be read.\n * @return reward The reward received by the user.\n */\n function getReward(address _addr) external view returns (uint256 reward) {\n if (userBalances[_addr].mul(totalRewardDeposit) == 0) {\n return 0;\n }\n return userBalances[_addr].mul(totalRewardDeposit).div(totalDeposit);\n }\n}\n" + }, + "contracts/events/AffiliatesEvents.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\ncontract AffiliatesEvents is ModulesCommonEvents {\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\n\n event SetAffiliatesReferrerFail(\n address indexed user,\n address indexed referrer,\n bool alreadySet,\n bool userNotFirstTrade\n );\n\n event SetUserNotFirstTradeFlag(address indexed user);\n\n event PayTradingFeeToAffiliate(\n address indexed referrer,\n address trader,\n address indexed token,\n bool indexed isHeld,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountPaid\n );\n\n event PayTradingFeeToAffiliateFail(\n address indexed referrer,\n address trader,\n address indexed token,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountTryingToPaid\n );\n\n event WithdrawAffiliatesReferrerTokenFees(\n address indexed referrer,\n address indexed receiver,\n address indexed tokenAddress,\n uint256 amount\n );\n}\n" + }, + "contracts/events/FeesEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Fees Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for fee payments.\n * */\ncontract FeesEvents {\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\n\n event PayTradingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event PayBorrowingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event EarnReward(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n\n event EarnRewardFail(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n}\n" + }, + "contracts/events/LoanClosingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Closing Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan closing operations.\n * */\ncontract LoanClosingsEvents is ModulesCommonEvents {\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\n event CloseWithDeposit(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address closer,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\n event CloseWithSwap(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n address closer,\n uint256 positionCloseSize,\n uint256 loanCloseAmount,\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\n uint256 currentLeverage\n );\n\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\n event Liquidate(\n address indexed user,\n address indexed liquidator,\n bytes32 indexed loanId,\n address lender,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n event Rollover(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n uint256 principal,\n uint256 collateral,\n uint256 endTimestamp,\n address rewardReceiver,\n uint256 reward\n );\n\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\n}\n" + }, + "contracts/events/LoanMaintenanceEvents.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Maintenance Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan maintenance operations.\n * */\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\n}\n" + }, + "contracts/events/LoanOpeningsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Openings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan openings operations.\n * */\ncontract LoanOpeningsEvents is ModulesCommonEvents {\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\n event Borrow(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 newCollateral,\n uint256 interestRate,\n uint256 interestDuration,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\n event Trade(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n uint256 positionSize,\n uint256 borrowedAmount,\n uint256 interestRate,\n uint256 settlementDate,\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\n uint256 entryLeverage,\n uint256 currentLeverage\n );\n\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\n event DelegatedManagerSet(\n bytes32 indexed loanId,\n address indexed delegator,\n address indexed delegated,\n bool isActive\n );\n}\n" + }, + "contracts/events/LoanSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan settings operations.\n * */\ncontract LoanSettingsEvents is ModulesCommonEvents {\n event LoanParamsSetup(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\n\n event LoanParamsDisabled(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\n}\n" + }, + "contracts/events/ModulesCommonEvents.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title The common events for all modules\n * @notice This contract contains the events which will be used by all modules\n **/\n\ncontract ModulesCommonEvents {\n event ProtocolModuleContractReplaced(\n address indexed prevModuleContractAddress,\n address indexed newModuleContractAddress,\n bytes32 indexed module\n );\n}\n" + }, + "contracts/events/ProtocolSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title The Protocol Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for protocol settings operations.\n * */\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\n\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\n\n event SetLoanPool(\n address indexed sender,\n address indexed loanPool,\n address indexed underlying\n );\n\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\n\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateTradingTokenFeePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetLiquidationIncentivePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetFeesController(\n address indexed sender,\n address indexed oldController,\n address indexed newController\n );\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWethToken,\n address indexed newWethToken\n );\n\n event SetSovrynSwapContractRegistryAddress(\n address indexed sender,\n address indexed oldSovrynSwapContractRegistryAddress,\n address indexed newSovrynSwapContractRegistryAddress\n );\n\n event SetProtocolTokenAddress(\n address indexed sender,\n address indexed oldProtocolToken,\n address indexed newProtocolToken\n );\n\n event WithdrawFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 lendingAmount,\n uint256 tradingAmount,\n uint256 borrowingAmount,\n uint256 wRBTCConverted\n );\n\n event WithdrawLendingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawTradingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawBorrowingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetRebatePercent(\n address indexed sender,\n uint256 oldRebatePercent,\n uint256 newRebatePercent\n );\n\n event SetSpecialRebates(\n address indexed sender,\n address indexed sourceToken,\n address indexed destToken,\n uint256 oldSpecialRebatesPercent,\n uint256 newSpecialRebatesPercent\n );\n\n event SetProtocolAddress(\n address indexed sender,\n address indexed oldProtocol,\n address indexed newProtocol\n );\n\n event SetMinReferralsToPayoutAffiliates(\n address indexed sender,\n uint256 oldMinReferrals,\n uint256 newMinReferrals\n );\n\n event SetSOVTokenAddress(\n address indexed sender,\n address indexed oldTokenAddress,\n address indexed newTokenAddress\n );\n\n event SetLockedSOVAddress(\n address indexed sender,\n address indexed oldAddress,\n address indexed newAddress\n );\n\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\n\n event SetTradingRebateRewardsBasisPoint(\n address indexed sender,\n uint256 oldBasisPoint,\n uint256 newBasisPoint\n );\n\n event SetRolloverFlexFeePercent(\n address indexed sender,\n uint256 oldRolloverFlexFeePercent,\n uint256 newRolloverFlexFeePercent\n );\n\n event SetDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event RemoveDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n}\n" + }, + "contracts/events/SwapsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Swaps Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for swap operations.\n * */\ncontract SwapsEvents is ModulesCommonEvents {\n event LoanSwap(\n bytes32 indexed loanId,\n address indexed sourceToken,\n address indexed destToken,\n address borrower,\n uint256 sourceAmount,\n uint256 destAmount\n );\n\n event ExternalSwap(\n address indexed user,\n address indexed sourceToken,\n address indexed destToken,\n uint256 sourceAmount,\n uint256 destAmount\n );\n}\n" + }, + "contracts/farm/ILiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\n\ninterface ILiquidityMining {\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external;\n\n function onTokensDeposited(address _user, uint256 _amount) external;\n\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/farm/LiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./LiquidityMiningStorage.sol\";\nimport \"./ILiquidityMining.sol\";\n\ncontract LiquidityMining is ILiquidityMining, LiquidityMiningStorage {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n /* Constants */\n\n uint256 public constant PRECISION = 1e12;\n // Bonus multiplier for early liquidity providers.\n // During bonus period each passed block will be calculated like N passed blocks, where N = BONUS_MULTIPLIER\n uint256 public constant BONUS_BLOCK_MULTIPLIER = 10;\n\n uint256 public constant SECONDS_PER_BLOCK = 30;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event PoolTokenAdded(address indexed user, address indexed poolToken, uint256 allocationPoint);\n event PoolTokenUpdated(\n address indexed user,\n address indexed poolToken,\n uint256 newAllocationPoint,\n uint256 oldAllocationPoint\n );\n event Deposit(address indexed user, address indexed poolToken, uint256 amount);\n event RewardClaimed(address indexed user, address indexed poolToken, uint256 amount);\n event Withdraw(address indexed user, address indexed poolToken, uint256 amount);\n event EmergencyWithdraw(\n address indexed user,\n address indexed poolToken,\n uint256 amount,\n uint256 accumulatedReward\n );\n\n /* Functions */\n\n /**\n * @notice Initialize mining.\n *\n * @param _SOV The SOV token.\n * @param _rewardTokensPerBlock The number of reward tokens per block.\n * @param _startDelayBlocks The number of blocks should be passed to start\n * mining.\n * @param _numberOfBonusBlocks The number of blocks when each block will\n * be calculated as N blocks (BONUS_BLOCK_MULTIPLIER).\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n * SOV rewards are not paid directly to liquidity providers. Instead they\n * are deposited into a lockedSOV vault contract.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n */\n function initialize(\n IERC20 _SOV,\n uint256 _rewardTokensPerBlock,\n uint256 _startDelayBlocks,\n uint256 _numberOfBonusBlocks,\n address _wrapper,\n ILockedSOV _lockedSOV,\n uint256 _unlockedImmediatelyPercent\n ) external onlyAuthorized {\n /// @dev Non-idempotent function. Must be called just once.\n require(address(SOV) == address(0), \"Already initialized\");\n require(address(_SOV) != address(0), \"Invalid token address\");\n require(_startDelayBlocks > 0, \"Invalid start block\");\n require(\n _unlockedImmediatelyPercent < 10000,\n \"Unlocked immediately percent has to be less than 10000.\"\n );\n\n SOV = _SOV;\n rewardTokensPerBlock = _rewardTokensPerBlock;\n startBlock = block.number + _startDelayBlocks;\n bonusEndBlock = startBlock + _numberOfBonusBlocks;\n wrapper = _wrapper;\n lockedSOV = _lockedSOV;\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets lockedSOV contract.\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n */\n function setLockedSOV(ILockedSOV _lockedSOV) external onlyAuthorized {\n require(address(_lockedSOV) != address(0), \"Invalid lockedSOV Address.\");\n lockedSOV = _lockedSOV;\n }\n\n /**\n * @notice Sets unlocked immediately percent.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setUnlockedImmediatelyPercent(uint256 _unlockedImmediatelyPercent)\n external\n onlyAuthorized\n {\n require(\n _unlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets unlocked immediately percent overwrite for specific pool token.\n * @param _poolToken the address of pool token\n * @param _poolTokenUnlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setPoolTokenUnlockedImmediatelyPercent(\n address _poolToken,\n uint256 _poolTokenUnlockedImmediatelyPercent\n ) external onlyAuthorized {\n require(\n _poolTokenUnlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n poolTokensUnlockedImmediatelyPercent[_poolToken] = _poolTokenUnlockedImmediatelyPercent;\n }\n\n /**\n * @notice sets wrapper proxy contract\n * @dev can be set to zero address to remove wrapper\n */\n function setWrapper(address _wrapper) external onlyAuthorized {\n wrapper = _wrapper;\n }\n\n /**\n * @notice stops mining by setting end block\n */\n function stopMining() external onlyAuthorized {\n require(endBlock == 0, \"Already stopped\");\n\n endBlock = block.number;\n }\n\n /**\n * @notice Transfers SOV tokens to given address.\n * Owner use this function to withdraw SOV from LM contract\n * into another account.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) external onlyAuthorized {\n require(_receiver != address(0), \"Receiver address invalid\");\n require(_amount != 0, \"Amount invalid\");\n\n /// @dev Do not transfer more SOV than available.\n uint256 SOVBal = SOV.balanceOf(address(this));\n if (_amount > SOVBal) {\n _amount = SOVBal;\n }\n\n /// @dev The actual transfer.\n require(SOV.transfer(_receiver, _amount), \"Transfer failed\");\n\n /// @dev Event log.\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Get the missed SOV balance of LM contract.\n *\n * @return The amount of SOV tokens according to totalUsersBalance\n * in excess of actual SOV balance of the LM contract.\n * */\n function getMissedBalance() external view returns (uint256) {\n uint256 balance = SOV.balanceOf(address(this));\n return balance >= totalUsersBalance ? 0 : totalUsersBalance.sub(balance);\n }\n\n /**\n * @notice adds a new lp to the pool. Can only be called by the owner or an admin\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _withUpdate the flag whether we need to update all pools\n */\n function add(\n address _poolToken,\n uint96 _allocationPoint,\n bool _withUpdate\n ) external onlyAuthorized {\n require(_allocationPoint > 0, \"Invalid allocation point\");\n require(_poolToken != address(0), \"Invalid token address\");\n require(poolIdList[_poolToken] == 0, \"Token already added\");\n\n if (_withUpdate) {\n updateAllPools();\n }\n\n uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;\n totalAllocationPoint = totalAllocationPoint.add(_allocationPoint);\n\n poolInfoList.push(\n PoolInfo({\n poolToken: IERC20(_poolToken),\n allocationPoint: _allocationPoint,\n lastRewardBlock: lastRewardBlock,\n accumulatedRewardPerShare: 0\n })\n );\n //indexing starts from 1 in order to check whether token was already added\n poolIdList[_poolToken] = poolInfoList.length;\n\n emit PoolTokenAdded(msg.sender, _poolToken, _allocationPoint);\n }\n\n /**\n * @notice updates the given pool's reward tokens allocation point\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function update(\n address _poolToken,\n uint96 _allocationPoint,\n bool _updateAllFlag\n ) external onlyAuthorized {\n if (_updateAllFlag) {\n updateAllPools();\n } else {\n updatePool(_poolToken);\n }\n _updateToken(_poolToken, _allocationPoint);\n }\n\n function _updateToken(address _poolToken, uint96 _allocationPoint) internal {\n uint256 poolId = _getPoolId(_poolToken);\n\n uint256 previousAllocationPoint = poolInfoList[poolId].allocationPoint;\n totalAllocationPoint = totalAllocationPoint.sub(previousAllocationPoint).add(\n _allocationPoint\n );\n poolInfoList[poolId].allocationPoint = _allocationPoint;\n\n emit PoolTokenUpdated(msg.sender, _poolToken, _allocationPoint, previousAllocationPoint);\n }\n\n /**\n * @notice updates the given pools' reward tokens allocation points\n * @param _poolTokens array of addresses of pool tokens\n * @param _allocationPoints array of allocation points (weight) for the given pools\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function updateTokens(\n address[] calldata _poolTokens,\n uint96[] calldata _allocationPoints,\n bool _updateAllFlag\n ) external onlyAuthorized {\n require(_poolTokens.length == _allocationPoints.length, \"Arrays mismatch\");\n\n if (_updateAllFlag) {\n updateAllPools();\n }\n uint256 length = _poolTokens.length;\n for (uint256 i = 0; i < length; i++) {\n if (!_updateAllFlag) {\n updatePool(_poolTokens[i]);\n }\n _updateToken(_poolTokens[i], _allocationPoints[i]);\n }\n }\n\n /**\n * @notice returns reward multiplier over the given _from to _to block\n * @param _from the first block for a calculation\n * @param _to the last block for a calculation\n */\n function _getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n internal\n view\n returns (uint256)\n {\n if (_from < startBlock) {\n _from = startBlock;\n }\n if (endBlock > 0 && _to > endBlock) {\n _to = endBlock;\n }\n if (_to <= bonusEndBlock) {\n return _to.sub(_from).mul(BONUS_BLOCK_MULTIPLIER);\n } else if (_from >= bonusEndBlock) {\n return _to.sub(_from);\n } else {\n return\n bonusEndBlock.sub(_from).mul(BONUS_BLOCK_MULTIPLIER).add(_to.sub(bonusEndBlock));\n }\n }\n\n function _getUserAccumulatedReward(uint256 _poolId, address _user)\n internal\n view\n returns (uint256)\n {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_user];\n\n uint256 accumulatedRewardPerShare = pool.accumulatedRewardPerShare;\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (block.number > pool.lastRewardBlock && poolTokenBalance != 0) {\n (, uint256 accumulatedRewardPerShare_) = _getPoolAccumulatedReward(pool);\n accumulatedRewardPerShare = accumulatedRewardPerShare.add(accumulatedRewardPerShare_);\n }\n\n return\n user.accumulatedReward.add(\n user.amount.mul(accumulatedRewardPerShare).div(PRECISION).sub(user.rewardDebt)\n );\n }\n\n /**\n * @notice returns accumulated reward\n * @param _poolToken the address of pool token\n * @param _user the user address\n */\n function getUserAccumulatedReward(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n uint256 poolId = _getPoolId(_poolToken);\n return _getUserAccumulatedReward(poolId, _user);\n }\n\n /**\n * @notice returns estimated reward\n * @param _poolToken the address of pool token\n * @param _amount the amount of tokens to be deposited\n * @param _duration the duration of liquidity providing in seconds\n */\n function getEstimatedReward(\n address _poolToken,\n uint256 _amount,\n uint256 _duration\n ) external view returns (uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n uint256 start = block.number;\n uint256 end = start.add(_duration.div(SECONDS_PER_BLOCK));\n (, uint256 accumulatedRewardPerShare) =\n _getPoolAccumulatedReward(pool, _amount, start, end);\n return _amount.mul(accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Updates reward variables for all pools.\n * @dev Be careful of gas spending!\n */\n function updateAllPools() public {\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n _updatePool(i);\n }\n }\n\n /**\n * @notice Updates reward variables of the given pool to be up-to-date\n * @param _poolToken the address of pool token\n */\n function updatePool(address _poolToken) public {\n uint256 poolId = _getPoolId(_poolToken);\n _updatePool(poolId);\n }\n\n function _updatePool(uint256 _poolId) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n\n //this pool has been updated recently\n if (block.number <= pool.lastRewardBlock) {\n return;\n }\n\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (poolTokenBalance == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n (uint256 accumulatedReward_, uint256 accumulatedRewardPerShare_) =\n _getPoolAccumulatedReward(pool);\n pool.accumulatedRewardPerShare = pool.accumulatedRewardPerShare.add(\n accumulatedRewardPerShare_\n );\n pool.lastRewardBlock = block.number;\n\n totalUsersBalance = totalUsersBalance.add(accumulatedReward_);\n }\n\n function _getPoolAccumulatedReward(PoolInfo storage _pool)\n internal\n view\n returns (uint256, uint256)\n {\n return _getPoolAccumulatedReward(_pool, 0, _pool.lastRewardBlock, block.number);\n }\n\n function _getPoolAccumulatedReward(\n PoolInfo storage _pool,\n uint256 _additionalAmount,\n uint256 _startBlock,\n uint256 _endBlock\n ) internal view returns (uint256, uint256) {\n uint256 passedBlocks = _getPassedBlocksWithBonusMultiplier(_startBlock, _endBlock);\n uint256 accumulatedReward =\n passedBlocks.mul(rewardTokensPerBlock).mul(_pool.allocationPoint).div(\n totalAllocationPoint\n );\n\n uint256 poolTokenBalance = _pool.poolToken.balanceOf(address(this));\n poolTokenBalance = poolTokenBalance.add(_additionalAmount);\n uint256 accumulatedRewardPerShare = accumulatedReward.mul(PRECISION).div(poolTokenBalance);\n return (accumulatedReward, accumulatedRewardPerShare);\n }\n\n /**\n * @notice deposits pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it or to msg.sender\n */\n function deposit(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n _deposit(_poolToken, _amount, _user, false);\n }\n\n /**\n * @notice if the lending pools directly mint/transfer tokens to this address, process it like a user deposit\n * @dev only callable by the pool which issues the tokens\n * @param _user the user address\n * @param _amount the minted amount\n */\n function onTokensDeposited(address _user, uint256 _amount) external {\n //the msg.sender is the pool token. if the msg.sender is not a valid pool token, _deposit will revert\n _deposit(msg.sender, _amount, _user, true);\n }\n\n /**\n * @notice internal function for depositing pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it\n * @param alreadyTransferred true if the pool tokens have already been transferred\n */\n function _deposit(\n address _poolToken,\n uint256 _amount,\n address _user,\n bool alreadyTransferred\n ) internal {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _user != address(0) ? _user : msg.sender;\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n\n _updatePool(poolId);\n //sends reward directly to the user\n _updateReward(pool, user);\n\n if (_amount > 0) {\n //receives pool tokens from msg.sender, it can be user or WrapperProxy contract\n if (!alreadyTransferred)\n pool.poolToken.safeTransferFrom(address(msg.sender), address(this), _amount);\n user.amount = user.amount.add(_amount);\n }\n _updateRewardDebt(pool, user);\n emit Deposit(userAddress, _poolToken, _amount);\n }\n\n /**\n * @notice transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimReward(address _poolToken, address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n _claimReward(poolId, userAddress, true);\n }\n\n function _claimReward(\n uint256 _poolId,\n address _userAddress,\n bool _isStakingTokens\n ) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_userAddress];\n\n _updatePool(_poolId);\n _updateReward(pool, user);\n _transferReward(address(pool.poolToken), user, _userAddress, _isStakingTokens, true);\n _updateRewardDebt(pool, user);\n }\n\n /**\n * @notice transfers reward tokens from all pools\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimRewardFromAllPools(address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n uint256 poolId = i;\n _claimReward(poolId, userAddress, false);\n }\n\n if (\n lockedSOV.getLockedBalance(userAddress) > 0 ||\n lockedSOV.getUnlockedBalance(userAddress) > 0\n ) {\n lockedSOV.withdrawAndStakeTokensFrom(userAddress);\n }\n }\n\n /**\n * @notice withdraws pool tokens and transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the user address will be used to process a withdrawal (can be passed only by wrapper contract)\n */\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n require(user.amount >= _amount, \"Not enough balance\");\n\n _updatePool(poolId);\n _updateReward(pool, user);\n _transferReward(_poolToken, user, userAddress, false, false);\n\n user.amount = user.amount.sub(_amount);\n\n //msg.sender is wrapper -> send to wrapper\n if (msg.sender == wrapper) {\n pool.poolToken.safeTransfer(address(msg.sender), _amount);\n }\n //msg.sender is user or pool token (lending pool) -> send to user\n else {\n pool.poolToken.safeTransfer(userAddress, _amount);\n }\n\n _updateRewardDebt(pool, user);\n emit Withdraw(userAddress, _poolToken, _amount);\n }\n\n function _getUserAddress(address _user) internal view returns (address) {\n address userAddress = msg.sender;\n if (_user != address(0)) {\n //only wrapper can pass _user parameter\n require(\n msg.sender == wrapper || poolIdList[msg.sender] != 0,\n \"only wrapper or pools may withdraw for a user\"\n );\n userAddress = _user;\n }\n return userAddress;\n }\n\n function _updateReward(PoolInfo storage pool, UserInfo storage user) internal {\n //update user accumulated reward\n if (user.amount > 0) {\n //add reward for the previous amount of deposited tokens\n uint256 accumulatedReward =\n user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION).sub(\n user.rewardDebt\n );\n user.accumulatedReward = user.accumulatedReward.add(accumulatedReward);\n }\n }\n\n function _updateRewardDebt(PoolInfo storage pool, UserInfo storage user) internal {\n //reward accumulated before amount update (should be subtracted during next reward calculation)\n user.rewardDebt = user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Send reward in SOV to the lockedSOV vault.\n * @param _user The user info, to get its reward share.\n * @param _userAddress The address of the user, to send SOV in its behalf.\n * @param _isStakingTokens The flag whether we need to stake tokens\n * @param _isCheckingBalance The flag whether we need to throw error or don't process reward if SOV balance isn't enough\n */\n function _transferReward(\n address _poolToken,\n UserInfo storage _user,\n address _userAddress,\n bool _isStakingTokens,\n bool _isCheckingBalance\n ) internal {\n uint256 userAccumulatedReward = _user.accumulatedReward;\n /// @dev get unlock immediate percent of the pool token.\n uint256 calculatedUnlockedImmediatelyPercent = calcUnlockedImmediatelyPercent(_poolToken);\n\n /// @dev Transfer if enough SOV balance on this LM contract.\n uint256 balance = SOV.balanceOf(address(this));\n if (balance >= userAccumulatedReward) {\n totalUsersBalance = totalUsersBalance.sub(userAccumulatedReward);\n _user.accumulatedReward = 0;\n\n /// @dev If calculatedUnlockedImmediatelyPercent is 100%, transfer the reward to the LP (user).\n /// else, deposit it into lockedSOV vault contract, but first\n /// SOV deposit must be approved to move the SOV tokens\n /// from this LM contract into the lockedSOV vault.\n if (calculatedUnlockedImmediatelyPercent == 10000) {\n SOV.transfer(_userAddress, userAccumulatedReward);\n } else {\n require(SOV.approve(address(lockedSOV), userAccumulatedReward), \"Approve failed\");\n lockedSOV.deposit(\n _userAddress,\n userAccumulatedReward,\n calculatedUnlockedImmediatelyPercent\n );\n\n if (_isStakingTokens) {\n lockedSOV.withdrawAndStakeTokensFrom(_userAddress);\n }\n }\n\n /// @dev Event log.\n emit RewardClaimed(_userAddress, _poolToken, userAccumulatedReward);\n } else {\n require(!_isCheckingBalance, \"Claiming reward failed\");\n }\n }\n\n /**\n * @notice withdraws pool tokens without transferring reward tokens\n * @param _poolToken the address of pool token\n * @dev EMERGENCY ONLY\n */\n function emergencyWithdraw(address _poolToken) external {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][msg.sender];\n\n _updatePool(poolId);\n _updateReward(pool, user);\n\n totalUsersBalance = totalUsersBalance.sub(user.accumulatedReward);\n uint256 userAmount = user.amount;\n uint256 userAccumulatedReward = user.accumulatedReward;\n user.amount = 0;\n user.rewardDebt = 0;\n user.accumulatedReward = 0;\n pool.poolToken.safeTransfer(address(msg.sender), userAmount);\n\n emit EmergencyWithdraw(msg.sender, _poolToken, userAmount, userAccumulatedReward);\n }\n\n /**\n * @notice returns pool id\n * @param _poolToken the address of pool token\n */\n function getPoolId(address _poolToken) external view returns (uint256) {\n return _getPoolId(_poolToken);\n }\n\n function _getPoolId(address _poolToken) internal view returns (uint256) {\n uint256 poolId = poolIdList[_poolToken];\n require(poolId > 0, \"Pool token not found\");\n return poolId - 1;\n }\n\n /**\n * @notice returns count of pool tokens\n */\n function getPoolLength() external view returns (uint256) {\n return poolInfoList.length;\n }\n\n /**\n * @notice returns list of pool token's info\n */\n function getPoolInfoList() external view returns (PoolInfo[] memory) {\n return poolInfoList;\n }\n\n /**\n * @notice returns pool info for the given token\n * @param _poolToken the address of pool token\n */\n function getPoolInfo(address _poolToken) external view returns (PoolInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return poolInfoList[poolId];\n }\n\n /**\n * @notice returns list of [amount, accumulatedReward] for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserBalanceList(address _user) external view returns (uint256[2][] memory) {\n uint256 length = poolInfoList.length;\n uint256[2][] memory userBalanceList = new uint256[2][](length);\n for (uint256 i = 0; i < length; i++) {\n userBalanceList[i][0] = userInfoMap[i][_user].amount;\n userBalanceList[i][1] = _getUserAccumulatedReward(i, _user);\n }\n return userBalanceList;\n }\n\n /**\n * @notice returns UserInfo for the given pool and user\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserInfo(address _poolToken, address _user) public view returns (UserInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return userInfoMap[poolId][_user];\n }\n\n /**\n * @notice returns list of UserInfo for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserInfoList(address _user) external view returns (UserInfo[] memory) {\n uint256 length = poolInfoList.length;\n UserInfo[] memory userInfoList = new UserInfo[](length);\n for (uint256 i = 0; i < length; i++) {\n userInfoList[i] = userInfoMap[i][_user];\n }\n return userInfoList;\n }\n\n /**\n * @notice returns accumulated reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardList(address _user) external view returns (uint256[] memory) {\n uint256 length = poolInfoList.length;\n uint256[] memory rewardList = new uint256[](length);\n for (uint256 i = 0; i < length; i++) {\n rewardList[i] = _getUserAccumulatedReward(i, _user);\n }\n return rewardList;\n }\n\n /**\n * @notice returns the pool token balance a user has on the contract\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n UserInfo memory ui = getUserInfo(_poolToken, _user);\n return ui.amount;\n }\n\n /**\n * @notice returns the accumulated liquid reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBePaidLiquid(address _user)\n external\n view\n returns (uint256)\n {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n calculatedUnlockedImmediatelyPercent.mul(_getUserAccumulatedReward(i, _user)).div(\n 10000\n )\n );\n }\n\n return result;\n }\n\n /**\n * @notice returns the accumulated vested reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBeVested(address _user) external view returns (uint256) {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n (10000 - calculatedUnlockedImmediatelyPercent)\n .mul(_getUserAccumulatedReward(i, _user))\n .div(10000)\n );\n }\n\n return result;\n }\n\n /**\n * @dev calculate the unlocked immediate percentage of specific pool token\n * use the poolTokensUnlockedImmediatelyPercent by default, if it is not set, then use the unlockedImmediatelyPercent\n */\n function calcUnlockedImmediatelyPercent(address _poolToken) public view returns (uint256) {\n uint256 poolTokenUnlockedImmediatelyPercent =\n poolTokensUnlockedImmediatelyPercent[_poolToken];\n return\n poolTokenUnlockedImmediatelyPercent > 0\n ? poolTokenUnlockedImmediatelyPercent\n : unlockedImmediatelyPercent;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningConfigToken.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/IERC20_.sol\";\n\n/**\n * @title Dummy token with 0 total supply.\n *\n * @dev We need this token for having a flexibility with LiquidityMining configuration\n */\ncontract LiquidityMiningConfigToken is IERC20_ {\n function totalSupply() external view returns (uint256) {\n return 0;\n }\n\n function balanceOf(address account) external view returns (uint256) {\n return 0;\n }\n\n function transfer(address recipient, uint256 amount) external returns (bool) {\n return false;\n }\n\n function allowance(address owner, address spender) external view returns (uint256) {\n return 0;\n }\n\n function approve(address spender, uint256 amount) external returns (bool) {\n return false;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool) {\n return false;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./LiquidityMiningStorage.sol\";\nimport \"../proxy/UpgradableProxy.sol\";\n\n/**\n * @dev LiquidityMining contract should be upgradable, use UpgradableProxy\n */\ncontract LiquidityMiningProxy is LiquidityMiningStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/farm/LiquidityMiningStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../utils/AdminRole.sol\";\n\ncontract LiquidityMiningStorage is AdminRole {\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many pool tokens the user has provided.\n uint256 rewardDebt; // Reward debt. See explanation below.\n uint256 accumulatedReward; //Reward that's ready to be transferred\n //\n // We do some fancy math here. Basically, any point in time, the amount of reward tokens\n // entitled to a user but is accumulated to be distributed is:\n //\n // accumulated reward = (user.amount * pool.accumulatedRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accumulatedRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the accumulated reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 poolToken; // Address of LP token contract.\n uint96 allocationPoint; // How many allocation points assigned to this pool. Amount of reward tokens to distribute per block.\n uint256 lastRewardBlock; // Last block number that reward tokens distribution occurs.\n uint256 accumulatedRewardPerShare; // Accumulated amount of reward tokens per share, times 1e12. See below.\n }\n\n // Rewards tokens created per block.\n uint256 public rewardTokensPerBlock;\n // The block number when reward token mining starts.\n uint256 public startBlock;\n // Block number when bonus reward token period ends.\n uint256 public bonusEndBlock;\n // Block number when reward token period ends.\n uint256 public endBlock;\n\n //Wrapper contract which will be a proxy between user and LM\n address public wrapper;\n\n // Info of each pool.\n PoolInfo[] public poolInfoList;\n // Mapping pool token address => pool id\n mapping(address => uint256) poolIdList;\n // Total allocation points. Must be the sum of all allocation points in all pools.\n uint256 public totalAllocationPoint;\n\n // Info of each user that stakes LP tokens.\n mapping(uint256 => mapping(address => UserInfo)) public userInfoMap;\n // Total balance this contract should have to handle withdrawal for all users\n uint256 public totalUsersBalance;\n\n /// @dev The SOV token\n IERC20 public SOV;\n\n /// @dev The locked vault contract to deposit LP's rewards into.\n ILockedSOV public lockedSOV;\n\n // The % which determines how much will be unlocked immediately.\n /// @dev 10000 is 100%\n uint256 public unlockedImmediatelyPercent;\n\n /// @dev overwrite the unlockedImmediatelyPercent for specific token.\n mapping(address => uint256) public poolTokensUnlockedImmediatelyPercent;\n}\n" + }, + "contracts/feeds/BProPriceFeed.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IMoCState.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The BPro Price Feed contract.\n *\n * This contract gets/sets the MoC (Money on Chain) address of its state\n * contract and queries its method bproUsdPrice to get bPro/USD valuation.\n * */\ncontract BProPriceFeed is IPriceFeedsExt, Ownable {\n address public mocStateAddress;\n\n event SetMoCStateAddress(address indexed mocStateAddress, address changerAddress);\n\n /**\n * @notice Initializes a new MoC state.\n *\n * @param _mocStateAddress MoC state address\n * */\n constructor(address _mocStateAddress) public {\n setMoCStateAddress(_mocStateAddress);\n }\n\n /**\n * @notice Get BPro USD price.\n *\n * @return the BPro USD Price [using mocPrecision]\n */\n function latestAnswer() external view returns (uint256) {\n IMoCState _mocState = IMoCState(mocStateAddress);\n return _mocState.bproUsdPrice();\n }\n\n /**\n * @notice Supposed to get the MoC update time, but instead\n * get the current timestamp.\n *\n * @return Always returns current block's timestamp.\n * */\n function latestTimestamp() external view returns (uint256) {\n return now; /// MoC state doesn't return update timestamp.\n }\n\n /**\n * @notice Set MoC state address.\n *\n * @param _mocStateAddress The MoC state address.\n * */\n function setMoCStateAddress(address _mocStateAddress) public onlyOwner {\n require(Address.isContract(_mocStateAddress), \"_mocStateAddress not a contract\");\n mocStateAddress = _mocStateAddress;\n emit SetMoCStateAddress(mocStateAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/IMoCState.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IMoCState {\n function getRbtcInBitPro(bytes32 bucket) external view returns (uint256);\n\n function globalMaxBPro() external view returns (uint256);\n\n function maxBPro(bytes32 bucket) external view returns (uint256);\n\n function absoluteMaxBPro() external view returns (uint256);\n\n function maxBProWithDiscount() external view returns (uint256);\n\n function bproTecPrice() external view returns (uint256);\n\n function bucketBProTecPrice(bytes32 bucket) external view returns (uint256);\n\n function bproDiscountPrice() external view returns (uint256);\n\n function bproUsdPrice() external view returns (uint256);\n\n function bproSpotDiscountRate() external view returns (uint256);\n\n function getBucketNBPro(bytes32 bucket) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IPriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface IPriceFeeds {\n function queryRate(address sourceToken, address destToken)\n external\n view\n returns (uint256 rate, uint256 precision);\n\n function queryPrecision(address sourceToken, address destToken)\n external\n view\n returns (uint256 precision);\n\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) external view returns (uint256 destAmount);\n\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) external view returns (uint256 sourceToDestSwapRate);\n\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\n\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (uint256);\n\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\n\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\n\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (bool);\n\n function getFastGasPrice(address payToken) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IRSKOracle {\n function updatePrice(uint256 price, uint256 timestamp) external;\n\n function getPricing() external view returns (uint256, uint256);\n\n function setOracleAddress(address addr) external;\n\n function clearOracleAddress() external;\n}\n" + }, + "contracts/feeds/IV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IV1PoolOracle {\n function read(uint256 price, uint256 timestamp)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function latestAnswer() external view returns (uint256);\n\n function liquidityPool() external view returns (address);\n\n function latestPrice(address _baseToken) external view returns (uint256 answer);\n}\n\ninterface ILiquidityPoolV1Converter {\n function reserveTokens(uint256 index) external view returns (address);\n}\n" + }, + "contracts/feeds/PriceFeedRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IRSKOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @notice The Price Feed RSK Oracle contract.\n *\n * This contract implements RSK Oracle query functionality,\n * getting the price and the last timestamp from an external oracle contract.\n * */\ncontract PriceFeedRSKOracle is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public rskOracleAddress;\n\n /* Events */\n\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new RSK Oracle.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _rskOracleAddress) public {\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256 _price) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (_price, ) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestTimestamp() external view returns (uint256 _timestamp) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (, _timestamp) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/PriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./PriceFeedsConstants.sol\";\n\ninterface IPriceFeedsExt {\n function latestAnswer() external view returns (uint256);\n}\n\n/**\n * @title The Price Feeds contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract queries the price feeds contracts where\n * oracles updates token prices computing relative token prices.\n * And besides it includes some calculations about loans such as\n * drawdown, margin and collateral.\n * */\ncontract PriceFeeds is Constants, Ownable {\n using SafeMath for uint256;\n\n /* Events */\n\n event GlobalPricingPaused(address indexed sender, bool indexed isPaused);\n\n /* Storage */\n\n /// Mapping of PriceFeedsExt instances.\n /// token => pricefeed\n mapping(address => IPriceFeedsExt) public pricesFeeds;\n\n /// Decimals of supported tokens.\n mapping(address => uint256) public decimals;\n\n /// Value on rBTC weis for the protocol token.\n uint256 public protocolTokenEthPrice = 0.0002 ether;\n\n /// Flag to pause pricings.\n bool public globalPricingPaused = false;\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires 3 parameters.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * @param _protocolTokenAddress The address of the protocol token.\n * @param _baseTokenAddress The address of the base token.\n * */\n constructor(\n address _wrbtcTokenAddress,\n address _protocolTokenAddress,\n address _baseTokenAddress\n ) public {\n /// Set decimals for this token.\n decimals[address(0)] = 18;\n decimals[_wrbtcTokenAddress] = 18;\n _setWrbtcToken(_wrbtcTokenAddress);\n _setProtocolTokenAddress(_protocolTokenAddress);\n _setBaseToken(_baseTokenAddress);\n }\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @dev Public wrapper for _queryRate internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function queryRate(address sourceToken, address destToken)\n public\n view\n returns (uint256 rate, uint256 precision)\n {\n return _queryRate(sourceToken, destToken);\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @dev Public wrapper for _getDecimalPrecision internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function queryPrecision(address sourceToken, address destToken) public view returns (uint256) {\n return sourceToken != destToken ? _getDecimalPrecision(sourceToken, destToken) : 10**18;\n }\n\n /**\n * @notice Price conversor: Calculate the price of an amount of source\n * tokens in destiny token units.\n *\n * @dev NOTE: This function returns 0 during a pause, rather than a revert.\n * Ensure calling contracts handle correctly.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of the source tokens.\n *\n * @return destAmount The amount of destiny tokens equivalent in price\n * to the amount of source tokens.\n * */\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) public view returns (uint256 destAmount) {\n if (globalPricingPaused) {\n return 0;\n }\n\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n destAmount = sourceAmount.mul(rate).div(precision);\n }\n\n /**\n * @notice Calculate the swap rate between two tokens.\n *\n * Regarding slippage, there is a hardcoded slippage limit of 5%, enforced\n * by this function for all borrowing, lending and margin trading\n * originated swaps performed in the Sovryn exchange.\n *\n * This means all operations in the Sovryn exchange are subject to losing\n * up to 5% from the internal swap performed.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of source tokens.\n * @param destAmount The amount of destiny tokens.\n * @param maxSlippage The maximum slippage limit.\n *\n * @return sourceToDestSwapRate The swap rate between tokens.\n * */\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) public view returns (uint256 sourceToDestSwapRate) {\n require(!globalPricingPaused, \"pricing is paused\");\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n sourceToDestSwapRate = destAmount.mul(precision).div(sourceAmount);\n\n if (rate > sourceToDestSwapRate) {\n uint256 spreadValue = rate - sourceToDestSwapRate;\n spreadValue = spreadValue.mul(10**20).div(sourceToDestSwapRate);\n require(spreadValue <= maxSlippage, \"price disagreement\");\n }\n }\n\n /**\n * @notice Calculate the rBTC amount equivalent to a given token amount.\n * Native coin on RSK is rBTC. This code comes from Ethereum applications,\n * so Eth refers to 10**18 weis of native coin, i.e.: 1 rBTC.\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n *\n * @return ethAmount The amount of rBTC equivalent.\n * */\n function amountInEth(address tokenAddress, uint256 amount)\n public\n view\n returns (uint256 ethAmount)\n {\n /// Token is wrBTC, amount in rBTC is the same.\n if (tokenAddress == address(wrbtcToken)) {\n ethAmount = amount;\n } else {\n (uint256 toEthRate, uint256 toEthPrecision) =\n queryRate(tokenAddress, address(wrbtcToken));\n ethAmount = amount.mul(toEthRate).div(toEthPrecision);\n }\n }\n\n /**\n * @notice Calculate the maximum drawdown of a loan.\n *\n * A drawdown is commonly defined as the decline from a high peak to a\n * pullback low of a specific investment or equity in an account.\n *\n * Drawdown magnitude refers to the amount of value that a user loses\n * during the drawdown period.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param margin The relation between the position size and the loan.\n * margin = (total position size - loan) / loan\n *\n * @return maxDrawdown The maximum drawdown.\n * */\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 margin\n ) public view returns (uint256 maxDrawdown) {\n uint256 loanToCollateralAmount;\n if (collateralToken == loanToken) {\n loanToCollateralAmount = loanAmount;\n } else {\n (uint256 rate, uint256 precision) = queryRate(loanToken, collateralToken);\n loanToCollateralAmount = loanAmount.mul(rate).div(precision);\n }\n\n uint256 combined =\n loanToCollateralAmount.add(loanToCollateralAmount.mul(margin).div(10**20));\n\n maxDrawdown = collateralAmount > combined ? collateralAmount - combined : 0;\n }\n\n /**\n * @notice Calculate the margin and the collateral on rBTC.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralInEthAmount The amount of collateral on rBTC.\n * */\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralInEthAmount) {\n (currentMargin, ) = getCurrentMargin(\n loanToken,\n collateralToken,\n loanAmount,\n collateralAmount\n );\n\n collateralInEthAmount = amountInEth(collateralToken, collateralAmount);\n }\n\n /**\n * @notice Calculate the margin of a loan.\n *\n * @dev current margin = (total position size - loan) / loan\n * The collateral amount passed as parameter equals the total position size.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralToLoanRate The price ratio between collateral and\n * loan tokens.\n * */\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralToLoanRate) {\n uint256 collateralToLoanAmount;\n if (collateralToken == loanToken) {\n collateralToLoanAmount = collateralAmount;\n collateralToLoanRate = 10**18;\n } else {\n uint256 collateralToLoanPrecision;\n (collateralToLoanRate, collateralToLoanPrecision) = queryRate(\n collateralToken,\n loanToken\n );\n\n collateralToLoanRate = collateralToLoanRate.mul(10**18).div(collateralToLoanPrecision);\n\n collateralToLoanAmount = collateralAmount.mul(collateralToLoanRate).div(10**18);\n }\n\n if (loanAmount != 0 && collateralToLoanAmount >= loanAmount) {\n return (\n collateralToLoanAmount.sub(loanAmount).mul(10**20).div(loanAmount),\n collateralToLoanRate\n );\n } else {\n return (0, collateralToLoanRate);\n }\n }\n\n /**\n * @notice Get assessment about liquidating a loan.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param maintenanceMargin The minimum margin before liquidation.\n *\n * @return True/false to liquidate the loan.\n * */\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) public view returns (bool) {\n (uint256 currentMargin, ) =\n getCurrentMargin(loanToken, collateralToken, loanAmount, collateralAmount);\n\n return currentMargin <= maintenanceMargin;\n }\n\n /*\n * Owner functions\n */\n\n /**\n * @notice Set new value for protocolTokenEthPrice\n *\n * @param newPrice The new value for protocolTokenEthPrice\n * */\n function setProtocolTokenEthPrice(uint256 newPrice) external onlyOwner {\n require(newPrice != 0, \"invalid price\");\n protocolTokenEthPrice = newPrice;\n }\n\n /**\n * @notice Populate pricesFeeds mapping w/ values from feeds[]\n *\n * @param tokens The array of tokens to loop and get addresses.\n * @param feeds The array of contract instances for every token.\n * */\n function setPriceFeed(address[] calldata tokens, IPriceFeedsExt[] calldata feeds)\n external\n onlyOwner\n {\n require(tokens.length == feeds.length, \"count mismatch\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n pricesFeeds[tokens[i]] = feeds[i];\n }\n }\n\n /**\n * @notice Populate decimals mapping w/ values from tokens[].decimals\n *\n * @param tokens The array of tokens to loop and get values from.\n * */\n function setDecimals(IERC20[] calldata tokens) external onlyOwner {\n for (uint256 i = 0; i < tokens.length; i++) {\n decimals[address(tokens[i])] = tokens[i].decimals();\n }\n }\n\n /**\n * @notice Set flag globalPricingPaused\n *\n * @param isPaused The new status of pause (true/false).\n * */\n function setGlobalPricingPaused(bool isPaused) external onlyOwner {\n if (globalPricingPaused != isPaused) {\n globalPricingPaused = isPaused;\n\n emit GlobalPricingPaused(msg.sender, isPaused);\n }\n }\n\n /*\n * Internal functions\n */\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n /// Different tokens, query prices and perform division.\n if (sourceToken != destToken) {\n uint256 sourceRate;\n if (sourceToken != address(baseToken) && sourceToken != protocolTokenAddress) {\n IPriceFeedsExt _sourceFeed = pricesFeeds[sourceToken];\n require(address(_sourceFeed) != address(0), \"unsupported src feed\");\n\n /// Query token price on priceFeedsExt instance.\n sourceRate = _sourceFeed.latestAnswer();\n require(sourceRate != 0 && (sourceRate >> 128) == 0, \"price error\");\n } else {\n sourceRate = sourceToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n uint256 destRate;\n if (destToken != address(baseToken) && destToken != protocolTokenAddress) {\n IPriceFeedsExt _destFeed = pricesFeeds[destToken];\n require(address(_destFeed) != address(0), \"unsupported dst feed\");\n\n /// Query token price on priceFeedsExt instance.\n destRate = _destFeed.latestAnswer();\n require(destRate != 0 && (destRate >> 128) == 0, \"price error\");\n } else {\n destRate = destToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n rate = sourceRate.mul(10**18).div(destRate);\n\n precision = _getDecimalPrecision(sourceToken, destToken);\n\n /// Same tokens, return 1 with decimals.\n } else {\n rate = 10**18;\n precision = 10**18;\n }\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function _getDecimalPrecision(address sourceToken, address destToken)\n internal\n view\n returns (uint256)\n {\n /// Same tokens, return 1 with decimals.\n if (sourceToken == destToken) {\n return 10**18;\n\n /// Different tokens, query ERC20 precisions and return 18 +- diff.\n } else {\n uint256 sourceTokenDecimals = decimals[sourceToken];\n if (sourceTokenDecimals == 0) sourceTokenDecimals = IERC20(sourceToken).decimals();\n\n uint256 destTokenDecimals = decimals[destToken];\n if (destTokenDecimals == 0) destTokenDecimals = IERC20(destToken).decimals();\n\n if (destTokenDecimals >= sourceTokenDecimals)\n return 10**(SafeMath.sub(18, destTokenDecimals - sourceTokenDecimals));\n else return 10**(SafeMath.add(18, sourceTokenDecimals - destTokenDecimals));\n }\n }\n}\n" + }, + "contracts/feeds/PriceFeedsConstants.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The Price Feeds Constants contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract keep the addresses of token instances for wrBTC, base token\n * and protocol token.\n * */\ncontract Constants {\n IWrbtcERC20 public wrbtcToken;\n IWrbtcERC20 public baseToken;\n address internal protocolTokenAddress;\n\n /**\n * @notice Set wrBTC token address.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * */\n function _setWrbtcToken(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"_wrbtcTokenAddress not a contract\");\n wrbtcToken = IWrbtcERC20(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Set protocol token address.\n *\n * @param _protocolTokenAddress The address of the protocol token.\n * */\n function _setProtocolTokenAddress(address _protocolTokenAddress) internal {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n protocolTokenAddress = _protocolTokenAddress;\n }\n\n /**\n * @notice Set base token address.\n *\n * @param _baseTokenAddress The address of the base token.\n * */\n function _setBaseToken(address _baseTokenAddress) internal {\n require(Address.isContract(_baseTokenAddress), \"_baseTokenAddress not a contract\");\n baseToken = IWrbtcERC20(_baseTokenAddress);\n }\n}\n" + }, + "contracts/feeds/PriceFeedV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IV1PoolOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./IPriceFeeds.sol\";\n\n/**\n * @notice The Price Feed V1 Pool Oracle contract.\n *\n * This contract implements V1 Pool Oracle query functionality,\n * getting the price from v1 pool oracle.\n * */\ncontract PriceFeedV1PoolOracle is IPriceFeedsExt, Ownable {\n using SafeMath for uint256;\n /* Storage */\n\n address public v1PoolOracleAddress;\n address public wRBTCAddress;\n address public docAddress;\n address public baseCurrency;\n\n /* Events */\n event SetV1PoolOracleAddress(address indexed v1PoolOracleAddress, address changerAddress);\n event SetWRBTCAddress(address indexed wRBTCAddress, address changerAddress);\n event SetDOCAddress(address indexed docAddress, address changerAddress);\n event SetBaseCurrency(address indexed baseCurrency, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new V1 Pool Oracle.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n * @param _wRBTCAddress The wrbtc token address.\n * @param _docAddress The doc token address.\n * */\n constructor(\n address _v1PoolOracleAddress,\n address _wRBTCAddress,\n address _docAddress,\n address _baseCurrency\n ) public {\n setRBTCAddress(_wRBTCAddress);\n setDOCAddress(_docAddress);\n setV1PoolOracleAddress(_v1PoolOracleAddress);\n setBaseCurrency(_baseCurrency);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256) {\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(v1PoolOracleAddress);\n\n uint256 _price = _v1PoolOracle.latestPrice(baseCurrency);\n\n // Need to convert to USD, since the V1 pool return value is based on BTC\n uint256 priceInUSD = _convertAnswerToUsd(_price);\n require(priceInUSD != 0, \"price error\");\n\n return priceInUSD;\n }\n\n function _convertAnswerToUsd(uint256 _valueInBTC) private view returns (uint256) {\n address _priceFeeds = msg.sender;\n\n uint256 precision = IPriceFeeds(_priceFeeds).queryPrecision(wRBTCAddress, docAddress);\n uint256 valueInUSD =\n IPriceFeeds(_priceFeeds).queryReturn(wRBTCAddress, docAddress, _valueInBTC);\n\n /// Need to multiply by query precision (doc's precision) and divide by 1*10^18 (Because the based price in v1 pool is using 18 decimals)\n return valueInUSD.mul(precision).div(1e18);\n }\n\n /**\n * @notice Set the V1 Pool Oracle address.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n */\n function setV1PoolOracleAddress(address _v1PoolOracleAddress) public onlyOwner {\n require(Address.isContract(_v1PoolOracleAddress), \"_v1PoolOracleAddress not a contract\");\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(_v1PoolOracleAddress);\n address liquidityPool = _v1PoolOracle.liquidityPool();\n require(\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(0) == wRBTCAddress ||\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(1) == wRBTCAddress,\n \"one of the two reserves needs to be wrbtc\"\n );\n v1PoolOracleAddress = _v1PoolOracleAddress;\n emit SetV1PoolOracleAddress(v1PoolOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the rBtc address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the rBtc\n *\n * @param _wRBTCAddress The rBTC address\n */\n function setRBTCAddress(address _wRBTCAddress) public onlyOwner {\n require(_wRBTCAddress != address(0), \"wRBTC address cannot be zero address\");\n wRBTCAddress = _wRBTCAddress;\n emit SetWRBTCAddress(wRBTCAddress, msg.sender);\n }\n\n /**\n * @notice Set the DoC address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the DoC\n *\n * @param _docAddress The DoC address\n */\n function setDOCAddress(address _docAddress) public onlyOwner {\n require(_docAddress != address(0), \"DOC address cannot be zero address\");\n docAddress = _docAddress;\n emit SetDOCAddress(_docAddress, msg.sender);\n }\n\n /**\n * @notice Set the base currency address. That's the reserve address which is not WRBTC\n *\n * @param _baseCurrency The base currency address\n */\n function setBaseCurrency(address _baseCurrency) public onlyOwner {\n require(_baseCurrency != address(0), \"Base currency address cannot be zero address\");\n baseCurrency = _baseCurrency;\n emit SetBaseCurrency(_baseCurrency, msg.sender);\n }\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsLocal.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\n\n/**\n * @title Price Feeds Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the logic of setting and getting rates between two tokens.\n * */\ncontract PriceFeedsLocal is PriceFeeds {\n mapping(address => mapping(address => uint256)) public rates;\n\n /// uint256 public slippageMultiplier = 100 ether;\n\n /**\n * @notice Deploy local price feed contract.\n *\n * @param _wrbtcTokenAddress The address of the wrBTC instance.\n * @param _protocolTokenAddress The address of the protocol token instance.\n * */\n constructor(address _wrbtcTokenAddress, address _protocolTokenAddress)\n public\n PriceFeeds(_wrbtcTokenAddress, _protocolTokenAddress, _wrbtcTokenAddress)\n {}\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n if (sourceToken == destToken) {\n rate = 10**18;\n precision = 10**18;\n } else {\n if (sourceToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = protocolTokenEthPrice;\n } else if (destToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = SafeMath.div(10**36, protocolTokenEthPrice);\n } else {\n if (rates[sourceToken][destToken] != 0) {\n rate = rates[sourceToken][destToken];\n } else {\n uint256 sourceToEther =\n rates[sourceToken][address(wrbtcToken)] != 0\n ? rates[sourceToken][address(wrbtcToken)]\n : 10**18;\n uint256 etherToDest =\n rates[address(wrbtcToken)][destToken] != 0\n ? rates[address(wrbtcToken)][destToken]\n : 10**18;\n\n rate = sourceToEther.mul(etherToDest).div(10**18);\n }\n }\n precision = _getDecimalPrecision(sourceToken, destToken);\n }\n }\n\n /**\n * @notice Owner set price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param rate The price ratio source/dest.\n * */\n function setRates(\n address sourceToken,\n address destToken,\n uint256 rate\n ) public onlyOwner {\n if (sourceToken != destToken) {\n rates[sourceToken][destToken] = rate;\n rates[destToken][sourceToken] = SafeMath.div(10**36, rate);\n }\n }\n\n /*function setSlippageMultiplier(\n uint256 _slippageMultiplier)\n public\n onlyOwner\n {\n require (slippageMultiplier != _slippageMultiplier && _slippageMultiplier <= 100 ether);\n slippageMultiplier = _slippageMultiplier;\n }*/\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsMoC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\nimport \"../IRSKOracle.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\ninterface Medianizer {\n function peek() external view returns (bytes32, bool);\n}\n\n/**\n * @title Price Feed of MoC (Money on Chain) contract.\n *\n * This contract contains the logic to set MoC oracles\n * and query last price update.\n * */\ncontract PriceFeedsMoC is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public mocOracleAddress;\n address public rskOracleAddress;\n\n /* Events */\n\n event SetMoCOracleAddress(address indexed mocOracleAddress, address changerAddress);\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new MoC Oracle.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _mocOracleAddress, address _rskOracleAddress) public {\n setMoCOracleAddress(_mocOracleAddress);\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestAnswer() external view returns (uint256) {\n (bytes32 value, bool hasValue) = Medianizer(mocOracleAddress).peek();\n if (hasValue) {\n return uint256(value);\n } else {\n (uint256 price, ) = IRSKOracle(rskOracleAddress).getPricing();\n return price;\n }\n }\n\n /**\n * @notice Set the MoC Oracle address.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n */\n function setMoCOracleAddress(address _mocOracleAddress) public onlyOwner {\n require(Address.isContract(_mocOracleAddress), \"_mocOracleAddress not a contract\");\n mocOracleAddress = _mocOracleAddress;\n emit SetMoCOracleAddress(mocOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/USDTPriceFeed.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./PriceFeeds.sol\";\n\n/**\n * @notice The Price Feed USDT contract.\n *\n * This contract implements USDT query functionality,\n * getting the price and the last timestamp from a\n * trivial formula, always returning 1 and now.\n * */\ncontract USDTPriceFeed is IPriceFeedsExt {\n uint256 private constant USDT_RATE = 1 ether;\n\n /**\n * @notice Get the USDT price.\n *\n * @return Always returns the trivial rate of 1.\n * */\n function latestAnswer() external view returns (uint256) {\n return USDT_RATE;\n }\n\n /**\n * @notice Get the las time the price was updated.\n * @return Always trivial current block's timestamp.\n */\n function latestTimestamp() external view returns (uint256) {\n return now;\n }\n}\n" + }, + "contracts/governance/ApprovalReceiver.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./ErrorDecoder.sol\";\nimport \"../token/IApproveAndCall.sol\";\n\n/**\n * @title Base contract for receiving approval from SOV token.\n */\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\n modifier onlyThisContract() {\n // Accepts calls only from receiveApproval function.\n require(msg.sender == address(this), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external {\n // Accepts calls only from SOV token.\n require(msg.sender == _getToken(), \"unauthorized\");\n require(msg.sender == _token, \"unauthorized\");\n\n // Only allowed methods.\n bool isAllowed = false;\n bytes4[] memory selectors = _getSelectors();\n bytes4 sig = _getSig(_data);\n for (uint256 i = 0; i < selectors.length; i++) {\n if (sig == selectors[i]) {\n isAllowed = true;\n break;\n }\n }\n require(isAllowed, \"method is not allowed\");\n\n // Check sender and amount.\n address sender;\n uint256 amount;\n (, sender, amount) = abi.decode(\n abi.encodePacked(bytes28(0), _data),\n (bytes32, address, uint256)\n );\n require(sender == _sender, \"sender mismatch\");\n require(amount == _amount, \"amount mismatch\");\n\n _call(_data);\n }\n\n /**\n * @notice Returns token address, only this address can be a sender for receiveApproval.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, 0x. When overriden, the token address making the call.\n */\n function _getToken() internal view returns (address) {\n return address(0);\n }\n\n /**\n * @notice Returns list of function selectors allowed to be invoked.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, empty array. When overriden, allowed selectors.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n return new bytes4[](0);\n }\n\n /**\n * @notice Makes call and reverts w/ enhanced error message.\n * @param _data Error message as bytes.\n */\n function _call(bytes memory _data) internal {\n (bool success, bytes memory returnData) = address(this).call(_data);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"receiveApproval: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"receiveApproval: \", string(returnData)));\n }\n }\n }\n\n /**\n * @notice Extracts the called function selector, a hash of the signature.\n * @dev The first four bytes of the call data for a function call specifies\n * the function to be called. It is the first (left, high-order in big-endian)\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\n * Example:\n * msg.data:\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\n * 000450000000000000000000000000000000000000000000000000000000000000001\n * selector (or method ID): 0xcdcd77c0\n * signature: baz(uint32,bool)\n * @param _data The msg.data from the low level call.\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\n */\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\n assembly {\n sig := mload(add(_data, 32))\n }\n }\n}\n" + }, + "contracts/governance/ErrorDecoder.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base contract to properly handle returned data on failed calls\n * @dev On EVM if the return data length of a call is less than 68,\n * then the transaction fails silently without a revert message!\n *\n * As described in the Solidity documentation\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\n * the revert reason is an ABI-encoded string consisting of:\n * 0x08c379a0 // Function selector (method id) for \"Error(string)\" signature\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\n *\n * Another example, debug data from test:\n * 0x08c379a0\n * 0000000000000000000000000000000000000000000000000000000000000020\n * 0000000000000000000000000000000000000000000000000000000000000034\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n *\n * Parsed into:\n * Data offset: 20\n * Length: 34\n * Error message:\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n */\ncontract ErrorDecoder {\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\n\n /**\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\n * @param str1 First string, usually a hardcoded context written by dev.\n * @param str2 Second string, usually the error message from the reverted call.\n * @return The concatenated error string\n */\n function _addErrorMessage(string memory str1, string memory str2)\n internal\n pure\n returns (string memory)\n {\n bytes memory bytesStr1 = bytes(str1);\n bytes memory bytesStr2 = bytes(str2);\n string memory str12 =\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\n bytes memory bytesStr12 = bytes(str12);\n uint256 j = 0;\n for (uint256 i = 0; i < bytesStr1.length; i++) {\n bytesStr12[j++] = bytesStr1[i];\n }\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\n bytesStr12[j++] = bytesStr2[i];\n }\n return string(bytesStr12);\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../Staking/SafeMath96.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../interfaces/IConverterAMM.sol\";\n\n/**\n * @title The FeeSharingCollector contract.\n * @notice This contract withdraws fees to be paid to SOV Stakers from the protocol.\n * Stakers call withdraw() to get their share of the fees.\n *\n * @notice Staking is not only granting voting rights, but also access to fee\n * sharing according to the own voting power in relation to the total. Whenever\n * somebody decides to collect the fees from the protocol, they get transferred\n * to a proxy contract which invests the funds in the lending pool and keeps\n * the pool tokens.\n *\n * The fee sharing proxy will be set as feesController of the protocol contract.\n * This allows the fee sharing proxy to withdraw the fees. The fee sharing\n * proxy holds the pool tokens and keeps track of which user owns how many\n * tokens. In order to know how many tokens a user owns, the fee sharing proxy\n * needs to know the user’s weighted stake in relation to the total weighted\n * stake (aka total voting power).\n *\n * Because both values are subject to change, they may be different on each fee\n * withdrawal. To be able to calculate a user’s share of tokens when he wants\n * to withdraw, we need checkpoints.\n *\n * This contract is intended to be set as the protocol fee collector.\n * Anybody can invoke the withdrawFees function which uses\n * protocol.withdrawFees to obtain available fees from operations on a\n * certain token. These fees are deposited in the corresponding loanPool.\n * Also, the staking contract sends slashed tokens to this contract.\n * When a user calls the withdraw function, the contract transfers the fee sharing\n * rewards in proportion to the user’s weighted stake since the last withdrawal.\n *\n * The protocol initially collects fees in all tokens.\n * Then the FeeSharingCollector wihtdraws fees from the protocol.\n * When the fees are withdrawn all the tokens except SOV will be converted to wRBTC\n * and then transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n * */\ncontract FeeSharingCollector is\n SafeMath96,\n IFeeSharingCollector,\n Ownable,\n FeeSharingCollectorStorage\n{\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n address constant ZERO_ADDRESS = address(0);\n address public constant RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT =\n address(uint160(uint256(keccak256(\"RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\"))));\n\n /* Events */\n\n /// @notice Deprecated event after the unification between wrbtc & rbtc\n // event FeeWithdrawn(address indexed sender, address indexed token, uint256 amount);\n event FeeWithdrawnInRBTC(address indexed sender, uint256 amount);\n\n /// @notice An event emitted when tokens transferred.\n event TokensTransferred(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when checkpoint added.\n event CheckpointAdded(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeWithdrawn(\n address indexed sender,\n address indexed receiver,\n address indexed token,\n uint256 amount\n );\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeProcessedNoWithdraw(\n address indexed sender,\n address indexed token,\n uint256 prevProcessedCheckpoints,\n uint256 newProcessedCheckpoints\n );\n\n /**\n * @notice An event emitted when fee from AMM get withdrawn.\n *\n * @param sender sender who initiate the withdrawn amm fees.\n * @param converter the converter address.\n * @param amount total amount of fee (Already converted to WRBTC).\n */\n event FeeAMMWithdrawn(address indexed sender, address indexed converter, uint256 amount);\n\n /// @notice An event emitted when converter address has been registered to be whitelisted.\n event WhitelistedConverter(address indexed sender, address converter);\n\n /// @notice An event emitted when converter address has been removed from whitelist.\n event UnwhitelistedConverter(address indexed sender, address converter);\n\n event RBTCWithdrawn(address indexed sender, address indexed receiver, uint256 amount);\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWrbtcToken,\n address indexed newWrbtcToken\n );\n\n event SetLoanTokenWrbtc(\n address indexed sender,\n address indexed oldLoanTokenWrbtc,\n address indexed newLoanTokenWrbtc\n );\n\n /* Modifier */\n modifier oneTimeExecution(bytes4 _funcSig) {\n require(\n !isFunctionExecuted[_funcSig],\n \"FeeSharingCollector: function can only be called once\"\n );\n _;\n isFunctionExecuted[_funcSig] = true;\n }\n\n /* Functions */\n\n /// @dev fallback function to support rbtc transfer when unwrap the wrbtc.\n function() external payable {}\n\n /**\n * @dev initialize function for fee sharing collector proxy\n * @param wrbtcToken wrbtc token address\n * @param loanWrbtcToken address of loan token wrbtc (IWrbtc)\n */\n function initialize(address wrbtcToken, address loanWrbtcToken)\n external\n onlyOwner\n oneTimeExecution(this.initialize.selector)\n {\n require(\n wrbtcTokenAddress == address(0) && loanTokenWrbtcAddress == address(0),\n \"wrbtcToken or loanWrbtcToken has been initialized\"\n );\n setWrbtcToken(wrbtcToken);\n setLoanTokenWrbtc(loanWrbtcToken);\n }\n\n /**\n * @notice Set the wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newWrbtcTokenAddress The new address of the wrbtc token.\n * */\n function setWrbtcToken(address newWrbtcTokenAddress) public onlyOwner {\n require(Address.isContract(newWrbtcTokenAddress), \"newWrbtcTokenAddress not a contract\");\n emit SetWrbtcToken(msg.sender, wrbtcTokenAddress, newWrbtcTokenAddress);\n wrbtcTokenAddress = newWrbtcTokenAddress;\n }\n\n /**\n * @notice Set the loan wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newLoanTokenWrbtcAddress The new address of the loan wrbtc token.\n * */\n function setLoanTokenWrbtc(address newLoanTokenWrbtcAddress) public onlyOwner {\n require(\n Address.isContract(newLoanTokenWrbtcAddress),\n \"newLoanTokenWrbtcAddress not a contract\"\n );\n emit SetLoanTokenWrbtc(msg.sender, loanTokenWrbtcAddress, newLoanTokenWrbtcAddress);\n loanTokenWrbtcAddress = newLoanTokenWrbtcAddress;\n }\n\n /**\n * @notice Withdraw fees for the given token:\n * lendingFee + tradingFee + borrowingFee\n * the fees (except SOV) will be converted in wRBTC form, and then will be transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n *\n * @param _tokens array address of the token\n * */\n function withdrawFees(address[] calldata _tokens) external {\n for (uint256 i = 0; i < _tokens.length; i++) {\n require(\n Address.isContract(_tokens[i]),\n \"FeeSharingCollector::withdrawFees: token is not a contract\"\n );\n }\n\n uint256 wrbtcAmountWithdrawn = protocol.withdrawFees(_tokens, address(this));\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap the wrbtc to rbtc, and hold the rbtc.\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFees: wrbtc token amount exceeds 96 bits\"\n );\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, amount96);\n }\n\n // note deprecated event since we unify the wrbtc & rbtc\n // emit FeeWithdrawn(msg.sender, RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, poolTokenAmount);\n\n // note new emitted event\n emit FeeWithdrawnInRBTC(msg.sender, wrbtcAmountWithdrawn);\n }\n\n /**\n * @notice Withdraw amm fees for the given converter addresses:\n * protocolFee from the conversion\n * the fees will be converted in wRBTC form, and then will be transferred to wRBTC loan pool\n *\n * @param _converters array addresses of the converters\n * */\n function withdrawFeesAMM(address[] memory _converters) public {\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n // Validate\n _validateWhitelistedConverter(_converters);\n\n uint96 totalPoolTokenAmount;\n for (uint256 i = 0; i < _converters.length; i++) {\n uint256 wrbtcAmountWithdrawn =\n IConverterAMM(_converters[i]).withdrawFees(address(this));\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap wrbtc to rbtc, and hold the rbtc\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFeesAMM: wrbtc token amount exceeds 96 bits\"\n );\n\n totalPoolTokenAmount = add96(\n totalPoolTokenAmount,\n amount96,\n \"FeeSharingCollector::withdrawFeesAMM: total wrbtc token amount exceeds 96 bits\"\n );\n\n emit FeeAMMWithdrawn(msg.sender, _converters[i], wrbtcAmountWithdrawn);\n }\n }\n\n if (totalPoolTokenAmount > 0) {\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, totalPoolTokenAmount);\n }\n }\n\n /**\n * @notice Transfer tokens to this contract.\n * @dev We just update amount of tokens here and write checkpoint in a separate methods\n * in order to prevent adding checkpoints too often.\n * @param _token Address of the token.\n * @param _amount Amount to be transferred.\n * */\n function transferTokens(address _token, uint96 _amount) public {\n require(_token != ZERO_ADDRESS, \"FeeSharingCollector::transferTokens: invalid address\");\n require(_amount > 0, \"FeeSharingCollector::transferTokens: invalid amount\");\n\n /// @notice Transfer tokens from msg.sender\n bool success = IERC20(_token).transferFrom(address(msg.sender), address(this), _amount);\n require(success, \"Staking::transferTokens: token transfer failed\");\n\n // if _token is wrbtc, need to unwrap it to rbtc\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n if (_token == address(wrbtcToken)) {\n wrbtcToken.withdraw(_amount);\n _token = RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT;\n }\n\n _addCheckpoint(_token, _amount);\n\n emit TokensTransferred(msg.sender, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC / native tokens to this contract.\n * @dev We just write checkpoint here (based on the rbtc value that is sent) in a separate methods\n * in order to prevent adding checkpoints too often.\n * */\n function transferRBTC() external payable {\n uint96 _amount = uint96(msg.value);\n require(_amount > 0, \"FeeSharingCollector::transferRBTC: invalid value\");\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, _amount);\n\n emit TokensTransferred(msg.sender, ZERO_ADDRESS, _amount);\n }\n\n /**\n * @notice Add checkpoint with accumulated amount by function invocation.\n * @param _token Address of the token.\n * */\n function _addCheckpoint(address _token, uint96 _amount) internal {\n if (block.timestamp - lastFeeWithdrawalTime[_token] >= FEE_WITHDRAWAL_INTERVAL) {\n lastFeeWithdrawalTime[_token] = block.timestamp;\n uint96 amount =\n add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: amount exceeds 96 bits\"\n );\n\n /// @notice Reset unprocessed amount of tokens to zero.\n unprocessedAmount[_token] = 0;\n\n /// @notice Write a regular checkpoint.\n _writeTokenCheckpoint(_token, amount);\n } else {\n unprocessedAmount[_token] = add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: unprocessedAmount exceeds 96 bits\"\n );\n }\n }\n\n function _withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n /// @dev Prevents block gas limit hit when processing checkpoints\n require(\n _maxCheckpoints > 0,\n \"FeeSharingCollector::withdraw: _maxCheckpoints should be positive\"\n );\n\n address user = msg.sender;\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n uint256 processedUserCheckpoints = processedCheckpoints[user][_token];\n (uint256 amount, uint256 end) =\n _getAccumulatedFees(user, _token, processedUserCheckpoints, _maxCheckpoints);\n if (amount == 0) {\n if (end > processedUserCheckpoints) {\n emit UserFeeProcessedNoWithdraw(msg.sender, _token, processedUserCheckpoints, end);\n processedCheckpoints[user][_token] = end;\n return (0, end);\n } else {\n // getting here most likely means smth wrong with the state\n revert(\"FeeSharingCollector::withdrawFees: no tokens for withdrawal\");\n }\n }\n\n processedCheckpoints[user][_token] = end;\n if (loanTokenWrbtcAddress == _token) {\n // We will change, so that feeSharingCollector will directly burn then loanToken (IWRBTC) to rbtc and send to the user --- by call burnToBTC function\n ILoanTokenWRBTC(_token).burnToBTC(_receiver, amount, false);\n } else {\n // Previously it directly send the loanToken to the user\n require(\n IERC20(_token).transfer(_receiver, amount),\n \"FeeSharingCollector::withdraw: withdrawal failed\"\n );\n }\n\n emit UserFeeWithdrawn(msg.sender, _receiver, _token, amount);\n\n return (amount, end);\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power. Therefore, staking more\n * SOV and/or staking for longer will increase your share of the fees\n * generated, meaning you will earn more from staking.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed. Must be positive value.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public nonReentrant {\n _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n /// @notice Validates if the checkpoint is payable for the user\n function validFromCheckpointsParam(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n address _user\n ) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n // _fromCheckpoint is checkpoint number, not array index, so should be > 1\n require(tokenData.fromCheckpoint > 1, \"_fromCheckpoint param must be > 1\");\n uint256 fromCheckpointIndex = tokenData.fromCheckpoint - 1;\n require(\n tokenData.fromCheckpoint > processedCheckpoints[_user][tokenData.tokenAddress],\n \"_fromCheckpoint param must be > userProcessedCheckpoints\"\n );\n require(\n tokenData.fromCheckpoint <= totalTokenCheckpoints[tokenData.tokenAddress],\n \"_fromCheckpoint should be <= totalTokenCheckpoints\"\n );\n\n Checkpoint memory prevCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex - 1];\n\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n prevCheckpoint.blockNumber - 1,\n prevCheckpoint.timestamp\n );\n require(\n weightedStake == 0,\n \"User weighted stake should be zero at previous checkpoint\"\n );\n\n Checkpoint memory fromCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex];\n weightedStake = staking.getPriorWeightedStake(\n _user,\n fromCheckpoint.blockNumber - 1,\n fromCheckpoint.timestamp\n );\n\n require(weightedStake > 0, \"User weighted stake should be > 0 at _fromCheckpoint\");\n }\n }\n\n function validRBTCBasedTokens(address[] memory _tokens) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n address _token = _tokens[i];\n if (\n _token != RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT &&\n _token != wrbtcTokenAddress &&\n _token != loanTokenWrbtcAddress\n ) {\n revert(\"only rbtc-based tokens are allowed\");\n }\n }\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender/receiver.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @dev WARNING! This function skips all the checkpoints before '_fromCheckpoint' irreversibly, use with care\n *\n * @param _tokens Array of TokenWithSkippedCheckpointsWithdraw struct, which contains the token address, and fromCheckpoiint\n * fromCheckpoints Skips all the checkpoints before '_fromCheckpoint'\n * should be calculated offchain with getNextPositiveUserCheckpoint function\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n *\n * @return total processed checkpoints\n * */\n function _withdrawStartingFromCheckpoints(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validFromCheckpointsParam(_tokens, msg.sender);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n if (_maxCheckpoints == 0) break;\n uint256 endToken;\n uint256 totalAmount;\n\n uint256 previousProcessedUserCheckpoints =\n processedCheckpoints[msg.sender][tokenData.tokenAddress];\n uint256 startingCheckpoint =\n tokenData.fromCheckpoint > previousProcessedUserCheckpoints\n ? tokenData.fromCheckpoint\n : previousProcessedUserCheckpoints;\n\n if (\n tokenData.tokenAddress == wrbtcTokenAddress ||\n tokenData.tokenAddress == loanTokenWrbtcAddress ||\n tokenData.tokenAddress == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\n ) {\n (totalAmount, endToken) = _withdrawRbtcTokenStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n } else {\n (, endToken) = _withdrawStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n }\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint).add(1);\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n if (rbtcAmountToSend > 0) {\n // send all rbtc withdrawal\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Function to wrap:\n * 1. regular withdrawal for both rbtc & non-rbtc token\n * 2. skipped checkpoints withdrawal for both rbtc & non-rbtc token\n *\n * @param _nonRbtcTokensRegularWithdraw array of non-rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _rbtcTokensRegularWithdraw array of rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _tokensWithSkippedCheckpoints array of rbtc & non-rbtc TokenWithSkippedCheckpointsWithdraw struct, which has skipped checkpoints that will be withdrawn\n *\n */\n function claimAllCollectedFees(\n address[] calldata _nonRbtcTokensRegularWithdraw,\n address[] calldata _rbtcTokensRegularWithdraw,\n TokenWithSkippedCheckpointsWithdraw[] calldata _tokensWithSkippedCheckpoints,\n uint32 _maxCheckpoints,\n address _receiver\n ) external nonReentrant {\n uint256 totalProcessedCheckpoints;\n\n /** Process normal multiple withdrawal for RBTC based tokens */\n if (_rbtcTokensRegularWithdraw.length > 0) {\n totalProcessedCheckpoints = _withdrawRbtcTokens(\n _rbtcTokensRegularWithdraw,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process normal non-rbtc token withdrawal */\n for (uint256 i = 0; i < _nonRbtcTokensRegularWithdraw.length; i++) {\n if (_maxCheckpoints == 0) break;\n uint256 endTokenCheckpoint;\n\n address _nonRbtcTokenAddress = _nonRbtcTokensRegularWithdraw[i];\n\n /** starting checkpoint is the previous processedCheckpoints for token */\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_nonRbtcTokenAddress];\n\n (, endTokenCheckpoint) = _withdraw(_nonRbtcTokenAddress, _maxCheckpoints, _receiver);\n\n uint256 _previousUsedCheckpoint = endTokenCheckpoint.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n _previousUsedCheckpoint.add(1);\n }\n\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process token with skipped checkpoints withdrawal */\n if (_tokensWithSkippedCheckpoints.length > 0) {\n totalProcessedCheckpoints = _withdrawStartingFromCheckpoints(\n _tokensWithSkippedCheckpoints,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n }\n\n function _withdrawStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10 meaning we should set 9 user's processed checkpoints\n // after _withdraw() the user's processedCheckpoints should be 10\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n (totalAmount, endTokenCheckpoint) = _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function _withdrawRbtcToken(address _token, uint32 _maxCheckpoints)\n internal\n returns (uint256 totalAmount, uint256 endTokenCheckpoint)\n {\n address user = msg.sender;\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n (totalAmount, endTokenCheckpoint) = _getRBTCBalance(_token, user, _maxCheckpoints);\n\n if (totalAmount > 0) {\n processedCheckpoints[user][_token] = endTokenCheckpoint;\n if (_token == address(wrbtcToken)) {\n // unwrap the wrbtc\n wrbtcToken.withdraw(totalAmount);\n } else if (_token == loanTokenWrbtcAddress) {\n // pull out the iWRBTC to rbtc to this feeSharingCollector contract\n /** @dev will use the burned result from IWRBTC to RBTC as return total amount */\n totalAmount = ILoanTokenWRBTC(loanTokenWrbtcAddress).burnToBTC(\n address(this),\n totalAmount,\n false\n );\n }\n }\n }\n\n /**\n * @dev withdraw all of the RBTC balance based on particular checkpoints\n *\n * This function will withdraw RBTC balance which is passed as _token param, so it could be either of these:\n * - rbtc balance or\n * - wrbtc balance which will be unwrapped to rbtc or\n * - iwrbtc balance which will be unwrapped to rbtc or\n *\n *\n * @param _tokens array of either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _maxCheckpoints Maximum number of checkpoints to be processed to workaround block gas limit\n * @param _receiver An optional tokens receiver (msg.sender used if 0)\n */\n function _withdrawRbtcTokens(\n address[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validRBTCBasedTokens(_tokens);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n if (_maxCheckpoints == 0) break;\n address _token = _tokens[i];\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_token];\n\n (uint256 totalAmount, uint256 endToken) =\n _withdrawRbtcToken(_tokens[i], _maxCheckpoints);\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n // we only need to add used checkpoint by 1 only if starting checkpoint > 0\n _previousUsedCheckpoint.add(1);\n }\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n // send all rbtc\n if (rbtcAmountToSend > 0) {\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Withdraw either specific RBTC related token balance or all RBTC related tokens balances.\n * RBTC related here means, it could be either rbtc, wrbtc, or iwrbtc, depends on the _token param.\n */\n function _withdrawRbtcTokenStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) private returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10\n // after _withdraw() user's processedCheckpoints should be 10 =>\n // set processed checkpoints = 9, next maping index = 9 (10th checkpoint)\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n return _withdrawRbtcToken(_token, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n external\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n return _getNextPositiveUserCheckpoint(_user, _token, _startFrom, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function _getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n internal\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n if (staking.isVestingContract(_user)) {\n return (0, false, false);\n }\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n\n if (processedUserCheckpoints >= totalCheckpoints || totalCheckpoints == 0) {\n return (totalCheckpoints, false, false);\n }\n\n uint256 startFrom =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n\n uint256 end = startFrom.add(_maxCheckpoints);\n if (end >= totalCheckpoints) {\n end = totalCheckpoints;\n }\n\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startFrom; i < end; i++) {\n Checkpoint storage tokenCheckpoint = tokenCheckpoints[_token][i];\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n tokenCheckpoint.blockNumber - 1,\n tokenCheckpoint.timestamp\n );\n if (weightedStake > 0) {\n // i is the index and we need to return checkpoint num which is i + 1\n return (i + 1, i > processedUserCheckpoints, true);\n }\n }\n return (end, end > processedUserCheckpoints, false);\n }\n\n /**\n * @notice Get the accumulated loan pool fee of the message sender.\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @return The accumulated fee for the message sender.\n * */\n function getAccumulatedFees(address _user, address _token) public view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: 0\n });\n return amount;\n }\n\n /**\n * @notice Get the accumulated fee rewards for the message sender for a checkpoints range\n *\n * @dev This function is required to keep consistent with caching of weighted voting power when claiming fees\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The accumulated fees rewards for the _user in the given checkpoints interval: [_startFrom, _startFrom + maxCheckpoints].\n * */\n function getAccumulatedFeesForCheckpointsRange(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees(_user, _token, _startFrom, _maxCheckpoints);\n return amount;\n }\n\n /**\n * @dev Get all user fees reward per maxCheckpoint starting from latest processed checkpoint\n *\n * @dev e.g: Total user checkpoint for the particualar token = 300,\n * when we call this function with 50 maxCheckpoint, it will return 6 fee values in array form.\n * if there is no more fees, it will return empty array.\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The next checkpoint num which is the starting point to fetch all of the fees, array of calculated fees.\n * */\n function getAllUserFeesPerMaxCheckpoints(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256[] memory fees) {\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 totalTokensCheckpointsIndex = totalCheckpoints > 0 ? totalCheckpoints - 1 : 0;\n\n if (totalTokensCheckpointsIndex < _startFrom) return fees;\n\n uint256 arrSize = totalTokensCheckpointsIndex.sub(_startFrom).div(_maxCheckpoints) + 1;\n\n fees = new uint256[](arrSize);\n\n for (uint256 i = 0; i < fees.length; i++) {\n (uint256 fee, ) =\n _getAccumulatedFees(\n _user,\n _token,\n _startFrom + i * _maxCheckpoints,\n _maxCheckpoints\n );\n fees[i] = fee;\n }\n\n return fees;\n }\n\n /**\n * @notice Gets accumulated fees for a user starting from a given checkpoint\n *\n * @param _user Address of the user's account.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Max checkpoints to process at once to fit into block gas limit\n * @param _startFrom Checkpoint num to start calculations from\n *\n * @return feesAmount - accumulated fees amount\n * @return endCheckpoint - last checkpoint of fees calculation\n * */\n function _getAccumulatedFees(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 feesAmount, uint256 endCheckpoint) {\n if (staking.isVestingContract(_user)) {\n return (0, 0);\n }\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n uint256 startOfRange =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n endCheckpoint = _maxCheckpoints > 0\n ? _getEndOfRange(startOfRange, _token, _maxCheckpoints)\n : totalTokenCheckpoints[_token];\n\n if (startOfRange >= totalTokenCheckpoints[_token]) {\n return (0, endCheckpoint);\n }\n\n uint256 cachedLockDate = 0;\n uint96 cachedWeightedStake = 0;\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startOfRange; i < endCheckpoint; i++) {\n Checkpoint memory checkpoint = tokenCheckpoints[_token][i];\n uint256 lockDate = staking.timestampToLockDate(checkpoint.timestamp);\n uint96 weightedStake;\n if (lockDate == cachedLockDate) {\n weightedStake = cachedWeightedStake;\n } else {\n /// @dev We need to use \"checkpoint.blockNumber - 1\" here to calculate weighted stake\n /// For the same block like we did for total voting power in _writeTokenCheckpoint\n weightedStake = staking.getPriorWeightedStake(\n _user,\n checkpoint.blockNumber - 1,\n checkpoint.timestamp\n );\n cachedWeightedStake = weightedStake;\n cachedLockDate = lockDate;\n }\n uint256 share =\n uint256(checkpoint.numTokens).mul(weightedStake).div(\n uint256(checkpoint.totalWeightedStake)\n );\n feesAmount = feesAmount.add(share);\n }\n return (feesAmount, endCheckpoint);\n }\n\n /**\n * @notice Withdrawal should only be possible for blocks which were already\n * mined. If the fees are withdrawn in the same block as the user withdrawal\n * they are not considered by the withdrawing logic (to avoid inconsistencies).\n *\n * @param _start Start of the range.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of a pool token.\n * @param _maxCheckpoints Checkpoint index incremental.\n * */\n function _getEndOfRange(\n uint256 _start,\n address _token,\n uint32 _maxCheckpoints\n ) internal view returns (uint256) {\n uint256 nextCheckpointIndex = totalTokenCheckpoints[_token];\n if (nextCheckpointIndex == 0) {\n return 0;\n }\n uint256 end;\n\n if (_maxCheckpoints == 0) {\n /// @dev All checkpoints will be processed (only for getter outside of a transaction).\n end = nextCheckpointIndex;\n } else {\n end = safe32(\n _start + _maxCheckpoints,\n \"FeeSharingCollector::withdraw: checkpoint index exceeds 32 bits\"\n );\n if (end > nextCheckpointIndex) {\n end = nextCheckpointIndex;\n }\n }\n\n /// @dev Withdrawal should only be possible for blocks which were already mined.\n uint32 lastBlockNumber = tokenCheckpoints[_token][end - 1].blockNumber;\n if (block.number == lastBlockNumber) {\n end--;\n }\n return end;\n }\n\n /**\n * @notice Write a regular checkpoint w/ the foolowing data:\n * block number, block timestamp, total weighted stake and num of tokens.\n * @param _token The pool token address.\n * @param _numTokens The amount of pool tokens.\n * */\n function _writeTokenCheckpoint(address _token, uint96 _numTokens) internal {\n uint32 blockNumber =\n safe32(\n block.number,\n \"FeeSharingCollector::_writeCheckpoint: block number exceeds 32 bits\"\n );\n uint32 blockTimestamp =\n safe32(\n block.timestamp,\n \"FeeSharingCollector::_writeCheckpoint: block timestamp exceeds 32 bits\"\n );\n uint256 nextCheckpointsIndex = totalTokenCheckpoints[_token];\n\n uint96 totalWeightedStake = _getVoluntaryWeightedStake(blockNumber - 1, block.timestamp);\n require(totalWeightedStake > 0, \"Invalid totalWeightedStake\");\n if (\n nextCheckpointsIndex > 0 &&\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].blockNumber == blockNumber\n ) {\n tokenCheckpoints[_token][nextCheckpointsIndex - 1]\n .totalWeightedStake = totalWeightedStake;\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].numTokens = _numTokens;\n } else {\n tokenCheckpoints[_token][nextCheckpointsIndex] = Checkpoint(\n blockNumber,\n blockTimestamp,\n totalWeightedStake,\n _numTokens\n );\n totalTokenCheckpoints[_token] = nextCheckpointsIndex + 1;\n }\n emit CheckpointAdded(msg.sender, _token, _numTokens);\n }\n\n /**\n * Queries the total weighted stake and the weighted stake of vesting contracts and returns the difference\n * @param blockNumber the blocknumber\n * @param timestamp the timestamp\n */\n function _getVoluntaryWeightedStake(uint32 blockNumber, uint256 timestamp)\n internal\n view\n returns (uint96 totalWeightedStake)\n {\n uint96 vestingWeightedStake = staking.getPriorVestingWeightedStake(blockNumber, timestamp);\n totalWeightedStake = staking.getPriorTotalVotingPower(blockNumber, timestamp);\n totalWeightedStake = sub96(\n totalWeightedStake,\n vestingWeightedStake,\n \"FeeSharingCollector::_getTotalVoluntaryWeightedStake: vested stake exceeds total stake\"\n );\n }\n\n /**\n * @dev Whitelisting converter address.\n *\n * @param converterAddress converter address to be whitelisted.\n */\n function addWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n require(Address.isContract(converterAddress), \"Non contract address given\");\n whitelistedConverterList.add(converterAddress);\n emit WhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @dev Removing converter address from whitelist.\n *\n * @param converterAddress converter address to be removed from whitelist.\n */\n function removeWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n whitelistedConverterList.remove(converterAddress);\n emit UnwhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @notice Getter to query all of the whitelisted converter.\n * @return All of the whitelisted converter list.\n */\n function getWhitelistedConverterList() external view returns (address[] memory converterList) {\n converterList = whitelistedConverterList.enumerate();\n }\n\n /**\n * @dev validate array of given address whether is whitelisted or not.\n * @dev if one of them is not whitelisted, then revert.\n *\n * @param converterAddresses array of converter addresses.\n */\n function _validateWhitelistedConverter(address[] memory converterAddresses) private view {\n for (uint256 i = 0; i < converterAddresses.length; i++) {\n require(whitelistedConverterList.contains(converterAddresses[i]), \"Invalid Converter\");\n }\n }\n\n function withdrawWRBTC(address receiver, uint256 wrbtcAmount) external onlyOwner {\n IERC20 wrbtcToken = IERC20(wrbtcTokenAddress);\n\n uint256 balance = wrbtcToken.balanceOf(address(this));\n require(wrbtcAmount <= balance, \"Insufficient balance\");\n\n wrbtcToken.safeTransfer(receiver, wrbtcAmount);\n }\n\n /**\n * @dev This function is dedicated to recover the wrong fee allocation for the 4 year vesting contracts.\n * This function can only be called once\n * The affected tokens to be withdrawn\n * 1. RBTC\n * 2. ZUSD\n * 3. SOV\n * The amount for all of the tokens above is hardcoded\n * The withdrawn tokens will be sent to the owner.\n */\n function recoverIncorrectAllocatedFees()\n external\n oneTimeExecution(this.recoverIncorrectAllocatedFees.selector)\n onlyOwner\n {\n uint256 rbtcAmount = 878778886164898400;\n uint256 zusdAmount = 16658600400155126000000;\n uint256 sovAmount = 6275898259771202000000;\n\n address zusdToken = 0xdB107FA69E33f05180a4C2cE9c2E7CB481645C2d;\n address sovToken = 0xEFc78fc7d48b64958315949279Ba181c2114ABBd;\n\n // Withdraw rbtc\n (bool success, ) = owner().call.value(rbtcAmount)(\"\");\n require(\n success,\n \"FeeSharingCollector::recoverIncorrectAllocatedFees: Withdrawal rbtc failed\"\n );\n\n // Withdraw ZUSD\n IERC20(zusdToken).safeTransfer(owner(), zusdAmount);\n\n // Withdraw SOV\n IERC20(sovToken).safeTransfer(owner(), sovAmount);\n }\n\n /**\n * @dev view function that calculate the total RBTC that includes:\n * - RBTC\n * - WRBTC\n * - iWRBTC * iWRBTC.tokenPrice()\n * @param _user address of the user.\n * @return rbtc balance of the given user's address.\n */\n function getAccumulatedRBTCFeeBalances(address _user) external view returns (uint256) {\n (uint256 _rbtcAmount, uint256 _wrbtcAmount, uint256 _iWrbtcAmount, , , ) =\n _getRBTCBalances(_user, 0);\n uint256 iWRBTCAmountInRBTC =\n _iWrbtcAmount.mul(ILoanTokenWRBTC(loanTokenWrbtcAddress).tokenPrice()).div(1e18);\n return _rbtcAmount.add(_wrbtcAmount).add(iWRBTCAmountInRBTC);\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _rbtcAmount rbtc amount\n * @return _wrbtcAmount wrbtc amount\n * @return _iWrbtcAmount iWrbtc (wrbtc lending pool token) amount * token price\n * @return _endRBTC end time of accumulated fee calculation for rbtc\n * @return _endWRBTC end time of accumulated fee calculation for wrbtc\n * @return _endIWRBTC end time of accumulated fee calculation for iwrbtc\n */\n function _getRBTCBalances(address _user, uint32 _maxCheckpoints)\n private\n view\n returns (\n uint256 _rbtcAmount,\n uint256 _wrbtcAmount,\n uint256 _iWrbtcAmount,\n uint256 _endRBTC,\n uint256 _endWRBTC,\n uint256 _endIWRBTC\n )\n {\n (_rbtcAmount, _endRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n\n (_wrbtcAmount, _endWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: wrbtcTokenAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n (_iWrbtcAmount, _endIWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: loanTokenWrbtcAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _token either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _tokenAmount token (rbtc, or wrbtc, or iwrbtc) amount\n * @return _endToken end time of accumulated fee calculation for token (rbtc, or wrbtc, or iwrbtc )\n */\n function _getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 _tokenAmount, uint256 _endToken) {\n if (\n _token == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT ||\n _token == wrbtcTokenAddress ||\n _token == loanTokenWrbtcAddress\n ) {\n (_tokenAmount, _endToken) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n } else {\n revert(\"FeeSharingCollector::_getRBTCBalance: only rbtc-based tokens are allowed\");\n }\n }\n\n // @todo update dependency `numTokenCheckpoints` -> `totalTokenCheckpoints` and deprecate numTokenCheckpoints function\n /**\n * @dev This getter function `numTokenCheckpoints` is added for backwards compatibility\n * broken when renamed `numTokenCheckpoints` storage variable to `totalTokenCheckpoints`.\n *\n * @param _token token address to get checkpoints for\n *\n * @return Total token checkpoints\n */\n function numTokenCheckpoints(address _token) external view returns (uint256) {\n return totalTokenCheckpoints[_token];\n }\n}\n\n/* Interfaces */\ninterface ILoanToken {\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n}\n\ninterface ILoanTokenWRBTC {\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function tokenPrice() external view returns (uint256 price);\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title FeeSharingCollectorProxy contract.\n * @dev FeeSharingCollectorProxy contract should be upgradable, use UpgradableProxy.\n * FeeSharingCollectorStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract FeeSharingCollectorProxy is FeeSharingCollectorStorage, UpgradableProxy {\n /**\n * @notice Construct a new feeSharingCollectorProxy contract.\n * @param _protocol The address of the sovryn protocol.\n * @param _staking The address of the staking\n */\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorStorage.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../mixins/EnumerableAddressSet.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\n\n/**\n * @title FeeSharingCollectorStorage contact\n * @notice Just the storage part of FeeSharingCollector contract, and FeeSharingCollectorProxy. No functions,\n * only constant, variables and required structures (mappings)\n * */\ncontract FeeSharingCollectorStorage is Ownable {\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet;\n uint256 constant FEE_WITHDRAWAL_INTERVAL = 172800;\n\n IProtocol public protocol;\n IStaking public staking;\n\n /// @notice Checkpoints by index per pool token address\n mapping(address => mapping(uint256 => Checkpoint)) public tokenCheckpoints;\n\n /// @notice The number of checkpoints for each token address.\n mapping(address => uint256) public totalTokenCheckpoints;\n\n /// @notice\n /// user => token => processed checkpoints\n mapping(address => mapping(address => uint256)) public processedCheckpoints;\n\n /// @notice Last time fees were withdrawn per pool token address:\n /// token => time\n mapping(address => uint256) public lastFeeWithdrawalTime;\n\n /// @notice Amount of tokens that were transferred, but not saved in checkpoints.\n /// token => amount\n mapping(address => uint96) public unprocessedAmount;\n\n struct Checkpoint {\n uint32 blockNumber;\n uint32 timestamp;\n uint96 totalWeightedStake;\n uint96 numTokens;\n }\n\n struct TokenWithSkippedCheckpointsWithdraw {\n address tokenAddress;\n uint256 fromCheckpoint;\n }\n\n /**\n * @dev Add extra modifier (Reentrancy) below.\n * Because we cannot add any additional storage slot before this storage contract after initial deployment\n */\n\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Additional storage for converter whitelist mechanism.\n * @dev Initialization here does not works. We need to create a separate setter & getter.\n * @dev Just set the visibility to internal should be fine.\n */\n EnumerableAddressSet.AddressSet internal whitelistedConverterList;\n\n mapping(bytes4 => bool) public isFunctionExecuted;\n\n /**\n * @dev Wrbtc token address\n */\n address public wrbtcTokenAddress;\n\n /**\n * @dev iWrbtc loan token address\n */\n address public loanTokenWrbtcAddress;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n\n/* Interfaces */\n\ninterface IProtocol {\n /**\n *\n * @param tokens The array address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function underlyingToLoanPool(address token) external view returns (address);\n\n function wrbtcToken() external view returns (IWrbtcERC20);\n\n function getSovTokenAddress() external view returns (address);\n}\n" + }, + "contracts/governance/GovernorAlpha.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./Staking/SafeMath96.sol\";\nimport \"./Timelock.sol\";\nimport \"./Staking/interfaces/IStaking.sol\";\nimport \"../rsk/RSKAddrValidator.sol\";\n\n/**\n * @title Governance Contract.\n * @notice This is an adapted clone of compound’s governance model. In general,\n * the process is the same: Token holders can make (executable) proposals if\n * they possess enough voting power, vote on proposals during a predefined\n * voting period and in the end evaluate the outcome. If successful, the\n * proposal will be scheduled on the timelock contract. Only after sufficient\n * time passed, it can be executed. A minimum voting power is required for\n * making a proposal as well as a minimum quorum.\n *\n * Voting power in the Bitocracy:\n * Stakers will receive voting power in the Bitocracy in return for their\n * staking commitment. This voting power is weighted by how much SOV is staked\n * and for how long the staking period is - staking more SOV over longer staking\n * periods results in higher voting power. With this voting power, users can\n * vote for or against any SIP in bitocracy.sovryn.app.\n * */\ncontract GovernorAlpha is SafeMath96 {\n /* Storage */\n\n /// @notice The name of this contract.\n string public constant NAME = \"Sovryn Governor Alpha\";\n\n /// @notice The maximum number of actions that can be included in a proposal.\n function proposalMaxOperations() public pure returns (uint256) {\n return 10;\n } // 10 actions\n\n /// @notice The delay before voting on a proposal may take place, once proposed.\n function votingDelay() public pure returns (uint256) {\n return 1;\n } // 1 block\n\n /// @notice The duration of voting on a proposal, in blocks.\n function votingPeriod() public pure returns (uint256) {\n return 2880;\n } // ~1 day in blocks (assuming 30s blocks)\n\n /// @notice The address of the Sovryn Protocol Timelock.\n ITimelock public timelock;\n\n /// @notice The address of the Sovryn staking contract.\n IStaking public staking;\n\n /// @notice The address of the Governor Guardian.\n address public guardian;\n\n /// @notice The total number of proposals.\n uint256 public proposalCount;\n\n /// @notice Percentage of current total voting power require to vote.\n uint96 public quorumPercentageVotes;\n\n // @notice Majority percentage.\n uint96 public majorityPercentageVotes;\n\n struct Proposal {\n /// @notice Unique id for looking up a proposal.\n uint256 id;\n /// @notice The block at which voting begins: holders must delegate their votes prior to this block.\n uint32 startBlock;\n /// @notice The block at which voting ends: votes must be cast prior to this block.\n uint32 endBlock;\n /// @notice Current number of votes in favor of this proposal.\n uint96 forVotes;\n /// @notice Current number of votes in opposition to this proposal.\n uint96 againstVotes;\n ///@notice the quorum required for this proposal.\n uint96 quorum;\n ///@notice the majority percentage required for this proposal.\n uint96 majorityPercentage;\n /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds.\n uint64 eta;\n /// @notice the start time is required for the staking contract.\n uint64 startTime;\n /// @notice Flag marking whether the proposal has been canceled.\n bool canceled;\n /// @notice Flag marking whether the proposal has been executed.\n bool executed;\n /// @notice Creator of the proposal.\n address proposer;\n /// @notice the ordered list of target addresses for calls to be made.\n address[] targets;\n /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made.\n uint256[] values;\n /// @notice The ordered list of function signatures to be called.\n string[] signatures;\n /// @notice The ordered list of calldata to be passed to each call.\n bytes[] calldatas;\n /// @notice Receipts of ballots for the entire set of voters.\n mapping(address => Receipt) receipts;\n }\n\n /// @notice Ballot receipt record for a voter\n struct Receipt {\n /// @notice Whether or not a vote has been cast.\n bool hasVoted;\n /// @notice Whether or not the voter supports the proposal.\n bool support;\n /// @notice The number of votes the voter had, which were cast.\n uint96 votes;\n }\n\n /// @notice Possible states that a proposal may be in.\n enum ProposalState {\n Pending,\n Active,\n Canceled,\n Defeated,\n Succeeded,\n Queued,\n Expired,\n Executed\n }\n\n /// @notice The official record of all proposals ever proposed.\n mapping(uint256 => Proposal) public proposals;\n\n /// @notice The latest proposal for each proposer.\n mapping(address => uint256) public latestProposalIds;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the ballot struct used by the contract.\n bytes32 public constant BALLOT_TYPEHASH = keccak256(\"Ballot(uint256 proposalId,bool support)\");\n\n /* Events */\n\n /// @notice An event emitted when a new proposal is created.\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint256 startBlock,\n uint256 endBlock,\n string description\n );\n\n /// @notice An event emitted when a vote has been cast on a proposal.\n event VoteCast(address voter, uint256 proposalId, bool support, uint256 votes);\n\n /// @notice An event emitted when a proposal has been canceled.\n event ProposalCanceled(uint256 id);\n\n /// @notice An event emitted when a proposal has been queued in the Timelock.\n event ProposalQueued(uint256 id, uint256 eta);\n\n /// @notice An event emitted when a proposal has been executed in the Timelock.\n event ProposalExecuted(uint256 id);\n\n /* Functions */\n\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 _quorumPercentageVotes,\n uint96 _majorityPercentageVotes\n ) public {\n timelock = ITimelock(timelock_);\n staking = IStaking(staking_);\n guardian = guardian_;\n quorumPercentageVotes = _quorumPercentageVotes;\n majorityPercentageVotes = _majorityPercentageVotes;\n }\n\n /// @notice The number of votes required in order for a voter to become a proposer.\n function proposalThreshold() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(\n block.number - 1,\n \"GovernorAlpha::proposalThreshold: block number overflow\"\n ),\n block.timestamp\n );\n // 1% of current total voting power.\n return totalVotingPower / 100;\n }\n\n /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.\n function quorumVotes() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(block.number - 1, \"GovernorAlpha::quorumVotes: block number overflow\"),\n block.timestamp\n );\n // 4% of current total voting power.\n return\n mul96(\n quorumPercentageVotes,\n totalVotingPower,\n \"GovernorAlpha::quorumVotes:multiplication overflow\"\n ) / 100;\n }\n\n /**\n * @notice Create a new proposal.\n * @param targets Array of contract addresses to perform proposal execution.\n * @param values Array of rBTC amounts to send on proposal execution.\n * @param signatures Array of function signatures to call on proposal execution.\n * @param calldatas Array of payloads for the calls on proposal execution.\n * @param description Text describing the purpose of the proposal.\n * */\n function propose(\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // note: passing this block's timestamp, but the number of the previous block.\n // todo: think if it would be better to pass block.timestamp - 30 (average block time)\n // (probably not because proposal starts in 1 block from now).\n uint96 threshold = proposalThreshold();\n require(\n staking.getPriorVotes(msg.sender, sub256(block.number, 1), block.timestamp) >\n threshold,\n \"GovernorAlpha::propose: proposer votes below proposal threshold\"\n );\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"GovernorAlpha::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"GovernorAlpha::propose: must provide actions\");\n require(\n targets.length <= proposalMaxOperations(),\n \"GovernorAlpha::propose: too many actions\"\n );\n\n uint256 latestProposalId = latestProposalIds[msg.sender];\n if (latestProposalId != 0) {\n ProposalState proposersLatestProposalState = state(latestProposalId);\n require(\n proposersLatestProposalState != ProposalState.Active,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already active proposal\"\n );\n require(\n proposersLatestProposalState != ProposalState.Pending,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal\"\n );\n }\n\n uint256 startBlock = add256(block.number, votingDelay());\n uint256 endBlock = add256(startBlock, votingPeriod());\n\n proposalCount++;\n\n /// @dev quorum: proposalThreshold is 1% of total votes, we can save gas using this pre calculated value.\n /// @dev startTime: Required by the staking contract. not used by the governance contract itself.\n Proposal memory newProposal =\n Proposal({\n id: proposalCount,\n startBlock: safe32(\n startBlock,\n \"GovernorAlpha::propose: start block number overflow\"\n ),\n endBlock: safe32(endBlock, \"GovernorAlpha::propose: end block number overflow\"),\n forVotes: 0,\n againstVotes: 0,\n quorum: mul96(\n quorumPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on quorum computation\"\n ),\n majorityPercentage: mul96(\n majorityPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on majorityPercentage computation\"\n ),\n eta: 0,\n startTime: safe64(block.timestamp, \"GovernorAlpha::propose: startTime overflow\"),\n canceled: false,\n executed: false,\n proposer: msg.sender,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas\n });\n\n proposals[newProposal.id] = newProposal;\n latestProposalIds[newProposal.proposer] = newProposal.id;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n values,\n signatures,\n calldatas,\n startBlock,\n endBlock,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Enqueue a proposal and everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function queue(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Succeeded,\n \"GovernorAlpha::queue: proposal can only be queued if it is succeeded\"\n );\n Proposal storage proposal = proposals[proposalId];\n uint256 eta = add256(block.timestamp, timelock.delay());\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n proposal.eta = safe64(eta, \"GovernorAlpha::queue: ETA overflow\");\n emit ProposalQueued(proposalId, eta);\n }\n\n /**\n * @notice Tries to enqueue a proposal, verifying it has not been previously queued.\n * @param target Contract addresses to perform proposal execution.\n * @param value rBTC amount to send on proposal execution.\n * @param signature Function signature to call on proposal execution.\n * @param data Payload for the call on proposal execution.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function _queueOrRevert(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !timelock.queuedTransactions(\n keccak256(abi.encode(target, value, signature, data, eta))\n ),\n \"GovernorAlpha::_queueOrRevert: proposal action already queued at eta\"\n );\n timelock.queueTransaction(target, value, signature, data, eta);\n }\n\n /**\n * @notice Execute a proposal by looping and performing everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function execute(uint256 proposalId) public payable {\n require(\n state(proposalId) == ProposalState.Queued,\n \"GovernorAlpha::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.executeTransaction.value(proposal.values[i])(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal by looping and cancelling everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function cancel(uint256 proposalId) public {\n ProposalState state = state(proposalId);\n require(\n state != ProposalState.Executed,\n \"GovernorAlpha::cancel: cannot cancel executed proposal\"\n );\n\n Proposal storage proposal = proposals[proposalId];\n /// @notice Cancel only if sent by the guardian.\n require(msg.sender == guardian, \"GovernorAlpha::cancel: sender isn't a guardian\");\n\n proposal.canceled = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalCanceled(proposalId);\n }\n\n /**\n * @notice Get a proposal list of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return Arrays of the 4 call parameters: targets, values, signatures, calldatas.\n * */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.values, p.signatures, p.calldatas);\n }\n\n /**\n * @notice Get a proposal receipt.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param voter A governance stakeholder with voting power.\n * @return The voter receipt of the proposal.\n * */\n function getReceipt(uint256 proposalId, address voter) public view returns (Receipt memory) {\n return proposals[proposalId].receipts[voter];\n }\n\n /**\n * @notice Casts a vote by sender.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function castVote(uint256 proposalId, bool support) public {\n return _castVote(msg.sender, proposalId, support);\n }\n\n /**\n * @notice Voting with EIP-712 Signatures.\n *\n * Voting power can be delegated to any address, and then can be used to\n * vote on proposals. A key benefit to users of by-signature functionality\n * is that they can create a signed vote transaction for free, and have a\n * trusted third-party spend rBTC(or ETH) on gas fees and write it to the\n * blockchain for them.\n *\n * The third party in this scenario, submitting the SOV-holder’s signed\n * transaction holds a voting power that is for only a single proposal.\n * The signatory still holds the power to vote on their own behalf in\n * the proposal if the third party has not yet published the signed\n * transaction that was given to them.\n *\n * @dev The signature needs to be broken up into 3 parameters, known as\n * v, r and s:\n * const r = '0x' + sig.substring(2).substring(0, 64);\n * const s = '0x' + sig.substring(2).substring(64, 128);\n * const v = '0x' + sig.substring(2).substring(128, 130);\n *\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * @param v The recovery byte of the signature.\n * @param r Half of the ECDSA signature pair.\n * @param s Half of the ECDSA signature pair.\n * */\n function castVoteBySig(\n uint256 proposalId,\n bool support,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public {\n /**\n * @dev The DOMAIN_SEPARATOR is a hash that uniquely identifies a\n * smart contract. It is built from a string denoting it as an\n * EIP712 Domain, the name of the token contract, the version,\n * the chainId in case it changes, and the address that the\n * contract is deployed at.\n * */\n bytes32 domainSeparator =\n keccak256(\n abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this))\n );\n\n /// @dev GovernorAlpha uses BALLOT_TYPEHASH, while Staking uses DELEGATION_TYPEHASH\n bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support));\n\n bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n address signatory = ecrecover(digest, v, r, s);\n\n /// @dev Verify address is not null and PK is not null either.\n require(\n RSKAddrValidator.checkPKNotZero(signatory),\n \"GovernorAlpha::castVoteBySig: invalid signature\"\n );\n return _castVote(signatory, proposalId, support);\n }\n\n /**\n * @notice Cast a vote, adding it to the total counting.\n * @param voter A governance stakeholder with voting power that is casting the vote.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function _castVote(\n address voter,\n uint256 proposalId,\n bool support\n ) internal {\n require(\n state(proposalId) == ProposalState.Active,\n \"GovernorAlpha::_castVote: voting is closed\"\n );\n Proposal storage proposal = proposals[proposalId];\n Receipt storage receipt = proposal.receipts[voter];\n require(receipt.hasVoted == false, \"GovernorAlpha::_castVote: voter already voted\");\n uint96 votes = staking.getPriorVotes(voter, proposal.startBlock, proposal.startTime);\n\n if (support) {\n proposal.forVotes = add96(\n proposal.forVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n } else {\n proposal.againstVotes = add96(\n proposal.againstVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n }\n\n receipt.hasVoted = true;\n receipt.support = support;\n receipt.votes = votes;\n\n emit VoteCast(voter, proposalId, support, votes);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __acceptAdmin() public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__acceptAdmin: sender must be gov guardian\"\n );\n timelock.acceptAdmin();\n }\n\n /// @notice Sets guardian address to zero.\n function __abdicate() public {\n require(msg.sender == guardian, \"GovernorAlpha::__abdicate: sender must be gov guardian\");\n guardian = address(0);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.queueTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.executeTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /**\n * @notice Get a proposal state.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return The state of the proposal: Canceled, Pending, Active, Defeated,\n * Succeeded, Executed, Expired.\n * */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"GovernorAlpha::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n\n if (proposal.canceled) {\n return ProposalState.Canceled;\n }\n\n if (block.number <= proposal.startBlock) {\n return ProposalState.Pending;\n }\n\n if (block.number <= proposal.endBlock) {\n return ProposalState.Active;\n }\n\n uint96 totalVotes =\n add96(\n proposal.forVotes,\n proposal.againstVotes,\n \"GovernorAlpha:: state: forVotes + againstVotes > uint96\"\n );\n uint96 totalVotesMajorityPercentage =\n div96(totalVotes, 100, \"GovernorAlpha:: state: division error\");\n totalVotesMajorityPercentage = mul96(\n totalVotesMajorityPercentage,\n majorityPercentageVotes,\n \"GovernorAlpha:: state: totalVotes * majorityPercentage > uint96\"\n );\n if (proposal.forVotes <= totalVotesMajorityPercentage || totalVotes < proposal.quorum) {\n return ProposalState.Defeated;\n }\n\n if (proposal.eta == 0) {\n return ProposalState.Succeeded;\n }\n\n if (proposal.executed) {\n return ProposalState.Executed;\n }\n\n if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) {\n return ProposalState.Expired;\n }\n\n return ProposalState.Queued;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function add256(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"addition overflow\");\n return c;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function sub256(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b <= a, \"subtraction underflow\");\n return a - b;\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n}\n\n/* Interfaces */\n\ninterface TimelockInterface {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\ninterface StakingInterface {\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n}\n" + }, + "contracts/governance/GovernorVault.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title Governance Vault.\n * @notice This contract stores tokens and rBTC only transfereble by owner,\n * i.e. Sovryn governance.\n * */\ncontract GovernorVault is Ownable {\n /* Events */\n\n event Deposited(address indexed sender, uint256 amount);\n event TokensTransferred(address indexed receiver, address indexed token, uint256 amount);\n event RbtcTransferred(address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer tokens.\n * @param _receiver The receiver of tokens.\n * @param _token The address of token contract.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _receiver,\n address _token,\n uint256 _amount\n ) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n require(_token != address(0), \"Invalid token address\");\n\n require(IERC20(_token).transfer(_receiver, _amount), \"Transfer failed\");\n emit TokensTransferred(_receiver, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC.\n * @param _receiver The receiver of RBTC.\n * @param _amount The amount to be transferred.\n * */\n function transferRbtc(address payable _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n\n address(_receiver).transfer(_amount);\n emit RbtcTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {\n if (msg.value > 0) {\n emit Deposited(msg.sender, msg.value);\n }\n }\n}\n" + }, + "contracts/governance/IFeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * */\ninterface IFeeSharingCollector {\n function withdrawFees(address[] calldata _token) external;\n\n function transferTokens(address _token, uint96 _amount) external;\n\n function withdraw(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external;\n}\n" + }, + "contracts/governance/Staking/interfaces/IStaking.sol": { + "content": "pragma solidity ^0.5.17;\n\npragma experimental ABIEncoderV2;\n\n/**\n * @title Interface for Staking modules governance/Staking/modules\n */\n\ninterface IStaking {\n /*************************** StakingAdminModule ***************************/\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external;\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external;\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external;\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external;\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) external;\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external;\n\n /**\n * @notice Allows the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external;\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external;\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external;\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\n\n /*************************** StakingGovernanceModule ***************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\n * be internal instead of a public function.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external;\n\n /*************************** StakingStakeModule ***************************/\n\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance);\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes);\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\n\n /*************************** StakingStorageModule ***************************/\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n /// @return uint256(MAX_VOTING_WEIGHT);\n function getStorageMaxVotingWeight() external pure returns (uint256);\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n /// @return uint256(WEIGHT_FACTOR);\n function getStorageWeightFactor() external pure returns (uint256);\n\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\n function getStorageDefaultWeightScaling() external pure returns (uint256);\n\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\n\n /// @notice The EIP-712 typehash for the contract's domain.\n /// @return uint256(DOMAIN_TYPEHASH);\n function getStorageDomainTypehash() external pure returns (uint256);\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n /// @return uint256(DELEGATION_TYPEHASH);\n function getStorageDelegationTypehash() external pure returns (uint256);\n\n /// @return name;\n function getStorageName() external view returns (string memory);\n\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n function kickoffTS() external view returns (uint256);\n\n /// @notice The token to be staked\n function SOVToken() external view returns (address);\n\n /// @notice Stakers delegated voting power\n /// @param staker - the delegating address\n /// @param until - delegated voting\n /// @return _delegate - voting power delegated to address\n function delegates(address staker, uint256 until) external view returns (address _delegate);\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately\n /// see function unlockAllTokens() for details\n function allUnlocked() external view returns (bool);\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\n function newStakingContract() external view returns (address);\n\n /// CHECKPOINTS\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\n function totalStakingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n function numTotalStakingCheckpoints(uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n function delegateStakingCheckpoints(\n address delagatee,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n function userStakingCheckpoints(\n address user,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number\n function numUserStakingCheckpoints(address user, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n function nonces(address user) external view returns (uint256 nonce);\n\n /// SLASHING ///\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n function feeSharing() external view returns (address);\n\n /// @notice used for weight scaling when unstaking with slashing.\n /// @return uint96 DEFAULT_WEIGHT_SCALING\n function weightScaling() external view returns (uint96);\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n function admins(address isAdmin) external view returns (bool);\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n function vestingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\n\n ///@notice vesting registry contract PROXY address\n function vestingRegistryLogic() external view returns (address);\n\n /// @dev user => flag whether user has pauser role.\n function pausers(address isPauser) external view returns (bool);\n\n /// @dev Staking contract is paused\n function paused() external view returns (bool);\n\n /// @dev Staking contract is frozen\n function frozen() external view returns (bool);\n\n /*************************** StakingVestingModule ***************************/\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool);\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external;\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external;\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes);\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n /*************************** StakingWithdrawModule ***************************/\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * */\n function governanceWithdrawVesting(address vesting, address receiver) external;\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96);\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external;\n\n /*************************** WeightedStakingModule ***************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The date/timestamp of the unstaking time.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * TODO: WeightedStaking::weightedStakeByDate should probably better\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Returns public constant MAX_DURATION\n * preserved for backwards compatibility\n * Use getStorageMaxDurationToStakeTokens()\n * @return uint96 MAX_DURATION for staking\n **/\n function MAX_DURATION() external view returns (uint256);\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() external view returns (address);\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() external view returns (bool);\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) external;\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external;\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() external view returns (uint256);\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param maxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\n}\n" + }, + "contracts/governance/Staking/modules/shared/CheckpointsShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\n\n/**\n * @title Checkpoints contract.\n * @notice Increases and decreases storage values for users, delegatees and\n * total daily stake.\n * */\ncontract CheckpointsShared is StakingStorageShared, SafeMath96 {\n /// @notice An event emitted when an account changes its delegate.\n event DelegateChanged(\n address indexed delegator,\n uint256 lockedUntil,\n address indexed fromDelegate,\n address indexed toDelegate\n );\n\n /// @notice An event emitted when a delegate account's stake balance changes.\n event DelegateStakeChanged(\n address indexed delegate,\n uint256 lockedUntil,\n uint256 previousBalance,\n uint256 newBalance\n );\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n event ContractCodeHashAdded(bytes32 hash);\n\n event ContractCodeHashRemoved(bytes32 hash);\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n event TeamVestingCancelled(address indexed caller, address receiver);\n\n event TeamVestingPartiallyCancelled(\n address indexed caller,\n address receiver,\n uint256 lastProcessedDate\n );\n\n constructor() internal {\n // abstract\n }\n\n /**\n * @notice Increases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = add96(vested, value, \"CP01\"); // vested overflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Decreases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = sub96(vested, value, \"CP02\"); // vested underflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Writes on storage the user vested amount.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newVest The new vest balance.\n * */\n function _writeVestingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newVest\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP03\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n vestingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n vestingCheckpoints[lockedTS][nCheckpoints - 1].stake = newVest;\n } else {\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newVest);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP04\"); // staked overflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP05\"); // staked underflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the user stake.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeUserCheckpoint(\n address account,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP06\"); // block number > 32 bits\n\n if (\n nCheckpoints > 0 &&\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n userStakingCheckpoints[account][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numUserStakingCheckpoints[account][lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP07\"); // block number > 32 bits\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = 0;\n // @dev We need to check delegate checkpoint value here,\n //\t\tbecause we had an issue in `stake` function:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n // @dev It can be greater than 0, but inconsistent after 3 transactions\n if (staked > value) {\n newStake = sub96(staked, value, \"CP08\"); // staked underflow\n }\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the delegate stake.\n * @param delegatee The delegate address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeDelegateCheckpoint(\n address delegatee,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP09\"); // block numb > 32 bits\n uint96 oldStake = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n\n if (\n nCheckpoints > 0 &&\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].fromBlock ==\n blockNumber\n ) {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numDelegateStakingCheckpoints[delegatee][lockedTS] = nCheckpoints + 1;\n }\n emit DelegateStakeChanged(delegatee, lockedTS, oldStake, newStake);\n }\n\n /**\n * @notice Increases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP10\"); // staked overflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP11\"); // staked underflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the total stake.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeStakingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP12\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n totalStakingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newStake);\n numTotalStakingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Get the current balance of an account locked until a certain date.\n * @param account The user address.\n * @param lockDate The lock date.\n * @return The stake amount.\n * */\n function _currentBalance(address account, uint256 lockDate) internal view returns (uint96) {\n uint32 _numUnserStakingCheckpoints = numUserStakingCheckpoints[account][lockDate] - 1;\n return userStakingCheckpoints[account][lockDate][_numUnserStakingCheckpoints].stake;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\nimport \"../../../../openzeppelin/SafeMath.sol\";\nimport \"../../../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking modules shared functionality\n */\ncontract StakingShared is StakingStorageShared, SafeMath96 {\n using SafeMath for uint256;\n\n uint256 internal constant FOUR_WEEKS = 4 weeks;\n\n /**\n * @dev Throws if paused.\n */\n modifier whenNotPaused() {\n require(!paused, \"paused\"); // SS03\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\"); // SS01\n _;\n }\n\n /**\n\t * @dev Throws if called by any account other than the owner or admin or pauser.\n\t \n\tmodifier onlyAuthorizedOrPauser() {\n\t\trequire(isOwner() || admins[msg.sender] || pausers[msg.sender], \"unauthorized\"); // WS02\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if called by any account other than the owner or pauser.\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || pausers[msg.sender], \"unauthorized\"); // SS02\n _;\n }\n\n /**\n * @dev Throws if called by any account other than pauser.\n * @notice Uncomment when needed\n */\n /*\n\tmodifier onlyPauser() {\n\t\trequire(pausers[msg.sender], \"Not pauser\");\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if frozen.\n */\n modifier whenNotFrozen() {\n require(!frozen, \"paused\"); // SS04\n _;\n }\n\n constructor() internal {\n // abstract\n }\n\n function _notSameBlockAsStakingCheckpoint(uint256 lockDate, address stakeFor) internal view {\n uint32 nCheckpoints = numUserStakingCheckpoints[stakeFor][lockDate];\n bool notSameBlock =\n userStakingCheckpoints[stakeFor][lockDate][nCheckpoints - 1].fromBlock != block.number;\n require(notSameBlock, \"cannot be mined in the same block as last stake\"); // S20\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = kickoffTS;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / TWO_WEEKS;\n lockDate = periodFromKickoff * TWO_WEEKS + start;\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS14\n\n date = _adjustDateForOrigin(date);\n uint32 nCheckpoints = numUserStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (userStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return userStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (userStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = userStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return userStakingCheckpoints[account][date][lower].stake;\n }\n\n /**\n * @dev origin vesting contracts have different dates\n * we need to add 2 weeks to get end of period (by default, it's start)\n * @param date The staking date to compute the power for.\n * @return unlocking date.\n */\n function _adjustDateForOrigin(uint256 date) internal view returns (uint256) {\n uint256 adjustedDate = _timestampToLockDate(date);\n //origin vesting contracts have different dates\n //we need to add 2 weeks to get end of period (by default, it's start)\n if (adjustedDate != date) {\n date = adjustedDate + TWO_WEEKS;\n }\n return date;\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function _computeWeightByDate(uint256 date, uint256 startDate)\n internal\n pure\n returns (uint96 weight)\n {\n require(date >= startDate, \"date < startDate\"); // WS18\n uint256 remainingTime = (date - startDate);\n require(MAX_DURATION >= remainingTime, \"remaining time > max duration\"); // WS19\n /// @dev x = max days - remaining days\n uint96 x = uint96(MAX_DURATION - remainingTime) / (1 days);\n /// @dev w = (m^2 - x^2)/m^2 +1 (multiplied by the weight factor)\n weight = add96(\n WEIGHT_FACTOR,\n mul96(\n MAX_VOTING_WEIGHT * WEIGHT_FACTOR,\n sub96(\n MAX_DURATION_POW_2,\n x * x,\n \"weight underflow\" // WS20\n ),\n \"weight mul overflow\" // WS21\n ) / MAX_DURATION_POW_2,\n \"overflow on weight\" // WS22\n );\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function _isVestingContract(address stakerAddress) internal view returns (bool) {\n bool isVesting;\n bytes32 codeHash;\n\n assembly {\n codeHash := extcodehash(stakerAddress)\n }\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingStorageShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../../openzeppelin/Ownable.sol\";\nimport \"../../../../interfaces/IERC20.sol\";\nimport \"../../../IFeeSharingCollector.sol\";\nimport \"../../../Vesting/IVestingRegistry.sol\";\n\n/**\n * @title StakingStorageShared contract is inherited by Staking modules.\n * @notice Just the storage part of stacking contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingProxy and Checkpoints contracts.\n *\n * What is SOV staking?\n * The purpose of the SOV token is to provide a pseudonymous,\n * censorship-resistant mechanism for governing the parameters of the Sovryn\n * protocol, while aligning the incentives of protocol governors with the\n * long-term success of the protocol. Any SOV token holder can choose to\n * stake (lock up) their tokens for a fixed period of time in return for\n * voting rights in the Bitocracy. Stakers are further incentivised through\n * fee and slashing rewards.\n * */\ncontract StakingStorageShared is Ownable {\n /// @notice 2 weeks in seconds.\n uint256 constant TWO_WEEKS = 1209600;\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n uint96 public constant MAX_VOTING_WEIGHT = 9;\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n uint96 public constant WEIGHT_FACTOR = 10;\n\n /// @notice The maximum duration to stake tokens for.\n uint256 public constant MAX_DURATION = 1092 days;\n\n /// @notice The maximum duration ^2\n uint96 constant MAX_DURATION_POW_2 = 1092 * 1092;\n\n /// @notice Default weight scaling.\n uint96 constant DEFAULT_WEIGHT_SCALING = 3;\n\n /// @notice Range for weight scaling.\n uint96 constant MIN_WEIGHT_SCALING = 1;\n uint96 constant MAX_WEIGHT_SCALING = 9;\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n uint256 public kickoffTS;\n\n string name = \"SOVStaking\";\n\n /// @notice The token to be staked.\n IERC20 public SOVToken;\n\n /// @notice A record of each accounts delegate.\n mapping(address => mapping(uint256 => address)) public delegates;\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately.\n bool public allUnlocked = false;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n bytes32 public constant DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 lockDate,uint256 nonce,uint256 expiry)\");\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure.\n address public newStakingContract;\n\n /*************************** Checkpoints *******************************/\n\n /// @notice A checkpoint for marking the stakes from a given block\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public totalStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numTotalStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public delegateStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numDelegateStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public userStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numUserStakingCheckpoints;\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n mapping(address => uint256) public nonces;\n\n /*************************** Slashing *******************************/\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n IFeeSharingCollector public feeSharing;\n\n /// @notice used for weight scaling when unstaking with slashing.\n uint96 public weightScaling = DEFAULT_WEIGHT_SCALING;\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n mapping(address => bool) public vestingWhitelist;\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n mapping(address => bool) public admins;\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n mapping(bytes32 => bool) public vestingCodeHashes;\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public vestingCheckpoints;\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numVestingCheckpoints;\n\n ///@notice vesting registry contract\n IVestingRegistry public vestingRegistryLogic;\n\n /// @dev user => flag whether user has pauser role.\n mapping(address => bool) public pausers;\n\n /// @dev Staking contract is paused\n bool public paused;\n\n /// @dev Staking contract is frozen\n bool public frozen;\n\n /// @dev max iterations that can be supported in 1 tx for the withdrawal\n uint256 internal maxVestingWithdrawIterations;\n\n constructor() internal {\n //abstract\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingAdminModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Admin Module.\n * @notice Implements administrative functionality pause, freeze and setting addresses and parameters\n * related to staking\n * */\ncontract StakingAdminModule is IFunctionsList, StakingShared {\n using Address for address payable;\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(_admin != address(0), \"cannot add the zero address as an admin\");\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(admins[_admin], \"address is not an admin\");\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external onlyOwner whenNotFrozen {\n require(_pauser != address(0), \"cannot add the zero address as a pauser\");\n pausers[_pauser] = true;\n emit PauserAddedOrRemoved(_pauser, true);\n }\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external onlyOwner whenNotFrozen {\n require(pausers[_pauser], \"address is not a pauser\");\n delete pausers[_pauser];\n emit PauserAddedOrRemoved(_pauser, false);\n }\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) public onlyPauserOrOwner whenNotFrozen {\n paused = _pause;\n emit StakingPaused(_pause);\n }\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external onlyPauserOrOwner {\n require(_freeze != frozen, \"Cannot freeze/unfreeze to the same state\"); // WS25\n if (_freeze) pauseUnpause(true);\n frozen = _freeze;\n emit StakingFrozen(_freeze);\n }\n\n /**\n * @notice Allow the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external onlyOwner whenNotFrozen {\n require(_feeSharing != address(0), \"FeeSharing address shouldn't be 0\"); // S17\n feeSharing = IFeeSharingCollector(_feeSharing);\n }\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external onlyOwner whenNotFrozen {\n require(\n MIN_WEIGHT_SCALING <= _weightScaling && _weightScaling <= MAX_WEIGHT_SCALING,\n \"scaling doesn't belong to range [1, 9]\" // S18\n );\n weightScaling = _weightScaling;\n }\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external onlyOwner whenNotFrozen {\n require(_newStakingContract != address(0), \"can't reset the new staking contract to 0\"); // S16\n newStakingContract = _newStakingContract;\n }\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external whenNotFrozen {\n require(newStakingContract != address(0), \"there is no new staking contract set\"); // S19\n revert(\"not implemented\");\n /// @dev implementation:\n /// @dev Iterate over all possible lock dates from now until now + MAX_DURATION.\n /// @dev Read the stake & delegate of the msg.sender\n /// @dev If stake > 0, stake it at the new contract until the lock date with the current delegate.\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](13);\n functionsList[0] = this.addAdmin.selector;\n functionsList[1] = this.removeAdmin.selector;\n functionsList[2] = this.addPauser.selector;\n functionsList[3] = this.removePauser.selector;\n functionsList[4] = this.pauseUnpause.selector;\n functionsList[5] = this.freezeUnfreeze.selector;\n functionsList[6] = this.setFeeSharing.selector;\n functionsList[7] = this.setWeightScaling.selector;\n functionsList[8] = this.setNewStakingContract.selector;\n functionsList[9] = this.owner.selector;\n functionsList[10] = this.isOwner.selector;\n functionsList[11] = this.transferOwnership.selector;\n functionsList[12] = this.migrateToNewStakingContract.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingGovernanceModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/IVesting.sol\";\n\n/**\n * @title Staking Governance Module contract\n * @notice Implements voting power and delegation functionality\n * */\ncontract StakingGovernanceModule is IFunctionsList, StakingShared, CheckpointsShared {\n using Address for address payable;\n\n /************* TOTAL VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n /// @dev Start the computation with the exact or previous unlocking date (voting weight remians the same until the next break point).\n uint256 start = _timestampToLockDate(time);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n totalVotingPower = add96(\n totalVotingPower,\n _totalPowerByDate(i, start, blockNumber),\n \"arrays mismatch\"\n ); // WS06\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorTotalStakesForDate(date, blockNumber);\n /// @dev weight is multiplied by some factor to allow decimals.\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS07\n }\n\n /****************************** DELEGATED VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96) {\n return getPriorVotes(account, block.number - 1, block.timestamp);\n }\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96 votes) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n votes = add96(\n votes,\n _totalPowerByDateForDelegatee(account, i, start, blockNumber),\n \"overflow - total VP\"\n ); // WS09\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDateForDelegatee(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS10\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n date = _adjustDateForOrigin(date);\n return _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined yet\"); // WS11\n\n uint32 nCheckpoints = numDelegateStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (delegateStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return delegateStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (delegateStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = delegateStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return delegateStakingCheckpoints[account][date][lower].stake;\n }\n\n /**************** SHARED FUNCTIONS *********************/\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for. Adjusted to the next valid lock date, as necessary\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n public\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorTotalStakesForDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function _getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS08\n\n uint32 nCheckpoints = numTotalStakingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (totalStakingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return totalStakingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n // Next check implicit zero balance\n if (totalStakingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Checkpoint memory cp = totalStakingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return totalStakingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Set new delegatee. Move from user's current delegate to a new\n * delegatee the stake balance.\n * @param delegator The user address to move stake balance from its current delegatee.\n * @param delegatee The new delegatee. The address to move stake balance to.\n * @param lockedTS The lock date.\n * @dev Reverts if delegator balance or delegatee is not valid, unless the sender is a vesting contract.\n * */\n function _delegate(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n address currentDelegate = delegates[delegator][lockedTS];\n uint96 delegatorBalance = _currentBalance(delegator, lockedTS);\n\n // vesting contracts will in multiple cases try to delegate a zero balance\n // or to the existing delegatee\n if (_isVestingContract(msg.sender)) {\n if (delegatorBalance == 0 || currentDelegate == delegatee) {\n return;\n }\n } else {\n require(delegatorBalance > 0, \"no stake to delegate\");\n require(currentDelegate != delegatee, \"cannot delegate to the existing delegatee\");\n }\n\n delegates[delegator][lockedTS] = delegatee;\n\n emit DelegateChanged(delegator, lockedTS, currentDelegate, delegatee);\n\n _moveDelegates(currentDelegate, delegatee, delegatorBalance, lockedTS);\n }\n\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n function _delegateNext(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n if (_isVestingContract(msg.sender)) {\n uint256 nextLock = lockedTS.add(TWO_WEEKS);\n address currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n\n // @dev workaround for the issue with a delegation of the latest stake\n uint256 endDate = IVesting(msg.sender).endDate();\n nextLock = lockedTS.add(FOUR_WEEKS);\n if (nextLock == endDate) {\n currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n }\n }\n }\n\n /**\n * @notice Move an amount of delegate stake from a source address to a\n * destination address.\n * @param srcRep The address to get the staked amount from.\n * @param dstRep The address to send the staked amount to.\n * @param amount The staked amount to move.\n * @param lockedTS The lock date.\n * */\n function _moveDelegates(\n address srcRep,\n address dstRep,\n uint96 amount,\n uint256 lockedTS\n ) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) _decreaseDelegateStake(srcRep, lockedTS, amount);\n\n if (dstRep != address(0)) _increaseDelegateStake(dstRep, lockedTS, amount);\n }\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function _getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external whenNotPaused {\n require(delegatee != address(0), \"cannot delegate to the zero address\");\n _notSameBlockAsStakingCheckpoint(lockDate, msg.sender);\n\n _delegate(msg.sender, delegatee, lockDate);\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n _delegateNext(msg.sender, delegatee, lockDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](6);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStakeModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking contract staking functionality module\n * @notice Implements staking functionality\n **/\ncontract StakingStakeModule is IFunctionsList, StakingShared, CheckpointsShared, ApprovalReceiver {\n using SafeMath for uint256;\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stake(msg.sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external onlyThisContract whenNotPaused whenNotFrozen {\n _stake(sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * */\n function _stake(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted\n ) internal {\n _stakeOptionalTokenTransfer(\n sender,\n amount,\n until,\n stakeFor,\n delegatee,\n timeAdjusted,\n true // transfer SOV\n );\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * @param transferToken Should transfer SOV - false for multiple iterations like in stakeBySchedule\n * */\n function _stakeOptionalTokenTransfer(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted,\n bool transferToken\n ) internal {\n require(amount > 0, \"amount needs to be bigger than 0\"); // S01\n\n if (!timeAdjusted) {\n until = _timestampToLockDate(until);\n }\n require(\n until > block.timestamp,\n \"Staking::_timestampToLockDate: staking period too short\"\n ); // S02\n\n /// @dev Stake for the sender if not specified otherwise.\n if (stakeFor == address(0)) {\n stakeFor = sender;\n }\n // must wait a block before staking again for that same deadline\n _notSameBlockAsStakingCheckpoint(until, stakeFor);\n\n /// @dev Delegate for stakeFor if not specified otherwise.\n if (delegatee == address(0)) {\n delegatee = stakeFor;\n }\n\n /// @dev Do not stake longer than the max duration.\n if (!timeAdjusted) {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n }\n\n uint96 previousBalance = _currentBalance(stakeFor, until);\n\n /// @dev Increase stake.\n _increaseStake(sender, amount, stakeFor, until, transferToken);\n\n // @dev Previous version wasn't working properly for the following case:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n address previousDelegatee = delegates[stakeFor][until];\n\n if (previousDelegatee != delegatee) {\n // @dev only the user that stakes for himself is allowed to delegate VP to another address\n // which works with vesting stakes and prevents vulnerability of delegating VP to an arbitrary address from\n // any address\n\n if (delegatee != stakeFor) {\n require(\n stakeFor == sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n } else if (sender != stakeFor && previousDelegatee != address(0)) {\n require(stakeFor == sender, \"Only sender is allowed to change delegatee\");\n }\n\n /// @dev Update delegatee.\n delegates[stakeFor][until] = delegatee;\n\n /// @dev Decrease stake on previous balance for previous delegatee.\n _decreaseDelegateStake(previousDelegatee, until, previousBalance);\n\n /// @dev Add previousBalance to amount.\n amount = add96(previousBalance, amount, \"add amounts failed\");\n }\n\n /// @dev Increase stake.\n _increaseDelegateStake(delegatee, until, amount);\n emit DelegateChanged(stakeFor, until, previousDelegatee, delegatee);\n }\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until)\n external\n whenNotPaused\n whenNotFrozen\n {\n previousLock = _timestampToLockDate(previousLock);\n until = _timestampToLockDate(until);\n\n _notSameBlockAsStakingCheckpoint(previousLock, msg.sender);\n\n /// @dev Do not exceed the max duration, no overflow possible.\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n\n require(previousLock < until, \"must increase staking duration\"); // S04\n\n /// @dev Update checkpoints.\n /// @dev TODO James: Can reading stake at block.number -1 cause trouble with multiple tx in a block?\n uint96 amount = _getPriorUserStakeByDate(msg.sender, previousLock, block.number - 1);\n require(amount > 0, \"no stakes till the prev lock date\"); // S05\n _decreaseUserStake(msg.sender, previousLock, amount);\n _increaseUserStake(msg.sender, until, amount);\n\n if (_isVestingContract(msg.sender)) {\n _decreaseVestingStake(previousLock, amount);\n _increaseVestingStake(until, amount);\n }\n\n _decreaseDailyStake(previousLock, amount);\n _increaseDailyStake(until, amount);\n\n /// @dev Delegate might change: if there is already a delegate set for the until date, it will remain the delegate for this position\n address delegateFrom = delegates[msg.sender][previousLock];\n delegates[msg.sender][previousLock] = address(0); //the previousLock delegates nullifying before reading that form `until` guards in case delegateTo == until\n address delegateTo = delegates[msg.sender][until];\n if (delegateTo == address(0)) {\n delegateTo = delegateFrom;\n delegates[msg.sender][until] = delegateFrom;\n }\n _decreaseDelegateStake(delegateFrom, previousLock, amount);\n _increaseDelegateStake(delegateTo, until, amount);\n\n emit ExtendedStakingDuration(msg.sender, previousLock, until, amount);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param until The date until which the tokens will be staked.\n * @param transferToken if false - token transfer should be handled separately\n * */\n function _increaseStake(\n address sender,\n uint96 amount,\n address stakeFor,\n uint256 until,\n bool transferToken\n ) internal {\n /// @dev Retrieve the SOV tokens.\n if (transferToken)\n require(\n SOVToken.transferFrom(sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // IS10\n\n /// @dev Increase staked balance.\n uint96 balance = _currentBalance(stakeFor, until);\n balance = add96(balance, amount, \"increaseStake: overflow\"); // IS20\n\n /// @dev Update checkpoints.\n _increaseDailyStake(until, amount);\n _increaseUserStake(stakeFor, until, amount);\n\n if (_isVestingContract(stakeFor)) _increaseVestingStake(until, amount);\n\n emit TokensStaked(stakeFor, amount, until, balance);\n }\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function _stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) internal {\n require(amount > 0, \"Invalid amount\");\n require(duration <= MAX_DURATION, \"Invalid duration\");\n require(intervalLength > 0, \"Invalid interval length\");\n require(intervalLength % TWO_WEEKS == 0, \"Invalid interval length\");\n if (delegatee != stakeFor && delegatee != address(0)) {\n require(\n stakeFor == msg.sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n }\n /**\n * @dev Stake them until lock dates according to the vesting schedule.\n * Note: because staking is only possible in periods of 2 weeks,\n * the total duration might end up a bit shorter than specified\n * depending on the date of staking.\n * */\n uint256 start = _timestampToLockDate(block.timestamp + cliff);\n uint256 end = _timestampToLockDate(block.timestamp + duration);\n require(start <= end, \"Invalid schedule\");\n uint256 numIntervals;\n if (start < end) {\n numIntervals = (end - start) / intervalLength + 1;\n } else {\n numIntervals = 1;\n }\n uint256 stakedPerInterval = amount / numIntervals;\n\n /// @dev transferring total SOV amount before staking\n require(\n SOVToken.transferFrom(msg.sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // SS10\n /// @dev stakedPerInterval might lose some dust on rounding. Add it to the first staking date.\n if (numIntervals >= 1) {\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(amount - stakedPerInterval * (numIntervals - 1)),\n start,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n /// @dev Stake the rest in 4 week intervals.\n for (uint256 i = start + intervalLength; i <= end; i += intervalLength) {\n /// @dev Stakes for itself, delegates to the owner.\n _notSameBlockAsStakingCheckpoint(i, stakeFor); // must wait a block before staking again for that same deadline\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(stakedPerInterval),\n i,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n }\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance) {\n for (uint256 i = kickoffTS; i <= block.timestamp + MAX_DURATION; i += TWO_WEEKS) {\n balance = add96(balance, _currentBalance(account, i), \"Staking::balanceOf: overflow\"); // S12\n }\n }\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96) {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n return nCheckpoints > 0 ? totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake : 0;\n }\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes)\n {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n\n /// @dev Calculate stakes.\n uint256 count = 0;\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n if (_currentBalance(account, i) > 0) {\n count++;\n }\n }\n dates = new uint256[](count);\n stakes = new uint96[](count);\n\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n uint256 j = 0;\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n uint96 balance = _currentBalance(account, i);\n if (balance > 0) {\n dates[j] = i;\n stakes[j] = balance;\n j++;\n }\n }\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOVToken);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeWithApproval.selector;\n return selectors;\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256) {\n return _timestampToLockDate(timestamp);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](10);\n functionsList[0] = this.stake.selector;\n functionsList[1] = this.stakeWithApproval.selector;\n functionsList[2] = this.extendStakingDuration.selector;\n functionsList[3] = this.stakesBySchedule.selector;\n functionsList[4] = this.stakeBySchedule.selector;\n functionsList[5] = this.balanceOf.selector;\n functionsList[6] = this.getCurrentStakedUntil.selector;\n functionsList[7] = this.getStakes.selector;\n functionsList[8] = this.timestampToLockDate.selector;\n functionsList[9] = this.receiveApproval.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStorageModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/StakingStorageShared.sol\";\n\n/**\n * @title Staking Storage Module\n * @notice Provides getters for public storage variables\n **/\ncontract StakingStorageModule is IFunctionsList, StakingStorageShared {\n function getStorageDefaultWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256) {\n return MAX_DURATION;\n }\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n function getStorageMaxVotingWeight() external pure returns (uint256) {\n return uint256(MAX_VOTING_WEIGHT);\n }\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n function getStorageWeightFactor() external pure returns (uint256) {\n return uint256(WEIGHT_FACTOR);\n }\n\n /// @notice Default weight scaling.\n function getStorageDefaulWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling)\n {\n return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING));\n }\n\n /// @notice The EIP-712 typehash for the contract's domain.\n function getStorageDomainTypehash() external pure returns (uint256) {\n return uint256(DOMAIN_TYPEHASH);\n }\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n function getStorageDelegationTypehash() external pure returns (uint256) {\n return uint256(DELEGATION_TYPEHASH);\n }\n\n function getStorageName() external view returns (string memory) {\n return name;\n }\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() public view returns (uint256) {\n return maxVestingWithdrawIterations;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](32);\n functionsList[0] = this.getStorageMaxDurationToStakeTokens.selector;\n functionsList[1] = this.getStorageMaxVotingWeight.selector;\n functionsList[2] = this.getStorageWeightFactor.selector;\n functionsList[3] = this.getStorageDefaulWeightScaling.selector;\n functionsList[4] = this.getStorageRangeForWeightScaling.selector;\n functionsList[5] = this.getStorageDomainTypehash.selector;\n functionsList[6] = this.getStorageDelegationTypehash.selector;\n functionsList[7] = this.getStorageName.selector;\n functionsList[8] = this.kickoffTS.selector;\n functionsList[9] = this.SOVToken.selector;\n functionsList[10] = this.delegates.selector;\n functionsList[11] = this.allUnlocked.selector;\n functionsList[12] = this.newStakingContract.selector;\n functionsList[13] = this.totalStakingCheckpoints.selector;\n functionsList[14] = this.numTotalStakingCheckpoints.selector;\n functionsList[15] = this.delegateStakingCheckpoints.selector;\n functionsList[16] = this.numDelegateStakingCheckpoints.selector;\n functionsList[17] = this.userStakingCheckpoints.selector;\n functionsList[18] = this.numUserStakingCheckpoints.selector;\n functionsList[19] = this.nonces.selector;\n functionsList[20] = this.feeSharing.selector;\n functionsList[21] = this.weightScaling.selector;\n functionsList[22] = this.vestingWhitelist.selector;\n functionsList[23] = this.admins.selector;\n functionsList[24] = this.vestingCodeHashes.selector;\n functionsList[25] = this.vestingCheckpoints.selector;\n functionsList[26] = this.numVestingCheckpoints.selector;\n functionsList[27] = this.vestingRegistryLogic.selector;\n functionsList[28] = this.pausers.selector;\n functionsList[29] = this.paused.selector;\n functionsList[30] = this.frozen.selector;\n functionsList[31] = this.getMaxVestingWithdrawIterations.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingVestingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Vesting Module contract\n * @notice Implements interaction with Vesting functionality: vesting registry, vesting staking\n * */\ncontract StakingVestingModule is IFunctionsList, StakingShared {\n event ContractCodeHashAdded(bytes32 hash);\n event ContractCodeHashRemoved(bytes32 hash);\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external onlyOwner whenNotFrozen {\n vestingRegistryLogic = IVestingRegistry(_vestingRegistryProxy);\n }\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(lockedDates.length == values.length, \"arrays mismatch\"); // WS05\n\n uint256 length = lockedDates.length;\n for (uint256 i = 0; i < length; i++) {\n _setVestingStake(lockedDates[i], values[i]);\n }\n }\n\n /**\n * @notice Sets the users' vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to be set.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function _setVestingStake(uint256 lockedTS, uint96 value) internal {\n require(\n lockedTS > kickoffTS,\n \"Invalid lock dates: must greater than contract creation timestamp\"\n );\n\n // locked date must be multiples of 14 days / TWO_WEEKS\n require(\n (lockedTS - kickoffTS) % TWO_WEEKS == 0,\n \"Invalid lock dates: not multiples of 14 days\"\n );\n\n // locked date must not exceed the MAX_DURATION\n if (lockedTS > block.timestamp) {\n require(\n lockedTS - block.timestamp <= MAX_DURATION,\n \"Invalid lock dates: exceed max duration\"\n );\n }\n\n // the value must not exceed the total staked at the given locked date\n uint32 nStakeCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 totalStaked = totalStakingCheckpoints[lockedTS][nStakeCheckpoints - 1].stake;\n require(\n value <= totalStaked,\n \"Invalid stake amount: greater than the total staked for given date\"\n );\n\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint32 blockNumber;\n\n Checkpoint memory recentCP = vestingCheckpoints[lockedTS][nCheckpoints - 1];\n if (nCheckpoints == 0) blockNumber = uint32(block.number) - 1;\n else blockNumber = recentCP.fromBlock + 1;\n\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, value);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n\n emit VestingStakeSet(lockedTS, value);\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n uint96 priorStake = _getPriorUserStakeByDate(account, date, blockNumber);\n // @dev we need to modify function in order to workaround issue with Vesting.withdrawTokens:\n //\t\treturn 1 instead of 0 if message sender is a contract.\n if (priorStake == 0 && _isVestingContract(msg.sender)) {\n priorStake = 1;\n }\n return priorStake;\n }\n\n /*************************** Weighted Vesting Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes)\n {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedVestingStakeByDate(i, start, blockNumber);\n if (weightedStake > 0) {\n votes = add96(votes, weightedStake, \"overflow on total weight\"); // WS15\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n power = _weightedVestingStakeByDate(date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorVestingStakeByDate(date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul oveflow\") / WEIGHT_FACTOR; // WS16\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorVestingStakeByDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS17\n\n uint32 nCheckpoints = numVestingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (vestingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return vestingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (vestingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = vestingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return vestingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n require(vestingCodeHashes[codeHash], \"not a registered vesting code hash\");\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool) {\n bool isVesting;\n bytes32 codeHash = _getCodeHash(stakerAddress);\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](9);\n functionsList[0] = this.setVestingRegistry.selector;\n functionsList[1] = this.setVestingStakes.selector;\n functionsList[2] = this.getPriorUserStakeByDate.selector;\n functionsList[3] = this.getPriorVestingWeightedStake.selector;\n functionsList[4] = this.getPriorVestingStakeByDate.selector;\n functionsList[5] = this.addContractCodeHash.selector;\n functionsList[6] = this.removeContractCodeHash.selector;\n functionsList[7] = this.isVestingContract.selector;\n functionsList[8] = this.weightedVestingStakeByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingWithdrawModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/ITeamVesting.sol\";\nimport \"../../Vesting/IVesting.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking withdrawal functionality module\n **/\ncontract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShared {\n using SafeMath for uint256;\n\n event MaxVestingWithdrawIterationsUpdated(uint256 oldMaxIterations, uint256 newMaxIterations);\n\n /// @dev Struct for direct withdraw function -- to avoid stack too deep issue\n struct VestingConfig {\n address vestingAddress;\n uint256 startDate;\n uint256 endDate;\n uint256 cliff;\n uint256 duration;\n address tokenOwner;\n }\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev If until is not a valid lock date, the next lock date after until is used.\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n // adjust until here to avoid adjusting multiple times, and to make sure an adjusted date is passed to\n // _notSameBlockAsStakingCheckpoint\n until = _adjustDateForOrigin(until);\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, false);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe need to check block.timestamp here\n _withdrawNext(until, receiver, false);\n }\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external onlyAuthorized whenNotFrozen {\n /// require the caller only for team vesting contract.\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n _cancelTeamVesting(vesting, receiver, startFrom);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param _vesting The vesting address.\n * @param _receiver The receiving address.\n * @param _startFrom The start value for the iterations.\n * or just unlocked tokens (false).\n * */\n function _cancelTeamVesting(\n address _vesting,\n address _receiver,\n uint256 _startFrom\n ) private {\n require(_receiver != address(0), \"receiver address invalid\");\n\n ITeamVesting teamVesting = ITeamVesting(_vesting);\n\n VestingConfig memory vestingConfig =\n VestingConfig(\n _vesting,\n teamVesting.startDate(),\n teamVesting.endDate(),\n teamVesting.cliff(),\n teamVesting.duration(),\n teamVesting.tokenOwner()\n );\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them, as long as the itrations less than maxVestingWithdrawIterations.\n uint256 end = vestingConfig.endDate;\n\n uint256 defaultStart = vestingConfig.startDate + vestingConfig.cliff;\n\n _startFrom = _startFrom >= defaultStart ? _startFrom : defaultStart;\n\n /// @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 totalIterationValue =\n (_startFrom + (TWO_WEEKS * (maxVestingWithdrawIterations - 1)));\n uint256 adjustedEnd = end < totalIterationValue ? end : totalIterationValue;\n\n /// @dev Withdraw for each unlocked position.\n for (uint256 i = _startFrom; i <= adjustedEnd; i += TWO_WEEKS) {\n /// @dev Read amount to withdraw.\n uint96 tempStake = _getPriorUserStakeByDate(_vesting, i, block.number - 1);\n\n if (tempStake > 0) {\n /// @dev do governance direct withdraw for team vesting\n _withdrawFromTeamVesting(tempStake, i, _receiver, vestingConfig);\n }\n }\n\n if (adjustedEnd < end) {\n emit TeamVestingPartiallyCancelled(msg.sender, _receiver, adjustedEnd);\n } else {\n emit TeamVestingCancelled(msg.sender, _receiver);\n }\n }\n\n /**\n * @notice Send user' staked tokens to a receiver taking into account punishments.\n * Sovryn encourages long-term commitment and thinking. When/if you unstake before\n * the end of the staking period, a percentage of the original staking amount will\n * be slashed. This amount is also added to the reward pool and is distributed\n * between all other stakers.\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * Needs to be adjusted to the next valid lock date before calling this function.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdraw(\n uint96 amount,\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n // @dev it's very unlikely some one will have 1/10**18 SOV staked in Vesting contract\n //\t\tthis check is a part of workaround for Vesting.withdrawTokens issue\n if (amount == 1 && _isVestingContract(msg.sender)) {\n return;\n }\n _validateWithdrawParams(msg.sender, amount, until);\n\n /// @dev Determine the receiver.\n if (receiver == address(0)) receiver = msg.sender;\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(msg.sender, until, amount);\n if (_isVestingContract(msg.sender)) _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[msg.sender][until], until, amount);\n\n /// @dev Early unstaking should be punished.\n if (block.timestamp < until && !allUnlocked && !isGovernance) {\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n amount -= punishedAmount;\n\n /// @dev punishedAmount can be 0 if block.timestamp are very close to 'until'\n if (punishedAmount > 0) {\n require(address(feeSharing) != address(0), \"FeeSharing address wasn't set\"); // S08\n /// @dev Move punished amount to fee sharing.\n /// @dev Approve transfer here and let feeSharing do transfer and write checkpoint.\n SOVToken.approve(address(feeSharing), punishedAmount);\n feeSharing.transferTokens(address(SOVToken), punishedAmount);\n }\n }\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(msg.sender, amount, until, receiver, isGovernance);\n }\n\n /**\n * @notice Send user' staked tokens to a receiver.\n * This function is dedicated only for direct withdrawal from staking contract.\n * Currently only being used by cancelTeamVesting()\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender.\n * @param vestingConfig The vesting config.\n * @dev VestingConfig struct intended to avoid stack too deep issue, and it contains this properties:\n address vestingAddress; // vesting contract address\n uint256 startDate; //start date of vesting\n uint256 endDate; // end date of vesting\n uint256 cliff; // after this time period the tokens begin to unlock\n uint256 duration; // after this period all the tokens will be unlocked\n address tokenOwner; // owner of the vested tokens\n * */\n function _withdrawFromTeamVesting(\n uint96 amount,\n uint256 until,\n address receiver,\n VestingConfig memory vestingConfig\n ) internal {\n address vesting = vestingConfig.vestingAddress;\n\n until = _timestampToLockDate(until);\n _validateWithdrawParams(vesting, amount, until);\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(vesting, until, amount);\n\n _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[vesting][until], until, amount);\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(vesting, amount, until, receiver, true);\n }\n\n // @dev withdraws tokens for lock date 2 weeks later than given lock date\n function _withdrawNext(\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n if (_isVestingContract(msg.sender)) {\n // nextLock needs to be adjusted to the next valid lock date to make sure we don't accidentally\n // withdraw stakes that are in the future and would get slashed (if until is not\n // a valid lock date). but until is already handled in the withdraw function\n uint256 nextLock = until.add(TWO_WEEKS);\n if (isGovernance || block.timestamp >= nextLock) {\n uint96 stakes = _getPriorUserStakeByDate(msg.sender, nextLock, block.number - 1);\n if (stakes > 0) {\n _withdraw(stakes, nextLock, receiver, isGovernance);\n }\n }\n }\n }\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked. Adjusted to the next valid lock date, if necessary.\n * @return Amount to withraw and penalty amount\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96)\n {\n until = _adjustDateForOrigin(until);\n _validateWithdrawParams(msg.sender, amount, until);\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n return (amount - punishedAmount, punishedAmount);\n }\n\n /**\n * @notice Get punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _getPunishedAmount(uint96 amount, uint256 until) internal view returns (uint96) {\n uint256 date = _timestampToLockDate(block.timestamp);\n uint96 weight = _computeWeightByDate(until, date); /// @dev (10 - 1) * WEIGHT_FACTOR\n weight = weight * weightScaling;\n return (amount * weight) / WEIGHT_FACTOR / 100;\n }\n\n /**\n * @notice Validate withdraw parameters.\n * @param account Address to be validated.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _validateWithdrawParams(\n address account,\n uint96 amount,\n uint256 until\n ) internal view {\n require(amount > 0, \"Amount of tokens to withdraw must be > 0\"); // S10\n uint96 balance = _getPriorUserStakeByDate(account, until, block.number - 1);\n require(amount <= balance, \"Staking::withdraw: not enough balance\"); // S11\n }\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external onlyOwner whenNotFrozen {\n allUnlocked = true;\n emit TokensUnlocked(SOVToken.balanceOf(address(this)));\n }\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param newMaxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 newMaxIterations)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(newMaxIterations > 0, \"Invalid max iterations\");\n emit MaxVestingWithdrawIterationsUpdated(maxVestingWithdrawIterations, newMaxIterations);\n maxVestingWithdrawIterations = newMaxIterations;\n }\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * @dev This function is dedicated only to support backward compatibility for sovryn ecosystem that has been implementing this staking contract.\n * @dev Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/4bbfe5bd0311ca71e4ef0e3af810d3791d8e4061/contracts/governance/Staking/modules/StakingWithdrawModule.sol#L78\n * */\n function governanceWithdrawVesting(address vesting, address receiver)\n public\n onlyAuthorized\n whenNotFrozen\n {\n vestingWhitelist[vesting] = true;\n ITeamVesting(vesting).governanceWithdrawTokens(receiver);\n vestingWhitelist[vesting] = false;\n\n emit VestingTokensWithdrawn(vesting, receiver);\n }\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n require(vestingWhitelist[msg.sender], \"unauthorized\"); // S07\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, true);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe don't need to check block.timestamp here\n _withdrawNext(until, receiver, true);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.withdraw.selector;\n functionsList[1] = this.cancelTeamVesting.selector;\n functionsList[2] = this.getWithdrawAmounts.selector;\n functionsList[3] = this.unlockAllTokens.selector;\n functionsList[4] = this.setMaxVestingWithdrawIterations.selector;\n functionsList[5] = this.governanceWithdraw.selector;\n functionsList[6] = this.governanceWithdrawVesting.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/WeightedStakingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Weighted Staking module contract.\n * @notice Implements getters for weighted staking functionality\n * */\ncontract WeightedStakingModule is IFunctionsList, StakingShared, CheckpointsShared {\n /*************************** User Weighted Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The start date/timestamp from which to calculate the weighted stake.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake) {\n return _getPriorWeightedStake(account, blockNumber, date);\n }\n\n function _getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) internal view returns (uint96 priorWeightedStake) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedStakeByDate(account, i, start, blockNumber);\n if (weightedStake > 0) {\n priorWeightedStake = add96(\n priorWeightedStake,\n weightedStake,\n \"overflow on total weight calc\"\n ); // WS12\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n return _weightedStakeByDate(account, date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function _weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorUserStakeByDate(account, date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS13\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight)\n {\n return _computeWeightByDate(date, startDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](3);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/SafeMath96.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n/**\n * @title SafeMath96 contract.\n * @notice Improved Solidity's arithmetic operations with added overflow checks.\n * @dev SafeMath96 uses uint96, unsigned integers of 96 bits length, so every\n * integer from 0 to 2^96-1 can be operated.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * SafeMath restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this contract instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n * */\ncontract SafeMath96 {\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function safe64(uint256 n, string memory errorMessage) internal pure returns (uint64) {\n require(n < 2**64, errorMessage);\n return uint64(n);\n }\n\n function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) {\n require(n < 2**96, errorMessage);\n return uint96(n);\n }\n\n /**\n * @notice Adds two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `+` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe addition a+b.\n * */\n function add96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n uint96 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n /**\n * @notice Substracts two unsigned integers, reverting on underflow.\n * @dev Counterpart to Solidity's `-` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on underflow.\n * @return The safe substraction a-b.\n * */\n function sub96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n require(b <= a, errorMessage);\n return a - b;\n }\n\n /**\n * @notice Multiplies two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `*` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe product a*b.\n * */\n function mul96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n if (a == 0) {\n return 0;\n }\n\n uint96 c = a * b;\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @notice Divides two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `/` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe division a/b.\n * */\n function div96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint96 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n}\n" + }, + "contracts/governance/Staking/StakingProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./modules/shared/StakingStorageShared.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Staking Proxy contract.\n * @dev Staking contract should be upgradable, use UpgradableProxy.\n * StakingStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingProxy is StakingStorageShared, UpgradableProxy {\n /**\n * @notice Construct a new staking contract.\n * @param SOV The address of the SOV token address.\n */\n constructor(address SOV) public {\n SOVToken = IERC20(SOV);\n kickoffTS = block.timestamp;\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewards.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Staking Rewards Contract.\n * @notice This is a trial incentive program.\n * In this, the SOV emitted and becoming liquid from the Adoption Fund could be utilized\n * to offset the higher APY's offered for Liquidity Mining events.\n * Vesting contract stakes are excluded from these rewards.\n * Only wallets which have staked previously liquid SOV are eligible for these rewards.\n * Tokenholders who stake their SOV receive staking rewards, a pro-rata share\n * of the revenue that the platform generates from various transaction fees\n * plus revenues from stakers who have a portion of their SOV slashed for\n * early unstaking.\n * */\ncontract StakingRewards is StakingRewardsStorage {\n using SafeMath for uint256;\n\n /// @notice Emitted when SOV is withdrawn\n /// @param receiver The address which recieves the SOV\n /// @param amount The amount withdrawn from the Smart Contract\n event RewardWithdrawn(address indexed receiver, uint256 amount);\n\n /**\n * @notice Replacement of constructor by initialize function for Upgradable Contracts\n * This function will be called only once by the owner.\n * @param _SOV SOV token address\n * @param _staking StakingProxy address should be passed\n * */\n function initialize(address _SOV, IStaking _staking) external onlyOwner {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n SOV = IERC20(_SOV);\n staking = _staking;\n startTime = staking.timestampToLockDate(block.timestamp);\n setMaxDuration(15 * TWO_WEEKS);\n deploymentBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Stops the current rewards program.\n * @dev All stakes existing on the contract at the point in time of\n * cancellation continue accruing rewards until the end of the staking\n * period being rewarded\n * */\n function stop() external onlyOwner {\n require(stopBlock == 0, \"Already stopped\");\n stopBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Collect rewards\n * @dev User calls this function to collect SOV staking rewards as per the SIP-0024 program.\n * The weighted stake is calculated using getPriorWeightedStake. Block number sent to the functon\n * must be a finalised block, hence we deduct 1 from the current block. User is only allowed to withdraw\n * after intervals of 14 days.\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * The issue is that we can only run for a max duration and if someone stakes for the\n * first time after the max duration is over, the reward will always return 0. Thus, we need to restart\n * from the duration that elapsed without generating rewards.\n * */\n function collectReward(uint256 restartTime) external {\n (uint256 withdrawalTime, uint256 amount) = getStakerCurrentReward(true, restartTime);\n require(withdrawalTime > 0 && amount > 0, \"no valid reward\");\n withdrawals[msg.sender] = withdrawalTime;\n _payReward(msg.sender, amount);\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred.\n */\n function withdrawTokensByOwner(address _receiverAddress) external onlyOwner {\n uint256 value = SOV.balanceOf(address(this));\n _transferSOV(_receiverAddress, value);\n }\n\n /**\n * @notice Changes average block time - based on blockchain\n * @dev If average block time significantly changes, we can update it here and use for block number calculation\n */\n function setAverageBlockTime(uint256 _averageBlockTime) external onlyOwner {\n averageBlockTime = _averageBlockTime;\n }\n\n /**\n * @notice This function computes the last staking checkpoint and calculates the corresponding\n * block number using the average block time which is then added to the mapping `checkpointBlockDetails`.\n */\n function setBlock() external {\n uint256 lastCheckpointTime = staking.timestampToLockDate(block.timestamp);\n _setBlock(lastCheckpointTime);\n }\n\n /**\n * @notice This function computes the block number using the average block time for a given historical\n * checkpoint which is added to the mapping `checkpointBlockDetails`.\n * @param _time Exact staking checkpoint time\n */\n function setHistoricalBlock(uint256 _time) external {\n _setBlock(_time);\n }\n\n /**\n * @notice Sets the max duration\n * @dev Rewards can be collected for a maximum duration at a time. This\n * is to avoid Block Gas Limit failures. Setting it zero would mean that it will loop\n * through the entire duration since the start of rewards program.\n * It should ideally be set to a value, for which the rewards can be easily processed.\n * @param _duration Max duration for which rewards can be collected at a go (in seconds)\n * */\n function setMaxDuration(uint256 _duration) public onlyOwner {\n maxDuration = _duration;\n }\n\n /**\n * @notice Internal function to calculate weighted stake\n * @dev If the rewards program is stopped, the user will still continue to\n * earn till the end of staking period based on the stop block.\n * @param _staker Staker address\n * @param _block Last finalised block\n * @param _date The date to compute prior weighted stakes\n * @return The weighted stake\n * */\n function _computeRewardForDate(\n address _staker,\n uint256 _block,\n uint256 _date\n ) internal view returns (uint256 weightedStake) {\n weightedStake = staking.getPriorWeightedStake(_staker, _block, _date);\n if (stopBlock > 0 && stopBlock < _block) {\n uint256 previousWeightedStake =\n staking.getPriorWeightedStake(_staker, stopBlock, _date);\n if (previousWeightedStake < weightedStake) {\n weightedStake = previousWeightedStake;\n }\n }\n }\n\n /**\n * @notice Internal function to pay rewards\n * @dev Base rate is annual, but we pay interest for 14 days,\n * which is 1/26 of one staking year (1092 days)\n * @param _staker User address\n * @param amount the reward amount\n * */\n function _payReward(address _staker, uint256 amount) internal {\n require(SOV.balanceOf(address(this)) >= amount, \"not enough funds to reward user\");\n claimedBalances[_staker] = claimedBalances[_staker].add(amount);\n _transferSOV(_staker, amount);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit RewardWithdrawn(_receiver, _amount);\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Internal function to calculate and set block\n * */\n function _setBlock(uint256 _checkpointTime) internal {\n uint256 currentTS = block.timestamp;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n require(checkpointBlockDetails[_checkpointTime] == 0, \"block number already set\");\n uint256 checkpointBlock =\n lastFinalisedBlock.sub(((currentTS.sub(_checkpointTime)).div(averageBlockTime)));\n checkpointBlockDetails[_checkpointTime] = checkpointBlock;\n }\n\n /**\n * @notice Get staker's current accumulated reward\n * @dev The collectReward() function internally calls this function to calculate reward amount\n * @param considerMaxDuration True: Runs for the maximum duration - used in tx not to run out of gas\n * False - to query total rewards\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * @return The timestamp of last withdrawal\n * @return The accumulated reward\n */\n function getStakerCurrentReward(bool considerMaxDuration, uint256 restartTime)\n public\n view\n returns (uint256 lastWithdrawalInterval, uint256 amount)\n {\n uint256 weightedStake;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n uint256 currentTS = block.timestamp;\n uint256 duration;\n address staker = msg.sender;\n uint256 lastWithdrawal = withdrawals[staker];\n\n uint256 lastStakingInterval = staking.timestampToLockDate(currentTS);\n lastWithdrawalInterval = lastWithdrawal > 0 ? lastWithdrawal : startTime;\n if (lastStakingInterval <= lastWithdrawalInterval) return (0, 0);\n /* Normally the restart time is 0. If this function returns a valid lastWithdrawalInterval\n\t\tand zero amount - that means there were no valid rewards for that period. So the new period must start\n\t\tfrom the end of the last interval or till the time no rewards are accumulated i.e. restartTime */\n if (restartTime >= lastWithdrawalInterval) {\n uint256 latestRestartTime = staking.timestampToLockDate(restartTime);\n lastWithdrawalInterval = latestRestartTime;\n }\n\n if (considerMaxDuration) {\n uint256 addedMaxDuration = lastWithdrawalInterval.add(maxDuration);\n duration = addedMaxDuration < currentTS\n ? staking.timestampToLockDate(addedMaxDuration)\n : lastStakingInterval;\n } else {\n duration = lastStakingInterval;\n }\n for (uint256 i = lastWithdrawalInterval; i < duration; i += TWO_WEEKS) {\n uint256 referenceBlock = checkpointBlockDetails[i];\n if (referenceBlock == 0) {\n referenceBlock = lastFinalisedBlock.sub(\n ((currentTS.sub(i)).div(averageBlockTime))\n );\n }\n if (referenceBlock < deploymentBlock) referenceBlock = deploymentBlock;\n weightedStake = weightedStake.add(_computeRewardForDate(staker, referenceBlock, i));\n }\n lastWithdrawalInterval = duration;\n amount = weightedStake.mul(BASE_RATE).div(DIVISOR);\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title StakingRewards Proxy contract.\n * @dev StakingRewards contract should be upgradable. Used UpgradableProxy.\n * StakingRewardsStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy with\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingRewardsProxy is StakingRewardsStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking Rewards Storage Contract.\n * @notice Just the storage part of staking rewards contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingRewardsProxy.\n *\n * What is SOV staking rewards - SIP-0024?\n * The purpose of the SOV staking rewards - SIP-0024 is to reward,\n * \"marginal stakers\" (ie, stakers by choice, not currently vesting) with liquid SOV\n * at the beginning of each new staking interval.\n * */\ncontract StakingRewardsStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n ///@notice the staking proxy contract address\n IStaking public staking;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 1209600;\n\n /// @notice Annual Base Rate - it is the maximum interest rate(APY)\n uint256 public constant BASE_RATE = 2975;\n\n /// @notice DIVISOR is set as 2600000 = 26 (num periods per year) * 10 (max voting weight) * 10000 (2975 -> 0.2975)\n uint256 public constant DIVISOR = 2600000;\n\n /// @notice Maximum duration to collect rewards at one go\n uint256 public maxDuration;\n\n /// @notice Represents the time when the contract is deployed\n uint256 public startTime;\n\n /// @notice Represents the block when the Staking Rewards pogram is stopped\n uint256 public stopBlock;\n\n /// @notice User Address -> Last Withdrawn Timestamp\n mapping(address => uint256) public withdrawals;\n\n /// @notice User Address -> Claimed Balance\n mapping(address => uint256) public claimedBalances;\n\n /// @notice Represents the block when the StakingRwards Program is started\n uint256 public deploymentBlock;\n\n /// Moved the variables from Initializable contract to resolve issue caused by incorrect Inheritance Order\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /// @notice BlockTime -> BlockNumber for a Staking Checkpoint\n mapping(uint256 => uint256) public checkpointBlockDetails;\n\n /// @notice Average Block Time - making it flexible\n uint256 public averageBlockTime;\n}\n" + }, + "contracts/governance/Timelock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./ErrorDecoder.sol\";\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\n/**\n * @title Sovryn Protocol Timelock contract, based on Compound system.\n *\n * @notice This contract lets Sovryn governance system set up its\n * own Time Lock instance to execute transactions proposed through the\n * GovernorAlpha contract instance.\n *\n * The Timelock contract allows its admin (Sovryn governance on\n * GovernorAlpha contract) to add arbitrary function calls to a\n * queue. This contract can only execute a function call if the\n * function call has been in the queue for at least 3 hours.\n *\n * Anytime the Timelock contract makes a function call, it must be the\n * case that the function call was first made public by having been publicly\n * added to the queue at least 3 hours prior.\n *\n * The intention is to provide GovernorAlpha contract the functionality to\n * queue proposal actions. This would mean that any changes made by Sovryn\n * governance of any contract would necessarily come with at least an\n * advanced warning. This makes the Sovryn system follow a “time-delayed,\n * opt-out” upgrade pattern (rather than an “instant, forced” upgrade pattern).\n *\n * Time-delaying admin actions gives users a chance to exit system if its\n * admins become malicious or compromised (or make a change that the users\n * do not like). Downside is that honest admins would be unable\n * to lock down functionality to protect users if a critical bug was found.\n *\n * Delayed transactions reduce the amount of trust required by users of Sovryn\n * and the overall risk for contracts building on top of it, as GovernorAlpha.\n * */\ncontract Timelock is ErrorDecoder, ITimelock {\n using SafeMath for uint256;\n\n uint256 public constant GRACE_PERIOD = 14 days;\n uint256 public constant MINIMUM_DELAY = 3 hours;\n uint256 public constant MAXIMUM_DELAY = 30 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /**\n * @notice Function called on instance deployment of the contract.\n * @param admin_ Governance contract address.\n * @param delay_ Time to wait for queued transactions to be executed.\n * */\n constructor(address admin_, uint256 delay_) public {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {}\n\n /**\n * @notice Set a new delay when executing the contract calls.\n * @param delay_ The amount of time to wait until execution.\n * */\n function setDelay(uint256 delay_) public {\n require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n require(delay_ >= MINIMUM_DELAY, \"Timelock::setDelay: Delay must exceed minimum delay.\");\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n /**\n * @notice Accept a new admin for the timelock.\n * */\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n /**\n * @notice Set a new pending admin for the timelock.\n * @param pendingAdmin_ The new pending admin address.\n * */\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n /**\n * @notice Queue a new transaction from the governance contract.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function queueTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public returns (bytes32) {\n require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n /**\n * @notice Cancel a transaction.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function cancelTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public {\n require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n /**\n * @notice Executes a previously queued transaction from the governance.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function executeTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public payable returns (bytes memory) {\n require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call.value(value)(callData);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"Timelock::executeTransaction: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"Timelock::executeTransaction: \", string(returnData)));\n }\n }\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n /**\n * @notice A function used to get the current Block Timestamp.\n * @dev Timestamp of the current block in seconds since the epoch.\n * It is a Unix time stamp. So, it has the complete information about\n * the date, hours, minutes, and seconds (in UTC) when the block was\n * created.\n * */\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" + }, + "contracts/governance/Vesting/DevelopmentFund.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Development Fund.\n * @author Franklin Richards\n * @notice You can use this contract for timed token release from Dev Fund.\n */\ncontract DevelopmentFund {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The current contract status.\n enum Status { Deployed, Active, Expired }\n Status public status;\n\n /// @notice The owner of the locked tokens (usually Governance).\n address public lockedTokenOwner;\n /// @notice The owner of the unlocked tokens (usually MultiSig).\n address public unlockedTokenOwner;\n /// @notice The emergency transfer wallet/contract.\n address public safeVault;\n /// @notice The new locked token owner waiting to be approved.\n address public newLockedTokenOwner;\n\n /// @notice The last token release timestamp or the time of contract creation.\n uint256 public lastReleaseTime;\n\n /// @notice The release duration array in seconds.\n uint256[] public releaseDuration;\n /// @notice The release token amount.\n uint256[] public releaseTokenAmount;\n\n /* Events */\n\n /// @notice Emitted when the contract is activated.\n event DevelopmentFundActivated();\n\n /// @notice Emitted when the contract is expired due to total token transfer.\n event DevelopmentFundExpired();\n\n /// @notice Emitted when a new locked owner is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current locked owner.\n event NewLockedOwnerAdded(address indexed _initiator, address indexed _newLockedOwner);\n\n /// @notice Emitted when a new locked owner is approved to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _oldLockedOwner The address of the previous locked owner.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current unlocked owner.\n event NewLockedOwnerApproved(\n address indexed _initiator,\n address indexed _oldLockedOwner,\n address indexed _newLockedOwner\n );\n\n /// @notice Emitted when a new unlocked owner is updated in the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newUnlockedOwner The address which is updated as the new unlocked owner.\n /// @dev Can only be initiated by the current locked owner.\n event UnlockedOwnerUpdated(address indexed _initiator, address indexed _newUnlockedOwner);\n\n /// @notice Emitted when a new token deposit is done.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new release schedule is created.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseCount The number of releases planned in the schedule.\n event TokenReleaseChanged(address indexed _initiator, uint256 _releaseCount);\n\n /// @notice Emitted when a unlocked owner transfers all the tokens to a safe vault.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token withdrawn.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done in an emergency situation only to a predetermined wallet by locked token owner.\n event LockedTokenTransferByUnlockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /// @notice Emitted when a unlocked owner withdraws the released tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token withdrawn.\n /// @param _releaseCount The total number of releases done based on duration.\n event UnlockedTokenWithdrawalByUnlockedOwner(\n address indexed _initiator,\n uint256 _amount,\n uint256 _releaseCount\n );\n\n /// @notice Emitted when a locked owner transfers all the tokens to a receiver.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token transfer.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done only by locked token owner.\n event LockedTokenTransferByLockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /* Modifiers */\n\n modifier onlyLockedTokenOwner() {\n require(msg.sender == lockedTokenOwner, \"Only Locked Token Owner can call this.\");\n _;\n }\n\n modifier onlyUnlockedTokenOwner() {\n require(msg.sender == unlockedTokenOwner, \"Only Unlocked Token Owner can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _lockedTokenOwner The owner of the locked tokens & contract.\n * @param _safeVault The emergency wallet/contract to transfer token.\n * @param _unlockedTokenOwner The owner of the unlocked tokens.\n * @param _lastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev Initial release schedule should be verified, error will result in either redeployment or calling changeTokenReleaseSchedule() after init() along with token transfer.\n */\n constructor(\n address _SOV,\n address _lockedTokenOwner,\n address _safeVault,\n address _unlockedTokenOwner,\n uint256 _lastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_lockedTokenOwner != address(0), \"Locked token & contract owner address invalid.\");\n require(_safeVault != address(0), \"Safe Vault address invalid.\");\n require(_unlockedTokenOwner != address(0), \"Unlocked token address invalid.\");\n\n SOV = IERC20(_SOV);\n lockedTokenOwner = _lockedTokenOwner;\n safeVault = _safeVault;\n unlockedTokenOwner = _unlockedTokenOwner;\n\n lastReleaseTime = _lastReleaseTime;\n /// If last release time passed is zero, then current time stamp will be used as the last release time.\n if (_lastReleaseTime == 0) {\n lastReleaseTime = block.timestamp;\n }\n\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n }\n\n /**\n * @notice This function is called once after deployment for token transfer based on schedule.\n * @dev Without calling this function, the contract will not work.\n */\n function init() public checkStatus(Status.Deployed) {\n uint256[] memory _releaseTokenAmount = releaseTokenAmount;\n require(_releaseTokenAmount.length != 0, \"Release Schedule not set.\");\n\n /// Getting the current release schedule total token amount.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _releaseTotalTokenAmount);\n require(txStatus, \"Not enough token sent to change release schedule.\");\n\n status = Status.Active;\n\n emit DevelopmentFundActivated();\n }\n\n /**\n * @notice Update Locked Token Owner.\n * @param _newLockedTokenOwner The owner of the locked tokens & contract.\n */\n function updateLockedTokenOwner(address _newLockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newLockedTokenOwner != address(0), \"New locked token owner address invalid.\");\n\n newLockedTokenOwner = _newLockedTokenOwner;\n\n emit NewLockedOwnerAdded(msg.sender, _newLockedTokenOwner);\n }\n\n /**\n * @notice Approve Locked Token Owner.\n * @dev This approval is an added security to avoid development fund takeover by a compromised locked token owner.\n */\n function approveLockedTokenOwner() public onlyUnlockedTokenOwner checkStatus(Status.Active) {\n require(newLockedTokenOwner != address(0), \"No new locked owner added.\");\n\n emit NewLockedOwnerApproved(msg.sender, lockedTokenOwner, newLockedTokenOwner);\n\n lockedTokenOwner = newLockedTokenOwner;\n\n newLockedTokenOwner = address(0);\n }\n\n /**\n * @notice Update Unlocked Token Owner.\n * @param _newUnlockedTokenOwner The new unlocked token owner.\n */\n function updateUnlockedTokenOwner(address _newUnlockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newUnlockedTokenOwner != address(0), \"New unlocked token owner address invalid.\");\n\n unlockedTokenOwner = _newUnlockedTokenOwner;\n\n emit UnlockedOwnerUpdated(msg.sender, _newUnlockedTokenOwner);\n }\n\n /**\n * @notice Deposit tokens to this contract.\n * @param _amount the amount of tokens deposited.\n * @dev These tokens can be withdrawn/transferred any time by the lockedTokenOwner.\n */\n function depositTokens(uint256 _amount) public checkStatus(Status.Active) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDeposit(msg.sender, _amount);\n }\n\n /**\n * @notice Change the Token release schedule. It creates a completely new schedule, and does not append on the previous one.\n * @param _newLastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev _releaseDuration and _releaseTokenAmount should be specified in reverse order of release.\n */\n function changeTokenReleaseSchedule(\n uint256 _newLastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public onlyLockedTokenOwner checkStatus(Status.Active) {\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// If the last release time has to be changed, then you can pass a new one here.\n /// Or else, the duration of release will be calculated based on this timestamp.\n /// Even a future timestamp can be mentioned here.\n if (_newLastReleaseTime != 0) {\n lastReleaseTime = _newLastReleaseTime;\n }\n\n /// Checking if the contract have enough token balance for the release.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n /// Getting the current token balance of the contract.\n uint256 remainingTokens = SOV.balanceOf(address(this));\n\n /// If the token balance is not sufficient, then we transfer the change to contract.\n if (remainingTokens < _releaseTotalTokenAmount) {\n bool txStatus =\n SOV.transferFrom(\n msg.sender,\n address(this),\n _releaseTotalTokenAmount.sub(remainingTokens)\n );\n require(txStatus, \"Not enough token sent to change release schedule.\");\n } else if (remainingTokens > _releaseTotalTokenAmount) {\n /// If there are more tokens than required, send the extra tokens back.\n bool txStatus =\n SOV.transfer(msg.sender, remainingTokens.sub(_releaseTotalTokenAmount));\n require(txStatus, \"Token not received by the Locked Owner.\");\n }\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n\n emit TokenReleaseChanged(msg.sender, _releaseDuration.length);\n }\n\n /**\n * @notice Transfers all of the remaining tokens in an emergency situation.\n * @dev This could be called when governance or development fund might be compromised.\n */\n function transferTokensByUnlockedTokenOwner()\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(safeVault, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByUnlockedOwner(msg.sender, safeVault, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /**\n * @notice Withdraws all unlocked/released token.\n * @param _amount The amount to be withdrawn.\n */\n function withdrawTokensByUnlockedTokenOwner(uint256 _amount)\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_amount > 0, \"Zero can't be withdrawn.\");\n\n uint256 count; /// To know how many elements to be removed from the release schedule.\n uint256 amount = _amount; /// To know the total amount to be transferred.\n uint256 newLastReleaseTimeMemory = lastReleaseTime; /// Better to use memory than storage.\n uint256 releaseLength = releaseDuration.length.sub(1); /// Also checks if there are any elements in the release schedule.\n\n /// Getting the amount of tokens, the number of releases and calculating the total duration.\n while (\n amount > 0 &&\n newLastReleaseTimeMemory.add(releaseDuration[releaseLength]) < block.timestamp\n ) {\n if (amount >= releaseTokenAmount[releaseLength]) {\n amount = amount.sub(releaseTokenAmount[releaseLength]);\n newLastReleaseTimeMemory = newLastReleaseTimeMemory.add(\n releaseDuration[releaseLength]\n );\n count++;\n } else {\n /// This will be the last case, if correct amount is passed.\n releaseTokenAmount[releaseLength] = releaseTokenAmount[releaseLength].sub(amount);\n amount = 0;\n }\n releaseLength--;\n }\n\n /// Checking to see if atleast a single schedule was reached or not.\n require(count > 0 || amount == 0, \"No release schedule reached.\");\n\n /// If locked token owner tries to send a higher amount that schedule\n uint256 value = _amount.sub(amount);\n\n /// Now clearing up the release schedule.\n releaseDuration.length -= count;\n releaseTokenAmount.length -= count;\n\n /// Updating the last release time.\n lastReleaseTime = newLastReleaseTimeMemory;\n\n /// Sending the amount to unlocked token owner.\n bool txStatus = SOV.transfer(msg.sender, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit UnlockedTokenWithdrawalByUnlockedOwner(msg.sender, value, count);\n }\n\n /**\n * @notice Transfers all of the remaining tokens by the owner maybe for an upgrade.\n * @dev This could be called when the current development fund has to be upgraded.\n * @param _receiver The address which receives this token transfer.\n */\n function transferTokensByLockedTokenOwner(address _receiver)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(_receiver, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByLockedOwner(msg.sender, _receiver, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token release duration.\n * @return _currentReleaseDuration The current release duration.\n */\n function getReleaseDuration() public view returns (uint256[] memory _releaseTokenDuration) {\n return releaseDuration;\n }\n\n /**\n * @notice Function to read the current token release amount.\n * @return _currentReleaseTokenAmount The current release token amount.\n */\n function getReleaseTokenAmount()\n public\n view\n returns (uint256[] memory _currentReleaseTokenAmount)\n {\n return releaseTokenAmount;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../IFeeSharingCollector.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../proxy/UpgradableProxy.sol\";\nimport \"../../../openzeppelin/Address.sol\";\n\n/**\n * @title Four Year Vesting Contract.\n *\n * @notice A four year vesting contract.\n *\n * @dev Vesting contract is upgradable,\n * Make sure the vesting owner is multisig otherwise it will be\n * catastrophic.\n * */\ncontract FourYearVesting is FourYearVestingStorage, UpgradableProxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharingCollector Fee sharing proxy address.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n address _feeSharingCollector,\n uint256 _extendDurationFor\n ) public {\n require(Address.isContract(_logic), \"_logic not a contract\");\n require(_SOV != address(0), \"SOV address invalid\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(Address.isContract(_stakingAddress), \"_stakingAddress not a contract\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(Address.isContract(_feeSharingCollector), \"_feeSharingCollector not a contract\");\n require((_extendDurationFor % FOUR_WEEKS) == 0, \"invalid duration\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n tokenOwner = _tokenOwner;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n maxInterval = 18 * FOUR_WEEKS;\n extendDurationFor = _extendDurationFor;\n }\n\n /**\n * @notice Set address of the implementation - vesting owner.\n * @dev Overriding setImplementation function of UpgradableProxy. The logic can only be\n * modified when both token owner and veting owner approve. Since\n * setImplementation can only be called by vesting owner, we also need to check\n * if the new logic is already approved by the token owner.\n * @param _implementation Address of the implementation. Must match with what is set by token owner.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n require(Address.isContract(_implementation), \"_implementation not a contract\");\n require(newImplementation == _implementation, \"address mismatch\");\n _setImplementation(_implementation);\n newImplementation = address(0);\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"./FourYearVesting.sol\";\nimport \"./IFourYearVestingFactory.sol\";\n\n/**\n * @title Four Year Vesting Factory: Contract to deploy four year vesting contracts.\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract FourYearVestingFactory is IFourYearVestingFactory, Ownable {\n /// @dev Added an event to keep track of the vesting contract created for a token owner\n event FourYearVestingCreated(address indexed tokenOwner, address indexed vestingAddress);\n\n /**\n * @notice Deploys four year vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwnerMultisig The address of an owner of vesting contract.\n * @dev _vestingOwnerMultisig should ALWAYS be multisig.\n * @param _fourYearVestingLogic The implementation contract.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * @return The four year vesting contract address.\n * */\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external onlyOwner returns (address) {\n address fourYearVesting =\n address(\n new FourYearVesting(\n _fourYearVestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _feeSharing,\n _extendDurationFor\n )\n );\n Ownable(fourYearVesting).transferOwnership(_vestingOwnerMultisig);\n emit FourYearVestingCreated(_tokenOwner, fourYearVesting);\n return fourYearVesting;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./IFourYearVesting.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Four Year Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by FourYearVestingFactory contract.\n * */\ncontract FourYearVestingLogic is IFourYearVesting, FourYearVestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n\n /* Events */\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n event TokenOwnerChanged(address indexed newOwner, address indexed oldOwner);\n\n /* Modifiers */\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Sets the max interval.\n * @param _interval Max interval for which tokens scheduled shall be staked.\n * */\n function setMaxInterval(uint256 _interval) external onlyOwner {\n require(_interval.mod(FOUR_WEEKS) == 0, \"invalid interval\");\n maxInterval = _interval;\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount)\n {\n (lastSchedule, remainingAmount) = _stakeTokens(msg.sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokensWithApproval(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) external onlyThisContract returns (uint256 lastSchedule, uint256 remainingAmount) {\n (lastSchedule, remainingAmount) = _stakeTokens(_sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) external onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n uint256 stakingEndDate = endDate;\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate.add(cliff); i <= stakingEndDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) external onlyTokenOwner {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external onlyTokenOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Change token owner - only vesting owner is allowed to change.\n * @dev Modifies token owner. This must be followed by approval\n * from token owner.\n * @param _newTokenOwner Address of new token owner.\n * */\n function changeTokenOwner(address _newTokenOwner) public onlyOwner {\n require(_newTokenOwner != address(0), \"invalid new token owner address\");\n require(_newTokenOwner != tokenOwner, \"same owner not allowed\");\n newTokenOwner = _newTokenOwner;\n }\n\n /**\n * @notice Approve token owner change - only token Owner.\n * @dev Token owner can only be modified\n * when both vesting owner and token owner have approved. This\n * function ascertains the approval of token owner.\n * */\n function approveOwnershipTransfer() public onlyTokenOwner {\n require(newTokenOwner != address(0), \"invalid address\");\n tokenOwner = newTokenOwner;\n newTokenOwner = address(0);\n emit TokenOwnerChanged(tokenOwner, msg.sender);\n }\n\n /**\n * @notice Set address of the implementation - only Token Owner.\n * @dev This function sets the new implementation address.\n * It must also be approved by the Vesting owner.\n * @param _newImplementation Address of the new implementation.\n * */\n function setImpl(address _newImplementation) public onlyTokenOwner {\n require(_newImplementation != address(0), \"invalid new implementation address\");\n newImplementation = _newImplementation;\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() external onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Extends stakes(unlocked till timeDuration) for four year vesting contracts.\n * @dev Tokens are vested for 4 years. Since the max staking\n * period is 3 years and the tokens are unlocked only after the first year(timeDuration) is\n * passed, hence, we usually extend the duration of staking for all unlocked tokens for the first\n * year by 3 years. In some cases, the timeDuration can differ.\n * */\n function extendStaking() external {\n uint256 timeDuration = startDate.add(extendDurationFor);\n uint256[] memory dates;\n uint96[] memory stakes;\n (dates, stakes) = staking.getStakes(address(this));\n\n for (uint256 i = 0; i < dates.length; i++) {\n if ((dates[i] < block.timestamp) && (dates[i] <= timeDuration) && (stakes[i] > 0)) {\n staking.extendStakingDuration(dates[i], dates[i].add(156 weeks));\n endDate = dates[i].add(156 weeks);\n } else {\n break;\n }\n }\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function _stakeTokens(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) internal returns (uint256 lastSchedule, uint256 remainingAmount) {\n // Creating a new staking schedule for the same vesting contract is disallowed unlike normal vesting\n require(\n (startDate == 0) ||\n (startDate > 0 && remainingStakeAmount > 0 && _restartStakeSchedule > 0),\n \"create new vesting address\"\n );\n uint256 restartDate;\n uint256 relativeAmount;\n // Calling the _stakeTokens function first time for the vesting contract\n // Runs for maxInterval only (consider maxInterval = 18 * 4 = 72 weeks)\n if (startDate == 0 && _restartStakeSchedule == 0) {\n startDate = staking.timestampToLockDate(block.timestamp); // Set only once\n durationLeft = duration; // We do not touch duration and cliff as they are used throughout\n cliffAdded = cliff; // Hence, durationLeft and cliffAdded is created\n }\n // Calling the _stakeTokens second/third time - we start from the end of previous interval\n // and the remaining amount(amount left after tokens are staked in the previous interval)\n if (_restartStakeSchedule > 0) {\n require(\n _restartStakeSchedule == lastStakingSchedule && _amount == remainingStakeAmount,\n \"invalid params\"\n );\n restartDate = _restartStakeSchedule;\n } else {\n restartDate = startDate;\n }\n // Runs only once when the _stakeTokens is called for the first time\n if (endDate == 0) {\n endDate = staking.timestampToLockDate(block.timestamp.add(duration));\n }\n uint256 addedMaxInterval = restartDate.add(maxInterval); // run for maxInterval\n if (addedMaxInterval < endDate) {\n // Runs for max interval\n lastStakingSchedule = addedMaxInterval;\n relativeAmount = (_amount.mul(maxInterval)).div(durationLeft); // (_amount * 18) / 39\n durationLeft = durationLeft.sub(maxInterval); // durationLeft - 18 periods(72 weeks)\n remainingStakeAmount = _amount.sub(relativeAmount); // Amount left to be staked in subsequent intervals\n } else {\n // Normal run\n lastStakingSchedule = endDate; // if staking intervals left < 18 periods(72 weeks)\n remainingStakeAmount = 0;\n durationLeft = 0;\n relativeAmount = _amount; // Stake all amount left\n }\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), relativeAmount);\n require(success, \"transfer failed\");\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), relativeAmount);\n\n staking.stakesBySchedule(\n relativeAmount,\n cliffAdded,\n duration.sub(durationLeft),\n FOUR_WEEKS,\n address(this),\n tokenOwner\n );\n if (durationLeft == 0) {\n // All tokens staked\n cliffAdded = 0;\n } else {\n cliffAdded = cliffAdded.add(maxInterval); // Add cliff to the end of previous maxInterval\n }\n\n emit TokensStaked(_sender, relativeAmount);\n return (lastStakingSchedule, remainingStakeAmount);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n /// @dev For four year vesting, withdrawal of stakes for the first year is not allowed. These\n /// stakes are extended for three years. In some cases the withdrawal may be allowed at a different\n /// time and hence we use extendDurationFor.\n for (uint256 i = startDate.add(extendDurationFor); i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number.sub(1));\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../Staking/interfaces/IStaking.sol\";\nimport \"../../IFeeSharingCollector.sol\";\n\n/**\n * @title Four Year Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for four year vesting.\n * It is parent of FourYearVestingLogic and FourYearVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract FourYearVestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n // Used lower case for cliff and duration to maintain consistency with normal vesting\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public constant cliff = 4 weeks;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public constant duration = 156 weeks;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n /// @notice Maximum interval to stake tokens at one go\n uint256 public maxInterval;\n\n /// @notice End of previous staking schedule.\n uint256 public lastStakingSchedule;\n\n /// @notice Amount of shares left to be staked.\n uint256 public remainingStakeAmount;\n\n /// @notice Durations left.\n uint256 public durationLeft;\n\n /// @notice Cliffs added.\n uint256 public cliffAdded;\n\n /// @notice Address of new token owner.\n address public newTokenOwner;\n\n /// @notice Address of new implementation.\n address public newImplementation;\n\n /// @notice Duration(from start) till the time unlocked tokens are extended(for 3 years)\n uint256 public extendDurationFor;\n\n /// @dev Please add new state variables below this line. Mark them internal and\n /// add a getter function while upgrading the contracts.\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IFourYearVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IFourYearVesting {\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount);\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingFactory contract to override empty\n * implemention of deployFourYearVesting function\n * and use an instance of FourYearVestingFactory.\n */\ninterface IFourYearVestingFactory {\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/GenericTokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\n\n/**\n * @title Token sender contract.\n *\n * @notice This contract includes functions to transfer tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract GenericTokenSender is AdminRole {\n /* Events */\n\n event TokensTransferred(address indexed token, address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer given amounts of tokens to the given addresses.\n * @param _token The address of the token.\n * @param _receivers The addresses of the receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferTokensUsingList(\n address _token,\n address[] calldata _receivers,\n uint256[] calldata _amounts\n ) external onlyAuthorized {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferTokens(_token, _receivers[i], _amounts[i]);\n }\n }\n\n function() external payable {}\n\n /**\n * @notice Transfer tokens to given address.\n * @param _token The address of the token.\n * @param _receiver The address of the token receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) external onlyAuthorized {\n _transferTokens(_token, _receiver, _amount);\n }\n\n function _transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n if (_token != address(0)) {\n require(IERC20(_token).transfer(_receiver, _amount), \"transfer failed\");\n } else {\n (bool success, ) = _receiver.call.value(_amount)(\"\");\n require(success, \"RBTC transfer failed\");\n }\n emit TokensTransferred(_token, _receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/ITeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for TeamVesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by Staking contract to call governanceWithdrawTokens\n * function having the vesting contract instance address.\n */\ninterface ITeamVesting {\n function startDate() external view returns (uint256);\n\n function cliff() external view returns (uint256);\n\n function endDate() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function tokenOwner() external view returns (address);\n\n function governanceWithdrawTokens(address receiver) external;\n}\n" + }, + "contracts/governance/Vesting/IVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IVesting {\n function duration() external returns (uint256);\n\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 amount) external;\n\n function tokenOwner() external view returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingFactory contract to override empty\n * implemention of deployVesting and deployTeamVesting functions\n * and on VestingRegistry contract to use an instance of VestingFactory.\n */\ninterface IVestingFactory {\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for upgradable Vesting Registry contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IVestingRegistry {\n function getVesting(address _tokenOwner) external view returns (address);\n\n function getTeamVesting(address _tokenOwner) external view returns (address);\n\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n function isVestingAddress(address _vestingAddress) external view returns (bool);\n\n function isTeamVesting(address _vestingAddress) external view returns (bool);\n}\n" + }, + "contracts/governance/Vesting/OrigingVestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./VestingRegistry.sol\";\n\n/**\n * @title Temp contract for checking address, creating and staking tokens.\n * @notice It casts an instance of vestingRegistry and by using createVesting\n * function it creates a vesting, gets it and stakes some tokens w/ this vesting.\n * */\ncontract OrigingVestingCreator is Ownable {\n VestingRegistry public vestingRegistry;\n\n mapping(address => bool) processedList;\n\n constructor(address _vestingRegistry) public {\n vestingRegistry = VestingRegistry(_vestingRegistry);\n }\n\n /**\n * @notice Create a vesting, get it and stake some tokens w/ this vesting.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount of tokens to be vested.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyOwner {\n require(_tokenOwner != address(0), \"Invalid address\");\n require(!processedList[_tokenOwner], \"Already processed\");\n\n processedList[_tokenOwner] = true;\n\n vestingRegistry.createVesting(_tokenOwner, _amount, _cliff, _duration);\n address vesting = vestingRegistry.getVesting(_tokenOwner);\n vestingRegistry.stakeTokens(vesting, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/OriginInvestorsClaim.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./VestingRegistry.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\n\n/**\n * @title Origin investors claim vested cSOV tokens.\n * @notice // TODO: fund this contract with a total amount of SOV needed to distribute.\n * */\ncontract OriginInvestorsClaim is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// VestingRegistry public constant vestingRegistry = VestingRegistry(0x80B036ae59B3e38B573837c01BB1DB95515b7E6B);\n\n uint256 public totalAmount;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant SOV_VESTING_CLIFF = 6 weeks;\n\n uint256 public kickoffTS;\n uint256 public vestingTerm;\n uint256 public investorsQty;\n bool public investorsListInitialized;\n VestingRegistry public vestingRegistry;\n IStaking public staking;\n IERC20 public SOVToken;\n\n /// @dev user => flag : Whether user has admin role.\n mapping(address => bool) public admins;\n\n /// @dev investor => Amount : Origin investors entitled to claim SOV.\n mapping(address => uint256) public investorsAmountsList;\n\n /* Events */\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n event InvestorsAmountsListAppended(uint256 qty, uint256 amount);\n event ClaimVested(address indexed investor, uint256 amount);\n event ClaimTransferred(address indexed investor, uint256 amount);\n event InvestorsAmountsListInitialized(uint256 qty, uint256 totalAmount);\n\n /* Modifiers */\n\n /// @dev Throws if called by any account other than the owner or admin.\n modifier onlyAuthorized() {\n require(\n isOwner() || admins[msg.sender],\n \"OriginInvestorsClaim::onlyAuthorized: should be authorized\"\n );\n _;\n }\n\n /// @dev Throws if called by any account not whitelisted.\n modifier onlyWhitelisted() {\n require(\n investorsAmountsList[msg.sender] != 0,\n \"OriginInvestorsClaim::onlyWhitelisted: not whitelisted or already claimed\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an initialized investors list.\n modifier notInitialized() {\n require(\n !investorsListInitialized,\n \"OriginInvestorsClaim::notInitialized: the investors list should not be set as initialized\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an uninitialized investors list.\n modifier initialized() {\n require(\n investorsListInitialized,\n \"OriginInvestorsClaim::initialized: the investors list has not been set yet\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires one parameter:\n * @param vestingRegistryAddress The vestingRegistry contract instance address.\n * */\n constructor(address vestingRegistryAddress) public {\n vestingRegistry = VestingRegistry(vestingRegistryAddress);\n staking = IStaking(vestingRegistry.staking());\n kickoffTS = staking.kickoffTS();\n SOVToken = IERC20(staking.SOVToken());\n vestingTerm = kickoffTS + SOV_VESTING_CLIFF;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice In case we have unclaimed tokens or in emergency case\n * this function transfers all SOV tokens to a given address.\n * @param toAddress The recipient address of all this contract tokens.\n * */\n function authorizedBalanceWithdraw(address toAddress) public onlyAuthorized {\n require(\n SOVToken.transfer(toAddress, SOVToken.balanceOf(address(this))),\n \"OriginInvestorsClaim::authorizedTransferBalance: transfer failed\"\n );\n }\n\n /**\n * @notice Should be called after the investors list setup completed.\n * This function checks whether the SOV token balance of the contract is\n * enough and sets status list to initialized.\n * */\n function setInvestorsAmountsListInitialized() public onlyAuthorized notInitialized {\n require(\n SOVToken.balanceOf(address(this)) >= totalAmount,\n \"OriginInvestorsClaim::setInvestorsAmountsList: the contract is not enough financed\"\n );\n\n investorsListInitialized = true;\n\n emit InvestorsAmountsListInitialized(investorsQty, totalAmount);\n }\n\n /**\n * @notice The contract should be approved or transferred necessary\n * amount of SOV prior to calling the function.\n * @param investors The list of investors addresses to add to the list.\n * Duplicates will be skipped.\n * @param claimAmounts The list of amounts for investors investors[i]\n * will receive claimAmounts[i] of SOV.\n * */\n function appendInvestorsAmountsList(\n address[] calldata investors,\n uint256[] calldata claimAmounts\n ) external onlyAuthorized notInitialized {\n uint256 subQty;\n uint256 sumAmount;\n require(\n investors.length == claimAmounts.length,\n \"OriginInvestorsClaim::appendInvestorsAmountsList: investors.length != claimAmounts.length\"\n );\n\n for (uint256 i = 0; i < investors.length; i++) {\n if (investorsAmountsList[investors[i]] == 0) {\n investorsAmountsList[investors[i]] = claimAmounts[i];\n sumAmount = sumAmount.add(claimAmounts[i]);\n } else {\n subQty = subQty.add(1);\n }\n }\n\n investorsQty = investorsQty.add(investors.length.sub(subQty));\n totalAmount = totalAmount.add(sumAmount);\n emit InvestorsAmountsListAppended(investors.length.sub(subQty), sumAmount);\n }\n\n /**\n * @notice Claim tokens from this contract.\n * If vestingTerm is not yet achieved a vesting is created.\n * Otherwise tokens are tranferred.\n * */\n function claim() external onlyWhitelisted initialized {\n if (now < vestingTerm) {\n createVesting();\n } else {\n transfer();\n }\n }\n\n /**\n * @notice Transfer tokens from this contract to a vestingRegistry contract.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to vesting contract.\n * */\n function createVesting() internal {\n uint256 cliff = vestingTerm.sub(now);\n uint256 duration = cliff;\n uint256 amount = investorsAmountsList[msg.sender];\n address vestingContractAddress;\n\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n vestingContractAddress == address(0),\n \"OriginInvestorsClaim::withdraw: the claimer has an active vesting contract\"\n );\n\n delete investorsAmountsList[msg.sender];\n\n vestingRegistry.createVesting(msg.sender, amount, cliff, duration);\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n SOVToken.transfer(address(vestingRegistry), amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n vestingRegistry.stakeTokens(vestingContractAddress, amount);\n\n emit ClaimVested(msg.sender, amount);\n }\n\n /**\n * @notice Transfer tokens from this contract to the sender.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to its account.\n * */\n function transfer() internal {\n uint256 amount = investorsAmountsList[msg.sender];\n\n delete investorsAmountsList[msg.sender];\n\n /**\n * @dev Withdraw only for those claiming after the cliff, i.e. without vesting contracts.\n * Those with vestingContracts should withdraw using Vesting.withdrawTokens\n * from Vesting (VestingLogic) contract.\n * */\n require(\n SOVToken.transfer(msg.sender, amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n\n emit ClaimTransferred(msg.sender, amount);\n }\n}\n" + }, + "contracts/governance/Vesting/TeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n//import \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../proxy/Proxy.sol\";\n\n/**\n * @title Team Vesting Contract.\n *\n * @notice A regular vesting contract, but the owner (governance) is able to\n * withdraw earlier without a slashing.\n *\n * @dev Vesting contracts shouldn't be upgradable,\n * use Proxy instead of UpgradableProxy.\n * */\ncontract TeamVesting is VestingStorage, Proxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollector\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_duration >= _cliff, \"duration must be bigger than or equal to the cliff\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n require(_duration <= staking.MAX_DURATION(), \"duration may not exceed the max duration\");\n tokenOwner = _tokenOwner;\n cliff = _cliff;\n duration = _duration;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n }\n}\n" + }, + "contracts/governance/Vesting/TokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title SOV Token sender contract.\n *\n * @notice This contract includes functions to transfer SOV tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract TokenSender is Ownable {\n /* Storage */\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @dev user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n constructor(address _SOV) public {\n require(_SOV != address(0), \"SOV address invalid\");\n\n SOV = _SOV;\n }\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Transfer given amounts of SOV to the given addresses.\n * @param _receivers The addresses of the SOV receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferSOVusingList(address[] memory _receivers, uint256[] memory _amounts)\n public\n onlyAuthorized\n {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferSOV(_receivers[i], _amounts[i]);\n }\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyAuthorized {\n _transferSOV(_receiver, _amount);\n }\n\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/Vesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./TeamVesting.sol\";\n\n/**\n * @title Vesting Contract.\n * @notice Team tokens and investor tokens are vested. Therefore, a smart\n * contract needs to be developed to enforce the vesting schedule.\n *\n * @dev TODO add tests for governanceWithdrawTokens.\n * */\ncontract Vesting is TeamVesting {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollectorProxy\n )\n public\n TeamVesting(\n _logic,\n _SOV,\n _stakingAddress,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharingCollectorProxy\n )\n {}\n\n /**\n * @dev We need to add this implementation to prevent proxy call VestingLogic.governanceWithdrawTokens\n * @param receiver The receiver of the token withdrawal.\n * */\n function governanceWithdrawTokens(address receiver) public {\n revert(\"operation not supported\");\n }\n}\n" + }, + "contracts/governance/Vesting/VestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"./VestingRegistryLogic.sol\";\nimport \"./VestingLogic.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingCreator is AdminRole {\n using SafeMath for uint256;\n\n ///@notice Boolean to check both vesting creation and staking is completed for a record\n bool vestingCreated;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 2 weeks;\n\n ///@notice the SOV token contract\n IERC20 public SOV;\n\n ///@notice the vesting registry contract\n VestingRegistryLogic public vestingRegistryLogic;\n\n ///@notice Holds Vesting Data\n struct VestingData {\n uint256 amount;\n uint256 cliff;\n uint256 duration;\n bool governanceControl; ///@dev true - tokens can be withdrawn by governance\n address tokenOwner;\n uint256 vestingCreationType;\n }\n\n ///@notice list of vesting to be processed\n VestingData[] public vestingDataList;\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event TokensStaked(address indexed vesting, address indexed tokenOwner, uint256 amount);\n event VestingDataRemoved(address indexed caller, address indexed tokenOwner);\n event DataCleared(address indexed caller);\n\n constructor(address _SOV, address _vestingRegistryProxy) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_vestingRegistryProxy != address(0), \"Vesting registry address invalid\");\n\n SOV = IERC20(_SOV);\n vestingRegistryLogic = VestingRegistryLogic(_vestingRegistryProxy);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings to be processed to the list\n */\n function addVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _amounts,\n uint256[] calldata _cliffs,\n uint256[] calldata _durations,\n bool[] calldata _governanceControls,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n require(\n _tokenOwners.length == _amounts.length &&\n _tokenOwners.length == _cliffs.length &&\n _tokenOwners.length == _durations.length &&\n _tokenOwners.length == _governanceControls.length,\n \"arrays mismatch\"\n );\n\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(\n _durations[i] >= _cliffs[i],\n \"duration must be bigger than or equal to the cliff\"\n );\n require(_amounts[i] > 0, \"vesting amount cannot be 0\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_cliffs[i].mod(TWO_WEEKS) == 0, \"cliffs should have intervals of two weeks\");\n require(\n _durations[i].mod(TWO_WEEKS) == 0,\n \"durations should have intervals of two weeks\"\n );\n VestingData memory vestingData =\n VestingData({\n amount: _amounts[i],\n cliff: _cliffs[i],\n duration: _durations[i],\n governanceControl: _governanceControls[i],\n tokenOwner: _tokenOwners[i],\n vestingCreationType: _vestingCreationTypes[i]\n });\n vestingDataList.push(vestingData);\n }\n }\n\n /**\n * @notice Creates vesting contract and stakes tokens\n * @dev Vesting and Staking are merged for calls that fits the gas limit\n */\n function processNextVesting() external {\n processVestingCreation();\n processStaking();\n }\n\n /**\n * @notice Creates vesting contract without staking any tokens\n * @dev Separating the Vesting and Staking to tackle Block Gas Limit\n */\n function processVestingCreation() public {\n require(!vestingCreated, \"staking not done for the previous vesting\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n _createAndGetVesting(vestingData);\n vestingCreated = true;\n }\n }\n\n /**\n * @notice Staking vested tokens\n * @dev it can be the case when vesting creation and tokens staking can't be done in one transaction because of block gas limit\n */\n function processStaking() public {\n require(vestingCreated, \"cannot stake without vesting creation\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n address vestingAddress =\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n require(SOV.approve(address(vesting), vestingData.amount), \"Approve failed\");\n vesting.stakeTokens(vestingData.amount);\n emit TokensStaked(vestingAddress, vestingData.tokenOwner, vestingData.amount);\n address tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n vestingCreated = false;\n }\n\n /**\n * @notice removes next vesting data from the list\n * @dev we process inverted list\n * @dev we should be able to remove incorrect vesting data that can't be processed\n */\n function removeNextVesting() external onlyAuthorized {\n address tokenOwnerDetails;\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n\n /**\n * @notice removes all data about unprocessed vestings to be processed\n */\n function clearVestingDataList() public onlyAuthorized {\n delete vestingDataList;\n emit DataCleared(msg.sender);\n }\n\n /**\n * @notice returns address after vesting creation\n */\n function getVestingAddress() external view returns (address) {\n return\n _getVesting(\n vestingDataList[vestingDataList.length - 1].tokenOwner,\n vestingDataList[vestingDataList.length - 1].cliff,\n vestingDataList[vestingDataList.length - 1].duration,\n vestingDataList[vestingDataList.length - 1].governanceControl,\n vestingDataList[vestingDataList.length - 1].vestingCreationType\n );\n }\n\n /**\n * @notice returns period i.e. ((duration - cliff) / 4 WEEKS)\n * @dev will be used for deciding if vesting and staking needs to be processed\n * in a single transaction or separate transactions\n */\n function getVestingPeriod() external view returns (uint256) {\n uint256 duration = vestingDataList[vestingDataList.length - 1].duration;\n uint256 cliff = vestingDataList[vestingDataList.length - 1].cliff;\n uint256 fourWeeks = TWO_WEEKS.mul(2);\n uint256 period = duration.sub(cliff).div(fourWeeks);\n return period;\n }\n\n /**\n * @notice returns count of vestings to be processed\n */\n function getUnprocessedCount() external view returns (uint256) {\n return vestingDataList.length;\n }\n\n /**\n * @notice returns total amount of vestings to be processed\n */\n function getUnprocessedAmount() public view returns (uint256) {\n uint256 amount = 0;\n uint256 length = vestingDataList.length;\n for (uint256 i = 0; i < length; i++) {\n amount = amount.add(vestingDataList[i].amount);\n }\n return amount;\n }\n\n /**\n * @notice checks if contract balance is enough to process all vestings\n */\n function isEnoughBalance() public view returns (bool) {\n return SOV.balanceOf(address(this)) >= getUnprocessedAmount();\n }\n\n /**\n * @notice returns missed balance to process all vestings\n */\n function getMissingBalance() external view returns (uint256) {\n if (isEnoughBalance()) {\n return 0;\n }\n return getUnprocessedAmount() - SOV.balanceOf(address(this));\n }\n\n /**\n * @notice creates TeamVesting or Vesting contract\n * @dev new contract won't be created if account already has contract of the same type\n */\n function _createAndGetVesting(VestingData memory vestingData)\n internal\n returns (address vesting)\n {\n if (vestingData.governanceControl) {\n vestingRegistryLogic.createTeamVesting(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n } else {\n vestingRegistryLogic.createVestingAddr(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n }\n return\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n }\n\n /**\n * @notice returns an address of TeamVesting or Vesting contract (depends on a governance control)\n */\n function _getVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n bool _governanceControl,\n uint256 _vestingCreationType\n ) internal view returns (address vestingAddress) {\n if (_governanceControl) {\n vestingAddress = vestingRegistryLogic.getTeamVesting(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n } else {\n vestingAddress = vestingRegistryLogic.getVestingAddr(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n }\n }\n}\n" + }, + "contracts/governance/Vesting/VestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./Vesting.sol\";\nimport \"./TeamVesting.sol\";\nimport \"./IVestingFactory.sol\";\n\n/**\n * @title Vesting Factory: Contract to deploy vesting contracts\n * of two types: vesting (TokenHolder) and team vesting (Multisig).\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract VestingFactory is IVestingFactory, Ownable {\n address public vestingLogic;\n\n constructor(address _vestingLogic) public {\n require(_vestingLogic != address(0), \"invalid vesting logic address\");\n vestingLogic = _vestingLogic;\n }\n\n /**\n * @notice Deploys Vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner /// @dev owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new Vesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n\n /**\n * @notice Deploys Team Vesting contract.\n * @param _SOV The address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner //owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new TeamVesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\n\n/**\n * @title Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by a VestingFactory contract.\n * */\ncontract VestingLogic is IVesting, VestingStorage, ApprovalReceiver {\n /* Events */\n\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(uint256 _amount) public {\n _stakeTokens(msg.sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokensWithApproval(address _sender, uint256 _amount) public onlyThisContract {\n _stakeTokens(_sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * */\n function _stakeTokens(address _sender, uint256 _amount) internal {\n /// @dev Maybe better to allow staking unil the cliff was reached.\n if (startDate == 0) {\n startDate = staking.timestampToLockDate(block.timestamp);\n }\n endDate = staking.timestampToLockDate(block.timestamp + duration);\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), _amount);\n require(success);\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), _amount);\n\n staking.stakeBySchedule(_amount, cliff, duration, FOUR_WEEKS, address(this), tokenOwner);\n\n emit TokensStaked(_sender, _amount);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws all tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * @dev Can be called only by owner.\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdrawTokens(address receiver) public {\n require(msg.sender == address(staking), \"unauthorized\");\n\n _withdrawTokens(receiver, true);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) public onlyOwners {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number - 1);\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n if (isGovernance) {\n staking.governanceWithdraw(stake, i, receiver);\n } else {\n staking.withdraw(stake, i, receiver);\n }\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) public onlyOwners {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() public onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Registry contract.\n *\n * @notice On January 25, 2020, Sovryn launched the Genesis Reservation system.\n * Sovryn community members who controlled a special NFT were granted access to\n * stake BTC or rBTC for cSOV tokens at a rate of 2500 satoshis per cSOV. Per\n * SIP-0003, up to 2,000,000 cSOV were made available in the Genesis event,\n * which will be redeemable on a 1:1 basis for cSOV, subject to approval by\n * existing SOV holders.\n *\n * On 15 Feb 2021 Sovryn is taking another step in its journey to decentralized\n * financial sovereignty with the vote on SIP 0005. This proposal will enable\n * participants of the Genesis Reservation system to redeem their reserved cSOV\n * tokens for SOV. They will also have the choice to redeem cSOV for rBTC if\n * they decide to exit the system.\n *\n * This contract deals with the vesting and redemption of cSOV tokens.\n * */\ncontract VestingRegistry is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The cSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract.\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVReImburse(address from, uint256 CSOVamount, uint256 reImburseAmount);\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing collector proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n //---ACL------------------------------------------------------------------\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * TODO: This ACL logic should be available on OpenZeppeling Ownable.sol\n * or on our own overriding sovrynOwnable. This same logic is repeated\n * on OriginInvestorsClaim.sol, TokenSender.sol and VestingRegistry2.sol\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice cSOV payout to sender with rBTC currency.\n * 1.- Check holder cSOV balance by adding up every cSOV token balance.\n * 2.- ReImburse rBTC if funds available.\n * 3.- And store holder address in processedList.\n */\n function reImburse() public isNotProcessed isNotBlacklisted {\n uint256 CSOVAmountWei = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n CSOVAmountWei = CSOVAmountWei.add(balance);\n }\n\n require(CSOVAmountWei > lockedAmount[msg.sender], \"holder has no CSOV\");\n CSOVAmountWei -= lockedAmount[msg.sender];\n processedList[msg.sender] = true;\n\n /**\n * @dev Found and fixed the SIP-0007 bug on VestingRegistry::reImburse formula.\n * More details at Documenting Code issues at point 11 in\n * https://docs.google.com/document/d/10idTD1K6JvoBmtPKGuJ2Ub_mMh6qTLLlTP693GQKMyU/\n * Previous buggy code: uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**10);\n * */\n uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**8);\n require(address(this).balance >= reImburseAmount, \"Not enough funds to reimburse\");\n msg.sender.transfer(reImburseAmount);\n\n emit CSOVReImburse(msg.sender, CSOVAmountWei, reImburseAmount);\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Exchange cSOV to SOV with 1:1 rate\n */\n function exchangeAllCSOV() public isNotProcessed isNotBlacklisted {\n processedList[msg.sender] = true;\n\n uint256 amount = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n amount += balance;\n }\n\n require(amount > lockedAmount[msg.sender], \"amount invalid\");\n amount -= lockedAmount[msg.sender];\n\n _createVestingForCSOV(amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param _vesting The address of Vesting contract.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n /// @dev TODO: Owner of OwnerVesting contracts - the same address as tokenOwner.\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry2.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title VestingRegistry 2 contract.\n * @notice One time contract needed to distribute tokens to origin sales investors.\n * */\ncontract VestingRegistry2 is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The CSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry3.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingRegistry3 is Ownable {\n using SafeMath for uint256;\n\n IVestingFactory public vestingFactory;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n //@notice fee sharing proxy\n address public feeSharingCollector;\n //@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n //TODO add to the documentation: address can have only one vesting of each type\n //user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n //user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n constructor(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"./VestingRegistryStorage.sol\";\n\ncontract VestingRegistryLogic is VestingRegistryStorage {\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event VestingCreationAndTypesSet(\n address indexed vesting,\n VestingCreationAndTypeDetails vestingCreationAndType\n );\n\n /**\n * @notice Replace constructor with initialize function for Upgradable Contracts\n * This function will be called only once by the owner\n * */\n function initialize(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner,\n address _lockedSOV,\n address[] calldata _vestingRegistries\n ) external onlyOwner initializer {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n require(_lockedSOV != address(0), \"LockedSOV address invalid\");\n\n _setVestingFactory(_vestingFactory);\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n lockedSOV = LockedSOV(_lockedSOV);\n for (uint256 i = 0; i < _vestingRegistries.length; i++) {\n require(_vestingRegistries[i] != address(0), \"Vesting registry address invalid\");\n vestingRegistries.push(IVestingRegistry(_vestingRegistries[i]));\n }\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) external onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Internal function that sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings that were deployed in previous vesting registries\n * @dev migration of data from previous vesting registy contracts\n */\n function addDeployedVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingCreationTypes[i] > 0, \"vesting creation type must be greater than 0\");\n _addDeployedVestings(_tokenOwners[i], _vestingCreationTypes[i]);\n }\n }\n\n /**\n * @notice adds four year vestings to vesting registry logic\n * @param _tokenOwners array of token owners\n * @param _vestingAddresses array of vesting addresses\n */\n function addFourYearVestings(\n address[] calldata _tokenOwners,\n address[] calldata _vestingAddresses\n ) external onlyAuthorized {\n require(_tokenOwners.length == _vestingAddresses.length, \"arrays mismatch\");\n uint256 vestingCreationType = 4;\n uint256 cliff = 4 weeks;\n uint256 duration = 156 weeks;\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(!isVesting[_vestingAddresses[i]], \"vesting exists\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingAddresses[i] != address(0), \"vesting cannot be 0 address\");\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwners[i],\n uint256(VestingType.Vesting),\n cliff,\n duration,\n vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n vestingCreationType,\n _vestingAddresses[i]\n );\n vestingsOf[_tokenOwners[i]].push(uid);\n isVesting[_vestingAddresses[i]] = true;\n }\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @dev Calls a public createVestingAddr function with vestingCreationType. This is to accomodate the existing logic for LockedSOV\n * @dev vestingCreationType 0 = LockedSOV\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAuthorized {\n createVestingAddr(_tokenOwner, _amount, _cliff, _duration, 3);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createVestingAddr(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.Vesting),\n _vestingCreationType\n );\n\n emit VestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) external onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.TeamVesting),\n _vestingCreationType\n );\n\n emit TeamVestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) external onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n * @dev Calls a public getVestingAddr function with cliff and duration. This is to accomodate the existing logic for LockedSOV\n * @dev We need to use LockedSOV.changeRegistryCliffAndDuration function very judiciously\n * @dev vestingCreationType 0 - LockedSOV\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return getVestingAddr(_tokenOwner, lockedSOV.cliff(), lockedSOV.duration(), 3);\n }\n\n /**\n * @notice public function that returns vesting contract address for the given token owner, cliff, duration\n * @dev Important: Please use this instead of getVesting function\n */\n function getVestingAddr(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner, cliff, duration\n */\n function getTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @dev check if the specific vesting address is team vesting or not\n * @dev read the vestingType from vestingCreationAndTypes storage\n *\n * @param _vestingAddress address of vesting contract\n *\n * @return true for teamVesting, false for normal vesting\n */\n function isTeamVesting(address _vestingAddress) external view returns (bool) {\n return (vestingCreationAndTypes[_vestingAddress].isSet &&\n vestingCreationAndTypes[_vestingAddress].vestingType ==\n uint32(VestingType.TeamVesting));\n }\n\n /**\n * @dev setter function to register existing vesting contract to vestingCreationAndTypes storage\n * @dev need to set the function visilibty to public to support VestingCreationAndTypeDetails struct as parameter\n *\n * @param _vestingAddresses array of vesting address\n * @param _vestingCreationAndTypes array for VestingCreationAndTypeDetails struct\n */\n function registerVestingToVestingCreationAndTypes(\n address[] memory _vestingAddresses,\n VestingCreationAndTypeDetails[] memory _vestingCreationAndTypes\n ) public onlyAuthorized {\n require(_vestingAddresses.length == _vestingCreationAndTypes.length, \"Unmatched length\");\n for (uint256 i = 0; i < _vestingCreationAndTypes.length; i++) {\n VestingCreationAndTypeDetails memory _vestingCreationAndType =\n _vestingCreationAndTypes[i];\n address _vestingAddress = _vestingAddresses[i];\n\n vestingCreationAndTypes[_vestingAddress] = _vestingCreationAndType;\n\n emit VestingCreationAndTypesSet(\n _vestingAddress,\n vestingCreationAndTypes[_vestingAddress]\n );\n }\n }\n\n /**\n * @notice Internal function to deploy Vesting/Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _type the type of vesting\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _type,\n uint256 _vestingCreationType\n ) internal returns (address) {\n address vesting;\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, _type, _cliff, _duration, _vestingCreationType)\n )\n );\n if (vestings[uid].vestingAddress == address(0)) {\n if (_type == 1) {\n vesting = vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n } else {\n vesting = vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n }\n vestings[uid] = Vesting(_type, _vestingCreationType, vesting);\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vesting] = true;\n\n vestingCreationAndTypes[vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(_type),\n vestingCreationType: uint128(_vestingCreationType)\n });\n\n emit VestingCreationAndTypesSet(vesting, vestingCreationAndTypes[vesting]);\n }\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice stores the addresses of Vesting contracts from all three previous versions of Vesting Registry\n */\n function _addDeployedVestings(address _tokenOwner, uint256 _vestingCreationType) internal {\n uint256 uid;\n uint256 i = _vestingCreationType - 1;\n\n address vestingAddress = vestingRegistries[i].getVesting(_tokenOwner);\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.Vesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n _vestingCreationType,\n vestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vestingAddress] = true;\n }\n\n address teamVestingAddress = vestingRegistries[i].getTeamVesting(_tokenOwner);\n if (teamVestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(teamVestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.TeamVesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.TeamVesting),\n _vestingCreationType,\n teamVestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[teamVestingAddress] = true;\n }\n }\n\n /**\n * @notice returns all vesting details for the given token owner\n */\n function getVestingsOf(address _tokenOwner) external view returns (Vesting[] memory) {\n uint256[] memory vestingIds = vestingsOf[_tokenOwner];\n uint256 length = vestingIds.length;\n Vesting[] memory _vestings = new Vesting[](vestingIds.length);\n for (uint256 i = 0; i < length; i++) {\n _vestings[i] = vestings[vestingIds[i]];\n }\n return _vestings;\n }\n\n /**\n * @notice returns cliff and duration for Vesting & TeamVesting contracts\n */\n function getVestingDetails(address _vestingAddress)\n external\n view\n returns (uint256 cliff, uint256 duration)\n {\n VestingLogic vesting = VestingLogic(_vestingAddress);\n return (vesting.cliff(), vesting.duration());\n }\n\n /**\n * @notice returns if the address is a vesting address\n */\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return isVesting[_vestingAddress];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./VestingRegistryStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Vesting Registry Proxy contract.\n * @dev Vesting Registry contract should be upgradable, use UpgradableProxy.\n * VestingRegistryStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract VestingRegistryProxy is VestingRegistryStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Initializable.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"../../locked/LockedSOV.sol\";\nimport \"./IVestingRegistry.sol\";\n\n/**\n * @title Vesting Registry Storage Contract.\n *\n * @notice This contract is just the storage required for vesting registry.\n * It is parent of VestingRegistryProxy and VestingRegistryLogic.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\n\ncontract VestingRegistryStorage is Initializable, AdminRole {\n ///@notice the vesting factory contract\n IVestingFactory public vestingFactory;\n\n ///@notice the Locked SOV contract\n ILockedSOV public lockedSOV;\n\n ///@notice the list of vesting registries\n IVestingRegistry[] public vestingRegistries;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n\n ///@notice fee sharing proxy\n address public feeSharingCollector;\n\n ///@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n ///@notice Vesting details\n struct Vesting {\n uint256 vestingType;\n uint256 vestingCreationType;\n address vestingAddress;\n }\n\n ///@notice A record of vesting details for a unique id\n ///@dev vestings[uid] returns vesting data\n mapping(uint256 => Vesting) public vestings;\n\n ///@notice A record of all unique ids for a particular token owner\n ///@dev vestingsOf[tokenOwner] returns array of unique ids\n mapping(address => uint256[]) public vestingsOf;\n\n ///@notice A record of all vesting addresses\n ///@dev isVesting[address] returns if the address is a vesting address\n mapping(address => bool) public isVesting;\n\n /// @notice Store vesting creation type & vesting type information\n /// @dev it is packed into 1 single storage slot for cheaper gas usage\n struct VestingCreationAndTypeDetails {\n bool isSet;\n uint32 vestingType;\n uint128 vestingCreationType;\n }\n\n ///@notice A record of all vesting addresses with the detail\n ///@dev vestingDetail[vestingAddress] returns Vesting struct data\n ///@dev can be used to easily check the vesting type / creation type based on the vesting address itself\n mapping(address => VestingCreationAndTypeDetails) public vestingCreationAndTypes;\n}\n" + }, + "contracts/governance/Vesting/VestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\n\n/**\n * @title Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for vesting.\n * It is parent of VestingLogic and TeamVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract VestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public cliff;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 constant FOUR_WEEKS = 4 weeks;\n}\n" + }, + "contracts/interfaces/IChai.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IERC20.sol\";\n\ninterface IPot {\n function dsr() external view returns (uint256);\n\n function chi() external view returns (uint256);\n\n function rho() external view returns (uint256);\n}\n\ncontract IChai is IERC20 {\n function move(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function join(address dst, uint256 wad) external;\n\n function draw(address src, uint256 wad) external;\n\n function exit(address src, uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IConverterAMM.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IConverterAMM {\n function withdrawFees(address receiver) external returns (uint256);\n}\n" + }, + "contracts/interfaces/IERC20.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ncontract IERC20 {\n string public name;\n uint8 public decimals;\n string public symbol;\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address _who) external view returns (uint256);\n\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/interfaces/IERC777.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777Token standard as defined in the EIP.\n *\n * This contract uses the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let\n * token holders and recipients react to token movements by using setting implementers\n * for the associated interfaces in said registry. See {IERC1820Registry} and\n * {ERC1820Implementer}.\n */\ninterface IERC777 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the smallest part of the token that is not divisible. This\n * means all token operations (creation, movement and destruction) must have\n * amounts that are a multiple of this number.\n *\n * For most token contracts, this value will equal 1.\n */\n function granularity() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by an account (`owner`).\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * If send or receive hooks are registered for the caller and `recipient`,\n * the corresponding functions will be called with `data` and empty\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes calldata data\n ) external;\n\n /**\n * @dev Destroys `amount` tokens from the caller's account, reducing the\n * total supply.\n *\n * If a send hook is registered for the caller, the corresponding function\n * will be called with `data` and empty `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n */\n function burn(uint256 amount, bytes calldata data) external;\n\n /**\n * @dev Returns true if an account is an operator of `tokenHolder`.\n * Operators can send and burn tokens on behalf of their owners. All\n * accounts are their own operator.\n *\n * See {operatorSend} and {operatorBurn}.\n */\n function isOperatorFor(address operator, address tokenHolder) external view returns (bool);\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor}.\n *\n * Emits an {AuthorizedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function authorizeOperator(address operator) external;\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor} and {defaultOperators}.\n *\n * Emits a {RevokedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function revokeOperator(address operator) external;\n\n /**\n * @dev Returns the list of default operators. These accounts are operators\n * for all token holders, even if {authorizeOperator} was never called on\n * them.\n *\n * This list is immutable, but individual holders may revoke these via\n * {revokeOperator}, in which case {isOperatorFor} will return false.\n */\n function defaultOperators() external view returns (address[] memory);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must\n * be an operator of `sender`.\n *\n * If send or receive hooks are registered for `sender` and `recipient`,\n * the corresponding functions will be called with `data` and\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - `sender` cannot be the zero address.\n * - `sender` must have at least `amount` tokens.\n * - the caller must be an operator for `sender`.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n /**\n * @dev Destoys `amount` tokens from `account`, reducing the total supply.\n * The caller must be an operator of `account`.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `data` and `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n * - the caller must be an operator for `account`.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n event Sent(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Minted(\n address indexed operator,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Burned(\n address indexed operator,\n address indexed from,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event AuthorizedOperator(address indexed operator, address indexed tokenHolder);\n\n event RevokedOperator(address indexed operator, address indexed tokenHolder);\n}\n" + }, + "contracts/interfaces/IERC777Recipient.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.\n *\n * Accounts can be notified of {IERC777} tokens being sent to them by having a\n * contract implement this interface (contract holders can be their own\n * implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Recipient {\n /**\n * @dev Called by an {IERC777} token contract whenever tokens are being\n * moved or created into a registered account (`to`). The type of operation\n * is conveyed by `from` being the zero address or not.\n *\n * This call occurs _after_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the post-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/IERC777Sender.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensSender standard as defined in the EIP.\n *\n * {IERC777} Token holders can be notified of operations performed on their\n * tokens by having a contract implement this interface (contract holders can be\n * their own implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Sender {\n /**\n * @dev Called by an {IERC777} token contract whenever a registered holder's\n * (`from`) tokens are about to be moved or destroyed. The type of operation\n * is conveyed by `to` being the zero address or not.\n *\n * This call occurs _before_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the pre-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/ILoanPool.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface ILoanPool {\n function tokenPrice() external view returns (uint256 price);\n\n function borrowInterestRate() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/ILoanTokenModules.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\ninterface ILoanTokenModules {\n /** EVENT */\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /// topic: 0x9bbd2de400810774339120e2f8a2b517ed748595e944529bba8ebabf314d0591\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n\n /** INTERFACE */\n\n /** START LOAN TOKEN SETTINGS LOWER ADMIN */\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n\n function setAdmin(address _admin) external;\n\n function setPauser(address _pauser) external;\n\n function setupLoanParams(LoanParams[] calldata loanParamsList, bool areTorqueLoans) external;\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external;\n\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) external;\n\n function toggleFunctionPause(\n string calldata funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) external;\n\n function setTransactionLimits(address[] calldata addresses, uint256[] calldata limits)\n external;\n\n function changeLoanTokenNameAndSymbol(string calldata _name, string calldata _symbol) external;\n\n /** END LOAN TOKEN SETTINGS LOWER ADMIN */\n\n /** START LOAN TOKEN LOGIC STANDARD */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n address affiliateReferrer, // The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes // Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function borrowInterestRate() external view returns (uint256);\n\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n\n function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid);\n\n function checkPause(string calldata funcId) external view returns (bool isPaused);\n\n function nextBorrowInterestRate(uint256 borrowAmount) external view returns (uint256);\n\n function totalAssetBorrow() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes calldata /// loanDataBytes: arbitrary order data (for future use).\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n );\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function setLiquidityMiningAddress(address LMAddress) external;\n\n function getLiquidityMiningAddress() external view returns (address);\n\n function setStakingContractAddress(address _stakingContractAddress) external;\n\n function getStakingContractAddress() external view returns (address);\n\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n external\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n );\n\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 depositAmount);\n\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 borrowAmount);\n\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) external view;\n\n function getMaxEscrowAmount(uint256 leverageAmount)\n external\n view\n returns (uint256 maxEscrowAmount);\n\n function checkpointPrice(address _user) external view returns (uint256 price);\n\n function assetBalanceOf(address _owner) external view returns (uint256);\n\n function profitOf(address user) external view returns (int256);\n\n function tokenPrice() external view returns (uint256 price);\n\n function avgBorrowInterestRate() external view returns (uint256);\n\n function supplyInterestRate() external view returns (uint256);\n\n function nextSupplyInterestRate(uint256 supplyAmount) external view returns (uint256);\n\n function totalSupplyInterestRate(uint256 assetSupply) external view returns (uint256);\n\n function loanTokenAddress() external view returns (address);\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n external\n view\n returns (uint256, uint256);\n\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external;\n\n /** START LOAN TOKEN BASE */\n function initialPrice() external view returns (uint256);\n\n /** START LOAN TOKEN LOGIC LM */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external returns (uint256 minted);\n\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 redeemed);\n\n /** START LOAN TOKEN LOGIC WRBTC */\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n returns (uint256 mintAmount);\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function marketLiquidity() external view returns (uint256);\n\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n external\n view\n returns (uint256);\n\n /** START LOAN TOKEN LOGIC STORAGE */\n function pauser() external view returns (address);\n\n function liquidityMiningAddress() external view returns (address);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n /** START ADVANCED TOKEN */\n function approve(address _spender, uint256 _value) external returns (bool);\n\n /** START ADVANCED TOKEN STORAGE */\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function balanceOf(address _owner) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function loanParamsIds(uint256) external view returns (bytes32);\n}\n" + }, + "contracts/interfaces/ISovryn.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\npragma experimental ABIEncoderV2;\n//TODO: stored in ./interfaces only while brownie isn't removed\n//TODO: move to contracts/interfaces after with brownie is removed\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\ncontract ISovryn is\n State,\n ProtocolSettingsEvents,\n LoanSettingsEvents,\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n LoanClosingsEvents,\n SwapsEvents,\n AffiliatesEvents,\n FeesEvents\n{\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n ////// Protocol //////\n\n function replaceContract(address target) external;\n\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\n\n function getTarget(string calldata sig) external view returns (address);\n\n ////// Protocol Settings //////\n\n function setSovrynProtocolAddress(address newProtocolAddress) external;\n\n function setSOVTokenAddress(address newSovTokenAddress) external;\n\n function setLockedSOVAddress(address newSOVLockedAddress) external;\n\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\n\n function setPriceFeedContract(address newContract) external;\n\n function setSwapsImplContract(address newContract) external;\n\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\n\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\n\n function setLendingFeePercent(uint256 newValue) external;\n\n function setTradingFeePercent(uint256 newValue) external;\n\n function setBorrowingFeePercent(uint256 newValue) external;\n\n function setSwapExternalFeePercent(uint256 newValue) external;\n\n function setAffiliateFeePercent(uint256 newValue) external;\n\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\n\n function setLiquidationIncentivePercent(uint256 newAmount) external;\n\n function setMaxDisagreement(uint256 newAmount) external;\n\n function setSourceBuffer(uint256 newAmount) external;\n\n function setMaxSwapSize(uint256 newAmount) external;\n\n function setFeesController(address newController) external;\n\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n returns (address, bool);\n\n function depositProtocolToken(uint256 amount) external;\n\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function setWrbtcToken(address wrbtcTokenAddress) external;\n\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\n\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\n\n function setRolloverBaseReward(uint256 transactionCost) external;\n\n function setRebatePercent(uint256 rebatePercent) external;\n\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external;\n\n function getSpecialRebates(address sourceToken, address destToken)\n external\n view\n returns (uint256 specialRebatesPercent);\n\n function togglePaused(bool paused) external;\n\n function isProtocolPaused() external view returns (bool);\n\n ////// Loan Settings //////\n\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function getLoanParams(bytes32[] calldata loanParamsIdList)\n external\n view\n returns (LoanParams[] memory loanParamsList);\n\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n\n ////// Loan Openings //////\n\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external;\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n ////// Loan Closings //////\n\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n );\n\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata loanDataBytes\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n ////// Loan Maintenance //////\n\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount // must match msg.value if ether is sent\n ) external payable;\n\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 actualWithdrawAmount);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n );\n\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; // collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\n\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\n\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external returns (uint256 secondsExtended);\n\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 secondsReduced);\n\n ////// Swaps External //////\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view;\n\n ////// Affiliates Module //////\n\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\n\n function setUserNotFirstTradeFlag(address user) external;\n\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\n\n function getReferralsList(address referrer) external view returns (address[] memory refList);\n\n function getAffiliatesReferrerBalances(address referrer)\n external\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\n\n function getAffiliatesReferrerTokensList(address referrer)\n external\n view\n returns (address[] memory tokensList);\n\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n external\n view\n returns (uint256);\n\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) external;\n\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\n\n function getProtocolAddress() external view returns (address);\n\n function getSovTokenAddress() external view returns (address);\n\n function getLockedSOVAddress() external view returns (address);\n\n function getFeeRebatePercent() external view returns (uint256);\n\n function getMinReferralsToPayout() external view returns (uint256);\n\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\n\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\n\n function getAffiliateTradingTokenFeePercent()\n external\n view\n returns (uint256 affiliateTradingTokenFeePercent);\n\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount);\n\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\n\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\n\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\n\n function getDedicatedSOVRebate() external view returns (uint256);\n\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\n\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory);\n\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\n\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external;\n\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\n\n function setAdmin(address newAdmin) external;\n\n function getAdmin() external view returns (address);\n\n function setPauser(address newPauser) external;\n\n function getPauser() external view returns (address);\n}\n" + }, + "contracts/interfaces/IWrbtc.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface IWrbtc {\n function deposit() external payable;\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IWrbtcERC20.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IWrbtc.sol\";\nimport \"./IERC20.sol\";\n\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\n" + }, + "contracts/locked/ILockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title The Locked SOV Interface.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This interface is an incomplete yet useful for future migration of LockedSOV Contract.\n * @dev Only use it if you know what you are doing.\n */\ninterface ILockedSOV {\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external;\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external;\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external;\n\n function cliff() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function getLockedBalance(address _addr) external view returns (uint256 _balance);\n\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance);\n}\n" + }, + "contracts/locked/LockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../governance/Vesting/VestingRegistry.sol\";\nimport \"../governance/Vesting/VestingLogic.sol\";\nimport \"./ILockedSOV.sol\";\n\n/**\n * @title The Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This contract is used to receive reward from other contracts, Create Vesting and Stake Tokens.\n */\ncontract LockedSOV is ILockedSOV {\n using SafeMath for uint256;\n\n uint256 public constant MAX_BASIS_POINT = 10000;\n uint256 public constant MAX_DURATION = 37;\n\n /* Storage */\n\n /// @notice True if the migration to a new Locked SOV Contract has started.\n bool public migration;\n\n /// @notice The cliff is the time period after which the tokens begin to unlock.\n uint256 public cliff;\n /// @notice The duration is the time period after all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n /// @notice The Vesting registry contract.\n VestingRegistry public vestingRegistry;\n /// @notice The New (Future) Locked SOV.\n ILockedSOV public newLockedSOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) private lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) private unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) private isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /// @notice Emitted when Vesting Registry, Duration and/or Cliff is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vestingRegistry The Vesting Registry Contract.\n /// @param _cliff The time period after which the tokens begin to unlock.\n /// @param _duration The time period after all tokens will have been unlocked.\n event RegistryCliffAndDurationUpdated(\n address indexed _initiator,\n address indexed _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n );\n\n /// @notice Emitted when a new deposit is made.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user to whose un/locked balance a new deposit was made.\n /// @param _sovAmount The amount of SOV to be added to the un/locked balance.\n /// @param _basisPoint The % (in Basis Point) which determines how much will be unlocked immediately.\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n /// @notice Emitted when a user withdraws the fund.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _sovAmount The amount of SOV withdrawn from the unlocked balance.\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n /// @notice Emitted when a user creates a vesting for himself.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _vesting The Vesting Contract.\n event VestingCreated(\n address indexed _initiator,\n address indexed _userAddress,\n address indexed _vesting\n );\n\n /// @notice Emitted when a user stakes tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vesting The Vesting Contract.\n /// @param _amount The amount of locked tokens staked by the user.\n event TokenStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /// @notice Emitted when an admin initiates a migration to new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedSOV The address of the new Locked SOV Contract.\n event MigrationStarted(address indexed _initiator, address indexed _newLockedSOV);\n\n /// @notice Emitted when a user initiates the transfer to a new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of locked tokens to transfer from this contract to the new one.\n event UserTransfered(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n modifier migrationAllowed {\n require(migration, \"Migration has not yet started.\");\n _;\n }\n\n /* Constructor */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV Token Address.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @param _admins The list of Admins to be added.\n */\n constructor(\n address _SOV,\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration,\n address[] memory _admins\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_vestingRegistry != address(0), \"Vesting registry address is invalid.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n SOV = IERC20(_SOV);\n vestingRegistry = VestingRegistry(_vestingRegistry);\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /* Public or External Functions */\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n * @dev Only callable by an Admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address.\");\n require(!isAdmin[_newAdmin], \"Address is already admin.\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n * @dev Only callable by an Admin.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin.\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice The function to update the Vesting Registry, Duration and Cliff.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @dev IMPORTANT 1: You have to change Vesting Registry if you want to change Duration and/or Cliff.\n * IMPORTANT 2: `_cliff` and `_duration` is multiplied by 4 weeks in this function.\n */\n function changeRegistryCliffAndDuration(\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAdmin {\n require(\n address(vestingRegistry) != _vestingRegistry,\n \"Vesting Registry has to be different for changing duration and cliff.\"\n );\n /// If duration is also zero, then it is similar to Unlocked SOV.\n require(_duration != 0, \"Duration cannot be zero.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n vestingRegistry = VestingRegistry(_vestingRegistry);\n\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n emit RegistryCliffAndDurationUpdated(msg.sender, _vestingRegistry, _cliff, _duration);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // MAX_BASIS_POINT is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < MAX_BASIS_POINT, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(MAX_BASIS_POINT);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice A function to withdraw the unlocked balance.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdraw(address _receiverAddress) public {\n _withdraw(msg.sender, _receiverAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n /**\n * @notice Creates vesting if not already created and Stakes tokens for a user.\n * @dev Only use this function if the `duration` is small.\n */\n function createVestingAndStake() public {\n _createVestingAndStake(msg.sender);\n }\n\n function _createVestingAndStake(address _sender) private {\n address vestingAddr = _getVesting(_sender);\n\n if (vestingAddr == address(0)) {\n vestingAddr = _createVesting(_sender);\n }\n\n _stakeTokens(_sender, vestingAddr);\n }\n\n /**\n * @notice Creates vesting contract (if it hasn't been created yet) for the calling user.\n * @return _vestingAddress The New Vesting Contract Created.\n */\n function createVesting() public returns (address _vestingAddress) {\n _vestingAddress = _createVesting(msg.sender);\n }\n\n /**\n * @notice Stakes tokens for a user who already have a vesting created.\n * @dev The user should already have a vesting created, else this function will throw error.\n */\n function stakeTokens() public {\n VestingLogic vesting = VestingLogic(_getVesting(msg.sender));\n\n require(\n cliff == vesting.cliff() && duration == vesting.duration(),\n \"Wrong Vesting Schedule.\"\n );\n\n _stakeTokens(msg.sender, address(vesting));\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdrawAndStakeTokens(address _receiverAddress) external {\n _withdraw(msg.sender, _receiverAddress);\n _createVestingAndStake(msg.sender);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n /**\n * @notice Function to start the process of migration to new contract.\n * @param _newLockedSOV The new locked sov contract address.\n */\n function startMigration(address _newLockedSOV) external onlyAdmin {\n require(_newLockedSOV != address(0), \"New Locked SOV Address is Invalid.\");\n newLockedSOV = ILockedSOV(_newLockedSOV);\n SOV.approve(_newLockedSOV, SOV.balanceOf(address(this)));\n migration = true;\n\n emit MigrationStarted(msg.sender, _newLockedSOV);\n }\n\n /**\n * @notice Function to transfer the locked balance from this contract to new LockedSOV Contract.\n * @dev Address is not specified to discourage selling lockedSOV to other address.\n */\n function transfer() external migrationAllowed {\n uint256 amount = lockedBalances[msg.sender];\n lockedBalances[msg.sender] = 0;\n\n newLockedSOV.depositSOV(msg.sender, amount);\n\n emit UserTransfered(msg.sender, amount);\n }\n\n /* Internal Functions */\n\n /**\n * @notice Creates a Vesting Contract for a user.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n * @dev Does not do anything if Vesting Contract was already created.\n */\n function _createVesting(address _tokenOwner) internal returns (address _vestingAddress) {\n /// Here zero is given in place of amount, as amount is not really used in `vestingRegistry.createVesting()`.\n vestingRegistry.createVesting(_tokenOwner, 0, cliff, duration);\n _vestingAddress = _getVesting(_tokenOwner);\n emit VestingCreated(msg.sender, _tokenOwner, _vestingAddress);\n }\n\n /**\n * @notice Returns the Vesting Contract Address.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n */\n function _getVesting(address _tokenOwner) internal view returns (address _vestingAddress) {\n return vestingRegistry.getVesting(_tokenOwner);\n }\n\n /**\n * @notice Stakes the tokens in a particular vesting contract.\n * @param _vesting The Vesting Contract Address.\n */\n function _stakeTokens(address _sender, address _vesting) internal {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n require(SOV.approve(_vesting, amount), \"Approve failed.\");\n VestingLogic(_vesting).stakeTokens(amount);\n\n emit TokenStaked(_sender, _vesting, amount);\n }\n\n /* Getter or Read Functions */\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) external view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n\n /**\n * @notice The function to check is an address is admin or not.\n * @param _addr The address of the user to check the admin status.\n * @return _status True if admin, False otherwise.\n */\n function adminStatus(address _addr) external view returns (bool _status) {\n return isAdmin[_addr];\n }\n}\n" + }, + "contracts/mixins/EnumerableAddressSet.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Based on Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * As of v2.5.0, only `address` sets are supported.\n *\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\n *\n * _Available since v2.5.0._\n */\nlibrary EnumerableAddressSet {\n struct AddressSet {\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(address => uint256) index;\n address[] values;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n * Returns false if the value was already in the set.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n * Returns false if the value was not present in the set.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n // If the element we're deleting is the last one, we can just remove it without doing a swap\n if (lastIndex != toDeleteIndex) {\n address lastValue = set.values[lastIndex];\n\n // Move the last value to the index where the deleted value is\n set.values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n // Delete the index entry for the deleted value\n delete set.index[value];\n\n // Delete the old entry for the moved value\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns an array with all values in the set. O(N).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\n address[] memory output = new address[](set.values.length);\n for (uint256 i; i < set.values.length; i++) {\n output[i] = set.values[i];\n }\n return output;\n }\n\n /**\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n \n * @param start start index of chunk\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\n */\n function enumerateChunk(\n AddressSet storage set,\n uint256 start,\n uint256 count\n ) internal view returns (address[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = (set.values.length < end || count == 0) ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new address[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @dev Returns the number of elements on the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /** @dev Returns the element stored at position `index` in the set. O(1).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes32Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\n * */\nlibrary EnumerableBytes32Set {\n struct Bytes32Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes32 => uint256) index;\n bytes32[] values;\n }\n\n /**\n * @notice Add an address value to a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to add.\n *\n * @return False if the value was already in the set.\n */\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return addBytes32(set, value);\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove an address value from a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to remove.\n *\n * @return False if the address was not present in the set.\n */\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return removeBytes32(set, value);\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function containsAddress(Bytes32Set storage set, address addrvalue)\n internal\n view\n returns (bool)\n {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes32Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes32[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes32[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes4Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`.\n * */\nlibrary EnumerableBytes4Set {\n struct Bytes4Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes4 => uint256) index;\n bytes4[] values;\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes4 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes4Set storage set, bytes4 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes4Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes4[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes4[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes4Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes4Set storage set, uint256 index) internal view returns (bytes4) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/FeesHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ISovryn.sol\";\nimport \"../core/objects/LoanParamsStruct.sol\";\n\n/**\n * @title The Fees Helper contract.\n *\n * This contract calculates and pays lending/borrow fees and rewards.\n * */\ncontract FeesHelper is State, FeesEvents {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Calculate trading fee.\n * @param feeTokenAmount The amount of tokens to trade.\n * @return The fee of the trade.\n * */\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\n }\n\n /**\n * @notice Calculate swap external fee.\n * @param feeTokenAmount The amount of token to swap.\n * @return The fee of the swap.\n */\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\n }\n\n /*\n\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - tradingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);\n\t}*/\n\n /**\n * @notice Calculate the loan origination fee.\n * @param feeTokenAmount The amount of tokens to borrow.\n * @return The fee of the loan.\n * */\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\n /*\n\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - borrowingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);*/\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\n *\n * @param referrer The affiliate referrer address to send the reward to.\n * @param trader The account that performs this trade.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n *\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\n * */\n function _payTradingFeeToAffiliate(\n address referrer,\n address trader,\n address feeToken,\n uint256 tradingFee\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\n address(this)\n )\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n * */\n function _payTradingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 tradingFee\n ) internal {\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\n if (tradingFee != 0) {\n if (affiliatesUserReferrer[user] != address(0)) {\n _payTradingFeeToAffiliate(\n affiliatesUserReferrer[user],\n user,\n feeToken,\n protocolTradingFee\n );\n protocolTradingFee = (\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\n )\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\n }\n\n /// Increase the storage variable keeping track of the accumulated fees.\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\n protocolTradingFee\n );\n\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\n }\n }\n\n /**\n * @notice Settle the borrowing fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the borrowig fee is paid.\n * @param borrowingFee The height of the fee.\n * */\n function _payBorrowingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 borrowingFee\n ) internal {\n if (borrowingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\n\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\n }\n }\n\n /**\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\n * @param user The address to send the reward to.\n * @param feeToken The address of the token in which the lending fee is paid.\n * @param lendingFee The height of the fee.\n * */\n function _payLendingFee(\n address user,\n address feeToken,\n uint256 lendingFee\n ) internal {\n if (lendingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\n\n emit PayLendingFee(user, feeToken, lendingFee);\n\n //// NOTE: Lenders do not receive a fee reward ////\n }\n }\n\n /// Settle and pay borrowers based on the fees generated by their interest payments.\n function _settleFeeRewardForInterestExpense(\n LoanInterest storage loanInterestLocal,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n address user,\n uint256 interestTime\n ) internal {\n /// This represents the fee generated by a borrower's interest payment.\n uint256 interestExpenseFee =\n interestTime\n .sub(loanInterestLocal.updatedTimestamp)\n .mul(loanInterestLocal.owedPerDay)\n .mul(lendingFeePercent)\n .div(1 days * 10**20);\n\n loanInterestLocal.updatedTimestamp = interestTime;\n\n if (interestExpenseFee != 0) {\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\n }\n }\n\n /**\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associeated loan - used for logging only.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * */\n function _payFeeReward(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 feeAmount\n ) internal {\n uint256 rewardAmount;\n uint256 _feeRebatePercent = feeRebatePercent;\n address _priceFeeds = priceFeeds;\n\n if (specialRebates[feeToken][feeTokenPair] > 0) {\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\n }\n\n /// Note: this should be refactored.\n /// Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\n feeAmount.mul(_feeRebatePercent).div(10**20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n // Check the dedicated SOV that is used to pay trading rebate rewards\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"deposit(address,uint256,uint256)\",\n user,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n )\n );\n\n if (success) {\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\n\n emit EarnReward(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n } else {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n }\n}\n" + }, + "contracts/mixins/InterestUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"./FeesHelper.sol\";\n\n/**\n * @title The Interest User contract.\n *\n * This contract pays loan interests.\n * */\ncontract InterestUser is VaultController, FeesHelper {\n using SafeERC20 for IERC20;\n\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n /**\n * @notice Internal function to pay interest of a loan.\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * */\n function _payInterest(address lender, address interestToken) internal {\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\n\n uint256 interestOwedNow = 0;\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\n interestOwedNow = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(1 days);\n\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n\n if (interestOwedNow > lenderInterestLocal.owedTotal)\n interestOwedNow = lenderInterestLocal.owedTotal;\n\n if (interestOwedNow != 0) {\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\n\n _payInterestTransfer(lender, interestToken, interestOwedNow);\n }\n } else {\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n }\n }\n\n /**\n * @notice Internal function to transfer tokens for the interest of a loan.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * @param interestOwedNow The amount of interest to pay.\n * */\n function _payInterestTransfer(\n address lender,\n address interestToken,\n uint256 interestOwedNow\n ) internal {\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\n /// TODO: refactor: data incapsulation violation and DRY design principles\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\n\n _payLendingFee(lender, interestToken, lendingFee);\n\n /// Transfers the interest to the lender, less the interest fee.\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\n\n /// Event Log\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\n }\n}\n" + }, + "contracts/mixins/LiquidationHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\n/**\n * @title The Liquidation Helper contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract computes the liquidation amount.\n * */\ncontract LiquidationHelper is State {\n /**\n * @notice Compute how much needs to be liquidated in order to restore the\n * desired margin (maintenance + 5%).\n *\n * @param principal The total borrowed amount (in loan tokens).\n * @param collateral The collateral (in collateral tokens).\n * @param currentMargin The current margin.\n * @param maintenanceMargin The maintenance (minimum) margin.\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n *\n * @return maxLiquidatable The collateral you can get liquidating.\n * @return maxSeizable The loan you available for liquidation.\n * @return incentivePercent The discount on collateral.\n * */\n function _getLiquidationAmounts(\n uint256 principal,\n uint256 collateral,\n uint256 currentMargin,\n uint256 maintenanceMargin,\n uint256 collateralToLoanRate\n )\n internal\n view\n returns (\n uint256 maxLiquidatable,\n uint256 maxSeizable,\n uint256 incentivePercent\n )\n {\n incentivePercent = liquidationIncentivePercent;\n if (currentMargin > maintenanceMargin || collateralToLoanRate == 0) {\n return (maxLiquidatable, maxSeizable, incentivePercent);\n } else if (currentMargin <= incentivePercent) {\n return (principal, collateral, currentMargin);\n }\n\n /// 5 percentage points above maintenance.\n uint256 desiredMargin = maintenanceMargin.add(5 ether);\n\n /// maxLiquidatable = ((1 + desiredMargin)*principal - collateralToLoanRate*collateral) / (desiredMargin - 0.05)\n maxLiquidatable = desiredMargin.add(10**20).mul(principal).div(10**20);\n maxLiquidatable = maxLiquidatable.sub(collateral.mul(collateralToLoanRate).div(10**18));\n maxLiquidatable = maxLiquidatable.mul(10**20).div(desiredMargin.sub(incentivePercent));\n if (maxLiquidatable > principal) {\n maxLiquidatable = principal;\n }\n\n /// maxSeizable = maxLiquidatable * (1 + incentivePercent) / collateralToLoanRate\n maxSeizable = maxLiquidatable.mul(incentivePercent.add(10**20));\n maxSeizable = maxSeizable.div(collateralToLoanRate).div(100);\n if (maxSeizable > collateral) {\n maxSeizable = collateral;\n }\n\n return (maxLiquidatable, maxSeizable, incentivePercent);\n }\n}\n" + }, + "contracts/mixins/ModuleCommonFunctionalities.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\ncontract ModuleCommonFunctionalities is State {\n modifier whenNotPaused() {\n require(!pause, \"Paused\");\n _;\n }\n}\n" + }, + "contracts/mixins/ProtocolTokenUser.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\n\n/**\n * @title The Protocol Token User contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to withdraw protocol tokens.\n * */\ncontract ProtocolTokenUser is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Internal function to withdraw an amount of protocol tokens from this contract.\n *\n * @param receiver The address of the recipient.\n * @param amount The amount of tokens to withdraw.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function _withdrawProtocolToken(address receiver, uint256 amount)\n internal\n returns (address, bool)\n {\n uint256 withdrawAmount = amount;\n\n uint256 tokenBalance = protocolTokenHeld;\n if (withdrawAmount > tokenBalance) {\n withdrawAmount = tokenBalance;\n }\n if (withdrawAmount == 0) {\n return (protocolTokenAddress, false);\n }\n\n protocolTokenHeld = tokenBalance.sub(withdrawAmount);\n\n IERC20(protocolTokenAddress).safeTransfer(receiver, withdrawAmount);\n\n return (protocolTokenAddress, true);\n }\n}\n" + }, + "contracts/mixins/RewardHelper.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title The Reward Helper contract.\n * @notice This contract calculates the reward for rollover transactions.\n *\n * A rollover is a renewal of a deposit. Instead of liquidating a deposit\n * on maturity, you can roll it over into a new deposit. The outstanding\n * principal of the old deposit is rolled over with or without the interest\n * outstanding on it.\n * */\ncontract RewardHelper is State {\n using SafeMath for uint256;\n\n /**\n * @notice Calculate the reward of a rollover transaction.\n *\n * @param collateralToken The address of the collateral token.\n * @param loanToken The address of the loan token.\n * @param positionSize The amount of value of the position.\n *\n * @return The base fee + the flex fee.\n */\n function _getRolloverReward(\n address collateralToken,\n address loanToken,\n uint256 positionSize\n ) internal view returns (uint256 reward) {\n uint256 positionSizeInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(loanToken, collateralToken, positionSize);\n uint256 rolloverBaseRewardInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(\n address(wrbtcToken),\n collateralToken,\n rolloverBaseReward\n );\n\n return\n rolloverBaseRewardInCollateralToken\n .mul(2) /// baseFee\n .add(positionSizeInCollateralToken.mul(rolloverFlexFeePercent).div(10**20)); /// flexFee = 0.1% of position size\n }\n}\n" + }, + "contracts/mixins/VaultController.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\n\n/**\n * @title The Vault Controller contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to deposit and withdraw wrBTC and\n * other tokens from the vault.\n * */\ncontract VaultController is State {\n using SafeERC20 for IERC20;\n\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\n\n /**\n * @notice Deposit wrBTC into the vault.\n *\n * @param from The address of the account paying the deposit.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherDeposit(address from, uint256 value) internal {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n _wrbtcToken.deposit.value(value)();\n\n emit VaultDeposit(address(_wrbtcToken), from, value);\n }\n\n /**\n * @notice Withdraw wrBTC from the vault.\n *\n * @param to The address of the recipient.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherWithdraw(address to, uint256 value) internal {\n if (value != 0) {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n uint256 balance = address(this).balance;\n if (value > balance) {\n _wrbtcToken.withdraw(value - balance);\n }\n Address.sendValue(to, value);\n\n emit VaultWithdraw(address(_wrbtcToken), to, value);\n }\n }\n\n /**\n * @notice Deposit tokens into the vault.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying the deposit.\n * @param value The amount of tokens to transfer.\n */\n function vaultDeposit(\n address token,\n address from,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransferFrom(from, address(this), value);\n\n emit VaultDeposit(token, from, value);\n }\n }\n\n /**\n * @notice Withdraw tokens from the vault.\n *\n * @param token The address of the token instance.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultWithdraw(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransfer(to, value);\n\n emit VaultWithdraw(token, to, value);\n }\n }\n\n /**\n * @notice Transfer tokens from an account into another one.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultTransfer(\n address token,\n address from,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n if (from == address(this)) {\n IERC20(token).safeTransfer(to, value);\n } else {\n IERC20(token).safeTransferFrom(from, to, value);\n }\n }\n }\n\n /**\n * @notice Approve an allowance of tokens to be spent by an account.\n *\n * @param token The address of the token instance.\n * @param to The address of the spender.\n * @param value The amount of tokens to allow.\n */\n function vaultApprove(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\n IERC20(token).safeApprove(to, 0);\n }\n IERC20(token).safeApprove(to, value);\n }\n}\n" + }, + "contracts/mockup/BlockMockUp.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title Used to get and set mock block number.\n */\ncontract BlockMockUp {\n uint256 public blockNum;\n\n /**\n * @notice To get the `blockNum`.\n * @return _blockNum The block number.\n */\n function getBlockNum() public view returns (uint256 _blockNum) {\n return blockNum;\n }\n\n /**\n * @notice To set the `blockNum`.\n * @param _blockNum The block number.\n */\n function setBlockNum(uint256 _blockNum) public {\n blockNum = _blockNum;\n }\n}\n" + }, + "contracts/mockup/FeeSharingCollectorMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/FeeSharingCollector/FeeSharingCollector.sol\";\n\ncontract FeeSharingCollectorMockup is FeeSharingCollector {\n struct TestData {\n address loanPoolToken;\n uint32 maxCheckpoints;\n address receiver;\n }\n\n TestData public testData;\n\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n testData = TestData(_token, _maxCheckpoints, _receiver);\n }\n\n function trueWithdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function addCheckPoint(address loanPoolToken, uint256 poolTokenAmount) public {\n uint96 amount96 =\n safe96(\n poolTokenAmount,\n \"FeeSharingCollectorProxy::withdrawFees: pool token amount exceeds 96 bits\"\n );\n _addCheckpoint(loanPoolToken, amount96);\n }\n\n function setTotalTokenCheckpoints(address _token, uint256 qty) public {\n totalTokenCheckpoints[_token] = qty;\n }\n\n function setUserProcessedCheckpoints(\n address _user,\n address _token,\n uint256 num\n ) public {\n processedCheckpoints[_user][_token] = num;\n }\n\n function getFullAccumulatedFees(\n address _user,\n address _token,\n uint32 _maxCheckpoints\n ) public view returns (uint256 amount, uint256 end) {\n (amount, end) = _getAccumulatedFees(_user, _token, 0, _maxCheckpoints);\n }\n\n function endOfRangeWithZeroMaxCheckpoint(address _token) public view returns (uint256) {\n return _getEndOfRange(0, _token, 0);\n }\n\n function getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) public view returns (uint256 _tokenAmount, uint256 _endToken) {\n return _getRBTCBalance(_token, _user, _maxCheckpoints);\n }\n\n function testWithdrawReentrancy(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n}\n" + }, + "contracts/mockup/GovernorAlphaMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/GovernorAlpha.sol\";\n\ncontract GovernorAlphaMockup is GovernorAlpha {\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 quorumVotes_,\n uint96 _minPercentageVotes\n ) public GovernorAlpha(timelock_, staking_, guardian_, quorumVotes_, _minPercentageVotes) {}\n\n function votingPeriod() public pure returns (uint256) {\n return 10;\n }\n\n function queueProposals(uint256[] calldata proposalIds) external {\n for (uint256 i = 0; i < proposalIds.length; i++) {\n queue(proposalIds[i]);\n }\n }\n}\n" + }, + "contracts/mockup/LiquidityMiningMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract LiquidityMiningMockup is LiquidityMining {\n function getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n public\n view\n returns (uint256)\n {\n return _getPassedBlocksWithBonusMultiplier(_from, _to);\n }\n\n function getPoolAccumulatedReward(address _poolToken) public view returns (uint256, uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n return _getPoolAccumulatedReward(pool);\n }\n}\n" + }, + "contracts/mockup/LiquidityPoolV1ConverterMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/IERC20.sol\";\n\ncontract LiquidityPoolV1ConverterMockup {\n IERC20[] public reserveTokens;\n IERC20 wrbtcToken;\n uint256 totalFeeMockupValue;\n address feesController;\n\n constructor(IERC20 _token0, IERC20 _token1) public {\n reserveTokens.push(_token0);\n reserveTokens.push(_token1);\n }\n\n function setFeesController(address _feesController) public {\n feesController = _feesController;\n }\n\n function setWrbtcToken(IERC20 _wrbtcToken) public {\n wrbtcToken = _wrbtcToken;\n }\n\n function setTotalFeeMockupValue(uint256 _totalFeeMockupValue) public {\n totalFeeMockupValue = _totalFeeMockupValue;\n }\n\n function withdrawFees(address _receiver) external returns (uint256) {\n require(msg.sender == feesController, \"unauthorized\");\n\n // transfer wrbtc\n wrbtcToken.transfer(_receiver, totalFeeMockupValue);\n return totalFeeMockupValue;\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/LoanClosingsWith.sol\";\n\ncontract LoanClosingsWithMockup is LoanClosingsWith {\n function worthTheTransfer(address, uint256) internal returns (bool) {\n return true;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithoutInvariantCheck.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanClosingsWithMockup.sol\";\n\ncontract LoanClosingsWithoutInvariantCheck is LoanClosingsWithMockup {\n /** Override the modifier of invariant check so that we can test the shared reentrancy guard */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n _;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicLMMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\n\ncontract LoanTokenLogicLMMockup is LoanTokenLogicLM {\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n returns (uint256 loanAmountPaid)\n {\n _callOptionalReturn(\n 0x2c34D66a5ca8686330e100372Eb3FDFB5aEECD0B, //Random EOA for testing\n abi.encodeWithSelector(IERC20(receiver).transfer.selector, receiver, burnAmount),\n \"error\"\n );\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicV2Mockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicV1Mockup is LoanTokenLogicStandard {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](27);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n // res[31] = this.totalSupply.selector;\n res[25] = this.balanceOf.selector;\n res[26] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n\ncontract LoanTokenLogicV2Mockup is LoanTokenLogicStandard {\n function testNewFunction() external pure returns (bool) {\n return true;\n }\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](29);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mockup\n res[28] = this.testNewFunction.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/mockup/lockedSOVFailedMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An interface for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete interface of the Locked SOV Contract.\n */\ncontract LockedSOVFailedMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The user balances.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n revert(\"For testing purposes\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/LockedSOVMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An mockup for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete mockup of the Locked SOV Contract.\n */\ncontract LockedSOVMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n event TokensStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // 10000 is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < 10000, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(10000);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n function _createVestingAndStake(address _sender) private {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n emit TokensStaked(_sender, address(0), amount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/MockAffiliates.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/Affiliates.sol\";\n\ncontract MockAffiliates is Affiliates {\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n }\n}\n" + }, + "contracts/mockup/MockFourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/Vesting/fouryear/FourYearVestingLogic.sol\";\n\ncontract MockFourYearVestingLogic is FourYearVestingLogic {\n /**\n * @notice gets duration left\n */\n function getDurationLeft() external view returns (uint256) {\n return durationLeft;\n }\n}\n" + }, + "contracts/mockup/MockLoanTokenLogic.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogic is LoanTokenLogic {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](31);\n\n // Loan Token Logic\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mock\n res[28] = this.setAffiliatesReferrer.selector;\n res[29] = this.setUserNotFirstTradeFlag.selector;\n res[30] = this.getMarginBorrowAmountAndRate.selector;\n\n return (res, stringToBytes32(\"MockLoanTokenLogic\"));\n }\n\n function setAffiliatesReferrer(address user, address referrer) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(user, referrer);\n }\n\n function setUserNotFirstTradeFlag(address user) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(user);\n }\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n\n /*function initialize(address target) external onlyOwner {\n\t\t_setTarget(this.setAffiliatesUserReferrer.selector, target);\n\t}*/\n}\n\ncontract ILoanTokenModulesMock is ILoanTokenModules {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user) external;\n}\n" + }, + "contracts/mockup/MockLoanTokenLogicLM.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogicLM is LoanTokenLogicLM {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n /** LoanTokenLogicLM function signature */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\"));\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\"));\n res[2] = bytes4(keccak256(\"burn(address,uint256)\"));\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\"));\n\n return (res, stringToBytes32(\"MockLoanTokenLogicLM\"));\n }\n}\n" + }, + "contracts/mockup/modules/IWeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract IWeightedStakingModuleMockup {\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) external;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) external;\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external;\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) external;\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/mockup/modules/StakingModuleBlockMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/StakingGovernanceModule.sol\";\nimport \"../../governance/Staking/modules/StakingStakeModule.sol\";\nimport \"../../governance/Staking/modules/StakingVestingModule.sol\";\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../BlockMockUp.sol\";\n\ncontract StakingModuleBlockMockup is\n IFunctionsList,\n StakingGovernanceModule,\n StakingStakeModule,\n StakingVestingModule,\n WeightedStakingModule\n{\n uint96 public priorWeightedStake;\n mapping(uint256 => uint96) public priorWeightedStakeAtBlock;\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n function balanceOf_MultipliedByTwo(address account) external view returns (uint256) {\n return this.balanceOf(account) * 2;\n }\n\n uint96 priorTotalVotingPower;\n\n function MOCK_priorTotalVotingPower(uint96 _priorTotalVotingPower) public {\n priorTotalVotingPower = _priorTotalVotingPower;\n }\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n return\n priorTotalVotingPower != 0\n ? priorTotalVotingPower\n : super.getPriorTotalVotingPower(blockNumber, time);\n }\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) public view returns (bool) {\n bytes32 codeHash = _getCodeHash(stakerAddress);\n return vestingCodeHashes[codeHash];\n }\n\n function getPriorWeightedStakeAtBlock(uint256 blockNum) public view returns (uint256) {\n return uint256(priorWeightedStakeAtBlock[blockNum]);\n }\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n // StakingGovernanceModule\n bytes4[] memory functionsList = new bytes4[](31);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n\n // StakingStakeModule\n functionsList[6] = this.stake.selector;\n functionsList[7] = this.stakeWithApproval.selector;\n functionsList[8] = this.extendStakingDuration.selector;\n functionsList[9] = this.stakesBySchedule.selector;\n functionsList[10] = this.stakeBySchedule.selector;\n functionsList[11] = this.balanceOf.selector;\n functionsList[12] = this.getCurrentStakedUntil.selector;\n functionsList[13] = this.getStakes.selector;\n functionsList[14] = this.timestampToLockDate.selector;\n\n //StakingVestingModule\n functionsList[15] = this.setVestingRegistry.selector;\n functionsList[16] = this.setVestingStakes.selector;\n functionsList[17] = this.getPriorUserStakeByDate.selector;\n functionsList[18] = this.getPriorVestingWeightedStake.selector;\n functionsList[19] = this.getPriorVestingStakeByDate.selector;\n functionsList[20] = this.addContractCodeHash.selector;\n functionsList[21] = this.removeContractCodeHash.selector;\n functionsList[22] = this.isVestingContract.selector;\n\n //BlockMockup\n functionsList[23] = this.setBlockMockUpAddr.selector;\n functionsList[24] = this.MOCK_priorWeightedStake.selector;\n functionsList[25] = this.MOCK_priorWeightedStakeAtBlock.selector;\n\n //WeightedStakingModule\n functionsList[26] = this.getPriorWeightedStake.selector;\n functionsList[27] = this.weightedStakeByDate.selector;\n functionsList[28] = this.computeWeightByDate.selector;\n functionsList[29] = this.priorWeightedStakeAtBlock.selector;\n functionsList[30] = this.getPriorWeightedStakeAtBlock.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/modules/StakingSharedModuleMock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/shared/StakingShared.sol\";\nimport \"../BlockMockUp.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\n\ncontract StakingModuleMock is IFunctionsList, StakingShared {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](1);\n functionList[0] = this.setBlockMockUpAddr.selector;\n }\n}\n" + }, + "contracts/mockup/modules/StakingWrapperMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\ncontract StakingWrapperMockup {\n uint256 constant TWO_WEEKS = 1209600;\n\n IStaking staking;\n IERC20 token;\n\n constructor(IStaking _staking, IERC20 _token) public {\n staking = _staking;\n token = _token;\n }\n\n function stake2times(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stake(amount, until, stakeFor, delegatee);\n }\n\n function stakeAndExtend(uint96 amount, uint256 until) external {\n require(token.transferFrom(msg.sender, address(this), amount));\n token.approve(address(staking), amount);\n\n staking.stake(amount, until, address(this), address(this));\n staking.extendStakingDuration(until, until + TWO_WEEKS);\n }\n\n function stakeAndStakeBySchedule(\n uint96 amount,\n uint256 until,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n}\n" + }, + "contracts/mockup/modules/WeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract WeightedStakingModuleMockup is WeightedStakingModule {\n uint96 priorWeightedStake;\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n mapping(uint256 => uint96) priorWeightedStakeAtBlock;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n functionsList[3] = this.MOCK_priorWeightedStake.selector;\n functionsList[4] = this.MOCK_priorWeightedStakeAtBlock.selector;\n functionsList[5] = this.calculatePriorWeightedStake.selector;\n functionsList[6] = this.setDelegateStake.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n//@todo can I change this proxy to EIP-1822 proxy standard, please. https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\ncontract PreviousLoanToken is AdvancedTokenStorage {\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../connectors/loantoken/interfaces/ProtocolSettingsLike.sol\";\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n// It is a LoanToken implementation!\ncontract PreviousLoanTokenSettingsLowerAdmin is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress\n\n // ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n // ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n //@todo check for restrictions in this contract\n modifier onlyAdmin() {\n require(msg.sender == address(this) || msg.sender == owner(), \"unauthorized\");\n _;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function init(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans // isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n // These params should be percentages represented like so: 5% = 5000000000000000000\n // rateMultiplier + baseRate can't exceed 100%\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; // 80 ether\n kinkLevel = _kinkLevel; // 90 ether\n maxScaleRate = _maxScaleRate; // 100 ether\n }\n\n function toggleFunctionPause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyAdmin {\n // keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /**\n * sets the transaction limit per token address\n * @param addresses the token addresses\n * @param limits the limit denominated in the currency of the token address\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyOwner\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n}\n" + }, + "contracts/mockup/PriceFeedsMoCMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../feeds/testnet/PriceFeedsMoC.sol\";\n\n// This contract is only for test purposes\n// https://github.com/money-on-chain/Amphiraos-Oracle/blob/master/contracts/medianizer/medianizer.sol\ncontract PriceFeedsMoCMockup is Medianizer {\n uint256 public value;\n bool public has;\n\n function peek() external view returns (bytes32, bool) {\n return (bytes32(value), has);\n }\n\n function setValue(uint256 _value) public {\n value = _value;\n }\n\n function setHas(bool _has) public {\n has = _has;\n }\n}\n" + }, + "contracts/mockup/ProtocolSettingsMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/ProtocolSettings.sol\";\n\ncontract ProtocolSettingsMockup is ProtocolSettings {\n function setLendingFeeTokensHeld(address token, uint256 amout) public {\n lendingFeeTokensHeld[token] = amout;\n }\n\n function setTradingFeeTokensHeld(address token, uint256 amout) public {\n tradingFeeTokensHeld[token] = amout;\n }\n\n function setBorrowingFeeTokensHeld(address token, uint256 amout) public {\n borrowingFeeTokensHeld[token] = amout;\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n\n _setTarget(this.setLendingFeeTokensHeld.selector, target);\n _setTarget(this.setTradingFeeTokensHeld.selector, target);\n _setTarget(this.setBorrowingFeeTokensHeld.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n }\n}\n" + }, + "contracts/mockup/proxy/ImplementationMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\n\ncontract ImplementationMockup is StorageMockup {\n function setValue(uint256 _value) public {\n value = _value;\n emit ValueChanged(_value);\n }\n\n function getValue() public view returns (uint256) {\n return value;\n }\n}\n" + }, + "contracts/mockup/proxy/ProxyMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract ProxyMockup is StorageMockup, UpgradableProxy {}\n" + }, + "contracts/mockup/proxy/StorageMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\ncontract StorageMockup {\n uint256 value;\n\n event ValueChanged(uint256 value);\n}\n" + }, + "contracts/mockup/RBTCWrapperProxyMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract RBTCWrapperProxyMockup {\n LiquidityMining public liquidityMining;\n\n constructor(LiquidityMining _liquidityMining) public {\n liquidityMining = _liquidityMining;\n }\n\n function claimReward(address _poolToken) public {\n liquidityMining.claimReward(_poolToken, msg.sender);\n }\n\n function claimRewardFromAllPools() public {\n liquidityMining.claimRewardFromAllPools(msg.sender);\n }\n\n function withdraw(address _poolToken, uint256 _amount) public {\n liquidityMining.withdraw(_poolToken, _amount, msg.sender);\n }\n}\n" + }, + "contracts/mockup/StakingRewardsMockUp.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/StakingRewards/StakingRewards.sol\";\nimport \"./BlockMockUp.sol\";\n\n/**\n * @title Staking Rewards Contract MockUp\n * @notice This is used for Testing\n * */\ncontract StakingRewardsMockUp is StakingRewards {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n using SafeMath for uint256;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n}\n" + }, + "contracts/mockup/TimelockHarness.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"../governance/Timelock.sol\";\n\ninterface Administered {\n function _acceptAdmin() external returns (uint256);\n}\n\ncontract TimelockHarness is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, delay_) {}\n\n function setDelayWithoutChecking(uint256 delay_) public {\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function harnessSetPendingAdmin(address pendingAdmin_) public {\n pendingAdmin = pendingAdmin_;\n }\n\n function harnessSetAdmin(address admin_) public {\n admin = admin_;\n }\n}\n\ncontract TimelockTest is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, 2 days) {\n delay = delay_;\n }\n\n function harnessSetAdmin(address admin_) public {\n require(msg.sender == admin);\n admin = admin_;\n }\n\n function harnessAcceptAdmin(Administered administered) public {\n administered._acceptAdmin();\n }\n}\n" + }, + "contracts/mockup/VestingLogicMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/Vesting/VestingLogic.sol\";\n\ncontract VestingLogicMockup is VestingLogic {\n /**\n * @dev we had a bug in a loop: \"i < endDate\" instead of \"i <= endDate\"\n */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n}\n" + }, + "contracts/mockup/VestingRegistryLogicMockUp.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\nimport \"../governance/Vesting/VestingRegistryLogic.sol\";\n\ncontract VestingRegistryLogicMockup is VestingRegistryLogic {\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return true;\n }\n\n function setTeamVesting(address _vesting, uint256 _vestingCreationType) external {\n vestingCreationAndTypes[_vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(VestingType.TeamVesting),\n vestingCreationType: uint128(_vestingCreationType)\n });\n }\n}\n" + }, + "contracts/modules/Affiliates.sol": { + "content": "/**\n * Copyright 2017-2020, Sovryn, All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Affiliates contract.\n * @notice Track referrals and reward referrers (affiliates) with tokens.\n * In-detail specifications are found at https://wiki.sovryn.app/en/community/Affiliates\n * @dev Module: Affiliates upgradable\n * Storage: from State, functions called from Protocol by delegatecall\n */\ncontract Affiliates is State, AffiliatesEvents, ModuleCommonFunctionalities {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Void constructor.\n */\n // solhint-disable-next-line no-empty-blocks\n constructor() public {}\n\n /**\n * @notice Avoid calls to this contract except for those explicitly declared.\n */\n function() external {\n revert(\"Affiliates - fallback not allowed\");\n }\n\n /**\n * @notice Set delegate callable functions by proxy contract.\n * @dev This contract is designed as a module, this way logic can be\n * expanded and upgraded w/o losing storage that is kept in the protocol (State.sol)\n * initialize() is used to register in the proxy external (module) functions\n * to be called via the proxy.\n * @param target The address of a new logic implementation.\n */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setAffiliatesReferrer.selector];\n _setTarget(this.setAffiliatesReferrer.selector, target);\n _setTarget(this.getUserNotFirstTradeFlag.selector, target);\n _setTarget(this.getReferralsList.selector, target);\n _setTarget(this.setUserNotFirstTradeFlag.selector, target);\n _setTarget(this.payTradingFeeToAffiliatesReferrer.selector, target);\n _setTarget(this.getAffiliatesReferrerBalances.selector, target);\n _setTarget(this.getAffiliatesReferrerTokenBalance.selector, target);\n _setTarget(this.getAffiliatesReferrerTokensList.selector, target);\n _setTarget(this.withdrawAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.withdrawAllAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.getMinReferralsToPayout.selector, target);\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n _setTarget(this.getAffiliateRewardsHeld.selector, target);\n _setTarget(this.getAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.getAffiliatesTokenRewardsValueInRbtc.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"Affiliates\");\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from loan pools.\n */\n modifier onlyCallableByLoanPools() {\n require(loanPoolToUnderlying[msg.sender] != address(0), \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from within protocol functions.\n */\n modifier onlyCallableInternal() {\n require(msg.sender == protocolAddress, \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Data structure comprised of 3 flags to compute the result of setting a referrer.\n */\n struct SetAffiliatesReferrerResult {\n bool success;\n bool alreadySet;\n bool userNotFirstTradeFlag;\n }\n\n /**\n * @notice Loan pool calls this function to tell affiliates\n * a user coming from a referrer is trading and should be registered if not yet.\n * Taking into account some user status flags may lead to the user and referrer\n * become added or not to the affiliates record.\n *\n * @param user The address of the user that is trading on loan pools.\n * @param referrer The address of the referrer the user is coming from.\n */\n function setAffiliatesReferrer(address user, address referrer)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n SetAffiliatesReferrerResult memory result;\n\n result.userNotFirstTradeFlag = getUserNotFirstTradeFlag(user);\n result.alreadySet = affiliatesUserReferrer[user] != address(0);\n result.success = !(result.userNotFirstTradeFlag || result.alreadySet || user == referrer);\n if (result.success) {\n affiliatesUserReferrer[user] = referrer;\n referralsList[referrer].add(user);\n emit SetAffiliatesReferrer(user, referrer);\n } else {\n emit SetAffiliatesReferrerFail(\n user,\n referrer,\n result.alreadySet,\n result.userNotFirstTradeFlag\n );\n }\n }\n\n /**\n * @notice Getter to query the referrals coming from a referrer.\n * @param referrer The address of a given referrer.\n * @return The referralsList mapping value by referrer.\n */\n function getReferralsList(address referrer) external view returns (address[] memory refList) {\n refList = referralsList[referrer].enumerate();\n return refList;\n }\n\n /**\n * @notice Getter to query the not-first-trade flag of a user.\n * @param user The address of a given user.\n * @return The userNotFirstTradeFlag mapping value by user.\n */\n function getUserNotFirstTradeFlag(address user) public view returns (bool) {\n return userNotFirstTradeFlag[user];\n }\n\n /**\n * @notice Setter to toggle on the not-first-trade flag of a user.\n * @param user The address of a given user.\n */\n function setUserNotFirstTradeFlag(address user)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n if (!userNotFirstTradeFlag[user]) {\n userNotFirstTradeFlag[user] = true;\n emit SetUserNotFirstTradeFlag(user);\n }\n }\n\n /**\n * @notice Internal getter to query the fee share for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function _getAffiliatesTradingFeePercentForSOV() internal view returns (uint256) {\n return affiliateFeePercent;\n }\n\n /**\n * @notice Internal to calculate the affiliates trading token fee amount.\n * Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * This _getReferrerTradingFeeForToken calculates the first one\n * by applying a custom percentage multiplier.\n * @param feeTokenAmount The trading token fee amount.\n * @return The affiliates share of the trading token fee amount.\n */\n function _getReferrerTradingFeeForToken(uint256 feeTokenAmount)\n internal\n view\n returns (uint256)\n {\n return feeTokenAmount.mul(getAffiliateTradingTokenFeePercent()).div(10**20);\n }\n\n /**\n * @notice Getter to query the fee share of trading token fee for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function getAffiliateTradingTokenFeePercent() public view returns (uint256) {\n return affiliateTradingTokenFeePercent;\n }\n\n /**\n * @notice Getter to query referral threshold for paying out to the referrer.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The minimum number of referrals set by Protocol.\n */\n function getMinReferralsToPayout() public view returns (uint256) {\n return minReferralsToPayout;\n }\n\n /**\n * @notice Get the sovToken reward of a trade.\n * @dev The reward is worth x% of the trading fee.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * @return The reward amount.\n * */\n function _getSovBonusAmount(address feeToken, uint256 feeAmount)\n internal\n view\n returns (uint256)\n {\n uint256 rewardAmount;\n address _priceFeeds = priceFeeds;\n\n /// @dev Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// dest token = SOV\n feeAmount.mul(_getAffiliatesTradingFeePercentForSOV()).div(1e20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n return rewardAmount;\n }\n\n /**\n * @notice Protocol calls this function to pay the affiliates rewards to a user (referrer).\n *\n * @dev Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * Both are paid in this function.\n *\n * @dev Actually they are not paid, but just holded by protocol until user claims them by\n * actively calling withdrawAffiliatesReferrerTokenFees() function,\n * and/or when unvesting lockedSOV.\n *\n * @dev To be precise, what this function does is updating the registers of the rewards\n * for the referrer including the assignment of the SOV tokens as rewards to the\n * referrer's vesting contract.\n *\n * @param referrer The address of the referrer.\n * @param trader The address of the trader.\n * @param token The address of the token in which the trading/borrowing fee was paid.\n * @param tradingFeeTokenBaseAmount Total trading fee amount, the base for calculating referrer's fees.\n *\n * @return referrerBonusSovAmount The amount of SOV tokens paid to the referrer (through a vesting contract, lockedSOV).\n * @return referrerBonusTokenAmount The amount of trading tokens paid directly to the referrer.\n */\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n )\n external\n onlyCallableInternal\n whenNotPaused\n returns (uint256 referrerBonusSovAmount, uint256 referrerBonusTokenAmount)\n {\n bool isHeld = referralsList[referrer].length() < getMinReferralsToPayout();\n bool bonusPaymentIsSuccess = true;\n uint256 paidReferrerBonusSovAmount;\n\n /// Process token fee rewards first.\n referrerBonusTokenAmount = _getReferrerTradingFeeForToken(tradingFeeTokenBaseAmount);\n if (!affiliatesReferrerTokensList[referrer].contains(token))\n affiliatesReferrerTokensList[referrer].add(token);\n affiliatesReferrerBalances[referrer][token] = affiliatesReferrerBalances[referrer][token]\n .add(referrerBonusTokenAmount);\n\n /// Then process SOV rewards.\n referrerBonusSovAmount = _getSovBonusAmount(token, tradingFeeTokenBaseAmount);\n uint256 rewardsHeldByProtocol = affiliateRewardsHeld[referrer];\n\n if (isHeld) {\n /// If referrals less than minimum, temp the rewards SOV to the storage\n affiliateRewardsHeld[referrer] = rewardsHeldByProtocol.add(referrerBonusSovAmount);\n } else {\n /// If referrals >= minimum, directly send all of the remain rewards to locked sov\n /// Call depositSOV() in LockedSov contract\n /// Set the affiliaterewardsheld = 0\n if (affiliateRewardsHeld[referrer] > 0) {\n affiliateRewardsHeld[referrer] = 0;\n }\n\n paidReferrerBonusSovAmount = referrerBonusSovAmount.add(rewardsHeldByProtocol);\n IERC20(sovTokenAddress).approve(lockedSOVAddress, paidReferrerBonusSovAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"depositSOV(address,uint256)\",\n referrer,\n paidReferrerBonusSovAmount\n )\n );\n\n if (!success) {\n bonusPaymentIsSuccess = false;\n }\n }\n\n if (bonusPaymentIsSuccess) {\n emit PayTradingFeeToAffiliate(\n referrer,\n trader, // trader\n token,\n isHeld,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n } else {\n emit PayTradingFeeToAffiliateFail(\n referrer,\n trader, // trader\n token,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n }\n\n return (referrerBonusSovAmount, referrerBonusTokenAmount);\n }\n\n /**\n * @notice Referrer calls this function to receive its reward in a given token.\n * It will send the other (non-SOV) reward tokens from trading protocol fees,\n * to the referrer’s wallet.\n * @dev Rewards are held by protocol in different tokens coming from trading fees.\n * Referrer has to claim them one by one for every token with accumulated balance.\n * @param token The address of the token to withdraw.\n * @param receiver The address of the withdrawal beneficiary.\n * @param amount The amount of tokens to claim. If greater than balance, just sends balance.\n */\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) public whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n uint256 referrerTokenBalance = affiliatesReferrerBalances[referrer][token];\n uint256 withdrawAmount = referrerTokenBalance > amount ? amount : referrerTokenBalance;\n\n require(withdrawAmount > 0, \"Affiliates: cannot withdraw zero amount\");\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n uint256 newReferrerTokenBalance = referrerTokenBalance.sub(withdrawAmount);\n\n if (newReferrerTokenBalance == 0) {\n _removeAffiliatesReferrerToken(referrer, token);\n } else {\n affiliatesReferrerBalances[referrer][token] = newReferrerTokenBalance;\n }\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawAffiliatesReferrerTokenFees(referrer, receiver, token, withdrawAmount);\n }\n\n /**\n * @notice Withdraw to msg.sender all token fees for a referrer.\n * @dev It's done by looping through its available tokens.\n * @param receiver The address of the withdrawal beneficiary.\n */\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n (address[] memory tokenAddresses, uint256[] memory tokenBalances) =\n getAffiliatesReferrerBalances(referrer);\n for (uint256 i; i < tokenAddresses.length; i++) {\n withdrawAffiliatesReferrerTokenFees(tokenAddresses[i], receiver, tokenBalances[i]);\n }\n }\n\n /**\n * @notice Internal function to delete a referrer's token balance.\n * @param referrer The address of the referrer.\n * @param token The address of the token specifying the balance to remove.\n */\n function _removeAffiliatesReferrerToken(address referrer, address token) internal {\n delete affiliatesReferrerBalances[referrer][token];\n affiliatesReferrerTokensList[referrer].remove(token);\n }\n\n /**\n * @notice Get all token balances of a referrer.\n * @param referrer The address of the referrer.\n * @return referrerTokensList The array of available tokens (keys).\n * @return referrerTokensBalances The array of token balances (values).\n */\n function getAffiliatesReferrerBalances(address referrer)\n public\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances)\n {\n referrerTokensList = getAffiliatesReferrerTokensList(referrer);\n referrerTokensBalances = new uint256[](referrerTokensList.length);\n for (uint256 i; i < referrerTokensList.length; i++) {\n referrerTokensBalances[i] = getAffiliatesReferrerTokenBalance(\n referrer,\n referrerTokensList[i]\n );\n }\n return (referrerTokensList, referrerTokensBalances);\n }\n\n /**\n * @dev Get all token rewards estimation value in rbtc.\n *\n * @param referrer Address of referrer.\n *\n * @return The value estimation in rbtc.\n */\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount)\n {\n address[] memory tokensList = getAffiliatesReferrerTokensList(referrer);\n address _priceFeeds = priceFeeds;\n\n for (uint256 i; i < tokensList.length; i++) {\n // Get the value of each token in rbtc\n\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n tokensList[i], // source token\n address(wrbtcToken), // dest token = SOV\n affiliatesReferrerBalances[referrer][tokensList[i]] // total token rewards\n )\n );\n\n assembly {\n if eq(success, 1) {\n rbtcTotalAmount := add(rbtcTotalAmount, mload(add(data, 32)))\n }\n }\n }\n }\n\n /**\n * @notice Get all available tokens at the affiliates program for a given referrer.\n * @param referrer The address of a given referrer.\n * @return tokensList The list of available tokens.\n */\n function getAffiliatesReferrerTokensList(address referrer)\n public\n view\n returns (address[] memory tokensList)\n {\n tokensList = affiliatesReferrerTokensList[referrer].enumerate();\n return tokensList;\n }\n\n /**\n * @notice Getter to query the affiliate balance for a given referrer and token.\n * @param referrer The address of the referrer.\n * @param token The address of the token to get balance for.\n * @return The affiliatesReferrerBalances mapping value by referrer and token keys.\n */\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n public\n view\n returns (uint256)\n {\n return affiliatesReferrerBalances[referrer][token];\n }\n\n /**\n * @notice Getter to query the address of referrer for a given user.\n * @param user The address of the user.\n * @return The address on affiliatesUserReferrer mapping value by user key.\n */\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user];\n }\n\n /**\n * @notice Getter to query the reward amount held for a given referrer.\n * @param referrer The address of the referrer.\n * @return The affiliateRewardsHeld mapping value by referrer key.\n */\n function getAffiliateRewardsHeld(address referrer) public view returns (uint256) {\n return affiliateRewardsHeld[referrer];\n }\n}\n" + }, + "contracts/modules/interfaces/ProtocolAffiliatesInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolAffiliatesInterface {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user_) external;\n\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\n\n function payTradingFeeToAffiliatesReferrer(\n address affiliate,\n address trader,\n address token,\n uint256 amount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n}\n" + }, + "contracts/modules/interfaces/ProtocolSwapExternalInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolSwapExternalInterface {\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n}\n" + }, + "contracts/modules/LoanClosingsLiquidation.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsLiquidation contract.\n * @notice Ways to close a loan: liquidation. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsLiquidation is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.liquidate.selector];\n _setTarget(this.liquidate.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsLiquidation\"\n );\n }\n\n /**\n * @notice Liquidate an unhealty loan.\n *\n * @dev Public wrapper for _liquidate internal function.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * loanId is the ID of the loan, which is created on loan opening.\n * It can be obtained either by parsing the Trade event or by reading\n * the open loans from the contract by calling getActiveLoans or getUserLoans.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n return _liquidate(loanId, receiver, closeAmount);\n }\n\n /**\n * @notice Internal function for liquidating an unhealthy loan.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function _liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin <= loanParamsLocal.maintenanceMargin, \"healthy position\");\n\n loanCloseAmount = closeAmount;\n\n //amounts to restore the desired margin (maintencance + 5%)\n (uint256 maxLiquidatable, uint256 maxSeizable, ) =\n _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n\n if (loanCloseAmount < maxLiquidatable) {\n //close maxLiquidatable if tiny position will remain\n uint256 remainingAmount = maxLiquidatable - loanCloseAmount;\n remainingAmount = _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingAmount <= TINY_AMOUNT) {\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable.mul(loanCloseAmount).div(maxLiquidatable);\n }\n } else if (loanCloseAmount > maxLiquidatable) {\n // adjust down the close amount to the max\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable;\n }\n\n require(loanCloseAmount != 0, \"nothing to liquidate\");\n\n // liquidator deposits the principal being closed\n _returnPrincipalWithDeposit(loanParamsLocal.loanToken, address(this), loanCloseAmount);\n\n // a portion of the principal is repaid to the lender out of interest refunded\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n loanLocal.borrower\n );\n\n if (loanCloseAmount > loanCloseAmountLessInterest) {\n // full interest refund goes to the borrower\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanCloseAmount - loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmountLessInterest != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n seizedToken = loanParamsLocal.collateralToken;\n\n if (seizedAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(seizedAmount);\n\n _withdrawAsset(seizedToken, receiver, seizedAmount);\n }\n\n _closeLoan(loanLocal, loanCloseAmount);\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n seizedAmount,\n collateralToLoanRate,\n 0,\n currentMargin,\n CloseTypes.Liquidation\n );\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsRollover.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsRollover contract.\n * @notice Ways to close a loan: rollover. Margin trade\n * positions are always closed with a swap.\n *\n * */\ncontract LoanClosingsRollover is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.rollover.selector];\n _setTarget(this.rollover.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsRollover\"\n );\n }\n\n /**\n * @notice Roll over a loan.\n *\n * @dev Public wrapper for _rollover internal function.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * The function rollover on the protocol contract extends the loan\n * duration by the maximum term (28 days for margin trades at the moment\n * of writing), pays the interest to the lender and refunds the caller\n * for the gas cost by sending 2 * the gas cost using the fast gas price\n * as base for the calculation.\n *\n * @param loanId The ID of the loan to roll over.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n * */\n function rollover(\n bytes32 loanId,\n bytes calldata // for future use /*loanDataBytes*/\n ) external nonReentrant globallyNonReentrant iTokenSupplyUnchanged(loanId) whenNotPaused {\n // restrict to EOAs to prevent griefing attacks, during interest rate recalculation\n require(msg.sender == tx.origin, \"EOAs call\");\n\n return\n _rollover(\n loanId,\n \"\" // loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for roll over a loan.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * @param loanId The ID of the loan to roll over.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n * */\n function _rollover(bytes32 loanId, bytes memory loanDataBytes) internal {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n require(block.timestamp > loanLocal.endTimestamp.sub(3600), \"healthy position\");\n require(loanPoolToUnderlying[loanLocal.lender] != address(0), \"invalid lender\");\n\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n // Handle back interest: calculates interest owned since the loan endtime passed but the loan remained open\n uint256 backInterestTime;\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestTime = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestTime.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(1 days);\n }\n\n //note: to avoid code duplication, it would be nicer to store loanParamsLocal.maxLoanTerm in a local variable\n //however, we've got stack too deep issues if we do so.\n if (loanParamsLocal.maxLoanTerm != 0) {\n // fixed-term loan, so need to query iToken for latest variable rate\n uint256 owedPerDay =\n loanLocal.principal.mul(ILoanPool(loanLocal.lender).borrowInterestRate()).div(\n 365 * 10**20\n );\n\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(\n loanInterestLocal.owedPerDay\n );\n\n loanInterestLocal.owedPerDay = owedPerDay;\n\n //if the loan has been open for longer than an additional period, add at least 1 additional day\n if (backInterestTime >= loanParamsLocal.maxLoanTerm) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n }\n //extend by the max loan term\n else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(loanParamsLocal.maxLoanTerm);\n }\n } else {\n // loanInterestLocal.owedPerDay doesn't change\n if (backInterestTime >= MONTH) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n } else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(MONTH);\n }\n }\n\n uint256 interestAmountRequired = loanLocal.endTimestamp.sub(block.timestamp);\n interestAmountRequired = interestAmountRequired.mul(loanInterestLocal.owedPerDay);\n interestAmountRequired = interestAmountRequired.div(1 days);\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n\n // add backInterestOwed\n interestAmountRequired = interestAmountRequired.add(backInterestOwed);\n\n // collect interest (needs to be converted from the collateral)\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n 0, //min swap 0 -> swap connector estimates the amount of source tokens to use\n interestAmountRequired, //required destination tokens\n true, // returnTokenIsCollateral\n loanDataBytes\n );\n\n //received more tokens than needed to pay the interest\n if (destTokenAmountReceived > interestAmountRequired) {\n // swap rest back to collateral, if the amount is big enough to cover gas cost\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n )\n ) {\n (destTokenAmountReceived, , ) = _swapBackExcess(\n loanLocal,\n loanParamsLocal,\n destTokenAmountReceived - interestAmountRequired, //amount to be swapped\n loanDataBytes\n );\n sourceTokenAmountUsed = sourceTokenAmountUsed.sub(destTokenAmountReceived);\n }\n //else give it to the protocol as a lending fee\n else {\n _payLendingFee(\n loanLocal.borrower,\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n );\n }\n }\n\n //subtract the interest from the collateral\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n if (backInterestOwed != 0) {\n // pay out backInterestOwed\n\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n uint256 rolloverReward =\n _getRolloverReward(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.principal\n );\n\n if (rolloverReward != 0) {\n // if the reward > collateral:\n if (rolloverReward > loanLocal.collateral) {\n // 1. pay back the remaining loan to the lender\n // 2. pay the remaining collateral to msg.sender\n // 3. close the position & emit close event\n _closeWithSwap(\n loanLocal.id,\n msg.sender,\n loanLocal.collateral,\n false,\n \"\" // loanDataBytes\n );\n } else {\n // pay out reward to caller\n loanLocal.collateral = loanLocal.collateral.sub(rolloverReward);\n\n _withdrawAsset(loanParamsLocal.collateralToken, msg.sender, rolloverReward);\n }\n }\n\n if (loanLocal.collateral > 0) {\n //close whole loan if tiny position will remain\n if (_getAmountInRbtc(loanParamsLocal.loanToken, loanLocal.principal) <= TINY_AMOUNT) {\n _closeWithSwap(\n loanLocal.id,\n loanLocal.borrower,\n loanLocal.collateral, // swap all collaterals\n false,\n \"\" /// loanDataBytes\n );\n } else {\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n require(\n currentMargin > 3 ether, // ensure there's more than 3% margin remaining\n \"unhealthy position\"\n );\n }\n }\n\n if (loanLocal.active) {\n emit Rollover(\n loanLocal.borrower, // user (borrower)\n loanLocal.lender, // lender\n loanLocal.id, // loanId\n loanLocal.principal, // principal\n loanLocal.collateral, // collateral\n loanLocal.endTimestamp, // endTimestamp\n msg.sender, // rewardReceiver\n rolloverReward // reward\n );\n }\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsShared.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/RewardHelper.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\n/**\n * @title LoanClosingsShared contract.\n * @notice This contract should only contains the internal function that is being used / utilized by\n * LoanClosingsLiquidation, LoanClosingsRollover & LoanClosingsWith contract\n *\n * */\ncontract LoanClosingsShared is\n LoanClosingsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n RewardHelper,\n ModuleCommonFunctionalities\n{\n uint256 internal constant MONTH = 365 days / 12;\n //0.00001 BTC, would be nicer in State.sol, but would require a redeploy of the complete protocol, so adding it here instead\n //because it's not shared state anyway and only used by this contract\n uint256 public constant paySwapExcessToBorrowerThreshold = 10000000000000;\n\n uint256 public constant TINY_AMOUNT = 25e13;\n\n enum CloseTypes { Deposit, Swap, Liquidation }\n\n /** modifier for invariant check */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n Loan storage loanLocal = loans[loanId];\n\n require(loanLocal.lender != address(0), \"Invalid loan token pool address\");\n\n uint256 previousITokenSupply = ILoanTokenModules(loanLocal.lender).totalSupply();\n\n _;\n\n /// Validate iToken total supply\n require(\n previousITokenSupply == ILoanTokenModules(loanLocal.lender).totalSupply(),\n \"loan token supply invariant check failure\"\n );\n }\n\n /**\n * @dev computes the interest which needs to be refunded to the borrower based on the amount he's closing and either\n * subtracts it from the amount which still needs to be paid back (in case outstanding amount > interest) or withdraws the\n * excess to the borrower (in case interest > outstanding).\n * @param loanLocal the loan\n * @param loanParamsLocal the loan params\n * @param loanCloseAmount the amount to be closed (base for the computation)\n * @param receiver the address of the receiver (usually the borrower)\n * */\n function _settleInterestToPrincipal(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 loanCloseAmount,\n address receiver\n ) internal returns (uint256) {\n uint256 loanCloseAmountLessInterest = loanCloseAmount;\n\n //compute the interest which neeeds to be refunded to the borrower (because full interest is paid on loan )\n uint256 interestRefundToBorrower =\n _settleInterest(loanParamsLocal, loanLocal, loanCloseAmountLessInterest);\n\n uint256 interestAppliedToPrincipal;\n //if the outstanding loan is bigger than the interest to be refunded, reduce the amount to be paid back / closed by the interest\n if (loanCloseAmountLessInterest >= interestRefundToBorrower) {\n // apply all of borrower interest refund torwards principal\n interestAppliedToPrincipal = interestRefundToBorrower;\n\n // principal needed is reduced by this amount\n loanCloseAmountLessInterest -= interestRefundToBorrower;\n\n // no interest refund remaining\n interestRefundToBorrower = 0;\n } else {\n //if the interest refund is bigger than the outstanding loan, the user needs to get back the interest\n // principal fully covered by excess interest\n interestAppliedToPrincipal = loanCloseAmountLessInterest;\n\n // amount refunded is reduced by this amount\n interestRefundToBorrower -= loanCloseAmountLessInterest;\n\n // principal fully covered by excess interest\n loanCloseAmountLessInterest = 0;\n\n if (interestRefundToBorrower != 0) {\n // refund overage\n _withdrawAsset(loanParamsLocal.loanToken, receiver, interestRefundToBorrower);\n }\n }\n\n //pay the interest to the lender\n //note: this is a waste of gas, because the loanCloseAmountLessInterest is withdrawn to the lender, too. It could be done at once.\n if (interestAppliedToPrincipal != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, interestAppliedToPrincipal);\n }\n\n return loanCloseAmountLessInterest;\n }\n\n // The receiver always gets back an ERC20 (even wrbtc)\n function _returnPrincipalWithDeposit(\n address loanToken,\n address receiver,\n uint256 principalNeeded\n ) internal {\n if (principalNeeded != 0) {\n if (msg.value == 0) {\n vaultTransfer(loanToken, msg.sender, receiver, principalNeeded);\n } else {\n require(loanToken == address(wrbtcToken), \"wrong asset sent\");\n require(msg.value >= principalNeeded, \"not enough ether\");\n wrbtcToken.deposit.value(principalNeeded)();\n if (receiver != address(this)) {\n vaultTransfer(loanToken, address(this), receiver, principalNeeded);\n }\n if (msg.value > principalNeeded) {\n // refund overage\n Address.sendValue(msg.sender, msg.value - principalNeeded);\n }\n }\n } else {\n require(msg.value == 0, \"wrong asset sent\");\n }\n }\n\n /**\n * @dev checks if the amount of the asset to be transfered is worth the transfer fee\n * @param asset the asset to be transfered\n * @param amount the amount to be transfered\n * @return True if the amount is bigger than the threshold\n * */\n function worthTheTransfer(address asset, uint256 amount) internal returns (bool) {\n uint256 amountInRbtc = _getAmountInRbtc(asset, amount);\n emit swapExcess(\n amountInRbtc > paySwapExcessToBorrowerThreshold,\n amount,\n amountInRbtc,\n paySwapExcessToBorrowerThreshold\n );\n\n return amountInRbtc > paySwapExcessToBorrowerThreshold;\n }\n\n /**\n * swaps collateral tokens for loan tokens\n * @param loanLocal the loan object\n * @param loanParamsLocal the loan parameters\n * @param swapAmount the amount to be swapped\n * @param principalNeeded the required destination token amount\n * @param returnTokenIsCollateral if true -> required destination token amount will be passed on, else not\n * note: quite dirty. should be refactored.\n * @param loanDataBytes additional loan data (not in use for token swaps)\n * */\n function _doCollateralSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n loanLocal.collateral, // maxSourceTokenAmount\n returnTokenIsCollateral\n ? principalNeeded // requiredDestTokenAmount\n : 0,\n false, // bypassFee\n loanDataBytes\n );\n require(destTokenAmountReceived >= principalNeeded, \"insufficient dest amount\");\n require(sourceTokenAmountUsed <= loanLocal.collateral, \"excessive source amount\");\n }\n\n /**\n * @notice Withdraw asset to receiver.\n *\n * @param assetToken The loan token.\n * @param receiver The address of the receiver.\n * @param assetAmount The loan token amount.\n * */\n function _withdrawAsset(\n address assetToken,\n address receiver,\n uint256 assetAmount\n ) internal {\n if (assetAmount != 0) {\n if (assetToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, assetAmount);\n } else {\n vaultWithdraw(assetToken, receiver, assetAmount);\n }\n }\n }\n\n /**\n * @notice Internal function to close a loan.\n *\n * @param loanLocal The loan object.\n * @param loanCloseAmount The amount to close: principal or lower.\n *\n * */\n function _closeLoan(Loan storage loanLocal, uint256 loanCloseAmount) internal {\n require(loanCloseAmount != 0, \"nothing to close\");\n\n if (loanCloseAmount == loanLocal.principal) {\n loanLocal.principal = 0;\n loanLocal.active = false;\n loanLocal.endTimestamp = block.timestamp;\n loanLocal.pendingTradesId = 0;\n activeLoansSet.removeBytes32(loanLocal.id);\n lenderLoanSets[loanLocal.lender].removeBytes32(loanLocal.id);\n borrowerLoanSets[loanLocal.borrower].removeBytes32(loanLocal.id);\n } else {\n loanLocal.principal = loanLocal.principal.sub(loanCloseAmount);\n }\n }\n\n function _settleInterest(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 closePrincipal\n ) internal returns (uint256) {\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 interestTime = block.timestamp;\n if (interestTime > loanLocal.endTimestamp) {\n interestTime = loanLocal.endTimestamp;\n }\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n interestTime\n );\n\n uint256 owedPerDayRefund;\n if (closePrincipal < loanLocal.principal) {\n owedPerDayRefund = loanInterestLocal.owedPerDay.mul(closePrincipal).div(\n loanLocal.principal\n );\n } else {\n owedPerDayRefund = loanInterestLocal.owedPerDay;\n }\n\n // update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.sub(owedPerDayRefund);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(owedPerDayRefund);\n\n // update borrower interest\n uint256 interestRefundToBorrower = loanLocal.endTimestamp.sub(interestTime);\n interestRefundToBorrower = interestRefundToBorrower.mul(owedPerDayRefund);\n interestRefundToBorrower = interestRefundToBorrower.div(1 days);\n\n if (closePrincipal < loanLocal.principal) {\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(\n interestRefundToBorrower\n );\n } else {\n loanInterestLocal.depositTotal = 0;\n }\n\n // update remaining lender interest values\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.sub(\n closePrincipal\n );\n\n uint256 owedTotal = lenderInterestLocal.owedTotal;\n lenderInterestLocal.owedTotal = owedTotal > interestRefundToBorrower\n ? owedTotal - interestRefundToBorrower\n : 0;\n\n return interestRefundToBorrower;\n }\n\n /**\n * @notice Check sender is borrower or delegatee and loan id exists.\n *\n * @param loanId byte32 of the loan id.\n * */\n function _checkAuthorized(bytes32 loanId) internal view {\n Loan storage loanLocal = loans[loanId];\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n }\n\n /**\n * @notice Internal function for closing a position by swapping the\n * collateral back to loan tokens, paying the lender and withdrawing\n * the remainder.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collatral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid\n * out in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(swapAmount != 0, \"swapAmount == 0\");\n\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't swap more than collateral.\n swapAmount = swapAmount > loanLocal.collateral ? loanLocal.collateral : swapAmount;\n\n //close whole loan if tiny position will remain\n if (loanLocal.collateral - swapAmount > 0) {\n if (\n _getAmountInRbtc(\n loanParamsLocal.collateralToken,\n loanLocal.collateral - swapAmount\n ) <= TINY_AMOUNT\n ) {\n swapAmount = loanLocal.collateral;\n }\n }\n\n uint256 loanCloseAmountLessInterest;\n if (swapAmount == loanLocal.collateral || returnTokenIsCollateral) {\n /// loanCloseAmountLessInterest will be passed as required amount amount of destination tokens.\n /// this means, the actual swapAmount passed to the swap contract does not matter at all.\n /// the source token amount will be computed depending on the required amount amount of destination tokens.\n loanCloseAmount = swapAmount == loanLocal.collateral\n ? loanLocal.principal\n : loanLocal.principal.mul(swapAmount).div(loanLocal.collateral);\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Computes the interest refund for the borrower and sends it to the lender to cover part of the principal.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n } else {\n /// loanCloseAmount is calculated after swap; for this case we want to swap the entire source amount\n /// and determine the loanCloseAmount and withdraw amount based on that.\n loanCloseAmountLessInterest = 0;\n }\n\n uint256 coveredPrincipal;\n uint256 usedCollateral;\n\n /// swapAmount repurposed for collateralToLoanSwapRate to avoid stack too deep error.\n (coveredPrincipal, usedCollateral, withdrawAmount, swapAmount) = _coverPrincipalWithSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount, /// The amount of source tokens to swap (only matters if !returnTokenIsCollateral or loanCloseAmountLessInterest = 0)\n loanCloseAmountLessInterest, /// This is the amount of destination tokens we want to receive (only matters if returnTokenIsCollateral)\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (loanCloseAmountLessInterest == 0) {\n /// Condition prior to swap: swapAmount != loanLocal.collateral && !returnTokenIsCollateral\n\n /// Amounts that is closed.\n loanCloseAmount = coveredPrincipal;\n if (coveredPrincipal != loanLocal.principal) {\n loanCloseAmount = loanCloseAmount.mul(usedCollateral).div(loanLocal.collateral);\n }\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Amount that is returned to the lender.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n\n /// Remaining amount withdrawn to the receiver.\n withdrawAmount = withdrawAmount.add(coveredPrincipal).sub(loanCloseAmountLessInterest);\n } else {\n /// Pay back the amount which was covered by the swap.\n loanCloseAmountLessInterest = coveredPrincipal;\n }\n\n require(loanCloseAmountLessInterest != 0, \"closeAmount is 0 after swap\");\n\n /// Reduce the collateral by the amount which was swapped for the closure.\n if (usedCollateral != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(usedCollateral);\n }\n\n /// Repays principal to lender.\n /// The lender always gets back an ERC20 (even wrbtc), so we call\n /// withdraw directly rather than use the _withdrawAsset helper function.\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, loanCloseAmountLessInterest);\n\n withdrawToken = returnTokenIsCollateral\n ? loanParamsLocal.collateralToken\n : loanParamsLocal.loanToken;\n\n if (withdrawAmount != 0) {\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n usedCollateral,\n swapAmount, /// collateralToLoanSwapRate\n CloseTypes.Swap\n );\n }\n\n /**\n * @notice Close a loan.\n *\n * @dev Wrapper for _closeLoan internal function.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan params.\n * @param loanCloseAmount The amount to close: principal or lower.\n * @param collateralCloseAmount The amount of collateral to close.\n * @param collateralToLoanSwapRate The price rate collateral/loan token.\n * @param closeType The type of loan close.\n * */\n function _finalizeClose(\n Loan storage loanLocal,\n LoanParams storage loanParamsLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanSwapRate,\n CloseTypes closeType\n ) internal {\n _closeLoan(loanLocal, loanCloseAmount);\n\n address _priceFeeds = priceFeeds;\n uint256 currentMargin;\n uint256 collateralToLoanRate;\n\n /// This is still called even with full loan close to return collateralToLoanRate\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).getCurrentMargin.selector,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n )\n );\n assembly {\n if eq(success, 1) {\n currentMargin := mload(add(data, 32))\n collateralToLoanRate := mload(add(data, 64))\n }\n }\n /// Note: We can safely skip the margin check if closing\n /// via closeWithDeposit or if closing the loan in full by any method.\n require(\n closeType == CloseTypes.Deposit ||\n loanLocal.principal == 0 || /// loan fully closed\n currentMargin > loanParamsLocal.maintenanceMargin,\n \"unhealthy position\"\n );\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n collateralCloseAmount,\n collateralToLoanRate,\n collateralToLoanSwapRate,\n currentMargin,\n closeType\n );\n }\n\n /**\n * swaps a share of a loan's collateral or the complete collateral in order to cover the principle.\n * @param loanLocal the loan\n * @param loanParamsLocal the loan parameters\n * @param swapAmount in case principalNeeded == 0 or !returnTokenIsCollateral, this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens needed for the swap is estimated by the connector.\n * @param principalNeeded the required amount of destination tokens in order to cover the principle (only used if returnTokenIsCollateral)\n * @param returnTokenIsCollateral tells if the user wants to withdraw his remaining collateral + profit in collateral tokens\n * @notice Swaps a share of a loan's collateral or the complete collateral\n * in order to cover the principle.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount In case principalNeeded == 0 or !returnTokenIsCollateral,\n * this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens\n * needed for the swap is estimated by the connector.\n * @param principalNeeded The required amount of destination tokens in order to\n * cover the principle (only used if returnTokenIsCollateral).\n * @param returnTokenIsCollateral Tells if the user wants to withdraw his\n * remaining collateral + profit in collateral tokens.\n *\n * @return coveredPrincipal The amount of principal that is covered.\n * @return usedCollateral The amount of collateral used.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _coverPrincipalWithSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 coveredPrincipal,\n uint256 usedCollateral,\n uint256 withdrawAmount,\n uint256 collateralToLoanSwapRate\n )\n {\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n (\n destTokenAmountReceived,\n sourceTokenAmountUsed,\n collateralToLoanSwapRate\n ) = _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount,\n principalNeeded,\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (returnTokenIsCollateral) {\n coveredPrincipal = principalNeeded;\n\n /// Better fill than expected.\n if (destTokenAmountReceived > coveredPrincipal) {\n /// Send excess to borrower if the amount is big enough to be\n /// worth the gas fees.\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - coveredPrincipal\n )\n ) {\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n destTokenAmountReceived - coveredPrincipal\n );\n }\n /// Else, give the excess to the lender (if it goes to the\n /// borrower, they're very confused. causes more trouble than it's worth)\n else {\n coveredPrincipal = destTokenAmountReceived;\n }\n }\n withdrawAmount = swapAmount > sourceTokenAmountUsed\n ? swapAmount - sourceTokenAmountUsed\n : 0;\n } else {\n require(sourceTokenAmountUsed == swapAmount, \"swap error\");\n\n if (swapAmount == loanLocal.collateral) {\n /// sourceTokenAmountUsed == swapAmount == loanLocal.collateral\n\n coveredPrincipal = principalNeeded;\n withdrawAmount = destTokenAmountReceived - principalNeeded;\n } else {\n /// sourceTokenAmountUsed == swapAmount < loanLocal.collateral\n\n if (destTokenAmountReceived >= loanLocal.principal) {\n /// Edge case where swap covers full principal.\n\n coveredPrincipal = loanLocal.principal;\n withdrawAmount = destTokenAmountReceived - loanLocal.principal;\n\n /// Excess collateral refunds to the borrower.\n _withdrawAsset(\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n loanLocal.collateral - sourceTokenAmountUsed\n );\n sourceTokenAmountUsed = loanLocal.collateral;\n } else {\n coveredPrincipal = destTokenAmountReceived;\n withdrawAmount = 0;\n }\n }\n }\n\n usedCollateral = sourceTokenAmountUsed > swapAmount ? sourceTokenAmountUsed : swapAmount;\n }\n\n function _emitClosingEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanRate,\n uint256 collateralToLoanSwapRate,\n uint256 currentMargin,\n CloseTypes closeType\n ) internal {\n if (closeType == CloseTypes.Deposit) {\n emit CloseWithDeposit(\n loanLocal.borrower, /// user (borrower)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n msg.sender, /// closer\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n loanCloseAmount, /// loanCloseAmount\n collateralCloseAmount, /// collateralCloseAmount\n collateralToLoanRate, /// collateralToLoanRate\n currentMargin /// currentMargin\n );\n } else if (closeType == CloseTypes.Swap) {\n /// exitPrice = 1 / collateralToLoanSwapRate\n if (collateralToLoanSwapRate != 0) {\n collateralToLoanSwapRate = SafeMath.div(10**36, collateralToLoanSwapRate);\n }\n\n /// currentLeverage = 100 / currentMargin\n if (currentMargin != 0) {\n currentMargin = SafeMath.div(10**38, currentMargin);\n }\n\n emit CloseWithSwap(\n loanLocal.borrower, /// user (trader)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n msg.sender, /// closer\n collateralCloseAmount, /// positionCloseSize\n loanCloseAmount, /// loanCloseAmount\n collateralToLoanSwapRate, /// exitPrice (1 / collateralToLoanSwapRate)\n currentMargin /// currentLeverage\n );\n } else if (closeType == CloseTypes.Liquidation) {\n emit Liquidate(\n loanLocal.borrower, // user (borrower)\n msg.sender, // liquidator\n loanLocal.id, // loanId\n loanLocal.lender, // lender\n loanParamsLocal.loanToken, // loanToken\n loanParamsLocal.collateralToken, // collateralToken\n loanCloseAmount, // loanCloseAmount\n collateralCloseAmount, // collateralCloseAmount\n collateralToLoanRate, // collateralToLoanRate\n currentMargin // currentMargin\n );\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal view returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n IPriceFeeds(priceFeeds).queryRate(asset, address(wrbtcToken));\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /**\n * @dev private function which check the loanLocal & loanParamsLocal does exist\n *\n * @param loanId bytes32 of loanId\n *\n * @return Loan storage\n * @return LoanParams storage\n */\n function _checkLoan(bytes32 loanId) internal view returns (Loan storage, LoanParams storage) {\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n return (loanLocal, loanParamsLocal);\n }\n}\n" + }, + "contracts/modules/LoanClosingsWith.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsWith contract.\n * @notice Close a loan w/deposit, close w/swap. There are 2 functions for ending a loan on the\n * protocol contract: closeWithSwap and closeWithDeposit. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsWith is LoanClosingsShared {\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n\n /**\n * @notice Closes a loan by doing a deposit.\n *\n * @dev Public wrapper for _closeWithDeposit internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens. (e.g. rBTC on a iSUSD contract).\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n public\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return _closeWithDeposit(loanId, receiver, depositAmount);\n }\n\n /**\n * @notice Close a position by swapping the collateral back to loan tokens\n * paying the lender and withdrawing the remainder.\n *\n * @dev Public wrapper for _closeWithSwap internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collateral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid out\n * in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes memory // for future use /*loanDataBytes*/\n )\n public\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return\n _closeWithSwap(\n loanId,\n receiver,\n swapAmount,\n returnTokenIsCollateral,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for closing a loan by doing a deposit.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens.\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(depositAmount != 0, \"depositAmount == 0\");\n\n //TODO should we skip this check if invoked from rollover ?\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't close more than the full principal.\n loanCloseAmount = depositAmount > loanLocal.principal\n ? loanLocal.principal\n : depositAmount;\n\n //revert if tiny position remains\n uint256 remainingAmount = loanLocal.principal - loanCloseAmount;\n if (remainingAmount > 0) {\n require(\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount) > TINY_AMOUNT,\n \"Tiny amount when closing with deposit\"\n );\n }\n\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(loanLocal, loanParamsLocal, loanCloseAmount, receiver);\n\n if (loanCloseAmountLessInterest != 0) {\n _returnPrincipalWithDeposit(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmount == loanLocal.principal) {\n withdrawAmount = loanLocal.collateral;\n } else {\n withdrawAmount = loanLocal.collateral.mul(loanCloseAmount).div(loanLocal.principal);\n }\n\n withdrawToken = loanParamsLocal.collateralToken;\n\n if (withdrawAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(withdrawAmount);\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n withdrawAmount, /// collateralCloseAmount\n 0, /// collateralToLoanSwapRate\n CloseTypes.Deposit\n );\n }\n\n /**\n * @notice Function to check whether the given loanId & deposit amount when closing with deposit will cause the tiny position\n *\n * @param loanId The id of the loan.\n * @param depositAmount Defines how much the deposit amount to close the position.\n *\n * @return isTinyPosition true is indicating tiny position, false otherwise.\n * @return tinyPositionAmount will return 0 for non tiny position, and will return the amount of tiny position if true\n */\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount)\n {\n (Loan memory loanLocal, LoanParams memory loanParamsLocal) = _checkLoan(loanId);\n\n if (depositAmount < loanLocal.principal) {\n uint256 remainingAmount = loanLocal.principal - depositAmount;\n uint256 remainingRBTCAmount =\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingRBTCAmount < TINY_AMOUNT) {\n isTinyPosition = true;\n tinyPositionAmount = remainingRBTCAmount;\n }\n }\n\n return (isTinyPosition, tinyPositionAmount);\n }\n}\n" + }, + "contracts/modules/LoanMaintenance.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Maintenance contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to query loan data and to modify its status\n * by withdrawing or depositing collateral.\n * */\ncontract LoanMaintenance is\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n LiquidationHelper,\n ModuleCommonFunctionalities\n{\n // Keep the old LoanReturnData for backward compatibility (especially for the watcher)\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n // The new struct which contained borrower & creation time of a loan\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set initial values of proxy targets.\n *\n * @param target The address of the logic contract instance.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.depositCollateral.selector];\n _setTarget(this.depositCollateral.selector, target);\n _setTarget(this.withdrawCollateral.selector, target);\n _setTarget(this.withdrawAccruedInterest.selector, target);\n _setTarget(this.extendLoanDuration.selector, target);\n _setTarget(this.reduceLoanDuration.selector, target);\n _setTarget(this.getLenderInterestData.selector, target);\n _setTarget(this.getLoanInterestData.selector, target);\n _setTarget(this.getUserLoans.selector, target);\n _setTarget(this.getUserLoansV2.selector, target);\n _setTarget(this.getLoan.selector, target);\n _setTarget(this.getLoanV2.selector, target);\n _setTarget(this.getActiveLoans.selector, target);\n _setTarget(this.getActiveLoansV2.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanMaintenance\");\n }\n\n /**\n * @notice Increase the margin of a position by depositing additional collateral.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount /// must match msg.value if ether is sent\n ) external payable nonReentrant whenNotPaused {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.value == 0 || loanParamsLocal.collateralToken == address(wrbtcToken),\n \"wrong asset sent\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(depositAmount);\n\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.collateralToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n\n (uint256 collateralToLoanRate, ) =\n IPriceFeeds(priceFeeds).queryRate(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n\n emit DepositCollateral(loanId, depositAmount, collateralToLoanRate);\n }\n\n /**\n * @notice Withdraw from the collateral. This reduces the margin of a position.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 actualWithdrawAmount) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral,\n loanParamsLocal.maintenanceMargin\n );\n\n if (withdrawAmount > maxDrawdown) {\n actualWithdrawAmount = maxDrawdown;\n } else {\n actualWithdrawAmount = withdrawAmount;\n }\n\n loanLocal.collateral = loanLocal.collateral.sub(actualWithdrawAmount);\n\n if (loanParamsLocal.collateralToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, actualWithdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.collateralToken, receiver, actualWithdrawAmount);\n }\n }\n\n /**\n * @notice Withdraw accrued loan interest.\n *\n * @dev Wrapper for _payInterest internal function.\n *\n * @param loanToken The loan token address.\n * */\n function withdrawAccruedInterest(address loanToken) external whenNotPaused {\n /// Pay outstanding interest to lender.\n _payInterest(\n msg.sender, /// Lender.\n loanToken\n );\n }\n\n /**\n * @notice Extend the loan duration by as much time as depositAmount can buy.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in loan tokens. Used to pay the interest for the new duration.\n * @param useCollateral Whether pay interests w/ the collateral. If true, depositAmount of loan tokens\n *\t\t\t\t\t\twill be purchased with the collateral.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n *\n * @return secondsExtended The amount of time in seconds the loan is extended.\n * */\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external payable nonReentrant whenNotPaused returns (uint256 secondsExtended) {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n !useCollateral ||\n msg.sender == loanLocal.borrower ||\n delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(\n msg.value == 0 || (!useCollateral && loanParamsLocal.loanToken == address(wrbtcToken)),\n \"wrong asset sent\"\n );\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n /// Handle back interest: calculates interest owned since the loan\n /// endtime passed but the loan remained open.\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestOwed = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestOwed.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(86400);\n\n require(depositAmount > backInterestOwed, \"deposit cannot cover back interest\");\n }\n\n /// Deposit interest.\n if (useCollateral) {\n /// Used the whole converted loanToken to extend the loan duration\n depositAmount = _doCollateralSwap(loanLocal, loanParamsLocal, depositAmount);\n } else {\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.loanToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n }\n\n if (backInterestOwed != 0) {\n depositAmount = depositAmount.sub(backInterestOwed);\n\n /// Pay out backInterestOwed\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n secondsExtended = depositAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(secondsExtended);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(depositAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .add(depositAmount);\n }\n\n /**\n * @notice Reduce the loan duration by withdrawing from the deposited interest.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in loan tokens.\n *\n * @return secondsReduced The amount of time in seconds the loan is reduced.\n * */\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 secondsReduced) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(loanLocal.endTimestamp > block.timestamp, \"loan term has ended\");\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 interestDepositRemaining =\n loanLocal.endTimestamp.sub(block.timestamp).mul(loanInterestLocal.owedPerDay).div(\n 86400\n );\n require(withdrawAmount < interestDepositRemaining, \"withdraw amount too high\");\n\n /// Withdraw interest.\n if (loanParamsLocal.loanToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, withdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.loanToken, receiver, withdrawAmount);\n }\n\n secondsReduced = withdrawAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n require(loanLocal.endTimestamp > secondsReduced, \"loan too short\");\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.sub(secondsReduced);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(withdrawAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .sub(withdrawAmount);\n }\n\n /**\n * @notice Get current lender interest data totals for all loans\n * with a specific oracle and interest token.\n *\n * @param lender The lender address.\n * @param loanToken The loan token address.\n *\n * @return interestPaid The total amount of interest that has been paid to a lender so far.\n * @return interestPaidDate The date of the last interest pay out, or 0 if no interest has been withdrawn yet.\n * @return interestOwedPerDay The amount of interest the lender is earning per day.\n * @return interestUnPaid The total amount of interest the lender is owned and not yet withdrawn.\n * @return interestFeePercent The fee retained by the protocol before interest is paid to the lender.\n * @return principalTotal The total amount of outstanding principal the lender has loaned.\n * */\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n )\n {\n LenderInterest memory lenderInterestLocal = lenderInterest[lender][loanToken];\n\n interestUnPaid = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(86400);\n if (interestUnPaid > lenderInterestLocal.owedTotal)\n interestUnPaid = lenderInterestLocal.owedTotal;\n\n return (\n lenderInterestLocal.paidTotal,\n lenderInterestLocal.paidTotal != 0 ? lenderInterestLocal.updatedTimestamp : 0,\n lenderInterestLocal.owedPerDay,\n lenderInterestLocal.updatedTimestamp != 0 ? interestUnPaid : 0,\n lendingFeePercent,\n lenderInterestLocal.principalTotal\n );\n }\n\n /**\n * @notice Get current interest data for a loan.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loanToken The loan token that interest is paid in.\n * @return interestOwedPerDay The amount of interest the borrower is paying per day.\n * @return interestDepositTotal The total amount of interest the borrower has deposited.\n * @return interestDepositRemaining The amount of deposited interest that is not yet owed to a lender.\n * */\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n )\n {\n loanToken = loanParams[loans[loanId].loanParamsId].loanToken;\n interestOwedPerDay = loanInterest[loanId].owedPerDay;\n interestDepositTotal = loanInterest[loanId].depositTotal;\n\n uint256 endTimestamp = loans[loanId].endTimestamp;\n uint256 interestTime = block.timestamp > endTimestamp ? endTimestamp : block.timestamp;\n interestDepositRemaining = endTimestamp > interestTime\n ? endTimestamp.sub(interestTime).mul(interestOwedPerDay).div(86400)\n : 0;\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData) {\n return\n _getLoan(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2) {\n return\n _getLoanV2(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get all active loans.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @dev New view function which will return the loan data.\n * @dev This function was created to support backward compatibility\n * @dev As in we the old getActiveLoans function is not expected to be changed by the wathcers.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loanData The data structure\n * @return extendedLoanData The data structure which contained (borrower & creation time)\n */\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Internal function to get one loan data structure.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ the loan information.\n * */\n function _getLoan(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnData memory loanData) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanData;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanData;\n }\n\n return\n LoanReturnData({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable\n });\n }\n\n /**\n * @notice Internal function to get one loan data structure v2.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data v2 structure w/ the loan information.\n * */\n function _getLoanV2(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnDataV2 memory loanDataV2) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanDataV2;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanDataV2;\n }\n\n return\n LoanReturnDataV2({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n borrower: loanLocal.borrower,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable,\n creationTimestamp: loanLocal.startTimestamp\n });\n }\n\n /**\n * @notice Internal function to collect interest from the collateral.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param depositAmount The amount of underlying tokens provided on the loan.\n * */\n function _doCollateralSwap(\n Loan storage loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 depositAmount\n ) internal returns (uint256 purchasedLoanToken) {\n /// Reverts in _loanSwap if amountNeeded can't be bought.\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanLocal.collateral, /// minSourceTokenAmount\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n depositAmount, /// requiredDestTokenAmount (partial spend of loanLocal.collateral to fill this amount)\n true, /// bypassFee\n \"\" /// loanDataBytes\n );\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n /// Ensure the loan is still healthy.\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n return destTokenAmountReceived;\n }\n}\n" + }, + "contracts/modules/LoanOpenings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\n/**\n * @title Loan Openings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to borrow and trade.\n * */\ncontract LoanOpenings is\n LoanOpeningsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n ModuleCommonFunctionalities\n{\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\n _setTarget(this.borrowOrTradeFromPool.selector, target);\n _setTarget(this.setDelegatedManager.selector, target);\n _setTarget(this.getEstimatedMarginExposure.selector, target);\n _setTarget(this.getRequiredCollateral.selector, target);\n _setTarget(this.getBorrowAmount.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanOpenings\");\n }\n\n /**\n * @notice Borrow or trade from pool.\n *\n * @dev Note: Only callable by loan pools (iTokens).\n * Wrapper to _borrowOrTrade internal function.\n *\n * @param loanParamsId The ID of the loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return newPrincipal The new loan size.\n * @return newCollateral The new collateral amount.\n * */\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n bytes calldata loanDataBytes\n )\n external\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 newPrincipal, uint256 newCollateral)\n {\n require(msg.value == 0 || loanDataBytes.length != 0, \"loanDataBytes required with ether\");\n\n /// Only callable by loan pools.\n require(loanPoolToUnderlying[msg.sender] != address(0), \"not authorized\");\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n /// Get required collateral.\n uint256 collateralAmountRequired =\n _getRequiredCollateral(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentValues.newPrincipal,\n initialMargin,\n isTorqueLoan\n );\n require(collateralAmountRequired != 0, \"collateral is 0\");\n\n return\n _borrowOrTrade(\n loanParamsLocal,\n loanId,\n isTorqueLoan,\n collateralAmountRequired,\n initialMargin,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @dev Wrapper for _setDelegatedManager internal function.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external whenNotPaused {\n require(loans[loanId].borrower == msg.sender, \"unauthorized\");\n\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\n }\n\n /**\n * @notice Get the estimated margin exposure.\n *\n * Margin is the money borrowed from a broker to purchase an investment\n * and is the difference between the total value of investment and the\n * loan amount. Margin trading refers to the practice of using borrowed\n * funds from a broker to trade a financial asset, which forms the\n * collateral for the loan from the broker.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param loanTokenSent The amount of loan tokens sent.\n * @param collateralTokenSent The amount of collateral tokens sent.\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\n * @param newPrincipal The updated amount of principal (current debt).\n *\n * @return The margin exposure.\n * */\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256) {\n uint256 maxLoanTerm = 2419200; // 28 days\n\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\n\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\n\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\n uint256 tradingFee = _getTradingFee(swapAmount);\n if (tradingFee != 0) {\n swapAmount = swapAmount.sub(tradingFee);\n }\n\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\n if (receivedAmount == 0) {\n return 0;\n } else {\n return collateralTokenSent.add(receivedAmount);\n }\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Calls internal _getRequiredCollateral and add fees.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralAmountRequired The required collateral.\n * */\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 collateralAmountRequired) {\n if (marginAmount != 0) {\n collateralAmountRequired = _getRequiredCollateral(\n loanToken,\n collateralToken,\n newPrincipal,\n marginAmount,\n isTorqueLoan\n );\n\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n // cannot be applied solely as it drives to some other tests failure\n /*\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (collateralAmountRequired != 0 && feePercent != 0) {\n\t\t\t\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t);\n\t\t\t}*/\n\n uint256 fee =\n isTorqueLoan\n ? _getBorrowingFee(collateralAmountRequired)\n : _getTradingFee(collateralAmountRequired);\n if (fee != 0) {\n collateralAmountRequired = collateralAmountRequired.add(fee);\n }\n }\n }\n\n /**\n * @notice Get the borrow amount of a trade loan.\n *\n * @dev Basically borrowAmount = collateral / marginAmount\n *\n * Collateral is something that helps secure a loan. When you borrow money,\n * you agree that your lender can take something and sell it to get their\n * money back if you fail to repay the loan. That's the collateral.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param collateralTokenAmount The amount of collateral.\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return borrowAmount The borrow amount.\n * */\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 borrowAmount) {\n if (marginAmount != 0) {\n if (isTorqueLoan) {\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\n }\n uint256 collateral = collateralTokenAmount;\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\n if (fee != 0) {\n collateral = collateral.sub(fee);\n }\n if (loanToken == collateralToken) {\n borrowAmount = collateral.mul(10**20).div(marginAmount);\n } else {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestPrecision != 0) {\n borrowAmount = collateral\n .mul(10**20)\n .mul(sourceToDestRate)\n .div(marginAmount)\n .div(sourceToDestPrecision);\n }\n }\n /*\n\t\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t\t// cannot be applied solely as it drives to some other tests failure\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (borrowAmount != 0 && feePercent != 0) {\n\t\t\t\tborrowAmount = borrowAmount\n\t\t\t\t\t.mul(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t)\n\t\t\t\t\t.divCeil(10**20);\n\t\t\t}*/\n }\n }\n\n /**\n * @notice Borrow or trade.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param collateralAmountRequired The required amount of collateral.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return The new loan size.\n * @return The new collateral amount.\n * */\n function _borrowOrTrade(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 collateralAmountRequired,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n require(\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\n \"collateral/loan match\"\n );\n require(initialMargin >= loanParamsLocal.minInitialMargin, \"initialMargin too low\");\n\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\n require(\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\n \"invalid interest\"\n );\n\n // @note this fix is for borrowing only\n uint256 sentNewPrincipal = isTorqueLoan ? sentValues.newPrincipal : 0;\n\n /// Initialize loan.\n Loan storage loanLocal =\n loans[\n _initializeLoan(\n loanParamsLocal,\n loanId,\n initialMargin,\n sentAddresses,\n sentValues.newPrincipal\n )\n ];\n\n // Get required interest.\n uint256 amount =\n _initializeInterest(\n loanParamsLocal,\n loanLocal,\n sentValues.interestRate, /// newRate\n sentValues.newPrincipal, /// newPrincipal,\n sentValues.interestInitialAmount /// torqueInterest\n );\n\n /// substract out interest from usable loanToken sent.\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\n\n if (isTorqueLoan) {\n require(sentValues.loanTokenSent == 0, \"surplus loan token\");\n\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\n // need to temp into local state to avoid\n address _collateralToken = loanParamsLocal.collateralToken;\n address _loanToken = loanParamsLocal.loanToken;\n if (borrowingFee != 0) {\n _payBorrowingFee(\n sentAddresses.borrower, /// borrower\n loanLocal.id,\n _collateralToken, /// fee token\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n borrowingFee\n );\n\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\n }\n } else {\n /// Update collateral after trade.\n sentValues = _updateCollateralAfterTrade(\n loanId,\n loanParamsLocal,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /// Settle collateral.\n require(\n _isCollateralSatisfied(\n loanParamsLocal,\n loanLocal,\n initialMargin,\n sentValues.collateralTokenSent,\n collateralAmountRequired,\n sentNewPrincipal\n ),\n \"collateral insufficient\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\n\n if (isTorqueLoan) {\n /// reclaiming variable -> interestDuration\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\n } else {\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\n }\n\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\n\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\n }\n\n function _updateCollateralAfterTrade(\n bytes32 loanId,\n LoanParams memory loanParamsLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (MarginTradeStructHelpers.SentAmounts memory) {\n uint256 receivedAmount;\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\n loanId,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentAddresses.borrower, /// borrower\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\n false, /// bypassFee\n loanDataBytes\n );\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\n\n /// Check the minEntryPrice with the rate\n require(\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\n \"entry price above the minimum\"\n );\n\n return sentValues;\n }\n\n /**\n * @notice Finalize an open loan.\n *\n * @dev Finalize it by updating local parameters of the loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _finalizeOpen(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bool isTorqueLoan\n ) internal {\n /// @dev TODO: here the actual used rate and margin should go.\n (uint256 initialMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(initialMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n if (loanLocal.startTimestamp == block.timestamp) {\n uint256 loanToCollateralPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken\n );\n uint256 collateralToLoanPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\n loanLocal.startRate = isTorqueLoan\n ? collateralToLoanRate\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\n }\n\n _emitOpeningEvents(\n loanParamsLocal,\n loanLocal,\n sentAddresses,\n sentValues,\n collateralToLoanRate,\n initialMargin,\n isTorqueLoan\n );\n }\n\n /**\n * @notice Emit the opening events.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n * @param margin The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _emitOpeningEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n uint256 collateralToLoanRate,\n uint256 margin,\n bool isTorqueLoan\n ) internal {\n if (isTorqueLoan) {\n emit Borrow(\n sentAddresses.borrower, /// user (borrower)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n sentValues.newPrincipal, /// newPrincipal\n sentValues.collateralTokenSent, /// newCollateral\n sentValues.interestRate, /// interestRate\n sentValues.interestDuration, /// interestDuration\n collateralToLoanRate, /// collateralToLoanRate,\n margin /// currentMargin\n );\n } else {\n /// currentLeverage = 100 / currentMargin\n margin = SafeMath.div(10**38, margin);\n\n emit Trade(\n sentAddresses.borrower, /// user (trader)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n sentValues.collateralTokenSent, /// positionSize\n sentValues.newPrincipal, /// borrowedAmount\n sentValues.interestRate, /// interestRate,\n loanLocal.endTimestamp, /// settlementDate\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\n sentValues.entryLeverage, /// entryLeverage\n margin /// currentLeverage\n );\n }\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegator The address of previous manager.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function _setDelegatedManager(\n bytes32 loanId,\n address delegator,\n address delegated,\n bool toggle\n ) internal {\n delegatedManagers[loanId][delegated] = toggle;\n\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\n }\n\n /**\n * @notice Calculate whether the collateral is satisfied.\n *\n * @dev Basically check collateral + drawdown >= 98% of required.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param initialMargin The initial amount of margin.\n * @param newCollateral The amount of new collateral.\n * @param collateralAmountRequired The amount of required collateral.\n * @param newPrincipal The amount to borrow.\n *\n * @return Whether the collateral is satisfied.\n * */\n function _isCollateralSatisfied(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 initialMargin,\n uint256 newCollateral,\n uint256 collateralAmountRequired,\n uint256 newPrincipal\n ) internal view returns (bool) {\n /// Allow at most 2% under-collateralized.\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\n\n if (newCollateral < collateralAmountRequired) {\n /// Check that existing collateral is sufficient coverage.\n if (loanLocal.collateral != 0) {\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal.sub(newPrincipal), // sub(newPrincipal) to exclude the new borrowed amount from the total principal to calculate maxDrawdown for existing loan\n loanLocal.collateral,\n initialMargin\n );\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\n } else {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @notice Initialize a loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan.\n * @param initialMargin The amount of margin of the trade.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\n * @return The loanId.\n * */\n function _initializeLoan(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n uint256 newPrincipal\n ) internal returns (bytes32) {\n require(loanParamsLocal.active, \"loanParams disabled\");\n\n address lender = sentAddresses.lender;\n address borrower = sentAddresses.borrower;\n address manager = sentAddresses.manager;\n\n Loan memory loanLocal;\n\n if (loanId == 0) {\n borrowerNonce[borrower]++;\n loanId = keccak256(\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\n );\n require(loans[loanId].id == 0, \"loan exists\");\n\n loanLocal = Loan({\n id: loanId,\n loanParamsId: loanParamsLocal.id,\n pendingTradesId: 0,\n active: true,\n principal: newPrincipal,\n collateral: 0, /// calculated later\n startTimestamp: block.timestamp,\n endTimestamp: 0, /// calculated later\n startMargin: initialMargin,\n startRate: 0, /// queried later\n borrower: borrower,\n lender: lender\n });\n\n activeLoansSet.addBytes32(loanId);\n lenderLoanSets[lender].addBytes32(loanId);\n borrowerLoanSets[borrower].addBytes32(loanId);\n } else {\n loanLocal = loans[loanId];\n require(\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\n \"loan has ended\"\n );\n require(loanLocal.borrower == borrower, \"borrower mismatch\");\n require(loanLocal.lender == lender, \"lender mismatch\");\n require(loanLocal.loanParamsId == loanParamsLocal.id, \"loanParams mismatch\");\n\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\n }\n\n if (manager != address(0)) {\n _setDelegatedManager(loanId, borrower, manager, true);\n }\n\n loans[loanId] = loanLocal;\n\n return loanId;\n }\n\n /**\n * @notice Initialize a loan interest.\n *\n * @dev A Torque loan is an indefinite-term loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param newRate The new interest rate of the loan.\n * @param newPrincipal The new principal amount of the loan.\n * @param torqueInterest The interest rate of the Torque loan.\n *\n * @return interestAmountRequired The interest amount required.\n * */\n function _initializeInterest(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n uint256 newRate,\n uint256 newPrincipal,\n uint256 torqueInterest /// ignored for fixed-term loans\n ) internal returns (uint256 interestAmountRequired) {\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 previousDepositRemaining;\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\n previousDepositRemaining = loanLocal\n .endTimestamp\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\n .mul(loanInterestLocal.owedPerDay)\n .div(86400);\n }\n\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\n\n /// Update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n\n if (maxLoanTerm == 0) {\n /// Indefinite-term (Torque) loan.\n\n /// torqueInterest != 0 was confirmed earlier.\n loanLocal.endTimestamp = torqueInterest\n .add(previousDepositRemaining)\n .mul(86400)\n .div(loanInterestLocal.owedPerDay)\n .add(block.timestamp);\n\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxLoanTerm > 3600, \"loan too short\");\n\n interestAmountRequired = torqueInterest;\n } else {\n /// Fixed-term loan.\n\n if (loanLocal.endTimestamp == 0) {\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\n }\n\n interestAmountRequired = loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(owedPerDay)\n .div(86400);\n }\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n /// Update remaining lender interest values.\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Basically collateral = newPrincipal * marginAmount\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralTokenAmount The required collateral.\n * */\n function _getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) internal view returns (uint256 collateralTokenAmount) {\n if (loanToken == collateralToken) {\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\n } else {\n /// Using the price feed instead of the swap expected return\n /// because we need the rate in the inverse direction\n /// so the swap is probably farther off than the price feed.\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestRate != 0) {\n collateralTokenAmount = newPrincipal\n .mul(sourceToDestPrecision)\n .div(sourceToDestRate)\n .mul(marginAmount)\n .div(10**20);\n /*TODO: review\n\t\t\t\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\n }\n }\n // ./tests/loan-token/TradingTestToken.test.js\n if (isTorqueLoan && collateralTokenAmount != 0) {\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\n collateralTokenAmount\n );\n }\n }\n}\n" + }, + "contracts/modules/LoanSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to get and set loan parameters.\n * */\ncontract LoanSettings is State, LoanSettingsEvents, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"LoanSettings - fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setupLoanParams.selector];\n _setTarget(this.setupLoanParams.selector, target);\n _setTarget(this.disableLoanParams.selector, target);\n _setTarget(this.getLoanParams.selector, target);\n _setTarget(this.getLoanParamsList.selector, target);\n _setTarget(this.getTotalPrincipal.selector, target);\n _setTarget(this.minInitialMargin.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanSettings\");\n }\n\n /**\n * @notice Setup loan parameters, by looping every loan\n * and populating its parameters.\n *\n * @dev For each loan calls _setupLoanParams internal function.\n *\n * @param loanParamsList The array of loan parameters.\n *\n * @return loanParamsIdList The array of loan parameters IDs.\n * */\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n whenNotPaused\n returns (bytes32[] memory loanParamsIdList)\n {\n loanParamsIdList = new bytes32[](loanParamsList.length);\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsIdList[i] = _setupLoanParams(loanParamsList[i]);\n }\n }\n\n /**\n * @notice Deactivate LoanParams for future loans. Active loans\n * using it are unaffected.\n *\n * @param loanParamsIdList The array of loan parameters IDs to deactivate.\n * */\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external whenNotPaused {\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n require(msg.sender == loanParams[loanParamsIdList[i]].owner, \"unauthorized owner\");\n loanParams[loanParamsIdList[i]].active = false;\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n emit LoanParamsDisabled(\n loanParamsLocal.id,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdDisabled(loanParamsLocal.id, loanParamsLocal.owner);\n }\n }\n\n /**\n * @notice Get loan parameters for every matching IDs.\n *\n * @param loanParamsIdList The array of loan parameters IDs to match.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParams(bytes32[] memory loanParamsIdList)\n public\n view\n returns (LoanParams[] memory loanParamsList)\n {\n loanParamsList = new LoanParams[](loanParamsIdList.length);\n uint256 itemCount;\n\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n if (loanParamsLocal.id == 0) {\n continue;\n }\n loanParamsList[itemCount] = loanParamsLocal;\n itemCount++;\n }\n\n if (itemCount < loanParamsList.length) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get loan parameters for an owner and a given page\n * defined by an offset and a limit.\n *\n * @param owner The address of the loan owner.\n * @param start The page offset.\n * @param count The page limit.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList) {\n EnumerableBytes32Set.Bytes32Set storage set = userLoanParamSets[owner];\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loanParamsList;\n }\n\n loanParamsList = new bytes32[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n loanParamsList[itemCount] = set.get(i + start - 1);\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get the total principal of the loans by a lender.\n *\n * @param lender The address of the lender.\n * @param loanToken The address of the token instance.\n *\n * @return The total principal of the loans.\n * */\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256) {\n return lenderInterest[lender][loanToken].principalTotal;\n }\n\n /**\n * @notice Setup a loan parameters.\n *\n * @param loanParamsLocal The loan parameters.\n *\n * @return loanParamsId The loan parameters ID.\n * */\n function _setupLoanParams(LoanParams memory loanParamsLocal) internal returns (bytes32) {\n bytes32 loanParamsId =\n keccak256(\n abi.encodePacked(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm,\n block.timestamp\n )\n );\n require(loanParams[loanParamsId].id == 0, \"loanParams exists\");\n\n require(\n loanParamsLocal.loanToken != address(0) &&\n loanParamsLocal.collateralToken != address(0) &&\n loanParamsLocal.minInitialMargin > loanParamsLocal.maintenanceMargin &&\n (loanParamsLocal.maxLoanTerm == 0 || loanParamsLocal.maxLoanTerm > 3600), /// A defined maxLoanTerm has to be greater than one hour.\n \"invalid params\"\n );\n\n loanParamsLocal.id = loanParamsId;\n loanParamsLocal.active = true;\n loanParamsLocal.owner = msg.sender;\n\n loanParams[loanParamsId] = loanParamsLocal;\n userLoanParamSets[msg.sender].addBytes32(loanParamsId);\n\n emit LoanParamsSetup(\n loanParamsId,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdSetup(loanParamsId, loanParamsLocal.owner);\n\n return loanParamsId;\n }\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256) {\n return loanParams[loanParamsId].minInitialMargin;\n }\n}\n" + }, + "contracts/modules/ProtocolSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../mixins/ProtocolTokenUser.sol\";\nimport \"../modules/interfaces/ProtocolSwapExternalInterface.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../swaps/ISwapsImpl.sol\";\nimport \"../governance/IFeeSharingCollector.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title Protocol Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to customize protocol settings.\n * */\ncontract ProtocolSettings is\n State,\n ProtocolTokenUser,\n ProtocolSettingsEvents,\n ModuleCommonFunctionalities\n{\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyAdminOrOwner {\n address prevModuleContractAddress = logicTargets[this.setPriceFeedContract.selector];\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n _setTarget(this.setRebatePercent.selector, target);\n _setTarget(this.setSpecialRebates.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.togglePaused.selector, target);\n _setTarget(this.isProtocolPaused.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n _setTarget(this.setRolloverFlexFeePercent.selector, target);\n _setTarget(this.getDefaultPathConversion.selector, target);\n _setTarget(this.setDefaultPathConversion.selector, target);\n _setTarget(this.removeDefaultPathConversion.selector, target);\n _setTarget(this.setAdmin.selector, target);\n _setTarget(this.getAdmin.selector, target);\n _setTarget(this.setPauser.selector, target);\n _setTarget(this.getPauser.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"ProtocolSettings\");\n }\n\n /**\n * setting wrong address will break inter module functions calling\n * should be set once\n */\n function setSovrynProtocolAddress(address newProtocolAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address oldProtocolAddress = protocolAddress;\n protocolAddress = newProtocolAddress;\n\n emit SetProtocolAddress(msg.sender, oldProtocolAddress, newProtocolAddress);\n }\n\n function setSOVTokenAddress(address newSovTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newSovTokenAddress), \"newSovTokenAddress not a contract\");\n\n address oldTokenAddress = sovTokenAddress;\n sovTokenAddress = newSovTokenAddress;\n\n emit SetSOVTokenAddress(msg.sender, oldTokenAddress, newSovTokenAddress);\n }\n\n function setLockedSOVAddress(address newLockedSOVAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newLockedSOVAddress), \"newLockSOVAddress not a contract\");\n\n address oldLockedSOVAddress = lockedSOVAddress;\n lockedSOVAddress = newLockedSOVAddress;\n\n emit SetLockedSOVAddress(msg.sender, oldLockedSOVAddress, newLockedSOVAddress);\n }\n\n /**\n * @notice Set the basis point of trading rebate rewards (SOV), max value is 9999 (99.99% liquid, 0.01% vested).\n *\n * @param newBasisPoint Basis point value.\n */\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newBasisPoint <= 9999, \"value too high\");\n\n uint256 oldBasisPoint = tradingRebateRewardsBasisPoint;\n tradingRebateRewardsBasisPoint = newBasisPoint;\n\n emit SetTradingRebateRewardsBasisPoint(msg.sender, oldBasisPoint, newBasisPoint);\n }\n\n /**\n * @notice Update the minimum number of referrals to get affiliates rewards.\n *\n * @param newMinReferrals The new minimum number of referrals.\n * */\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n uint256 oldMinReferrals = minReferralsToPayout;\n minReferralsToPayout = newMinReferrals;\n\n emit SetMinReferralsToPayoutAffiliates(msg.sender, oldMinReferrals, newMinReferrals);\n }\n\n /**\n * @notice Set the address of the Price Feed instance.\n *\n * @param newContract The address of the Price Feed new instance.\n * */\n function setPriceFeedContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = priceFeeds;\n priceFeeds = newContract;\n\n emit SetPriceFeedContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set the address of the asset swapper instance.\n *\n * @param newContract The address of the asset swapper new instance.\n * */\n function setSwapsImplContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = swapsImpl;\n swapsImpl = newContract;\n\n emit SetSwapsImplContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set a list of loan pools and its tokens.\n *\n * @param pools The array of addresses of new loan pool instances.\n * @param assets The array of addresses of the corresponding underlying tokens.\n * */\n function setLoanPool(address[] calldata pools, address[] calldata assets)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(pools.length == assets.length, \"count mismatch\");\n\n for (uint256 i = 0; i < pools.length; i++) {\n require(pools[i] != assets[i], \"pool == asset\");\n require(pools[i] != address(0), \"pool == 0\");\n require(\n assets[i] != address(0) || loanPoolToUnderlying[pools[i]] != address(0),\n \"pool not exists\"\n );\n if (assets[i] == address(0)) {\n underlyingToLoanPool[loanPoolToUnderlying[pools[i]]] = address(0);\n loanPoolToUnderlying[pools[i]] = address(0);\n loanPoolsSet.removeAddress(pools[i]);\n } else {\n loanPoolToUnderlying[pools[i]] = assets[i];\n underlyingToLoanPool[assets[i]] = pools[i];\n loanPoolsSet.addAddress(pools[i]);\n }\n\n emit SetLoanPool(msg.sender, pools[i], assets[i]);\n }\n }\n\n /**\n * @notice Set a list of supported tokens by populating the\n * storage supportedTokens mapping.\n *\n * @param addrs The array of addresses of the tokens.\n * @param toggles The array of flags indicating whether\n * the corresponding token is supported or not.\n * */\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(addrs.length == toggles.length, \"count mismatch\");\n\n for (uint256 i = 0; i < addrs.length; i++) {\n supportedTokens[addrs[i]] = toggles[i];\n\n emit SetSupportedTokens(msg.sender, addrs[i], toggles[i]);\n }\n }\n\n /**\n * @notice Set the value of lendingFeePercent storage variable.\n *\n * @param newValue The new value for lendingFeePercent.\n * */\n function setLendingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = lendingFeePercent;\n lendingFeePercent = newValue;\n\n emit SetLendingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of tradingFeePercent storage variable.\n *\n * @param newValue The new value for tradingFeePercent.\n * */\n function setTradingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = tradingFeePercent;\n tradingFeePercent = newValue;\n\n emit SetTradingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of borrowingFeePercent storage variable.\n *\n * @param newValue The new value for borrowingFeePercent.\n * */\n function setBorrowingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = borrowingFeePercent;\n borrowingFeePercent = newValue;\n\n emit SetBorrowingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of swapExtrernalFeePercent storage variable\n *\n * @param newValue the new value for swapExternalFeePercent\n */\n function setSwapExternalFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = swapExtrernalFeePercent;\n swapExtrernalFeePercent = newValue;\n\n emit SetSwapExternalFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateFeePercent storage variable.\n *\n * @param newValue The new value for affiliateFeePercent.\n * */\n function setAffiliateFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateFeePercent;\n affiliateFeePercent = newValue;\n\n emit SetAffiliateFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateTradingTokenFeePercent storage variable.\n *\n * @param newValue The new value for affiliateTradingTokenFeePercent.\n * */\n function setAffiliateTradingTokenFeePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateTradingTokenFeePercent;\n affiliateTradingTokenFeePercent = newValue;\n\n emit SetAffiliateTradingTokenFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of liquidationIncentivePercent storage variable.\n *\n * @param newValue The new value for liquidationIncentivePercent.\n * */\n function setLiquidationIncentivePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = liquidationIncentivePercent;\n liquidationIncentivePercent = newValue;\n\n emit SetLiquidationIncentivePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of the maximum swap spread.\n *\n * @param newValue The new value for maxDisagreement.\n * */\n function setMaxDisagreement(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n maxDisagreement = newValue;\n }\n\n /**\n * @notice Set the value of the maximum source buffer.\n *\n * @dev To avoid rounding issues on the swap rate a small buffer is implemented.\n *\n * @param newValue The new value for the maximum source buffer.\n * */\n function setSourceBuffer(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n sourceBuffer = newValue;\n }\n\n /**\n * @notice Set the value of the swap size limit.\n *\n * @param newValue The new value for the maximum swap size.\n * */\n function setMaxSwapSize(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n uint256 oldValue = maxSwapSize;\n maxSwapSize = newValue;\n\n emit SetMaxSwapSize(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the address of the feesController instance.\n *\n * @dev The fee sharing proxy must be the feesController of the\n * protocol contract. This allows the fee sharing proxy\n * to withdraw the fees.\n *\n * @param newController The new address of the feesController.\n * */\n function setFeesController(address newController) external onlyAdminOrOwner whenNotPaused {\n address oldController = feesController;\n feesController = newController;\n\n emit SetFeesController(msg.sender, oldController, newController);\n }\n\n /**\n * @notice Set the pauser address of sovryn protocol.\n *\n * only pauser or owner can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Get pauser address.\n *\n *\n * @return pauser address.\n */\n function getPauser() external view returns (address) {\n return pauser;\n }\n\n /*\n * @notice Set the admin address of sovryn protocol.\n *\n * only owner can perform this action.\n *\n * @param newAdmin The new address of the admin.\n * */\n function setAdmin(address newAdmin) external onlyOwner {\n emit SetAdmin(msg.sender, admin, newAdmin);\n admin = newAdmin;\n }\n\n /**\n * @dev Get admin address.\n *\n *\n * @return admin address.\n */\n function getAdmin() external view returns (address) {\n return admin;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * from three sources: lending, trading and borrowing.\n * The fees (except SOV) will be converted to wRBTC.\n * For SOV, it will be deposited directly to feeSharingCollector from the protocol.\n *\n * @param tokens The array of address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n whenNotPaused\n returns (uint256 totalWRBTCWithdrawn)\n {\n require(msg.sender == feesController, \"unauthorized\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n uint256 lendingBalance = lendingFeeTokensHeld[tokens[i]];\n if (lendingBalance > 0) {\n lendingFeeTokensHeld[tokens[i]] = 0;\n lendingFeeTokensPaid[tokens[i]] = lendingFeeTokensPaid[tokens[i]].add(\n lendingBalance\n );\n }\n\n uint256 tradingBalance = tradingFeeTokensHeld[tokens[i]];\n if (tradingBalance > 0) {\n tradingFeeTokensHeld[tokens[i]] = 0;\n tradingFeeTokensPaid[tokens[i]] = tradingFeeTokensPaid[tokens[i]].add(\n tradingBalance\n );\n }\n\n uint256 borrowingBalance = borrowingFeeTokensHeld[tokens[i]];\n if (borrowingBalance > 0) {\n borrowingFeeTokensHeld[tokens[i]] = 0;\n borrowingFeeTokensPaid[tokens[i]] = borrowingFeeTokensPaid[tokens[i]].add(\n borrowingBalance\n );\n }\n\n uint256 tempAmount = lendingBalance.add(tradingBalance).add(borrowingBalance);\n\n if (tempAmount == 0) {\n continue;\n }\n\n uint256 amountConvertedToWRBTC;\n if (tokens[i] == address(sovTokenAddress)) {\n IERC20(tokens[i]).approve(feesController, tempAmount);\n IFeeSharingCollector(feesController).transferTokens(\n address(sovTokenAddress),\n uint96(tempAmount)\n );\n amountConvertedToWRBTC = 0;\n } else {\n if (tokens[i] == address(wrbtcToken)) {\n amountConvertedToWRBTC = tempAmount;\n\n IERC20(address(wrbtcToken)).safeTransfer(receiver, amountConvertedToWRBTC);\n } else {\n IERC20(tokens[i]).approve(protocolAddress, tempAmount);\n\n (amountConvertedToWRBTC, ) = ProtocolSwapExternalInterface(protocolAddress)\n .swapExternal(\n tokens[i], // source token address\n address(wrbtcToken), // dest token address\n feesController, // set feeSharingCollector as receiver\n protocolAddress, // protocol as the sender\n tempAmount, // source token amount\n 0, // reqDestToken\n 0, // minReturn\n \"\" // loan data bytes\n );\n\n /// Will revert if disagreement found.\n IPriceFeeds(priceFeeds).checkPriceDisagreement(\n tokens[i],\n address(wrbtcToken),\n tempAmount,\n amountConvertedToWRBTC,\n maxDisagreement\n );\n }\n\n totalWRBTCWithdrawn = totalWRBTCWithdrawn.add(amountConvertedToWRBTC);\n }\n\n emit WithdrawFees(\n msg.sender,\n tokens[i],\n receiver,\n lendingBalance,\n tradingBalance,\n borrowingBalance,\n amountConvertedToWRBTC\n );\n }\n\n return totalWRBTCWithdrawn;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from lending operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = lendingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n lendingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n lendingFeeTokensPaid[token] = lendingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawLendingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from trading operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = tradingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n tradingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n tradingFeeTokensPaid[token] = tradingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawTradingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from borrowing operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = borrowingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n borrowingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n borrowingFeeTokensPaid[token] = borrowingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawBorrowingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The owner calls this function to withdraw protocol tokens.\n *\n * @dev Wrapper for ProtocolTokenUser::_withdrawProtocolToken internal function.\n *\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of tokens to get.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n onlyAdminOrOwner\n whenNotPaused\n returns (address, bool)\n {\n return _withdrawProtocolToken(receiver, amount);\n }\n\n /**\n * @notice The owner calls this function to deposit protocol tokens.\n *\n * @param amount The tokens of fees to send.\n * */\n function depositProtocolToken(uint256 amount) external onlyAdminOrOwner whenNotPaused {\n /// @dev Update local balance\n protocolTokenHeld = protocolTokenHeld.add(amount);\n\n /// @dev Send the tokens\n IERC20(protocolTokenAddress).safeTransferFrom(msg.sender, address(this), amount);\n }\n\n /**\n * @notice Get a list of loan pools.\n *\n * @param start The offset.\n * @param count The limit.\n *\n * @return The array of loan pools.\n * */\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory)\n {\n return loanPoolsSet.enumerate(start, count);\n }\n\n /**\n * @notice Check whether a token is a pool token.\n *\n * @dev By querying its underlying token.\n *\n * @param loanPool The token address to check.\n * */\n function isLoanPool(address loanPool) external view returns (bool) {\n return loanPoolToUnderlying[loanPool] != address(0);\n }\n\n /**\n * @notice Set the contract registry address of the SovrynSwap network.\n *\n * @param registryAddress the address of the registry contract.\n * */\n function setSovrynSwapContractRegistryAddress(address registryAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(registryAddress), \"registryAddress not a contract\");\n\n address oldSovrynSwapContractRegistryAddress = sovrynSwapContractRegistryAddress;\n sovrynSwapContractRegistryAddress = registryAddress;\n\n emit SetSovrynSwapContractRegistryAddress(\n msg.sender,\n oldSovrynSwapContractRegistryAddress,\n sovrynSwapContractRegistryAddress\n );\n }\n\n /**\n * @notice Set the wrBTC contract address.\n *\n * @param wrbtcTokenAddress The address of the wrBTC contract.\n * */\n function setWrbtcToken(address wrbtcTokenAddress) external onlyAdminOrOwner whenNotPaused {\n require(Address.isContract(wrbtcTokenAddress), \"wrbtcTokenAddress not a contract\");\n\n address oldwrbtcToken = address(wrbtcToken);\n wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n emit SetWrbtcToken(msg.sender, oldwrbtcToken, wrbtcTokenAddress);\n }\n\n /**\n * @notice Set the protocol token contract address.\n *\n * @param _protocolTokenAddress The address of the protocol token contract.\n * */\n function setProtocolTokenAddress(address _protocolTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n\n address oldProtocolTokenAddress = protocolTokenAddress;\n protocolTokenAddress = _protocolTokenAddress;\n\n emit SetProtocolTokenAddress(msg.sender, oldProtocolTokenAddress, _protocolTokenAddress);\n }\n\n /**\n * @notice Set rollover base reward. It should be denominated in wrBTC.\n *\n * @param baseRewardValue The base reward.\n * */\n function setRolloverBaseReward(uint256 baseRewardValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(baseRewardValue > 0, \"Base reward is zero\");\n\n uint256 oldValue = rolloverBaseReward;\n rolloverBaseReward = baseRewardValue;\n\n emit SetRolloverBaseReward(msg.sender, oldValue, rolloverBaseReward);\n }\n\n /**\n * @notice Set the fee rebate percent.\n *\n * @param rebatePercent The fee rebate percent.\n * */\n function setRebatePercent(uint256 rebatePercent) external onlyAdminOrOwner whenNotPaused {\n require(rebatePercent <= 10**20, \"Fee rebate is too high\");\n\n uint256 oldRebatePercent = feeRebatePercent;\n feeRebatePercent = rebatePercent;\n\n emit SetRebatePercent(msg.sender, oldRebatePercent, rebatePercent);\n }\n\n /**\n * @notice Set the special fee rebate percent for specific pair\n *\n * @param specialRebatesPercent The new special fee rebate percent.\n * */\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external onlyAdminOrOwner whenNotPaused {\n // Set max special rebates to 1000%\n require(specialRebatesPercent <= 1000e18, \"Special fee rebate is too high\");\n\n uint256 oldSpecialRebatesPercent = specialRebates[sourceToken][destToken];\n specialRebates[sourceToken][destToken] = specialRebatesPercent;\n\n emit SetSpecialRebates(\n msg.sender,\n sourceToken,\n destToken,\n oldSpecialRebatesPercent,\n specialRebatesPercent\n );\n }\n\n /**\n * @notice Get a rebate percent of specific pairs.\n *\n * @param sourceTokenAddress The source of pairs.\n * @param destTokenAddress The dest of pairs.\n *\n * @return The percent rebates of the pairs.\n * */\n function getSpecialRebates(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 specialRebatesPercent)\n {\n return specialRebates[sourceTokenAddress][destTokenAddress];\n }\n\n function getProtocolAddress() external view returns (address) {\n return protocolAddress;\n }\n\n function getSovTokenAddress() external view returns (address) {\n return sovTokenAddress;\n }\n\n function getLockedSOVAddress() external view returns (address) {\n return lockedSOVAddress;\n }\n\n function getFeeRebatePercent() external view returns (uint256) {\n return feeRebatePercent;\n }\n\n function togglePaused(bool paused) external onlyPauserOrOwner {\n require(paused != pause, \"Can't toggle\");\n pause = paused;\n emit TogglePaused(msg.sender, !paused, paused);\n }\n\n function isProtocolPaused() external view returns (bool) {\n return pause;\n }\n\n function getSwapExternalFeePercent() external view returns (uint256) {\n return swapExtrernalFeePercent;\n }\n\n /**\n * @notice Get the basis point of trading rebate rewards.\n *\n * @return The basis point value.\n */\n function getTradingRebateRewardsBasisPoint() external view returns (uint256) {\n return tradingRebateRewardsBasisPoint;\n }\n\n /**\n * @dev Get how much SOV that is dedicated to pay the trading rebate rewards.\n * @notice If SOV balance is less than the fees held, it will return 0.\n *\n * @return total dedicated SOV.\n */\n function getDedicatedSOVRebate() public view returns (uint256) {\n uint256 sovProtocolBalance = IERC20(sovTokenAddress).balanceOf(address(this));\n uint256 sovFees =\n lendingFeeTokensHeld[sovTokenAddress].add(tradingFeeTokensHeld[sovTokenAddress]).add(\n borrowingFeeTokensHeld[sovTokenAddress]\n );\n\n return sovProtocolBalance >= sovFees ? sovProtocolBalance.sub(sovFees) : 0;\n }\n\n /**\n * @notice Set rolloverFlexFeePercent (max value is 1%)\n *\n * @param newRolloverFlexFeePercent uint256 value of new rollover flex fee percentage (0.1 ether = 0.1%)\n */\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newRolloverFlexFeePercent <= 1e18, \"value too high\");\n uint256 oldRolloverFlexFeePercent = rolloverFlexFeePercent;\n rolloverFlexFeePercent = newRolloverFlexFeePercent;\n\n emit SetRolloverFlexFeePercent(\n msg.sender,\n oldRolloverFlexFeePercent,\n newRolloverFlexFeePercent\n );\n }\n\n /**\n * @dev Get default path conversion for pairs.\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address.\n *\n * @return default path of the conversion.\n */\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory)\n {\n return defaultPathConversion[sourceTokenAddress][destTokenAddress];\n }\n\n /**\n * @dev Set default path conversion for pairs.\n *\n * @param defaultPath array of addresses for the default path.\n *\n */\n function setDefaultPathConversion(IERC20[] calldata defaultPath)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address sourceTokenAddress = address(defaultPath[0]);\n address destTokenAddress = address(defaultPath[defaultPath.length - 1]);\n\n uint256 defaultPathLength = defaultPath.length;\n require(defaultPathLength >= 3, \"ERR_PATH_LENGTH\");\n\n for (uint256 i = 0; i < defaultPathLength; i++) {\n require(Address.isContract(address(defaultPath[i])), \"ERR_PATH_NON_CONTRACT_ADDR\");\n }\n\n defaultPathConversion[sourceTokenAddress][destTokenAddress] = defaultPath;\n\n emit SetDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPath\n );\n }\n\n /**\n * @dev Remove the default path conversion for pairs\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address\n */\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(\n defaultPathConversion[sourceTokenAddress][destTokenAddress].length > 0,\n \"DEFAULT_PATH_EMPTY\"\n );\n\n IERC20[] memory defaultPathValue =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n delete defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n emit RemoveDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPathValue\n );\n }\n}\n" + }, + "contracts/modules/SwapsExternal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../swaps/ISwapsImpl.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Swaps External contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to calculate and execute swaps.\n * */\ncontract SwapsExternal is VaultController, SwapsUser, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.swapExternal.selector];\n _setTarget(this.swapExternal.selector, target);\n _setTarget(this.getSwapExpectedReturn.selector, target);\n _setTarget(this.checkPriceDivergence.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"SwapsExternal\");\n }\n\n /**\n * @notice Perform a swap w/ tokens or rBTC as source currency.\n *\n * @dev External wrapper that calls SwapsUser::_swapsCall\n * after turning potential incoming rBTC into wrBTC tokens.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param receiver The address of the recipient account.\n * @param returnToSender The address of the sender account.\n * @param sourceTokenAmount The amount of source tokens.\n * @param requiredDestTokenAmount The amount of required destiny tokens.\n * @param minReturn Minimum amount (position size) in the collateral tokens.\n * @param swapData Additional swap data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes memory swapData\n )\n public\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(sourceTokenAmount != 0, \"sourceTokenAmount == 0\");\n checkPriceDivergence(sourceToken, destToken, sourceTokenAmount, minReturn);\n\n /// @dev Get payed value, be it rBTC or tokenized.\n if (msg.value != 0) {\n if (sourceToken == address(0)) {\n sourceToken = address(wrbtcToken);\n }\n require(sourceToken == address(wrbtcToken), \"sourceToken mismatch\");\n require(msg.value == sourceTokenAmount, \"sourceTokenAmount mismatch\");\n\n /// @dev Update wrBTC balance for this contract.\n wrbtcToken.deposit.value(sourceTokenAmount)();\n } else {\n if (address(this) != msg.sender) {\n IERC20(sourceToken).safeTransferFrom(msg.sender, address(this), sourceTokenAmount);\n }\n }\n\n /// @dev Perform the swap w/ tokens.\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n receiver,\n returnToSender,\n msg.sender /// user\n ],\n [\n sourceTokenAmount, /// minSourceTokenAmount\n sourceTokenAmount, /// maxSourceTokenAmount\n requiredDestTokenAmount\n ],\n 0, /// loanId (not tied to a specific loan)\n false, /// bypassFee\n swapData,\n true // the flag for swapExternal (so that it will use the swapExternalFeePercent)\n );\n\n emit ExternalSwap(\n msg.sender, /// user\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Get the swap expected return value.\n *\n * @dev External wrapper that calls SwapsUser::_swapsExpectedReturn\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n *\n * @return The expected return value.\n * */\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n }\n\n /**\n * @notice Check the slippage based on the swapExpectedReturn.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n * @param minReturn The amount (max slippage) that will be compared to the swapsExpectedReturn.\n *\n */\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view {\n uint256 destTokenAmount = _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n require(destTokenAmount >= minReturn, \"destTokenAmountReceived too low\");\n }\n}\n" + }, + "contracts/multisig/MultiSigKeyHolders.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/Ownable.sol\";\n\n/**\n * @title Multi Signature Key Holders contract.\n *\n * This contract contains the implementation of functions to add and remove\n * key holders w/ rBTC and BTC addresses.\n * */\ncontract MultiSigKeyHolders is Ownable {\n /* Storage */\n\n uint256 public constant MAX_OWNER_COUNT = 50;\n\n string private constant ERROR_INVALID_ADDRESS = \"Invalid address\";\n string private constant ERROR_INVALID_REQUIRED = \"Invalid required\";\n\n /// Flag and index for Ethereum address.\n mapping(address => Data) private isEthereumAddressAdded;\n\n /// List of Ethereum addresses.\n address[] private ethereumAddresses;\n\n /// Required number of signatures for the Ethereum multisig.\n uint256 public ethereumRequired = 2;\n\n /// Flag and index for Bitcoin address.\n mapping(string => Data) private isBitcoinAddressAdded;\n\n /// List of Bitcoin addresses.\n string[] private bitcoinAddresses;\n\n /// Required number of signatures for the Bitcoin multisig.\n uint256 public bitcoinRequired = 2;\n\n /// Helps removing items from array.\n struct Data {\n bool added;\n uint248 index;\n }\n\n /* Events */\n\n event EthereumAddressAdded(address indexed account);\n event EthereumAddressRemoved(address indexed account);\n event EthereumRequirementChanged(uint256 required);\n event BitcoinAddressAdded(string account);\n event BitcoinAddressRemoved(string account);\n event BitcoinRequirementChanged(uint256 required);\n\n /* Modifiers */\n\n modifier validRequirement(uint256 ownerCount, uint256 _required) {\n require(\n ownerCount <= MAX_OWNER_COUNT &&\n _required <= ownerCount &&\n _required != 0 &&\n ownerCount != 0,\n ERROR_INVALID_REQUIRED\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function addEthereumAddress(address _address) public onlyOwner {\n _addEthereumAddress(_address);\n }\n\n /**\n * @notice Add rBTC addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function _addEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (!isEthereumAddressAdded[_address].added) {\n isEthereumAddressAdded[_address] = Data({\n added: true,\n index: uint248(ethereumAddresses.length)\n });\n ethereumAddresses.push(_address);\n }\n\n emit EthereumAddressAdded(_address);\n }\n\n /**\n * @notice Remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeEthereumAddress(address _address) public onlyOwner {\n _removeEthereumAddress(_address);\n }\n\n /**\n * @notice Remove rBTC addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (isEthereumAddressAdded[_address].added) {\n uint248 index = isEthereumAddressAdded[_address].index;\n if (index != ethereumAddresses.length - 1) {\n ethereumAddresses[index] = ethereumAddresses[ethereumAddresses.length - 1];\n isEthereumAddressAdded[ethereumAddresses[index]].index = index;\n }\n ethereumAddresses.length--;\n delete isEthereumAddressAdded[_address];\n }\n\n emit EthereumAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether rBTC address is a key holder.\n * @param _address The rBTC address to be checked.\n * */\n function isEthereumAddressOwner(address _address) public view returns (bool) {\n return isEthereumAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of rBTC key holders.\n * */\n function getEthereumAddresses() public view returns (address[] memory) {\n return ethereumAddresses;\n }\n\n /**\n * @notice Set flag ethereumRequired to true/false.\n * @param _required The new value of the ethereumRequired flag.\n * */\n function changeEthereumRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(ethereumAddresses.length, _required)\n {\n ethereumRequired = _required;\n emit EthereumRequirementChanged(_required);\n }\n\n /**\n * @notice Add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function addBitcoinAddress(string memory _address) public onlyOwner {\n _addBitcoinAddress(_address);\n }\n\n /**\n * @notice Add bitcoin addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function _addBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (!isBitcoinAddressAdded[_address].added) {\n isBitcoinAddressAdded[_address] = Data({\n added: true,\n index: uint248(bitcoinAddresses.length)\n });\n bitcoinAddresses.push(_address);\n }\n\n emit BitcoinAddressAdded(_address);\n }\n\n /**\n * @notice Remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeBitcoinAddress(string memory _address) public onlyOwner {\n _removeBitcoinAddress(_address);\n }\n\n /**\n * @notice Remove bitcoin addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (isBitcoinAddressAdded[_address].added) {\n uint248 index = isBitcoinAddressAdded[_address].index;\n if (index != bitcoinAddresses.length - 1) {\n bitcoinAddresses[index] = bitcoinAddresses[bitcoinAddresses.length - 1];\n isBitcoinAddressAdded[bitcoinAddresses[index]].index = index;\n }\n bitcoinAddresses.length--;\n delete isBitcoinAddressAdded[_address];\n }\n\n emit BitcoinAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether bitcoin address is a key holder.\n * @param _address The bitcoin address to be checked.\n * */\n function isBitcoinAddressOwner(string memory _address) public view returns (bool) {\n return isBitcoinAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of bitcoin key holders.\n * */\n function getBitcoinAddresses() public view returns (string[] memory) {\n return bitcoinAddresses;\n }\n\n /**\n * @notice Set flag bitcoinRequired to true/false.\n * @param _required The new value of the bitcoinRequired flag.\n * */\n function changeBitcoinRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(bitcoinAddresses.length, _required)\n {\n bitcoinRequired = _required;\n emit BitcoinRequirementChanged(_required);\n }\n\n /**\n * @notice Add rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress the rBTC addresses to be added.\n * @param _bitcoinAddress the bitcoin addresses to be added.\n * */\n function addEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _addEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _addBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n\n /**\n * @notice Remove rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress The rBTC addresses to be removed.\n * @param _bitcoinAddress The bitcoin addresses to be removed.\n * */\n function removeEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _removeEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _removeBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n}\n" + }, + "contracts/openzeppelin/Address.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256('')`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n codehash := extcodehash(account)\n }\n return (codehash != accountHash && codehash != 0x0);\n }\n\n /**\n * @dev Converts an `address` into `address payable`. Note that this is\n * simply a type cast: the actual underlying value is not changed.\n *\n * _Available since v2.4.0._\n */\n function toPayable(address account) internal pure returns (address payable) {\n return address(uint160(account));\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n *\n * _Available since v2.4.0._\n */\n function sendValue(address recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-call-value\n (bool success, ) = recipient.call.value(amount)(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n}\n" + }, + "contracts/openzeppelin/Context.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n // Empty internal constructor, to prevent people from mistakenly deploying\n // an instance of this contract, which should be used via inheritance.\n constructor() internal {}\n\n // solhint-disable-previous-line no-empty-blocks\n\n function _msgSender() internal view returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n" + }, + "contracts/openzeppelin/ERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./Context.sol\";\nimport \"./IERC20_.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20Mintable}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20_ {\n using SafeMath for uint256;\n\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20};\n *\n * Requirements:\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for `sender`'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n _allowances[sender][_msgSender()].sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n _approve(\n _msgSender(),\n spender,\n _allowances[_msgSender()][spender].sub(\n subtractedValue,\n \"ERC20: decreased allowance below zero\"\n )\n );\n return true;\n }\n\n /**\n * @dev Moves tokens `amount` from `sender` to `recipient`.\n *\n * This is internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _balances[sender] = _balances[sender].sub(\n amount,\n \"ERC20: transfer amount exceeds balance\"\n );\n _balances[recipient] = _balances[recipient].add(amount);\n emit Transfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n *\n * This is internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`.`amount` is then deducted\n * from the caller's allowance.\n *\n * See {_burn} and {_approve}.\n */\n function _burnFrom(address account, uint256 amount) internal {\n _burn(account, amount);\n _approve(\n account,\n _msgSender(),\n _allowances[account][_msgSender()].sub(amount, \"ERC20: burn amount exceeds allowance\")\n );\n }\n}\n" + }, + "contracts/openzeppelin/ERC20Detailed.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20_.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n */\ncontract ERC20Detailed is IERC20_ {\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n */\n constructor(\n string memory name,\n string memory symbol,\n uint8 decimals\n ) public {\n _name = name;\n _symbol = symbol;\n _decimals = decimals;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/openzeppelin/IERC20_.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20_ {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/openzeppelin/Initializable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n */\ncontract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(_initializing || !_initialized, \"Initializable: contract is already initialized\");\n\n bool isTopLevelCall = !_initializing;\n if (isTopLevelCall) {\n _initializing = true;\n _initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n _initializing = false;\n }\n }\n}\n" + }, + "contracts/openzeppelin/Ownable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() public view returns (bool) {\n return _msgSender() == _owner;\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public onlyOwner {\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n */\n function _transferOwnership(address newOwner) internal {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n}\n" + }, + "contracts/openzeppelin/PausableOz.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./Ownable.sol\";\n\ncontract PausableOz is Ownable {\n /**\n * @dev Emitted when the pause is triggered by the owner (`account`).\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by the owner (`account`).\n */\n event Unpaused(address account);\n\n bool internal _paused;\n\n constructor() internal {}\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n */\n modifier whenNotPaused() {\n require(!_paused, \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n */\n modifier whenPaused() {\n require(_paused, \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/openzeppelin/ReentrancyGuard.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title Helps contracts guard against reentrancy attacks.\n * @author Remco Bloemen , Eenae \n * @dev If you mark a function `nonReentrant`, you should also\n * mark it `external`.\n */\ncontract ReentrancyGuard {\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n" + }, + "contracts/openzeppelin/SafeERC20.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./SafeMath.sol\";\nimport \"./Address.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\n );\n }\n\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n // solhint-disable-next-line max-line-length\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance =\n token.allowance(address(this), spender).sub(\n value,\n \"SafeERC20: decreased allowance below zero\"\n );\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves.\n\n // A Solidity high level call has three parts:\n // 1. The target address is checked to verify it contains contract code\n // 2. The call itself is made, and success asserted\n // 3. The return value is decoded, which in turn checks the size of the returned data.\n // solhint-disable-next-line max-line-length\n require(address(token).isContract(), \"SafeERC20: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(data);\n require(success, \"SafeERC20: low-level call failed\");\n\n if (returndata.length > 0) {\n // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "contracts/openzeppelin/SafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n *\n * _Available since v2.4.0._\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\n return divCeil(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n\n if (a == 0) {\n return 0;\n }\n uint256 c = ((a - 1) / b) + 1;\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\n return _a < _b ? _a : _b;\n }\n}\n" + }, + "contracts/openzeppelin/SignedSafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title SignedSafeMath\n * @dev Signed math operations with safety checks that revert on error.\n */\nlibrary SignedSafeMath {\n int256 private constant _INT256_MIN = -2**255;\n\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n require(!(a == -1 && b == _INT256_MIN), \"SignedSafeMath: multiplication overflow\");\n\n int256 c = a * b;\n require(c / a == b, \"SignedSafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n require(b != 0, \"SignedSafeMath: division by zero\");\n require(!(b == -1 && a == _INT256_MIN), \"SignedSafeMath: division overflow\");\n\n int256 c = a / b;\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a - b;\n require((b >= 0 && c <= a) || (b < 0 && c > a), \"SignedSafeMath: subtraction overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a + b;\n require((b >= 0 && c >= a) || (b < 0 && c < a), \"SignedSafeMath: addition overflow\");\n\n return c;\n }\n}\n" + }, + "contracts/proxy/modules/interfaces/IFunctionsList.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\ninterface IFunctionsList {\n function getFunctionsList() external pure returns (bytes4[] memory functionSignatures);\n}\n" + }, + "contracts/proxy/modules/interfaces/IModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\n/**\n * ModulesProxyRegistry Interface\n */\n\ncontract IModulesProxyRegistry {\n event AddModule(address indexed moduleAddress);\n event ReplaceModule(address indexed oldAddress, address indexed newAddress);\n event RemoveModule(address indexed moduleAddress);\n event SetModuleFuncImplementation(\n bytes4 indexed _funcSig,\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use ReplaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external;\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl) external;\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external;\n\n /// @notice to disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external;\n\n /// @param _sig function signature to get impmementation address for\n /// @return function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address);\n\n /// @notice verifies if no functions from the module deployed already registered\n /// @param _impl module implementation address to verify\n /// @return true if module can be added\n function canAddModule(address _impl) external view returns (bool);\n\n /// @notice Multiple modules verification if no functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return True if all modules can be added, false otherwise\n function canNotAddModules(address[] calldata _implementations)\n external\n view\n returns (address[] memory modules);\n\n /// @notice used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n );\n}\n" + }, + "contracts/proxy/modules/ModulesProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"./ModulesProxyRegistry.sol\";\n\n/**\n * ModulesProxy serves as a storage processed by a set of logic contracts - modules\n * Modules functions are registered in the contract's slots generated per func sig\n * All the function calls except for own Proxy functions are delegated to\n * the registered functions\n * The ModulesProxy is designed as a universal solution for refactorig contracts\n * reaching a 24K size limit (EIP-170)\n *\n * Upgradability is implemented at a module level to provide consistency\n * It does not allow to replace separate functions - only the whole module\n * meaning that if a module being registered contains other modules function signatures\n * then these modulea should be replaced completely - all the functions should be removed\n * to avoid leftovers or accidental replacements and therefore functional inconsistency.\n *\n * A module is either a new non-overlapping with registered modules\n * or a complete replacement of another registered module\n * in which case all the old module functions are unregistered and then\n * the new module functions are registered\n * There is also a separate function to unregister a module which unregisters all the functions\n * There is no option to unregister a subset of module functions - one should use pausable functionality\n * to achieve this\n */\n\ncontract ModulesProxy is ModulesProxyRegistry {\n // Uncomment for using beforeFallback() hook\n /*\n bytes private constant BEFORE_FALLBACK_SIG = abi.encodeWithSignature(\"beforeFallback()\");\n bytes4 private constant BEFORE_FALLBACK_SIG_BYTES4 = bytes4(keccak256(abi.encodePacked(\"beforeFallback()\")));\n */\n\n /**\n * @notice Fallback function delegates calls to modules.\n * Returns whatever the implementation call returns.\n * Has a hook to execute before delegating calls\n * To activate register a module with beforeFallback() function\n */\n function() external payable {\n /*\n // Commented to safe gas by default\n // Uncomment for using beforeFallback() hook \n // Implement and register beforeFallback() function in a module\n address beforeFallback = _getFuncImplementation(BEFORE_FALLBACK_SIG_BYTES4);\n if (beforeFallback != address(0)) {\n (bool success, ) = beforeFallback.delegatecall(bytes(0x39b0111a)); // abi.encodeWithSignature(\"beforeFallback()\")\n require(success, \"ModulesProxy::fallback: beforeFallback() fail\"); //MP02\n }\n */\n\n address target = _getFuncImplementation(msg.sig);\n require(target != address(0), \"ModulesProxy:target module not registered\"); // MP03\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/modules/ModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"../../utils/Utils.sol\";\nimport \"../../utils/ProxyOwnable.sol\";\nimport \"../modules/interfaces/IFunctionsList.sol\";\nimport \"../modules/interfaces/IModulesProxyRegistry.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * ModulesProxyRegistry provides modules registration/removing/replacing functionality to ModulesProxy\n * Designed to be inherited\n */\n\ncontract ModulesProxyRegistry is IModulesProxyRegistry, ProxyOwnable {\n using Address for address;\n\n bytes32 internal constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n\n ///@notice Constructor is internal to make contract abstract\n constructor() internal {\n // abstract\n }\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use replaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external onlyProxyOwner {\n _addModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external onlyProxyOwner {\n _addModules(_implementations);\n }\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl)\n external\n onlyProxyOwner\n {\n _replaceModule(_oldModuleImpl, _newModuleImpl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external onlyProxyOwner {\n require(\n _implementationsFrom.length == _implementationsTo.length,\n \"ModulesProxyRegistry::replaceModules: arrays sizes must be equal\"\n ); //MR10\n\n // because the order of addresses is arbitrary, all modules are removed first to avoid collisions\n _removeModules(_implementationsFrom);\n _addModules(_implementationsTo);\n }\n\n /// @notice To disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external onlyProxyOwner {\n _removeModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external onlyProxyOwner {\n _removeModules(_implementations);\n }\n\n /// @param _sig Function signature to get impmementation address for\n /// @return Function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address) {\n return _getFuncImplementation(_sig);\n }\n\n /// @notice Verifies if no functions from the module already registered\n /// @param _impl Module implementation address to verify\n /// @return True if module can be added\n function canAddModule(address _impl) external view returns (bool) {\n return _canAddModule(_impl);\n }\n\n /// @notice Multiple modules verification if there are functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return addresses of registered modules\n function canNotAddModules(address[] memory _implementations)\n public\n view\n returns (address[] memory)\n {\n for (uint256 i = 0; i < _implementations.length; i++) {\n if (_canAddModule(_implementations[i])) {\n delete _implementations[i];\n }\n }\n return _implementations;\n }\n\n /// @notice Used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return Clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n )\n {\n require(\n _newModule.isContract(),\n \"ModulesProxyRegistry::checkClashingFuncSelectors: address is not a contract\"\n ); //MR06\n bytes4[] memory newModuleFunctions = IFunctionsList(_newModule).getFunctionsList();\n bytes4[] memory proxyRegistryFunctions = _getFunctionsList(); //registry functions list\n uint256 clashingProxyRegistryFuncsSize;\n uint256 clashingArraySize;\n uint256 clashingArrayIndex;\n uint256 clashingRegistryArrayIndex;\n\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0) && funcImpl != _newModule) {\n clashingArraySize++;\n } else if (_isFuncClashingWithProxyFunctions(newModuleFunctions[i]))\n clashingProxyRegistryFuncsSize++;\n }\n clashingModules = new address[](clashingArraySize);\n clashingModulesFuncSelectors = new bytes4[](clashingArraySize);\n clashingProxyRegistryFuncSelectors = new bytes4[](clashingProxyRegistryFuncsSize);\n\n if (clashingArraySize == 0 && clashingProxyRegistryFuncsSize == 0)\n //return empty arrays\n return (\n clashingModules,\n clashingModulesFuncSelectors,\n clashingProxyRegistryFuncSelectors\n );\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0)) {\n clashingModules[clashingArrayIndex] = funcImpl;\n clashingModulesFuncSelectors[clashingArrayIndex] = newModuleFunctions[i];\n clashingArrayIndex++;\n }\n for (uint256 j = 0; j < proxyRegistryFunctions.length; j++) {\n //ModulesProxyRegistry has a clashing function selector\n if (proxyRegistryFunctions[j] == newModuleFunctions[i]) {\n clashingProxyRegistryFuncSelectors[\n clashingRegistryArrayIndex\n ] = proxyRegistryFunctions[j];\n clashingRegistryArrayIndex++;\n }\n }\n }\n }\n\n /// Verifies the deployed contract address is a registered module contract\n /// @param _impl deployment address to verify\n /// @return true if _impl address is a registered module\n function isModuleRegistered(address _impl) external view returns (bool) {\n return _getFirstRegisteredModuleAddress(_impl) == _impl;\n }\n\n /****************** INTERNAL FUNCTIONS ******************/\n\n function _getFirstRegisteredModuleAddress(address _impl) internal view returns (address) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_getRegisteredModuleAddress: address is not a contract\"\n );\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n address _moduleImpl = _getFuncImplementation(functions[i]);\n if (_moduleImpl != address(0)) {\n return (_moduleImpl);\n }\n }\n return address(0);\n }\n\n function _getFuncImplementation(bytes4 _sig) internal view returns (address) {\n //TODO: add querying Registry for logic address and then delegate call to it OR use proxy memory slots like this:\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n address implementation;\n assembly {\n implementation := sload(key)\n }\n return implementation;\n }\n\n function _addModule(address _impl) internal {\n require(_impl.isContract(), \"ModulesProxyRegistry::_addModule: address is not a contract\"); //MR01\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n require(\n _getFuncImplementation(functions[i]) == address(0),\n \"ModulesProxyRegistry::_addModule: function already registered - use replaceModule function\"\n ); //MR02\n require(functions[i] != bytes4(0), \"does not allow empty function id\"); // MR03\n require(\n !_isFuncClashingWithProxyFunctions(functions[i]),\n \"ModulesProxyRegistry::_addModule: has a function with the same signature\"\n ); //MR09\n _setModuleFuncImplementation(functions[i], _impl);\n }\n emit AddModule(_impl);\n }\n\n function _addModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _addModule(_implementations[i]);\n }\n }\n\n function _removeModule(address _impl) internal onlyProxyOwner {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_removeModule: address is not a contract\"\n ); //MR07\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n _setModuleFuncImplementation(functions[i], address(0));\n\n emit RemoveModule(_impl);\n }\n\n function _removeModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _removeModule(_implementations[i]);\n }\n }\n\n function _replaceModule(address _oldModuleImpl, address _newModuleImpl) internal {\n if (_oldModuleImpl != _newModuleImpl) {\n require(\n _newModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _newModuleImpl is not a contract\"\n ); //MR03\n require(\n _oldModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _oldModuleImpl is not a contract\"\n ); //MR04\n _removeModule(_oldModuleImpl);\n _addModule(_newModuleImpl);\n\n emit ReplaceModule(_oldModuleImpl, _newModuleImpl);\n }\n }\n\n function _setModuleFuncImplementation(bytes4 _sig, address _impl) internal {\n emit SetModuleFuncImplementation(_sig, _getFuncImplementation(_sig), _impl);\n\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n assembly {\n sstore(key, _impl)\n }\n }\n\n function _isFuncClashingWithProxyFunctions(bytes4 _sig) internal pure returns (bool) {\n bytes4[] memory functionList = _getFunctionsList();\n for (uint256 i = 0; i < functionList.length; i++) {\n if (_sig == functionList[i])\n //ModulesProxyRegistry has function with the same id\n return true;\n }\n return false;\n }\n\n function _canAddModule(address _impl) internal view returns (bool) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_canAddModule: address is not a contract\"\n ); //MR06\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n if (_getFuncImplementation(functions[i]) != address(0)) return (false);\n return true;\n }\n\n function _getFunctionsList() internal pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](13);\n functionList[0] = this.getFuncImplementation.selector;\n functionList[1] = this.addModule.selector;\n functionList[2] = this.addModules.selector;\n functionList[3] = this.removeModule.selector;\n functionList[4] = this.removeModules.selector;\n functionList[5] = this.replaceModule.selector;\n functionList[6] = this.replaceModules.selector;\n functionList[7] = this.canAddModule.selector;\n functionList[8] = this.canNotAddModules.selector;\n functionList[9] = this.setProxyOwner.selector;\n functionList[10] = this.getProxyOwner.selector;\n functionList[11] = this.checkClashingFuncSelectors.selector;\n functionList[12] = this.isModuleRegistered.selector;\n return functionList;\n }\n}\n" + }, + "contracts/proxy/Proxy.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base Proxy contract.\n * @notice The proxy performs delegated calls to the contract implementation\n * it is pointing to. This way upgradable contracts are possible on blockchain.\n *\n * Delegating proxy contracts are widely used for both upgradeability and gas\n * savings. These proxies rely on a logic contract (also known as implementation\n * contract or master copy) that is called using delegatecall. This allows\n * proxies to keep a persistent state (storage and balance) while the code is\n * delegated to the logic contract.\n *\n * Proxy contract is meant to be inherited and its internal functions\n * _setImplementation and _setProxyOwner to be called when upgrades become\n * neccessary.\n *\n * The loan token (iToken) contract as well as the protocol contract act as\n * proxies, delegating all calls to underlying contracts. Therefore, if you\n * want to interact with them using web3, you need to use the ABIs from the\n * contracts containing the actual logic or the interface contract.\n * ABI for LoanToken contracts: LoanTokenLogicStandard\n * ABI for Protocol contract: ISovryn\n *\n * @dev UpgradableProxy is the contract that inherits Proxy and wraps these\n * functions.\n * */\ncontract Proxy {\n bytes32 private constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);\n event ImplementationChanged(\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /**\n * @notice Set sender as an owner.\n * */\n constructor() public {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @notice Throw error if called not by an owner.\n * */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Proxy:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the implementation.\n * @param _implementation Address of the implementation.\n * */\n function _setImplementation(address _implementation) internal {\n require(_implementation != address(0), \"Proxy::setImplementation: invalid address\");\n emit ImplementationChanged(getImplementation(), _implementation);\n\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n sstore(key, _implementation)\n }\n }\n\n /**\n * @notice Return address of the implementation.\n * @return Address of the implementation.\n * */\n function getImplementation() public view returns (address _implementation) {\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n _implementation := sload(key)\n }\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"Proxy::setProxyOwner: invalid address\");\n emit OwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Return address of the owner.\n * @return Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n address implementation = getImplementation();\n require(implementation != address(0), \"Proxy::(): implementation not found\");\n\n assembly {\n let pointer := mload(0x40)\n calldatacopy(pointer, 0, calldatasize)\n let result := delegatecall(gas, implementation, pointer, calldatasize, 0, 0)\n let size := returndatasize\n returndatacopy(pointer, 0, size)\n\n switch result\n case 0 {\n revert(pointer, size)\n }\n default {\n return(pointer, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/UpgradableProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Proxy.sol\";\n\n/**\n * @title Upgradable Proxy contract.\n * @notice A disadvantage of the immutable ledger is that nobody can change the\n * source code of a smart contract after it’s been deployed. In order to fix\n * bugs or introduce new features, smart contracts need to be upgradable somehow.\n *\n * Although it is not possible to upgrade the code of an already deployed smart\n * contract, it is possible to set-up a proxy contract architecture that will\n * allow to use new deployed contracts as if the main logic had been upgraded.\n *\n * A proxy architecture pattern is such that all message calls go through a\n * Proxy contract that will redirect them to the latest deployed contract logic.\n * To upgrade, a new version of the contract is deployed, and the Proxy is\n * updated to reference the new contract address.\n * */\ncontract UpgradableProxy is Proxy {\n /**\n * @notice Set address of the implementation.\n * @dev Wrapper for _setImplementation that exposes the function\n * as public for owner to be able to set a new version of the\n * contract as current pointing implementation.\n * @param _implementation Address of the implementation.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n _setImplementation(_implementation);\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n}\n" + }, + "contracts/reentrancy/Mutex.sol": { + "content": "pragma solidity ^0.5.17;\n\n/*\n * @title Global Mutex contract\n *\n * @notice A mutex contract that allows only one function to be called at a time out\n * of a large set of functions. *Anyone* in the network can freely use any instance\n * of this contract to add a universal mutex to any function in any contract.\n */\ncontract Mutex {\n /*\n * We use an uint to store the mutex state.\n */\n uint256 public value;\n\n /*\n * @notice Increment the mutex state and return the new value.\n *\n * @dev This is the function that will be called by anyone to change the mutex\n * state. It is purposely not protected by any access control\n */\n function incrementAndGetValue() external returns (uint256) {\n /*\n * increment value using unsafe math. This is safe because we are\n * pretty certain no one will ever increment the value 2^256 times\n * in a single transaction.\n */\n return ++value;\n }\n}\n" + }, + "contracts/reentrancy/SharedReentrancyGuard.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Mutex.sol\";\n\n/*\n * @title Abstract contract for shared reentrancy guards\n *\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\n * that there's no reentrancy between *any* functions marked with the modifier.\n *\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\n */\ncontract SharedReentrancyGuard {\n /*\n * This is the address of the mutex contract that will be used as the\n * reentrancy guard.\n *\n * The address is hardcoded to avoid changing the memory layout of\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\n * because the Mutex contract is always deployed to the same address, with the\n * same method used in the deployment of ERC1820Registry.\n */\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\n\n /*\n * This is the modifier that will be used to protect functions from\n * reentrancy. It will call the mutex contract to increment the mutex\n * state and then revert if the mutex state was changed by another\n * nested call.\n */\n modifier globallyNonReentrant() {\n uint256 previous = MUTEX.incrementAndGetValue();\n\n _;\n\n /*\n * If the mutex state was changed by a nested function call, then\n * the value of the state variable will be different from the previous value.\n */\n require(previous == MUTEX.value(), \"reentrancy violation\");\n }\n}\n" + }, + "contracts/rsk/RSKAddrValidator.sol": { + "content": "// SPDX-License-Identifier:MIT\npragma solidity ^0.5.17;\n\nlibrary RSKAddrValidator {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n * */\n function checkPKNotZero(address addr) internal pure returns (bool) {\n return (addr != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && addr != address(0));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key.\n * */\n function safeEquals(address addr1, address addr2) internal pure returns (bool) {\n return (addr1 == addr2 &&\n addr1 != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\n addr1 != address(0));\n }\n}\n" + }, + "contracts/swaps/connectors/interfaces/IContractRegistry.sol": { + "content": "pragma solidity 0.5.17;\n\ncontract IContractRegistry {\n function addressOf(bytes32 contractName) public view returns (address);\n}\n" + }, + "contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol": { + "content": "pragma solidity >=0.5.8 <=0.5.17;\n\nimport \"../../../interfaces/IERC20.sol\";\n\ncontract ISovrynSwapNetwork {\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256);\n\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\n\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory);\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwap.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../../core/State.sol\";\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"../ISwapsImpl.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\n\n/**\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\ncontract SwapsImplSovrynSwap is State, ISwapsImpl {\n using SafeERC20 for IERC20;\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destination tokens.\n * @param receiverAddress The address who will received the swap token results\n * @param returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * @param minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * @param maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address receiverAddress,\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n require(\n supportedTokens[sourceTokenAddress] && supportedTokens[destTokenAddress],\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = estimateSourceTokenAmount(\n sourceTokenAddress,\n destTokenAddress,\n requiredDestTokenAmount,\n maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n allowTransfer(sourceTokenAmountUsed, sourceTokenAddress, address(sovrynSwapNetwork));\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n uint256 sourceToDestPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n internalExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n maxSourceTokenAmount,\n sovrynSwapContractRegistryAddress\n );\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > sourceBuffer) buffer = sourceBuffer;\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistryAddress\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * @param sovrynSwapContractRegistry The sovryn swap contract reigstry address.\n * @param defaultPath The default path for specific pairs.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistry,\n IERC20[] memory defaultPath\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistry);\n\n IERC20[] memory path =\n defaultPath.length >= 3\n ? defaultPath\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/testnet/SwapsImplLocal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../../core/State.sol\";\nimport \"../../../openzeppelin/SafeERC20.sol\";\nimport \"../../ISwapsImpl.sol\";\nimport \"../../../feeds/IPriceFeeds.sol\";\nimport \"../../../testhelpers/TestToken.sol\";\n\n/**\n * @title Swaps Implementation Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate calculations.\n * */\ncontract SwapsImplLocal is State, ISwapsImpl {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Swap two tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address, /*receiverAddress*/\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n\n (uint256 tradeRate, uint256 precision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n if (requiredDestTokenAmount == 0) {\n sourceTokenAmountUsed = minSourceTokenAmount;\n destTokenAmountReceived = minSourceTokenAmount.mul(tradeRate).div(precision);\n } else {\n destTokenAmountReceived = requiredDestTokenAmount;\n sourceTokenAmountUsed = requiredDestTokenAmount.mul(precision).div(tradeRate);\n require(sourceTokenAmountUsed <= minSourceTokenAmount, \"destAmount too great\");\n }\n\n TestToken(sourceTokenAddress).burn(address(this), sourceTokenAmountUsed);\n TestToken(destTokenAddress).mint(address(this), destTokenAmountReceived);\n\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Calculate the expected price rate of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n *\n * @return precision The expected price rate.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * @notice Calculate the expected return of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n * @param defaultPath defaultPath for swap.\n *\n * @return precision The expected return.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused,\n IERC20[] memory defaultPath\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n}\n" + }, + "contracts/swaps/ISwapsImpl.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../interfaces/IERC20.sol\";\n\ninterface ISwapsImpl {\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address receiverAddress,\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) external payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address optionalContractAddress\n ) external view returns (uint256);\n\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistryAddress,\n IERC20[] calldata defaultPath\n ) external view returns (uint256 expectedReturn);\n}\n" + }, + "contracts/swaps/SwapsUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../mixins/FeesHelper.sol\";\nimport \"./ISwapsImpl.sol\";\n\n/**\n * @title Perform token swaps for loans and trades.\n * */\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\n /**\n * @notice Internal loan swap.\n *\n * @param loanId The ID of the loan.\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of destiny tokens.\n * @param user The user address.\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * @param bypassFee To bypass or not the fee.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived\n * @return sourceTokenAmountUsed\n * @return sourceToDestSwapRate\n * */\n function _loanSwap(\n bytes32 loanId,\n address sourceToken,\n address destToken,\n address user,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount,\n bool bypassFee,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 sourceToDestSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n address(this), // receiver\n address(this), // returnToSender\n user\n ],\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\n loanId,\n bypassFee,\n loanDataBytes,\n false // swap external flag, set to false so that it will use the tradingFeePercent\n );\n\n /// Will revert if swap size too large.\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\n\n /// Will revert if disagreement found.\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived,\n maxDisagreement\n );\n\n emit LoanSwap(\n loanId,\n sourceToken,\n destToken,\n user,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Calculate amount of source and destiny tokens.\n *\n * @dev Wrapper for _swapsCall_internal function.\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n * @param loanId The Id of the associated loan.\n * @param miscBool True/false to bypassFee.\n * @param loanDataBytes Additional loan data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall(\n address[5] memory addrs,\n uint256[3] memory vals,\n bytes32 loanId,\n bool miscBool, /// bypassFee\n bytes memory loanDataBytes,\n bool isSwapExternal\n ) internal returns (uint256, uint256) {\n /// addrs[0]: sourceToken\n /// addrs[1]: destToken\n /// addrs[2]: receiver\n /// addrs[3]: returnToSender\n /// addrs[4]: user\n /// vals[0]: minSourceTokenAmount\n /// vals[1]: maxSourceTokenAmount\n /// vals[2]: requiredDestTokenAmount\n\n require(vals[0] != 0 || vals[1] != 0, \"min or max source token amount needs to be set\");\n\n if (vals[1] == 0) {\n vals[1] = vals[0];\n }\n require(vals[0] <= vals[1], \"sourceAmount larger than max\");\n\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n\n uint256 tradingFee;\n if (!miscBool) {\n /// bypassFee\n if (vals[2] == 0) {\n /// condition: vals[0] will always be used as sourceAmount\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[0]);\n } else {\n tradingFee = _getTradingFee(vals[0]);\n }\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId,\n addrs[0], /// sourceToken (feeToken)\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n vals[0] = vals[0].sub(tradingFee);\n }\n } else {\n /// Condition: unknown sourceAmount will be used.\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[2]);\n } else {\n tradingFee = _getTradingFee(vals[2]);\n }\n\n if (tradingFee != 0) {\n vals[2] = vals[2].add(tradingFee);\n }\n }\n }\n\n require(loanDataBytes.length == 0, \"invalid state\");\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\n\n if (vals[2] == 0) {\n /// There's no minimum destTokenAmount, but all of vals[0]\n /// (minSourceTokenAmount) must be spent.\n require(sourceTokenAmountUsed == vals[0], \"swap too large to fill\");\n\n if (tradingFee != 0) {\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\n }\n } else {\n /// There's a minimum destTokenAmount required, but\n /// sourceTokenAmountUsed won't be greater\n /// than vals[1] (maxSourceTokenAmount)\n require(sourceTokenAmountUsed <= vals[1], \"swap fill too large\");\n require(destTokenAmountReceived >= vals[2], \"insufficient swap liquidity\");\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId, /// loanId,\n addrs[1], /// destToken (feeToken)\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\n }\n }\n\n return (destTokenAmountReceived, sourceTokenAmountUsed);\n }\n\n /**\n * @notice Calculate amount of source and destiny tokens.\n *\n * @dev Calls swapsImpl::internalSwap\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\n internal\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n bytes memory data =\n abi.encodeWithSelector(\n ISwapsImpl(swapsImpl).internalSwap.selector,\n addrs[0], /// sourceToken\n addrs[1], /// destToken\n addrs[2], /// receiverAddress\n addrs[3], /// returnToSenderAddress\n vals[0], /// minSourceTokenAmount\n vals[1], /// maxSourceTokenAmount\n vals[2] /// requiredDestTokenAmount\n );\n\n bool success;\n (success, data) = swapsImpl.delegatecall(data);\n require(success, \"swap failed\");\n\n assembly {\n destTokenAmountReceived := mload(add(data, 32))\n sourceTokenAmountUsed := mload(add(data, 64))\n }\n }\n\n /**\n * @notice Calculate expected amount of destiny tokens.\n *\n * @dev Calls swapsImpl::internalExpectedReturn\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceTokenAmount The amount of the source tokens.\n *\n * @param destTokenAmount The amount of destiny tokens.\n * */\n function _swapsExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) internal view returns (uint256 destTokenAmount) {\n destTokenAmount = ISwapsImpl(swapsImpl).internalExpectedReturn(\n sourceToken,\n destToken,\n sourceTokenAmount,\n sovrynSwapContractRegistryAddress,\n defaultPathConversion[sourceToken][destToken]\n );\n }\n\n /**\n * @notice Verify that the amount of tokens are under the swap limit.\n *\n * @dev Calls priceFeeds::amountInEth\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n * */\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\n uint256 _maxSwapSize = maxSwapSize;\n if (_maxSwapSize != 0) {\n uint256 amountInEth;\n if (tokenAddress == address(wrbtcToken)) {\n amountInEth = amount;\n } else {\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\n }\n require(amountInEth <= _maxSwapSize, \"swap too large\");\n }\n }\n}\n" + }, + "contracts/testhelpers/FlashLoanerTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n// \"SPDX-License-Identifier: Apache-2.0\"\n\nimport \"../interfaces/IERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./ITokenFlashLoanTest.sol\";\n\ncontract FlashLoanerTest is Ownable {\n function initiateFlashLoanTest(\n address loanToken,\n address iToken,\n uint256 flashLoanAmount\n ) internal returns (bytes memory success) {\n ITokenFlashLoanTest iTokenContract = ITokenFlashLoanTest(iToken);\n return\n iTokenContract.flashBorrow(\n flashLoanAmount,\n address(this),\n address(this),\n \"\",\n abi.encodeWithSignature(\n \"executeOperation(address,address,uint256)\",\n loanToken,\n iToken,\n flashLoanAmount\n )\n );\n }\n\n function repayFlashLoan(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) internal {\n IERC20(loanToken).transfer(iToken, loanAmount);\n }\n\n function executeOperation(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) external returns (bytes memory success) {\n emit BalanceOf(IERC20(loanToken).balanceOf(address(this)));\n emit ExecuteOperation(loanToken, iToken, loanAmount);\n repayFlashLoan(loanToken, iToken, loanAmount);\n return bytes(\"1\");\n }\n\n function doStuffWithFlashLoan(\n address token,\n address iToken,\n uint256 amount\n ) external onlyOwner {\n bytes memory result;\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n result = initiateFlashLoanTest(token, iToken, amount);\n\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n // after loan checks and what not.\n if (hashCompareWithLengthCheck(bytes(\"1\"), result)) {\n revert(\"failed executeOperation\");\n }\n }\n\n function hashCompareWithLengthCheck(bytes memory a, bytes memory b)\n internal\n pure\n returns (bool)\n {\n if (a.length != b.length) {\n return false;\n } else {\n return keccak256(a) == keccak256(b);\n }\n }\n\n event ExecuteOperation(address loanToken, address iToken, uint256 loanAmount);\n\n event BalanceOf(uint256 balance);\n}\n" + }, + "contracts/testhelpers/interfaces/IERC1820Registry.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the global ERC1820 Registry, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register\n * implementers for interfaces in this registry, as well as query support.\n *\n * Implementers may be shared by multiple accounts, and can also implement more\n * than a single interface for each account. Contracts can implement interfaces\n * for themselves, but externally-owned accounts (EOA) must delegate this to a\n * contract.\n *\n * {IERC165} interfaces can also be queried via the registry.\n *\n * For an in-depth explanation and source code analysis, see the EIP text.\n */\ninterface IERC1820Registry {\n /**\n * @dev Sets `newManager` as the manager for `account`. A manager of an\n * account is able to set interface implementers for it.\n *\n * By default, each account is its own manager. Passing a value of `0x0` in\n * `newManager` will reset the manager to this initial state.\n *\n * Emits a {ManagerChanged} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n */\n function setManager(address account, address newManager) external;\n\n /**\n * @dev Returns the manager for `account`.\n *\n * See {setManager}.\n */\n function getManager(address account) external view returns (address);\n\n /**\n * @dev Sets the `implementer` contract as `account`'s implementer for\n * `interfaceHash`.\n *\n * `account` being the zero address is an alias for the caller's address.\n * The zero address can also be used in `implementer` to remove an old one.\n *\n * See {interfaceHash} to learn how these are created.\n *\n * Emits an {InterfaceImplementerSet} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not\n * end in 28 zeroes).\n * - `implementer` must implement {IERC1820Implementer} and return true when\n * queried for support, unless `implementer` is the caller. See\n * {IERC1820Implementer-canImplementInterfaceForAddress}.\n */\n function setInterfaceImplementer(\n address account,\n bytes32 interfaceHash,\n address implementer\n ) external;\n\n /**\n * @dev Returns the implementer of `interfaceHash` for `account`. If no such\n * implementer is registered, returns the zero address.\n *\n * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28\n * zeroes), `account` will be queried for support of it.\n *\n * `account` being the zero address is an alias for the caller's address.\n */\n function getInterfaceImplementer(address account, bytes32 interfaceHash)\n external\n view\n returns (address);\n\n /**\n * @dev Returns the interface hash for an `interfaceName`, as defined in the\n * corresponding\n * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].\n */\n function interfaceHash(string calldata interfaceName) external pure returns (bytes32);\n\n /**\n * @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n * @param account Address of the contract for which to update the cache.\n * @param interfaceId ERC165 interface for which to update the cache.\n */\n function updateERC165Cache(address account, bytes4 interfaceId) external;\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not.\n * If the result is not cached a direct lookup on the contract address is performed.\n * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n * {updateERC165Cache} with the contract address.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165Interface(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n event InterfaceImplementerSet(\n address indexed account,\n bytes32 indexed interfaceHash,\n address indexed implementer\n );\n\n event ManagerChanged(address indexed account, address indexed newManager);\n}\n" + }, + "contracts/testhelpers/ITokenFlashLoanTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n// \"SPDX-License-Identifier: Apache-2.0\"\n\ninterface ITokenFlashLoanTest {\n function flashBorrow(\n uint256 borrowAmount,\n address borrower,\n address target,\n string calldata signature,\n bytes calldata data\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/testhelpers/LoanTokenLogicTest.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicTest is LoanTokenLogic {\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestNonReentrantValueSetter.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\ncontract TestNonReentrantValueSetter is SharedReentrancyGuard {\n uint256 public value;\n\n // This will fail if another globallyNonReentrant function has already been entered\n function setValue(uint256 newValue) public globallyNonReentrant {\n value = newValue;\n }\n\n // this will always fail if `other.setValue` is globallyNonReentrant\n function setOtherContractValueNonReentrant(address other, uint256 newValue)\n external\n globallyNonReentrant\n {\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n\n // this is intentionally not globallyNonReentrant and should work even if both contracts are non-reentrant\n function setThisAndOtherContractValue(address other, uint256 newValue) external {\n setValue(newValue);\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestValueSetterProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract TestValueSetterProxy is UpgradableProxy {\n // This is here for the memory layout\n uint256 public value;\n}\n" + }, + "contracts/testhelpers/staking/StakingTester.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../TestToken.sol\";\n\ncontract StakingTester {\n IStaking public staking;\n TestToken public token;\n\n constructor(address _staking, address _token) public {\n staking = IStaking(_staking);\n token = TestToken(_token);\n }\n\n function stakeAndWithdraw(uint96 _amount, uint256 _until) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _until, address(this), address(this));\n staking.withdraw(_amount, _until, address(this));\n }\n\n function stakeAndDelegate(\n uint96 _amount,\n address _delegatee,\n uint256 _lockDate\n ) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _lockDate, address(this), address(this));\n staking.delegate(_delegatee, _lockDate);\n }\n}\n" + }, + "contracts/testhelpers/TestCoverage.sol": { + "content": "/**\n * In order to test some functionalities like Pausable::pausable() modifier,\n * it is required to add a contract to invoke them and get a full coverage on tests.\n */\n\npragma solidity 0.5.17;\n\nimport \"../connectors/loantoken/Pausable.sol\";\nimport \"../governance/Staking/SafeMath96.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../connectors/loantoken/AdvancedToken.sol\";\nimport \"../connectors/loantoken/LoanTokenLogicStorage.sol\";\n\ncontract TestCoverage is\n Pausable,\n SafeMath96,\n VaultController,\n AdvancedToken,\n LoanTokenLogicStorage\n{\n /// @dev Pausable is currently an unused contract that still is operative\n /// because margin trade flashloan functionality has been commented out.\n /// In case it were restored, contract would become used again, so for a\n /// complete test coverage it is required to test it.\n\n function dummyPausableFunction() external pausable(msg.sig) {\n /// @dev do nothing, just to check if modifier is working\n }\n\n /// @dev This function should be located on Pausable contract in the case\n /// it has to be used again by flashloan restoration.\n function togglePause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047)\n )\n );\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /// @dev Testing internal functions of governance/Staking/SafeMath96.sol\n function testSafeMath96_safe32(uint256 n) public pure returns (uint32) {\n // Public wrapper for SafeMath96 internal function\n return safe32(n, \"overflow\");\n }\n\n function testSafeMath96_safe64(uint256 n) public pure returns (uint64) {\n // Public wrapper for SafeMath96 internal function\n return safe64(n, \"overflow\");\n }\n\n function testSafeMath96_safe96(uint256 n) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return safe96(n, \"overflow\");\n }\n\n function testSafeMath96_sub96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return sub96(a, b, \"underflow\");\n }\n\n function testSafeMath96_mul96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return mul96(a, b, \"overflow\");\n }\n\n function testSafeMath96_div96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return div96(a, b, \"division by 0\");\n }\n\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;\n EnumerableBytes32Set.Bytes32Set internal aSet;\n\n function testEnum_AddRemove(bytes32 a, bytes32 b) public returns (bool) {\n aSet.addBytes32(a);\n return aSet.removeBytes32(b);\n }\n\n function testEnum_AddAddress(address a, address b) public returns (bool) {\n aSet.addAddress(a);\n return aSet.containsAddress(b);\n }\n\n function testEnum_AddAddressesAndEnumerate(\n address a,\n address b,\n uint256 start,\n uint256 count\n ) public returns (bytes32[] memory) {\n aSet.addAddress(a);\n aSet.addAddress(b);\n return aSet.enumerate(start, count);\n }\n\n /// @dev Wrapper to test internal function never called along current codebase\n function testVaultController_vaultApprove(\n address token,\n address to,\n uint256 value\n ) public {\n vaultApprove(token, to, value);\n }\n\n /// @dev mint wrapper w/o previous checks\n function testMint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) public {\n _mint(_to, _tokenAmount, _assetAmount, _price);\n }\n\n /// @dev wrapper for a function unreachable to tests\n function testStringToBytes32(string memory source) public pure returns (bytes32 result) {\n return stringToBytes32(source);\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some ERC777 from the lending pool.\n * 2. Close the loan with closeWithDeposit function in the protocol.\n * 3. Burn all iERC777.\n *\n * The cross-reentrancy happened in step#3. It might happened through a hook function (tokensToSend) that is implemented in this contract to support the ERC777 transfer.\n * Inside the hook function, it will try to mint the iERC777.\n * The details about the hook functions can be found here: https://eips.ethereum.org/EIPS/eip-777#hooks\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithDeposit function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyERC777 {\n address public loanToken;\n address public WRBTC;\n address public SUSD; /// ERC777\n ProtocolLike public sovrynProtocol;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iUSDTBalance;\n }\n\n function() external payable {}\n\n constructor(\n address _loanToken,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanToken = _loanToken;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777TokensSender\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: WRBTC has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n });\n\n IERC20(WRBTC).approve(loanToken, initial.susdBalance);\n\n ILoanTokenModules(loanToken).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n WRBTC,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanToken).loanParamsIds(\n uint256(keccak256(abi.encodePacked(WRBTC, true)))\n );\n bytes32 loan_id =\n keccak256(abi.encodePacked(loanParamsLocalId, loanToken, _borrower, _borrowerNonce));\n\n // STEP 3 close the borrowed position with a deposit\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(address(sovrynProtocol), _SUSDBalance);\n sovrynProtocol.closeWithDeposit(\n loan_id,\n address(this),\n collateralTokenSent.mul(20).div(100) // make it 20% higher from initial borrow amount\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iSUSD\n uint256 _iSUSDBalance = ILoanTokenModules(loanToken).balanceOf(_borrower);\n ILoanTokenModules(loanToken).burn(_receiver, _iSUSDBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n // });\n }\n\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256,\n bytes calldata,\n bytes calldata\n ) external {\n if (operator == address(sovrynProtocol) && to == loanToken && from == address(this)) {\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(loanToken, _SUSDBalance);\n\n ILoanTokenModules(loanToken).mint(address(this), 1000000 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyRBTC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some WRBTC from the lending pool.\n * 2. Close the loan with closeWithSwap function in the protocol.\n * 3. Burn all iWRBTC.\n *\n * The refund happened in step #3, which will send back the RBTC back to this contract.\n * Then, this contract will try to do another iWRBTC minting to the loan token --> this is where the cross-reentrancy happened between the protocol & the loan token contract.\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithSwap function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyRBTC {\n address public loanTokenWRBTC;\n address public WRBTC;\n address public SUSD;\n ProtocolLike public sovrynProtocol;\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iWRBTCBalance;\n }\n\n function() external payable {\n if (msg.sender == address(sovrynProtocol)) {\n uint256 latestRBTCBalance = address(this).balance;\n IWrbtcERC20(WRBTC).deposit.value(14 ether)();\n uint256 _WRBTCBalance = IERC20(WRBTC).balanceOf(address(this));\n IERC20(WRBTC).approve(loanTokenWRBTC, _WRBTCBalance);\n\n ILoanTokenModules(loanTokenWRBTC).mint(address(this), 14 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n\n constructor(\n address _loanTokenWRBTC,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanTokenWRBTC = _loanTokenWRBTC;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: SUSD has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n });\n\n IERC20(SUSD).approve(loanTokenWRBTC, initial.susdBalance);\n\n ILoanTokenModules(loanTokenWRBTC).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n SUSD,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanTokenWRBTC).loanParamsIds(\n uint256(keccak256(abi.encodePacked(SUSD, true)))\n );\n bytes32 loan_id =\n keccak256(\n abi.encodePacked(loanParamsLocalId, loanTokenWRBTC, _borrower, _borrowerNonce)\n );\n\n // STEP 3 close the borrowed position with a swap (probably works just as well with deposit)\n sovrynProtocol.closeWithSwap(\n loan_id,\n msg.sender,\n collateralTokenSent.mul(200).div(100), // make it 20% higher from initial collateral sent to make sure whole position is closed\n true,\n \"\"\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iRBTC\n uint256 _iWRBTCBalance = ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower);\n ILoanTokenModules(loanTokenWRBTC).burn(_receiver, _iWRBTCBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n // });\n }\n}\n" + }, + "contracts/testhelpers/TestLibraries.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../rsk/RSKAddrValidator.sol\";\n\n// contract for testing libraries\ncontract TestLibraries {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n */\n function RSKAddrValidator_checkPKNotZero(address addr) public pure returns (bool) {\n return (RSKAddrValidator.checkPKNotZero(addr));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key\n */\n function RSKAddrValidator_safeEquals(address addr1, address addr2) public pure returns (bool) {\n return (RSKAddrValidator.safeEquals(addr1, addr2));\n }\n}\n" + }, + "contracts/testhelpers/TestSovrynSwap.sol": { + "content": "/**\n * Test file simulating the SovrynSwap network\n * */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"./TestToken.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestSovrynSwap {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n address public priceFeeds;\n\n constructor(address feed) public {\n priceFeeds = feed;\n }\n\n /**\n * simulating the contract registry. always returns the address of this contract\n * */\n function addressOf(bytes32 contractName) public view returns (address) {\n return address(this);\n }\n\n /**\n * calculates the return tokens when swapping _amount, makes sure the return is bigger than _minReturn,\n * mints and burns the test tokens accordingly.\n * */\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256) {\n //compute the return for the amount of tokens provided\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n uint256 actualReturn = _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n\n require(actualReturn >= _minReturn, \"insufficient source tokens provided\");\n\n TestToken(address(_path[0])).burn(address(msg.sender), _amount);\n TestToken(address(_path[1])).mint(address(_beneficiary), actualReturn);\n return actualReturn;\n }\n\n /**\n * queries the rate from the Price Feed contract and computes the expected return amount based on the\n * amout of source tokens to be swapped.\n * */\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n\n return _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * returns the conversion path -> always a direct path\n * */\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory)\n {\n IERC20[] memory path = new IERC20[](2);\n path[0] = _sourceToken;\n path[1] = _targetToken;\n return path;\n }\n}\n" + }, + "contracts/testhelpers/TestToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestToken {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balances[_who], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[_who] = balances[_who].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(_who, _value);\n emit Transfer(_who, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/testhelpers/TestTokenERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Context.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../interfaces/IERC777.sol\";\nimport \"../interfaces/IERC777Recipient.sol\";\nimport \"../interfaces/IERC777Sender.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\n\ncontract TestTokenERC777 is Context, IERC777, IERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n mapping(address => uint256) private _balances;\n\n uint256 private _totalSupply;\n\n // We inline the result of the following hashes because Solidity doesn't resolve them at compile time.\n // See https://github.com/ethereum/solidity/issues/4024.\n\n // keccak256(\"ERC777TokensSender\")\n bytes32 private constant TOKENS_SENDER_INTERFACE_HASH =\n 0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895;\n\n // keccak256(\"ERC777TokensRecipient\")\n bytes32 private constant TOKENS_RECIPIENT_INTERFACE_HASH =\n 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;\n\n // This isn't ever read from - it's only used to respond to the defaultOperators query.\n address[] private _defaultOperatorsArray;\n\n // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).\n mapping(address => bool) private _defaultOperators;\n\n // For each account, a mapping of its operators and revoked default operators.\n mapping(address => mapping(address => bool)) private _operators;\n mapping(address => mapping(address => bool)) private _revokedDefaultOperators;\n\n // ERC20-allowances\n mapping(address => mapping(address => uint256)) private _allowances;\n\n /**\n * @dev `defaultOperators` may be an empty array.\n */\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _initialSupply,\n uint8 _decimals,\n address[] memory defaultOperators\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n _defaultOperatorsArray = defaultOperators;\n for (uint256 i = 0; i < _defaultOperatorsArray.length; i++) {\n _defaultOperators[_defaultOperatorsArray[i]] = true;\n }\n\n _mint(msg.sender, msg.sender, _initialSupply, \"\", \"\");\n\n // register interfaces\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777Token\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n /**\n * @dev See {IERC777-granularity}.\n *\n * This implementation always returns `1`.\n */\n function granularity() public view returns (uint256) {\n return 1;\n }\n\n /**\n * @dev See {IERC777-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev Returns the amount of tokens owned by an account (`tokenHolder`).\n */\n function balanceOf(address tokenHolder) public view returns (uint256) {\n return _balances[tokenHolder];\n }\n\n /**\n * @dev See {IERC777-send}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes memory data\n ) public {\n _send(_msgSender(), _msgSender(), recipient, amount, data, \"\", true);\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient}\n * interface if it is a contract.\n *\n * Also emits a {Sent} event.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n\n address from = _msgSender();\n\n _callTokensToSend(from, from, recipient, amount, \"\", \"\");\n\n _move(from, from, recipient, amount, \"\", \"\");\n\n _callTokensReceived(from, from, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev See {IERC777-burn}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function burn(uint256 amount, bytes memory data) public {\n _burn(_msgSender(), _msgSender(), amount, data, \"\");\n }\n\n /**\n * @dev See {IERC777-isOperatorFor}.\n */\n function isOperatorFor(address operator, address tokenHolder) public view returns (bool) {\n return\n operator == tokenHolder ||\n (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||\n _operators[tokenHolder][operator];\n }\n\n /**\n * @dev See {IERC777-authorizeOperator}.\n */\n function authorizeOperator(address operator) public {\n require(_msgSender() != operator, \"ERC777: authorizing self as operator\");\n\n if (_defaultOperators[operator]) {\n delete _revokedDefaultOperators[_msgSender()][operator];\n } else {\n _operators[_msgSender()][operator] = true;\n }\n\n emit AuthorizedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-revokeOperator}.\n */\n function revokeOperator(address operator) public {\n require(operator != _msgSender(), \"ERC777: revoking self as operator\");\n\n if (_defaultOperators[operator]) {\n _revokedDefaultOperators[_msgSender()][operator] = true;\n } else {\n delete _operators[_msgSender()][operator];\n }\n\n emit RevokedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-defaultOperators}.\n */\n function defaultOperators() public view returns (address[] memory) {\n return _defaultOperatorsArray;\n }\n\n /**\n * @dev See {IERC777-operatorSend}.\n *\n * Emits {Sent} and {IERC20-Transfer} events.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), sender),\n \"ERC777: caller is not an operator for holder\"\n );\n _send(_msgSender(), sender, recipient, amount, data, operatorData, true);\n }\n\n /**\n * @dev See {IERC777-operatorBurn}.\n *\n * Emits {Burned} and {IERC20-Transfer} events.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), account),\n \"ERC777: caller is not an operator for holder\"\n );\n _burn(_msgSender(), account, amount, data, operatorData);\n }\n\n /**\n * @dev See {IERC20-allowance}.\n *\n * Note that operator and allowance concepts are orthogonal: operators may\n * not have allowance, and accounts with allowance may not be operators\n * themselves.\n */\n function allowance(address holder, address spender) public view returns (uint256) {\n return _allowances[holder][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Note that accounts cannot have allowance issued by their operators.\n */\n function approve(address spender, uint256 value) public returns (bool) {\n address holder = _msgSender();\n _approve(holder, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Note that operator and allowance concepts are orthogonal: operators cannot\n * call `transferFrom` (unless they have allowance), and accounts with\n * allowance cannot call `operatorSend` (unless they are operators).\n *\n * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.\n */\n function transferFrom(\n address holder,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n require(holder != address(0), \"ERC777: transfer from the zero address\");\n\n address spender = _msgSender();\n\n _callTokensToSend(spender, holder, recipient, amount, \"\", \"\");\n\n _move(spender, holder, recipient, amount, \"\", \"\");\n\n _approve(\n holder,\n spender,\n _allowances[holder][spender].sub(amount, \"ERC777: transfer amount exceeds allowance\")\n );\n\n _callTokensReceived(spender, holder, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `operator`, `data` and `operatorData`.\n *\n * See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits {Minted} and {IERC20-Transfer} events.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - if `account` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function _mint(\n address operator,\n address account,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n require(account != address(0), \"ERC777: mint to the zero address\");\n\n // Update state variables\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n\n _callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);\n\n emit Minted(operator, account, amount, userData, operatorData);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Send tokens\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _send(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n require(from != address(0), \"ERC777: send from the zero address\");\n require(to != address(0), \"ERC777: send to the zero address\");\n\n _callTokensToSend(operator, from, to, amount, userData, operatorData);\n\n _move(operator, from, to, amount, userData, operatorData);\n\n _callTokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData,\n requireReceptionAck\n );\n }\n\n /**\n * @dev Burn tokens\n * @param operator address operator requesting the operation\n * @param from address token holder address\n * @param amount uint256 amount of tokens to burn\n * @param data bytes extra information provided by the token holder\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _burn(\n address operator,\n address from,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) internal {\n require(from != address(0), \"ERC777: burn from the zero address\");\n\n _callTokensToSend(operator, from, address(0), amount, data, operatorData);\n\n // Update state variables\n _balances[from] = _balances[from].sub(amount, \"ERC777: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n\n emit Burned(operator, from, amount, data, operatorData);\n emit Transfer(from, address(0), amount);\n }\n\n function _move(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) private {\n _balances[from] = _balances[from].sub(amount, \"ERC777: transfer amount exceeds balance\");\n _balances[to] = _balances[to].add(amount);\n\n emit Sent(operator, from, to, amount, userData, operatorData);\n emit Transfer(from, to, amount);\n }\n\n function _approve(\n address holder,\n address spender,\n uint256 value\n ) internal {\n // TODO: restore this require statement if this function becomes internal, or is called at a new callsite. It is\n // currently unnecessary.\n //require(holder != address(0), \"ERC777: approve from the zero address\");\n require(spender != address(0), \"ERC777: approve to the zero address\");\n\n _allowances[holder][spender] = value;\n emit Approval(holder, spender, value);\n }\n\n /**\n * @dev Call from.tokensToSend() if the interface is registered\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _callTokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Sender(implementer).tokensToSend(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n }\n }\n\n /**\n * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but\n * tokensReceived() was not registered for the recipient\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _callTokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Recipient(implementer).tokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n } else if (requireReceptionAck) {\n require(\n !to.isContract(),\n \"ERC777: token recipient contract has no implementer for ERC777TokensRecipient\"\n );\n }\n }\n\n function mint(address _to, uint256 _value) public {\n // Update state variables\n _totalSupply = _totalSupply.add(_value);\n _balances[_to] = _balances[_to].add(_value);\n\n emit Minted(msg.sender, _to, _value, \"\", \"\");\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balanceOf(_who), \"balance too low\");\n\n _burn(msg.sender, _who, _value, \"\", \"\");\n }\n}\n" + }, + "contracts/testhelpers/TestTokenLimited.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestTokenLimited {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n require(_value <= 100000 ether, \"max mint amount exceeded\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(uint256 _value) public {\n require(_value <= balances[msg.sender], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(msg.sender, _value);\n emit Transfer(msg.sender, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/token/IApproveAndCall.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/ApprovalReceiver.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IApproveAndCall {\n /**\n * @notice Receives approval from SOV token.\n * @param _sender The sender of SOV.approveAndCall function.\n * @param _amount The amount was approved.\n * @param _token The address of token.\n * @param _data The data will be used for low level call.\n * */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/token/SOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/ERC20Detailed.sol\";\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./IApproveAndCall.sol\";\n\n/**\n * @title Sovryn Token: SOV is an ERC-20 token contract for Sovryn governance.\n *\n * @notice This contract accounts for all holders' balances.\n *\n * @dev This contract represents a token with dynamic supply.\n * The owner of the token contract can mint/burn tokens to/from any account\n * based upon previous governance voting and approval.\n * */\ncontract SOV is ERC20, ERC20Detailed, Ownable {\n string constant NAME = \"Sovryn Token\";\n string constant SYMBOL = \"SOV\";\n uint8 constant DECIMALS = 18;\n\n /**\n * @notice Constructor called on deployment, initiates the contract.\n * @dev On deployment, some amount of tokens will be minted for the owner.\n * @param _initialAmount The amount of tokens to be minted on contract creation.\n * */\n constructor(uint256 _initialAmount) public ERC20Detailed(NAME, SYMBOL, DECIMALS) {\n if (_initialAmount != 0) {\n _mint(msg.sender, _initialAmount);\n }\n }\n\n /**\n * @notice Creates new tokens and sends them to the recipient.\n * @dev Don't create more than 2^96/10 tokens before updating the governance first.\n * @param _account The recipient address to get the minted tokens.\n * @param _amount The amount of tokens to be minted.\n * */\n function mint(address _account, uint256 _amount) public onlyOwner {\n _mint(_account, _amount);\n }\n\n /**\n * @notice Approves and then calls the receiving contract.\n * Useful to encapsulate sending tokens to a contract in one call.\n * Solidity has no native way to send tokens to contracts.\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\n * @param _spender The contract address to spend the tokens.\n * @param _amount The amount of tokens to be sent.\n * @param _data Parameters for the contract call, such as endpoint signature.\n * */\n function approveAndCall(\n address _spender,\n uint256 _amount,\n bytes memory _data\n ) public {\n approve(_spender, _amount);\n IApproveAndCall(_spender).receiveApproval(msg.sender, _amount, address(this), _data);\n }\n}\n" + }, + "contracts/utils/AdminRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\n\ncontract AdminRole is Ownable {\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * or on our own overriding sovrynOwnable.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n}\n" + }, + "contracts/utils/PausableRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/PausableOz.sol\";\n\ncontract PausableRole is PausableOz {\n address public pauser;\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n\n /**\n * @dev Modifier to make a function callable only when the caller is pauser or owner\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"Pausable: unauthorized\"); // SS02\n _;\n }\n\n /**\n * @notice Set the pauser address.\n *\n * only pauser can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyPauserOrOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyPauserOrOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/utils/ProxyOwnable.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\n/**\n * Based on OpenZeppelin's Ownable contract:\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\n *\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract ProxyOwnable {\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Ownable:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"ProxyOwnable::setProxyOwner: invalid address\");\n emit ProxyOwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Set address of the owner (only owner can call this function)\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n\n /**\n * @notice Return address of the owner.\n * @return _owner Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n}\n" + }, + "contracts/utils/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\nlibrary Utils {\n function stringToBytes32(string memory source) internal pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + }, + "remappings": [ + "ds-test/=foundry/lib/forge-std/lib/ds-test/src/", + "forge-std/=foundry/lib/forge-std/src/" + ] + } +} \ No newline at end of file diff --git a/deployment/deployments/rskSovrynTestnet/LoanOpenings.json b/deployment/deployments/rskSovrynTestnet/LoanOpenings.json index dbc6dabd5..30e1de4ab 100644 --- a/deployment/deployments/rskSovrynTestnet/LoanOpenings.json +++ b/deployment/deployments/rskSovrynTestnet/LoanOpenings.json @@ -1,5 +1,5 @@ { - "address": "0xE8659f42489b671F0215257cb6557EFAb15dfAa0", + "address": "0xc6Eb030BE1CBA9d09AB41e94AEc833bb5f0B86e8", "abi": [ { "inputs": [], @@ -1979,45 +1979,45 @@ "type": "function" } ], - "transactionHash": "0xc7037e920a28a1aff876ed87d6a8de3d5f340bb19b765823f2e5d80a18a4af68", + "transactionHash": "0x1099988394e586eef8f47e9c2cc0bdd1b8b5fca312242e96c72b2b09e270e5a2", "receipt": { "to": null, - "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", - "contractAddress": "0xE8659f42489b671F0215257cb6557EFAb15dfAa0", + "from": "0x8C9143221F2b72Fcef391893c3a02Cf0fE84f50b", + "contractAddress": "0xc6Eb030BE1CBA9d09AB41e94AEc833bb5f0B86e8", "transactionIndex": 0, - "gasUsed": "5868155", - "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000030000000000000000001800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x8a6faa21b337123d4101d0345d29305acd09f0da3c3f11e0465d39211eff777a", - "transactionHash": "0xc7037e920a28a1aff876ed87d6a8de3d5f340bb19b765823f2e5d80a18a4af68", + "gasUsed": "5911810", + "logsBloom": "0x00000000000000000000000000000000000000001000000000800000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000080000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x7037ee8b0aa00ef387ed9c8d964c873e5460144f62bc73a2fef3c7a83ef3d78d", + "transactionHash": "0x1099988394e586eef8f47e9c2cc0bdd1b8b5fca312242e96c72b2b09e270e5a2", "logs": [ { "transactionIndex": 0, - "blockNumber": 4578761, - "transactionHash": "0xc7037e920a28a1aff876ed87d6a8de3d5f340bb19b765823f2e5d80a18a4af68", - "address": "0xE8659f42489b671F0215257cb6557EFAb15dfAa0", + "blockNumber": 4704809, + "transactionHash": "0x1099988394e586eef8f47e9c2cc0bdd1b8b5fca312242e96c72b2b09e270e5a2", + "address": "0xc6Eb030BE1CBA9d09AB41e94AEc833bb5f0B86e8", "topics": [ "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + "0x0000000000000000000000008c9143221f2b72fcef391893c3a02cf0fe84f50b" ], "data": "0x", "logIndex": 0, - "blockHash": "0x8a6faa21b337123d4101d0345d29305acd09f0da3c3f11e0465d39211eff777a" + "blockHash": "0x7037ee8b0aa00ef387ed9c8d964c873e5460144f62bc73a2fef3c7a83ef3d78d" } ], - "blockNumber": 4578761, - "cumulativeGasUsed": "5868155", + "blockNumber": 4704809, + "cumulativeGasUsed": "5911810", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 1, - "solcInputHash": "9310031b42d2950fea7a6220c73f2cc4", - "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCollateral\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestDuration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"collateralToLoanRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"currentMargin\",\"type\":\"uint256\"}],\"name\":\"Borrow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegated\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isActive\",\"type\":\"bool\"}],\"name\":\"DelegatedManagerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeRebatePercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"basisPoint\",\"type\":\"uint256\"}],\"name\":\"EarnReward\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeRebatePercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"basisPoint\",\"type\":\"uint256\"}],\"name\":\"EarnRewardFail\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sourceAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"}],\"name\":\"ExternalSwap\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sourceAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"}],\"name\":\"LoanSwap\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayBorrowingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"interestToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"effectiveInterest\",\"type\":\"uint256\"}],\"name\":\"PayInterestTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayLendingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayTradingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"prevModuleContractAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newModuleContractAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"module\",\"type\":\"bytes32\"}],\"name\":\"ProtocolModuleContractReplaced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"positionSize\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"borrowedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"settlementDate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entryPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entryLeverage\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"currentLeverage\",\"type\":\"uint256\"}],\"name\":\"Trade\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"VaultDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"VaultWithdraw\",\"type\":\"event\"},{\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"constant\":true,\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"affiliateFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliateRewardsHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"affiliateTradingTokenFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliatesReferrerBalances\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliatesUserReferrer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"loanParamsId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"initialMargin\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"manager\",\"type\":\"address\"}],\"internalType\":\"struct MarginTradeStructHelpers.SentAddresses\",\"name\":\"sentAddresses\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestInitialAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"loanTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minEntryPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"loanToCollateralSwapRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"entryLeverage\",\"type\":\"uint256\"}],\"internalType\":\"struct MarginTradeStructHelpers.SentAmounts\",\"name\":\"sentValues\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"loanDataBytes\",\"type\":\"bytes\"}],\"name\":\"borrowOrTradeFromPool\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newCollateral\",\"type\":\"uint256\"}],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowerNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"borrowerOrders\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"lockedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"createdTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expirationTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"borrowingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"delegatedManagers\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feeRebatePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feesController\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"marginAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"}],\"name\":\"getBorrowAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"borrowAmount\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"loanTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"}],\"name\":\"getEstimatedMarginExposure\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"marginAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"}],\"name\":\"getRequiredCollateral\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"collateralAmountRequired\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lenderInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"principalTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"owedPerDay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"owedTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"paidTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"lenderOrders\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"lockedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"createdTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expirationTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"lendingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lendingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lendingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"liquidationIncentivePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loanInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"owedPerDay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"depositTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loanParams\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minInitialMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maintenanceMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"loanPoolToUnderlying\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loans\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"loanParamsId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"pendingTradesId\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"principal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateral\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startRate\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"lockedSOVAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"name\":\"logicTargets\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"maxDisagreement\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"maxSwapSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"minReferralsToPayout\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"pause\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"priceFeeds\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rolloverBaseReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rolloverFlexFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"delegated\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"toggle\",\"type\":\"bool\"}],\"name\":\"setDelegatedManager\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sourceBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sovTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sovrynSwapContractRegistryAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"specialRebates\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"supportedTokens\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"swapsImpl\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"tradingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tradingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tradingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"underlyingToLoanPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"userNotFirstTradeFlag\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"wrbtcToken\",\"outputs\":[{\"internalType\":\"contract IWrbtcERC20\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{\"borrowOrTradeFromPool(bytes32,bytes32,bool,uint256,(address,address,address,address),(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),bytes)\":{\"details\":\"Note: Only callable by loan pools (iTokens). Wrapper to _borrowOrTrade internal function.\",\"params\":{\"initialMargin\":\"The initial amount of margin.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanDataBytes\":\"The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\",\"loanId\":\"The ID of the loan. If 0, start a new loan.\",\"loanParamsId\":\"The ID of the loan parameters.\",\"sentAddresses\":\"The addresses to send tokens: lender, borrower, receiver and manager: lender: must match loan if loanId provided. borrower: must match loan if loanId provided. receiver: receiver of funds (address(0) assumes borrower address). manager: delegated manager of loan unless address(0).\",\"sentValues\":\"The values to send: interestRate: New loan interest rate. newPrincipal: New loan size (borrowAmount + any borrowed interest). interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length). loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans). collateralTokenSent: Total collateralToken deposit. minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\"},\"return\":\"newPrincipal The new loan size.newCollateral The new collateral amount.\"},\"getBorrowAmount(address,address,uint256,uint256,bool)\":{\"details\":\"Basically borrowAmount = collateral / marginAmount * Collateral is something that helps secure a loan. When you borrow money, you agree that your lender can take something and sell it to get their money back if you fail to repay the loan. That's the collateral.\",\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"collateralTokenAmount\":\"The amount of collateral.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanToken\":\"The loan token instance address.\",\"marginAmount\":\"The amount of margin of the trade.\"},\"return\":\"borrowAmount The borrow amount.\"},\"getEstimatedMarginExposure(address,address,uint256,uint256,uint256,uint256)\":{\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"collateralTokenSent\":\"The amount of collateral tokens sent.\",\"interestRate\":\"The interest rate. Percentage w/ 18 decimals.\",\"loanToken\":\"The loan token instance address.\",\"loanTokenSent\":\"The amount of loan tokens sent.\",\"newPrincipal\":\"The updated amount of principal (current debt).\"},\"return\":\"The margin exposure.\"},\"getRequiredCollateral(address,address,uint256,uint256,bool)\":{\"details\":\"Calls internal _getRequiredCollateral and add fees.\",\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanToken\":\"The loan token instance address.\",\"marginAmount\":\"The amount of margin of the trade.\",\"newPrincipal\":\"The updated amount of principal (current debt).\"},\"return\":\"collateralAmountRequired The required collateral.\"},\"initialize(address)\":{\"params\":{\"target\":\"The address of the target contract.\"}},\"isOwner()\":{\"details\":\"Returns true if the caller is the current owner.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"setDelegatedManager(bytes32,address,bool)\":{\"details\":\"Wrapper for _setDelegatedManager internal function.\",\"params\":{\"delegated\":\"The address of the delegated manager.\",\"loanId\":\"The ID of the loan. If 0, start a new loan.\",\"toggle\":\"The flag true/false for the delegated manager.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"Loan Openings contract.\"},\"userdoc\":{\"methods\":{\"borrowOrTradeFromPool(bytes32,bytes32,bool,uint256,(address,address,address,address),(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),bytes)\":{\"notice\":\"Borrow or trade from pool.\"},\"getBorrowAmount(address,address,uint256,uint256,bool)\":{\"notice\":\"Get the borrow amount of a trade loan.\"},\"getEstimatedMarginExposure(address,address,uint256,uint256,uint256,uint256)\":{\"notice\":\"Get the estimated margin exposure. * Margin is the money borrowed from a broker to purchase an investment and is the difference between the total value of investment and the loan amount. Margin trading refers to the practice of using borrowed funds from a broker to trade a financial asset, which forms the collateral for the loan from the broker.\"},\"getRequiredCollateral(address,address,uint256,uint256,bool)\":{\"notice\":\"Get the required collateral.\"},\"initialize(address)\":{\"notice\":\"Set function selectors on target contract.\"},\"setDelegatedManager(bytes32,address,bool)\":{\"notice\":\"Set the delegated manager.\"}},\"notice\":\"This contract code comes from bZx. bZx is a protocol for tokenized margin trading and lending https://bzx.network similar to the dYdX protocol. * This contract contains functions to borrow and trade.\"}},\"settings\":{\"compilationTarget\":{\"contracts/modules/LoanOpenings.sol\":\"LoanOpenings\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nlibrary MarginTradeStructHelpers {\\n struct SentAddresses {\\n address lender;\\n address borrower;\\n address receiver;\\n address manager;\\n }\\n\\n struct SentAmounts {\\n uint256 interestRate;\\n uint256 newPrincipal;\\n uint256 interestInitialAmount;\\n uint256 loanTokenSent;\\n uint256 collateralTokenSent;\\n uint256 minEntryPrice;\\n uint256 loanToCollateralSwapRate;\\n uint256 interestDuration;\\n uint256 entryLeverage;\\n }\\n}\\n\",\"keccak256\":\"0xf0612e2c0d13604a67c3d55efe88810c089f0b84ca63bd3ce82c1e09b0938973\"},\"contracts/core/Objects.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./objects/LoanStruct.sol\\\";\\nimport \\\"./objects/LoanParamsStruct.sol\\\";\\nimport \\\"./objects/OrderStruct.sol\\\";\\nimport \\\"./objects/LenderInterestStruct.sol\\\";\\nimport \\\"./objects/LoanInterestStruct.sol\\\";\\n\\n/**\\n * @title Objects contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract inherints and aggregates several structures needed to handle\\n * loans on the protocol.\\n * */\\ncontract Objects is\\n LoanStruct,\\n LoanParamsStruct,\\n OrderStruct,\\n LenderInterestStruct,\\n LoanInterestStruct\\n{\\n\\n}\\n\",\"keccak256\":\"0xa30b8887af813997ebb480f0aa296245f9f3bd728382060059aa087cd9ee332c\"},\"contracts/core/State.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./Objects.sol\\\";\\nimport \\\"../mixins/EnumerableAddressSet.sol\\\";\\nimport \\\"../mixins/EnumerableBytes32Set.sol\\\";\\nimport \\\"../openzeppelin/ReentrancyGuard.sol\\\";\\nimport \\\"../openzeppelin/Ownable.sol\\\";\\nimport \\\"../openzeppelin/SafeMath.sol\\\";\\nimport \\\"../interfaces/IWrbtcERC20.sol\\\";\\nimport \\\"../reentrancy/SharedReentrancyGuard.sol\\\";\\n\\n/**\\n * @title State contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage values of the Protocol.\\n * */\\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\\n using SafeMath for uint256;\\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\\n\\n /// Handles asset reference price lookups.\\n address public priceFeeds;\\n\\n /// Handles asset swaps using dex liquidity.\\n address public swapsImpl;\\n\\n /// Contract registry address of the Sovryn swap network.\\n address public sovrynSwapContractRegistryAddress;\\n\\n /// Implementations of protocol functions.\\n mapping(bytes4 => address) public logicTargets;\\n\\n /// Loans: loanId => Loan\\n mapping(bytes32 => Loan) public loans;\\n\\n /// Loan parameters: loanParamsId => LoanParams\\n mapping(bytes32 => LoanParams) public loanParams;\\n\\n /// lender => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\\n\\n /// borrower => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\\n\\n /// loanId => delegated => approved\\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\\n\\n /**\\n *** Interest ***\\n **/\\n\\n /// lender => loanToken => LenderInterest object\\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\\n\\n /// loanId => LoanInterest object\\n mapping(bytes32 => LoanInterest) public loanInterest;\\n\\n /**\\n *** Internals ***\\n **/\\n\\n /// Implementations set.\\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\\n\\n /// Active loans set.\\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\\n\\n /// Lender loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\\n\\n /// Borrow loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\\n\\n /// User loan params set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\\n\\n /// Address controlling fee withdrawals.\\n address public feesController;\\n\\n /// 10% fee /// Fee taken from lender interest payments.\\n uint256 public lendingFeePercent = 10**19;\\n\\n /// Total interest fees received and not withdrawn per asset.\\n mapping(address => uint256) public lendingFeeTokensHeld;\\n\\n /// Total interest fees withdraw per asset.\\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\\n mapping(address => uint256) public lendingFeeTokensPaid;\\n\\n /// 0.15% fee /// Fee paid for each trade.\\n uint256 public tradingFeePercent = 15 * 10**16;\\n\\n /// Total trading fees received and not withdrawn per asset.\\n mapping(address => uint256) public tradingFeeTokensHeld;\\n\\n /// Total trading fees withdraw per asset\\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\\n mapping(address => uint256) public tradingFeeTokensPaid;\\n\\n /// 0.09% fee /// Origination fee paid for each loan.\\n uint256 public borrowingFeePercent = 9 * 10**16;\\n\\n /// Total borrowing fees received and not withdrawn per asset.\\n mapping(address => uint256) public borrowingFeeTokensHeld;\\n\\n /// Total borrowing fees withdraw per asset.\\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\\n mapping(address => uint256) public borrowingFeeTokensPaid;\\n\\n /// Current protocol token deposit balance.\\n uint256 public protocolTokenHeld;\\n\\n /// Lifetime total payout of protocol token.\\n uint256 public protocolTokenPaid;\\n\\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\\n uint256 public affiliateFeePercent = 5 * 10**18;\\n\\n /// 5% collateral discount /// Discount on collateral for liquidators.\\n uint256 public liquidationIncentivePercent = 5 * 10**18;\\n\\n /// loanPool => underlying\\n mapping(address => address) public loanPoolToUnderlying;\\n\\n /// underlying => loanPool\\n mapping(address => address) public underlyingToLoanPool;\\n\\n /// Loan pools set.\\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\\n\\n /// Supported tokens for swaps.\\n mapping(address => bool) public supportedTokens;\\n\\n /// % disagreement between swap rate and reference rate.\\n uint256 public maxDisagreement = 5 * 10**18;\\n\\n /// Used as buffer for swap source amount estimations.\\n uint256 public sourceBuffer = 10000;\\n\\n /// Maximum support swap size in rBTC\\n uint256 public maxSwapSize = 50 ether;\\n\\n /// Nonce per borrower. Used for loan id creation.\\n mapping(address => uint256) public borrowerNonce;\\n\\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\\n uint256 public rolloverBaseReward = 16800000000000;\\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\\n\\n IWrbtcERC20 public wrbtcToken;\\n address public protocolTokenAddress;\\n\\n /// 50% fee rebate\\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\\n uint256 public feeRebatePercent = 50 * 10**18;\\n\\n address public admin;\\n\\n /// For modules interaction.\\n address public protocolAddress;\\n\\n /**\\n *** Affiliates ***\\n **/\\n\\n /// The flag is set on the user's first trade.\\n mapping(address => bool) public userNotFirstTradeFlag;\\n\\n /// User => referrer (affiliate).\\n mapping(address => address) public affiliatesUserReferrer;\\n\\n /// List of referral addresses affiliated to the referrer.\\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\\n\\n /// @dev Referral threshold for paying out to the referrer.\\n /// The referrer reward is being accumulated and locked until the threshold is passed.\\n uint256 public minReferralsToPayout = 3;\\n\\n /// @dev Total affiliate SOV rewards that held in the protocol\\n /// (Because the minimum referrals is less than the rule)\\n mapping(address => uint256) public affiliateRewardsHeld;\\n\\n /// @dev For affiliates SOV Bonus proccess.\\n address public sovTokenAddress;\\n address public lockedSOVAddress;\\n\\n /// @dev 20% fee share of trading token fee.\\n /// Fee share of trading token fee for affiliate program.\\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\\n\\n /// @dev Addresses of tokens in which commissions were paid to referrers.\\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\\n\\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\\n\\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\\n bool public pause; //Flag to pause all protocol modules\\n\\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\\n\\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\\n uint256 internal tradingRebateRewardsBasisPoint;\\n\\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\\n /// Will be used in internal swap.\\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\\n\\n address internal pauser;\\n\\n /**\\n * @notice Add signature and target to storage.\\n * @dev Protocol is a proxy and requires a way to add every\\n * module function dynamically during deployment.\\n * */\\n function _setTarget(bytes4 sig, address target) internal {\\n logicTargets[sig] = target;\\n\\n if (target != address(0)) {\\n logicTargetsSet.addBytes32(bytes32(sig));\\n } else {\\n logicTargetsSet.removeBytes32(bytes32(sig));\\n }\\n }\\n\\n modifier onlyAdminOrOwner() {\\n require(isOwner() || admin == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n\\n modifier onlyPauserOrOwner() {\\n require(isOwner() || pauser == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0xf8dfc02f3dc790c73b390a69898d0281c4473487bc91fec1f28fbebceacd3b3c\"},\"contracts/core/objects/LenderInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Lender Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Lender Interest.\\n * */\\ncontract LenderInterestStruct {\\n struct LenderInterest {\\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\\n uint256 paidTotal; /// Total interest paid so far for asset.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0x6583baadddded384836cec469980e7973ec09310ae505b4a2ec67fb7bc19e452\"},\"contracts/core/objects/LoanInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Interest.\\n * */\\ncontract LoanInterestStruct {\\n struct LoanInterest {\\n uint256 owedPerDay; /// Interest owed per day for loan.\\n uint256 depositTotal; /// Total escrowed interest for loan.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0xd9034c6adb1b72e1593589dca024dc4730a1ee8bf6b2dca9d22283f2e7159590\"},\"contracts/core/objects/LoanParamsStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Parameters.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Parameters.\\n * */\\ncontract LoanParamsStruct {\\n struct LoanParams {\\n /// @dev ID of loan params object.\\n bytes32 id;\\n /// @dev If false, this object has been disabled by the owner and can't\\n /// be used for future loans.\\n bool active;\\n /// @dev Owner of this object.\\n address owner;\\n /// @dev The token being loaned.\\n address loanToken;\\n /// @dev The required collateral token.\\n address collateralToken;\\n /// @dev The minimum allowed initial margin.\\n uint256 minInitialMargin;\\n /// @dev An unhealthy loan when current margin is at or below this value.\\n uint256 maintenanceMargin;\\n /// @dev The maximum term for new loans (0 means there's no max term).\\n uint256 maxLoanTerm;\\n }\\n}\\n\",\"keccak256\":\"0xe15aa97713521da7f501e5225af9d92cf34bd68d286dbfed86aa75aabb323945\"},\"contracts/core/objects/LoanStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Object.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Object.\\n * */\\ncontract LoanStruct {\\n struct Loan {\\n bytes32 id; /// ID of the loan.\\n bytes32 loanParamsId; /// The linked loan params ID.\\n bytes32 pendingTradesId; /// The linked pending trades ID.\\n bool active; /// If false, the loan has been fully closed.\\n uint256 principal; /// Total borrowed amount outstanding.\\n uint256 collateral; /// Total collateral escrowed for the loan.\\n uint256 startTimestamp; /// Loan start time.\\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\\n uint256 startMargin; /// Initial margin when the loan opened.\\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\\n address borrower; /// Borrower of this loan.\\n address lender; /// Lender of this loan.\\n }\\n}\\n\",\"keccak256\":\"0x7d05c3096a86d5892e4e72f3a01a5a806f13a5ac90ca6339c611e75c603637b4\"},\"contracts/core/objects/OrderStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Order.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Order.\\n * */\\ncontract OrderStruct {\\n struct Order {\\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\\n uint256 interestRate; /// Interest rate defined by the creator of this order.\\n uint256 minLoanTerm; /// Minimum loan term allowed.\\n uint256 maxLoanTerm; /// Maximum loan term allowed.\\n uint256 createdTimestamp; /// Timestamp when this order was created.\\n uint256 expirationTimestamp; /// Timestamp when this order expires.\\n }\\n}\\n\",\"keccak256\":\"0xcc053c5da34a5927041162259bf856ba913f3524ca03e63ad0c5877777d17e0f\"},\"contracts/events/AffiliatesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\ncontract AffiliatesEvents is ModulesCommonEvents {\\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\\n\\n event SetAffiliatesReferrerFail(\\n address indexed user,\\n address indexed referrer,\\n bool alreadySet,\\n bool userNotFirstTrade\\n );\\n\\n event SetUserNotFirstTradeFlag(address indexed user);\\n\\n event PayTradingFeeToAffiliate(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n bool indexed isHeld,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountPaid\\n );\\n\\n event PayTradingFeeToAffiliateFail(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountTryingToPaid\\n );\\n\\n event WithdrawAffiliatesReferrerTokenFees(\\n address indexed referrer,\\n address indexed receiver,\\n address indexed tokenAddress,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xf72cf23e90db3c49589ddc4e1796680ebfb69a9b146db89f9b61f5fcf6dd95ba\"},\"contracts/events/FeesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Fees Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for fee payments.\\n * */\\ncontract FeesEvents {\\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\\n\\n event PayTradingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event PayBorrowingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event EarnReward(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n\\n event EarnRewardFail(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n}\\n\",\"keccak256\":\"0xe69bf53e15479be5fde1cbaadaf0c004ee038e8a6a37c99f7769bf5d8387015f\"},\"contracts/events/LoanClosingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Closing Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan closing operations.\\n * */\\ncontract LoanClosingsEvents is ModulesCommonEvents {\\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\\n event CloseWithDeposit(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address closer,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\\n event CloseWithSwap(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n address closer,\\n uint256 positionCloseSize,\\n uint256 loanCloseAmount,\\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\\n event Liquidate(\\n address indexed user,\\n address indexed liquidator,\\n bytes32 indexed loanId,\\n address lender,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n event Rollover(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n uint256 principal,\\n uint256 collateral,\\n uint256 endTimestamp,\\n address rewardReceiver,\\n uint256 reward\\n );\\n\\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\\n}\\n\",\"keccak256\":\"0x1ea325b9a213012865a52f38941ce6c1e8c29dce919215b5bdcc63a8a5980be1\"},\"contracts/events/LoanMaintenanceEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Maintenance Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan maintenance operations.\\n * */\\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\\n}\\n\",\"keccak256\":\"0xdee5098b947c22bcef6e38ecaf62bae6941572d1c245d2065ad41ea4f494c61d\"},\"contracts/events/LoanOpeningsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Openings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan openings operations.\\n * */\\ncontract LoanOpeningsEvents is ModulesCommonEvents {\\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\\n event Borrow(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 newCollateral,\\n uint256 interestRate,\\n uint256 interestDuration,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\\n event Trade(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n uint256 positionSize,\\n uint256 borrowedAmount,\\n uint256 interestRate,\\n uint256 settlementDate,\\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\\n uint256 entryLeverage,\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\\n event DelegatedManagerSet(\\n bytes32 indexed loanId,\\n address indexed delegator,\\n address indexed delegated,\\n bool isActive\\n );\\n}\\n\",\"keccak256\":\"0x585710ce6c570c6dbd1b8daf43b63a54b1d60ad01ee1dc3cae407d74d78f3093\"},\"contracts/events/LoanSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan settings operations.\\n * */\\ncontract LoanSettingsEvents is ModulesCommonEvents {\\n event LoanParamsSetup(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\\n\\n event LoanParamsDisabled(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\\n}\\n\",\"keccak256\":\"0xae9c49678a7bc02c2283648939c474c8bfd33781506e05c635c8334c5bf8682f\"},\"contracts/events/ModulesCommonEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\n/**\\n * @title The common events for all modules\\n * @notice This contract contains the events which will be used by all modules\\n **/\\n\\ncontract ModulesCommonEvents {\\n event ProtocolModuleContractReplaced(\\n address indexed prevModuleContractAddress,\\n address indexed newModuleContractAddress,\\n bytes32 indexed module\\n );\\n}\\n\",\"keccak256\":\"0xb07af42d7e6b0fe983889b883691b662a58d2ef8d75b3f32f17faff1871c8b8f\"},\"contracts/events/ProtocolSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title The Protocol Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for protocol settings operations.\\n * */\\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetLoanPool(\\n address indexed sender,\\n address indexed loanPool,\\n address indexed underlying\\n );\\n\\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\\n\\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateTradingTokenFeePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetLiquidationIncentivePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetFeesController(\\n address indexed sender,\\n address indexed oldController,\\n address indexed newController\\n );\\n\\n event SetWrbtcToken(\\n address indexed sender,\\n address indexed oldWethToken,\\n address indexed newWethToken\\n );\\n\\n event SetSovrynSwapContractRegistryAddress(\\n address indexed sender,\\n address indexed oldSovrynSwapContractRegistryAddress,\\n address indexed newSovrynSwapContractRegistryAddress\\n );\\n\\n event SetProtocolTokenAddress(\\n address indexed sender,\\n address indexed oldProtocolToken,\\n address indexed newProtocolToken\\n );\\n\\n event WithdrawFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 lendingAmount,\\n uint256 tradingAmount,\\n uint256 borrowingAmount,\\n uint256 wRBTCConverted\\n );\\n\\n event WithdrawLendingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawTradingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawBorrowingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetRebatePercent(\\n address indexed sender,\\n uint256 oldRebatePercent,\\n uint256 newRebatePercent\\n );\\n\\n event SetSpecialRebates(\\n address indexed sender,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 oldSpecialRebatesPercent,\\n uint256 newSpecialRebatesPercent\\n );\\n\\n event SetProtocolAddress(\\n address indexed sender,\\n address indexed oldProtocol,\\n address indexed newProtocol\\n );\\n\\n event SetMinReferralsToPayoutAffiliates(\\n address indexed sender,\\n uint256 oldMinReferrals,\\n uint256 newMinReferrals\\n );\\n\\n event SetSOVTokenAddress(\\n address indexed sender,\\n address indexed oldTokenAddress,\\n address indexed newTokenAddress\\n );\\n\\n event SetLockedSOVAddress(\\n address indexed sender,\\n address indexed oldAddress,\\n address indexed newAddress\\n );\\n\\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\\n\\n event SetTradingRebateRewardsBasisPoint(\\n address indexed sender,\\n uint256 oldBasisPoint,\\n uint256 newBasisPoint\\n );\\n\\n event SetRolloverFlexFeePercent(\\n address indexed sender,\\n uint256 oldRolloverFlexFeePercent,\\n uint256 newRolloverFlexFeePercent\\n );\\n\\n event SetDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event RemoveDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\\n\\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\\n}\\n\",\"keccak256\":\"0x20ca66a2c53669aa33379bf5233e3bcdddbba3504cd430a0143f0ee3ce1c2641\"},\"contracts/events/SwapsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Swaps Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for swap operations.\\n * */\\ncontract SwapsEvents is ModulesCommonEvents {\\n event LoanSwap(\\n bytes32 indexed loanId,\\n address indexed sourceToken,\\n address indexed destToken,\\n address borrower,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n\\n event ExternalSwap(\\n address indexed user,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n}\\n\",\"keccak256\":\"0x0a1cd289076675980b916941ed923146160d34a8669fc3fb4a06610f285dfbd1\"},\"contracts/feeds/IPriceFeeds.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface IPriceFeeds {\\n function queryRate(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 rate, uint256 precision);\\n\\n function queryPrecision(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 precision);\\n\\n function queryReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount\\n ) external view returns (uint256 destAmount);\\n\\n function checkPriceDisagreement(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount,\\n uint256 destAmount,\\n uint256 maxSlippage\\n ) external view returns (uint256 sourceToDestSwapRate);\\n\\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\\n\\n function getMaxDrawdown(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (uint256);\\n\\n function getCurrentMarginAndCollateralSize(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\\n\\n function getCurrentMargin(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\\n\\n function shouldLiquidate(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (bool);\\n\\n function getFastGasPrice(address payToken) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x2e2c2b393336efedb97659a2fc21c8dfb75b70e15d2422a3bcbf7ebd5fc83c82\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/interfaces/ISovryn.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\npragma experimental ABIEncoderV2;\\n//TODO: stored in ./interfaces only while brownie isn't removed\\n//TODO: move to contracts/interfaces after with brownie is removed\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/ProtocolSettingsEvents.sol\\\";\\nimport \\\"../events/LoanSettingsEvents.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../events/LoanMaintenanceEvents.sol\\\";\\nimport \\\"../events/LoanClosingsEvents.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../events/AffiliatesEvents.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\ncontract ISovryn is\\n State,\\n ProtocolSettingsEvents,\\n LoanSettingsEvents,\\n LoanOpeningsEvents,\\n LoanMaintenanceEvents,\\n LoanClosingsEvents,\\n SwapsEvents,\\n AffiliatesEvents,\\n FeesEvents\\n{\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n ////// Protocol //////\\n\\n function replaceContract(address target) external;\\n\\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\\n\\n function getTarget(string calldata sig) external view returns (address);\\n\\n ////// Protocol Settings //////\\n\\n function setSovrynProtocolAddress(address newProtocolAddress) external;\\n\\n function setSOVTokenAddress(address newSovTokenAddress) external;\\n\\n function setLockedSOVAddress(address newSOVLockedAddress) external;\\n\\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\\n\\n function setPriceFeedContract(address newContract) external;\\n\\n function setSwapsImplContract(address newContract) external;\\n\\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\\n\\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\\n\\n function setLendingFeePercent(uint256 newValue) external;\\n\\n function setTradingFeePercent(uint256 newValue) external;\\n\\n function setBorrowingFeePercent(uint256 newValue) external;\\n\\n function setSwapExternalFeePercent(uint256 newValue) external;\\n\\n function setAffiliateFeePercent(uint256 newValue) external;\\n\\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\\n\\n function setLiquidationIncentivePercent(uint256 newAmount) external;\\n\\n function setMaxDisagreement(uint256 newAmount) external;\\n\\n function setSourceBuffer(uint256 newAmount) external;\\n\\n function setMaxSwapSize(uint256 newAmount) external;\\n\\n function setFeesController(address newController) external;\\n\\n function withdrawFees(address[] calldata tokens, address receiver)\\n external\\n returns (uint256 totalWRBTCWithdrawn);\\n\\n function withdrawLendingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawTradingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawBorrowingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawProtocolToken(address receiver, uint256 amount)\\n external\\n returns (address, bool);\\n\\n function depositProtocolToken(uint256 amount) external;\\n\\n function getLoanPoolsList(uint256 start, uint256 count)\\n external\\n view\\n returns (bytes32[] memory);\\n\\n function isLoanPool(address loanPool) external view returns (bool);\\n\\n function setWrbtcToken(address wrbtcTokenAddress) external;\\n\\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\\n\\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\\n\\n function setRolloverBaseReward(uint256 transactionCost) external;\\n\\n function setRebatePercent(uint256 rebatePercent) external;\\n\\n function setSpecialRebates(\\n address sourceToken,\\n address destToken,\\n uint256 specialRebatesPercent\\n ) external;\\n\\n function getSpecialRebates(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 specialRebatesPercent);\\n\\n function togglePaused(bool paused) external;\\n\\n function isProtocolPaused() external view returns (bool);\\n\\n ////// SwapsImplSovrynSwapModule //////\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (address);\\n\\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\\n\\n function swapsImplExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function swapsImplExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256 expectedReturn);\\n\\n ////// Loan Settings //////\\n\\n function setupLoanParams(LoanParams[] calldata loanParamsList)\\n external\\n returns (bytes32[] memory loanParamsIdList);\\n\\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\\n\\n function getLoanParams(bytes32[] calldata loanParamsIdList)\\n external\\n view\\n returns (LoanParams[] memory loanParamsList);\\n\\n function getLoanParamsList(\\n address owner,\\n uint256 start,\\n uint256 count\\n ) external view returns (bytes32[] memory loanParamsList);\\n\\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\\n\\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\\n\\n ////// Loan Openings //////\\n\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId, // if 0, start a new loan\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n // lender: must match loan if loanId provided\\n // borrower: must match loan if loanId provided\\n // receiver: receiver of funds (address(0) assumes borrower address)\\n // manager: delegated manager of loan unless address(0)\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n // newRate: new loan interest rate\\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\\n // collateralTokenReceived: total collateralToken deposit\\n bytes calldata loanDataBytes\\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\\n\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external;\\n\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256);\\n\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 collateralAmountRequired);\\n\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 borrowAmount);\\n\\n ////// Loan Closings //////\\n\\n function liquidate(\\n bytes32 loanId,\\n address receiver,\\n uint256 closeAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 seizedAmount,\\n address seizedToken\\n );\\n\\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\\n\\n function closeWithDeposit(\\n bytes32 loanId,\\n address receiver,\\n uint256 depositAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n function closeWithSwap(\\n bytes32 loanId,\\n address receiver,\\n uint256 swapAmount, // denominated in collateralToken\\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\\n bytes calldata loanDataBytes\\n )\\n external\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n ////// Loan Maintenance //////\\n\\n function depositCollateral(\\n bytes32 loanId,\\n uint256 depositAmount // must match msg.value if ether is sent\\n ) external payable;\\n\\n function withdrawCollateral(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 actualWithdrawAmount);\\n\\n function withdrawAccruedInterest(address loanToken) external;\\n\\n function getLenderInterestData(address lender, address loanToken)\\n external\\n view\\n returns (\\n uint256 interestPaid,\\n uint256 interestPaidDate,\\n uint256 interestOwedPerDay,\\n uint256 interestUnPaid,\\n uint256 interestFeePercent,\\n uint256 principalTotal\\n );\\n\\n function getLoanInterestData(bytes32 loanId)\\n external\\n view\\n returns (\\n address loanToken,\\n uint256 interestOwedPerDay,\\n uint256 interestDepositTotal,\\n uint256 interestDepositRemaining\\n );\\n\\n struct LoanReturnData {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; // collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n }\\n\\n struct LoanReturnDataV2 {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n address borrower;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; /// collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n uint256 creationTimestamp;\\n }\\n\\n function getUserLoans(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getUserLoansV2(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\\n\\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\\n\\n function getActiveLoans(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getActiveLoansV2(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function extendLoanDuration(\\n bytes32 loanId,\\n uint256 depositAmount,\\n bool useCollateral,\\n bytes calldata /// loanDataBytes, for future use.\\n ) external returns (uint256 secondsExtended);\\n\\n function reduceLoanDuration(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 secondsReduced);\\n\\n ////// Swaps External //////\\n function swapExternal(\\n address sourceToken,\\n address destToken,\\n address receiver,\\n address returnToSender,\\n uint256 sourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n uint256 minReturn,\\n bytes calldata swapData\\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\\n\\n function getSwapExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function checkPriceDivergence(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount,\\n uint256 minReturn\\n ) public view;\\n\\n ////// Affiliates Module //////\\n\\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\\n\\n function setUserNotFirstTradeFlag(address user) external;\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address referrer,\\n address trader,\\n address token,\\n uint256 tradingFeeTokenBaseAmount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n\\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\\n\\n function getReferralsList(address referrer) external view returns (address[] memory refList);\\n\\n function getAffiliatesReferrerBalances(address referrer)\\n external\\n view\\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\\n\\n function getAffiliatesReferrerTokensList(address referrer)\\n external\\n view\\n returns (address[] memory tokensList);\\n\\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\\n external\\n view\\n returns (uint256);\\n\\n function withdrawAffiliatesReferrerTokenFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external;\\n\\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\\n\\n function getProtocolAddress() external view returns (address);\\n\\n function getSovTokenAddress() external view returns (address);\\n\\n function getLockedSOVAddress() external view returns (address);\\n\\n function getFeeRebatePercent() external view returns (uint256);\\n\\n function getMinReferralsToPayout() external view returns (uint256);\\n\\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\\n\\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\\n\\n function getAffiliateTradingTokenFeePercent()\\n external\\n view\\n returns (uint256 affiliateTradingTokenFeePercent);\\n\\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\\n external\\n view\\n returns (uint256 rbtcTotalAmount);\\n\\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\\n\\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\\n\\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\\n\\n function getDedicatedSOVRebate() external view returns (uint256);\\n\\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\\n\\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external\\n view\\n returns (IERC20[] memory);\\n\\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\\n\\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external;\\n\\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\\n external\\n view\\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\\n\\n function setAdmin(address newAdmin) external;\\n\\n function getAdmin() external view returns (address);\\n\\n function setPauser(address newPauser) external;\\n\\n function getPauser() external view returns (address);\\n}\\n\",\"keccak256\":\"0x4e470e1fe1719c2c58b0e44aedce3ee6a21191063b533ccb71c9219a192e8884\"},\"contracts/interfaces/IWrbtc.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ninterface IWrbtc {\\n function deposit() external payable;\\n\\n function withdraw(uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x20fdfe4b5e32fd7f863b3fa128e3c80bd4ccf090a4ffba56186ef3b7f2a80492\"},\"contracts/interfaces/IWrbtcERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./IWrbtc.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\n\\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\\n\",\"keccak256\":\"0x7301a8c8ca7aa016ec94268a16d07366875f2e406442e929968dd745b1ee5be5\"},\"contracts/mixins/EnumerableAddressSet.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Based on Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * As of v2.5.0, only `address` sets are supported.\\n *\\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\\n *\\n * _Available since v2.5.0._\\n */\\nlibrary EnumerableAddressSet {\\n struct AddressSet {\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(address => uint256) index;\\n address[] values;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n * Returns false if the value was already in the set.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n * Returns false if the value was not present in the set.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n // If the element we're deleting is the last one, we can just remove it without doing a swap\\n if (lastIndex != toDeleteIndex) {\\n address lastValue = set.values[lastIndex];\\n\\n // Move the last value to the index where the deleted value is\\n set.values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n // Delete the index entry for the deleted value\\n delete set.index[value];\\n\\n // Delete the old entry for the moved value\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns an array with all values in the set. O(N).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\\n address[] memory output = new address[](set.values.length);\\n for (uint256 i; i < set.values.length; i++) {\\n output[i] = set.values[i];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n \\n * @param start start index of chunk\\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\\n */\\n function enumerateChunk(\\n AddressSet storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (address[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = (set.values.length < end || count == 0) ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new address[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns the number of elements on the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /** @dev Returns the element stored at position `index` in the set. O(1).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xea6fba941ec8502aa11a7ab37e74b917d0dc47bb254e359a2870a87ef97d9872\"},\"contracts/mixins/EnumerableBytes32Set.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title Library for managing loan sets.\\n *\\n * @notice Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\\n * */\\nlibrary EnumerableBytes32Set {\\n struct Bytes32Set {\\n /// Position of the value in the `values` array, plus 1 because index 0\\n /// means a value is not in the set.\\n mapping(bytes32 => uint256) index;\\n bytes32[] values;\\n }\\n\\n /**\\n * @notice Add an address value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return addBytes32(set, value);\\n }\\n\\n /**\\n * @notice Add a value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The new value to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Remove an address value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to remove.\\n *\\n * @return False if the address was not present in the set.\\n */\\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return removeBytes32(set, value);\\n }\\n\\n /**\\n * @notice Remove a value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The value to remove.\\n *\\n * @return False if the value was not present in the set.\\n */\\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n /// If the element we're deleting is the last one,\\n /// we can just remove it without doing a swap.\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set.values[lastIndex];\\n\\n /// Move the last value to the index where the deleted value is.\\n set.values[toDeleteIndex] = lastValue;\\n\\n /// Update the index for the moved value.\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n /// Delete the index entry for the deleted value.\\n delete set.index[value];\\n\\n /// Delete the old entry for the moved value.\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Find out whether a value exists in the set.\\n *\\n * @param set The set of values.\\n * @param value The value to find.\\n *\\n * @return True if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function containsAddress(Bytes32Set storage set, address addrvalue)\\n internal\\n view\\n returns (bool)\\n {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @notice Get all set values.\\n *\\n * @param set The set of values.\\n * @param start The offset of the returning set.\\n * @param count The limit of number of values to return.\\n *\\n * @return An array with all values in the set. O(N).\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(\\n Bytes32Set storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (bytes32[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = set.values.length < end ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new bytes32[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @notice Get the legth of the set.\\n *\\n * @param set The set of values.\\n *\\n * @return the number of elements on the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /**\\n * @notice Get an item from the set by its index.\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n *\\n * @param set The set of values.\\n * @param index The index of the value to return.\\n *\\n * @return the element stored at position `index` in the set. O(1).\\n */\\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xa2801a585c566e07f21c1ebccd0cd0447dd5fd9fe6c1ff2b58d4d979d88a6db0\"},\"contracts/mixins/FeesHelper.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../modules/interfaces/ProtocolAffiliatesInterface.sol\\\";\\nimport \\\"../interfaces/ISovryn.sol\\\";\\nimport \\\"../core/objects/LoanParamsStruct.sol\\\";\\n\\n/**\\n * @title The Fees Helper contract.\\n *\\n * This contract calculates and pays lending/borrow fees and rewards.\\n * */\\ncontract FeesHelper is State, FeesEvents {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Calculate trading fee.\\n * @param feeTokenAmount The amount of tokens to trade.\\n * @return The fee of the trade.\\n * */\\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\\n }\\n\\n /**\\n * @notice Calculate swap external fee.\\n * @param feeTokenAmount The amount of token to swap.\\n * @return The fee of the swap.\\n */\\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\\n }\\n\\n /*\\n\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\\n\\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n\\t\\tuint256 collateralAmountRequired =\\n\\t\\t\\tfeeTokenAmount.mul(10**20).divCeil(\\n\\t\\t\\t\\t10**20 - tradingFeePercent // never will overflow\\n\\t\\t\\t);\\n\\t\\treturn collateralAmountRequired.sub(feeTokenAmount);\\n\\t}*/\\n\\n /**\\n * @notice Calculate the loan origination fee.\\n * @param feeTokenAmount The amount of tokens to borrow.\\n * @return The fee of the loan.\\n * */\\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\\n /*\\n\\t\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t\\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\\n\\t\\tuint256 collateralAmountRequired =\\n\\t\\t\\tfeeTokenAmount.mul(10**20).divCeil(\\n\\t\\t\\t\\t10**20 - borrowingFeePercent // never will overflow\\n\\t\\t\\t);\\n\\t\\treturn collateralAmountRequired.sub(feeTokenAmount);*/\\n }\\n\\n /**\\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\\n *\\n * @param referrer The affiliate referrer address to send the reward to.\\n * @param trader The account that performs this trade.\\n * @param feeToken The address of the token in which the trading fee is paid.\\n * @param tradingFee The amount of tokens accrued as fees on the trading.\\n *\\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\\n * */\\n function _payTradingFeeToAffiliate(\\n address referrer,\\n address trader,\\n address feeToken,\\n uint256 tradingFee\\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\\n address(this)\\n )\\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\\n }\\n\\n /**\\n * @notice Settle the trading fee and pay the token reward to the user.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associated loan - used for logging only.\\n * @param feeToken The address of the token in which the trading fee is paid.\\n * @param tradingFee The amount of tokens accrued as fees on the trading.\\n * */\\n function _payTradingFee(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 tradingFee\\n ) internal {\\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\\n if (tradingFee != 0) {\\n if (affiliatesUserReferrer[user] != address(0)) {\\n _payTradingFeeToAffiliate(\\n affiliatesUserReferrer[user],\\n user,\\n feeToken,\\n protocolTradingFee\\n );\\n protocolTradingFee = (\\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\\n )\\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\\n }\\n\\n /// Increase the storage variable keeping track of the accumulated fees.\\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\\n protocolTradingFee\\n );\\n\\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\\n\\n /// Pay the token reward to the user.\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\\n }\\n }\\n\\n /**\\n * @notice Settle the borrowing fee and pay the token reward to the user.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associated loan - used for logging only.\\n * @param feeToken The address of the token in which the borrowig fee is paid.\\n * @param borrowingFee The height of the fee.\\n * */\\n function _payBorrowingFee(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 borrowingFee\\n ) internal {\\n if (borrowingFee != 0) {\\n /// Increase the storage variable keeping track of the accumulated fees.\\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\\n\\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\\n\\n /// Pay the token reward to the user.\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\\n }\\n }\\n\\n /**\\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\\n * @param user The address to send the reward to.\\n * @param feeToken The address of the token in which the lending fee is paid.\\n * @param lendingFee The height of the fee.\\n * */\\n function _payLendingFee(\\n address user,\\n address feeToken,\\n uint256 lendingFee\\n ) internal {\\n if (lendingFee != 0) {\\n /// Increase the storage variable keeping track of the accumulated fees.\\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\\n\\n emit PayLendingFee(user, feeToken, lendingFee);\\n\\n //// NOTE: Lenders do not receive a fee reward ////\\n }\\n }\\n\\n /// Settle and pay borrowers based on the fees generated by their interest payments.\\n function _settleFeeRewardForInterestExpense(\\n LoanInterest storage loanInterestLocal,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n address user,\\n uint256 interestTime\\n ) internal {\\n /// This represents the fee generated by a borrower's interest payment.\\n uint256 interestExpenseFee =\\n interestTime\\n .sub(loanInterestLocal.updatedTimestamp)\\n .mul(loanInterestLocal.owedPerDay)\\n .mul(lendingFeePercent)\\n .div(1 days * 10**20);\\n\\n loanInterestLocal.updatedTimestamp = interestTime;\\n\\n if (interestExpenseFee != 0) {\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\\n }\\n }\\n\\n /**\\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associeated loan - used for logging only.\\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\\n * @param feeAmount The height of the fee.\\n * */\\n function _payFeeReward(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 feeAmount\\n ) internal {\\n uint256 rewardAmount;\\n uint256 _feeRebatePercent = feeRebatePercent;\\n address _priceFeeds = priceFeeds;\\n\\n if (specialRebates[feeToken][feeTokenPair] > 0) {\\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\\n }\\n\\n /// Note: this should be refactored.\\n /// Calculate the reward amount, querying the price feed.\\n (bool success, bytes memory data) =\\n _priceFeeds.staticcall(\\n abi.encodeWithSelector(\\n IPriceFeeds(_priceFeeds).queryReturn.selector,\\n feeToken,\\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\\n feeAmount.mul(_feeRebatePercent).div(10**20)\\n )\\n );\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n if eq(success, 1) {\\n rewardAmount := mload(add(data, 32))\\n }\\n }\\n\\n // Check the dedicated SOV that is used to pay trading rebate rewards\\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\\n\\n (bool success, ) =\\n lockedSOVAddress.call(\\n abi.encodeWithSignature(\\n \\\"deposit(address,uint256,uint256)\\\",\\n user,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n )\\n );\\n\\n if (success) {\\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\\n\\n emit EarnReward(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n } else {\\n emit EarnRewardFail(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n }\\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\\n emit EarnRewardFail(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0x9094bce5eab7109594a795982a779641c951c2617a618f5eab1f651b3b945077\"},\"contracts/mixins/InterestUser.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../mixins/VaultController.sol\\\";\\nimport \\\"./FeesHelper.sol\\\";\\n\\n/**\\n * @title The Interest User contract.\\n *\\n * This contract pays loan interests.\\n * */\\ncontract InterestUser is VaultController, FeesHelper {\\n using SafeERC20 for IERC20;\\n\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n /**\\n * @notice Internal function to pay interest of a loan.\\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\\n * @param lender The account address of the lender.\\n * @param interestToken The token address to pay interest with.\\n * */\\n function _payInterest(address lender, address interestToken) internal {\\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\\n\\n uint256 interestOwedNow = 0;\\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\\n interestOwedNow = block\\n .timestamp\\n .sub(lenderInterestLocal.updatedTimestamp)\\n .mul(lenderInterestLocal.owedPerDay)\\n .div(1 days);\\n\\n lenderInterestLocal.updatedTimestamp = block.timestamp;\\n\\n if (interestOwedNow > lenderInterestLocal.owedTotal)\\n interestOwedNow = lenderInterestLocal.owedTotal;\\n\\n if (interestOwedNow != 0) {\\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\\n\\n _payInterestTransfer(lender, interestToken, interestOwedNow);\\n }\\n } else {\\n lenderInterestLocal.updatedTimestamp = block.timestamp;\\n }\\n }\\n\\n /**\\n * @notice Internal function to transfer tokens for the interest of a loan.\\n * @param lender The account address of the lender.\\n * @param interestToken The token address to pay interest with.\\n * @param interestOwedNow The amount of interest to pay.\\n * */\\n function _payInterestTransfer(\\n address lender,\\n address interestToken,\\n uint256 interestOwedNow\\n ) internal {\\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\\n /// TODO: refactor: data incapsulation violation and DRY design principles\\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\\n\\n _payLendingFee(lender, interestToken, lendingFee);\\n\\n /// Transfers the interest to the lender, less the interest fee.\\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\\n\\n /// Event Log\\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\\n }\\n}\\n\",\"keccak256\":\"0x870208d1ae2c7adca9478b86fe5e70b4458bf719d49b19f5a8a4441bdaccf866\"},\"contracts/mixins/ModuleCommonFunctionalities.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\n\\ncontract ModuleCommonFunctionalities is State {\\n modifier whenNotPaused() {\\n require(!pause, \\\"Paused\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0x9ed7a6a635ef960b53888b28a2a6bed8b071255cad8cd33f00386a634cbddb74\"},\"contracts/mixins/VaultController.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../core/State.sol\\\";\\n\\n/**\\n * @title The Vault Controller contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\\n * trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract implements functionality to deposit and withdraw wrBTC and\\n * other tokens from the vault.\\n * */\\ncontract VaultController is State {\\n using SafeERC20 for IERC20;\\n\\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\\n\\n /**\\n * @notice Deposit wrBTC into the vault.\\n *\\n * @param from The address of the account paying the deposit.\\n * @param value The amount of wrBTC tokens to transfer.\\n */\\n function vaultEtherDeposit(address from, uint256 value) internal {\\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\\n _wrbtcToken.deposit.value(value)();\\n\\n emit VaultDeposit(address(_wrbtcToken), from, value);\\n }\\n\\n /**\\n * @notice Withdraw wrBTC from the vault.\\n *\\n * @param to The address of the recipient.\\n * @param value The amount of wrBTC tokens to transfer.\\n */\\n function vaultEtherWithdraw(address to, uint256 value) internal {\\n if (value != 0) {\\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\\n uint256 balance = address(this).balance;\\n if (value > balance) {\\n _wrbtcToken.withdraw(value - balance);\\n }\\n Address.sendValue(to, value);\\n\\n emit VaultWithdraw(address(_wrbtcToken), to, value);\\n }\\n }\\n\\n /**\\n * @notice Deposit tokens into the vault.\\n *\\n * @param token The address of the token instance.\\n * @param from The address of the account paying the deposit.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultDeposit(\\n address token,\\n address from,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n IERC20(token).safeTransferFrom(from, address(this), value);\\n\\n emit VaultDeposit(token, from, value);\\n }\\n }\\n\\n /**\\n * @notice Withdraw tokens from the vault.\\n *\\n * @param token The address of the token instance.\\n * @param to The address of the recipient.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultWithdraw(\\n address token,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n IERC20(token).safeTransfer(to, value);\\n\\n emit VaultWithdraw(token, to, value);\\n }\\n }\\n\\n /**\\n * @notice Transfer tokens from an account into another one.\\n *\\n * @param token The address of the token instance.\\n * @param from The address of the account paying.\\n * @param to The address of the recipient.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultTransfer(\\n address token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n if (from == address(this)) {\\n IERC20(token).safeTransfer(to, value);\\n } else {\\n IERC20(token).safeTransferFrom(from, to, value);\\n }\\n }\\n }\\n\\n /**\\n * @notice Approve an allowance of tokens to be spent by an account.\\n *\\n * @param token The address of the token instance.\\n * @param to The address of the spender.\\n * @param value The amount of tokens to allow.\\n */\\n function vaultApprove(\\n address token,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\\n IERC20(token).safeApprove(to, 0);\\n }\\n IERC20(token).safeApprove(to, value);\\n }\\n}\\n\",\"keccak256\":\"0xdcde4eee041b77ec9b73378a4a75b4d20d62f2e76f96f759d55260cf6717d0f3\"},\"contracts/modules/LoanOpenings.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../mixins/VaultController.sol\\\";\\nimport \\\"../mixins/InterestUser.sol\\\";\\nimport \\\"../swaps/SwapsUser.sol\\\";\\nimport \\\"../mixins/ModuleCommonFunctionalities.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\n/**\\n * @title Loan Openings contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains functions to borrow and trade.\\n * */\\ncontract LoanOpenings is\\n LoanOpeningsEvents,\\n VaultController,\\n InterestUser,\\n SwapsUser,\\n ModuleCommonFunctionalities\\n{\\n constructor() public {}\\n\\n /**\\n * @notice Fallback function is to react to receiving value (rBTC).\\n * */\\n function() external {\\n revert(\\\"fallback not allowed\\\");\\n }\\n\\n /**\\n * @notice Set function selectors on target contract.\\n *\\n * @param target The address of the target contract.\\n * */\\n function initialize(address target) external onlyOwner {\\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\\n _setTarget(this.borrowOrTradeFromPool.selector, target);\\n _setTarget(this.setDelegatedManager.selector, target);\\n _setTarget(this.getEstimatedMarginExposure.selector, target);\\n _setTarget(this.getRequiredCollateral.selector, target);\\n _setTarget(this.getBorrowAmount.selector, target);\\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \\\"LoanOpenings\\\");\\n }\\n\\n /**\\n * @notice Borrow or trade from pool.\\n *\\n * @dev Note: Only callable by loan pools (iTokens).\\n * Wrapper to _borrowOrTrade internal function.\\n *\\n * @param loanParamsId The ID of the loan parameters.\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * @param initialMargin The initial amount of margin.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return newPrincipal The new loan size.\\n * @return newCollateral The new collateral amount.\\n * */\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId,\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n bytes calldata loanDataBytes\\n )\\n external\\n payable\\n nonReentrant\\n whenNotPaused\\n returns (uint256 newPrincipal, uint256 newCollateral)\\n {\\n require(msg.value == 0 || loanDataBytes.length != 0, \\\"loanDataBytes required with ether\\\");\\n\\n /// Only callable by loan pools.\\n require(loanPoolToUnderlying[msg.sender] != address(0), \\\"not authorized\\\");\\n\\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\\n require(loanParamsLocal.id != 0, \\\"loanParams not exists\\\");\\n\\n /// Get required collateral.\\n uint256 collateralAmountRequired =\\n _getRequiredCollateral(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n sentValues.newPrincipal,\\n initialMargin,\\n isTorqueLoan\\n );\\n require(collateralAmountRequired != 0, \\\"collateral is 0\\\");\\n\\n return\\n _borrowOrTrade(\\n loanParamsLocal,\\n loanId,\\n isTorqueLoan,\\n collateralAmountRequired,\\n initialMargin,\\n sentAddresses,\\n sentValues,\\n loanDataBytes\\n );\\n }\\n\\n /**\\n * @notice Set the delegated manager.\\n *\\n * @dev Wrapper for _setDelegatedManager internal function.\\n *\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param delegated The address of the delegated manager.\\n * @param toggle The flag true/false for the delegated manager.\\n * */\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external whenNotPaused {\\n require(loans[loanId].borrower == msg.sender, \\\"unauthorized\\\");\\n\\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\\n }\\n\\n /**\\n * @notice Get the estimated margin exposure.\\n *\\n * Margin is the money borrowed from a broker to purchase an investment\\n * and is the difference between the total value of investment and the\\n * loan amount. Margin trading refers to the practice of using borrowed\\n * funds from a broker to trade a financial asset, which forms the\\n * collateral for the loan from the broker.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param loanTokenSent The amount of loan tokens sent.\\n * @param collateralTokenSent The amount of collateral tokens sent.\\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\\n * @param newPrincipal The updated amount of principal (current debt).\\n *\\n * @return The margin exposure.\\n * */\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256) {\\n uint256 maxLoanTerm = 2419200; // 28 days\\n\\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\\n\\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\\n\\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\\n uint256 tradingFee = _getTradingFee(swapAmount);\\n if (tradingFee != 0) {\\n swapAmount = swapAmount.sub(tradingFee);\\n }\\n\\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\\n if (receivedAmount == 0) {\\n return 0;\\n } else {\\n return collateralTokenSent.add(receivedAmount);\\n }\\n }\\n\\n /**\\n * @notice Get the required collateral.\\n *\\n * @dev Calls internal _getRequiredCollateral and add fees.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param newPrincipal The updated amount of principal (current debt).\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return collateralAmountRequired The required collateral.\\n * */\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) public view returns (uint256 collateralAmountRequired) {\\n if (marginAmount != 0) {\\n collateralAmountRequired = _getRequiredCollateral(\\n loanToken,\\n collateralToken,\\n newPrincipal,\\n marginAmount,\\n isTorqueLoan\\n );\\n\\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n // cannot be applied solely as it drives to some other tests failure\\n /*\\n\\t\\t\\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\\n\\t\\t\\tif (collateralAmountRequired != 0 && feePercent != 0) {\\n\\t\\t\\t\\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\\n\\t\\t\\t\\t\\t10**20 - feePercent // never will overflow\\n\\t\\t\\t\\t);\\n\\t\\t\\t}*/\\n\\n uint256 fee =\\n isTorqueLoan\\n ? _getBorrowingFee(collateralAmountRequired)\\n : _getTradingFee(collateralAmountRequired);\\n if (fee != 0) {\\n collateralAmountRequired = collateralAmountRequired.add(fee);\\n }\\n }\\n }\\n\\n /**\\n * @notice Get the borrow amount of a trade loan.\\n *\\n * @dev Basically borrowAmount = collateral / marginAmount\\n *\\n * Collateral is something that helps secure a loan. When you borrow money,\\n * you agree that your lender can take something and sell it to get their\\n * money back if you fail to repay the loan. That's the collateral.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param collateralTokenAmount The amount of collateral.\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return borrowAmount The borrow amount.\\n * */\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) public view returns (uint256 borrowAmount) {\\n if (marginAmount != 0) {\\n if (isTorqueLoan) {\\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\\n }\\n uint256 collateral = collateralTokenAmount;\\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\\n if (fee != 0) {\\n collateral = collateral.sub(fee);\\n }\\n if (loanToken == collateralToken) {\\n borrowAmount = collateral.mul(10**20).div(marginAmount);\\n } else {\\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\\n if (sourceToDestPrecision != 0) {\\n borrowAmount = collateral\\n .mul(10**20)\\n .mul(sourceToDestRate)\\n .div(marginAmount)\\n .div(sourceToDestPrecision);\\n }\\n }\\n /*\\n\\t\\t\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t\\t\\t// cannot be applied solely as it drives to some other tests failure\\n\\t\\t\\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\\n\\t\\t\\tif (borrowAmount != 0 && feePercent != 0) {\\n\\t\\t\\t\\tborrowAmount = borrowAmount\\n\\t\\t\\t\\t\\t.mul(\\n\\t\\t\\t\\t\\t10**20 - feePercent // never will overflow\\n\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t.divCeil(10**20);\\n\\t\\t\\t}*/\\n }\\n }\\n\\n /**\\n * @notice Borrow or trade.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * @param collateralAmountRequired The required amount of collateral.\\n * @param initialMargin The initial amount of margin.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return The new loan size.\\n * @return The new collateral amount.\\n * */\\n function _borrowOrTrade(\\n LoanParams memory loanParamsLocal,\\n bytes32 loanId,\\n bool isTorqueLoan,\\n uint256 collateralAmountRequired,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n bytes memory loanDataBytes\\n ) internal returns (uint256, uint256) {\\n require(\\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\\n \\\"collateral/loan match\\\"\\n );\\n require(initialMargin >= loanParamsLocal.minInitialMargin, \\\"initialMargin too low\\\");\\n\\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\\n require(\\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\\n \\\"invalid interest\\\"\\n );\\n\\n /// Initialize loan.\\n Loan storage loanLocal =\\n loans[\\n _initializeLoan(\\n loanParamsLocal,\\n loanId,\\n initialMargin,\\n sentAddresses,\\n sentValues.newPrincipal\\n )\\n ];\\n\\n // Get required interest.\\n uint256 amount =\\n _initializeInterest(\\n loanParamsLocal,\\n loanLocal,\\n sentValues.interestRate, /// newRate\\n sentValues.newPrincipal, /// newPrincipal,\\n sentValues.interestInitialAmount /// torqueInterest\\n );\\n\\n /// substract out interest from usable loanToken sent.\\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\\n\\n if (isTorqueLoan) {\\n require(sentValues.loanTokenSent == 0, \\\"surplus loan token\\\");\\n\\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\\n // need to temp into local state to avoid\\n address _collateralToken = loanParamsLocal.collateralToken;\\n address _loanToken = loanParamsLocal.loanToken;\\n if (borrowingFee != 0) {\\n _payBorrowingFee(\\n sentAddresses.borrower, /// borrower\\n loanLocal.id,\\n _collateralToken, /// fee token\\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n borrowingFee\\n );\\n\\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\\n }\\n } else {\\n /// Update collateral after trade.\\n uint256 receivedAmount;\\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\\n loanId,\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n sentAddresses.borrower, /// borrower\\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\\n false, /// bypassFee\\n loanDataBytes\\n );\\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\\n\\n /// Check the minEntryPrice with the rate\\n require(\\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\\n \\\"entry price above the minimum\\\"\\n );\\n }\\n\\n /// Settle collateral.\\n require(\\n _isCollateralSatisfied(\\n loanParamsLocal,\\n loanLocal,\\n initialMargin,\\n sentValues.collateralTokenSent,\\n collateralAmountRequired\\n ),\\n \\\"collateral insufficient\\\"\\n );\\n\\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\\n\\n if (isTorqueLoan) {\\n /// reclaiming variable -> interestDuration\\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\\n } else {\\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\\n }\\n\\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\\n\\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\\n }\\n\\n /**\\n * @notice Finalize an open loan.\\n *\\n * @dev Finalize it by updating local parameters of the loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * */\\n function _finalizeOpen(\\n LoanParams memory loanParamsLocal,\\n Loan storage loanLocal,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n bool isTorqueLoan\\n ) internal {\\n /// @dev TODO: here the actual used rate and margin should go.\\n (uint256 initialMargin, uint256 collateralToLoanRate) =\\n IPriceFeeds(priceFeeds).getCurrentMargin(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n loanLocal.principal,\\n loanLocal.collateral\\n );\\n require(initialMargin > loanParamsLocal.maintenanceMargin, \\\"unhealthy position\\\");\\n\\n if (loanLocal.startTimestamp == block.timestamp) {\\n uint256 loanToCollateralPrecision =\\n IPriceFeeds(priceFeeds).queryPrecision(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken\\n );\\n uint256 collateralToLoanPrecision =\\n IPriceFeeds(priceFeeds).queryPrecision(\\n loanParamsLocal.collateralToken,\\n loanParamsLocal.loanToken\\n );\\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\\n loanLocal.startRate = isTorqueLoan\\n ? collateralToLoanRate\\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\\n }\\n\\n _emitOpeningEvents(\\n loanParamsLocal,\\n loanLocal,\\n sentAddresses,\\n sentValues,\\n collateralToLoanRate,\\n initialMargin,\\n isTorqueLoan\\n );\\n }\\n\\n /**\\n * @notice Emit the opening events.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param collateralToLoanRate The exchange rate from collateral to loan\\n * tokens.\\n * @param margin The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * */\\n function _emitOpeningEvents(\\n LoanParams memory loanParamsLocal,\\n Loan memory loanLocal,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n uint256 collateralToLoanRate,\\n uint256 margin,\\n bool isTorqueLoan\\n ) internal {\\n if (isTorqueLoan) {\\n emit Borrow(\\n sentAddresses.borrower, /// user (borrower)\\n sentAddresses.lender, /// lender\\n loanLocal.id, /// loanId\\n loanParamsLocal.loanToken, /// loanToken\\n loanParamsLocal.collateralToken, /// collateralToken\\n sentValues.newPrincipal, /// newPrincipal\\n sentValues.collateralTokenSent, /// newCollateral\\n sentValues.interestRate, /// interestRate\\n sentValues.interestDuration, /// interestDuration\\n collateralToLoanRate, /// collateralToLoanRate,\\n margin /// currentMargin\\n );\\n } else {\\n /// currentLeverage = 100 / currentMargin\\n margin = SafeMath.div(10**38, margin);\\n\\n emit Trade(\\n sentAddresses.borrower, /// user (trader)\\n sentAddresses.lender, /// lender\\n loanLocal.id, /// loanId\\n loanParamsLocal.collateralToken, /// collateralToken\\n loanParamsLocal.loanToken, /// loanToken\\n sentValues.collateralTokenSent, /// positionSize\\n sentValues.newPrincipal, /// borrowedAmount\\n sentValues.interestRate, /// interestRate,\\n loanLocal.endTimestamp, /// settlementDate\\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\\n sentValues.entryLeverage, /// entryLeverage\\n margin /// currentLeverage\\n );\\n }\\n }\\n\\n /**\\n * @notice Set the delegated manager.\\n *\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param delegator The address of previous manager.\\n * @param delegated The address of the delegated manager.\\n * @param toggle The flag true/false for the delegated manager.\\n * */\\n function _setDelegatedManager(\\n bytes32 loanId,\\n address delegator,\\n address delegated,\\n bool toggle\\n ) internal {\\n delegatedManagers[loanId][delegated] = toggle;\\n\\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\\n }\\n\\n /**\\n * @notice Calculate whether the collateral is satisfied.\\n *\\n * @dev Basically check collateral + drawdown >= 98% of required.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param initialMargin The initial amount of margin.\\n * @param newCollateral The amount of new collateral.\\n * @param collateralAmountRequired The amount of required collateral.\\n *\\n * @return Whether the collateral is satisfied.\\n * */\\n function _isCollateralSatisfied(\\n LoanParams memory loanParamsLocal,\\n Loan memory loanLocal,\\n uint256 initialMargin,\\n uint256 newCollateral,\\n uint256 collateralAmountRequired\\n ) internal view returns (bool) {\\n /// Allow at most 2% under-collateralized.\\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\\n\\n if (newCollateral < collateralAmountRequired) {\\n /// Check that existing collateral is sufficient coverage.\\n if (loanLocal.collateral != 0) {\\n uint256 maxDrawdown =\\n IPriceFeeds(priceFeeds).getMaxDrawdown(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n loanLocal.principal,\\n loanLocal.collateral,\\n initialMargin\\n );\\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\\n } else {\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /**\\n * @notice Initialize a loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanId The ID of the loan.\\n * @param initialMargin The amount of margin of the trade.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\\n * @return The loanId.\\n * */\\n function _initializeLoan(\\n LoanParams memory loanParamsLocal,\\n bytes32 loanId,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n uint256 newPrincipal\\n ) internal returns (bytes32) {\\n require(loanParamsLocal.active, \\\"loanParams disabled\\\");\\n\\n address lender = sentAddresses.lender;\\n address borrower = sentAddresses.borrower;\\n address manager = sentAddresses.manager;\\n\\n Loan memory loanLocal;\\n\\n if (loanId == 0) {\\n borrowerNonce[borrower]++;\\n loanId = keccak256(\\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\\n );\\n require(loans[loanId].id == 0, \\\"loan exists\\\");\\n\\n loanLocal = Loan({\\n id: loanId,\\n loanParamsId: loanParamsLocal.id,\\n pendingTradesId: 0,\\n active: true,\\n principal: newPrincipal,\\n collateral: 0, /// calculated later\\n startTimestamp: block.timestamp,\\n endTimestamp: 0, /// calculated later\\n startMargin: initialMargin,\\n startRate: 0, /// queried later\\n borrower: borrower,\\n lender: lender\\n });\\n\\n activeLoansSet.addBytes32(loanId);\\n lenderLoanSets[lender].addBytes32(loanId);\\n borrowerLoanSets[borrower].addBytes32(loanId);\\n } else {\\n loanLocal = loans[loanId];\\n require(\\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\\n \\\"loan has ended\\\"\\n );\\n require(loanLocal.borrower == borrower, \\\"borrower mismatch\\\");\\n require(loanLocal.lender == lender, \\\"lender mismatch\\\");\\n require(loanLocal.loanParamsId == loanParamsLocal.id, \\\"loanParams mismatch\\\");\\n\\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\\n }\\n\\n if (manager != address(0)) {\\n _setDelegatedManager(loanId, borrower, manager, true);\\n }\\n\\n loans[loanId] = loanLocal;\\n\\n return loanId;\\n }\\n\\n /**\\n * @notice Initialize a loan interest.\\n *\\n * @dev A Torque loan is an indefinite-term loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param newRate The new interest rate of the loan.\\n * @param newPrincipal The new principal amount of the loan.\\n * @param torqueInterest The interest rate of the Torque loan.\\n *\\n * @return interestAmountRequired The interest amount required.\\n * */\\n function _initializeInterest(\\n LoanParams memory loanParamsLocal,\\n Loan storage loanLocal,\\n uint256 newRate,\\n uint256 newPrincipal,\\n uint256 torqueInterest /// ignored for fixed-term loans\\n ) internal returns (uint256 interestAmountRequired) {\\n /// Pay outstanding interest to lender.\\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\\n\\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\\n LenderInterest storage lenderInterestLocal =\\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\\n\\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\\n\\n _settleFeeRewardForInterestExpense(\\n loanInterestLocal,\\n loanLocal.id,\\n loanParamsLocal.loanToken, /// fee token\\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n loanLocal.borrower,\\n block.timestamp\\n );\\n\\n uint256 previousDepositRemaining;\\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\\n previousDepositRemaining = loanLocal\\n .endTimestamp\\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\\n .mul(loanInterestLocal.owedPerDay)\\n .div(86400);\\n }\\n\\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\\n\\n /// Update stored owedPerDay\\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\\n\\n if (maxLoanTerm == 0) {\\n /// Indefinite-term (Torque) loan.\\n\\n /// torqueInterest != 0 was confirmed earlier.\\n loanLocal.endTimestamp = torqueInterest\\n .add(previousDepositRemaining)\\n .mul(86400)\\n .div(loanInterestLocal.owedPerDay)\\n .add(block.timestamp);\\n\\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\\n\\n /// Loan term has to at least be greater than one hour.\\n require(maxLoanTerm > 3600, \\\"loan too short\\\");\\n\\n interestAmountRequired = torqueInterest;\\n } else {\\n /// Fixed-term loan.\\n\\n if (loanLocal.endTimestamp == 0) {\\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\\n }\\n\\n interestAmountRequired = loanLocal\\n .endTimestamp\\n .sub(block.timestamp)\\n .mul(owedPerDay)\\n .div(86400);\\n }\\n\\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\\n interestAmountRequired\\n );\\n\\n /// Update remaining lender interest values.\\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\\n }\\n\\n /**\\n * @notice Get the required collateral.\\n *\\n * @dev Basically collateral = newPrincipal * marginAmount\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param newPrincipal The updated amount of principal (current debt).\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return collateralTokenAmount The required collateral.\\n * */\\n function _getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) internal view returns (uint256 collateralTokenAmount) {\\n if (loanToken == collateralToken) {\\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\\n } else {\\n /// Using the price feed instead of the swap expected return\\n /// because we need the rate in the inverse direction\\n /// so the swap is probably farther off than the price feed.\\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\\n if (sourceToDestRate != 0) {\\n collateralTokenAmount = newPrincipal\\n .mul(sourceToDestPrecision)\\n .div(sourceToDestRate)\\n .mul(marginAmount)\\n .div(10**20);\\n /*TODO: review\\n\\t\\t\\t\\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\\n }\\n }\\n // ./tests/loan-token/TradingTestToken.test.js\\n if (isTorqueLoan && collateralTokenAmount != 0) {\\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\\n collateralTokenAmount\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0x99a9332501c69a9991f9e240f614e168323695064d25c002c5d7b348a5d3d7e5\"},\"contracts/modules/interfaces/ProtocolAffiliatesInterface.sol\":{\"content\":\"/**\\n * Copyright 2020, Denis Savelev. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface ProtocolAffiliatesInterface {\\n function setAffiliatesReferrer(address user, address referrer) external;\\n\\n function setUserNotFirstTradeFlag(address user_) external;\\n\\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address affiliate,\\n address trader,\\n address token,\\n uint256 amount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n}\\n\",\"keccak256\":\"0x42f259156db09a06e3dcdf0ab9c6774712616b35e6baff97999a2a534d1c9c64\"},\"contracts/openzeppelin/Address.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n codehash := extcodehash(account)\\n }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x23df48a01dbac9b25e86c9131174fb7752bbc7e741e63f1aa982de22e055ad54\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/openzeppelin/ReentrancyGuard.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @title Helps contracts guard against reentrancy attacks.\\n * @author Remco Bloemen , Eenae \\n * @dev If you mark a function `nonReentrant`, you should also\\n * mark it `external`.\\n */\\ncontract ReentrancyGuard {\\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\\n\\n /// @dev Constant for locked guard state\\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\\n\\n /**\\n * @dev We use a single lock for the whole contract.\\n */\\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * If you mark a function `nonReentrant`, you should also\\n * mark it `external`. Calling one `nonReentrant` function from\\n * another is not supported. Instead, you can implement a\\n * `private` function doing the actual work, and an `external`\\n * wrapper marked as `nonReentrant`.\\n */\\n modifier nonReentrant() {\\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \\\"nonReentrant\\\");\\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\\n _;\\n reentrancyLock = REENTRANCY_GUARD_FREE;\\n }\\n}\\n\",\"keccak256\":\"0xd347de96ad57d1e45b07a2efe3050c1bd4b809236bbf354acb593de56d21a5c9\"},\"contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./Address.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\\n );\\n }\\n\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance =\\n token.allowance(address(this), spender).sub(\\n value,\\n \\\"SafeERC20: decreased allowance below zero\\\"\\n );\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) {\\n // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe99b4d979cb976a6b70e297600242afe38b8cd8f1b1ba6ee373f39f7abb3ca79\"},\"contracts/openzeppelin/SafeMath.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\\n return divCeil(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n\\n if (a == 0) {\\n return 0;\\n }\\n uint256 c = ((a - 1) / b) + 1;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n\\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n return _a < _b ? _a : _b;\\n }\\n}\\n\",\"keccak256\":\"0xbff8d6273e1a6870d1a142c0c23acd63a4dd47760f250390f49ee56333bcb6e8\"},\"contracts/reentrancy/Mutex.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/*\\n * @title Global Mutex contract\\n *\\n * @notice A mutex contract that allows only one function to be called at a time out\\n * of a large set of functions. *Anyone* in the network can freely use any instance\\n * of this contract to add a universal mutex to any function in any contract.\\n */\\ncontract Mutex {\\n /*\\n * We use an uint to store the mutex state.\\n */\\n uint256 public value;\\n\\n /*\\n * @notice Increment the mutex state and return the new value.\\n *\\n * @dev This is the function that will be called by anyone to change the mutex\\n * state. It is purposely not protected by any access control\\n */\\n function incrementAndGetValue() external returns (uint256) {\\n /*\\n * increment value using unsafe math. This is safe because we are\\n * pretty certain no one will ever increment the value 2^256 times\\n * in a single transaction.\\n */\\n return ++value;\\n }\\n}\\n\",\"keccak256\":\"0xd10b0fd07d5fed1ae1237e7c87e6501970fce2a86e2b8862e502258b0d3aeb2c\"},\"contracts/reentrancy/SharedReentrancyGuard.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./Mutex.sol\\\";\\n\\n/*\\n * @title Abstract contract for shared reentrancy guards\\n *\\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\\n * that there's no reentrancy between *any* functions marked with the modifier.\\n *\\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\\n */\\ncontract SharedReentrancyGuard {\\n /*\\n * This is the address of the mutex contract that will be used as the\\n * reentrancy guard.\\n *\\n * The address is hardcoded to avoid changing the memory layout of\\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\\n * because the Mutex contract is always deployed to the same address, with the\\n * same method used in the deployment of ERC1820Registry.\\n */\\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\\n\\n /*\\n * This is the modifier that will be used to protect functions from\\n * reentrancy. It will call the mutex contract to increment the mutex\\n * state and then revert if the mutex state was changed by another\\n * nested call.\\n */\\n modifier globallyNonReentrant() {\\n uint256 previous = MUTEX.incrementAndGetValue();\\n\\n _;\\n\\n /*\\n * If the mutex state was changed by a nested function call, then\\n * the value of the state variable will be different from the previous value.\\n */\\n require(previous == MUTEX.value(), \\\"reentrancy violation\\\");\\n }\\n}\\n\",\"keccak256\":\"0x2d0e61b104b91c1764f20fbeb381ba0f8a8889934ba7f6e8a167ed542ec2c124\"},\"contracts/swaps/SwapsUser.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../mixins/FeesHelper.sol\\\";\\nimport \\\"./connectors/SwapsImplSovrynSwapLib.sol\\\";\\n\\n/**\\n * @title Perform token swaps for loans and trades.\\n * */\\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\\n /**\\n * @notice Internal loan swap.\\n *\\n * @param loanId The ID of the loan.\\n * @param sourceToken The address of the source tokens.\\n * @param destToken The address of destination tokens.\\n * @param user The user address.\\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\\n * @param requiredDestTokenAmount The required amount of destination tokens.\\n * @param bypassFee To bypass or not the fee.\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return destTokenAmountReceived\\n * @return sourceTokenAmountUsed\\n * @return sourceToDestSwapRate\\n * */\\n function _loanSwap(\\n bytes32 loanId,\\n address sourceToken,\\n address destToken,\\n address user,\\n uint256 minSourceTokenAmount,\\n uint256 maxSourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n bool bypassFee,\\n bytes memory loanDataBytes\\n )\\n internal\\n returns (\\n uint256 destTokenAmountReceived,\\n uint256 sourceTokenAmountUsed,\\n uint256 sourceToDestSwapRate\\n )\\n {\\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\\n [\\n sourceToken,\\n destToken,\\n address(this), // receiver\\n address(this), // returnToSender\\n user\\n ],\\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\\n loanId,\\n bypassFee,\\n loanDataBytes,\\n false // swap external flag, set to false so that it will use the tradingFeePercent\\n );\\n\\n /// Will revert if swap size too large.\\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\\n\\n /// Will revert if disagreement found.\\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\\n sourceToken,\\n destToken,\\n sourceTokenAmountUsed,\\n destTokenAmountReceived,\\n maxDisagreement\\n );\\n\\n emit LoanSwap(\\n loanId,\\n sourceToken,\\n destToken,\\n user,\\n sourceTokenAmountUsed,\\n destTokenAmountReceived\\n );\\n }\\n\\n /**\\n * @notice Calculate amount of source and destination tokens.\\n *\\n * @dev Wrapper for _swapsCall_internal function.\\n *\\n * @param addrs The array of addresses.\\n * @param vals The array of values.\\n * @param loanId The Id of the associated loan.\\n * @param miscBool True/false to bypassFee.\\n * @param loanDataBytes Additional loan data (not in use yet).\\n *\\n * @return destTokenAmountReceived The amount of destination tokens received.\\n * @return sourceTokenAmountUsed The amount of source tokens used.\\n * */\\n function _swapsCall(\\n address[5] memory addrs,\\n uint256[3] memory vals,\\n bytes32 loanId,\\n bool miscBool, /// bypassFee\\n bytes memory loanDataBytes,\\n bool isSwapExternal\\n ) internal returns (uint256, uint256) {\\n /// addrs[0]: sourceToken\\n /// addrs[1]: destToken\\n /// addrs[2]: receiver\\n /// addrs[3]: returnToSender\\n /// addrs[4]: user\\n /// vals[0]: minSourceTokenAmount\\n /// vals[1]: maxSourceTokenAmount\\n /// vals[2]: requiredDestTokenAmount\\n\\n require(vals[0] != 0 || vals[1] != 0, \\\"min or max source token amount needs to be set\\\");\\n\\n if (vals[1] == 0) {\\n vals[1] = vals[0];\\n }\\n require(vals[0] <= vals[1], \\\"sourceAmount larger than max\\\");\\n\\n uint256 destTokenAmountReceived;\\n uint256 sourceTokenAmountUsed;\\n\\n uint256 tradingFee;\\n if (!miscBool) {\\n /// bypassFee\\n if (vals[2] == 0) {\\n /// condition: vals[0] will always be used as sourceAmount\\n\\n if (isSwapExternal) {\\n tradingFee = _getSwapExternalFee(vals[0]);\\n } else {\\n tradingFee = _getTradingFee(vals[0]);\\n }\\n\\n if (tradingFee != 0) {\\n _payTradingFee(\\n addrs[4], /// user\\n loanId,\\n addrs[0], /// sourceToken (feeToken)\\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n tradingFee\\n );\\n\\n vals[0] = vals[0].sub(tradingFee);\\n }\\n } else {\\n /// Condition: unknown sourceAmount will be used.\\n\\n if (isSwapExternal) {\\n tradingFee = _getSwapExternalFee(vals[2]);\\n } else {\\n tradingFee = _getTradingFee(vals[2]);\\n }\\n\\n if (tradingFee != 0) {\\n vals[2] = vals[2].add(tradingFee);\\n }\\n }\\n }\\n\\n require(loanDataBytes.length == 0, \\\"invalid state\\\");\\n\\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\\n\\n if (vals[2] == 0) {\\n /// There's no minimum destTokenAmount, but all of vals[0]\\n /// (minSourceTokenAmount) must be spent.\\n require(sourceTokenAmountUsed == vals[0], \\\"swap too large to fill\\\");\\n\\n if (tradingFee != 0) {\\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\\n }\\n } else {\\n /// There's a minimum destTokenAmount required, but\\n /// sourceTokenAmountUsed won't be greater\\n /// than vals[1] (maxSourceTokenAmount)\\n require(sourceTokenAmountUsed <= vals[1], \\\"swap fill too large\\\");\\n require(destTokenAmountReceived >= vals[2], \\\"insufficient swap liquidity\\\");\\n\\n if (tradingFee != 0) {\\n _payTradingFee(\\n addrs[4], /// user\\n loanId, /// loanId,\\n addrs[1], /// destToken (feeToken)\\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n tradingFee\\n );\\n\\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\\n }\\n }\\n\\n return (destTokenAmountReceived, sourceTokenAmountUsed);\\n }\\n\\n /**\\n * @notice Calculate amount of source and destination tokens.\\n *\\n * @dev Calls swapsImpl::internalSwap\\n *\\n * @param addrs The array of addresses.\\n * @param vals The array of values.\\n *\\n * @return destTokenAmountReceived The amount of destination tokens received.\\n * @return sourceTokenAmountUsed The amount of source tokens used.\\n * */\\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\\n internal\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n SwapsImplSovrynSwapLib.SwapParams memory swapParams;\\n\\n swapParams.sourceTokenAddress = addrs[0];\\n swapParams.destTokenAddress = addrs[1];\\n swapParams.receiverAddress = addrs[2];\\n swapParams.returnToSenderAddress = addrs[3];\\n swapParams.minSourceTokenAmount = vals[0];\\n swapParams.maxSourceTokenAmount = vals[1];\\n swapParams.requiredDestTokenAmount = vals[2];\\n\\n (destTokenAmountReceived, sourceTokenAmountUsed) = SwapsImplSovrynSwapLib.swap(swapParams);\\n }\\n\\n /**\\n * @notice Calculate expected amount of destination tokens.\\n *\\n * @dev Calls swapsImpl::internalExpectedReturn\\n *\\n * @param sourceToken The address of the source tokens.\\n * @param destToken The address of the destination tokens.\\n * @param sourceTokenAmount The amount of the source tokens.\\n *\\n * @param destTokenAmount The amount of destination tokens.\\n * */\\n function _swapsExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) internal view returns (uint256 destTokenAmount) {\\n destTokenAmount = SwapsImplSovrynSwapLib.getExpectedReturn(\\n sourceToken,\\n destToken,\\n sourceTokenAmount\\n );\\n }\\n\\n /**\\n * @notice Verify that the amount of tokens are under the swap limit.\\n *\\n * @dev Calls priceFeeds::amountInEth\\n *\\n * @param tokenAddress The address of the token to calculate price.\\n * @param amount The amount of tokens to calculate price.\\n * */\\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\\n uint256 _maxSwapSize = maxSwapSize;\\n if (_maxSwapSize != 0) {\\n uint256 amountInEth;\\n if (tokenAddress == address(wrbtcToken)) {\\n amountInEth = amount;\\n } else {\\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\\n }\\n require(amountInEth <= _maxSwapSize, \\\"swap too large\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x7dfc45e91455458caf886b49c96ad426de06cddffa442c16628eba4974f3d323\"},\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":{\"content\":\"pragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"./interfaces/ISovrynSwapNetwork.sol\\\";\\nimport \\\"./interfaces/IContractRegistry.sol\\\";\\nimport \\\"../../interfaces/ISovryn.sol\\\";\\n\\n/**\\n * @title Swaps Implementation Sovryn contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the implementation of swap process and rate\\n * calculations for Sovryn network.\\n * */\\nlibrary SwapsImplSovrynSwapLib {\\n using SafeMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n struct SwapParams {\\n address sourceTokenAddress;\\n address destTokenAddress;\\n address receiverAddress;\\n address returnToSenderAddress;\\n uint256 minSourceTokenAmount;\\n uint256 maxSourceTokenAmount;\\n uint256 requiredDestTokenAmount;\\n }\\n\\n /// bytes32 contractName = hex\\\"42616e636f724e6574776f726b\\\"; /// \\\"SovrynSwapNetwork\\\"\\n\\n /**\\n * Get the hex name of a contract.\\n * @param source The name of the contract.\\n * */\\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\\n assembly {\\n result := mload(add(source, 32))\\n }\\n }\\n\\n /**\\n * Look up the Sovryn swap network contract registered at the given address.\\n * @param sovrynSwapRegistryAddress The address of the registry.\\n * */\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (ISovrynSwapNetwork)\\n {\\n /// State variable sovrynSwapContractRegistryAddress is part of\\n /// State.sol and set in ProtocolSettings.sol and this function\\n /// needs to work without delegate call as well -> therefore pass it.\\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\\n return\\n ISovrynSwapNetwork(\\n contractRegistry.addressOf(getContractHexName(\\\"SovrynSwapNetwork\\\"))\\n );\\n }\\n\\n /**\\n * Swap the source token for the destination token on the oracle based AMM.\\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\\n * -> swap the minSourceTokenAmount\\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\\n * -> same as on rollover. minimum amount is not considered at all.\\n *\\n * @param params SwapParams struct\\n * sourceTokenAddress The address of the source tokens.\\n * destTokenAddress The address of the destination tokens.\\n * receiverAddress The address who will received the swap token results\\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\\n * requiredDestTokenAmount The required amount of destination tokens.\\n * */\\n function swap(SwapParams memory params)\\n public\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n require(params.sourceTokenAddress != params.destTokenAddress, \\\"source == dest\\\");\\n\\n ISovryn iSovryn = ISovryn(address(this));\\n require(\\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\\n iSovryn.supportedTokens(params.destTokenAddress),\\n \\\"invalid tokens\\\"\\n );\\n\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\\n\\n IERC20[] memory path =\\n _getConversionPath(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n sovrynSwapNetwork\\n );\\n\\n uint256 minReturn = 1;\\n sourceTokenAmountUsed = params.minSourceTokenAmount;\\n\\n /// If the required amount of destination tokens is passed, we need to\\n /// calculate the estimated amount of source tokens regardless of the\\n /// minimum source token amount (name is misleading).\\n if (params.requiredDestTokenAmount > 0) {\\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n params.requiredDestTokenAmount,\\n params.maxSourceTokenAmount\\n );\\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\\n require(\\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\\n params.requiredDestTokenAmount,\\n \\\"insufficient source tokens provided.\\\"\\n );\\n minReturn = params.requiredDestTokenAmount;\\n }\\n\\n require(sourceTokenAmountUsed > 0, \\\"cannot swap 0 tokens\\\");\\n\\n _allowTransfer(\\n sourceTokenAmountUsed,\\n params.sourceTokenAddress,\\n address(sovrynSwapNetwork)\\n );\\n\\n /// @dev Note: the kyber connector uses .call() to interact with kyber\\n /// to avoid bubbling up. here we allow bubbling up.\\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\\n path,\\n sourceTokenAmountUsed,\\n minReturn,\\n params.receiverAddress,\\n address(0),\\n 0\\n );\\n\\n /// If the sender is not the protocol (calling with delegatecall),\\n /// return the remainder to the specified address.\\n /// @dev Note: for the case that the swap is used without the\\n /// protocol. Not sure if it should, though. needs to be discussed.\\n if (params.returnToSenderAddress != address(this)) {\\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\\n /// Send unused source token back.\\n IERC20(params.sourceTokenAddress).safeTransfer(\\n params.returnToSenderAddress,\\n params.maxSourceTokenAmount - sourceTokenAmountUsed\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Check whether the existing allowance suffices to transfer\\n * the needed amount of tokens.\\n * If not, allows the transfer of an arbitrary amount of tokens.\\n *\\n * @param tokenAmount The amount to transfer.\\n * @param tokenAddress The address of the token to transfer.\\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\\n * */\\n function _allowTransfer(\\n uint256 tokenAmount,\\n address tokenAddress,\\n address sovrynSwapNetwork\\n ) internal {\\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\\n if (tempAllowance < tokenAmount) {\\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\\n }\\n }\\n\\n /**\\n * @notice Calculate the number of source tokens to provide in order to\\n * obtain the required destination amount.\\n *\\n * @param sourceTokenAddress The address of the source token address.\\n * @param destTokenAddress The address of the destination token address.\\n * @param requiredDestTokenAmount The number of destination tokens needed.\\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\\n *\\n * @return The estimated amount of source tokens needed.\\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\\n * */\\n function _estimateSourceTokenAmount(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 requiredDestTokenAmount,\\n uint256 maxSourceTokenAmount\\n ) internal view returns (uint256 estimatedSourceAmount) {\\n ISovryn iSovryn = ISovryn(address(this));\\n uint256 sourceToDestPrecision =\\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\\n\\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\\n uint256 expectedRate =\\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\\n\\n /// Compute the source tokens needed to get the required amount with the worst case rate.\\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\\n expectedRate\\n );\\n\\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\\n uint256 buffer = estimatedSourceAmount.div(1000);\\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\\n\\n /// Never spend more than the maximum.\\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\\n return maxSourceTokenAmount;\\n }\\n\\n /**\\n * @notice Get the expected rate for 1 source token when exchanging the\\n * given amount of source tokens.\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\\n * */\\n function getExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n\\n /// Return the rate for 1 token with 18 decimals.\\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\\n }\\n\\n /**\\n * @notice Get the expected return amount when exchanging the given\\n * amount of source tokens.\\n *\\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the return for.\\n * */\\n function getExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256 expectedReturn) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n }\\n\\n function _getConversionPath(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n ISovrynSwapNetwork sovrynSwapNetwork\\n ) private view returns (IERC20[] memory path) {\\n IERC20[] memory _defaultPathConversion =\\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\\n\\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\\n path = _defaultPathConversion.length >= 3\\n ? _defaultPathConversion\\n : sovrynSwapNetwork.conversionPath(\\n IERC20(sourceTokenAddress),\\n IERC20(destTokenAddress)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x058b8d733422a2421f17d1b159aed69f151ea8d5f48ee507bac5b4e86add8b0c\"},\"contracts/swaps/connectors/interfaces/IContractRegistry.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\ncontract IContractRegistry {\\n function addressOf(bytes32 contractName) public view returns (address);\\n}\\n\",\"keccak256\":\"0x793c4eefa2ee04cbf0a1a9da28676ac310ed7bf60a27ec7d86de7d7236ccf45b\"},\"contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol\":{\"content\":\"pragma solidity >=0.5.8 <=0.5.17;\\n\\nimport \\\"../../../interfaces/IERC20.sol\\\";\\n\\ncontract ISovrynSwapNetwork {\\n function convertByPath(\\n IERC20[] calldata _path,\\n uint256 _amount,\\n uint256 _minReturn,\\n address _beneficiary,\\n address _affiliateAccount,\\n uint256 _affiliateFee\\n ) external payable returns (uint256);\\n\\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\\n\\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\\n external\\n view\\n returns (IERC20[] memory);\\n}\\n\",\"keccak256\":\"0xcd28e146b77183bff18f78b511912f7ebe60d437430fdaa72ed145fdda61a5ad\"}},\"version\":1}", - "bytecode": "0x60806040526001600055678ac7230489e80000601555670214e8348c4f000060185567013fbe85edc90000601b55674563918244f40000602055674563918244f40000602155674563918244f400006027556127106028556802b5e3af16b1880000602955650f478e084000602b5567016345785d8a0000602c556802b5e3af16b1880000602f5560036035556801158e460913d00000603955348015620000a657600080fd5b506000620000bc6001600160e01b036200011016565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35062000114565b3390565b61507f80620001246000396000f3fe6080604052600436106103815760003560e01c80638f32d59b116101d1578063cd5d808d11610102578063e8f62764116100a0578063f589a3e71161006f578063f589a3e714610a05578063f6ddc8b314610a1a578063f706b1f214610a2f578063f851a44014610a4457610381565b8063e8f62764146109a6578063edab119f146109bb578063f0e085f5146109d0578063f2fde38b146109e557610381565b8063d485045e116100dc578063d485045e14610925578063d67f707714610945578063d84ca25414610965578063e762319f1461098657610381565b8063cd5d808d146108db578063d288208c146108fb578063d473c2da1461091057610381565b8063b7e152411161016f578063bdee453c11610149578063bdee453c1461082f578063c4a908151461084f578063c4d66de814610887578063cb6eacd1146108a757610381565b8063b7e15241146107e5578063b9cffa3e14610805578063ba4861e91461081a57610381565b8063acc04348116101ab578063acc0434814610779578063ae0a85301461078e578063afe84009146107a3578063b30643d9146107c557610381565b80638f32d59b1461072f57806392d894f814610744578063959083d31461076457610381565b80634203e395116102b65780636e663730116102545780637a8faeb8116102235780637a8faeb8146106d05780638456cb59146106e55780638da5cb5b146106fa5780638dc48ba51461070f57610381565b80636e663730146106715780637420ca3e14610691578063742e6798146106a657806378d849ed146106bb57610381565b8063569fc1fb11610290578063569fc1fb146105dc578063574442cc1461060b57806362fff3f61461062057806368c4ac261461065157610381565b80634203e395146105925780634699f846146105b25780634f28cac2146105c757610381565b80632a324027116103235780633432423c116102fd5780633432423c146105125780633452d2d4146105325780633fca506e146105525780634115a2b61461057257610381565b80632a324027146104c65780632f470764146104db57806333d8991f146104f057610381565b80631b7bde741161035f5780631b7bde741461042c578063218b39c61461045957806324cc57491461047957806325decac0146104a657610381565b8063065d810f146103af5780630676c1b7146103ea57806317548b791461040c575b34801561038d57600080fd5b5060405162461bcd60e51b81526004016103a690614e03565b60405180910390fd5b3480156103bb57600080fd5b506103cf6103ca366004613e77565b610a59565b6040516103e196959493929190614ef6565b60405180910390f35b3480156103f657600080fd5b506103ff610a99565b6040516103e1919061492d565b34801561041857600080fd5b506103ff61042736600461400a565b610aa8565b34801561043857600080fd5b5061044c610447366004613d41565b610ac3565b6040516103e19190614eb1565b34801561046557600080fd5b506103ff610474366004613d23565b610ae0565b34801561048557600080fd5b50610499610494366004613d23565b610afb565b6040516103e19190614b50565b3480156104b257600080fd5b5061044c6104c1366004613d7b565b610b10565b3480156104d257600080fd5b5061044c610b6b565b3480156104e757600080fd5b5061044c610b71565b3480156104fc57600080fd5b5061051061050b366004613f02565b610b77565b005b34801561051e57600080fd5b506103cf61052d366004613e77565b610be4565b34801561053e57600080fd5b5061044c61054d366004613d23565b610c24565b34801561055e57600080fd5b5061044c61056d366004613d23565b610c36565b34801561057e57600080fd5b5061049961058d366004613ee3565b610c48565b34801561059e57600080fd5b5061044c6105ad366004613d23565b610c68565b3480156105be57600080fd5b5061044c610c7a565b3480156105d357600080fd5b5061044c610c80565b3480156105e857600080fd5b506105fc6105f7366004613ec5565b610c86565b6040516103e193929190614ecd565b34801561061757600080fd5b5061044c610ca7565b34801561062c57600080fd5b5061064061063b366004613d41565b610cad565b6040516103e1959493929190614edb565b34801561065d57600080fd5b5061049961066c366004613d23565b610ce7565b34801561067d57600080fd5b506103ff61068c366004613d23565b610cfc565b34801561069d57600080fd5b506103ff610d17565b3480156106b257600080fd5b5061044c610d26565b3480156106c757600080fd5b506103ff610d2c565b3480156106dc57600080fd5b5061044c610d3b565b3480156106f157600080fd5b50610499610d41565b34801561070657600080fd5b506103ff610d4a565b34801561071b57600080fd5b506103ff61072a366004613d23565b610d59565b34801561073b57600080fd5b50610499610d74565b34801561075057600080fd5b5061044c61075f366004613d23565b610d9a565b34801561077057600080fd5b5061044c610dac565b34801561078557600080fd5b5061044c610db2565b34801561079a57600080fd5b5061044c610db8565b3480156107af57600080fd5b506107b8610dbe565b6040516103e19190614c54565b3480156107d157600080fd5b5061044c6107e0366004613d23565b610dcd565b3480156107f157600080fd5b5061044c610800366004613d23565b610ddf565b34801561081157600080fd5b506103ff610df1565b34801561082657600080fd5b506103ff610e00565b34801561083b57600080fd5b5061044c61084a366004613d23565b610e0f565b34801561085b57600080fd5b5061086f61086a366004613ec5565b610e21565b6040516103e19c9b9a99989796959493929190614ba1565b34801561089357600080fd5b506105106108a2366004613d23565b610e93565b3480156108b357600080fd5b506108c76108c2366004613ec5565b610f96565b6040516103e1989796959493929190614b5e565b3480156108e757600080fd5b5061044c6108f6366004613d41565b610fe8565b34801561090757600080fd5b506103ff611005565b34801561091c57600080fd5b5061044c611014565b34801561093157600080fd5b5061044c610940366004613d23565b61101a565b34801561095157600080fd5b5061044c610960366004613df0565b61102c565b610978610973366004613f4f565b6110fa565b6040516103e1929190614ebf565b34801561099257600080fd5b5061044c6109a1366004613d7b565b6112fa565b3480156109b257600080fd5b506103ff61146e565b3480156109c757600080fd5b5061044c61147d565b3480156109dc57600080fd5b5061044c611483565b3480156109f157600080fd5b50610510610a00366004613d23565b611489565b348015610a1157600080fd5b5061044c6114b9565b348015610a2657600080fd5b5061044c6114bf565b348015610a3b57600080fd5b506103ff6114c5565b348015610a5057600080fd5b506103ff6114d4565b6009602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b6031546001600160a01b031681565b6005602052600090815260409020546001600160a01b031681565b603b60209081526000928352604080842090915290825290205481565b6023602052600090815260409020546001600160a01b031681565b60326020526000908152604090205460ff1681565b60008215610b6257610b2586868686866114e3565b9050600082610b3c57610b378261161c565b610b45565b610b4582611652565b90508015610b6057610b5d828263ffffffff61167616565b91505b505b95945050505050565b60185481565b601f5481565b603d5460ff1615610b9a5760405162461bcd60e51b81526004016103a690614c83565b6000838152600660205260409020600a01546001600160a01b03163314610bd35760405162461bcd60e51b81526004016103a690614dc3565b610bdf833384846116a2565b505050565b6008602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b601a6020526000908152604090205481565b602a6020526000908152604090205481565b600a60209081526000928352604080842090915290825290205460ff1681565b60166020526000908152604090205481565b60155481565b60295481565b600c6020526000908152604090208054600182015460029092015490919083565b602b5481565b600b602090815260009283526040808420909152908252902080546001820154600283015460038401546004909401549293919290919085565b60266020526000908152604090205460ff1681565b6033602052600090815260409020546001600160a01b031681565b6003546001600160a01b031681565b60355481565b6002546001600160a01b031681565b601e5481565b603d5460ff1681565b6001546001600160a01b031690565b6022602052600090815260409020546001600160a01b031681565b6001546000906001600160a01b0316610d8b611717565b6001600160a01b031614905090565b60176020526000908152604090205481565b602c5481565b602f5481565b60205481565b602d546001600160a01b031681565b601d6020526000908152604090205481565b601c6020526000908152604090205481565b6037546001600160a01b031681565b6004546001600160a01b031681565b60366020526000908152604090205481565b600660208190526000918252604090912080546001820154600283015460038401546004850154600586015496860154600787015460088801546009890154600a8a0154600b909a0154989a9799969860ff909616979496949593949293919290916001600160a01b0391821691168c565b610e9b610d74565b610eb75760405162461bcd60e51b81526004016103a690614dc3565b633613289560e21b600081905260056020527fd3a886345208a8e3a0f774019653c4e69589e943ba1e46c7fa0ef875651e6e39546001600160a01b031690610eff908361171b565b610f106333d8991f60e01b8361171b565b610f2163d67f707760e01b8361171b565b610f3162977b2b60e61b8361171b565b610f4263e762319f60e01b8361171b565b6b4c6f616e4f70656e696e677360a01b826001600160a01b0316826001600160a01b03167f1420e3a2094d671bc2eb897941fa3d94ffa37f0cb6d530651946250a2151cb7f60405160405180910390a45050565b6007602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949560ff8516956101009095046001600160a01b03908116959481169493169288565b603c60209081526000928352604080842090915290825290205481565b6038546001600160a01b031681565b60275481565b60196020526000908152604090205481565b60006224ea008161105d6907baab4146b63dd00000611051868863ffffffff61179516565b9063ffffffff6117cf16565b9050600061107862015180611051858563ffffffff61179516565b9050600061108c898363ffffffff61181116565b905060006110998261161c565b905080156110b4576110b1828263ffffffff61181116565b91505b60006110c18d8d85611853565b9050806110d757600096505050505050506110f0565b6110e78a8263ffffffff61167616565b96505050505050505b9695505050505050565b60008060016000541461111f5760405162461bcd60e51b81526004016103a690614e33565b6002600055603d5460ff16156111475760405162461bcd60e51b81526004016103a690614c83565b34158061115357508215155b61116f5760405162461bcd60e51b81526004016103a690614e63565b336000908152602260205260409020546001600160a01b03166111a45760405162461bcd60e51b81526004016103a690614da3565b6111ac613a43565b5060008a815260076020908152604091829020825161010080820185528254808352600184015460ff811615159584019590955293046001600160a01b039081169482019490945260028201548416606082015260038201549093166080840152600481015460a0840152600581015460c08401526006015460e08301526112465760405162461bcd60e51b81526004016103a690614df3565b60006112618260600151836080015189602001358c8e6114e3565b9050806112805760405162461bcd60e51b81526004016103a690614d93565b6112e2828c8c848d611297368f90038f018f614028565b6112a6368f90038f018f614046565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118e992505050565b6001600055909d909c509a5050505050505050505050565b60008215610b62578115611324576113218368056bc75e2d6310000063ffffffff61167616565b92505b8360008361133a576113358261161c565b611343565b61134382611652565b9050801561135e5761135b828263ffffffff61181116565b91505b866001600160a01b0316886001600160a01b0316141561139c57611395856110518468056bc75e2d6310000063ffffffff61179516565b9250611463565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c906113d3908c908e9060040161493b565b604080518083038186803b1580156113ea57600080fd5b505afa1580156113fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114229190810190614083565b91509150806000146114605761145d816110518981866114518a68056bc75e2d6310000063ffffffff61179516565b9063ffffffff61179516565b94505b50505b505095945050505050565b6014546001600160a01b031681565b601b5481565b60285481565b611491610d74565b6114ad5760405162461bcd60e51b81526004016103a690614dc3565b6114b681611c22565b50565b60395481565b60215481565b602e546001600160a01b031681565b6030546001600160a01b031681565b6000846001600160a01b0316866001600160a01b031614156115235761151c68056bc75e2d63100000611051868663ffffffff61179516565b90506115de565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c9061155a908a908c9060040161493b565b604080518083038186803b15801561157157600080fd5b505afa158015611585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115a99190810190614083565b91509150816000146115db576115d868056bc75e2d631000006110518761145186838c8863ffffffff61179516565b92505b50505b8180156115ea57508015155b15610b62576110f081611610856110518368056bc75e2d6310000063ffffffff61179516565b9063ffffffff61167616565b600061164c68056bc75e2d631000006116406018548561179590919063ffffffff16565b9063ffffffff611ca416565b92915050565b600061164c68056bc75e2d63100000611640601b548561179590919063ffffffff16565b60008282018381101561169b5760405162461bcd60e51b81526004016103a690614ce3565b9392505050565b6000848152600a602090815260408083206001600160a01b038681168086529190935292819020805460ff1916851515179055519085169086907f0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c9843390611709908690614b50565b60405180910390a450505050565b3390565b6001600160e01b03198216600090815260056020526040902080546001600160a01b0319166001600160a01b0383169081179091551561177657611770600d6001600160e01b0319841663ffffffff611ce616565b50611791565b610bdf600d6001600160e01b0319841663ffffffff611d2e16565b5050565b6000826117a45750600061164c565b828202828482816117b157fe5b041461169b5760405162461bcd60e51b81526004016103a690614db3565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611def565b600061169b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611e26565b604051636dcd64e560e01b81526000907394D7CEE3Fe77432312e4faCf4dc416CA5Cd224a690636dcd64e5906118919087908790879060040161498b565b60206040518083038186803b1580156118a957600080fd5b505af41580156118bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118e19190810190614065565b949350505050565b60008089606001516001600160a01b03168a608001516001600160a01b031614156119265760405162461bcd60e51b81526004016103a690614d03565b8960a0015186101561194a5760405162461bcd60e51b81526004016103a690614e83565b60e08a015115158061195f5750604084015115155b61197b5760405162461bcd60e51b81526004016103a690614ca3565b6000600660006119928d8d8b8b8b60200151611e52565b8152602001908152602001600020905060006119bd8c83886000015189602001518a60400151612244565b60608701519091506119d5908263ffffffff61181116565b60608701528915611a5d57606086015115611a025760405162461bcd60e51b81526004016103a690614d63565b6000611a118760800151611652565b60808e015160608f0151919250908215611a5557611a3a8a602001518660000154848487612460565b6080890151611a4f908463ffffffff61181116565b60808a01525b505050611acf565b6000611a828c8e606001518f608001518b602001518b6060015160008060008e6124ff565b60c08a0152506080880151909150611aa0908263ffffffff61167616565b608088015260a087015160c08801511015611acd5760405162461bcd60e51b81526004016103a690614cc3565b505b60408051610180810182528354815260018401546020820152600284015491810191909152600383015460ff16151560608201526004830154608080830191909152600584015460a0830152600684015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b85015416610160830152870151611b78918e918b908d61265d565b611b945760405162461bcd60e51b81526004016103a690614dd3565b60808601516005830154611bad9163ffffffff61167616565b60058301558915611bd7576007820154611bcd904263ffffffff61181116565b60e0870152611bf8565b611bf16f4b3b4ca85a86c47a098a224000000000896117cf565b6101008701525b611c058c8389898e612763565b856020015186608001519350935050509850989650505050505050565b6001600160a01b038116611c485760405162461bcd60e51b81526004016103a690614cb3565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612a36565b6000611cf28383612a80565b611d26575060018083018054808301808355600092835260208084209092018590558483529085905260409091205561164c565b50600061164c565b6000611d3a8383612a80565b15611d265760008281526020849052604090205460018401546000199182019101808214611db2576000856001018281548110611d7357fe5b9060005260206000200154905080866001018481548110611d9057fe5b6000918252602080832090910192909255918252869052604090206001830190555b60008481526020869052604081205560018501805480611dce57fe5b6001900381819060005260206000200160009055905560019250505061164c565b60008183611e105760405162461bcd60e51b81526004016103a69190614c62565b506000838581611e1c57fe5b0495945050505050565b60008184841115611e4a5760405162461bcd60e51b81526004016103a69190614c62565b505050900390565b60008560200151611e755760405162461bcd60e51b81526004016103a690614e23565b825160208401516060850151611e89613a87565b88611fe0576001600160a01b0383166000908152602a60209081526040918290208054600101908190558c519251611ec89392889288929091016148d9565b60408051601f1981840301815291815281516020928301206000818152600690935291205490995015611f0d5760405162461bcd60e51b81526004016103a690614d53565b5060408051610180810182528981528a5160208201526000918101829052600160608201526080810187905260a081018290524260c082015260e0810182905261010081018990526101208101919091526001600160a01b038084166101408301528416610160820152611f88600f8a63ffffffff611ce616565b506001600160a01b0384166000908152601160205260409020611fb1908a63ffffffff611ce616565b506001600160a01b0383166000908152601260205260409020611fda908a63ffffffff611ce616565b50612161565b5060008881526006602081815260409283902083516101808101855281548152600182015492810192909252600281015493820193909352600383015460ff161580156060830181905260048501546080840152600585015460a08401529284015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b909401549093166101608201529161209a57508060e0015142105b6120b65760405162461bcd60e51b81526004016103a690614d73565b826001600160a01b03168161014001516001600160a01b0316146120ec5760405162461bcd60e51b81526004016103a690614cd3565b836001600160a01b03168161016001516001600160a01b0316146121225760405162461bcd60e51b81526004016103a690614d33565b89516020820151146121465760405162461bcd60e51b81526004016103a690614c73565b608081015161215b908763ffffffff61167616565b60808201525b6001600160a01b0382161561217d5761217d89848460016116a2565b60008981526006602081815260409283902084518155908401516001820155918301516002830155606083015160038301805460ff19169115159190911790556080830151600483015560a0830151600583015560c08301519082015560e0820151600782015561010082015160088201556101208201516009820155610140820151600a820180546001600160a01b03199081166001600160a01b039384161790915561016090930151600b909201805490931691161790555095979650505050505050565b600b8401546060860151600091612266916001600160a01b0390911690612a95565b84546000818152600c60209081526040808320600b808b01546001600160a01b03908116865290845282852060608d0180518316875294529190932060e08b0151925160808c0151600a8c0154959692956122c79488949392911642612b73565b6000811580156122da5750600789015415155b1561230857612305620151806110518660000154611451428e6007015461181190919063ffffffff16565b90505b60006123286907baab4146b63dd000006110518a8c63ffffffff61179516565b855490915061233d908263ffffffff61167616565b85556001840154612354908263ffffffff61167616565b6001850155826123c357845461238190429061161090611051620151806114518d8963ffffffff61167616565b60078b01819055612398904263ffffffff61181116565b9250610e1083116123bb5760405162461bcd60e51b81526004016103a690614cf3565b869550612407565b60078a01546123e2576123dc428463ffffffff61167616565b60078b01555b6124046201518061105183611451428f6007015461181190919063ffffffff16565b95505b600185015461241c908763ffffffff61167616565b60018601558354612433908963ffffffff61167616565b8455600284015461244a908763ffffffff61167616565b8460020181905550505050505095945050505050565b80156124f8576001600160a01b0383166000908152601c602052604090205461248f908263ffffffff61167616565b6001600160a01b038085166000818152601c6020526040908190209390935591518692918816907ffb6c38ae4fdd498b3a5003f02ca4ca5340dfedb36b1b100c679eb60633b2c0a7906124e3908690614eb1565b60405180910390a46124f88585858585612bc1565b5050505050565b6040805160a0810182526001600160a01b03808b16825289811660208084019190915230838501819052606080850191909152918a1660808401528351918201845288825281018790529182018590526000918291829161256491908e888886613027565b90935091506125738b8361324c565b600254602754604051631e2c62d360e01b81526001600160a01b0390921691631e2c62d3916125ac918f918f9188918a916004016149db565b60206040518083038186803b1580156125c457600080fd5b505afa1580156125d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125fc9190810190614065565b9050896001600160a01b03168b6001600160a01b03168d7fb4eb3c9b62efcce7021cba5fd9cd0c44df91c2272806ccc5e57df7c912e8d7168c868860405161264693929190614b35565b60405180910390a499509950999650505050505050565b600061268568056bc75e2d631000006110518468055005f0c61448000063ffffffff61179516565b9150818310156127575760a08501511561274f5760025460608701516080808901519088015160a089015160405163f80b25fb60e01b81526000956001600160a01b03169463f80b25fb946126e294919390928c906004016149db565b60206040518083038186803b1580156126fa57600080fd5b505afa15801561270e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127329190810190614065565b905082612745858363ffffffff61167616565b1015915050610b62565b506000610b62565b50600195945050505050565b6002546060860151608087015160048088015460058901546040516317f8680960e11b815260009687966001600160a01b0390911695632ff0d012956127ad9592949193016149b3565b604080518083038186803b1580156127c457600080fd5b505afa1580156127d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127fc9190810190614083565b915091508660c0015182116128235760405162461bcd60e51b81526004016103a690614de3565b4286600601541415612989576002546060880151608089015160405163524efd4b60e01b81526000936001600160a01b03169263524efd4b926128689260040161493b565b60206040518083038186803b15801561288057600080fd5b505afa158015612894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128b89190810190614065565b60025460808a015160608b015160405163524efd4b60e01b81529394506000936001600160a01b039093169263524efd4b926128f892909160040161493b565b60206040518083038186803b15801561291057600080fd5b505afa158015612924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129489190810190614065565b9050600061295c838363ffffffff61179516565b90508561297e5760c087015161297990829063ffffffff6117cf16565b612980565b835b60098a01555050505b60408051610180810182528754815260018801546020820152600288015491810191909152600387015460ff161515606082015260048701546080820152600587015460a0820152600687015460c0820152600787015460e082015260088701546101008201526009870154610120820152600a8701546001600160a01b03908116610140830152600b88015416610160820152612a2d908890878785878961331a565b50505050505050565b60008183612a575760405162461bcd60e51b81526004016103a69190614c62565b5083612a655750600061169b565b6000836001860381612a7357fe5b0460010195945050505050565b60009081526020919091526040902054151590565b6001600160a01b038083166000908152600b602090815260408083209385168352929052908120600181015490919015801590612ad55750600482015415155b15612b6657612b0062015180611051846001015461145186600401544261181190919063ffffffff16565b4260048401556002830154909150811115612b1c575060028101545b8015612b61576003820154612b37908263ffffffff61167616565b60038301556002820154612b51908263ffffffff61181116565b6002830155612b61848483613451565b612b6d565b4260048301555b50505050565b6000612ba96a07259756a8d619980000006110516015546114518b600001546114518d600201548961181190919063ffffffff16565b6002880183905590508015612a2d57612a2d83878787855b602f546002546001600160a01b038581166000908152603c602090815260408083208885168452909152812054909392919091169015612c24576001600160a01b038087166000908152603c602090815260408083209389168352929052205491505b6037546000906060906001600160a01b038085169163d138f9a160e01b918b9116612c6268056bc75e2d631000006110518c8b63ffffffff61179516565b604051602401612c749392919061498b565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612cb29190614921565b600060405180830381855afa9150503d8060008114612ced576040519150601f19603f3d011682016040523d82523d6000602084013e612cf2565b606091505b50915091506001821415612d0857602081015194505b6000306001600160a01b031663c22552f76040518163ffffffff1660e01b815260040160206040518083038186803b158015612d4357600080fd5b505afa158015612d57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d7b9190810190614065565b90508515801590612d8c5750858110155b15612fb45760375460385460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392612dc7929116908a90600401614b1a565b602060405180830381600087803b158015612de157600080fd5b505af1158015612df5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e199190810190613ea7565b50603854603f546040516000926001600160a01b031691612e40918f918b91602401614b35565b60408051601f198184030181529181526020820180516001600160e01b0316630efe6a8b60e01b17905251612e759190614921565b6000604051808303816000865af19150503d8060008114612eb2576040519150601f19603f3d011682016040523d82523d6000602084013e612eb7565b606091505b505090508015612f4657601f54612ed4908863ffffffff61167616565b601f819055508a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167ff41c644671512f1cda76abfe6038e3d7d526c1377a5a8c692f81703901db2150898b603f54604051612f3993929190614ecd565b60405180910390a4612fae565b8a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e710812898b603f54604051612fa593929190614ecd565b60405180910390a45b5061301a565b8515801590612fc257508581105b1561301a57603754603f546040518c926001600160a01b0390811692908f16917f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e71081291613011918b918d91614ecd565b60405180910390a45b5050505050505050505050565b8451600090819015158061303e5750602087015115155b61305a5760405162461bcd60e51b81526004016103a690614e13565b602087015161306b57865160208801525b6020870151875111156130905760405162461bcd60e51b81526004016103a690614d43565b60008060008761314d5760408a015161310c5785156130c1576130ba8a60005b60200201516134f6565b90506130d5565b6130d28a60005b602002015161161c565b90505b80156131075760808b01518b516130f891908b908e60015b60200201518561351a565b89516131049082611811565b8a525b61314d565b85156131245761311d8a60026130b0565b9050613132565b61312f8a60026130c8565b90505b801561314d5760408a01516131479082611676565b60408b01525b86511561316c5760405162461bcd60e51b81526004016103a690614e43565b6131768b8b61366a565b60408c015191945092506131c257895182146131a45760405162461bcd60e51b81526004016103a690614e73565b80156131bd576131ba828263ffffffff61167616565b91505b61323c565b60208a01518211156131e65760405162461bcd60e51b81526004016103a690614d23565b60408a015183101561320a5760405162461bcd60e51b81526004016103a690614c93565b801561323c5760808b015160208c015161322991908b908e60006130ed565b613239838263ffffffff61181116565b92505b5090999098509650505050505050565b6029548015610bdf57602d546000906001600160a01b03858116911614156132755750816132fa565b600254604051635967aa7560e11b81526001600160a01b039091169063b2cf54ea906132a79087908790600401614b1a565b60206040518083038186803b1580156132bf57600080fd5b505afa1580156132d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506132f79190810190614065565b90505b81811115612b6d5760405162461bcd60e51b81526004016103a690614d83565b80156133a357856000015185600001516001600160a01b031686602001516001600160a01b03167f7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f908a606001518b6080015189602001518a608001518b600001518c60e001518c8c604051613396989796959493929190614a1d565b60405180910390a4612a2d565b6133bd6f4b3b4ca85a86c47a098a224000000000836117cf565b9150856000015185600001516001600160a01b031686602001516001600160a01b03167ff640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c8a608001518b6060015189608001518a602001518b600001518e60e001518d60c001518e61010001518d60405161344099989796959493929190614a94565b60405180910390a450505050505050565b600061347568056bc75e2d631000006110516015548561179590919063ffffffff16565b9050613482848483613754565b61349c8385613497858563ffffffff61181116565b6137e2565b6001600160a01b038085169084167f220e66e3e759e1382aa86cd8af5abca05ebf3ad564f223ae62d977678337272a6134db858563ffffffff61181116565b6040516134e89190614eb1565b60405180910390a350505050565b600061164c68056bc75e2d63100000611640603e548561179590919063ffffffff16565b808015613662576001600160a01b0386811660009081526033602052604090205416156135d0576001600160a01b038087166000908152603360205260409020546135689116878684613845565b50506135cd61358f68056bc75e2d631000006110516039548561179590919063ffffffff16565b6135c16135b468056bc75e2d631000006110516020548761179590919063ffffffff16565b849063ffffffff61181116565b9063ffffffff61181116565b90505b6001600160a01b0384166000908152601960205260409020546135f9908263ffffffff61167616565b6001600160a01b03808616600081815260196020526040908190209390935591518792918916907fb23479169712c443e6b00fb0cec3506a5f5926f541df4243d313e11c8c5c71ed9061364d908690614eb1565b60405180910390a46136628686868686612bc1565b505050505050565b600080613675613aeb565b84516001600160a01b039081168252602080870151821683820152604080880151831681850152606080890151909316928401929092528551608084015285015160a08301528481015160c0830152516335aaa79d60e01b81527394D7CEE3Fe77432312e4faCf4dc416CA5Cd224a6906335aaa79d906136f9908490600401614ea3565b604080518083038186803b15801561371057600080fd5b505af4158015613724573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506137489190810190614083565b90969095509350505050565b8015610bdf576001600160a01b038216600090815260166020526040902054613783908263ffffffff61167616565b6001600160a01b0380841660008181526016602052604090819020939093559151908516907f40a75ae5f7a5336e75f7c7977e12c4b46a9ac0f30de01a2d5b6c1a4f4af63587906137d5908590614eb1565b60405180910390a3505050565b8015610bdf576138026001600160a01b038416838363ffffffff6138d116565b816001600160a01b0316836001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1836040516137d59190614eb1565b6040516306a688ff60e11b815260009081903090630d4d11fe90613873908990899089908990600401614956565b6040805180830381600087803b15801561388c57600080fd5b505af11580156138a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506138c49190810190614083565b9097909650945050505050565b604051610bdf90849063a9059cbb60e01b906138f39086908690602401614b1a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613937826001600160a01b0316613a0a565b6139535760405162461bcd60e51b81526004016103a690614e93565b60006060836001600160a01b03168360405161396f9190614921565b6000604051808303816000865af19150503d80600081146139ac576040519150601f19603f3d011682016040523d82523d6000602084013e6139b1565b606091505b5091509150816139d35760405162461bcd60e51b81526004016103a690614d13565b805115612b6d57808060200190516139ee9190810190613ea7565b612b6d5760405162461bcd60e51b81526004016103a690614e53565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906118e1575050151592915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b803561164c8161500d565b803561164c81615021565b805161164c81615021565b803561164c8161502a565b803561164c81615033565b60008083601f840112613b7057600080fd5b50813567ffffffffffffffff811115613b8857600080fd5b602083019150836001820283011115613ba057600080fd5b9250929050565b600060808284031215613bb957600080fd5b50919050565b600060808284031215613bd157600080fd5b613bdb6080614f50565b90506000613be98484613b27565b8252506020613bfa84848301613b27565b6020830152506040613c0e84828501613b27565b6040830152506060613c2284828501613b27565b60608301525092915050565b60006101208284031215613bb957600080fd5b60006101208284031215613c5457600080fd5b613c5f610120614f50565b90506000613c6d8484613b48565b8252506020613c7e84848301613b48565b6020830152506040613c9284828501613b48565b6040830152506060613ca684828501613b48565b6060830152506080613cba84828501613b48565b60808301525060a0613cce84828501613b48565b60a08301525060c0613ce284828501613b48565b60c08301525060e0613cf684828501613b48565b60e083015250610100613d0b84828501613b48565b6101008301525092915050565b805161164c8161502a565b600060208284031215613d3557600080fd5b60006118e18484613b27565b60008060408385031215613d5457600080fd5b6000613d608585613b27565b9250506020613d7185828601613b27565b9150509250929050565b600080600080600060a08688031215613d9357600080fd5b6000613d9f8888613b27565b9550506020613db088828901613b27565b9450506040613dc188828901613b48565b9350506060613dd288828901613b48565b9250506080613de388828901613b32565b9150509295509295909350565b60008060008060008060c08789031215613e0957600080fd5b6000613e158989613b27565b9650506020613e2689828a01613b27565b9550506040613e3789828a01613b48565b9450506060613e4889828a01613b48565b9350506080613e5989828a01613b48565b92505060a0613e6a89828a01613b48565b9150509295509295509295565b60008060408385031215613e8a57600080fd5b6000613e968585613b27565b9250506020613d7185828601613b48565b600060208284031215613eb957600080fd5b60006118e18484613b3d565b600060208284031215613ed757600080fd5b60006118e18484613b48565b60008060408385031215613ef657600080fd5b6000613d608585613b48565b600080600060608486031215613f1757600080fd5b6000613f238686613b48565b9350506020613f3486828701613b27565b9250506040613f4586828701613b32565b9150509250925092565b600080600080600080600080610240898b031215613f6c57600080fd5b6000613f788b8b613b48565b9850506020613f898b828c01613b48565b9750506040613f9a8b828c01613b32565b9650506060613fab8b828c01613b48565b9550506080613fbc8b828c01613ba7565b945050610100613fce8b828c01613c2e565b93505061022089013567ffffffffffffffff811115613fec57600080fd5b613ff88b828c01613b5e565b92509250509295985092959890939650565b60006020828403121561401c57600080fd5b60006118e18484613b53565b60006080828403121561403a57600080fd5b60006118e18484613bbf565b6000610120828403121561405957600080fd5b60006118e18484613c41565b60006020828403121561407757600080fd5b60006118e18484613d18565b6000806040838503121561409657600080fd5b60006140a28585613d18565b9250506020613d7185828601613d18565b6140bc81614f89565b82525050565b6140bc6140ce82614f89565b614fec565b6140bc81614f94565b6140bc81614f99565b6140bc6140f182614f99565b614f99565b600061410182614f77565b61410b8185614f7b565b935061411b818560208601614fc0565b9290920192915050565b6140bc81614fb5565b600061413982614f77565b6141438185614f80565b9350614153818560208601614fc0565b61415c81614ffd565b9093019392505050565b6000614173601383614f80565b720d8dec2dca0c2e4c2dae640dad2e6dac2e8c6d606b1b815260200192915050565b60006141a2600683614f80565b6514185d5cd95960d21b815260200192915050565b60006141c4601b83614f80565b7f696e73756666696369656e742073776170206c69717569646974790000000000815260200192915050565b60006141fd601083614f80565b6f1a5b9d985b1a59081a5b9d195c995cdd60821b815260200192915050565b6000614229602683614f80565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000614271601d83614f80565b7f656e7472792070726963652061626f766520746865206d696e696d756d000000815260200192915050565b60006142aa601183614f80565b700c4dee4e4deeecae440dad2e6dac2e8c6d607b1b815260200192915050565b60006142d7601b83614f80565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000614310600e83614f80565b6d1b1bd85b881d1bdbc81cda1bdc9d60921b815260200192915050565b600061433a601583614f80565b740c6ded8d8c2e8cae4c2d85ed8dec2dc40dac2e8c6d605b1b815260200192915050565b600061436b602083614f80565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b60006143a4601383614f80565b72737761702066696c6c20746f6f206c6172676560681b815260200192915050565b60006143d3600f83614f80565b6e0d8cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b60006143fe601c83614f80565b7f736f75726365416d6f756e74206c6172676572207468616e206d617800000000815260200192915050565b6000614437600b83614f80565b6a6c6f616e2065786973747360a81b815260200192915050565b600061445e601283614f80565b7139bab938363ab9903637b0b7103a37b5b2b760711b815260200192915050565b600061448c600e83614f80565b6d1b1bd85b881a185cc8195b99195960921b815260200192915050565b60006144b6600e83614f80565b6d7377617020746f6f206c6172676560901b815260200192915050565b60006144e0600f83614f80565b6e0636f6c6c61746572616c206973203608c1b815260200192915050565b600061450b600e83614f80565b6d1b9bdd08185d5d1a1bdc9a5e995960921b815260200192915050565b6000614535602183614f80565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000614578600c83614f80565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006145a0601783614f80565b7f636f6c6c61746572616c20696e73756666696369656e74000000000000000000815260200192915050565b60006145d9601283614f80565b713ab73432b0b63a343c903837b9b4ba34b7b760711b815260200192915050565b6000614607601583614f80565b746c6f616e506172616d73206e6f742065786973747360581b815260200192915050565b6000614638601483614f80565b7319985b1b189858dac81b9bdd08185b1b1bddd95960621b815260200192915050565b6000614668602e83614f80565b7f6d696e206f72206d617820736f7572636520746f6b656e20616d6f756e74206e81526d1959591cc81d1bc81899481cd95d60921b602082015260400192915050565b60006146b8601383614f80565b721b1bd85b94185c985b5cc8191a5cd8589b1959606a1b815260200192915050565b60006146e7600c83614f80565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b600061470f600d83614f80565b6c696e76616c696420737461746560981b815260200192915050565b6000614738602a83614f80565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b6000614784602183614f80565b7f6c6f616e446174614279746573207265717569726564207769746820657468658152603960f91b602082015260400192915050565b60006147c7601683614f80565b751cddd85c081d1bdbc81b185c99d9481d1bc8199a5b1b60521b815260200192915050565b60006147f9601583614f80565b74696e697469616c4d617267696e20746f6f206c6f7760581b815260200192915050565b600061482a601f83614f80565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160e083019061486784826140b3565b50602082015161487a60208501826140b3565b50604082015161488d60408501826140b3565b5060608201516148a060608501826140b3565b5060808201516148b360808501826140dc565b5060a08201516148c660a08501826140dc565b5060c0820151612b6d60c08501826140dc565b60006148e582876140e5565b6020820191506148f582866140c2565b60148201915061490582856140c2565b60148201915061491582846140e5565b50602001949350505050565b600061169b82846140f6565b6020810161164c82846140b3565b6040810161494982856140b3565b61169b60208301846140b3565b6080810161496482876140b3565b61497160208301866140b3565b61497e60408301856140b3565b610b6260608301846140dc565b6060810161499982866140b3565b6149a660208301856140b3565b6118e160408301846140dc565b608081016149c182876140b3565b6149ce60208301866140b3565b61497e60408301856140dc565b60a081016149e982886140b3565b6149f660208301876140b3565b614a0360408301866140dc565b614a1060608301856140dc565b6110f060808301846140dc565b6101008101614a2c828b6140b3565b614a39602083018a6140b3565b614a4660408301896140dc565b614a5360608301886140dc565b614a6060808301876140dc565b614a6d60a08301866140dc565b614a7a60c08301856140dc565b614a8760e08301846140dc565b9998505050505050505050565b6101208101614aa3828c6140b3565b614ab0602083018b6140b3565b614abd604083018a6140dc565b614aca60608301896140dc565b614ad760808301886140dc565b614ae460a08301876140dc565b614af160c08301866140dc565b614afe60e08301856140dc565b614b0c6101008301846140dc565b9a9950505050505050505050565b60408101614b2882856140b3565b61169b60208301846140dc565b60608101614b4382866140b3565b6149a660208301856140dc565b6020810161164c82846140d3565b6101008101614b6d828b6140dc565b614b7a602083018a6140d3565b614b8760408301896140b3565b614b9460608301886140b3565b614a6060808301876140b3565b6101808101614bb0828f6140dc565b614bbd602083018e6140dc565b614bca604083018d6140dc565b614bd7606083018c6140d3565b614be4608083018b6140dc565b614bf160a083018a6140dc565b614bfe60c08301896140dc565b614c0b60e08301886140dc565b614c196101008301876140dc565b614c276101208301866140dc565b614c356101408301856140b3565b614c436101608301846140b3565b9d9c50505050505050505050505050565b6020810161164c8284614125565b6020808252810161169b818461412e565b6020808252810161164c81614166565b6020808252810161164c81614195565b6020808252810161164c816141b7565b6020808252810161164c816141f0565b6020808252810161164c8161421c565b6020808252810161164c81614264565b6020808252810161164c8161429d565b6020808252810161164c816142ca565b6020808252810161164c81614303565b6020808252810161164c8161432d565b6020808252810161164c8161435e565b6020808252810161164c81614397565b6020808252810161164c816143c6565b6020808252810161164c816143f1565b6020808252810161164c8161442a565b6020808252810161164c81614451565b6020808252810161164c8161447f565b6020808252810161164c816144a9565b6020808252810161164c816144d3565b6020808252810161164c816144fe565b6020808252810161164c81614528565b6020808252810161164c8161456b565b6020808252810161164c81614593565b6020808252810161164c816145cc565b6020808252810161164c816145fa565b6020808252810161164c8161462b565b6020808252810161164c8161465b565b6020808252810161164c816146ab565b6020808252810161164c816146da565b6020808252810161164c81614702565b6020808252810161164c8161472b565b6020808252810161164c81614777565b6020808252810161164c816147ba565b6020808252810161164c816147ec565b6020808252810161164c8161481d565b60e0810161164c8284614856565b6020810161164c82846140dc565b60408101614b2882856140dc565b60608101614b4382866140dc565b60a08101614ee982886140dc565b6149f660208301876140dc565b60c08101614f0482896140dc565b614f1160208301886140dc565b614f1e60408301876140dc565b614f2b60608301866140dc565b614f3860808301856140dc565b614f4560a08301846140dc565b979650505050505050565b60405181810167ffffffffffffffff81118282101715614f6f57600080fd5b604052919050565b5190565b919050565b90815260200190565b600061164c82614fa9565b151590565b90565b6001600160e01b03191690565b6001600160a01b031690565b600061164c82614f89565b60005b83811015614fdb578181015183820152602001614fc3565b83811115612b6d5750506000910152565b600061164c82600061164c82615007565b601f01601f191690565b60601b90565b61501681614f89565b81146114b657600080fd5b61501681614f94565b61501681614f99565b61501681614f9c56fea365627a7a723158209a8d12e965f3506c2f6525444e34694cec46e043cf5ecbd237112664c19b0aa96c6578706572696d656e74616cf564736f6c63430005110040", - "deployedBytecode": "0x6080604052600436106103815760003560e01c80638f32d59b116101d1578063cd5d808d11610102578063e8f62764116100a0578063f589a3e71161006f578063f589a3e714610a05578063f6ddc8b314610a1a578063f706b1f214610a2f578063f851a44014610a4457610381565b8063e8f62764146109a6578063edab119f146109bb578063f0e085f5146109d0578063f2fde38b146109e557610381565b8063d485045e116100dc578063d485045e14610925578063d67f707714610945578063d84ca25414610965578063e762319f1461098657610381565b8063cd5d808d146108db578063d288208c146108fb578063d473c2da1461091057610381565b8063b7e152411161016f578063bdee453c11610149578063bdee453c1461082f578063c4a908151461084f578063c4d66de814610887578063cb6eacd1146108a757610381565b8063b7e15241146107e5578063b9cffa3e14610805578063ba4861e91461081a57610381565b8063acc04348116101ab578063acc0434814610779578063ae0a85301461078e578063afe84009146107a3578063b30643d9146107c557610381565b80638f32d59b1461072f57806392d894f814610744578063959083d31461076457610381565b80634203e395116102b65780636e663730116102545780637a8faeb8116102235780637a8faeb8146106d05780638456cb59146106e55780638da5cb5b146106fa5780638dc48ba51461070f57610381565b80636e663730146106715780637420ca3e14610691578063742e6798146106a657806378d849ed146106bb57610381565b8063569fc1fb11610290578063569fc1fb146105dc578063574442cc1461060b57806362fff3f61461062057806368c4ac261461065157610381565b80634203e395146105925780634699f846146105b25780634f28cac2146105c757610381565b80632a324027116103235780633432423c116102fd5780633432423c146105125780633452d2d4146105325780633fca506e146105525780634115a2b61461057257610381565b80632a324027146104c65780632f470764146104db57806333d8991f146104f057610381565b80631b7bde741161035f5780631b7bde741461042c578063218b39c61461045957806324cc57491461047957806325decac0146104a657610381565b8063065d810f146103af5780630676c1b7146103ea57806317548b791461040c575b34801561038d57600080fd5b5060405162461bcd60e51b81526004016103a690614e03565b60405180910390fd5b3480156103bb57600080fd5b506103cf6103ca366004613e77565b610a59565b6040516103e196959493929190614ef6565b60405180910390f35b3480156103f657600080fd5b506103ff610a99565b6040516103e1919061492d565b34801561041857600080fd5b506103ff61042736600461400a565b610aa8565b34801561043857600080fd5b5061044c610447366004613d41565b610ac3565b6040516103e19190614eb1565b34801561046557600080fd5b506103ff610474366004613d23565b610ae0565b34801561048557600080fd5b50610499610494366004613d23565b610afb565b6040516103e19190614b50565b3480156104b257600080fd5b5061044c6104c1366004613d7b565b610b10565b3480156104d257600080fd5b5061044c610b6b565b3480156104e757600080fd5b5061044c610b71565b3480156104fc57600080fd5b5061051061050b366004613f02565b610b77565b005b34801561051e57600080fd5b506103cf61052d366004613e77565b610be4565b34801561053e57600080fd5b5061044c61054d366004613d23565b610c24565b34801561055e57600080fd5b5061044c61056d366004613d23565b610c36565b34801561057e57600080fd5b5061049961058d366004613ee3565b610c48565b34801561059e57600080fd5b5061044c6105ad366004613d23565b610c68565b3480156105be57600080fd5b5061044c610c7a565b3480156105d357600080fd5b5061044c610c80565b3480156105e857600080fd5b506105fc6105f7366004613ec5565b610c86565b6040516103e193929190614ecd565b34801561061757600080fd5b5061044c610ca7565b34801561062c57600080fd5b5061064061063b366004613d41565b610cad565b6040516103e1959493929190614edb565b34801561065d57600080fd5b5061049961066c366004613d23565b610ce7565b34801561067d57600080fd5b506103ff61068c366004613d23565b610cfc565b34801561069d57600080fd5b506103ff610d17565b3480156106b257600080fd5b5061044c610d26565b3480156106c757600080fd5b506103ff610d2c565b3480156106dc57600080fd5b5061044c610d3b565b3480156106f157600080fd5b50610499610d41565b34801561070657600080fd5b506103ff610d4a565b34801561071b57600080fd5b506103ff61072a366004613d23565b610d59565b34801561073b57600080fd5b50610499610d74565b34801561075057600080fd5b5061044c61075f366004613d23565b610d9a565b34801561077057600080fd5b5061044c610dac565b34801561078557600080fd5b5061044c610db2565b34801561079a57600080fd5b5061044c610db8565b3480156107af57600080fd5b506107b8610dbe565b6040516103e19190614c54565b3480156107d157600080fd5b5061044c6107e0366004613d23565b610dcd565b3480156107f157600080fd5b5061044c610800366004613d23565b610ddf565b34801561081157600080fd5b506103ff610df1565b34801561082657600080fd5b506103ff610e00565b34801561083b57600080fd5b5061044c61084a366004613d23565b610e0f565b34801561085b57600080fd5b5061086f61086a366004613ec5565b610e21565b6040516103e19c9b9a99989796959493929190614ba1565b34801561089357600080fd5b506105106108a2366004613d23565b610e93565b3480156108b357600080fd5b506108c76108c2366004613ec5565b610f96565b6040516103e1989796959493929190614b5e565b3480156108e757600080fd5b5061044c6108f6366004613d41565b610fe8565b34801561090757600080fd5b506103ff611005565b34801561091c57600080fd5b5061044c611014565b34801561093157600080fd5b5061044c610940366004613d23565b61101a565b34801561095157600080fd5b5061044c610960366004613df0565b61102c565b610978610973366004613f4f565b6110fa565b6040516103e1929190614ebf565b34801561099257600080fd5b5061044c6109a1366004613d7b565b6112fa565b3480156109b257600080fd5b506103ff61146e565b3480156109c757600080fd5b5061044c61147d565b3480156109dc57600080fd5b5061044c611483565b3480156109f157600080fd5b50610510610a00366004613d23565b611489565b348015610a1157600080fd5b5061044c6114b9565b348015610a2657600080fd5b5061044c6114bf565b348015610a3b57600080fd5b506103ff6114c5565b348015610a5057600080fd5b506103ff6114d4565b6009602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b6031546001600160a01b031681565b6005602052600090815260409020546001600160a01b031681565b603b60209081526000928352604080842090915290825290205481565b6023602052600090815260409020546001600160a01b031681565b60326020526000908152604090205460ff1681565b60008215610b6257610b2586868686866114e3565b9050600082610b3c57610b378261161c565b610b45565b610b4582611652565b90508015610b6057610b5d828263ffffffff61167616565b91505b505b95945050505050565b60185481565b601f5481565b603d5460ff1615610b9a5760405162461bcd60e51b81526004016103a690614c83565b6000838152600660205260409020600a01546001600160a01b03163314610bd35760405162461bcd60e51b81526004016103a690614dc3565b610bdf833384846116a2565b505050565b6008602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b601a6020526000908152604090205481565b602a6020526000908152604090205481565b600a60209081526000928352604080842090915290825290205460ff1681565b60166020526000908152604090205481565b60155481565b60295481565b600c6020526000908152604090208054600182015460029092015490919083565b602b5481565b600b602090815260009283526040808420909152908252902080546001820154600283015460038401546004909401549293919290919085565b60266020526000908152604090205460ff1681565b6033602052600090815260409020546001600160a01b031681565b6003546001600160a01b031681565b60355481565b6002546001600160a01b031681565b601e5481565b603d5460ff1681565b6001546001600160a01b031690565b6022602052600090815260409020546001600160a01b031681565b6001546000906001600160a01b0316610d8b611717565b6001600160a01b031614905090565b60176020526000908152604090205481565b602c5481565b602f5481565b60205481565b602d546001600160a01b031681565b601d6020526000908152604090205481565b601c6020526000908152604090205481565b6037546001600160a01b031681565b6004546001600160a01b031681565b60366020526000908152604090205481565b600660208190526000918252604090912080546001820154600283015460038401546004850154600586015496860154600787015460088801546009890154600a8a0154600b909a0154989a9799969860ff909616979496949593949293919290916001600160a01b0391821691168c565b610e9b610d74565b610eb75760405162461bcd60e51b81526004016103a690614dc3565b633613289560e21b600081905260056020527fd3a886345208a8e3a0f774019653c4e69589e943ba1e46c7fa0ef875651e6e39546001600160a01b031690610eff908361171b565b610f106333d8991f60e01b8361171b565b610f2163d67f707760e01b8361171b565b610f3162977b2b60e61b8361171b565b610f4263e762319f60e01b8361171b565b6b4c6f616e4f70656e696e677360a01b826001600160a01b0316826001600160a01b03167f1420e3a2094d671bc2eb897941fa3d94ffa37f0cb6d530651946250a2151cb7f60405160405180910390a45050565b6007602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949560ff8516956101009095046001600160a01b03908116959481169493169288565b603c60209081526000928352604080842090915290825290205481565b6038546001600160a01b031681565b60275481565b60196020526000908152604090205481565b60006224ea008161105d6907baab4146b63dd00000611051868863ffffffff61179516565b9063ffffffff6117cf16565b9050600061107862015180611051858563ffffffff61179516565b9050600061108c898363ffffffff61181116565b905060006110998261161c565b905080156110b4576110b1828263ffffffff61181116565b91505b60006110c18d8d85611853565b9050806110d757600096505050505050506110f0565b6110e78a8263ffffffff61167616565b96505050505050505b9695505050505050565b60008060016000541461111f5760405162461bcd60e51b81526004016103a690614e33565b6002600055603d5460ff16156111475760405162461bcd60e51b81526004016103a690614c83565b34158061115357508215155b61116f5760405162461bcd60e51b81526004016103a690614e63565b336000908152602260205260409020546001600160a01b03166111a45760405162461bcd60e51b81526004016103a690614da3565b6111ac613a43565b5060008a815260076020908152604091829020825161010080820185528254808352600184015460ff811615159584019590955293046001600160a01b039081169482019490945260028201548416606082015260038201549093166080840152600481015460a0840152600581015460c08401526006015460e08301526112465760405162461bcd60e51b81526004016103a690614df3565b60006112618260600151836080015189602001358c8e6114e3565b9050806112805760405162461bcd60e51b81526004016103a690614d93565b6112e2828c8c848d611297368f90038f018f614028565b6112a6368f90038f018f614046565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118e992505050565b6001600055909d909c509a5050505050505050505050565b60008215610b62578115611324576113218368056bc75e2d6310000063ffffffff61167616565b92505b8360008361133a576113358261161c565b611343565b61134382611652565b9050801561135e5761135b828263ffffffff61181116565b91505b866001600160a01b0316886001600160a01b0316141561139c57611395856110518468056bc75e2d6310000063ffffffff61179516565b9250611463565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c906113d3908c908e9060040161493b565b604080518083038186803b1580156113ea57600080fd5b505afa1580156113fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114229190810190614083565b91509150806000146114605761145d816110518981866114518a68056bc75e2d6310000063ffffffff61179516565b9063ffffffff61179516565b94505b50505b505095945050505050565b6014546001600160a01b031681565b601b5481565b60285481565b611491610d74565b6114ad5760405162461bcd60e51b81526004016103a690614dc3565b6114b681611c22565b50565b60395481565b60215481565b602e546001600160a01b031681565b6030546001600160a01b031681565b6000846001600160a01b0316866001600160a01b031614156115235761151c68056bc75e2d63100000611051868663ffffffff61179516565b90506115de565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c9061155a908a908c9060040161493b565b604080518083038186803b15801561157157600080fd5b505afa158015611585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115a99190810190614083565b91509150816000146115db576115d868056bc75e2d631000006110518761145186838c8863ffffffff61179516565b92505b50505b8180156115ea57508015155b15610b62576110f081611610856110518368056bc75e2d6310000063ffffffff61179516565b9063ffffffff61167616565b600061164c68056bc75e2d631000006116406018548561179590919063ffffffff16565b9063ffffffff611ca416565b92915050565b600061164c68056bc75e2d63100000611640601b548561179590919063ffffffff16565b60008282018381101561169b5760405162461bcd60e51b81526004016103a690614ce3565b9392505050565b6000848152600a602090815260408083206001600160a01b038681168086529190935292819020805460ff1916851515179055519085169086907f0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c9843390611709908690614b50565b60405180910390a450505050565b3390565b6001600160e01b03198216600090815260056020526040902080546001600160a01b0319166001600160a01b0383169081179091551561177657611770600d6001600160e01b0319841663ffffffff611ce616565b50611791565b610bdf600d6001600160e01b0319841663ffffffff611d2e16565b5050565b6000826117a45750600061164c565b828202828482816117b157fe5b041461169b5760405162461bcd60e51b81526004016103a690614db3565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611def565b600061169b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611e26565b604051636dcd64e560e01b815260009073__$6b3065420287e4be5d93089ad806c078e3$__90636dcd64e5906118919087908790879060040161498b565b60206040518083038186803b1580156118a957600080fd5b505af41580156118bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118e19190810190614065565b949350505050565b60008089606001516001600160a01b03168a608001516001600160a01b031614156119265760405162461bcd60e51b81526004016103a690614d03565b8960a0015186101561194a5760405162461bcd60e51b81526004016103a690614e83565b60e08a015115158061195f5750604084015115155b61197b5760405162461bcd60e51b81526004016103a690614ca3565b6000600660006119928d8d8b8b8b60200151611e52565b8152602001908152602001600020905060006119bd8c83886000015189602001518a60400151612244565b60608701519091506119d5908263ffffffff61181116565b60608701528915611a5d57606086015115611a025760405162461bcd60e51b81526004016103a690614d63565b6000611a118760800151611652565b60808e015160608f0151919250908215611a5557611a3a8a602001518660000154848487612460565b6080890151611a4f908463ffffffff61181116565b60808a01525b505050611acf565b6000611a828c8e606001518f608001518b602001518b6060015160008060008e6124ff565b60c08a0152506080880151909150611aa0908263ffffffff61167616565b608088015260a087015160c08801511015611acd5760405162461bcd60e51b81526004016103a690614cc3565b505b60408051610180810182528354815260018401546020820152600284015491810191909152600383015460ff16151560608201526004830154608080830191909152600584015460a0830152600684015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b85015416610160830152870151611b78918e918b908d61265d565b611b945760405162461bcd60e51b81526004016103a690614dd3565b60808601516005830154611bad9163ffffffff61167616565b60058301558915611bd7576007820154611bcd904263ffffffff61181116565b60e0870152611bf8565b611bf16f4b3b4ca85a86c47a098a224000000000896117cf565b6101008701525b611c058c8389898e612763565b856020015186608001519350935050509850989650505050505050565b6001600160a01b038116611c485760405162461bcd60e51b81526004016103a690614cb3565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612a36565b6000611cf28383612a80565b611d26575060018083018054808301808355600092835260208084209092018590558483529085905260409091205561164c565b50600061164c565b6000611d3a8383612a80565b15611d265760008281526020849052604090205460018401546000199182019101808214611db2576000856001018281548110611d7357fe5b9060005260206000200154905080866001018481548110611d9057fe5b6000918252602080832090910192909255918252869052604090206001830190555b60008481526020869052604081205560018501805480611dce57fe5b6001900381819060005260206000200160009055905560019250505061164c565b60008183611e105760405162461bcd60e51b81526004016103a69190614c62565b506000838581611e1c57fe5b0495945050505050565b60008184841115611e4a5760405162461bcd60e51b81526004016103a69190614c62565b505050900390565b60008560200151611e755760405162461bcd60e51b81526004016103a690614e23565b825160208401516060850151611e89613a87565b88611fe0576001600160a01b0383166000908152602a60209081526040918290208054600101908190558c519251611ec89392889288929091016148d9565b60408051601f1981840301815291815281516020928301206000818152600690935291205490995015611f0d5760405162461bcd60e51b81526004016103a690614d53565b5060408051610180810182528981528a5160208201526000918101829052600160608201526080810187905260a081018290524260c082015260e0810182905261010081018990526101208101919091526001600160a01b038084166101408301528416610160820152611f88600f8a63ffffffff611ce616565b506001600160a01b0384166000908152601160205260409020611fb1908a63ffffffff611ce616565b506001600160a01b0383166000908152601260205260409020611fda908a63ffffffff611ce616565b50612161565b5060008881526006602081815260409283902083516101808101855281548152600182015492810192909252600281015493820193909352600383015460ff161580156060830181905260048501546080840152600585015460a08401529284015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b909401549093166101608201529161209a57508060e0015142105b6120b65760405162461bcd60e51b81526004016103a690614d73565b826001600160a01b03168161014001516001600160a01b0316146120ec5760405162461bcd60e51b81526004016103a690614cd3565b836001600160a01b03168161016001516001600160a01b0316146121225760405162461bcd60e51b81526004016103a690614d33565b89516020820151146121465760405162461bcd60e51b81526004016103a690614c73565b608081015161215b908763ffffffff61167616565b60808201525b6001600160a01b0382161561217d5761217d89848460016116a2565b60008981526006602081815260409283902084518155908401516001820155918301516002830155606083015160038301805460ff19169115159190911790556080830151600483015560a0830151600583015560c08301519082015560e0820151600782015561010082015160088201556101208201516009820155610140820151600a820180546001600160a01b03199081166001600160a01b039384161790915561016090930151600b909201805490931691161790555095979650505050505050565b600b8401546060860151600091612266916001600160a01b0390911690612a95565b84546000818152600c60209081526040808320600b808b01546001600160a01b03908116865290845282852060608d0180518316875294529190932060e08b0151925160808c0151600a8c0154959692956122c79488949392911642612b73565b6000811580156122da5750600789015415155b1561230857612305620151806110518660000154611451428e6007015461181190919063ffffffff16565b90505b60006123286907baab4146b63dd000006110518a8c63ffffffff61179516565b855490915061233d908263ffffffff61167616565b85556001840154612354908263ffffffff61167616565b6001850155826123c357845461238190429061161090611051620151806114518d8963ffffffff61167616565b60078b01819055612398904263ffffffff61181116565b9250610e1083116123bb5760405162461bcd60e51b81526004016103a690614cf3565b869550612407565b60078a01546123e2576123dc428463ffffffff61167616565b60078b01555b6124046201518061105183611451428f6007015461181190919063ffffffff16565b95505b600185015461241c908763ffffffff61167616565b60018601558354612433908963ffffffff61167616565b8455600284015461244a908763ffffffff61167616565b8460020181905550505050505095945050505050565b80156124f8576001600160a01b0383166000908152601c602052604090205461248f908263ffffffff61167616565b6001600160a01b038085166000818152601c6020526040908190209390935591518692918816907ffb6c38ae4fdd498b3a5003f02ca4ca5340dfedb36b1b100c679eb60633b2c0a7906124e3908690614eb1565b60405180910390a46124f88585858585612bc1565b5050505050565b6040805160a0810182526001600160a01b03808b16825289811660208084019190915230838501819052606080850191909152918a1660808401528351918201845288825281018790529182018590526000918291829161256491908e888886613027565b90935091506125738b8361324c565b600254602754604051631e2c62d360e01b81526001600160a01b0390921691631e2c62d3916125ac918f918f9188918a916004016149db565b60206040518083038186803b1580156125c457600080fd5b505afa1580156125d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506125fc9190810190614065565b9050896001600160a01b03168b6001600160a01b03168d7fb4eb3c9b62efcce7021cba5fd9cd0c44df91c2272806ccc5e57df7c912e8d7168c868860405161264693929190614b35565b60405180910390a499509950999650505050505050565b600061268568056bc75e2d631000006110518468055005f0c61448000063ffffffff61179516565b9150818310156127575760a08501511561274f5760025460608701516080808901519088015160a089015160405163f80b25fb60e01b81526000956001600160a01b03169463f80b25fb946126e294919390928c906004016149db565b60206040518083038186803b1580156126fa57600080fd5b505afa15801561270e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127329190810190614065565b905082612745858363ffffffff61167616565b1015915050610b62565b506000610b62565b50600195945050505050565b6002546060860151608087015160048088015460058901546040516317f8680960e11b815260009687966001600160a01b0390911695632ff0d012956127ad9592949193016149b3565b604080518083038186803b1580156127c457600080fd5b505afa1580156127d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127fc9190810190614083565b915091508660c0015182116128235760405162461bcd60e51b81526004016103a690614de3565b4286600601541415612989576002546060880151608089015160405163524efd4b60e01b81526000936001600160a01b03169263524efd4b926128689260040161493b565b60206040518083038186803b15801561288057600080fd5b505afa158015612894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128b89190810190614065565b60025460808a015160608b015160405163524efd4b60e01b81529394506000936001600160a01b039093169263524efd4b926128f892909160040161493b565b60206040518083038186803b15801561291057600080fd5b505afa158015612924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129489190810190614065565b9050600061295c838363ffffffff61179516565b90508561297e5760c087015161297990829063ffffffff6117cf16565b612980565b835b60098a01555050505b60408051610180810182528754815260018801546020820152600288015491810191909152600387015460ff161515606082015260048701546080820152600587015460a0820152600687015460c0820152600787015460e082015260088701546101008201526009870154610120820152600a8701546001600160a01b03908116610140830152600b88015416610160820152612a2d908890878785878961331a565b50505050505050565b60008183612a575760405162461bcd60e51b81526004016103a69190614c62565b5083612a655750600061169b565b6000836001860381612a7357fe5b0460010195945050505050565b60009081526020919091526040902054151590565b6001600160a01b038083166000908152600b602090815260408083209385168352929052908120600181015490919015801590612ad55750600482015415155b15612b6657612b0062015180611051846001015461145186600401544261181190919063ffffffff16565b4260048401556002830154909150811115612b1c575060028101545b8015612b61576003820154612b37908263ffffffff61167616565b60038301556002820154612b51908263ffffffff61181116565b6002830155612b61848483613451565b612b6d565b4260048301555b50505050565b6000612ba96a07259756a8d619980000006110516015546114518b600001546114518d600201548961181190919063ffffffff16565b6002880183905590508015612a2d57612a2d83878787855b602f546002546001600160a01b038581166000908152603c602090815260408083208885168452909152812054909392919091169015612c24576001600160a01b038087166000908152603c602090815260408083209389168352929052205491505b6037546000906060906001600160a01b038085169163d138f9a160e01b918b9116612c6268056bc75e2d631000006110518c8b63ffffffff61179516565b604051602401612c749392919061498b565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612cb29190614921565b600060405180830381855afa9150503d8060008114612ced576040519150601f19603f3d011682016040523d82523d6000602084013e612cf2565b606091505b50915091506001821415612d0857602081015194505b6000306001600160a01b031663c22552f76040518163ffffffff1660e01b815260040160206040518083038186803b158015612d4357600080fd5b505afa158015612d57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d7b9190810190614065565b90508515801590612d8c5750858110155b15612fb45760375460385460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392612dc7929116908a90600401614b1a565b602060405180830381600087803b158015612de157600080fd5b505af1158015612df5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612e199190810190613ea7565b50603854603f546040516000926001600160a01b031691612e40918f918b91602401614b35565b60408051601f198184030181529181526020820180516001600160e01b0316630efe6a8b60e01b17905251612e759190614921565b6000604051808303816000865af19150503d8060008114612eb2576040519150601f19603f3d011682016040523d82523d6000602084013e612eb7565b606091505b505090508015612f4657601f54612ed4908863ffffffff61167616565b601f819055508a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167ff41c644671512f1cda76abfe6038e3d7d526c1377a5a8c692f81703901db2150898b603f54604051612f3993929190614ecd565b60405180910390a4612fae565b8a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e710812898b603f54604051612fa593929190614ecd565b60405180910390a45b5061301a565b8515801590612fc257508581105b1561301a57603754603f546040518c926001600160a01b0390811692908f16917f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e71081291613011918b918d91614ecd565b60405180910390a45b5050505050505050505050565b8451600090819015158061303e5750602087015115155b61305a5760405162461bcd60e51b81526004016103a690614e13565b602087015161306b57865160208801525b6020870151875111156130905760405162461bcd60e51b81526004016103a690614d43565b60008060008761314d5760408a015161310c5785156130c1576130ba8a60005b60200201516134f6565b90506130d5565b6130d28a60005b602002015161161c565b90505b80156131075760808b01518b516130f891908b908e60015b60200201518561351a565b89516131049082611811565b8a525b61314d565b85156131245761311d8a60026130b0565b9050613132565b61312f8a60026130c8565b90505b801561314d5760408a01516131479082611676565b60408b01525b86511561316c5760405162461bcd60e51b81526004016103a690614e43565b6131768b8b61366a565b60408c015191945092506131c257895182146131a45760405162461bcd60e51b81526004016103a690614e73565b80156131bd576131ba828263ffffffff61167616565b91505b61323c565b60208a01518211156131e65760405162461bcd60e51b81526004016103a690614d23565b60408a015183101561320a5760405162461bcd60e51b81526004016103a690614c93565b801561323c5760808b015160208c015161322991908b908e60006130ed565b613239838263ffffffff61181116565b92505b5090999098509650505050505050565b6029548015610bdf57602d546000906001600160a01b03858116911614156132755750816132fa565b600254604051635967aa7560e11b81526001600160a01b039091169063b2cf54ea906132a79087908790600401614b1a565b60206040518083038186803b1580156132bf57600080fd5b505afa1580156132d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506132f79190810190614065565b90505b81811115612b6d5760405162461bcd60e51b81526004016103a690614d83565b80156133a357856000015185600001516001600160a01b031686602001516001600160a01b03167f7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f908a606001518b6080015189602001518a608001518b600001518c60e001518c8c604051613396989796959493929190614a1d565b60405180910390a4612a2d565b6133bd6f4b3b4ca85a86c47a098a224000000000836117cf565b9150856000015185600001516001600160a01b031686602001516001600160a01b03167ff640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c8a608001518b6060015189608001518a602001518b600001518e60e001518d60c001518e61010001518d60405161344099989796959493929190614a94565b60405180910390a450505050505050565b600061347568056bc75e2d631000006110516015548561179590919063ffffffff16565b9050613482848483613754565b61349c8385613497858563ffffffff61181116565b6137e2565b6001600160a01b038085169084167f220e66e3e759e1382aa86cd8af5abca05ebf3ad564f223ae62d977678337272a6134db858563ffffffff61181116565b6040516134e89190614eb1565b60405180910390a350505050565b600061164c68056bc75e2d63100000611640603e548561179590919063ffffffff16565b808015613662576001600160a01b0386811660009081526033602052604090205416156135d0576001600160a01b038087166000908152603360205260409020546135689116878684613845565b50506135cd61358f68056bc75e2d631000006110516039548561179590919063ffffffff16565b6135c16135b468056bc75e2d631000006110516020548761179590919063ffffffff16565b849063ffffffff61181116565b9063ffffffff61181116565b90505b6001600160a01b0384166000908152601960205260409020546135f9908263ffffffff61167616565b6001600160a01b03808616600081815260196020526040908190209390935591518792918916907fb23479169712c443e6b00fb0cec3506a5f5926f541df4243d313e11c8c5c71ed9061364d908690614eb1565b60405180910390a46136628686868686612bc1565b505050505050565b600080613675613aeb565b84516001600160a01b039081168252602080870151821683820152604080880151831681850152606080890151909316928401929092528551608084015285015160a08301528481015160c0830152516335aaa79d60e01b815273__$6b3065420287e4be5d93089ad806c078e3$__906335aaa79d906136f9908490600401614ea3565b604080518083038186803b15801561371057600080fd5b505af4158015613724573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506137489190810190614083565b90969095509350505050565b8015610bdf576001600160a01b038216600090815260166020526040902054613783908263ffffffff61167616565b6001600160a01b0380841660008181526016602052604090819020939093559151908516907f40a75ae5f7a5336e75f7c7977e12c4b46a9ac0f30de01a2d5b6c1a4f4af63587906137d5908590614eb1565b60405180910390a3505050565b8015610bdf576138026001600160a01b038416838363ffffffff6138d116565b816001600160a01b0316836001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1836040516137d59190614eb1565b6040516306a688ff60e11b815260009081903090630d4d11fe90613873908990899089908990600401614956565b6040805180830381600087803b15801561388c57600080fd5b505af11580156138a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506138c49190810190614083565b9097909650945050505050565b604051610bdf90849063a9059cbb60e01b906138f39086908690602401614b1a565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613937826001600160a01b0316613a0a565b6139535760405162461bcd60e51b81526004016103a690614e93565b60006060836001600160a01b03168360405161396f9190614921565b6000604051808303816000865af19150503d80600081146139ac576040519150601f19603f3d011682016040523d82523d6000602084013e6139b1565b606091505b5091509150816139d35760405162461bcd60e51b81526004016103a690614d13565b805115612b6d57808060200190516139ee9190810190613ea7565b612b6d5760405162461bcd60e51b81526004016103a690614e53565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906118e1575050151592915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b803561164c8161500d565b803561164c81615021565b805161164c81615021565b803561164c8161502a565b803561164c81615033565b60008083601f840112613b7057600080fd5b50813567ffffffffffffffff811115613b8857600080fd5b602083019150836001820283011115613ba057600080fd5b9250929050565b600060808284031215613bb957600080fd5b50919050565b600060808284031215613bd157600080fd5b613bdb6080614f50565b90506000613be98484613b27565b8252506020613bfa84848301613b27565b6020830152506040613c0e84828501613b27565b6040830152506060613c2284828501613b27565b60608301525092915050565b60006101208284031215613bb957600080fd5b60006101208284031215613c5457600080fd5b613c5f610120614f50565b90506000613c6d8484613b48565b8252506020613c7e84848301613b48565b6020830152506040613c9284828501613b48565b6040830152506060613ca684828501613b48565b6060830152506080613cba84828501613b48565b60808301525060a0613cce84828501613b48565b60a08301525060c0613ce284828501613b48565b60c08301525060e0613cf684828501613b48565b60e083015250610100613d0b84828501613b48565b6101008301525092915050565b805161164c8161502a565b600060208284031215613d3557600080fd5b60006118e18484613b27565b60008060408385031215613d5457600080fd5b6000613d608585613b27565b9250506020613d7185828601613b27565b9150509250929050565b600080600080600060a08688031215613d9357600080fd5b6000613d9f8888613b27565b9550506020613db088828901613b27565b9450506040613dc188828901613b48565b9350506060613dd288828901613b48565b9250506080613de388828901613b32565b9150509295509295909350565b60008060008060008060c08789031215613e0957600080fd5b6000613e158989613b27565b9650506020613e2689828a01613b27565b9550506040613e3789828a01613b48565b9450506060613e4889828a01613b48565b9350506080613e5989828a01613b48565b92505060a0613e6a89828a01613b48565b9150509295509295509295565b60008060408385031215613e8a57600080fd5b6000613e968585613b27565b9250506020613d7185828601613b48565b600060208284031215613eb957600080fd5b60006118e18484613b3d565b600060208284031215613ed757600080fd5b60006118e18484613b48565b60008060408385031215613ef657600080fd5b6000613d608585613b48565b600080600060608486031215613f1757600080fd5b6000613f238686613b48565b9350506020613f3486828701613b27565b9250506040613f4586828701613b32565b9150509250925092565b600080600080600080600080610240898b031215613f6c57600080fd5b6000613f788b8b613b48565b9850506020613f898b828c01613b48565b9750506040613f9a8b828c01613b32565b9650506060613fab8b828c01613b48565b9550506080613fbc8b828c01613ba7565b945050610100613fce8b828c01613c2e565b93505061022089013567ffffffffffffffff811115613fec57600080fd5b613ff88b828c01613b5e565b92509250509295985092959890939650565b60006020828403121561401c57600080fd5b60006118e18484613b53565b60006080828403121561403a57600080fd5b60006118e18484613bbf565b6000610120828403121561405957600080fd5b60006118e18484613c41565b60006020828403121561407757600080fd5b60006118e18484613d18565b6000806040838503121561409657600080fd5b60006140a28585613d18565b9250506020613d7185828601613d18565b6140bc81614f89565b82525050565b6140bc6140ce82614f89565b614fec565b6140bc81614f94565b6140bc81614f99565b6140bc6140f182614f99565b614f99565b600061410182614f77565b61410b8185614f7b565b935061411b818560208601614fc0565b9290920192915050565b6140bc81614fb5565b600061413982614f77565b6141438185614f80565b9350614153818560208601614fc0565b61415c81614ffd565b9093019392505050565b6000614173601383614f80565b720d8dec2dca0c2e4c2dae640dad2e6dac2e8c6d606b1b815260200192915050565b60006141a2600683614f80565b6514185d5cd95960d21b815260200192915050565b60006141c4601b83614f80565b7f696e73756666696369656e742073776170206c69717569646974790000000000815260200192915050565b60006141fd601083614f80565b6f1a5b9d985b1a59081a5b9d195c995cdd60821b815260200192915050565b6000614229602683614f80565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000614271601d83614f80565b7f656e7472792070726963652061626f766520746865206d696e696d756d000000815260200192915050565b60006142aa601183614f80565b700c4dee4e4deeecae440dad2e6dac2e8c6d607b1b815260200192915050565b60006142d7601b83614f80565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000614310600e83614f80565b6d1b1bd85b881d1bdbc81cda1bdc9d60921b815260200192915050565b600061433a601583614f80565b740c6ded8d8c2e8cae4c2d85ed8dec2dc40dac2e8c6d605b1b815260200192915050565b600061436b602083614f80565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b60006143a4601383614f80565b72737761702066696c6c20746f6f206c6172676560681b815260200192915050565b60006143d3600f83614f80565b6e0d8cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b60006143fe601c83614f80565b7f736f75726365416d6f756e74206c6172676572207468616e206d617800000000815260200192915050565b6000614437600b83614f80565b6a6c6f616e2065786973747360a81b815260200192915050565b600061445e601283614f80565b7139bab938363ab9903637b0b7103a37b5b2b760711b815260200192915050565b600061448c600e83614f80565b6d1b1bd85b881a185cc8195b99195960921b815260200192915050565b60006144b6600e83614f80565b6d7377617020746f6f206c6172676560901b815260200192915050565b60006144e0600f83614f80565b6e0636f6c6c61746572616c206973203608c1b815260200192915050565b600061450b600e83614f80565b6d1b9bdd08185d5d1a1bdc9a5e995960921b815260200192915050565b6000614535602183614f80565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000614578600c83614f80565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006145a0601783614f80565b7f636f6c6c61746572616c20696e73756666696369656e74000000000000000000815260200192915050565b60006145d9601283614f80565b713ab73432b0b63a343c903837b9b4ba34b7b760711b815260200192915050565b6000614607601583614f80565b746c6f616e506172616d73206e6f742065786973747360581b815260200192915050565b6000614638601483614f80565b7319985b1b189858dac81b9bdd08185b1b1bddd95960621b815260200192915050565b6000614668602e83614f80565b7f6d696e206f72206d617820736f7572636520746f6b656e20616d6f756e74206e81526d1959591cc81d1bc81899481cd95d60921b602082015260400192915050565b60006146b8601383614f80565b721b1bd85b94185c985b5cc8191a5cd8589b1959606a1b815260200192915050565b60006146e7600c83614f80565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b600061470f600d83614f80565b6c696e76616c696420737461746560981b815260200192915050565b6000614738602a83614f80565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b6000614784602183614f80565b7f6c6f616e446174614279746573207265717569726564207769746820657468658152603960f91b602082015260400192915050565b60006147c7601683614f80565b751cddd85c081d1bdbc81b185c99d9481d1bc8199a5b1b60521b815260200192915050565b60006147f9601583614f80565b74696e697469616c4d617267696e20746f6f206c6f7760581b815260200192915050565b600061482a601f83614f80565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160e083019061486784826140b3565b50602082015161487a60208501826140b3565b50604082015161488d60408501826140b3565b5060608201516148a060608501826140b3565b5060808201516148b360808501826140dc565b5060a08201516148c660a08501826140dc565b5060c0820151612b6d60c08501826140dc565b60006148e582876140e5565b6020820191506148f582866140c2565b60148201915061490582856140c2565b60148201915061491582846140e5565b50602001949350505050565b600061169b82846140f6565b6020810161164c82846140b3565b6040810161494982856140b3565b61169b60208301846140b3565b6080810161496482876140b3565b61497160208301866140b3565b61497e60408301856140b3565b610b6260608301846140dc565b6060810161499982866140b3565b6149a660208301856140b3565b6118e160408301846140dc565b608081016149c182876140b3565b6149ce60208301866140b3565b61497e60408301856140dc565b60a081016149e982886140b3565b6149f660208301876140b3565b614a0360408301866140dc565b614a1060608301856140dc565b6110f060808301846140dc565b6101008101614a2c828b6140b3565b614a39602083018a6140b3565b614a4660408301896140dc565b614a5360608301886140dc565b614a6060808301876140dc565b614a6d60a08301866140dc565b614a7a60c08301856140dc565b614a8760e08301846140dc565b9998505050505050505050565b6101208101614aa3828c6140b3565b614ab0602083018b6140b3565b614abd604083018a6140dc565b614aca60608301896140dc565b614ad760808301886140dc565b614ae460a08301876140dc565b614af160c08301866140dc565b614afe60e08301856140dc565b614b0c6101008301846140dc565b9a9950505050505050505050565b60408101614b2882856140b3565b61169b60208301846140dc565b60608101614b4382866140b3565b6149a660208301856140dc565b6020810161164c82846140d3565b6101008101614b6d828b6140dc565b614b7a602083018a6140d3565b614b8760408301896140b3565b614b9460608301886140b3565b614a6060808301876140b3565b6101808101614bb0828f6140dc565b614bbd602083018e6140dc565b614bca604083018d6140dc565b614bd7606083018c6140d3565b614be4608083018b6140dc565b614bf160a083018a6140dc565b614bfe60c08301896140dc565b614c0b60e08301886140dc565b614c196101008301876140dc565b614c276101208301866140dc565b614c356101408301856140b3565b614c436101608301846140b3565b9d9c50505050505050505050505050565b6020810161164c8284614125565b6020808252810161169b818461412e565b6020808252810161164c81614166565b6020808252810161164c81614195565b6020808252810161164c816141b7565b6020808252810161164c816141f0565b6020808252810161164c8161421c565b6020808252810161164c81614264565b6020808252810161164c8161429d565b6020808252810161164c816142ca565b6020808252810161164c81614303565b6020808252810161164c8161432d565b6020808252810161164c8161435e565b6020808252810161164c81614397565b6020808252810161164c816143c6565b6020808252810161164c816143f1565b6020808252810161164c8161442a565b6020808252810161164c81614451565b6020808252810161164c8161447f565b6020808252810161164c816144a9565b6020808252810161164c816144d3565b6020808252810161164c816144fe565b6020808252810161164c81614528565b6020808252810161164c8161456b565b6020808252810161164c81614593565b6020808252810161164c816145cc565b6020808252810161164c816145fa565b6020808252810161164c8161462b565b6020808252810161164c8161465b565b6020808252810161164c816146ab565b6020808252810161164c816146da565b6020808252810161164c81614702565b6020808252810161164c8161472b565b6020808252810161164c81614777565b6020808252810161164c816147ba565b6020808252810161164c816147ec565b6020808252810161164c8161481d565b60e0810161164c8284614856565b6020810161164c82846140dc565b60408101614b2882856140dc565b60608101614b4382866140dc565b60a08101614ee982886140dc565b6149f660208301876140dc565b60c08101614f0482896140dc565b614f1160208301886140dc565b614f1e60408301876140dc565b614f2b60608301866140dc565b614f3860808301856140dc565b614f4560a08301846140dc565b979650505050505050565b60405181810167ffffffffffffffff81118282101715614f6f57600080fd5b604052919050565b5190565b919050565b90815260200190565b600061164c82614fa9565b151590565b90565b6001600160e01b03191690565b6001600160a01b031690565b600061164c82614f89565b60005b83811015614fdb578181015183820152602001614fc3565b83811115612b6d5750506000910152565b600061164c82600061164c82615007565b601f01601f191690565b60601b90565b61501681614f89565b81146114b657600080fd5b61501681614f94565b61501681614f99565b61501681614f9c56fea365627a7a723158209a8d12e965f3506c2f6525444e34694cec46e043cf5ecbd237112664c19b0aa96c6578706572696d656e74616cf564736f6c63430005110040", + "numDeployments": 2, + "solcInputHash": "444414c40f489390e118f5b65a5947cc", + "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCollateral\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestDuration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"collateralToLoanRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"currentMargin\",\"type\":\"uint256\"}],\"name\":\"Borrow\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"delegated\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isActive\",\"type\":\"bool\"}],\"name\":\"DelegatedManagerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeRebatePercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"basisPoint\",\"type\":\"uint256\"}],\"name\":\"EarnReward\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeRebatePercent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"basisPoint\",\"type\":\"uint256\"}],\"name\":\"EarnRewardFail\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sourceAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"}],\"name\":\"ExternalSwap\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"destToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"sourceAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"destAmount\",\"type\":\"uint256\"}],\"name\":\"LoanSwap\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayBorrowingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"interestToken\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"effectiveInterest\",\"type\":\"uint256\"}],\"name\":\"PayInterestTransfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayLendingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"payer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"PayTradingFee\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"prevModuleContractAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newModuleContractAddress\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"module\",\"type\":\"bytes32\"}],\"name\":\"ProtocolModuleContractReplaced\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"positionSize\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"borrowedAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"settlementDate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entryPrice\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"entryLeverage\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"currentLeverage\",\"type\":\"uint256\"}],\"name\":\"Trade\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"VaultDeposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"VaultWithdraw\",\"type\":\"event\"},{\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"fallback\"},{\"constant\":true,\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"affiliateFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliateRewardsHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"affiliateTradingTokenFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliatesReferrerBalances\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"affiliatesUserReferrer\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"loanParamsId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"initialMargin\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"manager\",\"type\":\"address\"}],\"internalType\":\"struct MarginTradeStructHelpers.SentAddresses\",\"name\":\"sentAddresses\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestInitialAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"loanTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minEntryPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"loanToCollateralSwapRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestDuration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"entryLeverage\",\"type\":\"uint256\"}],\"internalType\":\"struct MarginTradeStructHelpers.SentAmounts\",\"name\":\"sentValues\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"loanDataBytes\",\"type\":\"bytes\"}],\"name\":\"borrowOrTradeFromPool\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newCollateral\",\"type\":\"uint256\"}],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowerNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"borrowerOrders\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"lockedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"createdTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expirationTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"borrowingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"borrowingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"delegatedManagers\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feeRebatePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feesController\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"marginAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"}],\"name\":\"getBorrowAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"borrowAmount\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"loanTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateralTokenSent\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"}],\"name\":\"getEstimatedMarginExposure\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"newPrincipal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"marginAmount\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isTorqueLoan\",\"type\":\"bool\"}],\"name\":\"getRequiredCollateral\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"collateralAmountRequired\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lenderInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"principalTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"owedPerDay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"owedTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"paidTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"lenderOrders\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"lockedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"interestRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"createdTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expirationTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"lendingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lendingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"lendingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"liquidationIncentivePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loanInterest\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"owedPerDay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"depositTotal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedTimestamp\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loanParams\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"loanToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"collateralToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minInitialMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maintenanceMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxLoanTerm\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"loanPoolToUnderlying\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"loans\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"loanParamsId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"pendingTradesId\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"active\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"principal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"collateral\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"endTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startMargin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"startRate\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"borrower\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"lender\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"lockedSOVAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"\",\"type\":\"bytes4\"}],\"name\":\"logicTargets\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"maxDisagreement\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"maxSwapSize\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"minReferralsToPayout\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"pause\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"priceFeeds\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"protocolTokenPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rolloverBaseReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"rolloverFlexFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"loanId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"delegated\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"toggle\",\"type\":\"bool\"}],\"name\":\"setDelegatedManager\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sourceBuffer\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sovTokenAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"sovrynSwapContractRegistryAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"specialRebates\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"supportedTokens\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"swapsImpl\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"tradingFeePercent\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tradingFeeTokensHeld\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"tradingFeeTokensPaid\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"underlyingToLoanPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"userNotFirstTradeFlag\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"wrbtcToken\",\"outputs\":[{\"internalType\":\"contract IWrbtcERC20\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{\"borrowOrTradeFromPool(bytes32,bytes32,bool,uint256,(address,address,address,address),(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),bytes)\":{\"details\":\"Note: Only callable by loan pools (iTokens). Wrapper to _borrowOrTrade internal function.\",\"params\":{\"initialMargin\":\"The initial amount of margin.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanDataBytes\":\"The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\",\"loanId\":\"The ID of the loan. If 0, start a new loan.\",\"loanParamsId\":\"The ID of the loan parameters.\",\"sentAddresses\":\"The addresses to send tokens: lender, borrower, receiver and manager: lender: must match loan if loanId provided. borrower: must match loan if loanId provided. receiver: receiver of funds (address(0) assumes borrower address). manager: delegated manager of loan unless address(0).\",\"sentValues\":\"The values to send: interestRate: New loan interest rate. newPrincipal: New loan size (borrowAmount + any borrowed interest). interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length). loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans). collateralTokenSent: Total collateralToken deposit. minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\"},\"return\":\"newPrincipal The new loan size.newCollateral The new collateral amount.\"},\"getBorrowAmount(address,address,uint256,uint256,bool)\":{\"details\":\"Basically borrowAmount = collateral / marginAmount * Collateral is something that helps secure a loan. When you borrow money, you agree that your lender can take something and sell it to get their money back if you fail to repay the loan. That's the collateral.\",\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"collateralTokenAmount\":\"The amount of collateral.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanToken\":\"The loan token instance address.\",\"marginAmount\":\"The amount of margin of the trade.\"},\"return\":\"borrowAmount The borrow amount.\"},\"getEstimatedMarginExposure(address,address,uint256,uint256,uint256,uint256)\":{\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"collateralTokenSent\":\"The amount of collateral tokens sent.\",\"interestRate\":\"The interest rate. Percentage w/ 18 decimals.\",\"loanToken\":\"The loan token instance address.\",\"loanTokenSent\":\"The amount of loan tokens sent.\",\"newPrincipal\":\"The updated amount of principal (current debt).\"},\"return\":\"The margin exposure.\"},\"getRequiredCollateral(address,address,uint256,uint256,bool)\":{\"details\":\"Calls internal _getRequiredCollateral and add fees.\",\"params\":{\"collateralToken\":\"The collateral token instance address.\",\"isTorqueLoan\":\"Whether the loan is a Torque loan.\",\"loanToken\":\"The loan token instance address.\",\"marginAmount\":\"The amount of margin of the trade.\",\"newPrincipal\":\"The updated amount of principal (current debt).\"},\"return\":\"collateralAmountRequired The required collateral.\"},\"initialize(address)\":{\"params\":{\"target\":\"The address of the target contract.\"}},\"isOwner()\":{\"details\":\"Returns true if the caller is the current owner.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"setDelegatedManager(bytes32,address,bool)\":{\"details\":\"Wrapper for _setDelegatedManager internal function.\",\"params\":{\"delegated\":\"The address of the delegated manager.\",\"loanId\":\"The ID of the loan. If 0, start a new loan.\",\"toggle\":\"The flag true/false for the delegated manager.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"Loan Openings contract.\"},\"userdoc\":{\"methods\":{\"borrowOrTradeFromPool(bytes32,bytes32,bool,uint256,(address,address,address,address),(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),bytes)\":{\"notice\":\"Borrow or trade from pool.\"},\"getBorrowAmount(address,address,uint256,uint256,bool)\":{\"notice\":\"Get the borrow amount of a trade loan.\"},\"getEstimatedMarginExposure(address,address,uint256,uint256,uint256,uint256)\":{\"notice\":\"Get the estimated margin exposure. * Margin is the money borrowed from a broker to purchase an investment and is the difference between the total value of investment and the loan amount. Margin trading refers to the practice of using borrowed funds from a broker to trade a financial asset, which forms the collateral for the loan from the broker.\"},\"getRequiredCollateral(address,address,uint256,uint256,bool)\":{\"notice\":\"Get the required collateral.\"},\"initialize(address)\":{\"notice\":\"Set function selectors on target contract.\"},\"setDelegatedManager(bytes32,address,bool)\":{\"notice\":\"Set the delegated manager.\"}},\"notice\":\"This contract code comes from bZx. bZx is a protocol for tokenized margin trading and lending https://bzx.network similar to the dYdX protocol. * This contract contains functions to borrow and trade.\"}},\"settings\":{\"compilationTarget\":{\"contracts/modules/LoanOpenings.sol\":\"LoanOpenings\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":ds-test/=foundry/lib/forge-std/lib/ds-test/src/\",\":forge-std/=foundry/lib/forge-std/src/\"]},\"sources\":{\"contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nlibrary MarginTradeStructHelpers {\\n struct SentAddresses {\\n address lender;\\n address borrower;\\n address receiver;\\n address manager;\\n }\\n\\n struct SentAmounts {\\n uint256 interestRate;\\n uint256 newPrincipal;\\n uint256 interestInitialAmount;\\n uint256 loanTokenSent;\\n uint256 collateralTokenSent;\\n uint256 minEntryPrice;\\n uint256 loanToCollateralSwapRate;\\n uint256 interestDuration;\\n uint256 entryLeverage;\\n }\\n}\\n\",\"keccak256\":\"0xf0612e2c0d13604a67c3d55efe88810c089f0b84ca63bd3ce82c1e09b0938973\"},\"contracts/core/Objects.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./objects/LoanStruct.sol\\\";\\nimport \\\"./objects/LoanParamsStruct.sol\\\";\\nimport \\\"./objects/OrderStruct.sol\\\";\\nimport \\\"./objects/LenderInterestStruct.sol\\\";\\nimport \\\"./objects/LoanInterestStruct.sol\\\";\\n\\n/**\\n * @title Objects contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract inherints and aggregates several structures needed to handle\\n * loans on the protocol.\\n * */\\ncontract Objects is\\n LoanStruct,\\n LoanParamsStruct,\\n OrderStruct,\\n LenderInterestStruct,\\n LoanInterestStruct\\n{\\n\\n}\\n\",\"keccak256\":\"0xa30b8887af813997ebb480f0aa296245f9f3bd728382060059aa087cd9ee332c\"},\"contracts/core/State.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./Objects.sol\\\";\\nimport \\\"../mixins/EnumerableAddressSet.sol\\\";\\nimport \\\"../mixins/EnumerableBytes32Set.sol\\\";\\nimport \\\"../openzeppelin/ReentrancyGuard.sol\\\";\\nimport \\\"../openzeppelin/Ownable.sol\\\";\\nimport \\\"../openzeppelin/SafeMath.sol\\\";\\nimport \\\"../interfaces/IWrbtcERC20.sol\\\";\\nimport \\\"../reentrancy/SharedReentrancyGuard.sol\\\";\\n\\n/**\\n * @title State contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage values of the Protocol.\\n * */\\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\\n using SafeMath for uint256;\\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\\n\\n /// Handles asset reference price lookups.\\n address public priceFeeds;\\n\\n /// Handles asset swaps using dex liquidity.\\n address public swapsImpl;\\n\\n /// Contract registry address of the Sovryn swap network.\\n address public sovrynSwapContractRegistryAddress;\\n\\n /// Implementations of protocol functions.\\n mapping(bytes4 => address) public logicTargets;\\n\\n /// Loans: loanId => Loan\\n mapping(bytes32 => Loan) public loans;\\n\\n /// Loan parameters: loanParamsId => LoanParams\\n mapping(bytes32 => LoanParams) public loanParams;\\n\\n /// lender => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\\n\\n /// borrower => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\\n\\n /// loanId => delegated => approved\\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\\n\\n /**\\n *** Interest ***\\n **/\\n\\n /// lender => loanToken => LenderInterest object\\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\\n\\n /// loanId => LoanInterest object\\n mapping(bytes32 => LoanInterest) public loanInterest;\\n\\n /**\\n *** Internals ***\\n **/\\n\\n /// Implementations set.\\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\\n\\n /// Active loans set.\\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\\n\\n /// Lender loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\\n\\n /// Borrow loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\\n\\n /// User loan params set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\\n\\n /// Address controlling fee withdrawals.\\n address public feesController;\\n\\n /// 10% fee /// Fee taken from lender interest payments.\\n uint256 public lendingFeePercent = 10**19;\\n\\n /// Total interest fees received and not withdrawn per asset.\\n mapping(address => uint256) public lendingFeeTokensHeld;\\n\\n /// Total interest fees withdraw per asset.\\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\\n mapping(address => uint256) public lendingFeeTokensPaid;\\n\\n /// 0.15% fee /// Fee paid for each trade.\\n uint256 public tradingFeePercent = 15 * 10**16;\\n\\n /// Total trading fees received and not withdrawn per asset.\\n mapping(address => uint256) public tradingFeeTokensHeld;\\n\\n /// Total trading fees withdraw per asset\\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\\n mapping(address => uint256) public tradingFeeTokensPaid;\\n\\n /// 0.09% fee /// Origination fee paid for each loan.\\n uint256 public borrowingFeePercent = 9 * 10**16;\\n\\n /// Total borrowing fees received and not withdrawn per asset.\\n mapping(address => uint256) public borrowingFeeTokensHeld;\\n\\n /// Total borrowing fees withdraw per asset.\\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\\n mapping(address => uint256) public borrowingFeeTokensPaid;\\n\\n /// Current protocol token deposit balance.\\n uint256 public protocolTokenHeld;\\n\\n /// Lifetime total payout of protocol token.\\n uint256 public protocolTokenPaid;\\n\\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\\n uint256 public affiliateFeePercent = 5 * 10**18;\\n\\n /// 5% collateral discount /// Discount on collateral for liquidators.\\n uint256 public liquidationIncentivePercent = 5 * 10**18;\\n\\n /// loanPool => underlying\\n mapping(address => address) public loanPoolToUnderlying;\\n\\n /// underlying => loanPool\\n mapping(address => address) public underlyingToLoanPool;\\n\\n /// Loan pools set.\\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\\n\\n /// Supported tokens for swaps.\\n mapping(address => bool) public supportedTokens;\\n\\n /// % disagreement between swap rate and reference rate.\\n uint256 public maxDisagreement = 5 * 10**18;\\n\\n /// Used as buffer for swap source amount estimations.\\n uint256 public sourceBuffer = 10000;\\n\\n /// Maximum support swap size in rBTC\\n uint256 public maxSwapSize = 50 ether;\\n\\n /// Nonce per borrower. Used for loan id creation.\\n mapping(address => uint256) public borrowerNonce;\\n\\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\\n uint256 public rolloverBaseReward = 16800000000000;\\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\\n\\n IWrbtcERC20 public wrbtcToken;\\n address public protocolTokenAddress;\\n\\n /// 50% fee rebate\\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\\n uint256 public feeRebatePercent = 50 * 10**18;\\n\\n address public admin;\\n\\n /// For modules interaction.\\n address public protocolAddress;\\n\\n /**\\n *** Affiliates ***\\n **/\\n\\n /// The flag is set on the user's first trade.\\n mapping(address => bool) public userNotFirstTradeFlag;\\n\\n /// User => referrer (affiliate).\\n mapping(address => address) public affiliatesUserReferrer;\\n\\n /// List of referral addresses affiliated to the referrer.\\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\\n\\n /// @dev Referral threshold for paying out to the referrer.\\n /// The referrer reward is being accumulated and locked until the threshold is passed.\\n uint256 public minReferralsToPayout = 3;\\n\\n /// @dev Total affiliate SOV rewards that held in the protocol\\n /// (Because the minimum referrals is less than the rule)\\n mapping(address => uint256) public affiliateRewardsHeld;\\n\\n /// @dev For affiliates SOV Bonus proccess.\\n address public sovTokenAddress;\\n address public lockedSOVAddress;\\n\\n /// @dev 20% fee share of trading token fee.\\n /// Fee share of trading token fee for affiliate program.\\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\\n\\n /// @dev Addresses of tokens in which commissions were paid to referrers.\\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\\n\\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\\n\\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\\n bool public pause; //Flag to pause all protocol modules\\n\\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\\n\\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\\n uint256 internal tradingRebateRewardsBasisPoint;\\n\\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\\n /// Will be used in internal swap.\\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\\n\\n address internal pauser;\\n\\n /**\\n * @notice Add signature and target to storage.\\n * @dev Protocol is a proxy and requires a way to add every\\n * module function dynamically during deployment.\\n * */\\n function _setTarget(bytes4 sig, address target) internal {\\n logicTargets[sig] = target;\\n\\n if (target != address(0)) {\\n logicTargetsSet.addBytes32(bytes32(sig));\\n } else {\\n logicTargetsSet.removeBytes32(bytes32(sig));\\n }\\n }\\n\\n modifier onlyAdminOrOwner() {\\n require(isOwner() || admin == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n\\n modifier onlyPauserOrOwner() {\\n require(isOwner() || pauser == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0xf8dfc02f3dc790c73b390a69898d0281c4473487bc91fec1f28fbebceacd3b3c\"},\"contracts/core/objects/LenderInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Lender Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Lender Interest.\\n * */\\ncontract LenderInterestStruct {\\n struct LenderInterest {\\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\\n uint256 paidTotal; /// Total interest paid so far for asset.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0x6583baadddded384836cec469980e7973ec09310ae505b4a2ec67fb7bc19e452\"},\"contracts/core/objects/LoanInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Interest.\\n * */\\ncontract LoanInterestStruct {\\n struct LoanInterest {\\n uint256 owedPerDay; /// Interest owed per day for loan.\\n uint256 depositTotal; /// Total escrowed interest for loan.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0xd9034c6adb1b72e1593589dca024dc4730a1ee8bf6b2dca9d22283f2e7159590\"},\"contracts/core/objects/LoanParamsStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Parameters.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Parameters.\\n * */\\ncontract LoanParamsStruct {\\n struct LoanParams {\\n /// @dev ID of loan params object.\\n bytes32 id;\\n /// @dev If false, this object has been disabled by the owner and can't\\n /// be used for future loans.\\n bool active;\\n /// @dev Owner of this object.\\n address owner;\\n /// @dev The token being loaned.\\n address loanToken;\\n /// @dev The required collateral token.\\n address collateralToken;\\n /// @dev The minimum allowed initial margin.\\n uint256 minInitialMargin;\\n /// @dev An unhealthy loan when current margin is at or below this value.\\n uint256 maintenanceMargin;\\n /// @dev The maximum term for new loans (0 means there's no max term).\\n uint256 maxLoanTerm;\\n }\\n}\\n\",\"keccak256\":\"0xe15aa97713521da7f501e5225af9d92cf34bd68d286dbfed86aa75aabb323945\"},\"contracts/core/objects/LoanStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Object.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Object.\\n * */\\ncontract LoanStruct {\\n struct Loan {\\n bytes32 id; /// ID of the loan.\\n bytes32 loanParamsId; /// The linked loan params ID.\\n bytes32 pendingTradesId; /// The linked pending trades ID.\\n bool active; /// If false, the loan has been fully closed.\\n uint256 principal; /// Total borrowed amount outstanding.\\n uint256 collateral; /// Total collateral escrowed for the loan.\\n uint256 startTimestamp; /// Loan start time.\\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\\n uint256 startMargin; /// Initial margin when the loan opened.\\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\\n address borrower; /// Borrower of this loan.\\n address lender; /// Lender of this loan.\\n }\\n}\\n\",\"keccak256\":\"0x7d05c3096a86d5892e4e72f3a01a5a806f13a5ac90ca6339c611e75c603637b4\"},\"contracts/core/objects/OrderStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Order.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Order.\\n * */\\ncontract OrderStruct {\\n struct Order {\\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\\n uint256 interestRate; /// Interest rate defined by the creator of this order.\\n uint256 minLoanTerm; /// Minimum loan term allowed.\\n uint256 maxLoanTerm; /// Maximum loan term allowed.\\n uint256 createdTimestamp; /// Timestamp when this order was created.\\n uint256 expirationTimestamp; /// Timestamp when this order expires.\\n }\\n}\\n\",\"keccak256\":\"0xcc053c5da34a5927041162259bf856ba913f3524ca03e63ad0c5877777d17e0f\"},\"contracts/events/AffiliatesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\ncontract AffiliatesEvents is ModulesCommonEvents {\\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\\n\\n event SetAffiliatesReferrerFail(\\n address indexed user,\\n address indexed referrer,\\n bool alreadySet,\\n bool userNotFirstTrade\\n );\\n\\n event SetUserNotFirstTradeFlag(address indexed user);\\n\\n event PayTradingFeeToAffiliate(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n bool indexed isHeld,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountPaid\\n );\\n\\n event PayTradingFeeToAffiliateFail(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountTryingToPaid\\n );\\n\\n event WithdrawAffiliatesReferrerTokenFees(\\n address indexed referrer,\\n address indexed receiver,\\n address indexed tokenAddress,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xf72cf23e90db3c49589ddc4e1796680ebfb69a9b146db89f9b61f5fcf6dd95ba\"},\"contracts/events/FeesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Fees Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for fee payments.\\n * */\\ncontract FeesEvents {\\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\\n\\n event PayTradingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event PayBorrowingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event EarnReward(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n\\n event EarnRewardFail(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n}\\n\",\"keccak256\":\"0xe69bf53e15479be5fde1cbaadaf0c004ee038e8a6a37c99f7769bf5d8387015f\"},\"contracts/events/LoanClosingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Closing Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan closing operations.\\n * */\\ncontract LoanClosingsEvents is ModulesCommonEvents {\\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\\n event CloseWithDeposit(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address closer,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\\n event CloseWithSwap(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n address closer,\\n uint256 positionCloseSize,\\n uint256 loanCloseAmount,\\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\\n event Liquidate(\\n address indexed user,\\n address indexed liquidator,\\n bytes32 indexed loanId,\\n address lender,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n event Rollover(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n uint256 principal,\\n uint256 collateral,\\n uint256 endTimestamp,\\n address rewardReceiver,\\n uint256 reward\\n );\\n\\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\\n}\\n\",\"keccak256\":\"0x1ea325b9a213012865a52f38941ce6c1e8c29dce919215b5bdcc63a8a5980be1\"},\"contracts/events/LoanMaintenanceEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Maintenance Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan maintenance operations.\\n * */\\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\\n}\\n\",\"keccak256\":\"0xdee5098b947c22bcef6e38ecaf62bae6941572d1c245d2065ad41ea4f494c61d\"},\"contracts/events/LoanOpeningsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Openings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan openings operations.\\n * */\\ncontract LoanOpeningsEvents is ModulesCommonEvents {\\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\\n event Borrow(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 newCollateral,\\n uint256 interestRate,\\n uint256 interestDuration,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\\n event Trade(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n uint256 positionSize,\\n uint256 borrowedAmount,\\n uint256 interestRate,\\n uint256 settlementDate,\\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\\n uint256 entryLeverage,\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\\n event DelegatedManagerSet(\\n bytes32 indexed loanId,\\n address indexed delegator,\\n address indexed delegated,\\n bool isActive\\n );\\n}\\n\",\"keccak256\":\"0x585710ce6c570c6dbd1b8daf43b63a54b1d60ad01ee1dc3cae407d74d78f3093\"},\"contracts/events/LoanSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan settings operations.\\n * */\\ncontract LoanSettingsEvents is ModulesCommonEvents {\\n event LoanParamsSetup(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\\n\\n event LoanParamsDisabled(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\\n}\\n\",\"keccak256\":\"0xae9c49678a7bc02c2283648939c474c8bfd33781506e05c635c8334c5bf8682f\"},\"contracts/events/ModulesCommonEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\n/**\\n * @title The common events for all modules\\n * @notice This contract contains the events which will be used by all modules\\n **/\\n\\ncontract ModulesCommonEvents {\\n event ProtocolModuleContractReplaced(\\n address indexed prevModuleContractAddress,\\n address indexed newModuleContractAddress,\\n bytes32 indexed module\\n );\\n}\\n\",\"keccak256\":\"0xb07af42d7e6b0fe983889b883691b662a58d2ef8d75b3f32f17faff1871c8b8f\"},\"contracts/events/ProtocolSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title The Protocol Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for protocol settings operations.\\n * */\\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetLoanPool(\\n address indexed sender,\\n address indexed loanPool,\\n address indexed underlying\\n );\\n\\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\\n\\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateTradingTokenFeePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetLiquidationIncentivePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetFeesController(\\n address indexed sender,\\n address indexed oldController,\\n address indexed newController\\n );\\n\\n event SetWrbtcToken(\\n address indexed sender,\\n address indexed oldWethToken,\\n address indexed newWethToken\\n );\\n\\n event SetSovrynSwapContractRegistryAddress(\\n address indexed sender,\\n address indexed oldSovrynSwapContractRegistryAddress,\\n address indexed newSovrynSwapContractRegistryAddress\\n );\\n\\n event SetProtocolTokenAddress(\\n address indexed sender,\\n address indexed oldProtocolToken,\\n address indexed newProtocolToken\\n );\\n\\n event WithdrawFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 lendingAmount,\\n uint256 tradingAmount,\\n uint256 borrowingAmount,\\n uint256 wRBTCConverted\\n );\\n\\n event WithdrawLendingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawTradingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawBorrowingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetRebatePercent(\\n address indexed sender,\\n uint256 oldRebatePercent,\\n uint256 newRebatePercent\\n );\\n\\n event SetSpecialRebates(\\n address indexed sender,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 oldSpecialRebatesPercent,\\n uint256 newSpecialRebatesPercent\\n );\\n\\n event SetProtocolAddress(\\n address indexed sender,\\n address indexed oldProtocol,\\n address indexed newProtocol\\n );\\n\\n event SetMinReferralsToPayoutAffiliates(\\n address indexed sender,\\n uint256 oldMinReferrals,\\n uint256 newMinReferrals\\n );\\n\\n event SetSOVTokenAddress(\\n address indexed sender,\\n address indexed oldTokenAddress,\\n address indexed newTokenAddress\\n );\\n\\n event SetLockedSOVAddress(\\n address indexed sender,\\n address indexed oldAddress,\\n address indexed newAddress\\n );\\n\\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\\n\\n event SetTradingRebateRewardsBasisPoint(\\n address indexed sender,\\n uint256 oldBasisPoint,\\n uint256 newBasisPoint\\n );\\n\\n event SetRolloverFlexFeePercent(\\n address indexed sender,\\n uint256 oldRolloverFlexFeePercent,\\n uint256 newRolloverFlexFeePercent\\n );\\n\\n event SetDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event RemoveDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\\n\\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\\n}\\n\",\"keccak256\":\"0x20ca66a2c53669aa33379bf5233e3bcdddbba3504cd430a0143f0ee3ce1c2641\"},\"contracts/events/SwapsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Swaps Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for swap operations.\\n * */\\ncontract SwapsEvents is ModulesCommonEvents {\\n event LoanSwap(\\n bytes32 indexed loanId,\\n address indexed sourceToken,\\n address indexed destToken,\\n address borrower,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n\\n event ExternalSwap(\\n address indexed user,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n}\\n\",\"keccak256\":\"0x0a1cd289076675980b916941ed923146160d34a8669fc3fb4a06610f285dfbd1\"},\"contracts/feeds/IPriceFeeds.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface IPriceFeeds {\\n function queryRate(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 rate, uint256 precision);\\n\\n function queryPrecision(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 precision);\\n\\n function queryReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount\\n ) external view returns (uint256 destAmount);\\n\\n function checkPriceDisagreement(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount,\\n uint256 destAmount,\\n uint256 maxSlippage\\n ) external view returns (uint256 sourceToDestSwapRate);\\n\\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\\n\\n function getMaxDrawdown(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (uint256);\\n\\n function getCurrentMarginAndCollateralSize(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\\n\\n function getCurrentMargin(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\\n\\n function shouldLiquidate(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (bool);\\n\\n function getFastGasPrice(address payToken) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x2e2c2b393336efedb97659a2fc21c8dfb75b70e15d2422a3bcbf7ebd5fc83c82\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/interfaces/ISovryn.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\npragma experimental ABIEncoderV2;\\n//TODO: stored in ./interfaces only while brownie isn't removed\\n//TODO: move to contracts/interfaces after with brownie is removed\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/ProtocolSettingsEvents.sol\\\";\\nimport \\\"../events/LoanSettingsEvents.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../events/LoanMaintenanceEvents.sol\\\";\\nimport \\\"../events/LoanClosingsEvents.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../events/AffiliatesEvents.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\ncontract ISovryn is\\n State,\\n ProtocolSettingsEvents,\\n LoanSettingsEvents,\\n LoanOpeningsEvents,\\n LoanMaintenanceEvents,\\n LoanClosingsEvents,\\n SwapsEvents,\\n AffiliatesEvents,\\n FeesEvents\\n{\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n ////// Protocol //////\\n\\n function replaceContract(address target) external;\\n\\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\\n\\n function getTarget(string calldata sig) external view returns (address);\\n\\n ////// Protocol Settings //////\\n\\n function setSovrynProtocolAddress(address newProtocolAddress) external;\\n\\n function setSOVTokenAddress(address newSovTokenAddress) external;\\n\\n function setLockedSOVAddress(address newSOVLockedAddress) external;\\n\\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\\n\\n function setPriceFeedContract(address newContract) external;\\n\\n function setSwapsImplContract(address newContract) external;\\n\\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\\n\\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\\n\\n function setLendingFeePercent(uint256 newValue) external;\\n\\n function setTradingFeePercent(uint256 newValue) external;\\n\\n function setBorrowingFeePercent(uint256 newValue) external;\\n\\n function setSwapExternalFeePercent(uint256 newValue) external;\\n\\n function setAffiliateFeePercent(uint256 newValue) external;\\n\\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\\n\\n function setLiquidationIncentivePercent(uint256 newAmount) external;\\n\\n function setMaxDisagreement(uint256 newAmount) external;\\n\\n function setSourceBuffer(uint256 newAmount) external;\\n\\n function setMaxSwapSize(uint256 newAmount) external;\\n\\n function setFeesController(address newController) external;\\n\\n function withdrawFees(address[] calldata tokens, address receiver)\\n external\\n returns (uint256 totalWRBTCWithdrawn);\\n\\n function withdrawLendingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawTradingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawBorrowingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawProtocolToken(address receiver, uint256 amount)\\n external\\n returns (address, bool);\\n\\n function depositProtocolToken(uint256 amount) external;\\n\\n function getLoanPoolsList(uint256 start, uint256 count)\\n external\\n view\\n returns (bytes32[] memory);\\n\\n function isLoanPool(address loanPool) external view returns (bool);\\n\\n function setWrbtcToken(address wrbtcTokenAddress) external;\\n\\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\\n\\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\\n\\n function setRolloverBaseReward(uint256 transactionCost) external;\\n\\n function setRebatePercent(uint256 rebatePercent) external;\\n\\n function setSpecialRebates(\\n address sourceToken,\\n address destToken,\\n uint256 specialRebatesPercent\\n ) external;\\n\\n function getSpecialRebates(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 specialRebatesPercent);\\n\\n function togglePaused(bool paused) external;\\n\\n function isProtocolPaused() external view returns (bool);\\n\\n ////// SwapsImplSovrynSwapModule //////\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (address);\\n\\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\\n\\n function swapsImplExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function swapsImplExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256 expectedReturn);\\n\\n ////// Loan Settings //////\\n\\n function setupLoanParams(LoanParams[] calldata loanParamsList)\\n external\\n returns (bytes32[] memory loanParamsIdList);\\n\\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\\n\\n function getLoanParams(bytes32[] calldata loanParamsIdList)\\n external\\n view\\n returns (LoanParams[] memory loanParamsList);\\n\\n function getLoanParamsList(\\n address owner,\\n uint256 start,\\n uint256 count\\n ) external view returns (bytes32[] memory loanParamsList);\\n\\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\\n\\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\\n\\n ////// Loan Openings //////\\n\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId, // if 0, start a new loan\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n // lender: must match loan if loanId provided\\n // borrower: must match loan if loanId provided\\n // receiver: receiver of funds (address(0) assumes borrower address)\\n // manager: delegated manager of loan unless address(0)\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n // newRate: new loan interest rate\\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\\n // collateralTokenReceived: total collateralToken deposit\\n bytes calldata loanDataBytes\\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\\n\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external;\\n\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256);\\n\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 collateralAmountRequired);\\n\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 borrowAmount);\\n\\n ////// Loan Closings //////\\n\\n function liquidate(\\n bytes32 loanId,\\n address receiver,\\n uint256 closeAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 seizedAmount,\\n address seizedToken\\n );\\n\\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\\n\\n function closeWithDeposit(\\n bytes32 loanId,\\n address receiver,\\n uint256 depositAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n function closeWithSwap(\\n bytes32 loanId,\\n address receiver,\\n uint256 swapAmount, // denominated in collateralToken\\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\\n bytes calldata loanDataBytes\\n )\\n external\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n ////// Loan Maintenance //////\\n\\n function depositCollateral(\\n bytes32 loanId,\\n uint256 depositAmount // must match msg.value if ether is sent\\n ) external payable;\\n\\n function withdrawCollateral(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 actualWithdrawAmount);\\n\\n function withdrawAccruedInterest(address loanToken) external;\\n\\n function getLenderInterestData(address lender, address loanToken)\\n external\\n view\\n returns (\\n uint256 interestPaid,\\n uint256 interestPaidDate,\\n uint256 interestOwedPerDay,\\n uint256 interestUnPaid,\\n uint256 interestFeePercent,\\n uint256 principalTotal\\n );\\n\\n function getLoanInterestData(bytes32 loanId)\\n external\\n view\\n returns (\\n address loanToken,\\n uint256 interestOwedPerDay,\\n uint256 interestDepositTotal,\\n uint256 interestDepositRemaining\\n );\\n\\n struct LoanReturnData {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; // collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n }\\n\\n struct LoanReturnDataV2 {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n address borrower;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; /// collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n uint256 creationTimestamp;\\n }\\n\\n function getUserLoans(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getUserLoansV2(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\\n\\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\\n\\n function getActiveLoans(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getActiveLoansV2(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function extendLoanDuration(\\n bytes32 loanId,\\n uint256 depositAmount,\\n bool useCollateral,\\n bytes calldata /// loanDataBytes, for future use.\\n ) external returns (uint256 secondsExtended);\\n\\n function reduceLoanDuration(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 secondsReduced);\\n\\n ////// Swaps External //////\\n function swapExternal(\\n address sourceToken,\\n address destToken,\\n address receiver,\\n address returnToSender,\\n uint256 sourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n uint256 minReturn,\\n bytes calldata swapData\\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\\n\\n function getSwapExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function checkPriceDivergence(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount,\\n uint256 minReturn\\n ) public view;\\n\\n ////// Affiliates Module //////\\n\\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\\n\\n function setUserNotFirstTradeFlag(address user) external;\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address referrer,\\n address trader,\\n address token,\\n uint256 tradingFeeTokenBaseAmount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n\\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\\n\\n function getReferralsList(address referrer) external view returns (address[] memory refList);\\n\\n function getAffiliatesReferrerBalances(address referrer)\\n external\\n view\\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\\n\\n function getAffiliatesReferrerTokensList(address referrer)\\n external\\n view\\n returns (address[] memory tokensList);\\n\\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\\n external\\n view\\n returns (uint256);\\n\\n function withdrawAffiliatesReferrerTokenFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external;\\n\\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\\n\\n function getProtocolAddress() external view returns (address);\\n\\n function getSovTokenAddress() external view returns (address);\\n\\n function getLockedSOVAddress() external view returns (address);\\n\\n function getFeeRebatePercent() external view returns (uint256);\\n\\n function getMinReferralsToPayout() external view returns (uint256);\\n\\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\\n\\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\\n\\n function getAffiliateTradingTokenFeePercent()\\n external\\n view\\n returns (uint256 affiliateTradingTokenFeePercent);\\n\\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\\n external\\n view\\n returns (uint256 rbtcTotalAmount);\\n\\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\\n\\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\\n\\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\\n\\n function getDedicatedSOVRebate() external view returns (uint256);\\n\\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\\n\\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external\\n view\\n returns (IERC20[] memory);\\n\\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\\n\\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external;\\n\\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\\n external\\n view\\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\\n\\n function setAdmin(address newAdmin) external;\\n\\n function getAdmin() external view returns (address);\\n\\n function setPauser(address newPauser) external;\\n\\n function getPauser() external view returns (address);\\n}\\n\",\"keccak256\":\"0x4e470e1fe1719c2c58b0e44aedce3ee6a21191063b533ccb71c9219a192e8884\"},\"contracts/interfaces/IWrbtc.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ninterface IWrbtc {\\n function deposit() external payable;\\n\\n function withdraw(uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x20fdfe4b5e32fd7f863b3fa128e3c80bd4ccf090a4ffba56186ef3b7f2a80492\"},\"contracts/interfaces/IWrbtcERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./IWrbtc.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\n\\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\\n\",\"keccak256\":\"0x7301a8c8ca7aa016ec94268a16d07366875f2e406442e929968dd745b1ee5be5\"},\"contracts/mixins/EnumerableAddressSet.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Based on Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * As of v2.5.0, only `address` sets are supported.\\n *\\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\\n *\\n * _Available since v2.5.0._\\n */\\nlibrary EnumerableAddressSet {\\n struct AddressSet {\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(address => uint256) index;\\n address[] values;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n * Returns false if the value was already in the set.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n * Returns false if the value was not present in the set.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n // If the element we're deleting is the last one, we can just remove it without doing a swap\\n if (lastIndex != toDeleteIndex) {\\n address lastValue = set.values[lastIndex];\\n\\n // Move the last value to the index where the deleted value is\\n set.values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n // Delete the index entry for the deleted value\\n delete set.index[value];\\n\\n // Delete the old entry for the moved value\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns an array with all values in the set. O(N).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\\n address[] memory output = new address[](set.values.length);\\n for (uint256 i; i < set.values.length; i++) {\\n output[i] = set.values[i];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n \\n * @param start start index of chunk\\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\\n */\\n function enumerateChunk(\\n AddressSet storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (address[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = (set.values.length < end || count == 0) ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new address[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns the number of elements on the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /** @dev Returns the element stored at position `index` in the set. O(1).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xea6fba941ec8502aa11a7ab37e74b917d0dc47bb254e359a2870a87ef97d9872\"},\"contracts/mixins/EnumerableBytes32Set.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title Library for managing loan sets.\\n *\\n * @notice Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\\n * */\\nlibrary EnumerableBytes32Set {\\n struct Bytes32Set {\\n /// Position of the value in the `values` array, plus 1 because index 0\\n /// means a value is not in the set.\\n mapping(bytes32 => uint256) index;\\n bytes32[] values;\\n }\\n\\n /**\\n * @notice Add an address value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return addBytes32(set, value);\\n }\\n\\n /**\\n * @notice Add a value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The new value to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Remove an address value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to remove.\\n *\\n * @return False if the address was not present in the set.\\n */\\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return removeBytes32(set, value);\\n }\\n\\n /**\\n * @notice Remove a value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The value to remove.\\n *\\n * @return False if the value was not present in the set.\\n */\\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n /// If the element we're deleting is the last one,\\n /// we can just remove it without doing a swap.\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set.values[lastIndex];\\n\\n /// Move the last value to the index where the deleted value is.\\n set.values[toDeleteIndex] = lastValue;\\n\\n /// Update the index for the moved value.\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n /// Delete the index entry for the deleted value.\\n delete set.index[value];\\n\\n /// Delete the old entry for the moved value.\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Find out whether a value exists in the set.\\n *\\n * @param set The set of values.\\n * @param value The value to find.\\n *\\n * @return True if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function containsAddress(Bytes32Set storage set, address addrvalue)\\n internal\\n view\\n returns (bool)\\n {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @notice Get all set values.\\n *\\n * @param set The set of values.\\n * @param start The offset of the returning set.\\n * @param count The limit of number of values to return.\\n *\\n * @return An array with all values in the set. O(N).\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(\\n Bytes32Set storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (bytes32[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = set.values.length < end ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new bytes32[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @notice Get the legth of the set.\\n *\\n * @param set The set of values.\\n *\\n * @return the number of elements on the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /**\\n * @notice Get an item from the set by its index.\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n *\\n * @param set The set of values.\\n * @param index The index of the value to return.\\n *\\n * @return the element stored at position `index` in the set. O(1).\\n */\\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xa2801a585c566e07f21c1ebccd0cd0447dd5fd9fe6c1ff2b58d4d979d88a6db0\"},\"contracts/mixins/FeesHelper.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../modules/interfaces/ProtocolAffiliatesInterface.sol\\\";\\nimport \\\"../interfaces/ISovryn.sol\\\";\\nimport \\\"../core/objects/LoanParamsStruct.sol\\\";\\n\\n/**\\n * @title The Fees Helper contract.\\n *\\n * This contract calculates and pays lending/borrow fees and rewards.\\n * */\\ncontract FeesHelper is State, FeesEvents {\\n using SafeERC20 for IERC20;\\n\\n /**\\n * @notice Calculate trading fee.\\n * @param feeTokenAmount The amount of tokens to trade.\\n * @return The fee of the trade.\\n * */\\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\\n }\\n\\n /**\\n * @notice Calculate swap external fee.\\n * @param feeTokenAmount The amount of token to swap.\\n * @return The fee of the swap.\\n */\\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\\n }\\n\\n /*\\n\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\\n\\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n\\t\\tuint256 collateralAmountRequired =\\n\\t\\t\\tfeeTokenAmount.mul(10**20).divCeil(\\n\\t\\t\\t\\t10**20 - tradingFeePercent // never will overflow\\n\\t\\t\\t);\\n\\t\\treturn collateralAmountRequired.sub(feeTokenAmount);\\n\\t}*/\\n\\n /**\\n * @notice Calculate the loan origination fee.\\n * @param feeTokenAmount The amount of tokens to borrow.\\n * @return The fee of the loan.\\n * */\\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\\n /*\\n\\t\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t\\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\\n\\t\\tuint256 collateralAmountRequired =\\n\\t\\t\\tfeeTokenAmount.mul(10**20).divCeil(\\n\\t\\t\\t\\t10**20 - borrowingFeePercent // never will overflow\\n\\t\\t\\t);\\n\\t\\treturn collateralAmountRequired.sub(feeTokenAmount);*/\\n }\\n\\n /**\\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\\n *\\n * @param referrer The affiliate referrer address to send the reward to.\\n * @param trader The account that performs this trade.\\n * @param feeToken The address of the token in which the trading fee is paid.\\n * @param tradingFee The amount of tokens accrued as fees on the trading.\\n *\\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\\n * */\\n function _payTradingFeeToAffiliate(\\n address referrer,\\n address trader,\\n address feeToken,\\n uint256 tradingFee\\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\\n address(this)\\n )\\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\\n }\\n\\n /**\\n * @notice Settle the trading fee and pay the token reward to the user.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associated loan - used for logging only.\\n * @param feeToken The address of the token in which the trading fee is paid.\\n * @param tradingFee The amount of tokens accrued as fees on the trading.\\n * */\\n function _payTradingFee(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 tradingFee\\n ) internal {\\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\\n if (tradingFee != 0) {\\n if (affiliatesUserReferrer[user] != address(0)) {\\n _payTradingFeeToAffiliate(\\n affiliatesUserReferrer[user],\\n user,\\n feeToken,\\n protocolTradingFee\\n );\\n protocolTradingFee = (\\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\\n )\\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\\n }\\n\\n /// Increase the storage variable keeping track of the accumulated fees.\\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\\n protocolTradingFee\\n );\\n\\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\\n\\n /// Pay the token reward to the user.\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\\n }\\n }\\n\\n /**\\n * @notice Settle the borrowing fee and pay the token reward to the user.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associated loan - used for logging only.\\n * @param feeToken The address of the token in which the borrowig fee is paid.\\n * @param borrowingFee The height of the fee.\\n * */\\n function _payBorrowingFee(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 borrowingFee\\n ) internal {\\n if (borrowingFee != 0) {\\n /// Increase the storage variable keeping track of the accumulated fees.\\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\\n\\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\\n\\n /// Pay the token reward to the user.\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\\n }\\n }\\n\\n /**\\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\\n * @param user The address to send the reward to.\\n * @param feeToken The address of the token in which the lending fee is paid.\\n * @param lendingFee The height of the fee.\\n * */\\n function _payLendingFee(\\n address user,\\n address feeToken,\\n uint256 lendingFee\\n ) internal {\\n if (lendingFee != 0) {\\n /// Increase the storage variable keeping track of the accumulated fees.\\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\\n\\n emit PayLendingFee(user, feeToken, lendingFee);\\n\\n //// NOTE: Lenders do not receive a fee reward ////\\n }\\n }\\n\\n /// Settle and pay borrowers based on the fees generated by their interest payments.\\n function _settleFeeRewardForInterestExpense(\\n LoanInterest storage loanInterestLocal,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n address user,\\n uint256 interestTime\\n ) internal {\\n /// This represents the fee generated by a borrower's interest payment.\\n uint256 interestExpenseFee =\\n interestTime\\n .sub(loanInterestLocal.updatedTimestamp)\\n .mul(loanInterestLocal.owedPerDay)\\n .mul(lendingFeePercent)\\n .div(1 days * 10**20);\\n\\n loanInterestLocal.updatedTimestamp = interestTime;\\n\\n if (interestExpenseFee != 0) {\\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\\n }\\n }\\n\\n /**\\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\\n * @param user The address to send the reward to.\\n * @param loanId The Id of the associeated loan - used for logging only.\\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\\n * @param feeAmount The height of the fee.\\n * */\\n function _payFeeReward(\\n address user,\\n bytes32 loanId,\\n address feeToken,\\n address feeTokenPair,\\n uint256 feeAmount\\n ) internal {\\n uint256 rewardAmount;\\n uint256 _feeRebatePercent = feeRebatePercent;\\n address _priceFeeds = priceFeeds;\\n\\n if (specialRebates[feeToken][feeTokenPair] > 0) {\\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\\n }\\n\\n /// Note: this should be refactored.\\n /// Calculate the reward amount, querying the price feed.\\n (bool success, bytes memory data) =\\n _priceFeeds.staticcall(\\n abi.encodeWithSelector(\\n IPriceFeeds(_priceFeeds).queryReturn.selector,\\n feeToken,\\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\\n feeAmount.mul(_feeRebatePercent).div(10**20)\\n )\\n );\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n if eq(success, 1) {\\n rewardAmount := mload(add(data, 32))\\n }\\n }\\n\\n // Check the dedicated SOV that is used to pay trading rebate rewards\\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\\n\\n (bool success, ) =\\n lockedSOVAddress.call(\\n abi.encodeWithSignature(\\n \\\"deposit(address,uint256,uint256)\\\",\\n user,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n )\\n );\\n\\n if (success) {\\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\\n\\n emit EarnReward(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n } else {\\n emit EarnRewardFail(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n }\\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\\n emit EarnRewardFail(\\n user,\\n sovTokenAddress,\\n loanId,\\n _feeRebatePercent,\\n rewardAmount,\\n tradingRebateRewardsBasisPoint\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0x9094bce5eab7109594a795982a779641c951c2617a618f5eab1f651b3b945077\"},\"contracts/mixins/InterestUser.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../mixins/VaultController.sol\\\";\\nimport \\\"./FeesHelper.sol\\\";\\n\\n/**\\n * @title The Interest User contract.\\n *\\n * This contract pays loan interests.\\n * */\\ncontract InterestUser is VaultController, FeesHelper {\\n using SafeERC20 for IERC20;\\n\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n /**\\n * @notice Internal function to pay interest of a loan.\\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\\n * @param lender The account address of the lender.\\n * @param interestToken The token address to pay interest with.\\n * */\\n function _payInterest(address lender, address interestToken) internal {\\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\\n\\n uint256 interestOwedNow = 0;\\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\\n interestOwedNow = block\\n .timestamp\\n .sub(lenderInterestLocal.updatedTimestamp)\\n .mul(lenderInterestLocal.owedPerDay)\\n .div(1 days);\\n\\n lenderInterestLocal.updatedTimestamp = block.timestamp;\\n\\n if (interestOwedNow > lenderInterestLocal.owedTotal)\\n interestOwedNow = lenderInterestLocal.owedTotal;\\n\\n if (interestOwedNow != 0) {\\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\\n\\n _payInterestTransfer(lender, interestToken, interestOwedNow);\\n }\\n } else {\\n lenderInterestLocal.updatedTimestamp = block.timestamp;\\n }\\n }\\n\\n /**\\n * @notice Internal function to transfer tokens for the interest of a loan.\\n * @param lender The account address of the lender.\\n * @param interestToken The token address to pay interest with.\\n * @param interestOwedNow The amount of interest to pay.\\n * */\\n function _payInterestTransfer(\\n address lender,\\n address interestToken,\\n uint256 interestOwedNow\\n ) internal {\\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\\n /// TODO: refactor: data incapsulation violation and DRY design principles\\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\\n\\n _payLendingFee(lender, interestToken, lendingFee);\\n\\n /// Transfers the interest to the lender, less the interest fee.\\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\\n\\n /// Event Log\\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\\n }\\n}\\n\",\"keccak256\":\"0x870208d1ae2c7adca9478b86fe5e70b4458bf719d49b19f5a8a4441bdaccf866\"},\"contracts/mixins/ModuleCommonFunctionalities.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\n\\ncontract ModuleCommonFunctionalities is State {\\n modifier whenNotPaused() {\\n require(!pause, \\\"Paused\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0x9ed7a6a635ef960b53888b28a2a6bed8b071255cad8cd33f00386a634cbddb74\"},\"contracts/mixins/VaultController.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"../core/State.sol\\\";\\n\\n/**\\n * @title The Vault Controller contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\\n * trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract implements functionality to deposit and withdraw wrBTC and\\n * other tokens from the vault.\\n * */\\ncontract VaultController is State {\\n using SafeERC20 for IERC20;\\n\\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\\n\\n /**\\n * @notice Deposit wrBTC into the vault.\\n *\\n * @param from The address of the account paying the deposit.\\n * @param value The amount of wrBTC tokens to transfer.\\n */\\n function vaultEtherDeposit(address from, uint256 value) internal {\\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\\n _wrbtcToken.deposit.value(value)();\\n\\n emit VaultDeposit(address(_wrbtcToken), from, value);\\n }\\n\\n /**\\n * @notice Withdraw wrBTC from the vault.\\n *\\n * @param to The address of the recipient.\\n * @param value The amount of wrBTC tokens to transfer.\\n */\\n function vaultEtherWithdraw(address to, uint256 value) internal {\\n if (value != 0) {\\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\\n uint256 balance = address(this).balance;\\n if (value > balance) {\\n _wrbtcToken.withdraw(value - balance);\\n }\\n Address.sendValue(to, value);\\n\\n emit VaultWithdraw(address(_wrbtcToken), to, value);\\n }\\n }\\n\\n /**\\n * @notice Deposit tokens into the vault.\\n *\\n * @param token The address of the token instance.\\n * @param from The address of the account paying the deposit.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultDeposit(\\n address token,\\n address from,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n IERC20(token).safeTransferFrom(from, address(this), value);\\n\\n emit VaultDeposit(token, from, value);\\n }\\n }\\n\\n /**\\n * @notice Withdraw tokens from the vault.\\n *\\n * @param token The address of the token instance.\\n * @param to The address of the recipient.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultWithdraw(\\n address token,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n IERC20(token).safeTransfer(to, value);\\n\\n emit VaultWithdraw(token, to, value);\\n }\\n }\\n\\n /**\\n * @notice Transfer tokens from an account into another one.\\n *\\n * @param token The address of the token instance.\\n * @param from The address of the account paying.\\n * @param to The address of the recipient.\\n * @param value The amount of tokens to transfer.\\n */\\n function vaultTransfer(\\n address token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0) {\\n if (from == address(this)) {\\n IERC20(token).safeTransfer(to, value);\\n } else {\\n IERC20(token).safeTransferFrom(from, to, value);\\n }\\n }\\n }\\n\\n /**\\n * @notice Approve an allowance of tokens to be spent by an account.\\n *\\n * @param token The address of the token instance.\\n * @param to The address of the spender.\\n * @param value The amount of tokens to allow.\\n */\\n function vaultApprove(\\n address token,\\n address to,\\n uint256 value\\n ) internal {\\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\\n IERC20(token).safeApprove(to, 0);\\n }\\n IERC20(token).safeApprove(to, value);\\n }\\n}\\n\",\"keccak256\":\"0xdcde4eee041b77ec9b73378a4a75b4d20d62f2e76f96f759d55260cf6717d0f3\"},\"contracts/modules/LoanOpenings.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../mixins/VaultController.sol\\\";\\nimport \\\"../mixins/InterestUser.sol\\\";\\nimport \\\"../swaps/SwapsUser.sol\\\";\\nimport \\\"../mixins/ModuleCommonFunctionalities.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\n/**\\n * @title Loan Openings contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains functions to borrow and trade.\\n * */\\ncontract LoanOpenings is\\n LoanOpeningsEvents,\\n VaultController,\\n InterestUser,\\n SwapsUser,\\n ModuleCommonFunctionalities\\n{\\n constructor() public {}\\n\\n /**\\n * @notice Fallback function is to react to receiving value (rBTC).\\n * */\\n function() external {\\n revert(\\\"fallback not allowed\\\");\\n }\\n\\n /**\\n * @notice Set function selectors on target contract.\\n *\\n * @param target The address of the target contract.\\n * */\\n function initialize(address target) external onlyOwner {\\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\\n _setTarget(this.borrowOrTradeFromPool.selector, target);\\n _setTarget(this.setDelegatedManager.selector, target);\\n _setTarget(this.getEstimatedMarginExposure.selector, target);\\n _setTarget(this.getRequiredCollateral.selector, target);\\n _setTarget(this.getBorrowAmount.selector, target);\\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \\\"LoanOpenings\\\");\\n }\\n\\n /**\\n * @notice Borrow or trade from pool.\\n *\\n * @dev Note: Only callable by loan pools (iTokens).\\n * Wrapper to _borrowOrTrade internal function.\\n *\\n * @param loanParamsId The ID of the loan parameters.\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * @param initialMargin The initial amount of margin.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return newPrincipal The new loan size.\\n * @return newCollateral The new collateral amount.\\n * */\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId,\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n bytes calldata loanDataBytes\\n )\\n external\\n payable\\n nonReentrant\\n whenNotPaused\\n returns (uint256 newPrincipal, uint256 newCollateral)\\n {\\n require(msg.value == 0 || loanDataBytes.length != 0, \\\"loanDataBytes required with ether\\\");\\n\\n /// Only callable by loan pools.\\n require(loanPoolToUnderlying[msg.sender] != address(0), \\\"not authorized\\\");\\n\\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\\n require(loanParamsLocal.id != 0, \\\"loanParams not exists\\\");\\n\\n /// Get required collateral.\\n uint256 collateralAmountRequired =\\n _getRequiredCollateral(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n sentValues.newPrincipal,\\n initialMargin,\\n isTorqueLoan\\n );\\n require(collateralAmountRequired != 0, \\\"collateral is 0\\\");\\n\\n return\\n _borrowOrTrade(\\n loanParamsLocal,\\n loanId,\\n isTorqueLoan,\\n collateralAmountRequired,\\n initialMargin,\\n sentAddresses,\\n sentValues,\\n loanDataBytes\\n );\\n }\\n\\n /**\\n * @notice Set the delegated manager.\\n *\\n * @dev Wrapper for _setDelegatedManager internal function.\\n *\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param delegated The address of the delegated manager.\\n * @param toggle The flag true/false for the delegated manager.\\n * */\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external whenNotPaused {\\n require(loans[loanId].borrower == msg.sender, \\\"unauthorized\\\");\\n\\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\\n }\\n\\n /**\\n * @notice Get the estimated margin exposure.\\n *\\n * Margin is the money borrowed from a broker to purchase an investment\\n * and is the difference between the total value of investment and the\\n * loan amount. Margin trading refers to the practice of using borrowed\\n * funds from a broker to trade a financial asset, which forms the\\n * collateral for the loan from the broker.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param loanTokenSent The amount of loan tokens sent.\\n * @param collateralTokenSent The amount of collateral tokens sent.\\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\\n * @param newPrincipal The updated amount of principal (current debt).\\n *\\n * @return The margin exposure.\\n * */\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256) {\\n uint256 maxLoanTerm = 2419200; // 28 days\\n\\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\\n\\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\\n\\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\\n uint256 tradingFee = _getTradingFee(swapAmount);\\n if (tradingFee != 0) {\\n swapAmount = swapAmount.sub(tradingFee);\\n }\\n\\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\\n if (receivedAmount == 0) {\\n return 0;\\n } else {\\n return collateralTokenSent.add(receivedAmount);\\n }\\n }\\n\\n /**\\n * @notice Get the required collateral.\\n *\\n * @dev Calls internal _getRequiredCollateral and add fees.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param newPrincipal The updated amount of principal (current debt).\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return collateralAmountRequired The required collateral.\\n * */\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) public view returns (uint256 collateralAmountRequired) {\\n if (marginAmount != 0) {\\n collateralAmountRequired = _getRequiredCollateral(\\n loanToken,\\n collateralToken,\\n newPrincipal,\\n marginAmount,\\n isTorqueLoan\\n );\\n\\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n // cannot be applied solely as it drives to some other tests failure\\n /*\\n\\t\\t\\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\\n\\t\\t\\tif (collateralAmountRequired != 0 && feePercent != 0) {\\n\\t\\t\\t\\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\\n\\t\\t\\t\\t\\t10**20 - feePercent // never will overflow\\n\\t\\t\\t\\t);\\n\\t\\t\\t}*/\\n\\n uint256 fee =\\n isTorqueLoan\\n ? _getBorrowingFee(collateralAmountRequired)\\n : _getTradingFee(collateralAmountRequired);\\n if (fee != 0) {\\n collateralAmountRequired = collateralAmountRequired.add(fee);\\n }\\n }\\n }\\n\\n /**\\n * @notice Get the borrow amount of a trade loan.\\n *\\n * @dev Basically borrowAmount = collateral / marginAmount\\n *\\n * Collateral is something that helps secure a loan. When you borrow money,\\n * you agree that your lender can take something and sell it to get their\\n * money back if you fail to repay the loan. That's the collateral.\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param collateralTokenAmount The amount of collateral.\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return borrowAmount The borrow amount.\\n * */\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) public view returns (uint256 borrowAmount) {\\n if (marginAmount != 0) {\\n if (isTorqueLoan) {\\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\\n }\\n uint256 collateral = collateralTokenAmount;\\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\\n if (fee != 0) {\\n collateral = collateral.sub(fee);\\n }\\n if (loanToken == collateralToken) {\\n borrowAmount = collateral.mul(10**20).div(marginAmount);\\n } else {\\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\\n if (sourceToDestPrecision != 0) {\\n borrowAmount = collateral\\n .mul(10**20)\\n .mul(sourceToDestRate)\\n .div(marginAmount)\\n .div(sourceToDestPrecision);\\n }\\n }\\n /*\\n\\t\\t\\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\\n\\t\\t\\t// cannot be applied solely as it drives to some other tests failure\\n\\t\\t\\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\\n\\t\\t\\tif (borrowAmount != 0 && feePercent != 0) {\\n\\t\\t\\t\\tborrowAmount = borrowAmount\\n\\t\\t\\t\\t\\t.mul(\\n\\t\\t\\t\\t\\t10**20 - feePercent // never will overflow\\n\\t\\t\\t\\t)\\n\\t\\t\\t\\t\\t.divCeil(10**20);\\n\\t\\t\\t}*/\\n }\\n }\\n\\n /**\\n * @notice Borrow or trade.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * @param collateralAmountRequired The required amount of collateral.\\n * @param initialMargin The initial amount of margin.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return The new loan size.\\n * @return The new collateral amount.\\n * */\\n function _borrowOrTrade(\\n LoanParams memory loanParamsLocal,\\n bytes32 loanId,\\n bool isTorqueLoan,\\n uint256 collateralAmountRequired,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n bytes memory loanDataBytes\\n ) internal returns (uint256, uint256) {\\n require(\\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\\n \\\"collateral/loan match\\\"\\n );\\n require(initialMargin >= loanParamsLocal.minInitialMargin, \\\"initialMargin too low\\\");\\n\\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\\n require(\\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\\n \\\"invalid interest\\\"\\n );\\n\\n // @note this fix is for borrowing only\\n uint256 sentNewPrincipal = isTorqueLoan ? sentValues.newPrincipal : 0;\\n\\n /// Initialize loan.\\n Loan storage loanLocal =\\n loans[\\n _initializeLoan(\\n loanParamsLocal,\\n loanId,\\n initialMargin,\\n sentAddresses,\\n sentValues.newPrincipal\\n )\\n ];\\n\\n // Get required interest.\\n uint256 amount =\\n _initializeInterest(\\n loanParamsLocal,\\n loanLocal,\\n sentValues.interestRate, /// newRate\\n sentValues.newPrincipal, /// newPrincipal,\\n sentValues.interestInitialAmount /// torqueInterest\\n );\\n\\n /// substract out interest from usable loanToken sent.\\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\\n\\n if (isTorqueLoan) {\\n require(sentValues.loanTokenSent == 0, \\\"surplus loan token\\\");\\n\\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\\n // need to temp into local state to avoid\\n address _collateralToken = loanParamsLocal.collateralToken;\\n address _loanToken = loanParamsLocal.loanToken;\\n if (borrowingFee != 0) {\\n _payBorrowingFee(\\n sentAddresses.borrower, /// borrower\\n loanLocal.id,\\n _collateralToken, /// fee token\\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n borrowingFee\\n );\\n\\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\\n }\\n } else {\\n /// Update collateral after trade.\\n sentValues = _updateCollateralAfterTrade(\\n loanId,\\n loanParamsLocal,\\n sentAddresses,\\n sentValues,\\n loanDataBytes\\n );\\n }\\n\\n /// Settle collateral.\\n require(\\n _isCollateralSatisfied(\\n loanParamsLocal,\\n loanLocal,\\n initialMargin,\\n sentValues.collateralTokenSent,\\n collateralAmountRequired,\\n sentNewPrincipal\\n ),\\n \\\"collateral insufficient\\\"\\n );\\n\\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\\n\\n if (isTorqueLoan) {\\n /// reclaiming variable -> interestDuration\\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\\n } else {\\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\\n }\\n\\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\\n\\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\\n }\\n\\n function _updateCollateralAfterTrade(\\n bytes32 loanId,\\n LoanParams memory loanParamsLocal,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n bytes memory loanDataBytes\\n ) internal returns (MarginTradeStructHelpers.SentAmounts memory) {\\n uint256 receivedAmount;\\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\\n loanId,\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n sentAddresses.borrower, /// borrower\\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\\n false, /// bypassFee\\n loanDataBytes\\n );\\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\\n\\n /// Check the minEntryPrice with the rate\\n require(\\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\\n \\\"entry price above the minimum\\\"\\n );\\n\\n return sentValues;\\n }\\n\\n /**\\n * @notice Finalize an open loan.\\n *\\n * @dev Finalize it by updating local parameters of the loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * */\\n function _finalizeOpen(\\n LoanParams memory loanParamsLocal,\\n Loan storage loanLocal,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n bool isTorqueLoan\\n ) internal {\\n /// @dev TODO: here the actual used rate and margin should go.\\n (uint256 initialMargin, uint256 collateralToLoanRate) =\\n IPriceFeeds(priceFeeds).getCurrentMargin(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n loanLocal.principal,\\n loanLocal.collateral\\n );\\n require(initialMargin > loanParamsLocal.maintenanceMargin, \\\"unhealthy position\\\");\\n\\n if (loanLocal.startTimestamp == block.timestamp) {\\n uint256 loanToCollateralPrecision =\\n IPriceFeeds(priceFeeds).queryPrecision(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken\\n );\\n uint256 collateralToLoanPrecision =\\n IPriceFeeds(priceFeeds).queryPrecision(\\n loanParamsLocal.collateralToken,\\n loanParamsLocal.loanToken\\n );\\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\\n loanLocal.startRate = isTorqueLoan\\n ? collateralToLoanRate\\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\\n }\\n\\n _emitOpeningEvents(\\n loanParamsLocal,\\n loanLocal,\\n sentAddresses,\\n sentValues,\\n collateralToLoanRate,\\n initialMargin,\\n isTorqueLoan\\n );\\n }\\n\\n /**\\n * @notice Emit the opening events.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param sentValues The values to send:\\n * interestRate: New loan interest rate.\\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\\n * collateralTokenSent: Total collateralToken deposit.\\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\\n * @param collateralToLoanRate The exchange rate from collateral to loan\\n * tokens.\\n * @param margin The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n * */\\n function _emitOpeningEvents(\\n LoanParams memory loanParamsLocal,\\n Loan memory loanLocal,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n MarginTradeStructHelpers.SentAmounts memory sentValues,\\n uint256 collateralToLoanRate,\\n uint256 margin,\\n bool isTorqueLoan\\n ) internal {\\n if (isTorqueLoan) {\\n emit Borrow(\\n sentAddresses.borrower, /// user (borrower)\\n sentAddresses.lender, /// lender\\n loanLocal.id, /// loanId\\n loanParamsLocal.loanToken, /// loanToken\\n loanParamsLocal.collateralToken, /// collateralToken\\n sentValues.newPrincipal, /// newPrincipal\\n sentValues.collateralTokenSent, /// newCollateral\\n sentValues.interestRate, /// interestRate\\n sentValues.interestDuration, /// interestDuration\\n collateralToLoanRate, /// collateralToLoanRate,\\n margin /// currentMargin\\n );\\n } else {\\n /// currentLeverage = 100 / currentMargin\\n margin = SafeMath.div(10**38, margin);\\n\\n emit Trade(\\n sentAddresses.borrower, /// user (trader)\\n sentAddresses.lender, /// lender\\n loanLocal.id, /// loanId\\n loanParamsLocal.collateralToken, /// collateralToken\\n loanParamsLocal.loanToken, /// loanToken\\n sentValues.collateralTokenSent, /// positionSize\\n sentValues.newPrincipal, /// borrowedAmount\\n sentValues.interestRate, /// interestRate,\\n loanLocal.endTimestamp, /// settlementDate\\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\\n sentValues.entryLeverage, /// entryLeverage\\n margin /// currentLeverage\\n );\\n }\\n }\\n\\n /**\\n * @notice Set the delegated manager.\\n *\\n * @param loanId The ID of the loan. If 0, start a new loan.\\n * @param delegator The address of previous manager.\\n * @param delegated The address of the delegated manager.\\n * @param toggle The flag true/false for the delegated manager.\\n * */\\n function _setDelegatedManager(\\n bytes32 loanId,\\n address delegator,\\n address delegated,\\n bool toggle\\n ) internal {\\n delegatedManagers[loanId][delegated] = toggle;\\n\\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\\n }\\n\\n /**\\n * @notice Calculate whether the collateral is satisfied.\\n *\\n * @dev Basically check collateral + drawdown >= 98% of required.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param initialMargin The initial amount of margin.\\n * @param newCollateral The amount of new collateral.\\n * @param collateralAmountRequired The amount of required collateral.\\n * @param newPrincipal The amount to borrow.\\n *\\n * @return Whether the collateral is satisfied.\\n * */\\n function _isCollateralSatisfied(\\n LoanParams memory loanParamsLocal,\\n Loan memory loanLocal,\\n uint256 initialMargin,\\n uint256 newCollateral,\\n uint256 collateralAmountRequired,\\n uint256 newPrincipal\\n ) internal view returns (bool) {\\n /// Allow at most 2% under-collateralized.\\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\\n\\n if (newCollateral < collateralAmountRequired) {\\n /// Check that existing collateral is sufficient coverage.\\n if (loanLocal.collateral != 0) {\\n uint256 maxDrawdown =\\n IPriceFeeds(priceFeeds).getMaxDrawdown(\\n loanParamsLocal.loanToken,\\n loanParamsLocal.collateralToken,\\n loanLocal.principal.sub(newPrincipal), // sub(newPrincipal) to exclude the new borrowed amount from the total principal to calculate maxDrawdown for existing loan\\n loanLocal.collateral,\\n initialMargin\\n );\\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\\n } else {\\n return false;\\n }\\n }\\n return true;\\n }\\n\\n /**\\n * @notice Initialize a loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanId The ID of the loan.\\n * @param initialMargin The amount of margin of the trade.\\n * @param sentAddresses The addresses to send tokens: lender, borrower,\\n * receiver and manager:\\n * lender: must match loan if loanId provided.\\n * borrower: must match loan if loanId provided.\\n * receiver: receiver of funds (address(0) assumes borrower address).\\n * manager: delegated manager of loan unless address(0).\\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\\n * @return The loanId.\\n * */\\n function _initializeLoan(\\n LoanParams memory loanParamsLocal,\\n bytes32 loanId,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\\n uint256 newPrincipal\\n ) internal returns (bytes32) {\\n require(loanParamsLocal.active, \\\"loanParams disabled\\\");\\n\\n address lender = sentAddresses.lender;\\n address borrower = sentAddresses.borrower;\\n address manager = sentAddresses.manager;\\n\\n Loan memory loanLocal;\\n\\n if (loanId == 0) {\\n borrowerNonce[borrower]++;\\n loanId = keccak256(\\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\\n );\\n require(loans[loanId].id == 0, \\\"loan exists\\\");\\n\\n loanLocal = Loan({\\n id: loanId,\\n loanParamsId: loanParamsLocal.id,\\n pendingTradesId: 0,\\n active: true,\\n principal: newPrincipal,\\n collateral: 0, /// calculated later\\n startTimestamp: block.timestamp,\\n endTimestamp: 0, /// calculated later\\n startMargin: initialMargin,\\n startRate: 0, /// queried later\\n borrower: borrower,\\n lender: lender\\n });\\n\\n activeLoansSet.addBytes32(loanId);\\n lenderLoanSets[lender].addBytes32(loanId);\\n borrowerLoanSets[borrower].addBytes32(loanId);\\n } else {\\n loanLocal = loans[loanId];\\n require(\\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\\n \\\"loan has ended\\\"\\n );\\n require(loanLocal.borrower == borrower, \\\"borrower mismatch\\\");\\n require(loanLocal.lender == lender, \\\"lender mismatch\\\");\\n require(loanLocal.loanParamsId == loanParamsLocal.id, \\\"loanParams mismatch\\\");\\n\\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\\n }\\n\\n if (manager != address(0)) {\\n _setDelegatedManager(loanId, borrower, manager, true);\\n }\\n\\n loans[loanId] = loanLocal;\\n\\n return loanId;\\n }\\n\\n /**\\n * @notice Initialize a loan interest.\\n *\\n * @dev A Torque loan is an indefinite-term loan.\\n *\\n * @param loanParamsLocal The loan parameters.\\n * @param loanLocal The loan object.\\n * @param newRate The new interest rate of the loan.\\n * @param newPrincipal The new principal amount of the loan.\\n * @param torqueInterest The interest rate of the Torque loan.\\n *\\n * @return interestAmountRequired The interest amount required.\\n * */\\n function _initializeInterest(\\n LoanParams memory loanParamsLocal,\\n Loan storage loanLocal,\\n uint256 newRate,\\n uint256 newPrincipal,\\n uint256 torqueInterest /// ignored for fixed-term loans\\n ) internal returns (uint256 interestAmountRequired) {\\n /// Pay outstanding interest to lender.\\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\\n\\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\\n LenderInterest storage lenderInterestLocal =\\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\\n\\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\\n\\n _settleFeeRewardForInterestExpense(\\n loanInterestLocal,\\n loanLocal.id,\\n loanParamsLocal.loanToken, /// fee token\\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n loanLocal.borrower,\\n block.timestamp\\n );\\n\\n uint256 previousDepositRemaining;\\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\\n previousDepositRemaining = loanLocal\\n .endTimestamp\\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\\n .mul(loanInterestLocal.owedPerDay)\\n .div(86400);\\n }\\n\\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\\n\\n /// Update stored owedPerDay\\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\\n\\n if (maxLoanTerm == 0) {\\n /// Indefinite-term (Torque) loan.\\n\\n /// torqueInterest != 0 was confirmed earlier.\\n loanLocal.endTimestamp = torqueInterest\\n .add(previousDepositRemaining)\\n .mul(86400)\\n .div(loanInterestLocal.owedPerDay)\\n .add(block.timestamp);\\n\\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\\n\\n /// Loan term has to at least be greater than one hour.\\n require(maxLoanTerm > 3600, \\\"loan too short\\\");\\n\\n interestAmountRequired = torqueInterest;\\n } else {\\n /// Fixed-term loan.\\n\\n if (loanLocal.endTimestamp == 0) {\\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\\n }\\n\\n interestAmountRequired = loanLocal\\n .endTimestamp\\n .sub(block.timestamp)\\n .mul(owedPerDay)\\n .div(86400);\\n }\\n\\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\\n interestAmountRequired\\n );\\n\\n /// Update remaining lender interest values.\\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\\n }\\n\\n /**\\n * @notice Get the required collateral.\\n *\\n * @dev Basically collateral = newPrincipal * marginAmount\\n *\\n * @param loanToken The loan token instance address.\\n * @param collateralToken The collateral token instance address.\\n * @param newPrincipal The updated amount of principal (current debt).\\n * @param marginAmount The amount of margin of the trade.\\n * @param isTorqueLoan Whether the loan is a Torque loan.\\n *\\n * @return collateralTokenAmount The required collateral.\\n * */\\n function _getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) internal view returns (uint256 collateralTokenAmount) {\\n if (loanToken == collateralToken) {\\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\\n } else {\\n /// Using the price feed instead of the swap expected return\\n /// because we need the rate in the inverse direction\\n /// so the swap is probably farther off than the price feed.\\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\\n if (sourceToDestRate != 0) {\\n collateralTokenAmount = newPrincipal\\n .mul(sourceToDestPrecision)\\n .div(sourceToDestRate)\\n .mul(marginAmount)\\n .div(10**20);\\n /*TODO: review\\n\\t\\t\\t\\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\\n }\\n }\\n // ./tests/loan-token/TradingTestToken.test.js\\n if (isTorqueLoan && collateralTokenAmount != 0) {\\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\\n collateralTokenAmount\\n );\\n }\\n }\\n}\\n\",\"keccak256\":\"0x1c2eb82f702d37c72c7fbc8bd9bf1ded7c880ac643a6b8e0d85b39c0c2b790a9\"},\"contracts/modules/interfaces/ProtocolAffiliatesInterface.sol\":{\"content\":\"/**\\n * Copyright 2020, Denis Savelev. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface ProtocolAffiliatesInterface {\\n function setAffiliatesReferrer(address user, address referrer) external;\\n\\n function setUserNotFirstTradeFlag(address user_) external;\\n\\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address affiliate,\\n address trader,\\n address token,\\n uint256 amount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n}\\n\",\"keccak256\":\"0x42f259156db09a06e3dcdf0ab9c6774712616b35e6baff97999a2a534d1c9c64\"},\"contracts/openzeppelin/Address.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n codehash := extcodehash(account)\\n }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x23df48a01dbac9b25e86c9131174fb7752bbc7e741e63f1aa982de22e055ad54\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/openzeppelin/ReentrancyGuard.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @title Helps contracts guard against reentrancy attacks.\\n * @author Remco Bloemen , Eenae \\n * @dev If you mark a function `nonReentrant`, you should also\\n * mark it `external`.\\n */\\ncontract ReentrancyGuard {\\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\\n\\n /// @dev Constant for locked guard state\\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\\n\\n /**\\n * @dev We use a single lock for the whole contract.\\n */\\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * If you mark a function `nonReentrant`, you should also\\n * mark it `external`. Calling one `nonReentrant` function from\\n * another is not supported. Instead, you can implement a\\n * `private` function doing the actual work, and an `external`\\n * wrapper marked as `nonReentrant`.\\n */\\n modifier nonReentrant() {\\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \\\"nonReentrant\\\");\\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\\n _;\\n reentrancyLock = REENTRANCY_GUARD_FREE;\\n }\\n}\\n\",\"keccak256\":\"0xd347de96ad57d1e45b07a2efe3050c1bd4b809236bbf354acb593de56d21a5c9\"},\"contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./Address.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\\n );\\n }\\n\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance =\\n token.allowance(address(this), spender).sub(\\n value,\\n \\\"SafeERC20: decreased allowance below zero\\\"\\n );\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) {\\n // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe99b4d979cb976a6b70e297600242afe38b8cd8f1b1ba6ee373f39f7abb3ca79\"},\"contracts/openzeppelin/SafeMath.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\\n return divCeil(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n\\n if (a == 0) {\\n return 0;\\n }\\n uint256 c = ((a - 1) / b) + 1;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n\\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n return _a < _b ? _a : _b;\\n }\\n}\\n\",\"keccak256\":\"0xbff8d6273e1a6870d1a142c0c23acd63a4dd47760f250390f49ee56333bcb6e8\"},\"contracts/reentrancy/Mutex.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/*\\n * @title Global Mutex contract\\n *\\n * @notice A mutex contract that allows only one function to be called at a time out\\n * of a large set of functions. *Anyone* in the network can freely use any instance\\n * of this contract to add a universal mutex to any function in any contract.\\n */\\ncontract Mutex {\\n /*\\n * We use an uint to store the mutex state.\\n */\\n uint256 public value;\\n\\n /*\\n * @notice Increment the mutex state and return the new value.\\n *\\n * @dev This is the function that will be called by anyone to change the mutex\\n * state. It is purposely not protected by any access control\\n */\\n function incrementAndGetValue() external returns (uint256) {\\n /*\\n * increment value using unsafe math. This is safe because we are\\n * pretty certain no one will ever increment the value 2^256 times\\n * in a single transaction.\\n */\\n return ++value;\\n }\\n}\\n\",\"keccak256\":\"0xd10b0fd07d5fed1ae1237e7c87e6501970fce2a86e2b8862e502258b0d3aeb2c\"},\"contracts/reentrancy/SharedReentrancyGuard.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./Mutex.sol\\\";\\n\\n/*\\n * @title Abstract contract for shared reentrancy guards\\n *\\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\\n * that there's no reentrancy between *any* functions marked with the modifier.\\n *\\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\\n */\\ncontract SharedReentrancyGuard {\\n /*\\n * This is the address of the mutex contract that will be used as the\\n * reentrancy guard.\\n *\\n * The address is hardcoded to avoid changing the memory layout of\\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\\n * because the Mutex contract is always deployed to the same address, with the\\n * same method used in the deployment of ERC1820Registry.\\n */\\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\\n\\n /*\\n * This is the modifier that will be used to protect functions from\\n * reentrancy. It will call the mutex contract to increment the mutex\\n * state and then revert if the mutex state was changed by another\\n * nested call.\\n */\\n modifier globallyNonReentrant() {\\n uint256 previous = MUTEX.incrementAndGetValue();\\n\\n _;\\n\\n /*\\n * If the mutex state was changed by a nested function call, then\\n * the value of the state variable will be different from the previous value.\\n */\\n require(previous == MUTEX.value(), \\\"reentrancy violation\\\");\\n }\\n}\\n\",\"keccak256\":\"0x2d0e61b104b91c1764f20fbeb381ba0f8a8889934ba7f6e8a167ed542ec2c124\"},\"contracts/swaps/SwapsUser.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../mixins/FeesHelper.sol\\\";\\nimport \\\"./connectors/SwapsImplSovrynSwapLib.sol\\\";\\n\\n/**\\n * @title Perform token swaps for loans and trades.\\n * */\\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\\n /**\\n * @notice Internal loan swap.\\n *\\n * @param loanId The ID of the loan.\\n * @param sourceToken The address of the source tokens.\\n * @param destToken The address of destination tokens.\\n * @param user The user address.\\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\\n * @param requiredDestTokenAmount The required amount of destination tokens.\\n * @param bypassFee To bypass or not the fee.\\n * @param loanDataBytes The payload for the call. These loan DataBytes are\\n * additional loan data (not in use for token swaps).\\n *\\n * @return destTokenAmountReceived\\n * @return sourceTokenAmountUsed\\n * @return sourceToDestSwapRate\\n * */\\n function _loanSwap(\\n bytes32 loanId,\\n address sourceToken,\\n address destToken,\\n address user,\\n uint256 minSourceTokenAmount,\\n uint256 maxSourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n bool bypassFee,\\n bytes memory loanDataBytes\\n )\\n internal\\n returns (\\n uint256 destTokenAmountReceived,\\n uint256 sourceTokenAmountUsed,\\n uint256 sourceToDestSwapRate\\n )\\n {\\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\\n [\\n sourceToken,\\n destToken,\\n address(this), // receiver\\n address(this), // returnToSender\\n user\\n ],\\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\\n loanId,\\n bypassFee,\\n loanDataBytes,\\n false // swap external flag, set to false so that it will use the tradingFeePercent\\n );\\n\\n /// Will revert if swap size too large.\\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\\n\\n /// Will revert if disagreement found.\\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\\n sourceToken,\\n destToken,\\n sourceTokenAmountUsed,\\n destTokenAmountReceived,\\n maxDisagreement\\n );\\n\\n emit LoanSwap(\\n loanId,\\n sourceToken,\\n destToken,\\n user,\\n sourceTokenAmountUsed,\\n destTokenAmountReceived\\n );\\n }\\n\\n /**\\n * @notice Calculate amount of source and destination tokens.\\n *\\n * @dev Wrapper for _swapsCall_internal function.\\n *\\n * @param addrs The array of addresses.\\n * @param vals The array of values.\\n * @param loanId The Id of the associated loan.\\n * @param miscBool True/false to bypassFee.\\n * @param loanDataBytes Additional loan data (not in use yet).\\n *\\n * @return destTokenAmountReceived The amount of destination tokens received.\\n * @return sourceTokenAmountUsed The amount of source tokens used.\\n * */\\n function _swapsCall(\\n address[5] memory addrs,\\n uint256[3] memory vals,\\n bytes32 loanId,\\n bool miscBool, /// bypassFee\\n bytes memory loanDataBytes,\\n bool isSwapExternal\\n ) internal returns (uint256, uint256) {\\n /// addrs[0]: sourceToken\\n /// addrs[1]: destToken\\n /// addrs[2]: receiver\\n /// addrs[3]: returnToSender\\n /// addrs[4]: user\\n /// vals[0]: minSourceTokenAmount\\n /// vals[1]: maxSourceTokenAmount\\n /// vals[2]: requiredDestTokenAmount\\n\\n require(vals[0] != 0 || vals[1] != 0, \\\"min or max source token amount needs to be set\\\");\\n\\n if (vals[1] == 0) {\\n vals[1] = vals[0];\\n }\\n require(vals[0] <= vals[1], \\\"sourceAmount larger than max\\\");\\n\\n uint256 destTokenAmountReceived;\\n uint256 sourceTokenAmountUsed;\\n\\n uint256 tradingFee;\\n if (!miscBool) {\\n /// bypassFee\\n if (vals[2] == 0) {\\n /// condition: vals[0] will always be used as sourceAmount\\n\\n if (isSwapExternal) {\\n tradingFee = _getSwapExternalFee(vals[0]);\\n } else {\\n tradingFee = _getTradingFee(vals[0]);\\n }\\n\\n if (tradingFee != 0) {\\n _payTradingFee(\\n addrs[4], /// user\\n loanId,\\n addrs[0], /// sourceToken (feeToken)\\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n tradingFee\\n );\\n\\n vals[0] = vals[0].sub(tradingFee);\\n }\\n } else {\\n /// Condition: unknown sourceAmount will be used.\\n\\n if (isSwapExternal) {\\n tradingFee = _getSwapExternalFee(vals[2]);\\n } else {\\n tradingFee = _getTradingFee(vals[2]);\\n }\\n\\n if (tradingFee != 0) {\\n vals[2] = vals[2].add(tradingFee);\\n }\\n }\\n }\\n\\n require(loanDataBytes.length == 0, \\\"invalid state\\\");\\n\\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\\n\\n if (vals[2] == 0) {\\n /// There's no minimum destTokenAmount, but all of vals[0]\\n /// (minSourceTokenAmount) must be spent.\\n require(sourceTokenAmountUsed == vals[0], \\\"swap too large to fill\\\");\\n\\n if (tradingFee != 0) {\\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\\n }\\n } else {\\n /// There's a minimum destTokenAmount required, but\\n /// sourceTokenAmountUsed won't be greater\\n /// than vals[1] (maxSourceTokenAmount)\\n require(sourceTokenAmountUsed <= vals[1], \\\"swap fill too large\\\");\\n require(destTokenAmountReceived >= vals[2], \\\"insufficient swap liquidity\\\");\\n\\n if (tradingFee != 0) {\\n _payTradingFee(\\n addrs[4], /// user\\n loanId, /// loanId,\\n addrs[1], /// destToken (feeToken)\\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\\n tradingFee\\n );\\n\\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\\n }\\n }\\n\\n return (destTokenAmountReceived, sourceTokenAmountUsed);\\n }\\n\\n /**\\n * @notice Calculate amount of source and destination tokens.\\n *\\n * @dev Calls swapsImpl::internalSwap\\n *\\n * @param addrs The array of addresses.\\n * @param vals The array of values.\\n *\\n * @return destTokenAmountReceived The amount of destination tokens received.\\n * @return sourceTokenAmountUsed The amount of source tokens used.\\n * */\\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\\n internal\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n SwapsImplSovrynSwapLib.SwapParams memory swapParams;\\n\\n swapParams.sourceTokenAddress = addrs[0];\\n swapParams.destTokenAddress = addrs[1];\\n swapParams.receiverAddress = addrs[2];\\n swapParams.returnToSenderAddress = addrs[3];\\n swapParams.minSourceTokenAmount = vals[0];\\n swapParams.maxSourceTokenAmount = vals[1];\\n swapParams.requiredDestTokenAmount = vals[2];\\n\\n (destTokenAmountReceived, sourceTokenAmountUsed) = SwapsImplSovrynSwapLib.swap(swapParams);\\n }\\n\\n /**\\n * @notice Calculate expected amount of destination tokens.\\n *\\n * @dev Calls swapsImpl::internalExpectedReturn\\n *\\n * @param sourceToken The address of the source tokens.\\n * @param destToken The address of the destination tokens.\\n * @param sourceTokenAmount The amount of the source tokens.\\n *\\n * @param destTokenAmount The amount of destination tokens.\\n * */\\n function _swapsExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) internal view returns (uint256 destTokenAmount) {\\n destTokenAmount = SwapsImplSovrynSwapLib.getExpectedReturn(\\n sourceToken,\\n destToken,\\n sourceTokenAmount\\n );\\n }\\n\\n /**\\n * @notice Verify that the amount of tokens are under the swap limit.\\n *\\n * @dev Calls priceFeeds::amountInEth\\n *\\n * @param tokenAddress The address of the token to calculate price.\\n * @param amount The amount of tokens to calculate price.\\n * */\\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\\n uint256 _maxSwapSize = maxSwapSize;\\n if (_maxSwapSize != 0) {\\n uint256 amountInEth;\\n if (tokenAddress == address(wrbtcToken)) {\\n amountInEth = amount;\\n } else {\\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\\n }\\n require(amountInEth <= _maxSwapSize, \\\"swap too large\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0x7dfc45e91455458caf886b49c96ad426de06cddffa442c16628eba4974f3d323\"},\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":{\"content\":\"pragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"./interfaces/ISovrynSwapNetwork.sol\\\";\\nimport \\\"./interfaces/IContractRegistry.sol\\\";\\nimport \\\"../../interfaces/ISovryn.sol\\\";\\n\\n/**\\n * @title Swaps Implementation Sovryn contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the implementation of swap process and rate\\n * calculations for Sovryn network.\\n * */\\nlibrary SwapsImplSovrynSwapLib {\\n using SafeMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n struct SwapParams {\\n address sourceTokenAddress;\\n address destTokenAddress;\\n address receiverAddress;\\n address returnToSenderAddress;\\n uint256 minSourceTokenAmount;\\n uint256 maxSourceTokenAmount;\\n uint256 requiredDestTokenAmount;\\n }\\n\\n /// bytes32 contractName = hex\\\"42616e636f724e6574776f726b\\\"; /// \\\"SovrynSwapNetwork\\\"\\n\\n /**\\n * Get the hex name of a contract.\\n * @param source The name of the contract.\\n * */\\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\\n assembly {\\n result := mload(add(source, 32))\\n }\\n }\\n\\n /**\\n * Look up the Sovryn swap network contract registered at the given address.\\n * @param sovrynSwapRegistryAddress The address of the registry.\\n * */\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (ISovrynSwapNetwork)\\n {\\n /// State variable sovrynSwapContractRegistryAddress is part of\\n /// State.sol and set in ProtocolSettings.sol and this function\\n /// needs to work without delegate call as well -> therefore pass it.\\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\\n return\\n ISovrynSwapNetwork(\\n contractRegistry.addressOf(getContractHexName(\\\"SovrynSwapNetwork\\\"))\\n );\\n }\\n\\n /**\\n * Swap the source token for the destination token on the oracle based AMM.\\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\\n * -> swap the minSourceTokenAmount\\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\\n * -> same as on rollover. minimum amount is not considered at all.\\n *\\n * @param params SwapParams struct\\n * sourceTokenAddress The address of the source tokens.\\n * destTokenAddress The address of the destination tokens.\\n * receiverAddress The address who will received the swap token results\\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\\n * requiredDestTokenAmount The required amount of destination tokens.\\n * */\\n function swap(SwapParams memory params)\\n public\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n require(params.sourceTokenAddress != params.destTokenAddress, \\\"source == dest\\\");\\n\\n ISovryn iSovryn = ISovryn(address(this));\\n require(\\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\\n iSovryn.supportedTokens(params.destTokenAddress),\\n \\\"invalid tokens\\\"\\n );\\n\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\\n\\n IERC20[] memory path =\\n _getConversionPath(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n sovrynSwapNetwork\\n );\\n\\n uint256 minReturn = 1;\\n sourceTokenAmountUsed = params.minSourceTokenAmount;\\n\\n /// If the required amount of destination tokens is passed, we need to\\n /// calculate the estimated amount of source tokens regardless of the\\n /// minimum source token amount (name is misleading).\\n if (params.requiredDestTokenAmount > 0) {\\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n params.requiredDestTokenAmount,\\n params.maxSourceTokenAmount\\n );\\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\\n require(\\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\\n params.requiredDestTokenAmount,\\n \\\"insufficient source tokens provided.\\\"\\n );\\n minReturn = params.requiredDestTokenAmount;\\n }\\n\\n require(sourceTokenAmountUsed > 0, \\\"cannot swap 0 tokens\\\");\\n\\n _allowTransfer(\\n sourceTokenAmountUsed,\\n params.sourceTokenAddress,\\n address(sovrynSwapNetwork)\\n );\\n\\n /// @dev Note: the kyber connector uses .call() to interact with kyber\\n /// to avoid bubbling up. here we allow bubbling up.\\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\\n path,\\n sourceTokenAmountUsed,\\n minReturn,\\n params.receiverAddress,\\n address(0),\\n 0\\n );\\n\\n /// If the sender is not the protocol (calling with delegatecall),\\n /// return the remainder to the specified address.\\n /// @dev Note: for the case that the swap is used without the\\n /// protocol. Not sure if it should, though. needs to be discussed.\\n if (params.returnToSenderAddress != address(this)) {\\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\\n /// Send unused source token back.\\n IERC20(params.sourceTokenAddress).safeTransfer(\\n params.returnToSenderAddress,\\n params.maxSourceTokenAmount - sourceTokenAmountUsed\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Check whether the existing allowance suffices to transfer\\n * the needed amount of tokens.\\n * If not, allows the transfer of an arbitrary amount of tokens.\\n *\\n * @param tokenAmount The amount to transfer.\\n * @param tokenAddress The address of the token to transfer.\\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\\n * */\\n function _allowTransfer(\\n uint256 tokenAmount,\\n address tokenAddress,\\n address sovrynSwapNetwork\\n ) internal {\\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\\n if (tempAllowance < tokenAmount) {\\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\\n }\\n }\\n\\n /**\\n * @notice Calculate the number of source tokens to provide in order to\\n * obtain the required destination amount.\\n *\\n * @param sourceTokenAddress The address of the source token address.\\n * @param destTokenAddress The address of the destination token address.\\n * @param requiredDestTokenAmount The number of destination tokens needed.\\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\\n *\\n * @return The estimated amount of source tokens needed.\\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\\n * */\\n function _estimateSourceTokenAmount(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 requiredDestTokenAmount,\\n uint256 maxSourceTokenAmount\\n ) internal view returns (uint256 estimatedSourceAmount) {\\n ISovryn iSovryn = ISovryn(address(this));\\n uint256 sourceToDestPrecision =\\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\\n\\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\\n uint256 expectedRate =\\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\\n\\n /// Compute the source tokens needed to get the required amount with the worst case rate.\\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\\n expectedRate\\n );\\n\\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\\n uint256 buffer = estimatedSourceAmount.div(1000);\\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\\n\\n /// Never spend more than the maximum.\\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\\n return maxSourceTokenAmount;\\n }\\n\\n /**\\n * @notice Get the expected rate for 1 source token when exchanging the\\n * given amount of source tokens.\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\\n * */\\n function getExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n\\n /// Return the rate for 1 token with 18 decimals.\\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\\n }\\n\\n /**\\n * @notice Get the expected return amount when exchanging the given\\n * amount of source tokens.\\n *\\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the return for.\\n * */\\n function getExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256 expectedReturn) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n }\\n\\n function _getConversionPath(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n ISovrynSwapNetwork sovrynSwapNetwork\\n ) private view returns (IERC20[] memory path) {\\n IERC20[] memory _defaultPathConversion =\\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\\n\\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\\n path = _defaultPathConversion.length >= 3\\n ? _defaultPathConversion\\n : sovrynSwapNetwork.conversionPath(\\n IERC20(sourceTokenAddress),\\n IERC20(destTokenAddress)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x058b8d733422a2421f17d1b159aed69f151ea8d5f48ee507bac5b4e86add8b0c\"},\"contracts/swaps/connectors/interfaces/IContractRegistry.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\ncontract IContractRegistry {\\n function addressOf(bytes32 contractName) public view returns (address);\\n}\\n\",\"keccak256\":\"0x793c4eefa2ee04cbf0a1a9da28676ac310ed7bf60a27ec7d86de7d7236ccf45b\"},\"contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol\":{\"content\":\"pragma solidity >=0.5.8 <=0.5.17;\\n\\nimport \\\"../../../interfaces/IERC20.sol\\\";\\n\\ncontract ISovrynSwapNetwork {\\n function convertByPath(\\n IERC20[] calldata _path,\\n uint256 _amount,\\n uint256 _minReturn,\\n address _beneficiary,\\n address _affiliateAccount,\\n uint256 _affiliateFee\\n ) external payable returns (uint256);\\n\\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\\n\\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\\n external\\n view\\n returns (IERC20[] memory);\\n}\\n\",\"keccak256\":\"0xcd28e146b77183bff18f78b511912f7ebe60d437430fdaa72ed145fdda61a5ad\"}},\"version\":1}", + "bytecode": "0x60806040526001600055678ac7230489e80000601555670214e8348c4f000060185567013fbe85edc90000601b55674563918244f40000602055674563918244f40000602155674563918244f400006027556127106028556802b5e3af16b1880000602955650f478e084000602b5567016345785d8a0000602c556802b5e3af16b1880000602f5560036035556801158e460913d00000603955348015620000a657600080fd5b506000620000bc6001600160e01b036200011016565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35062000114565b3390565b61512680620001246000396000f3fe6080604052600436106103815760003560e01c80638f32d59b116101d1578063cd5d808d11610102578063e8f62764116100a0578063f589a3e71161006f578063f589a3e714610a05578063f6ddc8b314610a1a578063f706b1f214610a2f578063f851a44014610a4457610381565b8063e8f62764146109a6578063edab119f146109bb578063f0e085f5146109d0578063f2fde38b146109e557610381565b8063d485045e116100dc578063d485045e14610925578063d67f707714610945578063d84ca25414610965578063e762319f1461098657610381565b8063cd5d808d146108db578063d288208c146108fb578063d473c2da1461091057610381565b8063b7e152411161016f578063bdee453c11610149578063bdee453c1461082f578063c4a908151461084f578063c4d66de814610887578063cb6eacd1146108a757610381565b8063b7e15241146107e5578063b9cffa3e14610805578063ba4861e91461081a57610381565b8063acc04348116101ab578063acc0434814610779578063ae0a85301461078e578063afe84009146107a3578063b30643d9146107c557610381565b80638f32d59b1461072f57806392d894f814610744578063959083d31461076457610381565b80634203e395116102b65780636e663730116102545780637a8faeb8116102235780637a8faeb8146106d05780638456cb59146106e55780638da5cb5b146106fa5780638dc48ba51461070f57610381565b80636e663730146106715780637420ca3e14610691578063742e6798146106a657806378d849ed146106bb57610381565b8063569fc1fb11610290578063569fc1fb146105dc578063574442cc1461060b57806362fff3f61461062057806368c4ac261461065157610381565b80634203e395146105925780634699f846146105b25780634f28cac2146105c757610381565b80632a324027116103235780633432423c116102fd5780633432423c146105125780633452d2d4146105325780633fca506e146105525780634115a2b61461057257610381565b80632a324027146104c65780632f470764146104db57806333d8991f146104f057610381565b80631b7bde741161035f5780631b7bde741461042c578063218b39c61461045957806324cc57491461047957806325decac0146104a657610381565b8063065d810f146103af5780630676c1b7146103ea57806317548b791461040c575b34801561038d57600080fd5b5060405162461bcd60e51b81526004016103a690614eaa565b60405180910390fd5b3480156103bb57600080fd5b506103cf6103ca366004613f1e565b610a59565b6040516103e196959493929190614f9d565b60405180910390f35b3480156103f657600080fd5b506103ff610a99565b6040516103e191906149d4565b34801561041857600080fd5b506103ff6104273660046140b1565b610aa8565b34801561043857600080fd5b5061044c610447366004613de8565b610ac3565b6040516103e19190614f58565b34801561046557600080fd5b506103ff610474366004613dca565b610ae0565b34801561048557600080fd5b50610499610494366004613dca565b610afb565b6040516103e19190614bf7565b3480156104b257600080fd5b5061044c6104c1366004613e22565b610b10565b3480156104d257600080fd5b5061044c610b6b565b3480156104e757600080fd5b5061044c610b71565b3480156104fc57600080fd5b5061051061050b366004613fa9565b610b77565b005b34801561051e57600080fd5b506103cf61052d366004613f1e565b610be4565b34801561053e57600080fd5b5061044c61054d366004613dca565b610c24565b34801561055e57600080fd5b5061044c61056d366004613dca565b610c36565b34801561057e57600080fd5b5061049961058d366004613f8a565b610c48565b34801561059e57600080fd5b5061044c6105ad366004613dca565b610c68565b3480156105be57600080fd5b5061044c610c7a565b3480156105d357600080fd5b5061044c610c80565b3480156105e857600080fd5b506105fc6105f7366004613f6c565b610c86565b6040516103e193929190614f74565b34801561061757600080fd5b5061044c610ca7565b34801561062c57600080fd5b5061064061063b366004613de8565b610cad565b6040516103e1959493929190614f82565b34801561065d57600080fd5b5061049961066c366004613dca565b610ce7565b34801561067d57600080fd5b506103ff61068c366004613dca565b610cfc565b34801561069d57600080fd5b506103ff610d17565b3480156106b257600080fd5b5061044c610d26565b3480156106c757600080fd5b506103ff610d2c565b3480156106dc57600080fd5b5061044c610d3b565b3480156106f157600080fd5b50610499610d41565b34801561070657600080fd5b506103ff610d4a565b34801561071b57600080fd5b506103ff61072a366004613dca565b610d59565b34801561073b57600080fd5b50610499610d74565b34801561075057600080fd5b5061044c61075f366004613dca565b610d9a565b34801561077057600080fd5b5061044c610dac565b34801561078557600080fd5b5061044c610db2565b34801561079a57600080fd5b5061044c610db8565b3480156107af57600080fd5b506107b8610dbe565b6040516103e19190614cfb565b3480156107d157600080fd5b5061044c6107e0366004613dca565b610dcd565b3480156107f157600080fd5b5061044c610800366004613dca565b610ddf565b34801561081157600080fd5b506103ff610df1565b34801561082657600080fd5b506103ff610e00565b34801561083b57600080fd5b5061044c61084a366004613dca565b610e0f565b34801561085b57600080fd5b5061086f61086a366004613f6c565b610e21565b6040516103e19c9b9a99989796959493929190614c48565b34801561089357600080fd5b506105106108a2366004613dca565b610e93565b3480156108b357600080fd5b506108c76108c2366004613f6c565b610f96565b6040516103e1989796959493929190614c05565b3480156108e757600080fd5b5061044c6108f6366004613de8565b610fe8565b34801561090757600080fd5b506103ff611005565b34801561091c57600080fd5b5061044c611014565b34801561093157600080fd5b5061044c610940366004613dca565b61101a565b34801561095157600080fd5b5061044c610960366004613e97565b61102c565b610978610973366004613ff6565b6110fa565b6040516103e1929190614f66565b34801561099257600080fd5b5061044c6109a1366004613e22565b6112fa565b3480156109b257600080fd5b506103ff61146e565b3480156109c757600080fd5b5061044c61147d565b3480156109dc57600080fd5b5061044c611483565b3480156109f157600080fd5b50610510610a00366004613dca565b611489565b348015610a1157600080fd5b5061044c6114b9565b348015610a2657600080fd5b5061044c6114bf565b348015610a3b57600080fd5b506103ff6114c5565b348015610a5057600080fd5b506103ff6114d4565b6009602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b6031546001600160a01b031681565b6005602052600090815260409020546001600160a01b031681565b603b60209081526000928352604080842090915290825290205481565b6023602052600090815260409020546001600160a01b031681565b60326020526000908152604090205460ff1681565b60008215610b6257610b2586868686866114e3565b9050600082610b3c57610b378261161c565b610b45565b610b4582611652565b90508015610b6057610b5d828263ffffffff61167616565b91505b505b95945050505050565b60185481565b601f5481565b603d5460ff1615610b9a5760405162461bcd60e51b81526004016103a690614d2a565b6000838152600660205260409020600a01546001600160a01b03163314610bd35760405162461bcd60e51b81526004016103a690614e6a565b610bdf833384846116a2565b505050565b6008602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b601a6020526000908152604090205481565b602a6020526000908152604090205481565b600a60209081526000928352604080842090915290825290205460ff1681565b60166020526000908152604090205481565b60155481565b60295481565b600c6020526000908152604090208054600182015460029092015490919083565b602b5481565b600b602090815260009283526040808420909152908252902080546001820154600283015460038401546004909401549293919290919085565b60266020526000908152604090205460ff1681565b6033602052600090815260409020546001600160a01b031681565b6003546001600160a01b031681565b60355481565b6002546001600160a01b031681565b601e5481565b603d5460ff1681565b6001546001600160a01b031690565b6022602052600090815260409020546001600160a01b031681565b6001546000906001600160a01b0316610d8b611717565b6001600160a01b031614905090565b60176020526000908152604090205481565b602c5481565b602f5481565b60205481565b602d546001600160a01b031681565b601d6020526000908152604090205481565b601c6020526000908152604090205481565b6037546001600160a01b031681565b6004546001600160a01b031681565b60366020526000908152604090205481565b600660208190526000918252604090912080546001820154600283015460038401546004850154600586015496860154600787015460088801546009890154600a8a0154600b909a0154989a9799969860ff909616979496949593949293919290916001600160a01b0391821691168c565b610e9b610d74565b610eb75760405162461bcd60e51b81526004016103a690614e6a565b633613289560e21b600081905260056020527fd3a886345208a8e3a0f774019653c4e69589e943ba1e46c7fa0ef875651e6e39546001600160a01b031690610eff908361171b565b610f106333d8991f60e01b8361171b565b610f2163d67f707760e01b8361171b565b610f3162977b2b60e61b8361171b565b610f4263e762319f60e01b8361171b565b6b4c6f616e4f70656e696e677360a01b826001600160a01b0316826001600160a01b03167f1420e3a2094d671bc2eb897941fa3d94ffa37f0cb6d530651946250a2151cb7f60405160405180910390a45050565b6007602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949560ff8516956101009095046001600160a01b03908116959481169493169288565b603c60209081526000928352604080842090915290825290205481565b6038546001600160a01b031681565b60275481565b60196020526000908152604090205481565b60006224ea008161105d6907baab4146b63dd00000611051868863ffffffff61179516565b9063ffffffff6117cf16565b9050600061107862015180611051858563ffffffff61179516565b9050600061108c898363ffffffff61181116565b905060006110998261161c565b905080156110b4576110b1828263ffffffff61181116565b91505b60006110c18d8d85611853565b9050806110d757600096505050505050506110f0565b6110e78a8263ffffffff61167616565b96505050505050505b9695505050505050565b60008060016000541461111f5760405162461bcd60e51b81526004016103a690614eda565b6002600055603d5460ff16156111475760405162461bcd60e51b81526004016103a690614d2a565b34158061115357508215155b61116f5760405162461bcd60e51b81526004016103a690614f0a565b336000908152602260205260409020546001600160a01b03166111a45760405162461bcd60e51b81526004016103a690614e4a565b6111ac613a9e565b5060008a815260076020908152604091829020825161010080820185528254808352600184015460ff811615159584019590955293046001600160a01b039081169482019490945260028201548416606082015260038201549093166080840152600481015460a0840152600581015460c08401526006015460e08301526112465760405162461bcd60e51b81526004016103a690614e9a565b60006112618260600151836080015189602001358c8e6114e3565b9050806112805760405162461bcd60e51b81526004016103a690614e3a565b6112e2828c8c848d611297368f90038f018f6140cf565b6112a6368f90038f018f6140ed565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118e992505050565b6001600055909d909c509a5050505050505050505050565b60008215610b62578115611324576113218368056bc75e2d6310000063ffffffff61167616565b92505b8360008361133a576113358261161c565b611343565b61134382611652565b9050801561135e5761135b828263ffffffff61181116565b91505b866001600160a01b0316886001600160a01b0316141561139c57611395856110518468056bc75e2d6310000063ffffffff61179516565b9250611463565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c906113d3908c908e906004016149e2565b604080518083038186803b1580156113ea57600080fd5b505afa1580156113fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611422919081019061412a565b91509150806000146114605761145d816110518981866114518a68056bc75e2d6310000063ffffffff61179516565b9063ffffffff61179516565b94505b50505b505095945050505050565b6014546001600160a01b031681565b601b5481565b60285481565b611491610d74565b6114ad5760405162461bcd60e51b81526004016103a690614e6a565b6114b681611be0565b50565b60395481565b60215481565b602e546001600160a01b031681565b6030546001600160a01b031681565b6000846001600160a01b0316866001600160a01b031614156115235761151c68056bc75e2d63100000611051868663ffffffff61179516565b90506115de565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c9061155a908a908c906004016149e2565b604080518083038186803b15801561157157600080fd5b505afa158015611585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115a9919081019061412a565b91509150816000146115db576115d868056bc75e2d631000006110518761145186838c8863ffffffff61179516565b92505b50505b8180156115ea57508015155b15610b62576110f081611610856110518368056bc75e2d6310000063ffffffff61179516565b9063ffffffff61167616565b600061164c68056bc75e2d631000006116406018548561179590919063ffffffff16565b9063ffffffff611c6216565b92915050565b600061164c68056bc75e2d63100000611640601b548561179590919063ffffffff16565b60008282018381101561169b5760405162461bcd60e51b81526004016103a690614d8a565b9392505050565b6000848152600a602090815260408083206001600160a01b038681168086529190935292819020805460ff1916851515179055519085169086907f0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c9843390611709908690614bf7565b60405180910390a450505050565b3390565b6001600160e01b03198216600090815260056020526040902080546001600160a01b0319166001600160a01b0383169081179091551561177657611770600d6001600160e01b0319841663ffffffff611ca416565b50611791565b610bdf600d6001600160e01b0319841663ffffffff611cec16565b5050565b6000826117a45750600061164c565b828202828482816117b157fe5b041461169b5760405162461bcd60e51b81526004016103a690614e5a565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611dad565b600061169b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611de4565b604051636dcd64e560e01b815260009073a98f000a528AC0bFf10a3FE499378437de44965990636dcd64e59061189190879087908790600401614a32565b60206040518083038186803b1580156118a957600080fd5b505af41580156118bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118e1919081019061410c565b949350505050565b60008089606001516001600160a01b03168a608001516001600160a01b031614156119265760405162461bcd60e51b81526004016103a690614daa565b8960a0015186101561194a5760405162461bcd60e51b81526004016103a690614f2a565b60e08a015115158061195f5750604084015115155b61197b5760405162461bcd60e51b81526004016103a690614d4a565b60008861198957600061198f565b84602001515b90506000600660006119a88e8e8c8c8c60200151611e10565b8152602001908152602001600020905060006119d38d8389600001518a602001518b60400151612202565b60608801519091506119eb908263ffffffff61181116565b60608801528a15611a7b57606087015115611a185760405162461bcd60e51b81526004016103a690614e0a565b6000611a278860800151611652565b905060008e60800151905060008f60600151905082600014611a7357611a588b60200151866000015484848761241e565b60808a0151611a6d908463ffffffff61181116565b60808b01525b505050611a8b565b611a888c8e8a8a8a6124bd565b96505b60408051610180810182528354815260018401546020820152600284015491810191909152600383015460ff16151560608201526004830154608080830191909152600584015460a0830152600684015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b85015416610160830152880151611b35918f918c908e88612540565b611b515760405162461bcd60e51b81526004016103a690614e7a565b60808701516005830154611b6a9163ffffffff61167616565b60058301558a15611b94576007820154611b8a904263ffffffff61181116565b60e0880152611bb5565b611bae6f4b3b4ca85a86c47a098a2240000000008a6117cf565b6101008801525b611bc28d838a8a8f61265b565b86602001518760800151945094505050509850989650505050505050565b6001600160a01b038116611c065760405162461bcd60e51b81526004016103a690614d5a565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061292e565b6000611cb08383612978565b611ce4575060018083018054808301808355600092835260208084209092018590558483529085905260409091205561164c565b50600061164c565b6000611cf88383612978565b15611ce45760008281526020849052604090205460018401546000199182019101808214611d70576000856001018281548110611d3157fe5b9060005260206000200154905080866001018481548110611d4e57fe5b6000918252602080832090910192909255918252869052604090206001830190555b60008481526020869052604081205560018501805480611d8c57fe5b6001900381819060005260206000200160009055905560019250505061164c565b60008183611dce5760405162461bcd60e51b81526004016103a69190614d09565b506000838581611dda57fe5b0495945050505050565b60008184841115611e085760405162461bcd60e51b81526004016103a69190614d09565b505050900390565b60008560200151611e335760405162461bcd60e51b81526004016103a690614eca565b825160208401516060850151611e47613ae2565b88611f9e576001600160a01b0383166000908152602a60209081526040918290208054600101908190558c519251611e86939288928892909101614980565b60408051601f1981840301815291815281516020928301206000818152600690935291205490995015611ecb5760405162461bcd60e51b81526004016103a690614dfa565b5060408051610180810182528981528a5160208201526000918101829052600160608201526080810187905260a081018290524260c082015260e0810182905261010081018990526101208101919091526001600160a01b038084166101408301528416610160820152611f46600f8a63ffffffff611ca416565b506001600160a01b0384166000908152601160205260409020611f6f908a63ffffffff611ca416565b506001600160a01b0383166000908152601260205260409020611f98908a63ffffffff611ca416565b5061211f565b5060008881526006602081815260409283902083516101808101855281548152600182015492810192909252600281015493820193909352600383015460ff161580156060830181905260048501546080840152600585015460a08401529284015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b909401549093166101608201529161205857508060e0015142105b6120745760405162461bcd60e51b81526004016103a690614e1a565b826001600160a01b03168161014001516001600160a01b0316146120aa5760405162461bcd60e51b81526004016103a690614d7a565b836001600160a01b03168161016001516001600160a01b0316146120e05760405162461bcd60e51b81526004016103a690614dda565b89516020820151146121045760405162461bcd60e51b81526004016103a690614d1a565b6080810151612119908763ffffffff61167616565b60808201525b6001600160a01b0382161561213b5761213b89848460016116a2565b60008981526006602081815260409283902084518155908401516001820155918301516002830155606083015160038301805460ff19169115159190911790556080830151600483015560a0830151600583015560c08301519082015560e0820151600782015561010082015160088201556101208201516009820155610140820151600a820180546001600160a01b03199081166001600160a01b039384161790915561016090930151600b909201805490931691161790555095979650505050505050565b600b8401546060860151600091612224916001600160a01b039091169061298d565b84546000818152600c60209081526040808320600b808b01546001600160a01b03908116865290845282852060608d0180518316875294529190932060e08b0151925160808c0151600a8c0154959692956122859488949392911642612a6b565b6000811580156122985750600789015415155b156122c6576122c3620151806110518660000154611451428e6007015461181190919063ffffffff16565b90505b60006122e66907baab4146b63dd000006110518a8c63ffffffff61179516565b85549091506122fb908263ffffffff61167616565b85556001840154612312908263ffffffff61167616565b60018501558261238157845461233f90429061161090611051620151806114518d8963ffffffff61167616565b60078b01819055612356904263ffffffff61181116565b9250610e1083116123795760405162461bcd60e51b81526004016103a690614d9a565b8695506123c5565b60078a01546123a05761239a428463ffffffff61167616565b60078b01555b6123c26201518061105183611451428f6007015461181190919063ffffffff16565b95505b60018501546123da908763ffffffff61167616565b600186015583546123f1908963ffffffff61167616565b84556002840154612408908763ffffffff61167616565b8460020181905550505050505095945050505050565b80156124b6576001600160a01b0383166000908152601c602052604090205461244d908263ffffffff61167616565b6001600160a01b038085166000818152601c6020526040908190209390935591518692918816907ffb6c38ae4fdd498b3a5003f02ca4ca5340dfedb36b1b100c679eb60633b2c0a7906124a1908690614f58565b60405180910390a46124b68585858585612ab9565b5050505050565b6124c5613b46565b60006124ea87876060015188608001518860200151886060015160008060008b612f1f565b60c0870152506080850151909150612508908263ffffffff61167616565b608085015260a084015160c085015110156125355760405162461bcd60e51b81526004016103a690614d6a565b509195945050505050565b600061256868056bc75e2d631000006110518568055005f0c61448000063ffffffff61179516565b92508284101561264e5760a0860151156126465760025460608801516080808a0151908901516000936001600160a01b03169263f80b25fb9290916125b3908863ffffffff61181116565b8b60a001518b6040518663ffffffff1660e01b81526004016125d9959493929190614a82565b60206040518083038186803b1580156125f157600080fd5b505afa158015612605573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612629919081019061410c565b90508361263c868363ffffffff61167616565b10159150506110f0565b5060006110f0565b5060019695505050505050565b6002546060860151608087015160048088015460058901546040516317f8680960e11b815260009687966001600160a01b0390911695632ff0d012956126a5959294919301614a5a565b604080518083038186803b1580156126bc57600080fd5b505afa1580156126d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126f4919081019061412a565b915091508660c00151821161271b5760405162461bcd60e51b81526004016103a690614e8a565b4286600601541415612881576002546060880151608089015160405163524efd4b60e01b81526000936001600160a01b03169263524efd4b92612760926004016149e2565b60206040518083038186803b15801561277857600080fd5b505afa15801561278c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127b0919081019061410c565b60025460808a015160608b015160405163524efd4b60e01b81529394506000936001600160a01b039093169263524efd4b926127f09290916004016149e2565b60206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612840919081019061410c565b90506000612854838363ffffffff61179516565b9050856128765760c087015161287190829063ffffffff6117cf16565b612878565b835b60098a01555050505b60408051610180810182528754815260018801546020820152600288015491810191909152600387015460ff161515606082015260048701546080820152600587015460a0820152600687015460c0820152600787015460e082015260088701546101008201526009870154610120820152600a8701546001600160a01b03908116610140830152600b88015416610160820152612925908890878785878961307d565b50505050505050565b6000818361294f5760405162461bcd60e51b81526004016103a69190614d09565b508361295d5750600061169b565b600083600186038161296b57fe5b0460010195945050505050565b60009081526020919091526040902054151590565b6001600160a01b038083166000908152600b6020908152604080832093851683529290529081206001810154909190158015906129cd5750600482015415155b15612a5e576129f862015180611051846001015461145186600401544261181190919063ffffffff16565b4260048401556002830154909150811115612a14575060028101545b8015612a59576003820154612a2f908263ffffffff61167616565b60038301556002820154612a49908263ffffffff61181116565b6002830155612a598484836131b4565b612a65565b4260048301555b50505050565b6000612aa16a07259756a8d619980000006110516015546114518b600001546114518d600201548961181190919063ffffffff16565b60028801839055905080156129255761292583878787855b602f546002546001600160a01b038581166000908152603c602090815260408083208885168452909152812054909392919091169015612b1c576001600160a01b038087166000908152603c602090815260408083209389168352929052205491505b6037546000906060906001600160a01b038085169163d138f9a160e01b918b9116612b5a68056bc75e2d631000006110518c8b63ffffffff61179516565b604051602401612b6c93929190614a32565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612baa91906149c8565b600060405180830381855afa9150503d8060008114612be5576040519150601f19603f3d011682016040523d82523d6000602084013e612bea565b606091505b50915091506001821415612c0057602081015194505b6000306001600160a01b031663c22552f76040518163ffffffff1660e01b815260040160206040518083038186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c73919081019061410c565b90508515801590612c845750858110155b15612eac5760375460385460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392612cbf929116908a90600401614bc1565b602060405180830381600087803b158015612cd957600080fd5b505af1158015612ced573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d119190810190613f4e565b50603854603f546040516000926001600160a01b031691612d38918f918b91602401614bdc565b60408051601f198184030181529181526020820180516001600160e01b0316630efe6a8b60e01b17905251612d6d91906149c8565b6000604051808303816000865af19150503d8060008114612daa576040519150601f19603f3d011682016040523d82523d6000602084013e612daf565b606091505b505090508015612e3e57601f54612dcc908863ffffffff61167616565b601f819055508a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167ff41c644671512f1cda76abfe6038e3d7d526c1377a5a8c692f81703901db2150898b603f54604051612e3193929190614f74565b60405180910390a4612ea6565b8a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e710812898b603f54604051612e9d93929190614f74565b60405180910390a45b50612f12565b8515801590612eba57508581105b15612f1257603754603f546040518c926001600160a01b0390811692908f16917f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e71081291612f09918b918d91614f74565b60405180910390a45b5050505050505050505050565b6040805160a0810182526001600160a01b03808b16825289811660208084019190915230838501819052606080850191909152918a16608084015283519182018452888252810187905291820185905260009182918291612f8491908e888886613259565b9093509150612f938b8361347e565b600254602754604051631e2c62d360e01b81526001600160a01b0390921691631e2c62d391612fcc918f918f9188918a91600401614a82565b60206040518083038186803b158015612fe457600080fd5b505afa158015612ff8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061301c919081019061410c565b9050896001600160a01b03168b6001600160a01b03168d7fb4eb3c9b62efcce7021cba5fd9cd0c44df91c2272806ccc5e57df7c912e8d7168c868860405161306693929190614bdc565b60405180910390a499509950999650505050505050565b801561310657856000015185600001516001600160a01b031686602001516001600160a01b03167f7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f908a606001518b6080015189602001518a608001518b600001518c60e001518c8c6040516130f9989796959493929190614ac4565b60405180910390a4612925565b6131206f4b3b4ca85a86c47a098a224000000000836117cf565b9150856000015185600001516001600160a01b031686602001516001600160a01b03167ff640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c8a608001518b6060015189608001518a602001518b600001518e60e001518d60c001518e61010001518d6040516131a399989796959493929190614b3b565b60405180910390a450505050505050565b60006131d868056bc75e2d631000006110516015548561179590919063ffffffff16565b90506131e584848361354c565b6131ff83856131fa858563ffffffff61181116565b6135da565b6001600160a01b038085169084167f220e66e3e759e1382aa86cd8af5abca05ebf3ad564f223ae62d977678337272a61323e858563ffffffff61181116565b60405161324b9190614f58565b60405180910390a350505050565b845160009081901515806132705750602087015115155b61328c5760405162461bcd60e51b81526004016103a690614eba565b602087015161329d57865160208801525b6020870151875111156132c25760405162461bcd60e51b81526004016103a690614dea565b60008060008761337f5760408a015161333e5785156132f3576132ec8a60005b602002015161363d565b9050613307565b6133048a60005b602002015161161c565b90505b80156133395760808b01518b5161332a91908b908e60015b602002015185613661565b89516133369082611811565b8a525b61337f565b85156133565761334f8a60026132e2565b9050613364565b6133618a60026132fa565b90505b801561337f5760408a01516133799082611676565b60408b01525b86511561339e5760405162461bcd60e51b81526004016103a690614eea565b6133a88b8b6137b1565b60408c015191945092506133f457895182146133d65760405162461bcd60e51b81526004016103a690614f1a565b80156133ef576133ec828263ffffffff61167616565b91505b61346e565b60208a01518211156134185760405162461bcd60e51b81526004016103a690614dca565b60408a015183101561343c5760405162461bcd60e51b81526004016103a690614d3a565b801561346e5760808b015160208c015161345b91908b908e600061331f565b61346b838263ffffffff61181116565b92505b5090999098509650505050505050565b6029548015610bdf57602d546000906001600160a01b03858116911614156134a757508161352c565b600254604051635967aa7560e11b81526001600160a01b039091169063b2cf54ea906134d99087908790600401614bc1565b60206040518083038186803b1580156134f157600080fd5b505afa158015613505573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613529919081019061410c565b90505b81811115612a655760405162461bcd60e51b81526004016103a690614e2a565b8015610bdf576001600160a01b03821660009081526016602052604090205461357b908263ffffffff61167616565b6001600160a01b0380841660008181526016602052604090819020939093559151908516907f40a75ae5f7a5336e75f7c7977e12c4b46a9ac0f30de01a2d5b6c1a4f4af63587906135cd908590614f58565b60405180910390a3505050565b8015610bdf576135fa6001600160a01b038416838363ffffffff61389b16565b816001600160a01b0316836001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1836040516135cd9190614f58565b600061164c68056bc75e2d63100000611640603e548561179590919063ffffffff16565b8080156137a9576001600160a01b038681166000908152603360205260409020541615613717576001600160a01b038087166000908152603360205260409020546136af91168786846138f4565b50506137146136d668056bc75e2d631000006110516039548561179590919063ffffffff16565b6137086136fb68056bc75e2d631000006110516020548761179590919063ffffffff16565b849063ffffffff61181116565b9063ffffffff61181116565b90505b6001600160a01b038416600090815260196020526040902054613740908263ffffffff61167616565b6001600160a01b03808616600081815260196020526040908190209390935591518792918916907fb23479169712c443e6b00fb0cec3506a5f5926f541df4243d313e11c8c5c71ed90613794908690614f58565b60405180910390a46137a98686868686612ab9565b505050505050565b6000806137bc613b92565b84516001600160a01b039081168252602080870151821683820152604080880151831681850152606080890151909316928401929092528551608084015285015160a08301528481015160c0830152516335aaa79d60e01b815273a98f000a528AC0bFf10a3FE499378437de449659906335aaa79d90613840908490600401614f4a565b604080518083038186803b15801561385757600080fd5b505af415801561386b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061388f919081019061412a565b90969095509350505050565b604051610bdf90849063a9059cbb60e01b906138bd9086908690602401614bc1565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613980565b6040516306a688ff60e11b815260009081903090630d4d11fe906139229089908990899089906004016149fd565b6040805180830381600087803b15801561393b57600080fd5b505af115801561394f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613973919081019061412a565b9097909650945050505050565b613992826001600160a01b0316613a65565b6139ae5760405162461bcd60e51b81526004016103a690614f3a565b60006060836001600160a01b0316836040516139ca91906149c8565b6000604051808303816000865af19150503d8060008114613a07576040519150601f19603f3d011682016040523d82523d6000602084013e613a0c565b606091505b509150915081613a2e5760405162461bcd60e51b81526004016103a690614dba565b805115612a655780806020019051613a499190810190613f4e565b612a655760405162461bcd60e51b81526004016103a690614efa565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906118e1575050151592915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b803561164c816150b4565b803561164c816150c8565b805161164c816150c8565b803561164c816150d1565b803561164c816150da565b60008083601f840112613c1757600080fd5b50813567ffffffffffffffff811115613c2f57600080fd5b602083019150836001820283011115613c4757600080fd5b9250929050565b600060808284031215613c6057600080fd5b50919050565b600060808284031215613c7857600080fd5b613c826080614ff7565b90506000613c908484613bce565b8252506020613ca184848301613bce565b6020830152506040613cb584828501613bce565b6040830152506060613cc984828501613bce565b60608301525092915050565b60006101208284031215613c6057600080fd5b60006101208284031215613cfb57600080fd5b613d06610120614ff7565b90506000613d148484613bef565b8252506020613d2584848301613bef565b6020830152506040613d3984828501613bef565b6040830152506060613d4d84828501613bef565b6060830152506080613d6184828501613bef565b60808301525060a0613d7584828501613bef565b60a08301525060c0613d8984828501613bef565b60c08301525060e0613d9d84828501613bef565b60e083015250610100613db284828501613bef565b6101008301525092915050565b805161164c816150d1565b600060208284031215613ddc57600080fd5b60006118e18484613bce565b60008060408385031215613dfb57600080fd5b6000613e078585613bce565b9250506020613e1885828601613bce565b9150509250929050565b600080600080600060a08688031215613e3a57600080fd5b6000613e468888613bce565b9550506020613e5788828901613bce565b9450506040613e6888828901613bef565b9350506060613e7988828901613bef565b9250506080613e8a88828901613bd9565b9150509295509295909350565b60008060008060008060c08789031215613eb057600080fd5b6000613ebc8989613bce565b9650506020613ecd89828a01613bce565b9550506040613ede89828a01613bef565b9450506060613eef89828a01613bef565b9350506080613f0089828a01613bef565b92505060a0613f1189828a01613bef565b9150509295509295509295565b60008060408385031215613f3157600080fd5b6000613f3d8585613bce565b9250506020613e1885828601613bef565b600060208284031215613f6057600080fd5b60006118e18484613be4565b600060208284031215613f7e57600080fd5b60006118e18484613bef565b60008060408385031215613f9d57600080fd5b6000613e078585613bef565b600080600060608486031215613fbe57600080fd5b6000613fca8686613bef565b9350506020613fdb86828701613bce565b9250506040613fec86828701613bd9565b9150509250925092565b600080600080600080600080610240898b03121561401357600080fd5b600061401f8b8b613bef565b98505060206140308b828c01613bef565b97505060406140418b828c01613bd9565b96505060606140528b828c01613bef565b95505060806140638b828c01613c4e565b9450506101006140758b828c01613cd5565b93505061022089013567ffffffffffffffff81111561409357600080fd5b61409f8b828c01613c05565b92509250509295985092959890939650565b6000602082840312156140c357600080fd5b60006118e18484613bfa565b6000608082840312156140e157600080fd5b60006118e18484613c66565b6000610120828403121561410057600080fd5b60006118e18484613ce8565b60006020828403121561411e57600080fd5b60006118e18484613dbf565b6000806040838503121561413d57600080fd5b60006141498585613dbf565b9250506020613e1885828601613dbf565b61416381615030565b82525050565b61416361417582615030565b615093565b6141638161503b565b61416381615040565b61416361419882615040565b615040565b60006141a88261501e565b6141b28185615022565b93506141c2818560208601615067565b9290920192915050565b6141638161505c565b60006141e08261501e565b6141ea8185615027565b93506141fa818560208601615067565b614203816150a4565b9093019392505050565b600061421a601383615027565b720d8dec2dca0c2e4c2dae640dad2e6dac2e8c6d606b1b815260200192915050565b6000614249600683615027565b6514185d5cd95960d21b815260200192915050565b600061426b601b83615027565b7f696e73756666696369656e742073776170206c69717569646974790000000000815260200192915050565b60006142a4601083615027565b6f1a5b9d985b1a59081a5b9d195c995cdd60821b815260200192915050565b60006142d0602683615027565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000614318601d83615027565b7f656e7472792070726963652061626f766520746865206d696e696d756d000000815260200192915050565b6000614351601183615027565b700c4dee4e4deeecae440dad2e6dac2e8c6d607b1b815260200192915050565b600061437e601b83615027565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006143b7600e83615027565b6d1b1bd85b881d1bdbc81cda1bdc9d60921b815260200192915050565b60006143e1601583615027565b740c6ded8d8c2e8cae4c2d85ed8dec2dc40dac2e8c6d605b1b815260200192915050565b6000614412602083615027565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061444b601383615027565b72737761702066696c6c20746f6f206c6172676560681b815260200192915050565b600061447a600f83615027565b6e0d8cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b60006144a5601c83615027565b7f736f75726365416d6f756e74206c6172676572207468616e206d617800000000815260200192915050565b60006144de600b83615027565b6a6c6f616e2065786973747360a81b815260200192915050565b6000614505601283615027565b7139bab938363ab9903637b0b7103a37b5b2b760711b815260200192915050565b6000614533600e83615027565b6d1b1bd85b881a185cc8195b99195960921b815260200192915050565b600061455d600e83615027565b6d7377617020746f6f206c6172676560901b815260200192915050565b6000614587600f83615027565b6e0636f6c6c61746572616c206973203608c1b815260200192915050565b60006145b2600e83615027565b6d1b9bdd08185d5d1a1bdc9a5e995960921b815260200192915050565b60006145dc602183615027565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b600061461f600c83615027565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6000614647601783615027565b7f636f6c6c61746572616c20696e73756666696369656e74000000000000000000815260200192915050565b6000614680601283615027565b713ab73432b0b63a343c903837b9b4ba34b7b760711b815260200192915050565b60006146ae601583615027565b746c6f616e506172616d73206e6f742065786973747360581b815260200192915050565b60006146df601483615027565b7319985b1b189858dac81b9bdd08185b1b1bddd95960621b815260200192915050565b600061470f602e83615027565b7f6d696e206f72206d617820736f7572636520746f6b656e20616d6f756e74206e81526d1959591cc81d1bc81899481cd95d60921b602082015260400192915050565b600061475f601383615027565b721b1bd85b94185c985b5cc8191a5cd8589b1959606a1b815260200192915050565b600061478e600c83615027565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b60006147b6600d83615027565b6c696e76616c696420737461746560981b815260200192915050565b60006147df602a83615027565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b600061482b602183615027565b7f6c6f616e446174614279746573207265717569726564207769746820657468658152603960f91b602082015260400192915050565b600061486e601683615027565b751cddd85c081d1bdbc81b185c99d9481d1bc8199a5b1b60521b815260200192915050565b60006148a0601583615027565b74696e697469616c4d617267696e20746f6f206c6f7760581b815260200192915050565b60006148d1601f83615027565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160e083019061490e848261415a565b506020820151614921602085018261415a565b506040820151614934604085018261415a565b506060820151614947606085018261415a565b50608082015161495a6080850182614183565b5060a082015161496d60a0850182614183565b5060c0820151612a6560c0850182614183565b600061498c828761418c565b60208201915061499c8286614169565b6014820191506149ac8285614169565b6014820191506149bc828461418c565b50602001949350505050565b600061169b828461419d565b6020810161164c828461415a565b604081016149f0828561415a565b61169b602083018461415a565b60808101614a0b828761415a565b614a18602083018661415a565b614a25604083018561415a565b610b626060830184614183565b60608101614a40828661415a565b614a4d602083018561415a565b6118e16040830184614183565b60808101614a68828761415a565b614a75602083018661415a565b614a256040830185614183565b60a08101614a90828861415a565b614a9d602083018761415a565b614aaa6040830186614183565b614ab76060830185614183565b6110f06080830184614183565b6101008101614ad3828b61415a565b614ae0602083018a61415a565b614aed6040830189614183565b614afa6060830188614183565b614b076080830187614183565b614b1460a0830186614183565b614b2160c0830185614183565b614b2e60e0830184614183565b9998505050505050505050565b6101208101614b4a828c61415a565b614b57602083018b61415a565b614b64604083018a614183565b614b716060830189614183565b614b7e6080830188614183565b614b8b60a0830187614183565b614b9860c0830186614183565b614ba560e0830185614183565b614bb3610100830184614183565b9a9950505050505050505050565b60408101614bcf828561415a565b61169b6020830184614183565b60608101614bea828661415a565b614a4d6020830185614183565b6020810161164c828461417a565b6101008101614c14828b614183565b614c21602083018a61417a565b614c2e604083018961415a565b614c3b606083018861415a565b614b07608083018761415a565b6101808101614c57828f614183565b614c64602083018e614183565b614c71604083018d614183565b614c7e606083018c61417a565b614c8b608083018b614183565b614c9860a083018a614183565b614ca560c0830189614183565b614cb260e0830188614183565b614cc0610100830187614183565b614cce610120830186614183565b614cdc61014083018561415a565b614cea61016083018461415a565b9d9c50505050505050505050505050565b6020810161164c82846141cc565b6020808252810161169b81846141d5565b6020808252810161164c8161420d565b6020808252810161164c8161423c565b6020808252810161164c8161425e565b6020808252810161164c81614297565b6020808252810161164c816142c3565b6020808252810161164c8161430b565b6020808252810161164c81614344565b6020808252810161164c81614371565b6020808252810161164c816143aa565b6020808252810161164c816143d4565b6020808252810161164c81614405565b6020808252810161164c8161443e565b6020808252810161164c8161446d565b6020808252810161164c81614498565b6020808252810161164c816144d1565b6020808252810161164c816144f8565b6020808252810161164c81614526565b6020808252810161164c81614550565b6020808252810161164c8161457a565b6020808252810161164c816145a5565b6020808252810161164c816145cf565b6020808252810161164c81614612565b6020808252810161164c8161463a565b6020808252810161164c81614673565b6020808252810161164c816146a1565b6020808252810161164c816146d2565b6020808252810161164c81614702565b6020808252810161164c81614752565b6020808252810161164c81614781565b6020808252810161164c816147a9565b6020808252810161164c816147d2565b6020808252810161164c8161481e565b6020808252810161164c81614861565b6020808252810161164c81614893565b6020808252810161164c816148c4565b60e0810161164c82846148fd565b6020810161164c8284614183565b60408101614bcf8285614183565b60608101614bea8286614183565b60a08101614f908288614183565b614a9d6020830187614183565b60c08101614fab8289614183565b614fb86020830188614183565b614fc56040830187614183565b614fd26060830186614183565b614fdf6080830185614183565b614fec60a0830184614183565b979650505050505050565b60405181810167ffffffffffffffff8111828210171561501657600080fd5b604052919050565b5190565b919050565b90815260200190565b600061164c82615050565b151590565b90565b6001600160e01b03191690565b6001600160a01b031690565b600061164c82615030565b60005b8381101561508257818101518382015260200161506a565b83811115612a655750506000910152565b600061164c82600061164c826150ae565b601f01601f191690565b60601b90565b6150bd81615030565b81146114b657600080fd5b6150bd8161503b565b6150bd81615040565b6150bd8161504356fea365627a7a7231582006262a07965035f357589c6bb924f7de44a817506b83c56eb712cec5934fdd626c6578706572696d656e74616cf564736f6c63430005110040", + "deployedBytecode": "0x6080604052600436106103815760003560e01c80638f32d59b116101d1578063cd5d808d11610102578063e8f62764116100a0578063f589a3e71161006f578063f589a3e714610a05578063f6ddc8b314610a1a578063f706b1f214610a2f578063f851a44014610a4457610381565b8063e8f62764146109a6578063edab119f146109bb578063f0e085f5146109d0578063f2fde38b146109e557610381565b8063d485045e116100dc578063d485045e14610925578063d67f707714610945578063d84ca25414610965578063e762319f1461098657610381565b8063cd5d808d146108db578063d288208c146108fb578063d473c2da1461091057610381565b8063b7e152411161016f578063bdee453c11610149578063bdee453c1461082f578063c4a908151461084f578063c4d66de814610887578063cb6eacd1146108a757610381565b8063b7e15241146107e5578063b9cffa3e14610805578063ba4861e91461081a57610381565b8063acc04348116101ab578063acc0434814610779578063ae0a85301461078e578063afe84009146107a3578063b30643d9146107c557610381565b80638f32d59b1461072f57806392d894f814610744578063959083d31461076457610381565b80634203e395116102b65780636e663730116102545780637a8faeb8116102235780637a8faeb8146106d05780638456cb59146106e55780638da5cb5b146106fa5780638dc48ba51461070f57610381565b80636e663730146106715780637420ca3e14610691578063742e6798146106a657806378d849ed146106bb57610381565b8063569fc1fb11610290578063569fc1fb146105dc578063574442cc1461060b57806362fff3f61461062057806368c4ac261461065157610381565b80634203e395146105925780634699f846146105b25780634f28cac2146105c757610381565b80632a324027116103235780633432423c116102fd5780633432423c146105125780633452d2d4146105325780633fca506e146105525780634115a2b61461057257610381565b80632a324027146104c65780632f470764146104db57806333d8991f146104f057610381565b80631b7bde741161035f5780631b7bde741461042c578063218b39c61461045957806324cc57491461047957806325decac0146104a657610381565b8063065d810f146103af5780630676c1b7146103ea57806317548b791461040c575b34801561038d57600080fd5b5060405162461bcd60e51b81526004016103a690614eaa565b60405180910390fd5b3480156103bb57600080fd5b506103cf6103ca366004613f1e565b610a59565b6040516103e196959493929190614f9d565b60405180910390f35b3480156103f657600080fd5b506103ff610a99565b6040516103e191906149d4565b34801561041857600080fd5b506103ff6104273660046140b1565b610aa8565b34801561043857600080fd5b5061044c610447366004613de8565b610ac3565b6040516103e19190614f58565b34801561046557600080fd5b506103ff610474366004613dca565b610ae0565b34801561048557600080fd5b50610499610494366004613dca565b610afb565b6040516103e19190614bf7565b3480156104b257600080fd5b5061044c6104c1366004613e22565b610b10565b3480156104d257600080fd5b5061044c610b6b565b3480156104e757600080fd5b5061044c610b71565b3480156104fc57600080fd5b5061051061050b366004613fa9565b610b77565b005b34801561051e57600080fd5b506103cf61052d366004613f1e565b610be4565b34801561053e57600080fd5b5061044c61054d366004613dca565b610c24565b34801561055e57600080fd5b5061044c61056d366004613dca565b610c36565b34801561057e57600080fd5b5061049961058d366004613f8a565b610c48565b34801561059e57600080fd5b5061044c6105ad366004613dca565b610c68565b3480156105be57600080fd5b5061044c610c7a565b3480156105d357600080fd5b5061044c610c80565b3480156105e857600080fd5b506105fc6105f7366004613f6c565b610c86565b6040516103e193929190614f74565b34801561061757600080fd5b5061044c610ca7565b34801561062c57600080fd5b5061064061063b366004613de8565b610cad565b6040516103e1959493929190614f82565b34801561065d57600080fd5b5061049961066c366004613dca565b610ce7565b34801561067d57600080fd5b506103ff61068c366004613dca565b610cfc565b34801561069d57600080fd5b506103ff610d17565b3480156106b257600080fd5b5061044c610d26565b3480156106c757600080fd5b506103ff610d2c565b3480156106dc57600080fd5b5061044c610d3b565b3480156106f157600080fd5b50610499610d41565b34801561070657600080fd5b506103ff610d4a565b34801561071b57600080fd5b506103ff61072a366004613dca565b610d59565b34801561073b57600080fd5b50610499610d74565b34801561075057600080fd5b5061044c61075f366004613dca565b610d9a565b34801561077057600080fd5b5061044c610dac565b34801561078557600080fd5b5061044c610db2565b34801561079a57600080fd5b5061044c610db8565b3480156107af57600080fd5b506107b8610dbe565b6040516103e19190614cfb565b3480156107d157600080fd5b5061044c6107e0366004613dca565b610dcd565b3480156107f157600080fd5b5061044c610800366004613dca565b610ddf565b34801561081157600080fd5b506103ff610df1565b34801561082657600080fd5b506103ff610e00565b34801561083b57600080fd5b5061044c61084a366004613dca565b610e0f565b34801561085b57600080fd5b5061086f61086a366004613f6c565b610e21565b6040516103e19c9b9a99989796959493929190614c48565b34801561089357600080fd5b506105106108a2366004613dca565b610e93565b3480156108b357600080fd5b506108c76108c2366004613f6c565b610f96565b6040516103e1989796959493929190614c05565b3480156108e757600080fd5b5061044c6108f6366004613de8565b610fe8565b34801561090757600080fd5b506103ff611005565b34801561091c57600080fd5b5061044c611014565b34801561093157600080fd5b5061044c610940366004613dca565b61101a565b34801561095157600080fd5b5061044c610960366004613e97565b61102c565b610978610973366004613ff6565b6110fa565b6040516103e1929190614f66565b34801561099257600080fd5b5061044c6109a1366004613e22565b6112fa565b3480156109b257600080fd5b506103ff61146e565b3480156109c757600080fd5b5061044c61147d565b3480156109dc57600080fd5b5061044c611483565b3480156109f157600080fd5b50610510610a00366004613dca565b611489565b348015610a1157600080fd5b5061044c6114b9565b348015610a2657600080fd5b5061044c6114bf565b348015610a3b57600080fd5b506103ff6114c5565b348015610a5057600080fd5b506103ff6114d4565b6009602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b6031546001600160a01b031681565b6005602052600090815260409020546001600160a01b031681565b603b60209081526000928352604080842090915290825290205481565b6023602052600090815260409020546001600160a01b031681565b60326020526000908152604090205460ff1681565b60008215610b6257610b2586868686866114e3565b9050600082610b3c57610b378261161c565b610b45565b610b4582611652565b90508015610b6057610b5d828263ffffffff61167616565b91505b505b95945050505050565b60185481565b601f5481565b603d5460ff1615610b9a5760405162461bcd60e51b81526004016103a690614d2a565b6000838152600660205260409020600a01546001600160a01b03163314610bd35760405162461bcd60e51b81526004016103a690614e6a565b610bdf833384846116a2565b505050565b6008602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600590950154939492939192909186565b601a6020526000908152604090205481565b602a6020526000908152604090205481565b600a60209081526000928352604080842090915290825290205460ff1681565b60166020526000908152604090205481565b60155481565b60295481565b600c6020526000908152604090208054600182015460029092015490919083565b602b5481565b600b602090815260009283526040808420909152908252902080546001820154600283015460038401546004909401549293919290919085565b60266020526000908152604090205460ff1681565b6033602052600090815260409020546001600160a01b031681565b6003546001600160a01b031681565b60355481565b6002546001600160a01b031681565b601e5481565b603d5460ff1681565b6001546001600160a01b031690565b6022602052600090815260409020546001600160a01b031681565b6001546000906001600160a01b0316610d8b611717565b6001600160a01b031614905090565b60176020526000908152604090205481565b602c5481565b602f5481565b60205481565b602d546001600160a01b031681565b601d6020526000908152604090205481565b601c6020526000908152604090205481565b6037546001600160a01b031681565b6004546001600160a01b031681565b60366020526000908152604090205481565b600660208190526000918252604090912080546001820154600283015460038401546004850154600586015496860154600787015460088801546009890154600a8a0154600b909a0154989a9799969860ff909616979496949593949293919290916001600160a01b0391821691168c565b610e9b610d74565b610eb75760405162461bcd60e51b81526004016103a690614e6a565b633613289560e21b600081905260056020527fd3a886345208a8e3a0f774019653c4e69589e943ba1e46c7fa0ef875651e6e39546001600160a01b031690610eff908361171b565b610f106333d8991f60e01b8361171b565b610f2163d67f707760e01b8361171b565b610f3162977b2b60e61b8361171b565b610f4263e762319f60e01b8361171b565b6b4c6f616e4f70656e696e677360a01b826001600160a01b0316826001600160a01b03167f1420e3a2094d671bc2eb897941fa3d94ffa37f0cb6d530651946250a2151cb7f60405160405180910390a45050565b6007602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949560ff8516956101009095046001600160a01b03908116959481169493169288565b603c60209081526000928352604080842090915290825290205481565b6038546001600160a01b031681565b60275481565b60196020526000908152604090205481565b60006224ea008161105d6907baab4146b63dd00000611051868863ffffffff61179516565b9063ffffffff6117cf16565b9050600061107862015180611051858563ffffffff61179516565b9050600061108c898363ffffffff61181116565b905060006110998261161c565b905080156110b4576110b1828263ffffffff61181116565b91505b60006110c18d8d85611853565b9050806110d757600096505050505050506110f0565b6110e78a8263ffffffff61167616565b96505050505050505b9695505050505050565b60008060016000541461111f5760405162461bcd60e51b81526004016103a690614eda565b6002600055603d5460ff16156111475760405162461bcd60e51b81526004016103a690614d2a565b34158061115357508215155b61116f5760405162461bcd60e51b81526004016103a690614f0a565b336000908152602260205260409020546001600160a01b03166111a45760405162461bcd60e51b81526004016103a690614e4a565b6111ac613a9e565b5060008a815260076020908152604091829020825161010080820185528254808352600184015460ff811615159584019590955293046001600160a01b039081169482019490945260028201548416606082015260038201549093166080840152600481015460a0840152600581015460c08401526006015460e08301526112465760405162461bcd60e51b81526004016103a690614e9a565b60006112618260600151836080015189602001358c8e6114e3565b9050806112805760405162461bcd60e51b81526004016103a690614e3a565b6112e2828c8c848d611297368f90038f018f6140cf565b6112a6368f90038f018f6140ed565b8d8d8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506118e992505050565b6001600055909d909c509a5050505050505050505050565b60008215610b62578115611324576113218368056bc75e2d6310000063ffffffff61167616565b92505b8360008361133a576113358261161c565b611343565b61134382611652565b9050801561135e5761135b828263ffffffff61181116565b91505b866001600160a01b0316886001600160a01b0316141561139c57611395856110518468056bc75e2d6310000063ffffffff61179516565b9250611463565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c906113d3908c908e906004016149e2565b604080518083038186803b1580156113ea57600080fd5b505afa1580156113fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611422919081019061412a565b91509150806000146114605761145d816110518981866114518a68056bc75e2d6310000063ffffffff61179516565b9063ffffffff61179516565b94505b50505b505095945050505050565b6014546001600160a01b031681565b601b5481565b60285481565b611491610d74565b6114ad5760405162461bcd60e51b81526004016103a690614e6a565b6114b681611be0565b50565b60395481565b60215481565b602e546001600160a01b031681565b6030546001600160a01b031681565b6000846001600160a01b0316866001600160a01b031614156115235761151c68056bc75e2d63100000611051868663ffffffff61179516565b90506115de565b600254604051630a7549df60e21b815260009182916001600160a01b03909116906329d5277c9061155a908a908c906004016149e2565b604080518083038186803b15801561157157600080fd5b505afa158015611585573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506115a9919081019061412a565b91509150816000146115db576115d868056bc75e2d631000006110518761145186838c8863ffffffff61179516565b92505b50505b8180156115ea57508015155b15610b62576110f081611610856110518368056bc75e2d6310000063ffffffff61179516565b9063ffffffff61167616565b600061164c68056bc75e2d631000006116406018548561179590919063ffffffff16565b9063ffffffff611c6216565b92915050565b600061164c68056bc75e2d63100000611640601b548561179590919063ffffffff16565b60008282018381101561169b5760405162461bcd60e51b81526004016103a690614d8a565b9392505050565b6000848152600a602090815260408083206001600160a01b038681168086529190935292819020805460ff1916851515179055519085169086907f0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c9843390611709908690614bf7565b60405180910390a450505050565b3390565b6001600160e01b03198216600090815260056020526040902080546001600160a01b0319166001600160a01b0383169081179091551561177657611770600d6001600160e01b0319841663ffffffff611ca416565b50611791565b610bdf600d6001600160e01b0319841663ffffffff611cec16565b5050565b6000826117a45750600061164c565b828202828482816117b157fe5b041461169b5760405162461bcd60e51b81526004016103a690614e5a565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611dad565b600061169b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611de4565b604051636dcd64e560e01b815260009073__$6b3065420287e4be5d93089ad806c078e3$__90636dcd64e59061189190879087908790600401614a32565b60206040518083038186803b1580156118a957600080fd5b505af41580156118bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506118e1919081019061410c565b949350505050565b60008089606001516001600160a01b03168a608001516001600160a01b031614156119265760405162461bcd60e51b81526004016103a690614daa565b8960a0015186101561194a5760405162461bcd60e51b81526004016103a690614f2a565b60e08a015115158061195f5750604084015115155b61197b5760405162461bcd60e51b81526004016103a690614d4a565b60008861198957600061198f565b84602001515b90506000600660006119a88e8e8c8c8c60200151611e10565b8152602001908152602001600020905060006119d38d8389600001518a602001518b60400151612202565b60608801519091506119eb908263ffffffff61181116565b60608801528a15611a7b57606087015115611a185760405162461bcd60e51b81526004016103a690614e0a565b6000611a278860800151611652565b905060008e60800151905060008f60600151905082600014611a7357611a588b60200151866000015484848761241e565b60808a0151611a6d908463ffffffff61181116565b60808b01525b505050611a8b565b611a888c8e8a8a8a6124bd565b96505b60408051610180810182528354815260018401546020820152600284015491810191909152600383015460ff16151560608201526004830154608080830191909152600584015460a0830152600684015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b85015416610160830152880151611b35918f918c908e88612540565b611b515760405162461bcd60e51b81526004016103a690614e7a565b60808701516005830154611b6a9163ffffffff61167616565b60058301558a15611b94576007820154611b8a904263ffffffff61181116565b60e0880152611bb5565b611bae6f4b3b4ca85a86c47a098a2240000000008a6117cf565b6101008801525b611bc28d838a8a8f61265b565b86602001518760800151945094505050509850989650505050505050565b6001600160a01b038116611c065760405162461bcd60e51b81526004016103a690614d5a565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600061169b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061292e565b6000611cb08383612978565b611ce4575060018083018054808301808355600092835260208084209092018590558483529085905260409091205561164c565b50600061164c565b6000611cf88383612978565b15611ce45760008281526020849052604090205460018401546000199182019101808214611d70576000856001018281548110611d3157fe5b9060005260206000200154905080866001018481548110611d4e57fe5b6000918252602080832090910192909255918252869052604090206001830190555b60008481526020869052604081205560018501805480611d8c57fe5b6001900381819060005260206000200160009055905560019250505061164c565b60008183611dce5760405162461bcd60e51b81526004016103a69190614d09565b506000838581611dda57fe5b0495945050505050565b60008184841115611e085760405162461bcd60e51b81526004016103a69190614d09565b505050900390565b60008560200151611e335760405162461bcd60e51b81526004016103a690614eca565b825160208401516060850151611e47613ae2565b88611f9e576001600160a01b0383166000908152602a60209081526040918290208054600101908190558c519251611e86939288928892909101614980565b60408051601f1981840301815291815281516020928301206000818152600690935291205490995015611ecb5760405162461bcd60e51b81526004016103a690614dfa565b5060408051610180810182528981528a5160208201526000918101829052600160608201526080810187905260a081018290524260c082015260e0810182905261010081018990526101208101919091526001600160a01b038084166101408301528416610160820152611f46600f8a63ffffffff611ca416565b506001600160a01b0384166000908152601160205260409020611f6f908a63ffffffff611ca416565b506001600160a01b0383166000908152601260205260409020611f98908a63ffffffff611ca416565b5061211f565b5060008881526006602081815260409283902083516101808101855281548152600182015492810192909252600281015493820193909352600383015460ff161580156060830181905260048501546080840152600585015460a08401529284015460c0830152600784015460e083015260088401546101008301526009840154610120830152600a8401546001600160a01b03908116610140840152600b909401549093166101608201529161205857508060e0015142105b6120745760405162461bcd60e51b81526004016103a690614e1a565b826001600160a01b03168161014001516001600160a01b0316146120aa5760405162461bcd60e51b81526004016103a690614d7a565b836001600160a01b03168161016001516001600160a01b0316146120e05760405162461bcd60e51b81526004016103a690614dda565b89516020820151146121045760405162461bcd60e51b81526004016103a690614d1a565b6080810151612119908763ffffffff61167616565b60808201525b6001600160a01b0382161561213b5761213b89848460016116a2565b60008981526006602081815260409283902084518155908401516001820155918301516002830155606083015160038301805460ff19169115159190911790556080830151600483015560a0830151600583015560c08301519082015560e0820151600782015561010082015160088201556101208201516009820155610140820151600a820180546001600160a01b03199081166001600160a01b039384161790915561016090930151600b909201805490931691161790555095979650505050505050565b600b8401546060860151600091612224916001600160a01b039091169061298d565b84546000818152600c60209081526040808320600b808b01546001600160a01b03908116865290845282852060608d0180518316875294529190932060e08b0151925160808c0151600a8c0154959692956122859488949392911642612a6b565b6000811580156122985750600789015415155b156122c6576122c3620151806110518660000154611451428e6007015461181190919063ffffffff16565b90505b60006122e66907baab4146b63dd000006110518a8c63ffffffff61179516565b85549091506122fb908263ffffffff61167616565b85556001840154612312908263ffffffff61167616565b60018501558261238157845461233f90429061161090611051620151806114518d8963ffffffff61167616565b60078b01819055612356904263ffffffff61181116565b9250610e1083116123795760405162461bcd60e51b81526004016103a690614d9a565b8695506123c5565b60078a01546123a05761239a428463ffffffff61167616565b60078b01555b6123c26201518061105183611451428f6007015461181190919063ffffffff16565b95505b60018501546123da908763ffffffff61167616565b600186015583546123f1908963ffffffff61167616565b84556002840154612408908763ffffffff61167616565b8460020181905550505050505095945050505050565b80156124b6576001600160a01b0383166000908152601c602052604090205461244d908263ffffffff61167616565b6001600160a01b038085166000818152601c6020526040908190209390935591518692918816907ffb6c38ae4fdd498b3a5003f02ca4ca5340dfedb36b1b100c679eb60633b2c0a7906124a1908690614f58565b60405180910390a46124b68585858585612ab9565b5050505050565b6124c5613b46565b60006124ea87876060015188608001518860200151886060015160008060008b612f1f565b60c0870152506080850151909150612508908263ffffffff61167616565b608085015260a084015160c085015110156125355760405162461bcd60e51b81526004016103a690614d6a565b509195945050505050565b600061256868056bc75e2d631000006110518568055005f0c61448000063ffffffff61179516565b92508284101561264e5760a0860151156126465760025460608801516080808a0151908901516000936001600160a01b03169263f80b25fb9290916125b3908863ffffffff61181116565b8b60a001518b6040518663ffffffff1660e01b81526004016125d9959493929190614a82565b60206040518083038186803b1580156125f157600080fd5b505afa158015612605573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612629919081019061410c565b90508361263c868363ffffffff61167616565b10159150506110f0565b5060006110f0565b5060019695505050505050565b6002546060860151608087015160048088015460058901546040516317f8680960e11b815260009687966001600160a01b0390911695632ff0d012956126a5959294919301614a5a565b604080518083038186803b1580156126bc57600080fd5b505afa1580156126d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506126f4919081019061412a565b915091508660c00151821161271b5760405162461bcd60e51b81526004016103a690614e8a565b4286600601541415612881576002546060880151608089015160405163524efd4b60e01b81526000936001600160a01b03169263524efd4b92612760926004016149e2565b60206040518083038186803b15801561277857600080fd5b505afa15801561278c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506127b0919081019061410c565b60025460808a015160608b015160405163524efd4b60e01b81529394506000936001600160a01b039093169263524efd4b926127f09290916004016149e2565b60206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612840919081019061410c565b90506000612854838363ffffffff61179516565b9050856128765760c087015161287190829063ffffffff6117cf16565b612878565b835b60098a01555050505b60408051610180810182528754815260018801546020820152600288015491810191909152600387015460ff161515606082015260048701546080820152600587015460a0820152600687015460c0820152600787015460e082015260088701546101008201526009870154610120820152600a8701546001600160a01b03908116610140830152600b88015416610160820152612925908890878785878961307d565b50505050505050565b6000818361294f5760405162461bcd60e51b81526004016103a69190614d09565b508361295d5750600061169b565b600083600186038161296b57fe5b0460010195945050505050565b60009081526020919091526040902054151590565b6001600160a01b038083166000908152600b6020908152604080832093851683529290529081206001810154909190158015906129cd5750600482015415155b15612a5e576129f862015180611051846001015461145186600401544261181190919063ffffffff16565b4260048401556002830154909150811115612a14575060028101545b8015612a59576003820154612a2f908263ffffffff61167616565b60038301556002820154612a49908263ffffffff61181116565b6002830155612a598484836131b4565b612a65565b4260048301555b50505050565b6000612aa16a07259756a8d619980000006110516015546114518b600001546114518d600201548961181190919063ffffffff16565b60028801839055905080156129255761292583878787855b602f546002546001600160a01b038581166000908152603c602090815260408083208885168452909152812054909392919091169015612b1c576001600160a01b038087166000908152603c602090815260408083209389168352929052205491505b6037546000906060906001600160a01b038085169163d138f9a160e01b918b9116612b5a68056bc75e2d631000006110518c8b63ffffffff61179516565b604051602401612b6c93929190614a32565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612baa91906149c8565b600060405180830381855afa9150503d8060008114612be5576040519150601f19603f3d011682016040523d82523d6000602084013e612bea565b606091505b50915091506001821415612c0057602081015194505b6000306001600160a01b031663c22552f76040518163ffffffff1660e01b815260040160206040518083038186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612c73919081019061410c565b90508515801590612c845750858110155b15612eac5760375460385460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392612cbf929116908a90600401614bc1565b602060405180830381600087803b158015612cd957600080fd5b505af1158015612ced573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d119190810190613f4e565b50603854603f546040516000926001600160a01b031691612d38918f918b91602401614bdc565b60408051601f198184030181529181526020820180516001600160e01b0316630efe6a8b60e01b17905251612d6d91906149c8565b6000604051808303816000865af19150503d8060008114612daa576040519150601f19603f3d011682016040523d82523d6000602084013e612daf565b606091505b505090508015612e3e57601f54612dcc908863ffffffff61167616565b601f819055508a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167ff41c644671512f1cda76abfe6038e3d7d526c1377a5a8c692f81703901db2150898b603f54604051612e3193929190614f74565b60405180910390a4612ea6565b8a603760009054906101000a90046001600160a01b03166001600160a01b03168d6001600160a01b03167f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e710812898b603f54604051612e9d93929190614f74565b60405180910390a45b50612f12565b8515801590612eba57508581105b15612f1257603754603f546040518c926001600160a01b0390811692908f16917f483f67ea49f76ac15e15bbad68b52788ca47d50aef1e4acfe95e5e307e71081291612f09918b918d91614f74565b60405180910390a45b5050505050505050505050565b6040805160a0810182526001600160a01b03808b16825289811660208084019190915230838501819052606080850191909152918a16608084015283519182018452888252810187905291820185905260009182918291612f8491908e888886613259565b9093509150612f938b8361347e565b600254602754604051631e2c62d360e01b81526001600160a01b0390921691631e2c62d391612fcc918f918f9188918a91600401614a82565b60206040518083038186803b158015612fe457600080fd5b505afa158015612ff8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061301c919081019061410c565b9050896001600160a01b03168b6001600160a01b03168d7fb4eb3c9b62efcce7021cba5fd9cd0c44df91c2272806ccc5e57df7c912e8d7168c868860405161306693929190614bdc565b60405180910390a499509950999650505050505050565b801561310657856000015185600001516001600160a01b031686602001516001600160a01b03167f7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f908a606001518b6080015189602001518a608001518b600001518c60e001518c8c6040516130f9989796959493929190614ac4565b60405180910390a4612925565b6131206f4b3b4ca85a86c47a098a224000000000836117cf565b9150856000015185600001516001600160a01b031686602001516001600160a01b03167ff640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c8a608001518b6060015189608001518a602001518b600001518e60e001518d60c001518e61010001518d6040516131a399989796959493929190614b3b565b60405180910390a450505050505050565b60006131d868056bc75e2d631000006110516015548561179590919063ffffffff16565b90506131e584848361354c565b6131ff83856131fa858563ffffffff61181116565b6135da565b6001600160a01b038085169084167f220e66e3e759e1382aa86cd8af5abca05ebf3ad564f223ae62d977678337272a61323e858563ffffffff61181116565b60405161324b9190614f58565b60405180910390a350505050565b845160009081901515806132705750602087015115155b61328c5760405162461bcd60e51b81526004016103a690614eba565b602087015161329d57865160208801525b6020870151875111156132c25760405162461bcd60e51b81526004016103a690614dea565b60008060008761337f5760408a015161333e5785156132f3576132ec8a60005b602002015161363d565b9050613307565b6133048a60005b602002015161161c565b90505b80156133395760808b01518b5161332a91908b908e60015b602002015185613661565b89516133369082611811565b8a525b61337f565b85156133565761334f8a60026132e2565b9050613364565b6133618a60026132fa565b90505b801561337f5760408a01516133799082611676565b60408b01525b86511561339e5760405162461bcd60e51b81526004016103a690614eea565b6133a88b8b6137b1565b60408c015191945092506133f457895182146133d65760405162461bcd60e51b81526004016103a690614f1a565b80156133ef576133ec828263ffffffff61167616565b91505b61346e565b60208a01518211156134185760405162461bcd60e51b81526004016103a690614dca565b60408a015183101561343c5760405162461bcd60e51b81526004016103a690614d3a565b801561346e5760808b015160208c015161345b91908b908e600061331f565b61346b838263ffffffff61181116565b92505b5090999098509650505050505050565b6029548015610bdf57602d546000906001600160a01b03858116911614156134a757508161352c565b600254604051635967aa7560e11b81526001600160a01b039091169063b2cf54ea906134d99087908790600401614bc1565b60206040518083038186803b1580156134f157600080fd5b505afa158015613505573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613529919081019061410c565b90505b81811115612a655760405162461bcd60e51b81526004016103a690614e2a565b8015610bdf576001600160a01b03821660009081526016602052604090205461357b908263ffffffff61167616565b6001600160a01b0380841660008181526016602052604090819020939093559151908516907f40a75ae5f7a5336e75f7c7977e12c4b46a9ac0f30de01a2d5b6c1a4f4af63587906135cd908590614f58565b60405180910390a3505050565b8015610bdf576135fa6001600160a01b038416838363ffffffff61389b16565b816001600160a01b0316836001600160a01b03167fc44aeefa68e8b9c1ad5f7be4b0dd194580f81f5c362862e72196503a320eb7a1836040516135cd9190614f58565b600061164c68056bc75e2d63100000611640603e548561179590919063ffffffff16565b8080156137a9576001600160a01b038681166000908152603360205260409020541615613717576001600160a01b038087166000908152603360205260409020546136af91168786846138f4565b50506137146136d668056bc75e2d631000006110516039548561179590919063ffffffff16565b6137086136fb68056bc75e2d631000006110516020548761179590919063ffffffff16565b849063ffffffff61181116565b9063ffffffff61181116565b90505b6001600160a01b038416600090815260196020526040902054613740908263ffffffff61167616565b6001600160a01b03808616600081815260196020526040908190209390935591518792918916907fb23479169712c443e6b00fb0cec3506a5f5926f541df4243d313e11c8c5c71ed90613794908690614f58565b60405180910390a46137a98686868686612ab9565b505050505050565b6000806137bc613b92565b84516001600160a01b039081168252602080870151821683820152604080880151831681850152606080890151909316928401929092528551608084015285015160a08301528481015160c0830152516335aaa79d60e01b815273__$6b3065420287e4be5d93089ad806c078e3$__906335aaa79d90613840908490600401614f4a565b604080518083038186803b15801561385757600080fd5b505af415801561386b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061388f919081019061412a565b90969095509350505050565b604051610bdf90849063a9059cbb60e01b906138bd9086908690602401614bc1565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613980565b6040516306a688ff60e11b815260009081903090630d4d11fe906139229089908990899089906004016149fd565b6040805180830381600087803b15801561393b57600080fd5b505af115801561394f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250613973919081019061412a565b9097909650945050505050565b613992826001600160a01b0316613a65565b6139ae5760405162461bcd60e51b81526004016103a690614f3a565b60006060836001600160a01b0316836040516139ca91906149c8565b6000604051808303816000865af19150503d8060008114613a07576040519150601f19603f3d011682016040523d82523d6000602084013e613a0c565b606091505b509150915081613a2e5760405162461bcd60e51b81526004016103a690614dba565b805115612a655780806020019051613a499190810190613f4e565b612a655760405162461bcd60e51b81526004016103a690614efa565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906118e1575050151592915050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b803561164c816150b4565b803561164c816150c8565b805161164c816150c8565b803561164c816150d1565b803561164c816150da565b60008083601f840112613c1757600080fd5b50813567ffffffffffffffff811115613c2f57600080fd5b602083019150836001820283011115613c4757600080fd5b9250929050565b600060808284031215613c6057600080fd5b50919050565b600060808284031215613c7857600080fd5b613c826080614ff7565b90506000613c908484613bce565b8252506020613ca184848301613bce565b6020830152506040613cb584828501613bce565b6040830152506060613cc984828501613bce565b60608301525092915050565b60006101208284031215613c6057600080fd5b60006101208284031215613cfb57600080fd5b613d06610120614ff7565b90506000613d148484613bef565b8252506020613d2584848301613bef565b6020830152506040613d3984828501613bef565b6040830152506060613d4d84828501613bef565b6060830152506080613d6184828501613bef565b60808301525060a0613d7584828501613bef565b60a08301525060c0613d8984828501613bef565b60c08301525060e0613d9d84828501613bef565b60e083015250610100613db284828501613bef565b6101008301525092915050565b805161164c816150d1565b600060208284031215613ddc57600080fd5b60006118e18484613bce565b60008060408385031215613dfb57600080fd5b6000613e078585613bce565b9250506020613e1885828601613bce565b9150509250929050565b600080600080600060a08688031215613e3a57600080fd5b6000613e468888613bce565b9550506020613e5788828901613bce565b9450506040613e6888828901613bef565b9350506060613e7988828901613bef565b9250506080613e8a88828901613bd9565b9150509295509295909350565b60008060008060008060c08789031215613eb057600080fd5b6000613ebc8989613bce565b9650506020613ecd89828a01613bce565b9550506040613ede89828a01613bef565b9450506060613eef89828a01613bef565b9350506080613f0089828a01613bef565b92505060a0613f1189828a01613bef565b9150509295509295509295565b60008060408385031215613f3157600080fd5b6000613f3d8585613bce565b9250506020613e1885828601613bef565b600060208284031215613f6057600080fd5b60006118e18484613be4565b600060208284031215613f7e57600080fd5b60006118e18484613bef565b60008060408385031215613f9d57600080fd5b6000613e078585613bef565b600080600060608486031215613fbe57600080fd5b6000613fca8686613bef565b9350506020613fdb86828701613bce565b9250506040613fec86828701613bd9565b9150509250925092565b600080600080600080600080610240898b03121561401357600080fd5b600061401f8b8b613bef565b98505060206140308b828c01613bef565b97505060406140418b828c01613bd9565b96505060606140528b828c01613bef565b95505060806140638b828c01613c4e565b9450506101006140758b828c01613cd5565b93505061022089013567ffffffffffffffff81111561409357600080fd5b61409f8b828c01613c05565b92509250509295985092959890939650565b6000602082840312156140c357600080fd5b60006118e18484613bfa565b6000608082840312156140e157600080fd5b60006118e18484613c66565b6000610120828403121561410057600080fd5b60006118e18484613ce8565b60006020828403121561411e57600080fd5b60006118e18484613dbf565b6000806040838503121561413d57600080fd5b60006141498585613dbf565b9250506020613e1885828601613dbf565b61416381615030565b82525050565b61416361417582615030565b615093565b6141638161503b565b61416381615040565b61416361419882615040565b615040565b60006141a88261501e565b6141b28185615022565b93506141c2818560208601615067565b9290920192915050565b6141638161505c565b60006141e08261501e565b6141ea8185615027565b93506141fa818560208601615067565b614203816150a4565b9093019392505050565b600061421a601383615027565b720d8dec2dca0c2e4c2dae640dad2e6dac2e8c6d606b1b815260200192915050565b6000614249600683615027565b6514185d5cd95960d21b815260200192915050565b600061426b601b83615027565b7f696e73756666696369656e742073776170206c69717569646974790000000000815260200192915050565b60006142a4601083615027565b6f1a5b9d985b1a59081a5b9d195c995cdd60821b815260200192915050565b60006142d0602683615027565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000614318601d83615027565b7f656e7472792070726963652061626f766520746865206d696e696d756d000000815260200192915050565b6000614351601183615027565b700c4dee4e4deeecae440dad2e6dac2e8c6d607b1b815260200192915050565b600061437e601b83615027565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006143b7600e83615027565b6d1b1bd85b881d1bdbc81cda1bdc9d60921b815260200192915050565b60006143e1601583615027565b740c6ded8d8c2e8cae4c2d85ed8dec2dc40dac2e8c6d605b1b815260200192915050565b6000614412602083615027565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061444b601383615027565b72737761702066696c6c20746f6f206c6172676560681b815260200192915050565b600061447a600f83615027565b6e0d8cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b60006144a5601c83615027565b7f736f75726365416d6f756e74206c6172676572207468616e206d617800000000815260200192915050565b60006144de600b83615027565b6a6c6f616e2065786973747360a81b815260200192915050565b6000614505601283615027565b7139bab938363ab9903637b0b7103a37b5b2b760711b815260200192915050565b6000614533600e83615027565b6d1b1bd85b881a185cc8195b99195960921b815260200192915050565b600061455d600e83615027565b6d7377617020746f6f206c6172676560901b815260200192915050565b6000614587600f83615027565b6e0636f6c6c61746572616c206973203608c1b815260200192915050565b60006145b2600e83615027565b6d1b9bdd08185d5d1a1bdc9a5e995960921b815260200192915050565b60006145dc602183615027565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b600061461f600c83615027565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6000614647601783615027565b7f636f6c6c61746572616c20696e73756666696369656e74000000000000000000815260200192915050565b6000614680601283615027565b713ab73432b0b63a343c903837b9b4ba34b7b760711b815260200192915050565b60006146ae601583615027565b746c6f616e506172616d73206e6f742065786973747360581b815260200192915050565b60006146df601483615027565b7319985b1b189858dac81b9bdd08185b1b1bddd95960621b815260200192915050565b600061470f602e83615027565b7f6d696e206f72206d617820736f7572636520746f6b656e20616d6f756e74206e81526d1959591cc81d1bc81899481cd95d60921b602082015260400192915050565b600061475f601383615027565b721b1bd85b94185c985b5cc8191a5cd8589b1959606a1b815260200192915050565b600061478e600c83615027565b6b1b9bdb9499595b9d1c985b9d60a21b815260200192915050565b60006147b6600d83615027565b6c696e76616c696420737461746560981b815260200192915050565b60006147df602a83615027565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b600061482b602183615027565b7f6c6f616e446174614279746573207265717569726564207769746820657468658152603960f91b602082015260400192915050565b600061486e601683615027565b751cddd85c081d1bdbc81b185c99d9481d1bc8199a5b1b60521b815260200192915050565b60006148a0601583615027565b74696e697469616c4d617267696e20746f6f206c6f7760581b815260200192915050565b60006148d1601f83615027565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b805160e083019061490e848261415a565b506020820151614921602085018261415a565b506040820151614934604085018261415a565b506060820151614947606085018261415a565b50608082015161495a6080850182614183565b5060a082015161496d60a0850182614183565b5060c0820151612a6560c0850182614183565b600061498c828761418c565b60208201915061499c8286614169565b6014820191506149ac8285614169565b6014820191506149bc828461418c565b50602001949350505050565b600061169b828461419d565b6020810161164c828461415a565b604081016149f0828561415a565b61169b602083018461415a565b60808101614a0b828761415a565b614a18602083018661415a565b614a25604083018561415a565b610b626060830184614183565b60608101614a40828661415a565b614a4d602083018561415a565b6118e16040830184614183565b60808101614a68828761415a565b614a75602083018661415a565b614a256040830185614183565b60a08101614a90828861415a565b614a9d602083018761415a565b614aaa6040830186614183565b614ab76060830185614183565b6110f06080830184614183565b6101008101614ad3828b61415a565b614ae0602083018a61415a565b614aed6040830189614183565b614afa6060830188614183565b614b076080830187614183565b614b1460a0830186614183565b614b2160c0830185614183565b614b2e60e0830184614183565b9998505050505050505050565b6101208101614b4a828c61415a565b614b57602083018b61415a565b614b64604083018a614183565b614b716060830189614183565b614b7e6080830188614183565b614b8b60a0830187614183565b614b9860c0830186614183565b614ba560e0830185614183565b614bb3610100830184614183565b9a9950505050505050505050565b60408101614bcf828561415a565b61169b6020830184614183565b60608101614bea828661415a565b614a4d6020830185614183565b6020810161164c828461417a565b6101008101614c14828b614183565b614c21602083018a61417a565b614c2e604083018961415a565b614c3b606083018861415a565b614b07608083018761415a565b6101808101614c57828f614183565b614c64602083018e614183565b614c71604083018d614183565b614c7e606083018c61417a565b614c8b608083018b614183565b614c9860a083018a614183565b614ca560c0830189614183565b614cb260e0830188614183565b614cc0610100830187614183565b614cce610120830186614183565b614cdc61014083018561415a565b614cea61016083018461415a565b9d9c50505050505050505050505050565b6020810161164c82846141cc565b6020808252810161169b81846141d5565b6020808252810161164c8161420d565b6020808252810161164c8161423c565b6020808252810161164c8161425e565b6020808252810161164c81614297565b6020808252810161164c816142c3565b6020808252810161164c8161430b565b6020808252810161164c81614344565b6020808252810161164c81614371565b6020808252810161164c816143aa565b6020808252810161164c816143d4565b6020808252810161164c81614405565b6020808252810161164c8161443e565b6020808252810161164c8161446d565b6020808252810161164c81614498565b6020808252810161164c816144d1565b6020808252810161164c816144f8565b6020808252810161164c81614526565b6020808252810161164c81614550565b6020808252810161164c8161457a565b6020808252810161164c816145a5565b6020808252810161164c816145cf565b6020808252810161164c81614612565b6020808252810161164c8161463a565b6020808252810161164c81614673565b6020808252810161164c816146a1565b6020808252810161164c816146d2565b6020808252810161164c81614702565b6020808252810161164c81614752565b6020808252810161164c81614781565b6020808252810161164c816147a9565b6020808252810161164c816147d2565b6020808252810161164c8161481e565b6020808252810161164c81614861565b6020808252810161164c81614893565b6020808252810161164c816148c4565b60e0810161164c82846148fd565b6020810161164c8284614183565b60408101614bcf8285614183565b60608101614bea8286614183565b60a08101614f908288614183565b614a9d6020830187614183565b60c08101614fab8289614183565b614fb86020830188614183565b614fc56040830187614183565b614fd26060830186614183565b614fdf6080830185614183565b614fec60a0830184614183565b979650505050505050565b60405181810167ffffffffffffffff8111828210171561501657600080fd5b604052919050565b5190565b919050565b90815260200190565b600061164c82615050565b151590565b90565b6001600160e01b03191690565b6001600160a01b031690565b600061164c82615030565b60005b8381101561508257818101518382015260200161506a565b83811115612a655750506000910152565b600061164c82600061164c826150ae565b601f01601f191690565b60601b90565b6150bd81615030565b81146114b657600080fd5b6150bd8161503b565b6150bd81615040565b6150bd8161504356fea365627a7a7231582006262a07965035f357589c6bb924f7de44a817506b83c56eb712cec5934fdd626c6578706572696d656e74616cf564736f6c63430005110040", "libraries": { - "SwapsImplSovrynSwapLib": "0x94D7CEE3Fe77432312e4faCf4dc416CA5Cd224a6" + "SwapsImplSovrynSwapLib": "0xa98f000a528AC0bFf10a3FE499378437de449659" }, "devdoc": { "methods": { @@ -2118,7 +2118,7 @@ "storageLayout": { "storage": [ { - "astId": 54790, + "astId": 54832, "contract": "contracts/modules/LoanOpenings.sol:LoanOpenings", "label": "reentrancyLock", "offset": 0, @@ -2126,7 +2126,7 @@ "type": "t_uint256" }, { - "astId": 54606, + "astId": 54648, "contract": "contracts/modules/LoanOpenings.sol:LoanOpenings", "label": "_owner", "offset": 0, diff --git a/deployment/deployments/rskSovrynTestnet/SwapsImplSovrynSwapLib.json b/deployment/deployments/rskSovrynTestnet/SwapsImplSovrynSwapLib.json index a7d3b1185..93613f072 100644 --- a/deployment/deployments/rskSovrynTestnet/SwapsImplSovrynSwapLib.json +++ b/deployment/deployments/rskSovrynTestnet/SwapsImplSovrynSwapLib.json @@ -1,5 +1,5 @@ { - "address": "0x94D7CEE3Fe77432312e4faCf4dc416CA5Cd224a6", + "address": "0xa98f000a528AC0bFf10a3FE499378437de449659", "abi": [ { "constant": true, @@ -106,28 +106,28 @@ "type": "function" } ], - "transactionHash": "0xb9b7656fb00bd2ee7c4e1ae897c2ff6e6fd6436d317b36d9242a008fd7e85cb7", + "transactionHash": "0x6d4186b5e34ed9d9173e8b842f2d8408b67d21993dcad38e98073302fad15d88", "receipt": { "to": null, - "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", - "contractAddress": "0x94D7CEE3Fe77432312e4faCf4dc416CA5Cd224a6", + "from": "0x8C9143221F2b72Fcef391893c3a02Cf0fE84f50b", + "contractAddress": "0xa98f000a528AC0bFf10a3FE499378437de449659", "transactionIndex": 0, - "gasUsed": "1722914", + "gasUsed": "1722978", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0xce01c045f331e6742ec77fc78423fd5b21ee00c3b608947fed37f998f66b4a2b", - "transactionHash": "0xb9b7656fb00bd2ee7c4e1ae897c2ff6e6fd6436d317b36d9242a008fd7e85cb7", + "blockHash": "0x863dc66c1c0e425fcdcc992f3e93c130b73fbee6bb7be1d5ecf7c643dc1f2e26", + "transactionHash": "0x6d4186b5e34ed9d9173e8b842f2d8408b67d21993dcad38e98073302fad15d88", "logs": [], - "blockNumber": 4578750, - "cumulativeGasUsed": "1722914", + "blockNumber": 4704807, + "cumulativeGasUsed": "1722978", "status": 1, "byzantium": true }, "args": [], - "numDeployments": 1, - "solcInputHash": "9310031b42d2950fea7a6220c73f2cc4", - "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[{\"internalType\":\"string\",\"name\":\"source\",\"type\":\"string\"}],\"name\":\"getContractHexName\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"result\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sourceTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceTokenAmount\",\"type\":\"uint256\"}],\"name\":\"getExpectedRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sourceTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceTokenAmount\",\"type\":\"uint256\"}],\"name\":\"getExpectedReturn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"expectedReturn\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sovrynSwapRegistryAddress\",\"type\":\"address\"}],\"name\":\"getSovrynSwapNetworkContract\",\"outputs\":[{\"internalType\":\"contract ISovrynSwapNetwork\",\"name\":\"\",\"type\":\"ISovrynSwapNetwork\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{\"getContractHexName(string)\":{\"params\":{\"source\":\"The name of the contract.\"}},\"getExpectedRate(address,address,uint256)\":{\"params\":{\"destTokenAddress\":\"The address of the destination token contract.\",\"sourceTokenAddress\":\"The address of the source token contract.\",\"sourceTokenAmount\":\"The amount of source tokens to get the rate for.\"}},\"getExpectedReturn(address,address,uint256)\":{\"params\":{\"destTokenAddress\":\"The address of the destination token contract.\",\"sourceTokenAddress\":\"The address of the source token contract.\",\"sourceTokenAmount\":\"The amount of source tokens to get the return for.\"}},\"getSovrynSwapNetworkContract(address)\":{\"params\":{\"sovrynSwapRegistryAddress\":\"The address of the registry.\"}},\"swap(SwapsImplSovrynSwapLib.SwapParams)\":{\"params\":{\"params\":\"SwapParams struct sourceTokenAddress The address of the source tokens. destTokenAddress The address of the destination tokens. receiverAddress The address who will received the swap token results returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract). minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0). maxSourceTokenAmount The maximum amount of source tokens to swapped. requiredDestTokenAmount The required amount of destination tokens.\"}}},\"title\":\"Swaps Implementation Sovryn contract.\"},\"userdoc\":{\"methods\":{\"getContractHexName(string)\":{\"notice\":\"Get the hex name of a contract.\"},\"getExpectedRate(address,address,uint256)\":{\"notice\":\"Get the expected rate for 1 source token when exchanging the given amount of source tokens.\"},\"getExpectedReturn(address,address,uint256)\":{\"notice\":\"Get the expected return amount when exchanging the given amount of source tokens.Right now, this function is being called directly by _swapsExpectedReturn from the protocol So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call. Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\"},\"getSovrynSwapNetworkContract(address)\":{\"notice\":\"Look up the Sovryn swap network contract registered at the given address.\"},\"swap(SwapsImplSovrynSwapLib.SwapParams)\":{\"notice\":\"Swap the source token for the destination token on the oracle based AMM. On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0 -> swap the minSourceTokenAmount On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0 -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded. On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0 -> same as on rollover. minimum amount is not considered at all.\"}},\"notice\":\"This contract code comes from bZx. bZx is a protocol for tokenized margin trading and lending https://bzx.network similar to the dYdX protocol. * This contract contains the implementation of swap process and rate calculations for Sovryn network.\"}},\"settings\":{\"compilationTarget\":{\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":\"SwapsImplSovrynSwapLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nlibrary MarginTradeStructHelpers {\\n struct SentAddresses {\\n address lender;\\n address borrower;\\n address receiver;\\n address manager;\\n }\\n\\n struct SentAmounts {\\n uint256 interestRate;\\n uint256 newPrincipal;\\n uint256 interestInitialAmount;\\n uint256 loanTokenSent;\\n uint256 collateralTokenSent;\\n uint256 minEntryPrice;\\n uint256 loanToCollateralSwapRate;\\n uint256 interestDuration;\\n uint256 entryLeverage;\\n }\\n}\\n\",\"keccak256\":\"0xf0612e2c0d13604a67c3d55efe88810c089f0b84ca63bd3ce82c1e09b0938973\"},\"contracts/core/Objects.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./objects/LoanStruct.sol\\\";\\nimport \\\"./objects/LoanParamsStruct.sol\\\";\\nimport \\\"./objects/OrderStruct.sol\\\";\\nimport \\\"./objects/LenderInterestStruct.sol\\\";\\nimport \\\"./objects/LoanInterestStruct.sol\\\";\\n\\n/**\\n * @title Objects contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract inherints and aggregates several structures needed to handle\\n * loans on the protocol.\\n * */\\ncontract Objects is\\n LoanStruct,\\n LoanParamsStruct,\\n OrderStruct,\\n LenderInterestStruct,\\n LoanInterestStruct\\n{\\n\\n}\\n\",\"keccak256\":\"0xa30b8887af813997ebb480f0aa296245f9f3bd728382060059aa087cd9ee332c\"},\"contracts/core/State.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./Objects.sol\\\";\\nimport \\\"../mixins/EnumerableAddressSet.sol\\\";\\nimport \\\"../mixins/EnumerableBytes32Set.sol\\\";\\nimport \\\"../openzeppelin/ReentrancyGuard.sol\\\";\\nimport \\\"../openzeppelin/Ownable.sol\\\";\\nimport \\\"../openzeppelin/SafeMath.sol\\\";\\nimport \\\"../interfaces/IWrbtcERC20.sol\\\";\\nimport \\\"../reentrancy/SharedReentrancyGuard.sol\\\";\\n\\n/**\\n * @title State contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage values of the Protocol.\\n * */\\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\\n using SafeMath for uint256;\\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\\n\\n /// Handles asset reference price lookups.\\n address public priceFeeds;\\n\\n /// Handles asset swaps using dex liquidity.\\n address public swapsImpl;\\n\\n /// Contract registry address of the Sovryn swap network.\\n address public sovrynSwapContractRegistryAddress;\\n\\n /// Implementations of protocol functions.\\n mapping(bytes4 => address) public logicTargets;\\n\\n /// Loans: loanId => Loan\\n mapping(bytes32 => Loan) public loans;\\n\\n /// Loan parameters: loanParamsId => LoanParams\\n mapping(bytes32 => LoanParams) public loanParams;\\n\\n /// lender => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\\n\\n /// borrower => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\\n\\n /// loanId => delegated => approved\\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\\n\\n /**\\n *** Interest ***\\n **/\\n\\n /// lender => loanToken => LenderInterest object\\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\\n\\n /// loanId => LoanInterest object\\n mapping(bytes32 => LoanInterest) public loanInterest;\\n\\n /**\\n *** Internals ***\\n **/\\n\\n /// Implementations set.\\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\\n\\n /// Active loans set.\\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\\n\\n /// Lender loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\\n\\n /// Borrow loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\\n\\n /// User loan params set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\\n\\n /// Address controlling fee withdrawals.\\n address public feesController;\\n\\n /// 10% fee /// Fee taken from lender interest payments.\\n uint256 public lendingFeePercent = 10**19;\\n\\n /// Total interest fees received and not withdrawn per asset.\\n mapping(address => uint256) public lendingFeeTokensHeld;\\n\\n /// Total interest fees withdraw per asset.\\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\\n mapping(address => uint256) public lendingFeeTokensPaid;\\n\\n /// 0.15% fee /// Fee paid for each trade.\\n uint256 public tradingFeePercent = 15 * 10**16;\\n\\n /// Total trading fees received and not withdrawn per asset.\\n mapping(address => uint256) public tradingFeeTokensHeld;\\n\\n /// Total trading fees withdraw per asset\\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\\n mapping(address => uint256) public tradingFeeTokensPaid;\\n\\n /// 0.09% fee /// Origination fee paid for each loan.\\n uint256 public borrowingFeePercent = 9 * 10**16;\\n\\n /// Total borrowing fees received and not withdrawn per asset.\\n mapping(address => uint256) public borrowingFeeTokensHeld;\\n\\n /// Total borrowing fees withdraw per asset.\\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\\n mapping(address => uint256) public borrowingFeeTokensPaid;\\n\\n /// Current protocol token deposit balance.\\n uint256 public protocolTokenHeld;\\n\\n /// Lifetime total payout of protocol token.\\n uint256 public protocolTokenPaid;\\n\\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\\n uint256 public affiliateFeePercent = 5 * 10**18;\\n\\n /// 5% collateral discount /// Discount on collateral for liquidators.\\n uint256 public liquidationIncentivePercent = 5 * 10**18;\\n\\n /// loanPool => underlying\\n mapping(address => address) public loanPoolToUnderlying;\\n\\n /// underlying => loanPool\\n mapping(address => address) public underlyingToLoanPool;\\n\\n /// Loan pools set.\\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\\n\\n /// Supported tokens for swaps.\\n mapping(address => bool) public supportedTokens;\\n\\n /// % disagreement between swap rate and reference rate.\\n uint256 public maxDisagreement = 5 * 10**18;\\n\\n /// Used as buffer for swap source amount estimations.\\n uint256 public sourceBuffer = 10000;\\n\\n /// Maximum support swap size in rBTC\\n uint256 public maxSwapSize = 50 ether;\\n\\n /// Nonce per borrower. Used for loan id creation.\\n mapping(address => uint256) public borrowerNonce;\\n\\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\\n uint256 public rolloverBaseReward = 16800000000000;\\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\\n\\n IWrbtcERC20 public wrbtcToken;\\n address public protocolTokenAddress;\\n\\n /// 50% fee rebate\\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\\n uint256 public feeRebatePercent = 50 * 10**18;\\n\\n address public admin;\\n\\n /// For modules interaction.\\n address public protocolAddress;\\n\\n /**\\n *** Affiliates ***\\n **/\\n\\n /// The flag is set on the user's first trade.\\n mapping(address => bool) public userNotFirstTradeFlag;\\n\\n /// User => referrer (affiliate).\\n mapping(address => address) public affiliatesUserReferrer;\\n\\n /// List of referral addresses affiliated to the referrer.\\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\\n\\n /// @dev Referral threshold for paying out to the referrer.\\n /// The referrer reward is being accumulated and locked until the threshold is passed.\\n uint256 public minReferralsToPayout = 3;\\n\\n /// @dev Total affiliate SOV rewards that held in the protocol\\n /// (Because the minimum referrals is less than the rule)\\n mapping(address => uint256) public affiliateRewardsHeld;\\n\\n /// @dev For affiliates SOV Bonus proccess.\\n address public sovTokenAddress;\\n address public lockedSOVAddress;\\n\\n /// @dev 20% fee share of trading token fee.\\n /// Fee share of trading token fee for affiliate program.\\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\\n\\n /// @dev Addresses of tokens in which commissions were paid to referrers.\\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\\n\\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\\n\\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\\n bool public pause; //Flag to pause all protocol modules\\n\\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\\n\\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\\n uint256 internal tradingRebateRewardsBasisPoint;\\n\\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\\n /// Will be used in internal swap.\\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\\n\\n address internal pauser;\\n\\n /**\\n * @notice Add signature and target to storage.\\n * @dev Protocol is a proxy and requires a way to add every\\n * module function dynamically during deployment.\\n * */\\n function _setTarget(bytes4 sig, address target) internal {\\n logicTargets[sig] = target;\\n\\n if (target != address(0)) {\\n logicTargetsSet.addBytes32(bytes32(sig));\\n } else {\\n logicTargetsSet.removeBytes32(bytes32(sig));\\n }\\n }\\n\\n modifier onlyAdminOrOwner() {\\n require(isOwner() || admin == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n\\n modifier onlyPauserOrOwner() {\\n require(isOwner() || pauser == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0xf8dfc02f3dc790c73b390a69898d0281c4473487bc91fec1f28fbebceacd3b3c\"},\"contracts/core/objects/LenderInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Lender Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Lender Interest.\\n * */\\ncontract LenderInterestStruct {\\n struct LenderInterest {\\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\\n uint256 paidTotal; /// Total interest paid so far for asset.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0x6583baadddded384836cec469980e7973ec09310ae505b4a2ec67fb7bc19e452\"},\"contracts/core/objects/LoanInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Interest.\\n * */\\ncontract LoanInterestStruct {\\n struct LoanInterest {\\n uint256 owedPerDay; /// Interest owed per day for loan.\\n uint256 depositTotal; /// Total escrowed interest for loan.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0xd9034c6adb1b72e1593589dca024dc4730a1ee8bf6b2dca9d22283f2e7159590\"},\"contracts/core/objects/LoanParamsStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Parameters.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Parameters.\\n * */\\ncontract LoanParamsStruct {\\n struct LoanParams {\\n /// @dev ID of loan params object.\\n bytes32 id;\\n /// @dev If false, this object has been disabled by the owner and can't\\n /// be used for future loans.\\n bool active;\\n /// @dev Owner of this object.\\n address owner;\\n /// @dev The token being loaned.\\n address loanToken;\\n /// @dev The required collateral token.\\n address collateralToken;\\n /// @dev The minimum allowed initial margin.\\n uint256 minInitialMargin;\\n /// @dev An unhealthy loan when current margin is at or below this value.\\n uint256 maintenanceMargin;\\n /// @dev The maximum term for new loans (0 means there's no max term).\\n uint256 maxLoanTerm;\\n }\\n}\\n\",\"keccak256\":\"0xe15aa97713521da7f501e5225af9d92cf34bd68d286dbfed86aa75aabb323945\"},\"contracts/core/objects/LoanStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Object.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Object.\\n * */\\ncontract LoanStruct {\\n struct Loan {\\n bytes32 id; /// ID of the loan.\\n bytes32 loanParamsId; /// The linked loan params ID.\\n bytes32 pendingTradesId; /// The linked pending trades ID.\\n bool active; /// If false, the loan has been fully closed.\\n uint256 principal; /// Total borrowed amount outstanding.\\n uint256 collateral; /// Total collateral escrowed for the loan.\\n uint256 startTimestamp; /// Loan start time.\\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\\n uint256 startMargin; /// Initial margin when the loan opened.\\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\\n address borrower; /// Borrower of this loan.\\n address lender; /// Lender of this loan.\\n }\\n}\\n\",\"keccak256\":\"0x7d05c3096a86d5892e4e72f3a01a5a806f13a5ac90ca6339c611e75c603637b4\"},\"contracts/core/objects/OrderStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Order.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Order.\\n * */\\ncontract OrderStruct {\\n struct Order {\\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\\n uint256 interestRate; /// Interest rate defined by the creator of this order.\\n uint256 minLoanTerm; /// Minimum loan term allowed.\\n uint256 maxLoanTerm; /// Maximum loan term allowed.\\n uint256 createdTimestamp; /// Timestamp when this order was created.\\n uint256 expirationTimestamp; /// Timestamp when this order expires.\\n }\\n}\\n\",\"keccak256\":\"0xcc053c5da34a5927041162259bf856ba913f3524ca03e63ad0c5877777d17e0f\"},\"contracts/events/AffiliatesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\ncontract AffiliatesEvents is ModulesCommonEvents {\\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\\n\\n event SetAffiliatesReferrerFail(\\n address indexed user,\\n address indexed referrer,\\n bool alreadySet,\\n bool userNotFirstTrade\\n );\\n\\n event SetUserNotFirstTradeFlag(address indexed user);\\n\\n event PayTradingFeeToAffiliate(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n bool indexed isHeld,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountPaid\\n );\\n\\n event PayTradingFeeToAffiliateFail(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountTryingToPaid\\n );\\n\\n event WithdrawAffiliatesReferrerTokenFees(\\n address indexed referrer,\\n address indexed receiver,\\n address indexed tokenAddress,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xf72cf23e90db3c49589ddc4e1796680ebfb69a9b146db89f9b61f5fcf6dd95ba\"},\"contracts/events/FeesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Fees Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for fee payments.\\n * */\\ncontract FeesEvents {\\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\\n\\n event PayTradingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event PayBorrowingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event EarnReward(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n\\n event EarnRewardFail(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n}\\n\",\"keccak256\":\"0xe69bf53e15479be5fde1cbaadaf0c004ee038e8a6a37c99f7769bf5d8387015f\"},\"contracts/events/LoanClosingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Closing Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan closing operations.\\n * */\\ncontract LoanClosingsEvents is ModulesCommonEvents {\\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\\n event CloseWithDeposit(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address closer,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\\n event CloseWithSwap(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n address closer,\\n uint256 positionCloseSize,\\n uint256 loanCloseAmount,\\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\\n event Liquidate(\\n address indexed user,\\n address indexed liquidator,\\n bytes32 indexed loanId,\\n address lender,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n event Rollover(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n uint256 principal,\\n uint256 collateral,\\n uint256 endTimestamp,\\n address rewardReceiver,\\n uint256 reward\\n );\\n\\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\\n}\\n\",\"keccak256\":\"0x1ea325b9a213012865a52f38941ce6c1e8c29dce919215b5bdcc63a8a5980be1\"},\"contracts/events/LoanMaintenanceEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Maintenance Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan maintenance operations.\\n * */\\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\\n}\\n\",\"keccak256\":\"0xdee5098b947c22bcef6e38ecaf62bae6941572d1c245d2065ad41ea4f494c61d\"},\"contracts/events/LoanOpeningsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Openings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan openings operations.\\n * */\\ncontract LoanOpeningsEvents is ModulesCommonEvents {\\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\\n event Borrow(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 newCollateral,\\n uint256 interestRate,\\n uint256 interestDuration,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\\n event Trade(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n uint256 positionSize,\\n uint256 borrowedAmount,\\n uint256 interestRate,\\n uint256 settlementDate,\\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\\n uint256 entryLeverage,\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\\n event DelegatedManagerSet(\\n bytes32 indexed loanId,\\n address indexed delegator,\\n address indexed delegated,\\n bool isActive\\n );\\n}\\n\",\"keccak256\":\"0x585710ce6c570c6dbd1b8daf43b63a54b1d60ad01ee1dc3cae407d74d78f3093\"},\"contracts/events/LoanSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan settings operations.\\n * */\\ncontract LoanSettingsEvents is ModulesCommonEvents {\\n event LoanParamsSetup(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\\n\\n event LoanParamsDisabled(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\\n}\\n\",\"keccak256\":\"0xae9c49678a7bc02c2283648939c474c8bfd33781506e05c635c8334c5bf8682f\"},\"contracts/events/ModulesCommonEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\n/**\\n * @title The common events for all modules\\n * @notice This contract contains the events which will be used by all modules\\n **/\\n\\ncontract ModulesCommonEvents {\\n event ProtocolModuleContractReplaced(\\n address indexed prevModuleContractAddress,\\n address indexed newModuleContractAddress,\\n bytes32 indexed module\\n );\\n}\\n\",\"keccak256\":\"0xb07af42d7e6b0fe983889b883691b662a58d2ef8d75b3f32f17faff1871c8b8f\"},\"contracts/events/ProtocolSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title The Protocol Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for protocol settings operations.\\n * */\\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetLoanPool(\\n address indexed sender,\\n address indexed loanPool,\\n address indexed underlying\\n );\\n\\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\\n\\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateTradingTokenFeePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetLiquidationIncentivePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetFeesController(\\n address indexed sender,\\n address indexed oldController,\\n address indexed newController\\n );\\n\\n event SetWrbtcToken(\\n address indexed sender,\\n address indexed oldWethToken,\\n address indexed newWethToken\\n );\\n\\n event SetSovrynSwapContractRegistryAddress(\\n address indexed sender,\\n address indexed oldSovrynSwapContractRegistryAddress,\\n address indexed newSovrynSwapContractRegistryAddress\\n );\\n\\n event SetProtocolTokenAddress(\\n address indexed sender,\\n address indexed oldProtocolToken,\\n address indexed newProtocolToken\\n );\\n\\n event WithdrawFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 lendingAmount,\\n uint256 tradingAmount,\\n uint256 borrowingAmount,\\n uint256 wRBTCConverted\\n );\\n\\n event WithdrawLendingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawTradingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawBorrowingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetRebatePercent(\\n address indexed sender,\\n uint256 oldRebatePercent,\\n uint256 newRebatePercent\\n );\\n\\n event SetSpecialRebates(\\n address indexed sender,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 oldSpecialRebatesPercent,\\n uint256 newSpecialRebatesPercent\\n );\\n\\n event SetProtocolAddress(\\n address indexed sender,\\n address indexed oldProtocol,\\n address indexed newProtocol\\n );\\n\\n event SetMinReferralsToPayoutAffiliates(\\n address indexed sender,\\n uint256 oldMinReferrals,\\n uint256 newMinReferrals\\n );\\n\\n event SetSOVTokenAddress(\\n address indexed sender,\\n address indexed oldTokenAddress,\\n address indexed newTokenAddress\\n );\\n\\n event SetLockedSOVAddress(\\n address indexed sender,\\n address indexed oldAddress,\\n address indexed newAddress\\n );\\n\\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\\n\\n event SetTradingRebateRewardsBasisPoint(\\n address indexed sender,\\n uint256 oldBasisPoint,\\n uint256 newBasisPoint\\n );\\n\\n event SetRolloverFlexFeePercent(\\n address indexed sender,\\n uint256 oldRolloverFlexFeePercent,\\n uint256 newRolloverFlexFeePercent\\n );\\n\\n event SetDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event RemoveDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\\n\\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\\n}\\n\",\"keccak256\":\"0x20ca66a2c53669aa33379bf5233e3bcdddbba3504cd430a0143f0ee3ce1c2641\"},\"contracts/events/SwapsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Swaps Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for swap operations.\\n * */\\ncontract SwapsEvents is ModulesCommonEvents {\\n event LoanSwap(\\n bytes32 indexed loanId,\\n address indexed sourceToken,\\n address indexed destToken,\\n address borrower,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n\\n event ExternalSwap(\\n address indexed user,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n}\\n\",\"keccak256\":\"0x0a1cd289076675980b916941ed923146160d34a8669fc3fb4a06610f285dfbd1\"},\"contracts/feeds/IPriceFeeds.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface IPriceFeeds {\\n function queryRate(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 rate, uint256 precision);\\n\\n function queryPrecision(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 precision);\\n\\n function queryReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount\\n ) external view returns (uint256 destAmount);\\n\\n function checkPriceDisagreement(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount,\\n uint256 destAmount,\\n uint256 maxSlippage\\n ) external view returns (uint256 sourceToDestSwapRate);\\n\\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\\n\\n function getMaxDrawdown(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (uint256);\\n\\n function getCurrentMarginAndCollateralSize(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\\n\\n function getCurrentMargin(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\\n\\n function shouldLiquidate(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (bool);\\n\\n function getFastGasPrice(address payToken) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x2e2c2b393336efedb97659a2fc21c8dfb75b70e15d2422a3bcbf7ebd5fc83c82\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/interfaces/ISovryn.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\npragma experimental ABIEncoderV2;\\n//TODO: stored in ./interfaces only while brownie isn't removed\\n//TODO: move to contracts/interfaces after with brownie is removed\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/ProtocolSettingsEvents.sol\\\";\\nimport \\\"../events/LoanSettingsEvents.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../events/LoanMaintenanceEvents.sol\\\";\\nimport \\\"../events/LoanClosingsEvents.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../events/AffiliatesEvents.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\ncontract ISovryn is\\n State,\\n ProtocolSettingsEvents,\\n LoanSettingsEvents,\\n LoanOpeningsEvents,\\n LoanMaintenanceEvents,\\n LoanClosingsEvents,\\n SwapsEvents,\\n AffiliatesEvents,\\n FeesEvents\\n{\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n ////// Protocol //////\\n\\n function replaceContract(address target) external;\\n\\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\\n\\n function getTarget(string calldata sig) external view returns (address);\\n\\n ////// Protocol Settings //////\\n\\n function setSovrynProtocolAddress(address newProtocolAddress) external;\\n\\n function setSOVTokenAddress(address newSovTokenAddress) external;\\n\\n function setLockedSOVAddress(address newSOVLockedAddress) external;\\n\\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\\n\\n function setPriceFeedContract(address newContract) external;\\n\\n function setSwapsImplContract(address newContract) external;\\n\\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\\n\\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\\n\\n function setLendingFeePercent(uint256 newValue) external;\\n\\n function setTradingFeePercent(uint256 newValue) external;\\n\\n function setBorrowingFeePercent(uint256 newValue) external;\\n\\n function setSwapExternalFeePercent(uint256 newValue) external;\\n\\n function setAffiliateFeePercent(uint256 newValue) external;\\n\\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\\n\\n function setLiquidationIncentivePercent(uint256 newAmount) external;\\n\\n function setMaxDisagreement(uint256 newAmount) external;\\n\\n function setSourceBuffer(uint256 newAmount) external;\\n\\n function setMaxSwapSize(uint256 newAmount) external;\\n\\n function setFeesController(address newController) external;\\n\\n function withdrawFees(address[] calldata tokens, address receiver)\\n external\\n returns (uint256 totalWRBTCWithdrawn);\\n\\n function withdrawLendingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawTradingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawBorrowingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawProtocolToken(address receiver, uint256 amount)\\n external\\n returns (address, bool);\\n\\n function depositProtocolToken(uint256 amount) external;\\n\\n function getLoanPoolsList(uint256 start, uint256 count)\\n external\\n view\\n returns (bytes32[] memory);\\n\\n function isLoanPool(address loanPool) external view returns (bool);\\n\\n function setWrbtcToken(address wrbtcTokenAddress) external;\\n\\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\\n\\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\\n\\n function setRolloverBaseReward(uint256 transactionCost) external;\\n\\n function setRebatePercent(uint256 rebatePercent) external;\\n\\n function setSpecialRebates(\\n address sourceToken,\\n address destToken,\\n uint256 specialRebatesPercent\\n ) external;\\n\\n function getSpecialRebates(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 specialRebatesPercent);\\n\\n function togglePaused(bool paused) external;\\n\\n function isProtocolPaused() external view returns (bool);\\n\\n ////// SwapsImplSovrynSwapModule //////\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (address);\\n\\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\\n\\n function swapsImplExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function swapsImplExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256 expectedReturn);\\n\\n ////// Loan Settings //////\\n\\n function setupLoanParams(LoanParams[] calldata loanParamsList)\\n external\\n returns (bytes32[] memory loanParamsIdList);\\n\\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\\n\\n function getLoanParams(bytes32[] calldata loanParamsIdList)\\n external\\n view\\n returns (LoanParams[] memory loanParamsList);\\n\\n function getLoanParamsList(\\n address owner,\\n uint256 start,\\n uint256 count\\n ) external view returns (bytes32[] memory loanParamsList);\\n\\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\\n\\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\\n\\n ////// Loan Openings //////\\n\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId, // if 0, start a new loan\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n // lender: must match loan if loanId provided\\n // borrower: must match loan if loanId provided\\n // receiver: receiver of funds (address(0) assumes borrower address)\\n // manager: delegated manager of loan unless address(0)\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n // newRate: new loan interest rate\\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\\n // collateralTokenReceived: total collateralToken deposit\\n bytes calldata loanDataBytes\\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\\n\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external;\\n\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256);\\n\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 collateralAmountRequired);\\n\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 borrowAmount);\\n\\n ////// Loan Closings //////\\n\\n function liquidate(\\n bytes32 loanId,\\n address receiver,\\n uint256 closeAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 seizedAmount,\\n address seizedToken\\n );\\n\\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\\n\\n function closeWithDeposit(\\n bytes32 loanId,\\n address receiver,\\n uint256 depositAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n function closeWithSwap(\\n bytes32 loanId,\\n address receiver,\\n uint256 swapAmount, // denominated in collateralToken\\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\\n bytes calldata loanDataBytes\\n )\\n external\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n ////// Loan Maintenance //////\\n\\n function depositCollateral(\\n bytes32 loanId,\\n uint256 depositAmount // must match msg.value if ether is sent\\n ) external payable;\\n\\n function withdrawCollateral(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 actualWithdrawAmount);\\n\\n function withdrawAccruedInterest(address loanToken) external;\\n\\n function getLenderInterestData(address lender, address loanToken)\\n external\\n view\\n returns (\\n uint256 interestPaid,\\n uint256 interestPaidDate,\\n uint256 interestOwedPerDay,\\n uint256 interestUnPaid,\\n uint256 interestFeePercent,\\n uint256 principalTotal\\n );\\n\\n function getLoanInterestData(bytes32 loanId)\\n external\\n view\\n returns (\\n address loanToken,\\n uint256 interestOwedPerDay,\\n uint256 interestDepositTotal,\\n uint256 interestDepositRemaining\\n );\\n\\n struct LoanReturnData {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; // collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n }\\n\\n struct LoanReturnDataV2 {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n address borrower;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; /// collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n uint256 creationTimestamp;\\n }\\n\\n function getUserLoans(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getUserLoansV2(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\\n\\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\\n\\n function getActiveLoans(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getActiveLoansV2(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function extendLoanDuration(\\n bytes32 loanId,\\n uint256 depositAmount,\\n bool useCollateral,\\n bytes calldata /// loanDataBytes, for future use.\\n ) external returns (uint256 secondsExtended);\\n\\n function reduceLoanDuration(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 secondsReduced);\\n\\n ////// Swaps External //////\\n function swapExternal(\\n address sourceToken,\\n address destToken,\\n address receiver,\\n address returnToSender,\\n uint256 sourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n uint256 minReturn,\\n bytes calldata swapData\\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\\n\\n function getSwapExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function checkPriceDivergence(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount,\\n uint256 minReturn\\n ) public view;\\n\\n ////// Affiliates Module //////\\n\\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\\n\\n function setUserNotFirstTradeFlag(address user) external;\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address referrer,\\n address trader,\\n address token,\\n uint256 tradingFeeTokenBaseAmount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n\\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\\n\\n function getReferralsList(address referrer) external view returns (address[] memory refList);\\n\\n function getAffiliatesReferrerBalances(address referrer)\\n external\\n view\\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\\n\\n function getAffiliatesReferrerTokensList(address referrer)\\n external\\n view\\n returns (address[] memory tokensList);\\n\\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\\n external\\n view\\n returns (uint256);\\n\\n function withdrawAffiliatesReferrerTokenFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external;\\n\\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\\n\\n function getProtocolAddress() external view returns (address);\\n\\n function getSovTokenAddress() external view returns (address);\\n\\n function getLockedSOVAddress() external view returns (address);\\n\\n function getFeeRebatePercent() external view returns (uint256);\\n\\n function getMinReferralsToPayout() external view returns (uint256);\\n\\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\\n\\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\\n\\n function getAffiliateTradingTokenFeePercent()\\n external\\n view\\n returns (uint256 affiliateTradingTokenFeePercent);\\n\\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\\n external\\n view\\n returns (uint256 rbtcTotalAmount);\\n\\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\\n\\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\\n\\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\\n\\n function getDedicatedSOVRebate() external view returns (uint256);\\n\\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\\n\\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external\\n view\\n returns (IERC20[] memory);\\n\\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\\n\\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external;\\n\\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\\n external\\n view\\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\\n\\n function setAdmin(address newAdmin) external;\\n\\n function getAdmin() external view returns (address);\\n\\n function setPauser(address newPauser) external;\\n\\n function getPauser() external view returns (address);\\n}\\n\",\"keccak256\":\"0x4e470e1fe1719c2c58b0e44aedce3ee6a21191063b533ccb71c9219a192e8884\"},\"contracts/interfaces/IWrbtc.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ninterface IWrbtc {\\n function deposit() external payable;\\n\\n function withdraw(uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x20fdfe4b5e32fd7f863b3fa128e3c80bd4ccf090a4ffba56186ef3b7f2a80492\"},\"contracts/interfaces/IWrbtcERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./IWrbtc.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\n\\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\\n\",\"keccak256\":\"0x7301a8c8ca7aa016ec94268a16d07366875f2e406442e929968dd745b1ee5be5\"},\"contracts/mixins/EnumerableAddressSet.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Based on Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * As of v2.5.0, only `address` sets are supported.\\n *\\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\\n *\\n * _Available since v2.5.0._\\n */\\nlibrary EnumerableAddressSet {\\n struct AddressSet {\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(address => uint256) index;\\n address[] values;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n * Returns false if the value was already in the set.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n * Returns false if the value was not present in the set.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n // If the element we're deleting is the last one, we can just remove it without doing a swap\\n if (lastIndex != toDeleteIndex) {\\n address lastValue = set.values[lastIndex];\\n\\n // Move the last value to the index where the deleted value is\\n set.values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n // Delete the index entry for the deleted value\\n delete set.index[value];\\n\\n // Delete the old entry for the moved value\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns an array with all values in the set. O(N).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\\n address[] memory output = new address[](set.values.length);\\n for (uint256 i; i < set.values.length; i++) {\\n output[i] = set.values[i];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n \\n * @param start start index of chunk\\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\\n */\\n function enumerateChunk(\\n AddressSet storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (address[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = (set.values.length < end || count == 0) ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new address[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns the number of elements on the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /** @dev Returns the element stored at position `index` in the set. O(1).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xea6fba941ec8502aa11a7ab37e74b917d0dc47bb254e359a2870a87ef97d9872\"},\"contracts/mixins/EnumerableBytes32Set.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title Library for managing loan sets.\\n *\\n * @notice Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\\n * */\\nlibrary EnumerableBytes32Set {\\n struct Bytes32Set {\\n /// Position of the value in the `values` array, plus 1 because index 0\\n /// means a value is not in the set.\\n mapping(bytes32 => uint256) index;\\n bytes32[] values;\\n }\\n\\n /**\\n * @notice Add an address value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return addBytes32(set, value);\\n }\\n\\n /**\\n * @notice Add a value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The new value to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Remove an address value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to remove.\\n *\\n * @return False if the address was not present in the set.\\n */\\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return removeBytes32(set, value);\\n }\\n\\n /**\\n * @notice Remove a value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The value to remove.\\n *\\n * @return False if the value was not present in the set.\\n */\\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n /// If the element we're deleting is the last one,\\n /// we can just remove it without doing a swap.\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set.values[lastIndex];\\n\\n /// Move the last value to the index where the deleted value is.\\n set.values[toDeleteIndex] = lastValue;\\n\\n /// Update the index for the moved value.\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n /// Delete the index entry for the deleted value.\\n delete set.index[value];\\n\\n /// Delete the old entry for the moved value.\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Find out whether a value exists in the set.\\n *\\n * @param set The set of values.\\n * @param value The value to find.\\n *\\n * @return True if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function containsAddress(Bytes32Set storage set, address addrvalue)\\n internal\\n view\\n returns (bool)\\n {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @notice Get all set values.\\n *\\n * @param set The set of values.\\n * @param start The offset of the returning set.\\n * @param count The limit of number of values to return.\\n *\\n * @return An array with all values in the set. O(N).\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(\\n Bytes32Set storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (bytes32[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = set.values.length < end ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new bytes32[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @notice Get the legth of the set.\\n *\\n * @param set The set of values.\\n *\\n * @return the number of elements on the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /**\\n * @notice Get an item from the set by its index.\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n *\\n * @param set The set of values.\\n * @param index The index of the value to return.\\n *\\n * @return the element stored at position `index` in the set. O(1).\\n */\\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xa2801a585c566e07f21c1ebccd0cd0447dd5fd9fe6c1ff2b58d4d979d88a6db0\"},\"contracts/openzeppelin/Address.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n codehash := extcodehash(account)\\n }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x23df48a01dbac9b25e86c9131174fb7752bbc7e741e63f1aa982de22e055ad54\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/openzeppelin/ReentrancyGuard.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @title Helps contracts guard against reentrancy attacks.\\n * @author Remco Bloemen , Eenae \\n * @dev If you mark a function `nonReentrant`, you should also\\n * mark it `external`.\\n */\\ncontract ReentrancyGuard {\\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\\n\\n /// @dev Constant for locked guard state\\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\\n\\n /**\\n * @dev We use a single lock for the whole contract.\\n */\\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * If you mark a function `nonReentrant`, you should also\\n * mark it `external`. Calling one `nonReentrant` function from\\n * another is not supported. Instead, you can implement a\\n * `private` function doing the actual work, and an `external`\\n * wrapper marked as `nonReentrant`.\\n */\\n modifier nonReentrant() {\\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \\\"nonReentrant\\\");\\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\\n _;\\n reentrancyLock = REENTRANCY_GUARD_FREE;\\n }\\n}\\n\",\"keccak256\":\"0xd347de96ad57d1e45b07a2efe3050c1bd4b809236bbf354acb593de56d21a5c9\"},\"contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./Address.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\\n );\\n }\\n\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance =\\n token.allowance(address(this), spender).sub(\\n value,\\n \\\"SafeERC20: decreased allowance below zero\\\"\\n );\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) {\\n // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe99b4d979cb976a6b70e297600242afe38b8cd8f1b1ba6ee373f39f7abb3ca79\"},\"contracts/openzeppelin/SafeMath.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\\n return divCeil(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n\\n if (a == 0) {\\n return 0;\\n }\\n uint256 c = ((a - 1) / b) + 1;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n\\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n return _a < _b ? _a : _b;\\n }\\n}\\n\",\"keccak256\":\"0xbff8d6273e1a6870d1a142c0c23acd63a4dd47760f250390f49ee56333bcb6e8\"},\"contracts/reentrancy/Mutex.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/*\\n * @title Global Mutex contract\\n *\\n * @notice A mutex contract that allows only one function to be called at a time out\\n * of a large set of functions. *Anyone* in the network can freely use any instance\\n * of this contract to add a universal mutex to any function in any contract.\\n */\\ncontract Mutex {\\n /*\\n * We use an uint to store the mutex state.\\n */\\n uint256 public value;\\n\\n /*\\n * @notice Increment the mutex state and return the new value.\\n *\\n * @dev This is the function that will be called by anyone to change the mutex\\n * state. It is purposely not protected by any access control\\n */\\n function incrementAndGetValue() external returns (uint256) {\\n /*\\n * increment value using unsafe math. This is safe because we are\\n * pretty certain no one will ever increment the value 2^256 times\\n * in a single transaction.\\n */\\n return ++value;\\n }\\n}\\n\",\"keccak256\":\"0xd10b0fd07d5fed1ae1237e7c87e6501970fce2a86e2b8862e502258b0d3aeb2c\"},\"contracts/reentrancy/SharedReentrancyGuard.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./Mutex.sol\\\";\\n\\n/*\\n * @title Abstract contract for shared reentrancy guards\\n *\\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\\n * that there's no reentrancy between *any* functions marked with the modifier.\\n *\\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\\n */\\ncontract SharedReentrancyGuard {\\n /*\\n * This is the address of the mutex contract that will be used as the\\n * reentrancy guard.\\n *\\n * The address is hardcoded to avoid changing the memory layout of\\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\\n * because the Mutex contract is always deployed to the same address, with the\\n * same method used in the deployment of ERC1820Registry.\\n */\\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\\n\\n /*\\n * This is the modifier that will be used to protect functions from\\n * reentrancy. It will call the mutex contract to increment the mutex\\n * state and then revert if the mutex state was changed by another\\n * nested call.\\n */\\n modifier globallyNonReentrant() {\\n uint256 previous = MUTEX.incrementAndGetValue();\\n\\n _;\\n\\n /*\\n * If the mutex state was changed by a nested function call, then\\n * the value of the state variable will be different from the previous value.\\n */\\n require(previous == MUTEX.value(), \\\"reentrancy violation\\\");\\n }\\n}\\n\",\"keccak256\":\"0x2d0e61b104b91c1764f20fbeb381ba0f8a8889934ba7f6e8a167ed542ec2c124\"},\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":{\"content\":\"pragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"./interfaces/ISovrynSwapNetwork.sol\\\";\\nimport \\\"./interfaces/IContractRegistry.sol\\\";\\nimport \\\"../../interfaces/ISovryn.sol\\\";\\n\\n/**\\n * @title Swaps Implementation Sovryn contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the implementation of swap process and rate\\n * calculations for Sovryn network.\\n * */\\nlibrary SwapsImplSovrynSwapLib {\\n using SafeMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n struct SwapParams {\\n address sourceTokenAddress;\\n address destTokenAddress;\\n address receiverAddress;\\n address returnToSenderAddress;\\n uint256 minSourceTokenAmount;\\n uint256 maxSourceTokenAmount;\\n uint256 requiredDestTokenAmount;\\n }\\n\\n /// bytes32 contractName = hex\\\"42616e636f724e6574776f726b\\\"; /// \\\"SovrynSwapNetwork\\\"\\n\\n /**\\n * Get the hex name of a contract.\\n * @param source The name of the contract.\\n * */\\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\\n assembly {\\n result := mload(add(source, 32))\\n }\\n }\\n\\n /**\\n * Look up the Sovryn swap network contract registered at the given address.\\n * @param sovrynSwapRegistryAddress The address of the registry.\\n * */\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (ISovrynSwapNetwork)\\n {\\n /// State variable sovrynSwapContractRegistryAddress is part of\\n /// State.sol and set in ProtocolSettings.sol and this function\\n /// needs to work without delegate call as well -> therefore pass it.\\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\\n return\\n ISovrynSwapNetwork(\\n contractRegistry.addressOf(getContractHexName(\\\"SovrynSwapNetwork\\\"))\\n );\\n }\\n\\n /**\\n * Swap the source token for the destination token on the oracle based AMM.\\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\\n * -> swap the minSourceTokenAmount\\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\\n * -> same as on rollover. minimum amount is not considered at all.\\n *\\n * @param params SwapParams struct\\n * sourceTokenAddress The address of the source tokens.\\n * destTokenAddress The address of the destination tokens.\\n * receiverAddress The address who will received the swap token results\\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\\n * requiredDestTokenAmount The required amount of destination tokens.\\n * */\\n function swap(SwapParams memory params)\\n public\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n require(params.sourceTokenAddress != params.destTokenAddress, \\\"source == dest\\\");\\n\\n ISovryn iSovryn = ISovryn(address(this));\\n require(\\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\\n iSovryn.supportedTokens(params.destTokenAddress),\\n \\\"invalid tokens\\\"\\n );\\n\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\\n\\n IERC20[] memory path =\\n _getConversionPath(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n sovrynSwapNetwork\\n );\\n\\n uint256 minReturn = 1;\\n sourceTokenAmountUsed = params.minSourceTokenAmount;\\n\\n /// If the required amount of destination tokens is passed, we need to\\n /// calculate the estimated amount of source tokens regardless of the\\n /// minimum source token amount (name is misleading).\\n if (params.requiredDestTokenAmount > 0) {\\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n params.requiredDestTokenAmount,\\n params.maxSourceTokenAmount\\n );\\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\\n require(\\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\\n params.requiredDestTokenAmount,\\n \\\"insufficient source tokens provided.\\\"\\n );\\n minReturn = params.requiredDestTokenAmount;\\n }\\n\\n require(sourceTokenAmountUsed > 0, \\\"cannot swap 0 tokens\\\");\\n\\n _allowTransfer(\\n sourceTokenAmountUsed,\\n params.sourceTokenAddress,\\n address(sovrynSwapNetwork)\\n );\\n\\n /// @dev Note: the kyber connector uses .call() to interact with kyber\\n /// to avoid bubbling up. here we allow bubbling up.\\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\\n path,\\n sourceTokenAmountUsed,\\n minReturn,\\n params.receiverAddress,\\n address(0),\\n 0\\n );\\n\\n /// If the sender is not the protocol (calling with delegatecall),\\n /// return the remainder to the specified address.\\n /// @dev Note: for the case that the swap is used without the\\n /// protocol. Not sure if it should, though. needs to be discussed.\\n if (params.returnToSenderAddress != address(this)) {\\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\\n /// Send unused source token back.\\n IERC20(params.sourceTokenAddress).safeTransfer(\\n params.returnToSenderAddress,\\n params.maxSourceTokenAmount - sourceTokenAmountUsed\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Check whether the existing allowance suffices to transfer\\n * the needed amount of tokens.\\n * If not, allows the transfer of an arbitrary amount of tokens.\\n *\\n * @param tokenAmount The amount to transfer.\\n * @param tokenAddress The address of the token to transfer.\\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\\n * */\\n function _allowTransfer(\\n uint256 tokenAmount,\\n address tokenAddress,\\n address sovrynSwapNetwork\\n ) internal {\\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\\n if (tempAllowance < tokenAmount) {\\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\\n }\\n }\\n\\n /**\\n * @notice Calculate the number of source tokens to provide in order to\\n * obtain the required destination amount.\\n *\\n * @param sourceTokenAddress The address of the source token address.\\n * @param destTokenAddress The address of the destination token address.\\n * @param requiredDestTokenAmount The number of destination tokens needed.\\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\\n *\\n * @return The estimated amount of source tokens needed.\\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\\n * */\\n function _estimateSourceTokenAmount(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 requiredDestTokenAmount,\\n uint256 maxSourceTokenAmount\\n ) internal view returns (uint256 estimatedSourceAmount) {\\n ISovryn iSovryn = ISovryn(address(this));\\n uint256 sourceToDestPrecision =\\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\\n\\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\\n uint256 expectedRate =\\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\\n\\n /// Compute the source tokens needed to get the required amount with the worst case rate.\\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\\n expectedRate\\n );\\n\\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\\n uint256 buffer = estimatedSourceAmount.div(1000);\\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\\n\\n /// Never spend more than the maximum.\\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\\n return maxSourceTokenAmount;\\n }\\n\\n /**\\n * @notice Get the expected rate for 1 source token when exchanging the\\n * given amount of source tokens.\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\\n * */\\n function getExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n\\n /// Return the rate for 1 token with 18 decimals.\\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\\n }\\n\\n /**\\n * @notice Get the expected return amount when exchanging the given\\n * amount of source tokens.\\n *\\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the return for.\\n * */\\n function getExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256 expectedReturn) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n }\\n\\n function _getConversionPath(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n ISovrynSwapNetwork sovrynSwapNetwork\\n ) private view returns (IERC20[] memory path) {\\n IERC20[] memory _defaultPathConversion =\\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\\n\\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\\n path = _defaultPathConversion.length >= 3\\n ? _defaultPathConversion\\n : sovrynSwapNetwork.conversionPath(\\n IERC20(sourceTokenAddress),\\n IERC20(destTokenAddress)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x058b8d733422a2421f17d1b159aed69f151ea8d5f48ee507bac5b4e86add8b0c\"},\"contracts/swaps/connectors/interfaces/IContractRegistry.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\ncontract IContractRegistry {\\n function addressOf(bytes32 contractName) public view returns (address);\\n}\\n\",\"keccak256\":\"0x793c4eefa2ee04cbf0a1a9da28676ac310ed7bf60a27ec7d86de7d7236ccf45b\"},\"contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol\":{\"content\":\"pragma solidity >=0.5.8 <=0.5.17;\\n\\nimport \\\"../../../interfaces/IERC20.sol\\\";\\n\\ncontract ISovrynSwapNetwork {\\n function convertByPath(\\n IERC20[] calldata _path,\\n uint256 _amount,\\n uint256 _minReturn,\\n address _beneficiary,\\n address _affiliateAccount,\\n uint256 _affiliateFee\\n ) external payable returns (uint256);\\n\\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\\n\\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\\n external\\n view\\n returns (IERC20[] memory);\\n}\\n\",\"keccak256\":\"0xcd28e146b77183bff18f78b511912f7ebe60d437430fdaa72ed145fdda61a5ad\"}},\"version\":1}", - "bytecode": "0x61187c610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100615760003560e01c806335aaa79d146100665780636dcd64e51461009d578063809a9e55146100bd578063b1fb7f56146100d0578063ca83d575146100e3575b600080fd5b81801561007257600080fd5b50610086610081366004611199565b610103565b6040516100949291906116ef565b60405180910390f35b6100b06100ab3660046110c4565b6104dd565b6040516100949190611607565b6100b06100cb3660046110c4565b6105b6565b6100b06100de366004611164565b6106bd565b6100f66100f1366004611088565b6106c4565b6040516100949190611630565b60008082602001516001600160a01b031683600001516001600160a01b031614156101495760405162461bcd60e51b81526004016101409061169f565b60405180910390fd5b8251604051633462561360e11b8152309182916368c4ac269161016e91600401611544565b60206040518083038186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101be9190810190611146565b801561024557506020840151604051633462561360e11b81526001600160a01b038316916368c4ac26916101f59190600401611544565b60206040518083038186803b15801561020d57600080fd5b505afa158015610221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102459190810190611146565b6102615760405162461bcd60e51b81526004016101409061167f565b60006102d7826001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b505afa1580156102b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506100f191908101906110a6565b905060606102ee8660000151876020015184610777565b608087015160c0880151909550909150600190156103cc57610322876000015188602001518960c001518a60a00151610893565b94508660c00151836001600160a01b0316637f9c0ecd84886040518363ffffffff1660e01b8152600401610357929190611588565b60206040518083038186803b15801561036f57600080fd5b505afa158015610383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103a791908101906111b7565b10156103c55760405162461bcd60e51b8152600401610140906116af565b5060c08601515b600085116103ec5760405162461bcd60e51b81526004016101409061164f565b6103fb85886000015185610afd565b604080880151905163b77d239b60e01b81526001600160a01b0385169163b77d239b916104359186918a91879160009081906004016115a8565b602060405180830381600087803b15801561044f57600080fd5b505af1158015610463573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061048791908101906111b7565b60608801519096506001600160a01b031630146104d4578660a001518510156104d457606087015160a088015188516104d4926001600160a01b039091169188900363ffffffff610baa16565b50505050915091565b60008061051c306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b9050606061052b868684610777565b604051637f9c0ecd60e01b81529091506001600160a01b03831690637f9c0ecd9061055c9084908890600401611588565b60206040518083038186803b15801561057457600080fd5b505afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105ac91908101906111b7565b9695505050505050565b6000806105f5306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b90506060610604868684610777565b90506000826001600160a01b0316637f9c0ecd83876040518363ffffffff1660e01b8152600401610636929190611588565b60206040518083038186803b15801561064e57600080fd5b505afa158015610662573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061068691908101906111b7565b90506106b0856106a483670de0b6b3a764000063ffffffff610c0816565b9063ffffffff610c4b16565b93505050505b9392505050565b6020015190565b600080829050806001600160a01b031663bb34534c61070b60405180604001604052806011815260200170536f7672796e537761704e6574776f726b60781b8152506106bd565b6040518263ffffffff1660e01b81526004016107279190611607565b60206040518083038186803b15801561073f57600080fd5b505afa158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106b691908101906110a6565b604051638654042960e01b8152606090819030906386540429906107a19088908890600401611552565b60006040518083038186803b1580156107b957600080fd5b505afa1580156107cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107f59190810190611111565b90506003815110156108885760405163d734fa1960e01b81526001600160a01b0384169063d734fa199061082f9088908890600401611615565b60006040518083038186803b15801561084757600080fd5b505afa15801561085b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108839190810190611111565b61088a565b805b95945050505050565b6000803090506000816001600160a01b03166378d849ed6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108d457600080fd5b505afa1580156108e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061090c91908101906110a6565b6001600160a01b031663524efd4b88886040518363ffffffff1660e01b8152600401610939929190611552565b60206040518083038186803b15801561095157600080fd5b505afa158015610965573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098991908101906111b7565b90508061099a578392505050610af5565b60006109a78888876105b6565b90506109bd816106a4888563ffffffff610c0816565b935060006109d3856103e863ffffffff610c4b16565b9050836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0e57600080fd5b505afa158015610a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a4691908101906111b7565b811115610ac157836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8657600080fd5b505afa158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610abe91908101906111b7565b90505b610ad1858263ffffffff610c8d16565b9450841580610adf57508585115b15610af05785945050505050610af5565b505050505b949350505050565b604051636eb1769f60e11b81526000906001600160a01b0384169063dd62ed3e90610b2e9030908690600401611552565b60206040518083038186803b158015610b4657600080fd5b505afa158015610b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b7e91908101906111b7565b905083811015610ba457610ba46001600160a01b0384168360001963ffffffff610cb216565b50505050565b604051610c0390849063a9059cbb60e01b90610bcc908690869060240161156d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610d78565b505050565b600082610c1757506000610c45565b82820282848281610c2457fe5b0414610c425760405162461bcd60e51b81526004016101409061168f565b90505b92915050565b6000610c4283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250610e5d565b600082820183811015610c425760405162461bcd60e51b81526004016101409061165f565b801580610d3a5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90610ce89030908690600401611552565b60206040518083038186803b158015610d0057600080fd5b505afa158015610d14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d3891908101906111b7565b155b610d565760405162461bcd60e51b8152600401610140906116cf565b604051610c0390849063095ea7b360e01b90610bcc908690869060240161156d565b610d8a826001600160a01b0316610e94565b610da65760405162461bcd60e51b8152600401610140906116df565b60006060836001600160a01b031683604051610dc29190611538565b6000604051808303816000865af19150503d8060008114610dff576040519150601f19603f3d011682016040523d82523d6000602084013e610e04565b606091505b509150915081610e265760405162461bcd60e51b81526004016101409061166f565b805115610ba45780806020019051610e419190810190611146565b610ba45760405162461bcd60e51b8152600401610140906116bf565b60008183610e7e5760405162461bcd60e51b8152600401610140919061163e565b506000838581610e8a57fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610af5575050151592915050565b8035610c4581611807565b8051610c4581611807565b600082601f830112610ef457600080fd5b8151610f07610f0282611724565b6116fd565b91508181835260208401935060208101905083856020840282011115610f2c57600080fd5b60005b83811015610f585781610f428882610f6d565b8452506020928301929190910190600101610f2f565b5050505092915050565b8051610c458161181e565b8051610c4581611827565b600082601f830112610f8957600080fd5b8135610f97610f0282611745565b91508082526020830160208301858383011115610fb357600080fd5b610fbe8382846117c5565b50505092915050565b600060e08284031215610fd957600080fd5b610fe360e06116fd565b90506000610ff18484610ecd565b825250602061100284848301610ecd565b602083015250604061101684828501610ecd565b604083015250606061102a84828501610ecd565b606083015250608061103e84828501611072565b60808301525060a061105284828501611072565b60a08301525060c061106684828501611072565b60c08301525092915050565b8035610c4581611830565b8051610c4581611830565b60006020828403121561109a57600080fd5b6000610af58484610ecd565b6000602082840312156110b857600080fd5b6000610af58484610ed8565b6000806000606084860312156110d957600080fd5b60006110e58686610ecd565b93505060206110f686828701610ecd565b925050604061110786828701611072565b9150509250925092565b60006020828403121561112357600080fd5b815167ffffffffffffffff81111561113a57600080fd5b610af584828501610ee3565b60006020828403121561115857600080fd5b6000610af58484610f62565b60006020828403121561117657600080fd5b813567ffffffffffffffff81111561118d57600080fd5b610af584828501610f78565b600060e082840312156111ab57600080fd5b6000610af58484610fc7565b6000602082840312156111c957600080fd5b6000610af5848461107d565b60006111e18383611292565b505060200190565b6111f2816117af565b82525050565b6111f281611785565b600061120c82611773565b6112168185611777565b93506112218361176d565b8060005b8381101561124f57815161123988826111d5565b97506112448361176d565b925050600101611225565b509495945050505050565b6111f281611795565b600061126e82611773565b6112788185611780565b93506112888185602086016117d1565b9290920192915050565b6111f281611798565b6111f2816117ba565b60006112af82611773565b6112b98185611777565b93506112c98185602086016117d1565b6112d2816117fd565b9093019392505050565b60006112e9601483611777565b7363616e6e6f742073776170203020746f6b656e7360601b815260200192915050565b6000611319601b83611777565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000611352602083611777565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061138b600e83611777565b6d696e76616c696420746f6b656e7360901b815260200192915050565b60006113b5602183611777565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006113f8600e83611777565b6d1cdbdd5c98d9480f4f4819195cdd60921b815260200192915050565b6000611422602483611777565b7f696e73756666696369656e7420736f7572636520746f6b656e732070726f76698152633232b21760e11b602082015260400192915050565b6000611468602a83611777565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006114b4603683611777565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b602082015260400192915050565b600061150c601f83611777565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b60006106b68284611263565b60208101610c4582846111f8565b6040810161156082856111f8565b6106b660208301846111f8565b6040810161157b82856111f8565b6106b6602083018461125a565b604080825281016115998185611201565b90506106b6602083018461125a565b60c080825281016115b98189611201565b90506115c8602083018861125a565b6115d5604083018761125a565b6115e260608301866111f8565b6115ef60808301856111e9565b6115fc60a083018461129b565b979650505050505050565b60208101610c45828461125a565b604081016116238285611292565b6106b66020830184611292565b60208101610c458284611292565b60208082528101610c4281846112a4565b60208082528101610c45816112dc565b60208082528101610c458161130c565b60208082528101610c4581611345565b60208082528101610c458161137e565b60208082528101610c45816113a8565b60208082528101610c45816113eb565b60208082528101610c4581611415565b60208082528101610c458161145b565b60208082528101610c45816114a7565b60208082528101610c45816114ff565b6040810161157b828561125a565b60405181810167ffffffffffffffff8111828210171561171c57600080fd5b604052919050565b600067ffffffffffffffff82111561173b57600080fd5b5060209081020190565b600067ffffffffffffffff82111561175c57600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b919050565b6000610c45826117a3565b151590565b90565b6000610c4582611785565b6001600160a01b031690565b6000610c4582611798565b6000610c4582611795565b82818337506000910152565b60005b838110156117ec5781810151838201526020016117d4565b83811115610ba45750506000910152565b601f01601f191690565b61181081611785565b811461181b57600080fd5b50565b61181081611790565b61181081611798565b6118108161179556fea365627a7a72315820442923cda7d549003cabd4f660a3fb25f1212665bf81032f0ee5dde5e6d2ded46c6578706572696d656e74616cf564736f6c63430005110040", - "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100615760003560e01c806335aaa79d146100665780636dcd64e51461009d578063809a9e55146100bd578063b1fb7f56146100d0578063ca83d575146100e3575b600080fd5b81801561007257600080fd5b50610086610081366004611199565b610103565b6040516100949291906116ef565b60405180910390f35b6100b06100ab3660046110c4565b6104dd565b6040516100949190611607565b6100b06100cb3660046110c4565b6105b6565b6100b06100de366004611164565b6106bd565b6100f66100f1366004611088565b6106c4565b6040516100949190611630565b60008082602001516001600160a01b031683600001516001600160a01b031614156101495760405162461bcd60e51b81526004016101409061169f565b60405180910390fd5b8251604051633462561360e11b8152309182916368c4ac269161016e91600401611544565b60206040518083038186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101be9190810190611146565b801561024557506020840151604051633462561360e11b81526001600160a01b038316916368c4ac26916101f59190600401611544565b60206040518083038186803b15801561020d57600080fd5b505afa158015610221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102459190810190611146565b6102615760405162461bcd60e51b81526004016101409061167f565b60006102d7826001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b505afa1580156102b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506100f191908101906110a6565b905060606102ee8660000151876020015184610777565b608087015160c0880151909550909150600190156103cc57610322876000015188602001518960c001518a60a00151610893565b94508660c00151836001600160a01b0316637f9c0ecd84886040518363ffffffff1660e01b8152600401610357929190611588565b60206040518083038186803b15801561036f57600080fd5b505afa158015610383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103a791908101906111b7565b10156103c55760405162461bcd60e51b8152600401610140906116af565b5060c08601515b600085116103ec5760405162461bcd60e51b81526004016101409061164f565b6103fb85886000015185610afd565b604080880151905163b77d239b60e01b81526001600160a01b0385169163b77d239b916104359186918a91879160009081906004016115a8565b602060405180830381600087803b15801561044f57600080fd5b505af1158015610463573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061048791908101906111b7565b60608801519096506001600160a01b031630146104d4578660a001518510156104d457606087015160a088015188516104d4926001600160a01b039091169188900363ffffffff610baa16565b50505050915091565b60008061051c306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b9050606061052b868684610777565b604051637f9c0ecd60e01b81529091506001600160a01b03831690637f9c0ecd9061055c9084908890600401611588565b60206040518083038186803b15801561057457600080fd5b505afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105ac91908101906111b7565b9695505050505050565b6000806105f5306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b90506060610604868684610777565b90506000826001600160a01b0316637f9c0ecd83876040518363ffffffff1660e01b8152600401610636929190611588565b60206040518083038186803b15801561064e57600080fd5b505afa158015610662573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061068691908101906111b7565b90506106b0856106a483670de0b6b3a764000063ffffffff610c0816565b9063ffffffff610c4b16565b93505050505b9392505050565b6020015190565b600080829050806001600160a01b031663bb34534c61070b60405180604001604052806011815260200170536f7672796e537761704e6574776f726b60781b8152506106bd565b6040518263ffffffff1660e01b81526004016107279190611607565b60206040518083038186803b15801561073f57600080fd5b505afa158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106b691908101906110a6565b604051638654042960e01b8152606090819030906386540429906107a19088908890600401611552565b60006040518083038186803b1580156107b957600080fd5b505afa1580156107cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107f59190810190611111565b90506003815110156108885760405163d734fa1960e01b81526001600160a01b0384169063d734fa199061082f9088908890600401611615565b60006040518083038186803b15801561084757600080fd5b505afa15801561085b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108839190810190611111565b61088a565b805b95945050505050565b6000803090506000816001600160a01b03166378d849ed6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108d457600080fd5b505afa1580156108e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061090c91908101906110a6565b6001600160a01b031663524efd4b88886040518363ffffffff1660e01b8152600401610939929190611552565b60206040518083038186803b15801561095157600080fd5b505afa158015610965573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098991908101906111b7565b90508061099a578392505050610af5565b60006109a78888876105b6565b90506109bd816106a4888563ffffffff610c0816565b935060006109d3856103e863ffffffff610c4b16565b9050836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0e57600080fd5b505afa158015610a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a4691908101906111b7565b811115610ac157836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8657600080fd5b505afa158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610abe91908101906111b7565b90505b610ad1858263ffffffff610c8d16565b9450841580610adf57508585115b15610af05785945050505050610af5565b505050505b949350505050565b604051636eb1769f60e11b81526000906001600160a01b0384169063dd62ed3e90610b2e9030908690600401611552565b60206040518083038186803b158015610b4657600080fd5b505afa158015610b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b7e91908101906111b7565b905083811015610ba457610ba46001600160a01b0384168360001963ffffffff610cb216565b50505050565b604051610c0390849063a9059cbb60e01b90610bcc908690869060240161156d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610d78565b505050565b600082610c1757506000610c45565b82820282848281610c2457fe5b0414610c425760405162461bcd60e51b81526004016101409061168f565b90505b92915050565b6000610c4283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250610e5d565b600082820183811015610c425760405162461bcd60e51b81526004016101409061165f565b801580610d3a5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90610ce89030908690600401611552565b60206040518083038186803b158015610d0057600080fd5b505afa158015610d14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d3891908101906111b7565b155b610d565760405162461bcd60e51b8152600401610140906116cf565b604051610c0390849063095ea7b360e01b90610bcc908690869060240161156d565b610d8a826001600160a01b0316610e94565b610da65760405162461bcd60e51b8152600401610140906116df565b60006060836001600160a01b031683604051610dc29190611538565b6000604051808303816000865af19150503d8060008114610dff576040519150601f19603f3d011682016040523d82523d6000602084013e610e04565b606091505b509150915081610e265760405162461bcd60e51b81526004016101409061166f565b805115610ba45780806020019051610e419190810190611146565b610ba45760405162461bcd60e51b8152600401610140906116bf565b60008183610e7e5760405162461bcd60e51b8152600401610140919061163e565b506000838581610e8a57fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610af5575050151592915050565b8035610c4581611807565b8051610c4581611807565b600082601f830112610ef457600080fd5b8151610f07610f0282611724565b6116fd565b91508181835260208401935060208101905083856020840282011115610f2c57600080fd5b60005b83811015610f585781610f428882610f6d565b8452506020928301929190910190600101610f2f565b5050505092915050565b8051610c458161181e565b8051610c4581611827565b600082601f830112610f8957600080fd5b8135610f97610f0282611745565b91508082526020830160208301858383011115610fb357600080fd5b610fbe8382846117c5565b50505092915050565b600060e08284031215610fd957600080fd5b610fe360e06116fd565b90506000610ff18484610ecd565b825250602061100284848301610ecd565b602083015250604061101684828501610ecd565b604083015250606061102a84828501610ecd565b606083015250608061103e84828501611072565b60808301525060a061105284828501611072565b60a08301525060c061106684828501611072565b60c08301525092915050565b8035610c4581611830565b8051610c4581611830565b60006020828403121561109a57600080fd5b6000610af58484610ecd565b6000602082840312156110b857600080fd5b6000610af58484610ed8565b6000806000606084860312156110d957600080fd5b60006110e58686610ecd565b93505060206110f686828701610ecd565b925050604061110786828701611072565b9150509250925092565b60006020828403121561112357600080fd5b815167ffffffffffffffff81111561113a57600080fd5b610af584828501610ee3565b60006020828403121561115857600080fd5b6000610af58484610f62565b60006020828403121561117657600080fd5b813567ffffffffffffffff81111561118d57600080fd5b610af584828501610f78565b600060e082840312156111ab57600080fd5b6000610af58484610fc7565b6000602082840312156111c957600080fd5b6000610af5848461107d565b60006111e18383611292565b505060200190565b6111f2816117af565b82525050565b6111f281611785565b600061120c82611773565b6112168185611777565b93506112218361176d565b8060005b8381101561124f57815161123988826111d5565b97506112448361176d565b925050600101611225565b509495945050505050565b6111f281611795565b600061126e82611773565b6112788185611780565b93506112888185602086016117d1565b9290920192915050565b6111f281611798565b6111f2816117ba565b60006112af82611773565b6112b98185611777565b93506112c98185602086016117d1565b6112d2816117fd565b9093019392505050565b60006112e9601483611777565b7363616e6e6f742073776170203020746f6b656e7360601b815260200192915050565b6000611319601b83611777565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000611352602083611777565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061138b600e83611777565b6d696e76616c696420746f6b656e7360901b815260200192915050565b60006113b5602183611777565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006113f8600e83611777565b6d1cdbdd5c98d9480f4f4819195cdd60921b815260200192915050565b6000611422602483611777565b7f696e73756666696369656e7420736f7572636520746f6b656e732070726f76698152633232b21760e11b602082015260400192915050565b6000611468602a83611777565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006114b4603683611777565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b602082015260400192915050565b600061150c601f83611777565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b60006106b68284611263565b60208101610c4582846111f8565b6040810161156082856111f8565b6106b660208301846111f8565b6040810161157b82856111f8565b6106b6602083018461125a565b604080825281016115998185611201565b90506106b6602083018461125a565b60c080825281016115b98189611201565b90506115c8602083018861125a565b6115d5604083018761125a565b6115e260608301866111f8565b6115ef60808301856111e9565b6115fc60a083018461129b565b979650505050505050565b60208101610c45828461125a565b604081016116238285611292565b6106b66020830184611292565b60208101610c458284611292565b60208082528101610c4281846112a4565b60208082528101610c45816112dc565b60208082528101610c458161130c565b60208082528101610c4581611345565b60208082528101610c458161137e565b60208082528101610c45816113a8565b60208082528101610c45816113eb565b60208082528101610c4581611415565b60208082528101610c458161145b565b60208082528101610c45816114a7565b60208082528101610c45816114ff565b6040810161157b828561125a565b60405181810167ffffffffffffffff8111828210171561171c57600080fd5b604052919050565b600067ffffffffffffffff82111561173b57600080fd5b5060209081020190565b600067ffffffffffffffff82111561175c57600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b919050565b6000610c45826117a3565b151590565b90565b6000610c4582611785565b6001600160a01b031690565b6000610c4582611798565b6000610c4582611795565b82818337506000910152565b60005b838110156117ec5781810151838201526020016117d4565b83811115610ba45750506000910152565b601f01601f191690565b61181081611785565b811461181b57600080fd5b50565b61181081611790565b61181081611798565b6118108161179556fea365627a7a72315820442923cda7d549003cabd4f660a3fb25f1212665bf81032f0ee5dde5e6d2ded46c6578706572696d656e74616cf564736f6c63430005110040", + "numDeployments": 2, + "solcInputHash": "444414c40f489390e118f5b65a5947cc", + "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[{\"internalType\":\"string\",\"name\":\"source\",\"type\":\"string\"}],\"name\":\"getContractHexName\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"result\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sourceTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceTokenAmount\",\"type\":\"uint256\"}],\"name\":\"getExpectedRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sourceTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"destTokenAddress\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"sourceTokenAmount\",\"type\":\"uint256\"}],\"name\":\"getExpectedReturn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"expectedReturn\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sovrynSwapRegistryAddress\",\"type\":\"address\"}],\"name\":\"getSovrynSwapNetworkContract\",\"outputs\":[{\"internalType\":\"contract ISovrynSwapNetwork\",\"name\":\"\",\"type\":\"ISovrynSwapNetwork\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{\"getContractHexName(string)\":{\"params\":{\"source\":\"The name of the contract.\"}},\"getExpectedRate(address,address,uint256)\":{\"params\":{\"destTokenAddress\":\"The address of the destination token contract.\",\"sourceTokenAddress\":\"The address of the source token contract.\",\"sourceTokenAmount\":\"The amount of source tokens to get the rate for.\"}},\"getExpectedReturn(address,address,uint256)\":{\"params\":{\"destTokenAddress\":\"The address of the destination token contract.\",\"sourceTokenAddress\":\"The address of the source token contract.\",\"sourceTokenAmount\":\"The amount of source tokens to get the return for.\"}},\"getSovrynSwapNetworkContract(address)\":{\"params\":{\"sovrynSwapRegistryAddress\":\"The address of the registry.\"}},\"swap(SwapsImplSovrynSwapLib.SwapParams)\":{\"params\":{\"params\":\"SwapParams struct sourceTokenAddress The address of the source tokens. destTokenAddress The address of the destination tokens. receiverAddress The address who will received the swap token results returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract). minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0). maxSourceTokenAmount The maximum amount of source tokens to swapped. requiredDestTokenAmount The required amount of destination tokens.\"}}},\"title\":\"Swaps Implementation Sovryn contract.\"},\"userdoc\":{\"methods\":{\"getContractHexName(string)\":{\"notice\":\"Get the hex name of a contract.\"},\"getExpectedRate(address,address,uint256)\":{\"notice\":\"Get the expected rate for 1 source token when exchanging the given amount of source tokens.\"},\"getExpectedReturn(address,address,uint256)\":{\"notice\":\"Get the expected return amount when exchanging the given amount of source tokens.Right now, this function is being called directly by _swapsExpectedReturn from the protocol So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call. Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\"},\"getSovrynSwapNetworkContract(address)\":{\"notice\":\"Look up the Sovryn swap network contract registered at the given address.\"},\"swap(SwapsImplSovrynSwapLib.SwapParams)\":{\"notice\":\"Swap the source token for the destination token on the oracle based AMM. On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0 -> swap the minSourceTokenAmount On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0 -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded. On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0 -> same as on rollover. minimum amount is not considered at all.\"}},\"notice\":\"This contract code comes from bZx. bZx is a protocol for tokenized margin trading and lending https://bzx.network similar to the dYdX protocol. * This contract contains the implementation of swap process and rate calculations for Sovryn network.\"}},\"settings\":{\"compilationTarget\":{\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":\"SwapsImplSovrynSwapLib\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":ds-test/=foundry/lib/forge-std/lib/ds-test/src/\",\":forge-std/=foundry/lib/forge-std/src/\"]},\"sources\":{\"contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nlibrary MarginTradeStructHelpers {\\n struct SentAddresses {\\n address lender;\\n address borrower;\\n address receiver;\\n address manager;\\n }\\n\\n struct SentAmounts {\\n uint256 interestRate;\\n uint256 newPrincipal;\\n uint256 interestInitialAmount;\\n uint256 loanTokenSent;\\n uint256 collateralTokenSent;\\n uint256 minEntryPrice;\\n uint256 loanToCollateralSwapRate;\\n uint256 interestDuration;\\n uint256 entryLeverage;\\n }\\n}\\n\",\"keccak256\":\"0xf0612e2c0d13604a67c3d55efe88810c089f0b84ca63bd3ce82c1e09b0938973\"},\"contracts/core/Objects.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./objects/LoanStruct.sol\\\";\\nimport \\\"./objects/LoanParamsStruct.sol\\\";\\nimport \\\"./objects/OrderStruct.sol\\\";\\nimport \\\"./objects/LenderInterestStruct.sol\\\";\\nimport \\\"./objects/LoanInterestStruct.sol\\\";\\n\\n/**\\n * @title Objects contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract inherints and aggregates several structures needed to handle\\n * loans on the protocol.\\n * */\\ncontract Objects is\\n LoanStruct,\\n LoanParamsStruct,\\n OrderStruct,\\n LenderInterestStruct,\\n LoanInterestStruct\\n{\\n\\n}\\n\",\"keccak256\":\"0xa30b8887af813997ebb480f0aa296245f9f3bd728382060059aa087cd9ee332c\"},\"contracts/core/State.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./Objects.sol\\\";\\nimport \\\"../mixins/EnumerableAddressSet.sol\\\";\\nimport \\\"../mixins/EnumerableBytes32Set.sol\\\";\\nimport \\\"../openzeppelin/ReentrancyGuard.sol\\\";\\nimport \\\"../openzeppelin/Ownable.sol\\\";\\nimport \\\"../openzeppelin/SafeMath.sol\\\";\\nimport \\\"../interfaces/IWrbtcERC20.sol\\\";\\nimport \\\"../reentrancy/SharedReentrancyGuard.sol\\\";\\n\\n/**\\n * @title State contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage values of the Protocol.\\n * */\\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\\n using SafeMath for uint256;\\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\\n\\n /// Handles asset reference price lookups.\\n address public priceFeeds;\\n\\n /// Handles asset swaps using dex liquidity.\\n address public swapsImpl;\\n\\n /// Contract registry address of the Sovryn swap network.\\n address public sovrynSwapContractRegistryAddress;\\n\\n /// Implementations of protocol functions.\\n mapping(bytes4 => address) public logicTargets;\\n\\n /// Loans: loanId => Loan\\n mapping(bytes32 => Loan) public loans;\\n\\n /// Loan parameters: loanParamsId => LoanParams\\n mapping(bytes32 => LoanParams) public loanParams;\\n\\n /// lender => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\\n\\n /// borrower => orderParamsId => Order\\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\\n\\n /// loanId => delegated => approved\\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\\n\\n /**\\n *** Interest ***\\n **/\\n\\n /// lender => loanToken => LenderInterest object\\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\\n\\n /// loanId => LoanInterest object\\n mapping(bytes32 => LoanInterest) public loanInterest;\\n\\n /**\\n *** Internals ***\\n **/\\n\\n /// Implementations set.\\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\\n\\n /// Active loans set.\\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\\n\\n /// Lender loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\\n\\n /// Borrow loans set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\\n\\n /// User loan params set.\\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\\n\\n /// Address controlling fee withdrawals.\\n address public feesController;\\n\\n /// 10% fee /// Fee taken from lender interest payments.\\n uint256 public lendingFeePercent = 10**19;\\n\\n /// Total interest fees received and not withdrawn per asset.\\n mapping(address => uint256) public lendingFeeTokensHeld;\\n\\n /// Total interest fees withdraw per asset.\\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\\n mapping(address => uint256) public lendingFeeTokensPaid;\\n\\n /// 0.15% fee /// Fee paid for each trade.\\n uint256 public tradingFeePercent = 15 * 10**16;\\n\\n /// Total trading fees received and not withdrawn per asset.\\n mapping(address => uint256) public tradingFeeTokensHeld;\\n\\n /// Total trading fees withdraw per asset\\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\\n mapping(address => uint256) public tradingFeeTokensPaid;\\n\\n /// 0.09% fee /// Origination fee paid for each loan.\\n uint256 public borrowingFeePercent = 9 * 10**16;\\n\\n /// Total borrowing fees received and not withdrawn per asset.\\n mapping(address => uint256) public borrowingFeeTokensHeld;\\n\\n /// Total borrowing fees withdraw per asset.\\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\\n mapping(address => uint256) public borrowingFeeTokensPaid;\\n\\n /// Current protocol token deposit balance.\\n uint256 public protocolTokenHeld;\\n\\n /// Lifetime total payout of protocol token.\\n uint256 public protocolTokenPaid;\\n\\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\\n uint256 public affiliateFeePercent = 5 * 10**18;\\n\\n /// 5% collateral discount /// Discount on collateral for liquidators.\\n uint256 public liquidationIncentivePercent = 5 * 10**18;\\n\\n /// loanPool => underlying\\n mapping(address => address) public loanPoolToUnderlying;\\n\\n /// underlying => loanPool\\n mapping(address => address) public underlyingToLoanPool;\\n\\n /// Loan pools set.\\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\\n\\n /// Supported tokens for swaps.\\n mapping(address => bool) public supportedTokens;\\n\\n /// % disagreement between swap rate and reference rate.\\n uint256 public maxDisagreement = 5 * 10**18;\\n\\n /// Used as buffer for swap source amount estimations.\\n uint256 public sourceBuffer = 10000;\\n\\n /// Maximum support swap size in rBTC\\n uint256 public maxSwapSize = 50 ether;\\n\\n /// Nonce per borrower. Used for loan id creation.\\n mapping(address => uint256) public borrowerNonce;\\n\\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\\n uint256 public rolloverBaseReward = 16800000000000;\\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\\n\\n IWrbtcERC20 public wrbtcToken;\\n address public protocolTokenAddress;\\n\\n /// 50% fee rebate\\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\\n uint256 public feeRebatePercent = 50 * 10**18;\\n\\n address public admin;\\n\\n /// For modules interaction.\\n address public protocolAddress;\\n\\n /**\\n *** Affiliates ***\\n **/\\n\\n /// The flag is set on the user's first trade.\\n mapping(address => bool) public userNotFirstTradeFlag;\\n\\n /// User => referrer (affiliate).\\n mapping(address => address) public affiliatesUserReferrer;\\n\\n /// List of referral addresses affiliated to the referrer.\\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\\n\\n /// @dev Referral threshold for paying out to the referrer.\\n /// The referrer reward is being accumulated and locked until the threshold is passed.\\n uint256 public minReferralsToPayout = 3;\\n\\n /// @dev Total affiliate SOV rewards that held in the protocol\\n /// (Because the minimum referrals is less than the rule)\\n mapping(address => uint256) public affiliateRewardsHeld;\\n\\n /// @dev For affiliates SOV Bonus proccess.\\n address public sovTokenAddress;\\n address public lockedSOVAddress;\\n\\n /// @dev 20% fee share of trading token fee.\\n /// Fee share of trading token fee for affiliate program.\\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\\n\\n /// @dev Addresses of tokens in which commissions were paid to referrers.\\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\\n\\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\\n\\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\\n bool public pause; //Flag to pause all protocol modules\\n\\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\\n\\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\\n uint256 internal tradingRebateRewardsBasisPoint;\\n\\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\\n /// Will be used in internal swap.\\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\\n\\n address internal pauser;\\n\\n /**\\n * @notice Add signature and target to storage.\\n * @dev Protocol is a proxy and requires a way to add every\\n * module function dynamically during deployment.\\n * */\\n function _setTarget(bytes4 sig, address target) internal {\\n logicTargets[sig] = target;\\n\\n if (target != address(0)) {\\n logicTargetsSet.addBytes32(bytes32(sig));\\n } else {\\n logicTargetsSet.removeBytes32(bytes32(sig));\\n }\\n }\\n\\n modifier onlyAdminOrOwner() {\\n require(isOwner() || admin == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n\\n modifier onlyPauserOrOwner() {\\n require(isOwner() || pauser == (msg.sender), \\\"unauthorized\\\");\\n _;\\n }\\n}\\n\",\"keccak256\":\"0xf8dfc02f3dc790c73b390a69898d0281c4473487bc91fec1f28fbebceacd3b3c\"},\"contracts/core/objects/LenderInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Lender Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Lender Interest.\\n * */\\ncontract LenderInterestStruct {\\n struct LenderInterest {\\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\\n uint256 paidTotal; /// Total interest paid so far for asset.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0x6583baadddded384836cec469980e7973ec09310ae505b4a2ec67fb7bc19e452\"},\"contracts/core/objects/LoanInterestStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Interest.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Interest.\\n * */\\ncontract LoanInterestStruct {\\n struct LoanInterest {\\n uint256 owedPerDay; /// Interest owed per day for loan.\\n uint256 depositTotal; /// Total escrowed interest for loan.\\n uint256 updatedTimestamp; /// Last update.\\n }\\n}\\n\",\"keccak256\":\"0xd9034c6adb1b72e1593589dca024dc4730a1ee8bf6b2dca9d22283f2e7159590\"},\"contracts/core/objects/LoanParamsStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Parameters.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Parameters.\\n * */\\ncontract LoanParamsStruct {\\n struct LoanParams {\\n /// @dev ID of loan params object.\\n bytes32 id;\\n /// @dev If false, this object has been disabled by the owner and can't\\n /// be used for future loans.\\n bool active;\\n /// @dev Owner of this object.\\n address owner;\\n /// @dev The token being loaned.\\n address loanToken;\\n /// @dev The required collateral token.\\n address collateralToken;\\n /// @dev The minimum allowed initial margin.\\n uint256 minInitialMargin;\\n /// @dev An unhealthy loan when current margin is at or below this value.\\n uint256 maintenanceMargin;\\n /// @dev The maximum term for new loans (0 means there's no max term).\\n uint256 maxLoanTerm;\\n }\\n}\\n\",\"keccak256\":\"0xe15aa97713521da7f501e5225af9d92cf34bd68d286dbfed86aa75aabb323945\"},\"contracts/core/objects/LoanStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Object.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Object.\\n * */\\ncontract LoanStruct {\\n struct Loan {\\n bytes32 id; /// ID of the loan.\\n bytes32 loanParamsId; /// The linked loan params ID.\\n bytes32 pendingTradesId; /// The linked pending trades ID.\\n bool active; /// If false, the loan has been fully closed.\\n uint256 principal; /// Total borrowed amount outstanding.\\n uint256 collateral; /// Total collateral escrowed for the loan.\\n uint256 startTimestamp; /// Loan start time.\\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\\n uint256 startMargin; /// Initial margin when the loan opened.\\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\\n address borrower; /// Borrower of this loan.\\n address lender; /// Lender of this loan.\\n }\\n}\\n\",\"keccak256\":\"0x7d05c3096a86d5892e4e72f3a01a5a806f13a5ac90ca6339c611e75c603637b4\"},\"contracts/core/objects/OrderStruct.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Loan Order.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the storage structure of the Loan Order.\\n * */\\ncontract OrderStruct {\\n struct Order {\\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\\n uint256 interestRate; /// Interest rate defined by the creator of this order.\\n uint256 minLoanTerm; /// Minimum loan term allowed.\\n uint256 maxLoanTerm; /// Maximum loan term allowed.\\n uint256 createdTimestamp; /// Timestamp when this order was created.\\n uint256 expirationTimestamp; /// Timestamp when this order expires.\\n }\\n}\\n\",\"keccak256\":\"0xcc053c5da34a5927041162259bf856ba913f3524ca03e63ad0c5877777d17e0f\"},\"contracts/events/AffiliatesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\ncontract AffiliatesEvents is ModulesCommonEvents {\\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\\n\\n event SetAffiliatesReferrerFail(\\n address indexed user,\\n address indexed referrer,\\n bool alreadySet,\\n bool userNotFirstTrade\\n );\\n\\n event SetUserNotFirstTradeFlag(address indexed user);\\n\\n event PayTradingFeeToAffiliate(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n bool indexed isHeld,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountPaid\\n );\\n\\n event PayTradingFeeToAffiliateFail(\\n address indexed referrer,\\n address trader,\\n address indexed token,\\n uint256 tradingFeeTokenAmount,\\n uint256 tokenBonusAmount,\\n uint256 sovBonusAmount,\\n uint256 sovBonusAmountTryingToPaid\\n );\\n\\n event WithdrawAffiliatesReferrerTokenFees(\\n address indexed referrer,\\n address indexed receiver,\\n address indexed tokenAddress,\\n uint256 amount\\n );\\n}\\n\",\"keccak256\":\"0xf72cf23e90db3c49589ddc4e1796680ebfb69a9b146db89f9b61f5fcf6dd95ba\"},\"contracts/events/FeesEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title The Fees Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for fee payments.\\n * */\\ncontract FeesEvents {\\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\\n\\n event PayTradingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event PayBorrowingFee(\\n address indexed payer,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 amount\\n );\\n\\n event EarnReward(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n\\n event EarnRewardFail(\\n address indexed receiver,\\n address indexed token,\\n bytes32 indexed loanId,\\n uint256 feeRebatePercent,\\n uint256 amount,\\n uint256 basisPoint\\n );\\n}\\n\",\"keccak256\":\"0xe69bf53e15479be5fde1cbaadaf0c004ee038e8a6a37c99f7769bf5d8387015f\"},\"contracts/events/LoanClosingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Closing Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan closing operations.\\n * */\\ncontract LoanClosingsEvents is ModulesCommonEvents {\\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\\n event CloseWithDeposit(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address closer,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\\n event CloseWithSwap(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n address closer,\\n uint256 positionCloseSize,\\n uint256 loanCloseAmount,\\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\\n event Liquidate(\\n address indexed user,\\n address indexed liquidator,\\n bytes32 indexed loanId,\\n address lender,\\n address loanToken,\\n address collateralToken,\\n uint256 repayAmount,\\n uint256 collateralWithdrawAmount,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n event Rollover(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n uint256 principal,\\n uint256 collateral,\\n uint256 endTimestamp,\\n address rewardReceiver,\\n uint256 reward\\n );\\n\\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\\n}\\n\",\"keccak256\":\"0x1ea325b9a213012865a52f38941ce6c1e8c29dce919215b5bdcc63a8a5980be1\"},\"contracts/events/LoanMaintenanceEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Maintenance Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan maintenance operations.\\n * */\\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\\n}\\n\",\"keccak256\":\"0xdee5098b947c22bcef6e38ecaf62bae6941572d1c245d2065ad41ea4f494c61d\"},\"contracts/events/LoanOpeningsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Openings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan openings operations.\\n * */\\ncontract LoanOpeningsEvents is ModulesCommonEvents {\\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\\n event Borrow(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 newCollateral,\\n uint256 interestRate,\\n uint256 interestDuration,\\n uint256 collateralToLoanRate,\\n uint256 currentMargin\\n );\\n\\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\\n event Trade(\\n address indexed user,\\n address indexed lender,\\n bytes32 indexed loanId,\\n address collateralToken,\\n address loanToken,\\n uint256 positionSize,\\n uint256 borrowedAmount,\\n uint256 interestRate,\\n uint256 settlementDate,\\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\\n uint256 entryLeverage,\\n uint256 currentLeverage\\n );\\n\\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\\n event DelegatedManagerSet(\\n bytes32 indexed loanId,\\n address indexed delegator,\\n address indexed delegated,\\n bool isActive\\n );\\n}\\n\",\"keccak256\":\"0x585710ce6c570c6dbd1b8daf43b63a54b1d60ad01ee1dc3cae407d74d78f3093\"},\"contracts/events/LoanSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Loan Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for loan settings operations.\\n * */\\ncontract LoanSettingsEvents is ModulesCommonEvents {\\n event LoanParamsSetup(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\\n\\n event LoanParamsDisabled(\\n bytes32 indexed id,\\n address owner,\\n address indexed loanToken,\\n address indexed collateralToken,\\n uint256 minInitialMargin,\\n uint256 maintenanceMargin,\\n uint256 maxLoanTerm\\n );\\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\\n}\\n\",\"keccak256\":\"0xae9c49678a7bc02c2283648939c474c8bfd33781506e05c635c8334c5bf8682f\"},\"contracts/events/ModulesCommonEvents.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\n/**\\n * @title The common events for all modules\\n * @notice This contract contains the events which will be used by all modules\\n **/\\n\\ncontract ModulesCommonEvents {\\n event ProtocolModuleContractReplaced(\\n address indexed prevModuleContractAddress,\\n address indexed newModuleContractAddress,\\n bytes32 indexed module\\n );\\n}\\n\",\"keccak256\":\"0xb07af42d7e6b0fe983889b883691b662a58d2ef8d75b3f32f17faff1871c8b8f\"},\"contracts/events/ProtocolSettingsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title The Protocol Settings Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for protocol settings operations.\\n * */\\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\\n\\n event SetLoanPool(\\n address indexed sender,\\n address indexed loanPool,\\n address indexed underlying\\n );\\n\\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\\n\\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetAffiliateTradingTokenFeePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetLiquidationIncentivePercent(\\n address indexed sender,\\n uint256 oldValue,\\n uint256 newValue\\n );\\n\\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetFeesController(\\n address indexed sender,\\n address indexed oldController,\\n address indexed newController\\n );\\n\\n event SetWrbtcToken(\\n address indexed sender,\\n address indexed oldWethToken,\\n address indexed newWethToken\\n );\\n\\n event SetSovrynSwapContractRegistryAddress(\\n address indexed sender,\\n address indexed oldSovrynSwapContractRegistryAddress,\\n address indexed newSovrynSwapContractRegistryAddress\\n );\\n\\n event SetProtocolTokenAddress(\\n address indexed sender,\\n address indexed oldProtocolToken,\\n address indexed newProtocolToken\\n );\\n\\n event WithdrawFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 lendingAmount,\\n uint256 tradingAmount,\\n uint256 borrowingAmount,\\n uint256 wRBTCConverted\\n );\\n\\n event WithdrawLendingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawTradingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event WithdrawBorrowingFees(\\n address indexed sender,\\n address indexed token,\\n address indexed receiver,\\n uint256 amount\\n );\\n\\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\\n\\n event SetRebatePercent(\\n address indexed sender,\\n uint256 oldRebatePercent,\\n uint256 newRebatePercent\\n );\\n\\n event SetSpecialRebates(\\n address indexed sender,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 oldSpecialRebatesPercent,\\n uint256 newSpecialRebatesPercent\\n );\\n\\n event SetProtocolAddress(\\n address indexed sender,\\n address indexed oldProtocol,\\n address indexed newProtocol\\n );\\n\\n event SetMinReferralsToPayoutAffiliates(\\n address indexed sender,\\n uint256 oldMinReferrals,\\n uint256 newMinReferrals\\n );\\n\\n event SetSOVTokenAddress(\\n address indexed sender,\\n address indexed oldTokenAddress,\\n address indexed newTokenAddress\\n );\\n\\n event SetLockedSOVAddress(\\n address indexed sender,\\n address indexed oldAddress,\\n address indexed newAddress\\n );\\n\\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\\n\\n event SetTradingRebateRewardsBasisPoint(\\n address indexed sender,\\n uint256 oldBasisPoint,\\n uint256 newBasisPoint\\n );\\n\\n event SetRolloverFlexFeePercent(\\n address indexed sender,\\n uint256 oldRolloverFlexFeePercent,\\n uint256 newRolloverFlexFeePercent\\n );\\n\\n event SetDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event RemoveDefaultPathConversion(\\n address indexed sender,\\n address indexed sourceTokenAddress,\\n address indexed destTokenAddress,\\n IERC20[] defaultPath\\n );\\n\\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\\n\\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\\n}\\n\",\"keccak256\":\"0x20ca66a2c53669aa33379bf5233e3bcdddbba3504cd430a0143f0ee3ce1c2641\"},\"contracts/events/SwapsEvents.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\nimport \\\"./ModulesCommonEvents.sol\\\";\\n\\n/**\\n * @title The Swaps Events contract.\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the events for swap operations.\\n * */\\ncontract SwapsEvents is ModulesCommonEvents {\\n event LoanSwap(\\n bytes32 indexed loanId,\\n address indexed sourceToken,\\n address indexed destToken,\\n address borrower,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n\\n event ExternalSwap(\\n address indexed user,\\n address indexed sourceToken,\\n address indexed destToken,\\n uint256 sourceAmount,\\n uint256 destAmount\\n );\\n}\\n\",\"keccak256\":\"0x0a1cd289076675980b916941ed923146160d34a8669fc3fb4a06610f285dfbd1\"},\"contracts/feeds/IPriceFeeds.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\ninterface IPriceFeeds {\\n function queryRate(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 rate, uint256 precision);\\n\\n function queryPrecision(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 precision);\\n\\n function queryReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount\\n ) external view returns (uint256 destAmount);\\n\\n function checkPriceDisagreement(\\n address sourceToken,\\n address destToken,\\n uint256 sourceAmount,\\n uint256 destAmount,\\n uint256 maxSlippage\\n ) external view returns (uint256 sourceToDestSwapRate);\\n\\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\\n\\n function getMaxDrawdown(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (uint256);\\n\\n function getCurrentMarginAndCollateralSize(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\\n\\n function getCurrentMargin(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount\\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\\n\\n function shouldLiquidate(\\n address loanToken,\\n address collateralToken,\\n uint256 loanAmount,\\n uint256 collateralAmount,\\n uint256 maintenanceMargin\\n ) external view returns (bool);\\n\\n function getFastGasPrice(address payToken) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x2e2c2b393336efedb97659a2fc21c8dfb75b70e15d2422a3bcbf7ebd5fc83c82\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/interfaces/ISovryn.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\npragma experimental ABIEncoderV2;\\n//TODO: stored in ./interfaces only while brownie isn't removed\\n//TODO: move to contracts/interfaces after with brownie is removed\\n\\nimport \\\"../core/State.sol\\\";\\nimport \\\"../events/ProtocolSettingsEvents.sol\\\";\\nimport \\\"../events/LoanSettingsEvents.sol\\\";\\nimport \\\"../events/LoanOpeningsEvents.sol\\\";\\nimport \\\"../events/LoanMaintenanceEvents.sol\\\";\\nimport \\\"../events/LoanClosingsEvents.sol\\\";\\nimport \\\"../events/FeesEvents.sol\\\";\\nimport \\\"../events/SwapsEvents.sol\\\";\\nimport \\\"../events/AffiliatesEvents.sol\\\";\\nimport \\\"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\\\";\\n\\ncontract ISovryn is\\n State,\\n ProtocolSettingsEvents,\\n LoanSettingsEvents,\\n LoanOpeningsEvents,\\n LoanMaintenanceEvents,\\n LoanClosingsEvents,\\n SwapsEvents,\\n AffiliatesEvents,\\n FeesEvents\\n{\\n /// Triggered whenever interest is paid to lender.\\n event PayInterestTransfer(\\n address indexed interestToken,\\n address indexed lender,\\n uint256 effectiveInterest\\n );\\n\\n ////// Protocol //////\\n\\n function replaceContract(address target) external;\\n\\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\\n\\n function getTarget(string calldata sig) external view returns (address);\\n\\n ////// Protocol Settings //////\\n\\n function setSovrynProtocolAddress(address newProtocolAddress) external;\\n\\n function setSOVTokenAddress(address newSovTokenAddress) external;\\n\\n function setLockedSOVAddress(address newSOVLockedAddress) external;\\n\\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\\n\\n function setPriceFeedContract(address newContract) external;\\n\\n function setSwapsImplContract(address newContract) external;\\n\\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\\n\\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\\n\\n function setLendingFeePercent(uint256 newValue) external;\\n\\n function setTradingFeePercent(uint256 newValue) external;\\n\\n function setBorrowingFeePercent(uint256 newValue) external;\\n\\n function setSwapExternalFeePercent(uint256 newValue) external;\\n\\n function setAffiliateFeePercent(uint256 newValue) external;\\n\\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\\n\\n function setLiquidationIncentivePercent(uint256 newAmount) external;\\n\\n function setMaxDisagreement(uint256 newAmount) external;\\n\\n function setSourceBuffer(uint256 newAmount) external;\\n\\n function setMaxSwapSize(uint256 newAmount) external;\\n\\n function setFeesController(address newController) external;\\n\\n function withdrawFees(address[] calldata tokens, address receiver)\\n external\\n returns (uint256 totalWRBTCWithdrawn);\\n\\n function withdrawLendingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawTradingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawBorrowingFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external returns (bool);\\n\\n function withdrawProtocolToken(address receiver, uint256 amount)\\n external\\n returns (address, bool);\\n\\n function depositProtocolToken(uint256 amount) external;\\n\\n function getLoanPoolsList(uint256 start, uint256 count)\\n external\\n view\\n returns (bytes32[] memory);\\n\\n function isLoanPool(address loanPool) external view returns (bool);\\n\\n function setWrbtcToken(address wrbtcTokenAddress) external;\\n\\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\\n\\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\\n\\n function setRolloverBaseReward(uint256 transactionCost) external;\\n\\n function setRebatePercent(uint256 rebatePercent) external;\\n\\n function setSpecialRebates(\\n address sourceToken,\\n address destToken,\\n uint256 specialRebatesPercent\\n ) external;\\n\\n function getSpecialRebates(address sourceToken, address destToken)\\n external\\n view\\n returns (uint256 specialRebatesPercent);\\n\\n function togglePaused(bool paused) external;\\n\\n function isProtocolPaused() external view returns (bool);\\n\\n ////// SwapsImplSovrynSwapModule //////\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (address);\\n\\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\\n\\n function swapsImplExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function swapsImplExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256 expectedReturn);\\n\\n ////// Loan Settings //////\\n\\n function setupLoanParams(LoanParams[] calldata loanParamsList)\\n external\\n returns (bytes32[] memory loanParamsIdList);\\n\\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\\n\\n function getLoanParams(bytes32[] calldata loanParamsIdList)\\n external\\n view\\n returns (LoanParams[] memory loanParamsList);\\n\\n function getLoanParamsList(\\n address owner,\\n uint256 start,\\n uint256 count\\n ) external view returns (bytes32[] memory loanParamsList);\\n\\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\\n\\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\\n\\n ////// Loan Openings //////\\n\\n function borrowOrTradeFromPool(\\n bytes32 loanParamsId,\\n bytes32 loanId, // if 0, start a new loan\\n bool isTorqueLoan,\\n uint256 initialMargin,\\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\\n // lender: must match loan if loanId provided\\n // borrower: must match loan if loanId provided\\n // receiver: receiver of funds (address(0) assumes borrower address)\\n // manager: delegated manager of loan unless address(0)\\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\\n // newRate: new loan interest rate\\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\\n // collateralTokenReceived: total collateralToken deposit\\n bytes calldata loanDataBytes\\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\\n\\n function setDelegatedManager(\\n bytes32 loanId,\\n address delegated,\\n bool toggle\\n ) external;\\n\\n function getEstimatedMarginExposure(\\n address loanToken,\\n address collateralToken,\\n uint256 loanTokenSent,\\n uint256 collateralTokenSent,\\n uint256 interestRate,\\n uint256 newPrincipal\\n ) external view returns (uint256);\\n\\n function getRequiredCollateral(\\n address loanToken,\\n address collateralToken,\\n uint256 newPrincipal,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 collateralAmountRequired);\\n\\n function getBorrowAmount(\\n address loanToken,\\n address collateralToken,\\n uint256 collateralTokenAmount,\\n uint256 marginAmount,\\n bool isTorqueLoan\\n ) external view returns (uint256 borrowAmount);\\n\\n ////// Loan Closings //////\\n\\n function liquidate(\\n bytes32 loanId,\\n address receiver,\\n uint256 closeAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 seizedAmount,\\n address seizedToken\\n );\\n\\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\\n\\n function closeWithDeposit(\\n bytes32 loanId,\\n address receiver,\\n uint256 depositAmount // denominated in loanToken\\n )\\n external\\n payable\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n function closeWithSwap(\\n bytes32 loanId,\\n address receiver,\\n uint256 swapAmount, // denominated in collateralToken\\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\\n bytes calldata loanDataBytes\\n )\\n external\\n returns (\\n uint256 loanCloseAmount,\\n uint256 withdrawAmount,\\n address withdrawToken\\n );\\n\\n ////// Loan Maintenance //////\\n\\n function depositCollateral(\\n bytes32 loanId,\\n uint256 depositAmount // must match msg.value if ether is sent\\n ) external payable;\\n\\n function withdrawCollateral(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 actualWithdrawAmount);\\n\\n function withdrawAccruedInterest(address loanToken) external;\\n\\n function getLenderInterestData(address lender, address loanToken)\\n external\\n view\\n returns (\\n uint256 interestPaid,\\n uint256 interestPaidDate,\\n uint256 interestOwedPerDay,\\n uint256 interestUnPaid,\\n uint256 interestFeePercent,\\n uint256 principalTotal\\n );\\n\\n function getLoanInterestData(bytes32 loanId)\\n external\\n view\\n returns (\\n address loanToken,\\n uint256 interestOwedPerDay,\\n uint256 interestDepositTotal,\\n uint256 interestDepositRemaining\\n );\\n\\n struct LoanReturnData {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; // collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n }\\n\\n struct LoanReturnDataV2 {\\n bytes32 loanId;\\n address loanToken;\\n address collateralToken;\\n address borrower;\\n uint256 principal;\\n uint256 collateral;\\n uint256 interestOwedPerDay;\\n uint256 interestDepositRemaining;\\n uint256 startRate; /// collateralToLoanRate\\n uint256 startMargin;\\n uint256 maintenanceMargin;\\n uint256 currentMargin;\\n uint256 maxLoanTerm;\\n uint256 endTimestamp;\\n uint256 maxLiquidatable;\\n uint256 maxSeizable;\\n uint256 creationTimestamp;\\n }\\n\\n function getUserLoans(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getUserLoansV2(\\n address user,\\n uint256 start,\\n uint256 count,\\n uint256 loanType,\\n bool isLender,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\\n\\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\\n\\n function getActiveLoans(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnData[] memory loansData);\\n\\n function getActiveLoansV2(\\n uint256 start,\\n uint256 count,\\n bool unsafeOnly\\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\\n\\n function extendLoanDuration(\\n bytes32 loanId,\\n uint256 depositAmount,\\n bool useCollateral,\\n bytes calldata /// loanDataBytes, for future use.\\n ) external returns (uint256 secondsExtended);\\n\\n function reduceLoanDuration(\\n bytes32 loanId,\\n address receiver,\\n uint256 withdrawAmount\\n ) external returns (uint256 secondsReduced);\\n\\n ////// Swaps External //////\\n function swapExternal(\\n address sourceToken,\\n address destToken,\\n address receiver,\\n address returnToSender,\\n uint256 sourceTokenAmount,\\n uint256 requiredDestTokenAmount,\\n uint256 minReturn,\\n bytes calldata swapData\\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\\n\\n function getSwapExpectedReturn(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount\\n ) external view returns (uint256);\\n\\n function checkPriceDivergence(\\n address sourceToken,\\n address destToken,\\n uint256 sourceTokenAmount,\\n uint256 minReturn\\n ) public view;\\n\\n ////// Affiliates Module //////\\n\\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\\n\\n function setUserNotFirstTradeFlag(address user) external;\\n\\n function payTradingFeeToAffiliatesReferrer(\\n address referrer,\\n address trader,\\n address token,\\n uint256 tradingFeeTokenBaseAmount\\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\\n\\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\\n\\n function getReferralsList(address referrer) external view returns (address[] memory refList);\\n\\n function getAffiliatesReferrerBalances(address referrer)\\n external\\n view\\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\\n\\n function getAffiliatesReferrerTokensList(address referrer)\\n external\\n view\\n returns (address[] memory tokensList);\\n\\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\\n external\\n view\\n returns (uint256);\\n\\n function withdrawAffiliatesReferrerTokenFees(\\n address token,\\n address receiver,\\n uint256 amount\\n ) external;\\n\\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\\n\\n function getProtocolAddress() external view returns (address);\\n\\n function getSovTokenAddress() external view returns (address);\\n\\n function getLockedSOVAddress() external view returns (address);\\n\\n function getFeeRebatePercent() external view returns (uint256);\\n\\n function getMinReferralsToPayout() external view returns (uint256);\\n\\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\\n\\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\\n\\n function getAffiliateTradingTokenFeePercent()\\n external\\n view\\n returns (uint256 affiliateTradingTokenFeePercent);\\n\\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\\n external\\n view\\n returns (uint256 rbtcTotalAmount);\\n\\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\\n\\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\\n\\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\\n\\n function getDedicatedSOVRebate() external view returns (uint256);\\n\\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\\n\\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external\\n view\\n returns (IERC20[] memory);\\n\\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\\n\\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\\n external;\\n\\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\\n external\\n view\\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\\n\\n function setAdmin(address newAdmin) external;\\n\\n function getAdmin() external view returns (address);\\n\\n function setPauser(address newPauser) external;\\n\\n function getPauser() external view returns (address);\\n}\\n\",\"keccak256\":\"0x4e470e1fe1719c2c58b0e44aedce3ee6a21191063b533ccb71c9219a192e8884\"},\"contracts/interfaces/IWrbtc.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ninterface IWrbtc {\\n function deposit() external payable;\\n\\n function withdraw(uint256 wad) external;\\n}\\n\",\"keccak256\":\"0x20fdfe4b5e32fd7f863b3fa128e3c80bd4ccf090a4ffba56186ef3b7f2a80492\"},\"contracts/interfaces/IWrbtcERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./IWrbtc.sol\\\";\\nimport \\\"./IERC20.sol\\\";\\n\\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\\n\",\"keccak256\":\"0x7301a8c8ca7aa016ec94268a16d07366875f2e406442e929968dd745b1ee5be5\"},\"contracts/mixins/EnumerableAddressSet.sol\":{\"content\":\"pragma solidity ^0.5.0;\\n\\n/**\\n * @dev Based on Library for managing\\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\\n * types.\\n *\\n * Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * As of v2.5.0, only `address` sets are supported.\\n *\\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\\n *\\n * _Available since v2.5.0._\\n */\\nlibrary EnumerableAddressSet {\\n struct AddressSet {\\n // Position of the value in the `values` array, plus 1 because index 0\\n // means a value is not in the set.\\n mapping(address => uint256) index;\\n address[] values;\\n }\\n\\n /**\\n * @dev Add a value to a set. O(1).\\n * Returns false if the value was already in the set.\\n */\\n function add(AddressSet storage set, address value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Removes a value from a set. O(1).\\n * Returns false if the value was not present in the set.\\n */\\n function remove(AddressSet storage set, address value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n // If the element we're deleting is the last one, we can just remove it without doing a swap\\n if (lastIndex != toDeleteIndex) {\\n address lastValue = set.values[lastIndex];\\n\\n // Move the last value to the index where the deleted value is\\n set.values[toDeleteIndex] = lastValue;\\n // Update the index for the moved value\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n // Delete the index entry for the deleted value\\n delete set.index[value];\\n\\n // Delete the old entry for the moved value\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function contains(AddressSet storage set, address value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns an array with all values in the set. O(N).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\\n address[] memory output = new address[](set.values.length);\\n for (uint256 i; i < set.values.length; i++) {\\n output[i] = set.values[i];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n \\n * @param start start index of chunk\\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\\n */\\n function enumerateChunk(\\n AddressSet storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (address[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = (set.values.length < end || count == 0) ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new address[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @dev Returns the number of elements on the set. O(1).\\n */\\n function length(AddressSet storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /** @dev Returns the element stored at position `index` in the set. O(1).\\n * Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n */\\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xea6fba941ec8502aa11a7ab37e74b917d0dc47bb254e359a2870a87ef97d9872\"},\"contracts/mixins/EnumerableBytes32Set.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity 0.5.17;\\n\\n/**\\n * @title Library for managing loan sets.\\n *\\n * @notice Sets have the following properties:\\n *\\n * - Elements are added, removed, and checked for existence in constant time\\n * (O(1)).\\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\\n *\\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\\n * */\\nlibrary EnumerableBytes32Set {\\n struct Bytes32Set {\\n /// Position of the value in the `values` array, plus 1 because index 0\\n /// means a value is not in the set.\\n mapping(bytes32 => uint256) index;\\n bytes32[] values;\\n }\\n\\n /**\\n * @notice Add an address value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return addBytes32(set, value);\\n }\\n\\n /**\\n * @notice Add a value to a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The new value to add.\\n *\\n * @return False if the value was already in the set.\\n */\\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (!contains(set, value)) {\\n set.index[value] = set.values.push(value);\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Remove an address value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param addrvalue The address to remove.\\n *\\n * @return False if the address was not present in the set.\\n */\\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return removeBytes32(set, value);\\n }\\n\\n /**\\n * @notice Remove a value from a set. O(1).\\n *\\n * @param set The set of values.\\n * @param value The value to remove.\\n *\\n * @return False if the value was not present in the set.\\n */\\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\\n if (contains(set, value)) {\\n uint256 toDeleteIndex = set.index[value] - 1;\\n uint256 lastIndex = set.values.length - 1;\\n\\n /// If the element we're deleting is the last one,\\n /// we can just remove it without doing a swap.\\n if (lastIndex != toDeleteIndex) {\\n bytes32 lastValue = set.values[lastIndex];\\n\\n /// Move the last value to the index where the deleted value is.\\n set.values[toDeleteIndex] = lastValue;\\n\\n /// Update the index for the moved value.\\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\\n }\\n\\n /// Delete the index entry for the deleted value.\\n delete set.index[value];\\n\\n /// Delete the old entry for the moved value.\\n set.values.pop();\\n\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @notice Find out whether a value exists in the set.\\n *\\n * @param set The set of values.\\n * @param value The value to find.\\n *\\n * @return True if the value is in the set. O(1).\\n */\\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @dev Returns true if the value is in the set. O(1).\\n */\\n function containsAddress(Bytes32Set storage set, address addrvalue)\\n internal\\n view\\n returns (bool)\\n {\\n bytes32 value;\\n assembly {\\n value := addrvalue\\n }\\n return set.index[value] != 0;\\n }\\n\\n /**\\n * @notice Get all set values.\\n *\\n * @param set The set of values.\\n * @param start The offset of the returning set.\\n * @param count The limit of number of values to return.\\n *\\n * @return An array with all values in the set. O(N).\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * WARNING: This function may run out of gas on large sets: use {length} and\\n * {get} instead in these cases.\\n */\\n function enumerate(\\n Bytes32Set storage set,\\n uint256 start,\\n uint256 count\\n ) internal view returns (bytes32[] memory output) {\\n uint256 end = start + count;\\n require(end >= start, \\\"addition overflow\\\");\\n end = set.values.length < end ? set.values.length : end;\\n if (end == 0 || start >= end) {\\n return output;\\n }\\n\\n output = new bytes32[](end - start);\\n for (uint256 i; i < end - start; i++) {\\n output[i] = set.values[i + start];\\n }\\n return output;\\n }\\n\\n /**\\n * @notice Get the legth of the set.\\n *\\n * @param set The set of values.\\n *\\n * @return the number of elements on the set. O(1).\\n */\\n function length(Bytes32Set storage set) internal view returns (uint256) {\\n return set.values.length;\\n }\\n\\n /**\\n * @notice Get an item from the set by its index.\\n *\\n * @dev Note that there are no guarantees on the ordering of values inside the\\n * array, and it may change when more values are added or removed.\\n *\\n * Requirements:\\n *\\n * - `index` must be strictly less than {length}.\\n *\\n * @param set The set of values.\\n * @param index The index of the value to return.\\n *\\n * @return the element stored at position `index` in the set. O(1).\\n */\\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\\n return set.values[index];\\n }\\n}\\n\",\"keccak256\":\"0xa2801a585c566e07f21c1ebccd0cd0447dd5fd9fe6c1ff2b58d4d979d88a6db0\"},\"contracts/openzeppelin/Address.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\\n // for accounts without code, i.e. `keccak256('')`\\n bytes32 codehash;\\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\\n // solhint-disable-next-line no-inline-assembly\\n assembly {\\n codehash := extcodehash(account)\\n }\\n return (codehash != accountHash && codehash != 0x0);\\n }\\n\\n /**\\n * @dev Converts an `address` into `address payable`. Note that this is\\n * simply a type cast: the actual underlying value is not changed.\\n *\\n * _Available since v2.4.0._\\n */\\n function toPayable(address account) internal pure returns (address payable) {\\n return address(uint160(account));\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n *\\n * _Available since v2.4.0._\\n */\\n function sendValue(address recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n // solhint-disable-next-line avoid-call-value\\n (bool success, ) = recipient.call.value(amount)(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n}\\n\",\"keccak256\":\"0x23df48a01dbac9b25e86c9131174fb7752bbc7e741e63f1aa982de22e055ad54\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/openzeppelin/ReentrancyGuard.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @title Helps contracts guard against reentrancy attacks.\\n * @author Remco Bloemen , Eenae \\n * @dev If you mark a function `nonReentrant`, you should also\\n * mark it `external`.\\n */\\ncontract ReentrancyGuard {\\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\\n\\n /// @dev Constant for locked guard state\\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\\n\\n /**\\n * @dev We use a single lock for the whole contract.\\n */\\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\\n\\n /**\\n * @dev Prevents a contract from calling itself, directly or indirectly.\\n * If you mark a function `nonReentrant`, you should also\\n * mark it `external`. Calling one `nonReentrant` function from\\n * another is not supported. Instead, you can implement a\\n * `private` function doing the actual work, and an `external`\\n * wrapper marked as `nonReentrant`.\\n */\\n modifier nonReentrant() {\\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \\\"nonReentrant\\\");\\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\\n _;\\n reentrancyLock = REENTRANCY_GUARD_FREE;\\n }\\n}\\n\",\"keccak256\":\"0xd347de96ad57d1e45b07a2efe3050c1bd4b809236bbf354acb593de56d21a5c9\"},\"contracts/openzeppelin/SafeERC20.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./Address.sol\\\";\\nimport \\\"../interfaces/IERC20.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n using SafeMath for uint256;\\n using Address for address;\\n\\n function safeTransfer(\\n IERC20 token,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n }\\n\\n function safeTransferFrom(\\n IERC20 token,\\n address from,\\n address to,\\n uint256 value\\n ) internal {\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\\n );\\n }\\n\\n function safeApprove(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n // safeApprove should only be called when setting an initial allowance,\\n // or when resetting it to zero. To increase and decrease it, use\\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n // solhint-disable-next-line max-line-length\\n require(\\n (value == 0) || (token.allowance(address(this), spender) == 0),\\n \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n );\\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n }\\n\\n function safeIncreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n function safeDecreaseAllowance(\\n IERC20 token,\\n address spender,\\n uint256 value\\n ) internal {\\n uint256 newAllowance =\\n token.allowance(address(this), spender).sub(\\n value,\\n \\\"SafeERC20: decreased allowance below zero\\\"\\n );\\n callOptionalReturn(\\n token,\\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\\n );\\n }\\n\\n /**\\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n * on the return value: the return value is optional (but if data is returned, it must not be false).\\n * @param token The token targeted by the call.\\n * @param data The call data (encoded using abi.encode or one of its variants).\\n */\\n function callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves.\\n\\n // A Solidity high level call has three parts:\\n // 1. The target address is checked to verify it contains contract code\\n // 2. The call itself is made, and success asserted\\n // 3. The return value is decoded, which in turn checks the size of the returned data.\\n // solhint-disable-next-line max-line-length\\n require(address(token).isContract(), \\\"SafeERC20: call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = address(token).call(data);\\n require(success, \\\"SafeERC20: low-level call failed\\\");\\n\\n if (returndata.length > 0) {\\n // Return data is optional\\n // solhint-disable-next-line max-line-length\\n require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n }\\n }\\n}\\n\",\"keccak256\":\"0xe99b4d979cb976a6b70e297600242afe38b8cd8f1b1ba6ee373f39f7abb3ca79\"},\"contracts/openzeppelin/SafeMath.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\\n return divCeil(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n\\n if (a == 0) {\\n return 0;\\n }\\n uint256 c = ((a - 1) / b) + 1;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n\\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n return _a < _b ? _a : _b;\\n }\\n}\\n\",\"keccak256\":\"0xbff8d6273e1a6870d1a142c0c23acd63a4dd47760f250390f49ee56333bcb6e8\"},\"contracts/reentrancy/Mutex.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/*\\n * @title Global Mutex contract\\n *\\n * @notice A mutex contract that allows only one function to be called at a time out\\n * of a large set of functions. *Anyone* in the network can freely use any instance\\n * of this contract to add a universal mutex to any function in any contract.\\n */\\ncontract Mutex {\\n /*\\n * We use an uint to store the mutex state.\\n */\\n uint256 public value;\\n\\n /*\\n * @notice Increment the mutex state and return the new value.\\n *\\n * @dev This is the function that will be called by anyone to change the mutex\\n * state. It is purposely not protected by any access control\\n */\\n function incrementAndGetValue() external returns (uint256) {\\n /*\\n * increment value using unsafe math. This is safe because we are\\n * pretty certain no one will ever increment the value 2^256 times\\n * in a single transaction.\\n */\\n return ++value;\\n }\\n}\\n\",\"keccak256\":\"0xd10b0fd07d5fed1ae1237e7c87e6501970fce2a86e2b8862e502258b0d3aeb2c\"},\"contracts/reentrancy/SharedReentrancyGuard.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./Mutex.sol\\\";\\n\\n/*\\n * @title Abstract contract for shared reentrancy guards\\n *\\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\\n * that there's no reentrancy between *any* functions marked with the modifier.\\n *\\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\\n */\\ncontract SharedReentrancyGuard {\\n /*\\n * This is the address of the mutex contract that will be used as the\\n * reentrancy guard.\\n *\\n * The address is hardcoded to avoid changing the memory layout of\\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\\n * because the Mutex contract is always deployed to the same address, with the\\n * same method used in the deployment of ERC1820Registry.\\n */\\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\\n\\n /*\\n * This is the modifier that will be used to protect functions from\\n * reentrancy. It will call the mutex contract to increment the mutex\\n * state and then revert if the mutex state was changed by another\\n * nested call.\\n */\\n modifier globallyNonReentrant() {\\n uint256 previous = MUTEX.incrementAndGetValue();\\n\\n _;\\n\\n /*\\n * If the mutex state was changed by a nested function call, then\\n * the value of the state variable will be different from the previous value.\\n */\\n require(previous == MUTEX.value(), \\\"reentrancy violation\\\");\\n }\\n}\\n\",\"keccak256\":\"0x2d0e61b104b91c1764f20fbeb381ba0f8a8889934ba7f6e8a167ed542ec2c124\"},\"contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol\":{\"content\":\"pragma solidity 0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../feeds/IPriceFeeds.sol\\\";\\nimport \\\"../../openzeppelin/SafeERC20.sol\\\";\\nimport \\\"./interfaces/ISovrynSwapNetwork.sol\\\";\\nimport \\\"./interfaces/IContractRegistry.sol\\\";\\nimport \\\"../../interfaces/ISovryn.sol\\\";\\n\\n/**\\n * @title Swaps Implementation Sovryn contract.\\n *\\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\\n *\\n * This contract contains the implementation of swap process and rate\\n * calculations for Sovryn network.\\n * */\\nlibrary SwapsImplSovrynSwapLib {\\n using SafeMath for uint256;\\n using SafeERC20 for IERC20;\\n\\n struct SwapParams {\\n address sourceTokenAddress;\\n address destTokenAddress;\\n address receiverAddress;\\n address returnToSenderAddress;\\n uint256 minSourceTokenAmount;\\n uint256 maxSourceTokenAmount;\\n uint256 requiredDestTokenAmount;\\n }\\n\\n /// bytes32 contractName = hex\\\"42616e636f724e6574776f726b\\\"; /// \\\"SovrynSwapNetwork\\\"\\n\\n /**\\n * Get the hex name of a contract.\\n * @param source The name of the contract.\\n * */\\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\\n assembly {\\n result := mload(add(source, 32))\\n }\\n }\\n\\n /**\\n * Look up the Sovryn swap network contract registered at the given address.\\n * @param sovrynSwapRegistryAddress The address of the registry.\\n * */\\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\\n public\\n view\\n returns (ISovrynSwapNetwork)\\n {\\n /// State variable sovrynSwapContractRegistryAddress is part of\\n /// State.sol and set in ProtocolSettings.sol and this function\\n /// needs to work without delegate call as well -> therefore pass it.\\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\\n return\\n ISovrynSwapNetwork(\\n contractRegistry.addressOf(getContractHexName(\\\"SovrynSwapNetwork\\\"))\\n );\\n }\\n\\n /**\\n * Swap the source token for the destination token on the oracle based AMM.\\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\\n * -> swap the minSourceTokenAmount\\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\\n * -> same as on rollover. minimum amount is not considered at all.\\n *\\n * @param params SwapParams struct\\n * sourceTokenAddress The address of the source tokens.\\n * destTokenAddress The address of the destination tokens.\\n * receiverAddress The address who will received the swap token results\\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\\n * requiredDestTokenAmount The required amount of destination tokens.\\n * */\\n function swap(SwapParams memory params)\\n public\\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\\n {\\n require(params.sourceTokenAddress != params.destTokenAddress, \\\"source == dest\\\");\\n\\n ISovryn iSovryn = ISovryn(address(this));\\n require(\\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\\n iSovryn.supportedTokens(params.destTokenAddress),\\n \\\"invalid tokens\\\"\\n );\\n\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\\n\\n IERC20[] memory path =\\n _getConversionPath(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n sovrynSwapNetwork\\n );\\n\\n uint256 minReturn = 1;\\n sourceTokenAmountUsed = params.minSourceTokenAmount;\\n\\n /// If the required amount of destination tokens is passed, we need to\\n /// calculate the estimated amount of source tokens regardless of the\\n /// minimum source token amount (name is misleading).\\n if (params.requiredDestTokenAmount > 0) {\\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\\n params.sourceTokenAddress,\\n params.destTokenAddress,\\n params.requiredDestTokenAmount,\\n params.maxSourceTokenAmount\\n );\\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\\n require(\\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\\n params.requiredDestTokenAmount,\\n \\\"insufficient source tokens provided.\\\"\\n );\\n minReturn = params.requiredDestTokenAmount;\\n }\\n\\n require(sourceTokenAmountUsed > 0, \\\"cannot swap 0 tokens\\\");\\n\\n _allowTransfer(\\n sourceTokenAmountUsed,\\n params.sourceTokenAddress,\\n address(sovrynSwapNetwork)\\n );\\n\\n /// @dev Note: the kyber connector uses .call() to interact with kyber\\n /// to avoid bubbling up. here we allow bubbling up.\\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\\n path,\\n sourceTokenAmountUsed,\\n minReturn,\\n params.receiverAddress,\\n address(0),\\n 0\\n );\\n\\n /// If the sender is not the protocol (calling with delegatecall),\\n /// return the remainder to the specified address.\\n /// @dev Note: for the case that the swap is used without the\\n /// protocol. Not sure if it should, though. needs to be discussed.\\n if (params.returnToSenderAddress != address(this)) {\\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\\n /// Send unused source token back.\\n IERC20(params.sourceTokenAddress).safeTransfer(\\n params.returnToSenderAddress,\\n params.maxSourceTokenAmount - sourceTokenAmountUsed\\n );\\n }\\n }\\n }\\n\\n /**\\n * @notice Check whether the existing allowance suffices to transfer\\n * the needed amount of tokens.\\n * If not, allows the transfer of an arbitrary amount of tokens.\\n *\\n * @param tokenAmount The amount to transfer.\\n * @param tokenAddress The address of the token to transfer.\\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\\n * */\\n function _allowTransfer(\\n uint256 tokenAmount,\\n address tokenAddress,\\n address sovrynSwapNetwork\\n ) internal {\\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\\n if (tempAllowance < tokenAmount) {\\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\\n }\\n }\\n\\n /**\\n * @notice Calculate the number of source tokens to provide in order to\\n * obtain the required destination amount.\\n *\\n * @param sourceTokenAddress The address of the source token address.\\n * @param destTokenAddress The address of the destination token address.\\n * @param requiredDestTokenAmount The number of destination tokens needed.\\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\\n *\\n * @return The estimated amount of source tokens needed.\\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\\n * */\\n function _estimateSourceTokenAmount(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 requiredDestTokenAmount,\\n uint256 maxSourceTokenAmount\\n ) internal view returns (uint256 estimatedSourceAmount) {\\n ISovryn iSovryn = ISovryn(address(this));\\n uint256 sourceToDestPrecision =\\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\\n\\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\\n uint256 expectedRate =\\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\\n\\n /// Compute the source tokens needed to get the required amount with the worst case rate.\\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\\n expectedRate\\n );\\n\\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\\n uint256 buffer = estimatedSourceAmount.div(1000);\\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\\n\\n /// Never spend more than the maximum.\\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\\n return maxSourceTokenAmount;\\n }\\n\\n /**\\n * @notice Get the expected rate for 1 source token when exchanging the\\n * given amount of source tokens.\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\\n * */\\n function getExpectedRate(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n\\n /// Return the rate for 1 token with 18 decimals.\\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\\n }\\n\\n /**\\n * @notice Get the expected return amount when exchanging the given\\n * amount of source tokens.\\n *\\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\\n *\\n * @param sourceTokenAddress The address of the source token contract.\\n * @param destTokenAddress The address of the destination token contract.\\n * @param sourceTokenAmount The amount of source tokens to get the return for.\\n * */\\n function getExpectedReturn(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n uint256 sourceTokenAmount\\n ) public view returns (uint256 expectedReturn) {\\n ISovrynSwapNetwork sovrynSwapNetwork =\\n getSovrynSwapNetworkContract(\\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\\n );\\n\\n IERC20[] memory path =\\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\\n\\n /// Is returning the total amount of destination tokens.\\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\\n }\\n\\n function _getConversionPath(\\n address sourceTokenAddress,\\n address destTokenAddress,\\n ISovrynSwapNetwork sovrynSwapNetwork\\n ) private view returns (IERC20[] memory path) {\\n IERC20[] memory _defaultPathConversion =\\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\\n\\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\\n path = _defaultPathConversion.length >= 3\\n ? _defaultPathConversion\\n : sovrynSwapNetwork.conversionPath(\\n IERC20(sourceTokenAddress),\\n IERC20(destTokenAddress)\\n );\\n }\\n}\\n\",\"keccak256\":\"0x058b8d733422a2421f17d1b159aed69f151ea8d5f48ee507bac5b4e86add8b0c\"},\"contracts/swaps/connectors/interfaces/IContractRegistry.sol\":{\"content\":\"pragma solidity 0.5.17;\\n\\ncontract IContractRegistry {\\n function addressOf(bytes32 contractName) public view returns (address);\\n}\\n\",\"keccak256\":\"0x793c4eefa2ee04cbf0a1a9da28676ac310ed7bf60a27ec7d86de7d7236ccf45b\"},\"contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol\":{\"content\":\"pragma solidity >=0.5.8 <=0.5.17;\\n\\nimport \\\"../../../interfaces/IERC20.sol\\\";\\n\\ncontract ISovrynSwapNetwork {\\n function convertByPath(\\n IERC20[] calldata _path,\\n uint256 _amount,\\n uint256 _minReturn,\\n address _beneficiary,\\n address _affiliateAccount,\\n uint256 _affiliateFee\\n ) external payable returns (uint256);\\n\\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\\n\\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\\n external\\n view\\n returns (IERC20[] memory);\\n}\\n\",\"keccak256\":\"0xcd28e146b77183bff18f78b511912f7ebe60d437430fdaa72ed145fdda61a5ad\"}},\"version\":1}", + "bytecode": "0x61187c610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100615760003560e01c806335aaa79d146100665780636dcd64e51461009d578063809a9e55146100bd578063b1fb7f56146100d0578063ca83d575146100e3575b600080fd5b81801561007257600080fd5b50610086610081366004611199565b610103565b6040516100949291906116ef565b60405180910390f35b6100b06100ab3660046110c4565b6104dd565b6040516100949190611607565b6100b06100cb3660046110c4565b6105b6565b6100b06100de366004611164565b6106bd565b6100f66100f1366004611088565b6106c4565b6040516100949190611630565b60008082602001516001600160a01b031683600001516001600160a01b031614156101495760405162461bcd60e51b81526004016101409061169f565b60405180910390fd5b8251604051633462561360e11b8152309182916368c4ac269161016e91600401611544565b60206040518083038186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101be9190810190611146565b801561024557506020840151604051633462561360e11b81526001600160a01b038316916368c4ac26916101f59190600401611544565b60206040518083038186803b15801561020d57600080fd5b505afa158015610221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102459190810190611146565b6102615760405162461bcd60e51b81526004016101409061167f565b60006102d7826001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b505afa1580156102b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506100f191908101906110a6565b905060606102ee8660000151876020015184610777565b608087015160c0880151909550909150600190156103cc57610322876000015188602001518960c001518a60a00151610893565b94508660c00151836001600160a01b0316637f9c0ecd84886040518363ffffffff1660e01b8152600401610357929190611588565b60206040518083038186803b15801561036f57600080fd5b505afa158015610383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103a791908101906111b7565b10156103c55760405162461bcd60e51b8152600401610140906116af565b5060c08601515b600085116103ec5760405162461bcd60e51b81526004016101409061164f565b6103fb85886000015185610afd565b604080880151905163b77d239b60e01b81526001600160a01b0385169163b77d239b916104359186918a91879160009081906004016115a8565b602060405180830381600087803b15801561044f57600080fd5b505af1158015610463573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061048791908101906111b7565b60608801519096506001600160a01b031630146104d4578660a001518510156104d457606087015160a088015188516104d4926001600160a01b039091169188900363ffffffff610baa16565b50505050915091565b60008061051c306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b9050606061052b868684610777565b604051637f9c0ecd60e01b81529091506001600160a01b03831690637f9c0ecd9061055c9084908890600401611588565b60206040518083038186803b15801561057457600080fd5b505afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105ac91908101906111b7565b9695505050505050565b6000806105f5306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b90506060610604868684610777565b90506000826001600160a01b0316637f9c0ecd83876040518363ffffffff1660e01b8152600401610636929190611588565b60206040518083038186803b15801561064e57600080fd5b505afa158015610662573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061068691908101906111b7565b90506106b0856106a483670de0b6b3a764000063ffffffff610c0816565b9063ffffffff610c4b16565b93505050505b9392505050565b6020015190565b600080829050806001600160a01b031663bb34534c61070b60405180604001604052806011815260200170536f7672796e537761704e6574776f726b60781b8152506106bd565b6040518263ffffffff1660e01b81526004016107279190611607565b60206040518083038186803b15801561073f57600080fd5b505afa158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106b691908101906110a6565b604051638654042960e01b8152606090819030906386540429906107a19088908890600401611552565b60006040518083038186803b1580156107b957600080fd5b505afa1580156107cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107f59190810190611111565b90506003815110156108885760405163d734fa1960e01b81526001600160a01b0384169063d734fa199061082f9088908890600401611615565b60006040518083038186803b15801561084757600080fd5b505afa15801561085b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108839190810190611111565b61088a565b805b95945050505050565b6000803090506000816001600160a01b03166378d849ed6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108d457600080fd5b505afa1580156108e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061090c91908101906110a6565b6001600160a01b031663524efd4b88886040518363ffffffff1660e01b8152600401610939929190611552565b60206040518083038186803b15801561095157600080fd5b505afa158015610965573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098991908101906111b7565b90508061099a578392505050610af5565b60006109a78888876105b6565b90506109bd816106a4888563ffffffff610c0816565b935060006109d3856103e863ffffffff610c4b16565b9050836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0e57600080fd5b505afa158015610a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a4691908101906111b7565b811115610ac157836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8657600080fd5b505afa158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610abe91908101906111b7565b90505b610ad1858263ffffffff610c8d16565b9450841580610adf57508585115b15610af05785945050505050610af5565b505050505b949350505050565b604051636eb1769f60e11b81526000906001600160a01b0384169063dd62ed3e90610b2e9030908690600401611552565b60206040518083038186803b158015610b4657600080fd5b505afa158015610b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b7e91908101906111b7565b905083811015610ba457610ba46001600160a01b0384168360001963ffffffff610cb216565b50505050565b604051610c0390849063a9059cbb60e01b90610bcc908690869060240161156d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610d78565b505050565b600082610c1757506000610c45565b82820282848281610c2457fe5b0414610c425760405162461bcd60e51b81526004016101409061168f565b90505b92915050565b6000610c4283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250610e5d565b600082820183811015610c425760405162461bcd60e51b81526004016101409061165f565b801580610d3a5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90610ce89030908690600401611552565b60206040518083038186803b158015610d0057600080fd5b505afa158015610d14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d3891908101906111b7565b155b610d565760405162461bcd60e51b8152600401610140906116cf565b604051610c0390849063095ea7b360e01b90610bcc908690869060240161156d565b610d8a826001600160a01b0316610e94565b610da65760405162461bcd60e51b8152600401610140906116df565b60006060836001600160a01b031683604051610dc29190611538565b6000604051808303816000865af19150503d8060008114610dff576040519150601f19603f3d011682016040523d82523d6000602084013e610e04565b606091505b509150915081610e265760405162461bcd60e51b81526004016101409061166f565b805115610ba45780806020019051610e419190810190611146565b610ba45760405162461bcd60e51b8152600401610140906116bf565b60008183610e7e5760405162461bcd60e51b8152600401610140919061163e565b506000838581610e8a57fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610af5575050151592915050565b8035610c4581611807565b8051610c4581611807565b600082601f830112610ef457600080fd5b8151610f07610f0282611724565b6116fd565b91508181835260208401935060208101905083856020840282011115610f2c57600080fd5b60005b83811015610f585781610f428882610f6d565b8452506020928301929190910190600101610f2f565b5050505092915050565b8051610c458161181e565b8051610c4581611827565b600082601f830112610f8957600080fd5b8135610f97610f0282611745565b91508082526020830160208301858383011115610fb357600080fd5b610fbe8382846117c5565b50505092915050565b600060e08284031215610fd957600080fd5b610fe360e06116fd565b90506000610ff18484610ecd565b825250602061100284848301610ecd565b602083015250604061101684828501610ecd565b604083015250606061102a84828501610ecd565b606083015250608061103e84828501611072565b60808301525060a061105284828501611072565b60a08301525060c061106684828501611072565b60c08301525092915050565b8035610c4581611830565b8051610c4581611830565b60006020828403121561109a57600080fd5b6000610af58484610ecd565b6000602082840312156110b857600080fd5b6000610af58484610ed8565b6000806000606084860312156110d957600080fd5b60006110e58686610ecd565b93505060206110f686828701610ecd565b925050604061110786828701611072565b9150509250925092565b60006020828403121561112357600080fd5b815167ffffffffffffffff81111561113a57600080fd5b610af584828501610ee3565b60006020828403121561115857600080fd5b6000610af58484610f62565b60006020828403121561117657600080fd5b813567ffffffffffffffff81111561118d57600080fd5b610af584828501610f78565b600060e082840312156111ab57600080fd5b6000610af58484610fc7565b6000602082840312156111c957600080fd5b6000610af5848461107d565b60006111e18383611292565b505060200190565b6111f2816117af565b82525050565b6111f281611785565b600061120c82611773565b6112168185611777565b93506112218361176d565b8060005b8381101561124f57815161123988826111d5565b97506112448361176d565b925050600101611225565b509495945050505050565b6111f281611795565b600061126e82611773565b6112788185611780565b93506112888185602086016117d1565b9290920192915050565b6111f281611798565b6111f2816117ba565b60006112af82611773565b6112b98185611777565b93506112c98185602086016117d1565b6112d2816117fd565b9093019392505050565b60006112e9601483611777565b7363616e6e6f742073776170203020746f6b656e7360601b815260200192915050565b6000611319601b83611777565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000611352602083611777565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061138b600e83611777565b6d696e76616c696420746f6b656e7360901b815260200192915050565b60006113b5602183611777565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006113f8600e83611777565b6d1cdbdd5c98d9480f4f4819195cdd60921b815260200192915050565b6000611422602483611777565b7f696e73756666696369656e7420736f7572636520746f6b656e732070726f76698152633232b21760e11b602082015260400192915050565b6000611468602a83611777565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006114b4603683611777565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b602082015260400192915050565b600061150c601f83611777565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b60006106b68284611263565b60208101610c4582846111f8565b6040810161156082856111f8565b6106b660208301846111f8565b6040810161157b82856111f8565b6106b6602083018461125a565b604080825281016115998185611201565b90506106b6602083018461125a565b60c080825281016115b98189611201565b90506115c8602083018861125a565b6115d5604083018761125a565b6115e260608301866111f8565b6115ef60808301856111e9565b6115fc60a083018461129b565b979650505050505050565b60208101610c45828461125a565b604081016116238285611292565b6106b66020830184611292565b60208101610c458284611292565b60208082528101610c4281846112a4565b60208082528101610c45816112dc565b60208082528101610c458161130c565b60208082528101610c4581611345565b60208082528101610c458161137e565b60208082528101610c45816113a8565b60208082528101610c45816113eb565b60208082528101610c4581611415565b60208082528101610c458161145b565b60208082528101610c45816114a7565b60208082528101610c45816114ff565b6040810161157b828561125a565b60405181810167ffffffffffffffff8111828210171561171c57600080fd5b604052919050565b600067ffffffffffffffff82111561173b57600080fd5b5060209081020190565b600067ffffffffffffffff82111561175c57600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b919050565b6000610c45826117a3565b151590565b90565b6000610c4582611785565b6001600160a01b031690565b6000610c4582611798565b6000610c4582611795565b82818337506000910152565b60005b838110156117ec5781810151838201526020016117d4565b83811115610ba45750506000910152565b601f01601f191690565b61181081611785565b811461181b57600080fd5b50565b61181081611790565b61181081611798565b6118108161179556fea365627a7a72315820ebc5e468d7f9c6318e17879153dc3c0c04f9da7556939114f9f7ba14b6786def6c6578706572696d656e74616cf564736f6c63430005110040", + "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600436106100615760003560e01c806335aaa79d146100665780636dcd64e51461009d578063809a9e55146100bd578063b1fb7f56146100d0578063ca83d575146100e3575b600080fd5b81801561007257600080fd5b50610086610081366004611199565b610103565b6040516100949291906116ef565b60405180910390f35b6100b06100ab3660046110c4565b6104dd565b6040516100949190611607565b6100b06100cb3660046110c4565b6105b6565b6100b06100de366004611164565b6106bd565b6100f66100f1366004611088565b6106c4565b6040516100949190611630565b60008082602001516001600160a01b031683600001516001600160a01b031614156101495760405162461bcd60e51b81526004016101409061169f565b60405180910390fd5b8251604051633462561360e11b8152309182916368c4ac269161016e91600401611544565b60206040518083038186803b15801561018657600080fd5b505afa15801561019a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101be9190810190611146565b801561024557506020840151604051633462561360e11b81526001600160a01b038316916368c4ac26916101f59190600401611544565b60206040518083038186803b15801561020d57600080fd5b505afa158015610221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102459190810190611146565b6102615760405162461bcd60e51b81526004016101409061167f565b60006102d7826001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b505afa1580156102b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506100f191908101906110a6565b905060606102ee8660000151876020015184610777565b608087015160c0880151909550909150600190156103cc57610322876000015188602001518960c001518a60a00151610893565b94508660c00151836001600160a01b0316637f9c0ecd84886040518363ffffffff1660e01b8152600401610357929190611588565b60206040518083038186803b15801561036f57600080fd5b505afa158015610383573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103a791908101906111b7565b10156103c55760405162461bcd60e51b8152600401610140906116af565b5060c08601515b600085116103ec5760405162461bcd60e51b81526004016101409061164f565b6103fb85886000015185610afd565b604080880151905163b77d239b60e01b81526001600160a01b0385169163b77d239b916104359186918a91879160009081906004016115a8565b602060405180830381600087803b15801561044f57600080fd5b505af1158015610463573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061048791908101906111b7565b60608801519096506001600160a01b031630146104d4578660a001518510156104d457606087015160a088015188516104d4926001600160a01b039091169188900363ffffffff610baa16565b50505050915091565b60008061051c306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b9050606061052b868684610777565b604051637f9c0ecd60e01b81529091506001600160a01b03831690637f9c0ecd9061055c9084908890600401611588565b60206040518083038186803b15801561057457600080fd5b505afa158015610588573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105ac91908101906111b7565b9695505050505050565b6000806105f5306001600160a01b031663ba4861e96040518163ffffffff1660e01b815260040160206040518083038186803b15801561029f57600080fd5b90506060610604868684610777565b90506000826001600160a01b0316637f9c0ecd83876040518363ffffffff1660e01b8152600401610636929190611588565b60206040518083038186803b15801561064e57600080fd5b505afa158015610662573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061068691908101906111b7565b90506106b0856106a483670de0b6b3a764000063ffffffff610c0816565b9063ffffffff610c4b16565b93505050505b9392505050565b6020015190565b600080829050806001600160a01b031663bb34534c61070b60405180604001604052806011815260200170536f7672796e537761704e6574776f726b60781b8152506106bd565b6040518263ffffffff1660e01b81526004016107279190611607565b60206040518083038186803b15801561073f57600080fd5b505afa158015610753573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106b691908101906110a6565b604051638654042960e01b8152606090819030906386540429906107a19088908890600401611552565b60006040518083038186803b1580156107b957600080fd5b505afa1580156107cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526107f59190810190611111565b90506003815110156108885760405163d734fa1960e01b81526001600160a01b0384169063d734fa199061082f9088908890600401611615565b60006040518083038186803b15801561084757600080fd5b505afa15801561085b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108839190810190611111565b61088a565b805b95945050505050565b6000803090506000816001600160a01b03166378d849ed6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108d457600080fd5b505afa1580156108e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061090c91908101906110a6565b6001600160a01b031663524efd4b88886040518363ffffffff1660e01b8152600401610939929190611552565b60206040518083038186803b15801561095157600080fd5b505afa158015610965573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061098991908101906111b7565b90508061099a578392505050610af5565b60006109a78888876105b6565b90506109bd816106a4888563ffffffff610c0816565b935060006109d3856103e863ffffffff610c4b16565b9050836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a0e57600080fd5b505afa158015610a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610a4691908101906111b7565b811115610ac157836001600160a01b031663f0e085f56040518163ffffffff1660e01b815260040160206040518083038186803b158015610a8657600080fd5b505afa158015610a9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610abe91908101906111b7565b90505b610ad1858263ffffffff610c8d16565b9450841580610adf57508585115b15610af05785945050505050610af5565b505050505b949350505050565b604051636eb1769f60e11b81526000906001600160a01b0384169063dd62ed3e90610b2e9030908690600401611552565b60206040518083038186803b158015610b4657600080fd5b505afa158015610b5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b7e91908101906111b7565b905083811015610ba457610ba46001600160a01b0384168360001963ffffffff610cb216565b50505050565b604051610c0390849063a9059cbb60e01b90610bcc908690869060240161156d565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610d78565b505050565b600082610c1757506000610c45565b82820282848281610c2457fe5b0414610c425760405162461bcd60e51b81526004016101409061168f565b90505b92915050565b6000610c4283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250610e5d565b600082820183811015610c425760405162461bcd60e51b81526004016101409061165f565b801580610d3a5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e90610ce89030908690600401611552565b60206040518083038186803b158015610d0057600080fd5b505afa158015610d14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d3891908101906111b7565b155b610d565760405162461bcd60e51b8152600401610140906116cf565b604051610c0390849063095ea7b360e01b90610bcc908690869060240161156d565b610d8a826001600160a01b0316610e94565b610da65760405162461bcd60e51b8152600401610140906116df565b60006060836001600160a01b031683604051610dc29190611538565b6000604051808303816000865af19150503d8060008114610dff576040519150601f19603f3d011682016040523d82523d6000602084013e610e04565b606091505b509150915081610e265760405162461bcd60e51b81526004016101409061166f565b805115610ba45780806020019051610e419190810190611146565b610ba45760405162461bcd60e51b8152600401610140906116bf565b60008183610e7e5760405162461bcd60e51b8152600401610140919061163e565b506000838581610e8a57fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610af5575050151592915050565b8035610c4581611807565b8051610c4581611807565b600082601f830112610ef457600080fd5b8151610f07610f0282611724565b6116fd565b91508181835260208401935060208101905083856020840282011115610f2c57600080fd5b60005b83811015610f585781610f428882610f6d565b8452506020928301929190910190600101610f2f565b5050505092915050565b8051610c458161181e565b8051610c4581611827565b600082601f830112610f8957600080fd5b8135610f97610f0282611745565b91508082526020830160208301858383011115610fb357600080fd5b610fbe8382846117c5565b50505092915050565b600060e08284031215610fd957600080fd5b610fe360e06116fd565b90506000610ff18484610ecd565b825250602061100284848301610ecd565b602083015250604061101684828501610ecd565b604083015250606061102a84828501610ecd565b606083015250608061103e84828501611072565b60808301525060a061105284828501611072565b60a08301525060c061106684828501611072565b60c08301525092915050565b8035610c4581611830565b8051610c4581611830565b60006020828403121561109a57600080fd5b6000610af58484610ecd565b6000602082840312156110b857600080fd5b6000610af58484610ed8565b6000806000606084860312156110d957600080fd5b60006110e58686610ecd565b93505060206110f686828701610ecd565b925050604061110786828701611072565b9150509250925092565b60006020828403121561112357600080fd5b815167ffffffffffffffff81111561113a57600080fd5b610af584828501610ee3565b60006020828403121561115857600080fd5b6000610af58484610f62565b60006020828403121561117657600080fd5b813567ffffffffffffffff81111561118d57600080fd5b610af584828501610f78565b600060e082840312156111ab57600080fd5b6000610af58484610fc7565b6000602082840312156111c957600080fd5b6000610af5848461107d565b60006111e18383611292565b505060200190565b6111f2816117af565b82525050565b6111f281611785565b600061120c82611773565b6112168185611777565b93506112218361176d565b8060005b8381101561124f57815161123988826111d5565b97506112448361176d565b925050600101611225565b509495945050505050565b6111f281611795565b600061126e82611773565b6112788185611780565b93506112888185602086016117d1565b9290920192915050565b6111f281611798565b6111f2816117ba565b60006112af82611773565b6112b98185611777565b93506112c98185602086016117d1565b6112d2816117fd565b9093019392505050565b60006112e9601483611777565b7363616e6e6f742073776170203020746f6b656e7360601b815260200192915050565b6000611319601b83611777565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000611352602083611777565b7f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b600061138b600e83611777565b6d696e76616c696420746f6b656e7360901b815260200192915050565b60006113b5602183611777565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b60006113f8600e83611777565b6d1cdbdd5c98d9480f4f4819195cdd60921b815260200192915050565b6000611422602483611777565b7f696e73756666696369656e7420736f7572636520746f6b656e732070726f76698152633232b21760e11b602082015260400192915050565b6000611468602a83611777565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b60006114b4603683611777565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f81527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b602082015260400192915050565b600061150c601f83611777565b7f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b60006106b68284611263565b60208101610c4582846111f8565b6040810161156082856111f8565b6106b660208301846111f8565b6040810161157b82856111f8565b6106b6602083018461125a565b604080825281016115998185611201565b90506106b6602083018461125a565b60c080825281016115b98189611201565b90506115c8602083018861125a565b6115d5604083018761125a565b6115e260608301866111f8565b6115ef60808301856111e9565b6115fc60a083018461129b565b979650505050505050565b60208101610c45828461125a565b604081016116238285611292565b6106b66020830184611292565b60208101610c458284611292565b60208082528101610c4281846112a4565b60208082528101610c45816112dc565b60208082528101610c458161130c565b60208082528101610c4581611345565b60208082528101610c458161137e565b60208082528101610c45816113a8565b60208082528101610c45816113eb565b60208082528101610c4581611415565b60208082528101610c458161145b565b60208082528101610c45816114a7565b60208082528101610c45816114ff565b6040810161157b828561125a565b60405181810167ffffffffffffffff8111828210171561171c57600080fd5b604052919050565b600067ffffffffffffffff82111561173b57600080fd5b5060209081020190565b600067ffffffffffffffff82111561175c57600080fd5b506020601f91909101601f19160190565b60200190565b5190565b90815260200190565b919050565b6000610c45826117a3565b151590565b90565b6000610c4582611785565b6001600160a01b031690565b6000610c4582611798565b6000610c4582611795565b82818337506000910152565b60005b838110156117ec5781810151838201526020016117d4565b83811115610ba45750506000910152565b601f01601f191690565b61181081611785565b811461181b57600080fd5b50565b61181081611790565b61181081611798565b6118108161179556fea365627a7a72315820ebc5e468d7f9c6318e17879153dc3c0c04f9da7556939114f9f7ba14b6786def6c6578706572696d656e74616cf564736f6c63430005110040", "devdoc": { "methods": { "getContractHexName(string)": { diff --git a/deployment/deployments/rskSovrynTestnet/VestingFactory.json b/deployment/deployments/rskSovrynTestnet/VestingFactory.json new file mode 100644 index 000000000..12bb5317f --- /dev/null +++ b/deployment/deployments/rskSovrynTestnet/VestingFactory.json @@ -0,0 +1,313 @@ +{ + "address": "0x164E4f8c386da88Ff474E4456EFf917cF46767Bc", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_vestingLogic", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_SOV", + "type": "address" + }, + { + "internalType": "address", + "name": "_staking", + "type": "address" + }, + { + "internalType": "address", + "name": "_tokenOwner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_cliff", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_feeSharing", + "type": "address" + }, + { + "internalType": "address", + "name": "_vestingOwner", + "type": "address" + } + ], + "name": "deployTeamVesting", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_SOV", + "type": "address" + }, + { + "internalType": "address", + "name": "_staking", + "type": "address" + }, + { + "internalType": "address", + "name": "_tokenOwner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_cliff", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_duration", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_feeSharing", + "type": "address" + }, + { + "internalType": "address", + "name": "_vestingOwner", + "type": "address" + } + ], + "name": "deployVesting", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isOwner", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "vestingLogic", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x07e561de83e85fc6fc5a23d901bbcee494bc3450bbfeab65ddcffaf6a9f885cc", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0x164E4f8c386da88Ff474E4456EFf917cF46767Bc", + "transactionIndex": 0, + "gasUsed": "2593623", + "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000010000000000000000100020000000000000000000000000000000000000000000000000000000000000000100", + "blockHash": "0x148ce9cda6a6828be3277b2eadfe32c06668a74fdf432024d54f1ed87e4d59f0", + "transactionHash": "0x07e561de83e85fc6fc5a23d901bbcee494bc3450bbfeab65ddcffaf6a9f885cc", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4639994, + "transactionHash": "0x07e561de83e85fc6fc5a23d901bbcee494bc3450bbfeab65ddcffaf6a9f885cc", + "address": "0x164E4f8c386da88Ff474E4456EFf917cF46767Bc", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x148ce9cda6a6828be3277b2eadfe32c06668a74fdf432024d54f1ed87e4d59f0" + } + ], + "blockNumber": 4639994, + "cumulativeGasUsed": "2593623", + "status": 1, + "byzantium": true + }, + "args": [ + "0x07ba5E5bD20810A0B00b0B22D55243aAdd3F33E4" + ], + "numDeployments": 2, + "solcInputHash": "aca886878e9e0827277d5a4711a5589b", + "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vestingLogic\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_SOV\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_staking\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_tokenOwner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_cliff\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_duration\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_feeSharing\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vestingOwner\",\"type\":\"address\"}],\"name\":\"deployTeamVesting\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_SOV\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_staking\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_tokenOwner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_cliff\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_duration\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_feeSharing\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vestingOwner\",\"type\":\"address\"}],\"name\":\"deployVesting\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"vestingLogic\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{\"deployTeamVesting(address,address,address,uint256,uint256,address,address)\":{\"params\":{\"_SOV\":\"The address of SOV token.\",\"_cliff\":\"The time interval to the first withdraw in seconds.\",\"_duration\":\"The total duration in seconds.\",\"_feeSharing\":\"The address of fee sharing contract.\",\"_staking\":\"The address of staking contract.\",\"_tokenOwner\":\"The owner of the tokens.\",\"_vestingOwner\":\"The address of an owner of vesting contract.\"},\"return\":\"The vesting contract address.\"},\"deployVesting(address,address,address,uint256,uint256,address,address)\":{\"params\":{\"_SOV\":\"the address of SOV token.\",\"_cliff\":\"The time interval to the first withdraw in seconds.\",\"_duration\":\"The total duration in seconds.\",\"_feeSharing\":\"The address of fee sharing contract.\",\"_staking\":\"The address of staking contract.\",\"_tokenOwner\":\"The owner of the tokens.\",\"_vestingOwner\":\"The address of an owner of vesting contract.\"},\"return\":\"The vesting contract address.\"},\"isOwner()\":{\"details\":\"Returns true if the caller is the current owner.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"title\":\"Vesting Factory: Contract to deploy vesting contracts of two types: vesting (TokenHolder) and team vesting (Multisig).\"},\"userdoc\":{\"methods\":{\"deployTeamVesting(address,address,address,uint256,uint256,address,address)\":{\"notice\":\"Deploys Team Vesting contract.\"},\"deployVesting(address,address,address,uint256,uint256,address,address)\":{\"notice\":\"Deploys Vesting contract.\"}},\"notice\":\"Factory pattern allows to create multiple instances of the same contract and keep track of them easier.\"}},\"settings\":{\"compilationTarget\":{\"contracts/governance/Vesting/VestingFactory.sol\":\"VestingFactory\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/governance/ApprovalReceiver.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./ErrorDecoder.sol\\\";\\nimport \\\"../token/IApproveAndCall.sol\\\";\\n\\n/**\\n * @title Base contract for receiving approval from SOV token.\\n */\\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\\n modifier onlyThisContract() {\\n // Accepts calls only from receiveApproval function.\\n require(msg.sender == address(this), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _data The data will be used for low level call.\\n */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external {\\n // Accepts calls only from SOV token.\\n require(msg.sender == _getToken(), \\\"unauthorized\\\");\\n require(msg.sender == _token, \\\"unauthorized\\\");\\n\\n // Only allowed methods.\\n bool isAllowed = false;\\n bytes4[] memory selectors = _getSelectors();\\n bytes4 sig = _getSig(_data);\\n for (uint256 i = 0; i < selectors.length; i++) {\\n if (sig == selectors[i]) {\\n isAllowed = true;\\n break;\\n }\\n }\\n require(isAllowed, \\\"method is not allowed\\\");\\n\\n // Check sender and amount.\\n address sender;\\n uint256 amount;\\n (, sender, amount) = abi.decode(\\n abi.encodePacked(bytes28(0), _data),\\n (bytes32, address, uint256)\\n );\\n require(sender == _sender, \\\"sender mismatch\\\");\\n require(amount == _amount, \\\"amount mismatch\\\");\\n\\n _call(_data);\\n }\\n\\n /**\\n * @notice Returns token address, only this address can be a sender for receiveApproval.\\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\\n * @return By default, 0x. When overriden, the token address making the call.\\n */\\n function _getToken() internal view returns (address) {\\n return address(0);\\n }\\n\\n /**\\n * @notice Returns list of function selectors allowed to be invoked.\\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\\n * @return By default, empty array. When overriden, allowed selectors.\\n */\\n function _getSelectors() internal pure returns (bytes4[] memory) {\\n return new bytes4[](0);\\n }\\n\\n /**\\n * @notice Makes call and reverts w/ enhanced error message.\\n * @param _data Error message as bytes.\\n */\\n function _call(bytes memory _data) internal {\\n (bool success, bytes memory returnData) = address(this).call(_data);\\n if (!success) {\\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\\n revert(\\\"receiveApproval: Transaction execution reverted.\\\");\\n } else {\\n revert(_addErrorMessage(\\\"receiveApproval: \\\", string(returnData)));\\n }\\n }\\n }\\n\\n /**\\n * @notice Extracts the called function selector, a hash of the signature.\\n * @dev The first four bytes of the call data for a function call specifies\\n * the function to be called. It is the first (left, high-order in big-endian)\\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\\n * Example:\\n * msg.data:\\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\\n * 000450000000000000000000000000000000000000000000000000000000000000001\\n * selector (or method ID): 0xcdcd77c0\\n * signature: baz(uint32,bool)\\n * @param _data The msg.data from the low level call.\\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\\n */\\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\\n assembly {\\n sig := mload(add(_data, 32))\\n }\\n }\\n}\\n\",\"keccak256\":\"0xfec344456774fa83b0885dd71825ccb6780be8db63c394f3ca09107977c65429\"},\"contracts/governance/ErrorDecoder.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Base contract to properly handle returned data on failed calls\\n * @dev On EVM if the return data length of a call is less than 68,\\n * then the transaction fails silently without a revert message!\\n *\\n * As described in the Solidity documentation\\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\\n * the revert reason is an ABI-encoded string consisting of:\\n * 0x08c379a0 // Function selector (method id) for \\\"Error(string)\\\" signature\\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\\n *\\n * Another example, debug data from test:\\n * 0x08c379a0\\n * 0000000000000000000000000000000000000000000000000000000000000020\\n * 0000000000000000000000000000000000000000000000000000000000000034\\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\\n *\\n * Parsed into:\\n * Data offset: 20\\n * Length: 34\\n * Error message:\\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\\n */\\ncontract ErrorDecoder {\\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\\n\\n /**\\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\\n * @param str1 First string, usually a hardcoded context written by dev.\\n * @param str2 Second string, usually the error message from the reverted call.\\n * @return The concatenated error string\\n */\\n function _addErrorMessage(string memory str1, string memory str2)\\n internal\\n pure\\n returns (string memory)\\n {\\n bytes memory bytesStr1 = bytes(str1);\\n bytes memory bytesStr2 = bytes(str2);\\n string memory str12 =\\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\\n bytes memory bytesStr12 = bytes(str12);\\n uint256 j = 0;\\n for (uint256 i = 0; i < bytesStr1.length; i++) {\\n bytesStr12[j++] = bytesStr1[i];\\n }\\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\\n bytesStr12[j++] = bytesStr2[i];\\n }\\n return string(bytesStr12);\\n }\\n}\\n\",\"keccak256\":\"0xa0fa7986924aab574ca9e7c265f8c7bf00671ba1d86dbad143df7c14455f1c6a\"},\"contracts/governance/IFeeSharingCollector.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n * */\\ninterface IFeeSharingCollector {\\n function withdrawFees(address[] calldata _token) external;\\n\\n function transferTokens(address _token, uint96 _amount) external;\\n\\n function withdraw(\\n address _loanPoolToken,\\n uint32 _maxCheckpoints,\\n address _receiver\\n ) external;\\n}\\n\",\"keccak256\":\"0x7794cb434d9395ea983dcf8ded48db5b68897a338429320f60172c4caa47fb40\"},\"contracts/governance/Staking/interfaces/IStaking.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\npragma experimental ABIEncoderV2;\\n\\n/**\\n * @title Interface for Staking modules governance/Staking/modules\\n */\\n\\ninterface IStaking {\\n /*************************** StakingAdminModule ***************************/\\n\\n /**\\n * @notice Add account to Admins ACL.\\n * @param _admin The addresses of the account to grant permissions.\\n * */\\n function addAdmin(address _admin) external;\\n\\n /**\\n * @notice Remove account from Admins ACL.\\n * @param _admin The addresses of the account to revoke permissions.\\n * */\\n function removeAdmin(address _admin) external;\\n\\n /**\\n * @notice Add account to pausers ACL.\\n * @param _pauser The address to grant pauser permissions.\\n * */\\n function addPauser(address _pauser) external;\\n\\n /**\\n * @notice Remove account from pausers ACL.\\n * @param _pauser The address to grant pauser permissions.\\n * */\\n function removePauser(address _pauser) external;\\n\\n /**\\n * @notice Pause/unpause contract\\n * @param _pause true when pausing, false when unpausing\\n * */\\n function pauseUnpause(bool _pause) external;\\n\\n /**\\n * @notice Freeze contract - disable all functions\\n * @param _freeze true when freezing, false when unfreezing\\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\\n * */\\n function freezeUnfreeze(bool _freeze) external;\\n\\n /**\\n * @notice Allows the owner to set a fee sharing proxy contract.\\n * We need it for unstaking with slashing.\\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\\n * */\\n function setFeeSharing(address _feeSharing) external;\\n\\n /**\\n * @notice Allow the owner to set weight scaling.\\n * We need it for unstaking with slashing.\\n * @param _weightScaling The weight scaling.\\n * */\\n function setWeightScaling(uint96 _weightScaling) external;\\n\\n /**\\n * @notice Allow the owner to set a new staking contract.\\n * As a consequence it allows the stakers to migrate their positions\\n * to the new contract.\\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\\n * is not implemented.\\n * @param _newStakingContract The address of the new staking contract.\\n * */\\n function setNewStakingContract(address _newStakingContract) external;\\n\\n /**\\n * @notice Allow a staker to migrate his positions to the new staking contract.\\n * @dev Staking contract needs to be set before by the owner.\\n * Currently not implemented, just needed for the interface.\\n * In case it's needed at some point in the future,\\n * the implementation needs to be changed first.\\n * */\\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\\n\\n /*************************** StakingGovernanceModule ***************************/\\n\\n /**\\n * @notice Compute the total voting power at a given time.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @param time The timestamp for which to calculate the total voting power.\\n * @return The total voting power at the given time.\\n * */\\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Get the current votes balance for a user account.\\n * @param account The address to get votes balance.\\n * @dev This is a wrapper to simplify arguments. The actual computation is\\n * performed on WeightedStaking parent contract.\\n * @return The number of current votes for a user account.\\n * */\\n function getCurrentVotes(address account) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of votes for a delegatee as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will revert\\n * to prevent misinformation.\\n * Used for Voting, not for fee sharing.\\n * @param account The address of the account to check.\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The staking date to compute the power for.\\n * @return The number of votes the delegatee had as of the given block.\\n * */\\n function getPriorVotes(\\n address account,\\n uint256 blockNumber,\\n uint256 date\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of stake for an account as of a block number.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * @param account The address of the account to check.\\n * @param date The staking date to compute the power for.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorStakeByDateForDelegatee(\\n address account,\\n uint256 date,\\n uint256 blockNumber\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\\n * be internal instead of a public function.\\n * @param date The date to check the stakes for.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\\n * @param delegatee The address to delegate votes to.\\n * @param lockDate the date if the position to delegate.\\n * */\\n function delegate(address delegatee, uint256 lockDate) external;\\n\\n /*************************** StakingStakeModule ***************************/\\n\\n event TokensStaked(\\n address indexed staker,\\n uint256 amount,\\n uint256 lockedUntil,\\n uint256 totalStaked\\n );\\n\\n /**\\n * @notice Stake the given amount for the given duration of time.\\n * @param amount The number of tokens to stake.\\n * @param until Timestamp indicating the date until which to stake.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stake(\\n uint96 amount,\\n uint256 until,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Stake the given amount for the given duration of time.\\n * @dev This function will be invoked from receiveApproval\\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\\n * @param sender The sender of SOV.approveAndCall\\n * @param amount The number of tokens to stake.\\n * @param until Timestamp indicating the date until which to stake.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stakeWithApproval(\\n address sender,\\n uint96 amount,\\n uint256 until,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _data The data will be used for low level call.\\n */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @notice Extend the staking duration until the specified date.\\n * @param previousLock The old unlocking timestamp.\\n * @param until The new unlocking timestamp in seconds.\\n * */\\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\\n\\n /**\\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\\n * */\\n function stakesBySchedule(\\n uint256 amount,\\n uint256 cliff,\\n uint256 duration,\\n uint256 intervalLength,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Stake tokens according to the vesting schedule.\\n * @param amount The amount of tokens to stake.\\n * @param cliff The time interval to the first withdraw.\\n * @param duration The staking duration.\\n * @param intervalLength The length of each staking interval when cliff passed.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stakeBySchedule(\\n uint256 amount,\\n uint256 cliff,\\n uint256 duration,\\n uint256 intervalLength,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Get the number of staked tokens held by the user account.\\n * @dev Iterate checkpoints adding up stakes.\\n * @param account The address of the account to get the balance of.\\n * @return The number of tokens held.\\n * */\\n function balanceOf(address account) external view returns (uint96 balance);\\n\\n /**\\n * @notice Get the current number of tokens staked for a day.\\n * @param lockedTS The timestamp to get the staked tokens for.\\n * */\\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\\n\\n /**\\n * @notice Get list of stakes for a user account.\\n * @param account The address to get stakes.\\n * @return The arrays of dates and stakes.\\n * */\\n function getStakes(address account)\\n external\\n view\\n returns (uint256[] memory dates, uint96[] memory stakes);\\n\\n /**\\n * @notice Unstaking is possible every 2 weeks only. This means, to\\n * calculate the key value for the staking checkpoints, we need to\\n * map the intended timestamp to the closest available date.\\n * @param timestamp The unlocking timestamp.\\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\\n * */\\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\\n\\n /*************************** StakingStorageModule ***************************/\\n\\n /// @notice The maximum duration to stake tokens\\n /// @return MAX_DURATION to stake tokens\\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\\n\\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\\n /// @return uint256(MAX_VOTING_WEIGHT);\\n function getStorageMaxVotingWeight() external pure returns (uint256);\\n\\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\\n /// @return uint256(WEIGHT_FACTOR);\\n function getStorageWeightFactor() external pure returns (uint256);\\n\\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\\n function getStorageDefaultWeightScaling() external pure returns (uint256);\\n\\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\\n function getStorageRangeForWeightScaling()\\n external\\n pure\\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\\n\\n /// @notice The EIP-712 typehash for the contract's domain.\\n /// @return uint256(DOMAIN_TYPEHASH);\\n function getStorageDomainTypehash() external pure returns (uint256);\\n\\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\\n /// @return uint256(DELEGATION_TYPEHASH);\\n function getStorageDelegationTypehash() external pure returns (uint256);\\n\\n /// @return name;\\n function getStorageName() external view returns (string memory);\\n\\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\\n\\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\\n function kickoffTS() external view returns (uint256);\\n\\n /// @notice The token to be staked\\n function SOVToken() external view returns (address);\\n\\n /// @notice Stakers delegated voting power\\n /// @param staker - the delegating address\\n /// @param until - delegated voting\\n /// @return _delegate - voting power delegated to address\\n function delegates(address staker, uint256 until) external view returns (address _delegate);\\n\\n /// @notice If this flag is set to true, all tokens are unlocked immediately\\n /// see function unlockAllTokens() for details\\n function allUnlocked() external view returns (bool);\\n\\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\\n function newStakingContract() external view returns (address);\\n\\n /// CHECKPOINTS\\n struct Checkpoint {\\n uint32 fromBlock;\\n uint96 stake;\\n }\\n\\n /// @notice A record of tokens to be unstaked at a given time in total.\\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\\n function totalStakingCheckpoints(uint256 date, uint32 index)\\n external\\n view\\n returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date.\\n /// @dev numTotalStakingCheckpoints[date] is a number.\\n function numTotalStakingCheckpoints(uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\\n function delegateStakingCheckpoints(\\n address delagatee,\\n uint256 date,\\n uint32 index\\n ) external view returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date per delegate.\\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\\n function userStakingCheckpoints(\\n address user,\\n uint256 date,\\n uint32 index\\n ) external view returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date per user.\\n /// @dev numUserStakingCheckpoints[user][date] is a number\\n function numUserStakingCheckpoints(address user, uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of states for signing / validating signatures\\n /// @dev nonces[user] is a number.\\n function nonces(address user) external view returns (uint256 nonce);\\n\\n /// SLASHING ///\\n\\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\\n function feeSharing() external view returns (address);\\n\\n /// @notice used for weight scaling when unstaking with slashing.\\n /// @return uint96 DEFAULT_WEIGHT_SCALING\\n function weightScaling() external view returns (uint96);\\n\\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\\n /// @dev vestingWhitelist[contract] is true/false.\\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\\n\\n /// @dev user => flag whether user has admin role.\\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\\n /// \\tthis function works only with Team Vesting contracts\\n function admins(address isAdmin) external view returns (bool);\\n\\n /// @dev vesting contract code hash => flag whether it's registered code hash\\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\\n\\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\\n function vestingCheckpoints(uint256 date, uint32 index)\\n external\\n view\\n returns (Checkpoint memory);\\n\\n /// @notice The number of total vesting checkpoints for each date.\\n /// @dev numVestingCheckpoints[date] is a number.\\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\\n\\n ///@notice vesting registry contract PROXY address\\n function vestingRegistryLogic() external view returns (address);\\n\\n /// @dev user => flag whether user has pauser role.\\n function pausers(address isPauser) external view returns (bool);\\n\\n /// @dev Staking contract is paused\\n function paused() external view returns (bool);\\n\\n /// @dev Staking contract is frozen\\n function frozen() external view returns (bool);\\n\\n /*************************** StakingVestingModule ***************************/\\n\\n event VestingStakeSet(uint256 lockedTS, uint96 value);\\n\\n /**\\n * @notice Return flag whether the given address is a registered vesting contract.\\n * @param stakerAddress the address to check\\n */\\n function isVestingContract(address stakerAddress) external view returns (bool);\\n\\n /**\\n * @notice Remove vesting contract's code hash to a map of code hashes.\\n * @param vesting The address of Vesting contract.\\n * @dev We need it to use isVestingContract() function instead of isContract()\\n */\\n function removeContractCodeHash(address vesting) external;\\n\\n /**\\n * @notice Add vesting contract's code hash to a map of code hashes.\\n * @param vesting The address of Vesting contract.\\n * @dev We need it to use isVestingContract() function instead of isContract()\\n */\\n function addContractCodeHash(address vesting) external;\\n\\n /**\\n * @notice Determine the prior number of vested stake for an account until a\\n * certain lock date as of a block number.\\n * @dev Block number must be a finalized block or else this function\\n * will revert to prevent misinformation.\\n * @param date The lock date.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Compute the voting power for a specific date.\\n * Power = stake * weight\\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\\n * @param startDate The date for which we need to know the power of the stake.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @return The stacking power.\\n * */\\n function weightedVestingStakeByDate(\\n uint256 date,\\n uint256 startDate,\\n uint256 blockNumber\\n ) external view returns (uint96 power);\\n\\n /**\\n * @notice Determine the prior weighted vested amount for an account as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * Used for fee sharing, not voting.\\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \\\"votes\\\"\\n * to add up token stake, and that could be misleading.\\n *\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The staking date to compute the power for.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\\n external\\n view\\n returns (uint96 votes);\\n\\n /**\\n * @notice Determine the prior number of stake for an account until a\\n * certain lock date as of a block number.\\n * @dev Block number must be a finalized block or else this function\\n * will revert to prevent misinformation.\\n * @param account The address of the account to check.\\n * @param date The lock date.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorUserStakeByDate(\\n address account,\\n uint256 date,\\n uint256 blockNumber\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\\n * @param lockedDates The arrays of lock dates.\\n * @param values The array of values to add to the staked balance.\\n */\\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\\n\\n /**\\n * @notice sets vesting registry\\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\\n * various other functionalities without the necessity of linking it with Vesting Registry\\n */\\n function setVestingRegistry(address _vestingRegistryProxy) external;\\n\\n /*************************** StakingWithdrawModule ***************************/\\n\\n /**\\n * @notice Withdraw the given amount of tokens if they are unlocked.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * */\\n function withdraw(\\n uint96 amount,\\n uint256 until,\\n address receiver\\n ) external;\\n\\n /**\\n * @notice Withdraw the given amount of tokens.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\\n * */\\n function governanceWithdraw(\\n uint96 amount,\\n uint256 until,\\n address receiver\\n ) external;\\n\\n /**\\n * @notice Withdraw tokens for vesting contract.\\n * @param vesting The address of Vesting contract.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\\n * */\\n function governanceWithdrawVesting(address vesting, address receiver) external;\\n\\n /**\\n * @notice Get available and punished amount for withdrawing.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * */\\n function getWithdrawAmounts(uint96 amount, uint256 until)\\n external\\n view\\n returns (uint96, uint96);\\n\\n /**\\n * @notice Allow the owner to unlock all tokens in case the staking contract\\n * is going to be replaced\\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\\n * The owner should not be able to just quickly unlock to withdraw his own\\n * tokens and lock again.\\n * @dev Last resort.\\n * */\\n function unlockAllTokens() external;\\n\\n /*************************** WeightedStakingModule ***************************/\\n\\n /**\\n * @notice Determine the prior weighted stake for an account as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * Used for fee sharing, not voting.\\n *\\n * @param account The address of the account to check.\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The date/timestamp of the unstaking time.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function getPriorWeightedStake(\\n address account,\\n uint256 blockNumber,\\n uint256 date\\n ) external view returns (uint96 priorWeightedStake);\\n\\n /**\\n * @notice Compute the voting power for a specific date.\\n * Power = stake * weight\\n * TODO: WeightedStaking::weightedStakeByDate should probably better\\n * be internal instead of a public function.\\n * @param account The user address.\\n * @param date The staking date to compute the power for.\\n * @param startDate The date for which we need to know the power of the stake.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @return The stacking power.\\n * */\\n function weightedStakeByDate(\\n address account,\\n uint256 date,\\n uint256 startDate,\\n uint256 blockNumber\\n ) external view returns (uint96 power);\\n\\n /**\\n * @notice Compute the weight for a specific date.\\n * @param date The unlocking date.\\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function computeWeightByDate(uint256 date, uint256 startDate)\\n external\\n pure\\n returns (uint96 weight);\\n\\n /**\\n * @notice Returns public constant MAX_DURATION\\n * preserved for backwards compatibility\\n * Use getStorageMaxDurationToStakeTokens()\\n * @return uint96 MAX_DURATION for staking\\n **/\\n function MAX_DURATION() external view returns (uint256);\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() external view returns (address);\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() external view returns (bool);\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) external;\\n\\n /**\\n * @notice Governance withdraw vesting directly through staking contract.\\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\\n * This function only allows cancelling vesting contract of the TeamVesting type.\\n *\\n * @param vesting The vesting address.\\n * @param receiver The receiving address.\\n * @param startFrom The start value for the iterations.\\n */\\n function cancelTeamVesting(\\n address vesting,\\n address receiver,\\n uint256 startFrom\\n ) external;\\n\\n /**\\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\\n *\\n * @return max iteration value.\\n */\\n function getMaxVestingWithdrawIterations() external view returns (uint256);\\n\\n /**\\n * @dev set max withdraw iterations.\\n *\\n * @param maxIterations new max iterations value.\\n */\\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\\n}\\n\",\"keccak256\":\"0x720bd2cc1042cb4abc2bd3a6839131638eafd3d224571ad9ac21cae36625ec2e\"},\"contracts/governance/Vesting/IVesting.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for Vesting contract.\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n * This interface is used by VestingLogic contract to implement stakeTokens function\\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\\n * at a vesting instance.\\n */\\ninterface IVesting {\\n function duration() external returns (uint256);\\n\\n function endDate() external returns (uint256);\\n\\n function stakeTokens(uint256 amount) external;\\n\\n function tokenOwner() external view returns (address);\\n}\\n\",\"keccak256\":\"0x3482a1e27402655f85f5ff2cb06e0876e9bb94e1a63446a09e33babd60274b4b\"},\"contracts/governance/Vesting/IVestingFactory.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for Vesting Factory contract.\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n * This interface is used by VestingFactory contract to override empty\\n * implemention of deployVesting and deployTeamVesting functions\\n * and on VestingRegistry contract to use an instance of VestingFactory.\\n */\\ninterface IVestingFactory {\\n function deployVesting(\\n address _SOV,\\n address _staking,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharing,\\n address _owner\\n ) external returns (address);\\n\\n function deployTeamVesting(\\n address _SOV,\\n address _staking,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharing,\\n address _owner\\n ) external returns (address);\\n}\\n\",\"keccak256\":\"0xc77e276b71ec23ca6d4eead9a842bc01cc37bcfe55a88528190f1f6106773175\"},\"contracts/governance/Vesting/TeamVesting.sol\":{\"content\":\"pragma solidity ^0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../openzeppelin/Ownable.sol\\\";\\nimport \\\"../../interfaces/IERC20.sol\\\";\\n//import \\\"../Staking/interfaces/IStaking.sol\\\";\\nimport \\\"../IFeeSharingCollector.sol\\\";\\nimport \\\"./IVesting.sol\\\";\\nimport \\\"../ApprovalReceiver.sol\\\";\\nimport \\\"./VestingStorage.sol\\\";\\nimport \\\"../../proxy/Proxy.sol\\\";\\n\\n/**\\n * @title Team Vesting Contract.\\n *\\n * @notice A regular vesting contract, but the owner (governance) is able to\\n * withdraw earlier without a slashing.\\n *\\n * @dev Vesting contracts shouldn't be upgradable,\\n * use Proxy instead of UpgradableProxy.\\n * */\\ncontract TeamVesting is VestingStorage, Proxy {\\n /**\\n * @notice Setup the vesting schedule.\\n * @param _logic The address of logic contract.\\n * @param _SOV The SOV token address.\\n * @param _tokenOwner The owner of the tokens.\\n * @param _cliff The time interval to the first withdraw in seconds.\\n * @param _duration The total duration in seconds.\\n * */\\n constructor(\\n address _logic,\\n address _SOV,\\n address _stakingAddress,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharingCollector\\n ) public {\\n require(_SOV != address(0), \\\"SOV address invalid\\\");\\n require(_stakingAddress != address(0), \\\"staking address invalid\\\");\\n require(_tokenOwner != address(0), \\\"token owner address invalid\\\");\\n require(_duration >= _cliff, \\\"duration must be bigger than or equal to the cliff\\\");\\n require(_feeSharingCollector != address(0), \\\"feeSharingCollector address invalid\\\");\\n\\n _setImplementation(_logic);\\n SOV = IERC20(_SOV);\\n staking = IStaking(_stakingAddress);\\n require(_duration <= staking.MAX_DURATION(), \\\"duration may not exceed the max duration\\\");\\n tokenOwner = _tokenOwner;\\n cliff = _cliff;\\n duration = _duration;\\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\\n }\\n}\\n\",\"keccak256\":\"0xba6c95ae79e37dc20ba1c67a48ec227f7b3c210078763b5e8ad20c8b3db0b645\"},\"contracts/governance/Vesting/Vesting.sol\":{\"content\":\"pragma solidity ^0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./TeamVesting.sol\\\";\\n\\n/**\\n * @title Vesting Contract.\\n * @notice Team tokens and investor tokens are vested. Therefore, a smart\\n * contract needs to be developed to enforce the vesting schedule.\\n *\\n * */\\ncontract Vesting is TeamVesting {\\n /**\\n * @notice Setup the vesting schedule.\\n * @param _logic The address of logic contract.\\n * @param _SOV The SOV token address.\\n * @param _tokenOwner The owner of the tokens.\\n * @param _cliff The time interval to the first withdraw in seconds.\\n * @param _duration The total duration in seconds.\\n * */\\n constructor(\\n address _logic,\\n address _SOV,\\n address _stakingAddress,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharingCollectorProxy\\n )\\n public\\n TeamVesting(\\n _logic,\\n _SOV,\\n _stakingAddress,\\n _tokenOwner,\\n _cliff,\\n _duration,\\n _feeSharingCollectorProxy\\n )\\n {}\\n\\n /**\\n * @dev We need to add this implementation to prevent proxy call VestingLogic.governanceWithdrawTokens\\n * @param receiver The receiver of the token withdrawal.\\n * */\\n function governanceWithdrawTokens(address receiver) public {\\n revert(\\\"operation not supported\\\");\\n }\\n}\\n\",\"keccak256\":\"0xa042b910acc3bec9c75213160bc5257c3acade8ce56b4dd0777caab903d0ab23\"},\"contracts/governance/Vesting/VestingFactory.sol\":{\"content\":\"pragma solidity ^0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../openzeppelin/Ownable.sol\\\";\\nimport \\\"./Vesting.sol\\\";\\nimport \\\"./TeamVesting.sol\\\";\\nimport \\\"./IVestingFactory.sol\\\";\\n\\n/**\\n * @title Vesting Factory: Contract to deploy vesting contracts\\n * of two types: vesting (TokenHolder) and team vesting (Multisig).\\n * @notice Factory pattern allows to create multiple instances\\n * of the same contract and keep track of them easier.\\n * */\\ncontract VestingFactory is IVestingFactory, Ownable {\\n address public vestingLogic;\\n\\n constructor(address _vestingLogic) public {\\n require(_vestingLogic != address(0), \\\"invalid vesting logic address\\\");\\n vestingLogic = _vestingLogic;\\n }\\n\\n /**\\n * @notice Deploys Vesting contract.\\n * @param _SOV the address of SOV token.\\n * @param _staking The address of staking contract.\\n * @param _tokenOwner The owner of the tokens.\\n * @param _cliff The time interval to the first withdraw in seconds.\\n * @param _duration The total duration in seconds.\\n * @param _feeSharing The address of fee sharing contract.\\n * @param _vestingOwner The address of an owner of vesting contract.\\n * @return The vesting contract address.\\n * */\\n function deployVesting(\\n address _SOV,\\n address _staking,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharing,\\n address _vestingOwner\\n )\\n external\\n onlyOwner /// @dev owner - VestingRegistry\\n returns (address)\\n {\\n address vesting =\\n address(\\n new Vesting(\\n vestingLogic,\\n _SOV,\\n _staking,\\n _tokenOwner,\\n _cliff,\\n _duration,\\n _feeSharing\\n )\\n );\\n Ownable(vesting).transferOwnership(_vestingOwner);\\n return vesting;\\n }\\n\\n /**\\n * @notice Deploys Team Vesting contract.\\n * @param _SOV The address of SOV token.\\n * @param _staking The address of staking contract.\\n * @param _tokenOwner The owner of the tokens.\\n * @param _cliff The time interval to the first withdraw in seconds.\\n * @param _duration The total duration in seconds.\\n * @param _feeSharing The address of fee sharing contract.\\n * @param _vestingOwner The address of an owner of vesting contract.\\n * @return The vesting contract address.\\n * */\\n function deployTeamVesting(\\n address _SOV,\\n address _staking,\\n address _tokenOwner,\\n uint256 _cliff,\\n uint256 _duration,\\n address _feeSharing,\\n address _vestingOwner\\n )\\n external\\n onlyOwner //owner - VestingRegistry\\n returns (address)\\n {\\n address vesting =\\n address(\\n new TeamVesting(\\n vestingLogic,\\n _SOV,\\n _staking,\\n _tokenOwner,\\n _cliff,\\n _duration,\\n _feeSharing\\n )\\n );\\n Ownable(vesting).transferOwnership(_vestingOwner);\\n return vesting;\\n }\\n}\\n\",\"keccak256\":\"0x50ea6d6fc9ab0522c442bbf14be6a7fd0808fd96141d2d198c818b300e04298c\"},\"contracts/governance/Vesting/VestingStorage.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"../../openzeppelin/Ownable.sol\\\";\\nimport \\\"../../interfaces/IERC20.sol\\\";\\nimport \\\"../Staking/interfaces/IStaking.sol\\\";\\nimport \\\"../IFeeSharingCollector.sol\\\";\\n\\n/**\\n * @title Vesting Storage Contract.\\n *\\n * @notice This contract is just the storage required for vesting.\\n * It is parent of VestingLogic and TeamVesting.\\n *\\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\\n * */\\ncontract VestingStorage is Ownable {\\n /// @notice The SOV token contract.\\n IERC20 public SOV;\\n\\n /// @notice The staking contract address.\\n IStaking public staking;\\n\\n /// @notice The owner of the vested tokens.\\n address public tokenOwner;\\n\\n /// @notice Fee sharing Proxy.\\n IFeeSharingCollector public feeSharingCollector;\\n\\n /// @notice The cliff. After this time period the tokens begin to unlock.\\n uint256 public cliff;\\n\\n /// @notice The duration. After this period all tokens will have been unlocked.\\n uint256 public duration;\\n\\n /// @notice The start date of the vesting.\\n uint256 public startDate;\\n\\n /// @notice The end date of the vesting.\\n uint256 public endDate;\\n\\n /// @notice Constant used for computing the vesting dates.\\n uint256 constant FOUR_WEEKS = 4 weeks;\\n}\\n\",\"keccak256\":\"0xf70f579d357d8f0aa0839824c1a1d66713c3cd42a58118d2893a35b52baaa140\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/proxy/Proxy.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Base Proxy contract.\\n * @notice The proxy performs delegated calls to the contract implementation\\n * it is pointing to. This way upgradable contracts are possible on blockchain.\\n *\\n * Delegating proxy contracts are widely used for both upgradeability and gas\\n * savings. These proxies rely on a logic contract (also known as implementation\\n * contract or master copy) that is called using delegatecall. This allows\\n * proxies to keep a persistent state (storage and balance) while the code is\\n * delegated to the logic contract.\\n *\\n * Proxy contract is meant to be inherited and its internal functions\\n * _setImplementation and _setProxyOwner to be called when upgrades become\\n * neccessary.\\n *\\n * The loan token (iToken) contract as well as the protocol contract act as\\n * proxies, delegating all calls to underlying contracts. Therefore, if you\\n * want to interact with them using web3, you need to use the ABIs from the\\n * contracts containing the actual logic or the interface contract.\\n * ABI for LoanToken contracts: LoanTokenLogicStandard\\n * ABI for Protocol contract: ISovryn\\n *\\n * @dev UpgradableProxy is the contract that inherits Proxy and wraps these\\n * functions.\\n * */\\ncontract Proxy {\\n bytes32 private constant KEY_IMPLEMENTATION = keccak256(\\\"key.implementation\\\");\\n bytes32 private constant KEY_OWNER = keccak256(\\\"key.proxy.owner\\\");\\n\\n event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);\\n event ImplementationChanged(\\n address indexed _oldImplementation,\\n address indexed _newImplementation\\n );\\n\\n /**\\n * @notice Set sender as an owner.\\n * */\\n constructor() public {\\n _setProxyOwner(msg.sender);\\n }\\n\\n /**\\n * @notice Throw error if called not by an owner.\\n * */\\n modifier onlyProxyOwner() {\\n require(msg.sender == getProxyOwner(), \\\"Proxy:: access denied\\\");\\n _;\\n }\\n\\n /**\\n * @notice Set address of the implementation.\\n * @param _implementation Address of the implementation.\\n * */\\n function _setImplementation(address _implementation) internal {\\n require(_implementation != address(0), \\\"Proxy::setImplementation: invalid address\\\");\\n emit ImplementationChanged(getImplementation(), _implementation);\\n\\n bytes32 key = KEY_IMPLEMENTATION;\\n assembly {\\n sstore(key, _implementation)\\n }\\n }\\n\\n /**\\n * @notice Return address of the implementation.\\n * @return Address of the implementation.\\n * */\\n function getImplementation() public view returns (address _implementation) {\\n bytes32 key = KEY_IMPLEMENTATION;\\n assembly {\\n _implementation := sload(key)\\n }\\n }\\n\\n /**\\n * @notice Set address of the owner.\\n * @param _owner Address of the owner.\\n * */\\n function _setProxyOwner(address _owner) internal {\\n require(_owner != address(0), \\\"Proxy::setProxyOwner: invalid address\\\");\\n emit OwnershipTransferred(getProxyOwner(), _owner);\\n\\n bytes32 key = KEY_OWNER;\\n assembly {\\n sstore(key, _owner)\\n }\\n }\\n\\n /**\\n * @notice Return address of the owner.\\n * @return Address of the owner.\\n * */\\n function getProxyOwner() public view returns (address _owner) {\\n bytes32 key = KEY_OWNER;\\n assembly {\\n _owner := sload(key)\\n }\\n }\\n\\n /**\\n * @notice Fallback function performs a delegate call\\n * to the actual implementation address is pointing this proxy.\\n * Returns whatever the implementation call returns.\\n * */\\n function() external payable {\\n address implementation = getImplementation();\\n require(implementation != address(0), \\\"Proxy::(): implementation not found\\\");\\n\\n assembly {\\n let pointer := mload(0x40)\\n calldatacopy(pointer, 0, calldatasize)\\n let result := delegatecall(gas, implementation, pointer, calldatasize, 0, 0)\\n let size := returndatasize\\n returndatacopy(pointer, 0, size)\\n\\n switch result\\n case 0 {\\n revert(pointer, size)\\n }\\n default {\\n return(pointer, size)\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x8574814d1ea5b04efc8ef1e629e04e5783d4c106ff73a47c72e279c027a6a403\"},\"contracts/token/IApproveAndCall.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for contract governance/ApprovalReceiver.sol\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n */\\ninterface IApproveAndCall {\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _sender The sender of SOV.approveAndCall function.\\n * @param _amount The amount was approved.\\n * @param _token The address of token.\\n * @param _data The data will be used for low level call.\\n * */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x0ca93f8436a4d81d80de5ea9214139b490d96f708f09c975a0869ce9abc61635\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5060405161264338038061264383398101604081905261002f916100f5565b60006100426001600160e01b036100e016565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b0381166100bb5760405162461bcd60e51b81526004016100b290610154565b60405180910390fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055610195565b3390565b80516100ef8161017e565b92915050565b60006020828403121561010757600080fd5b600061011384846100e4565b949350505050565b6000610128601d83610164565b7f696e76616c69642076657374696e67206c6f6769632061646472657373000000815260200192915050565b602080825281016100ef8161011b565b90815260200190565b60006001600160a01b0382166100ef565b6101878161016d565b811461019257600080fd5b50565b61249f806101a46000396000f3fe60806040523480156200001157600080fd5b50600436106200006a5760003560e01c8063546344f0146200006f5780638da5cb5b146200009e5780638f32d59b14620000a8578063c0cad24e14620000c1578063f2fde38b14620000cb578063fa5f771e14620000e4575b600080fd5b6200008662000080366004620003bc565b620000fb565b60405162000095919062000502565b60405180910390f35b62000086620001fd565b620000b26200020c565b60405162000095919062000588565b6200008662000232565b620000e2620000dc36600462000393565b62000241565b005b62000086620000f5366004620003bc565b62000278565b6000620001076200020c565b6200012f5760405162461bcd60e51b81526004016200012690620005aa565b60405180910390fd5b6000600160009054906101000a90046001600160a01b03168989898989896040516200015b9062000357565b6200016d979695949392919062000512565b604051809103906000f0801580156200018a573d6000803e3d6000fd5b5060405163f2fde38b60e01b81529091506001600160a01b0382169063f2fde38b90620001bc90869060040162000502565b600060405180830381600087803b158015620001d757600080fd5b505af1158015620001ec573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6000546001600160a01b031690565b600080546001600160a01b031662000223620002cf565b6001600160a01b031614905090565b6001546001600160a01b031681565b6200024b6200020c565b6200026a5760405162461bcd60e51b81526004016200012690620005aa565b6200027581620002d3565b50565b6000620002846200020c565b620002a35760405162461bcd60e51b81526004016200012690620005aa565b6000600160009054906101000a90046001600160a01b03168989898989896040516200015b9062000365565b3390565b6001600160a01b038116620002fc5760405162461bcd60e51b8152600401620001269062000598565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b610ed5806200060983390190565b610f7f80620014de83390190565b80356200038081620005e6565b92915050565b80356200038081620005fd565b600060208284031215620003a657600080fd5b6000620003b4848462000373565b949350505050565b600080600080600080600060e0888a031215620003d857600080fd5b6000620003e68a8a62000373565b9750506020620003f98a828b0162000373565b96505060406200040c8a828b0162000373565b95505060606200041f8a828b0162000386565b9450506080620004328a828b0162000386565b93505060a0620004458a828b0162000373565b92505060c0620004588a828b0162000373565b91505092959891949750929550565b6200047281620005c5565b82525050565b6200047281620005d2565b600062000492602683620005bc565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000620004dc600c83620005bc565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6200047281620005e3565b6020810162000380828462000467565b60e0810162000522828a62000467565b62000531602083018962000467565b62000540604083018862000467565b6200054f606083018762000467565b6200055e6080830186620004f7565b6200056d60a0830185620004f7565b6200057c60c083018462000467565b98975050505050505050565b6020810162000380828462000478565b60208082528101620003808162000483565b602080825281016200038081620004cd565b90815260200190565b60006200038082620005d7565b151590565b6001600160a01b031690565b90565b620005f181620005c5565b81146200027557600080fd5b620005f181620005e356fe60806040523480156200001157600080fd5b5060405162000ed538038062000ed58339810160408190526200003491620003ef565b6000620000496001600160e01b036200028416565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062000eb5833981519152908290a35062000096336001600160e01b036200028816565b6001600160a01b038616620000c85760405162461bcd60e51b8152600401620000bf90620007e8565b60405180910390fd5b6001600160a01b038516620000f15760405162461bcd60e51b8152600401620000bf90620007d6565b6001600160a01b0384166200011a5760405162461bcd60e51b8152600401620000bf906200078e565b828210156200013d5760405162461bcd60e51b8152600401620000bf906200077c565b6001600160a01b038116620001665760405162461bcd60e51b8152600401620000bf90620007b2565b6200017a876001600160e01b036200031216565b600180546001600160a01b038089166001600160a01b0319928316179092556002805488841692169190911790819055604080516358b925a360e11b81529051919092169163b1724b46916004808301926020929190829003018186803b158015620001e557600080fd5b505afa158015620001fa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200022091908101906200049a565b821115620002425760405162461bcd60e51b8152600401620000bf906200076a565b600380546001600160a01b039586166001600160a01b031991821617909155600593909355600691909155600480549190931691161790555062000842915050565b3390565b6001600160a01b038116620002b15760405162461bcd60e51b8152600401620000bf90620007c4565b6001600160a01b038116620002ce6001600160e01b036200039d16565b6001600160a01b031660008051602062000eb583398151915260405160405180910390a3600060405162000302906200075d565b6040519081900390209190915550565b6001600160a01b0381166200033b5760405162461bcd60e51b8152600401620000bf90620007a0565b6001600160a01b038116620003586001600160e01b03620003be16565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a36000604051620003029062000750565b600080604051620003ae906200075d565b6040519081900390205492915050565b600080604051620003ae9062000750565b8051620003dc816200081d565b92915050565b8051620003dc8162000837565b600080600080600080600060e0888a0312156200040b57600080fd5b6000620004198a8a620003cf565b97505060206200042c8a828b01620003cf565b96505060406200043f8a828b01620003cf565b9550506060620004528a828b01620003cf565b9450506080620004658a828b01620003e2565b93505060a0620004788a828b01620003e2565b92505060c06200048b8a828b01620003cf565b91505092959891949750929550565b600060208284031215620004ad57600080fd5b6000620004bb8484620003e2565b949350505050565b6000620004d2602883620007fa565b7f6475726174696f6e206d6179206e6f742065786365656420746865206d617820815267323ab930ba34b7b760c11b602082015260400192915050565b60006200051e603283620007fa565b7f6475726174696f6e206d75737420626520626967676572207468616e206f722081527132b8bab0b6103a37903a34329031b634b33360711b602082015260400192915050565b600062000574601b83620007fa565b7f746f6b656e206f776e6572206164647265737320696e76616c69640000000000815260200192915050565b6000620005af602983620007fa565b7f50726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6981526864206164647265737360b81b602082015260400192915050565b6000620005fc60128362000803565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006200062c602383620007fa565b7f66656553686172696e67436f6c6c6563746f72206164647265737320696e76618152621b1a5960ea1b602082015260400192915050565b600062000673600f8362000803565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000620006a0602583620007fa565b7f50726f78793a3a73657450726f78794f776e65723a20696e76616c6964206164815264647265737360d81b602082015260400192915050565b6000620006e9601783620007fa565b7f7374616b696e67206164647265737320696e76616c6964000000000000000000815260200192915050565b600062000724601383620007fa565b7f534f56206164647265737320696e76616c696400000000000000000000000000815260200192915050565b6000620003dc82620005ed565b6000620003dc8262000664565b60208082528101620003dc81620004c3565b60208082528101620003dc816200050f565b60208082528101620003dc8162000565565b60208082528101620003dc81620005a0565b60208082528101620003dc816200061d565b60208082528101620003dc8162000691565b60208082528101620003dc81620006da565b60208082528101620003dc8162000715565b90815260200190565b919050565b60006001600160a01b038216620003dc565b90565b620008288162000808565b81146200083457600080fd5b50565b62000828816200081a565b61066380620008526000396000f3fe6080604052600436106100c25760003560e01c80636b7dbb2d1161007f578063a3e6761011610059578063a3e676101461021c578063aaf10f4214610231578063c24a0f8b14610246578063f2fde38b1461025b576100c2565b80636b7dbb2d146101d05780638da5cb5b146101e55780638f32d59b146101fa576100c2565b806308dcb360146101225780630b97bc861461014d5780630fb5a6b41461016f57806313d033c0146101845780631ab7710d146101995780634cf088d9146101bb575b60006100cc61027d565b90506001600160a01b0381166100fd5760405162461bcd60e51b81526004016100f4906105b6565b60405180910390fd5b60405136600082376000803683855af43d806000843e81801561011e578184f35b8184fd5b34801561012e57600080fd5b5061013761029c565b6040516101449190610588565b60405180910390f35b34801561015957600080fd5b506101626102ab565b60405161014491906105c6565b34801561017b57600080fd5b506101626102b1565b34801561019057600080fd5b506101626102b7565b3480156101a557600080fd5b506101ae6102bd565b604051610144919061056c565b3480156101c757600080fd5b506101376102cc565b3480156101dc57600080fd5b506101376102db565b3480156101f157600080fd5b506101ae6102ea565b34801561020657600080fd5b5061020f6102f9565b604051610144919061057a565b34801561022857600080fd5b506101ae61031d565b34801561023d57600080fd5b506101ae61027d565b34801561025257600080fd5b5061016261032c565b34801561026757600080fd5b5061027b6102763660046103f8565b610332565b005b60008060405161028c90610556565b6040519081900390205492915050565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b60008060405161028c90610561565b6002546001600160a01b031681565b6004546001600160a01b031681565b6000546001600160a01b031690565b600080546001600160a01b031661030e610362565b6001600160a01b031614905090565b6003546001600160a01b031681565b60085481565b61033a6102f9565b6103565760405162461bcd60e51b81526004016100f4906105a6565b61035f81610366565b50565b3390565b6001600160a01b03811661038c5760405162461bcd60e51b81526004016100f490610596565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b80356103f28161060c565b92915050565b60006020828403121561040a57600080fd5b600061041684846103e7565b949350505050565b610427816105e2565b82525050565b610427816105ed565b61042781610601565b600061044c6026836105d4565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000610494600c836105d4565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006104bc6012836105dd565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006104ea600f836105dd565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b60006105156023836105d4565b7f50726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f8152621d5b9960ea1b602082015260400192915050565b610427816105fe565b60006103f2826104af565b60006103f2826104dd565b602081016103f2828461041e565b602081016103f2828461042d565b602081016103f28284610436565b602080825281016103f28161043f565b602080825281016103f281610487565b602080825281016103f281610508565b602081016103f2828461054d565b90815260200190565b919050565b60006103f2826105f2565b151590565b6001600160a01b031690565b90565b60006103f2826105e2565b610615816105e2565b811461035f57600080fdfea365627a7a723158208fadf5a06e09bf0282ebdaf120f87f9d40a56739860e4c58f5e6f248e5be98c96c6578706572696d656e74616cf564736f6c634300051100408be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060806040523480156200001157600080fd5b5060405162000f7f38038062000f7f8339810160408190526200003491620003fd565b868686868686866000620000506001600160e01b036200029216565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062000f5f833981519152908290a3506200009d336001600160e01b036200029616565b6001600160a01b038616620000cf5760405162461bcd60e51b8152600401620000c690620007f6565b60405180910390fd5b6001600160a01b038516620000f85760405162461bcd60e51b8152600401620000c690620007e4565b6001600160a01b038416620001215760405162461bcd60e51b8152600401620000c6906200079c565b82821015620001445760405162461bcd60e51b8152600401620000c6906200078a565b6001600160a01b0381166200016d5760405162461bcd60e51b8152600401620000c690620007c0565b62000181876001600160e01b036200032016565b600180546001600160a01b038089166001600160a01b0319928316179092556002805488841692169190911790819055604080516358b925a360e11b81529051919092169163b1724b46916004808301926020929190829003018186803b158015620001ec57600080fd5b505afa15801562000201573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002279190810190620004a8565b821115620002495760405162461bcd60e51b8152600401620000c69062000778565b600380546001600160a01b039586166001600160a01b03199182161790915560059390935560069190915560048054919093169116179055506200085098505050505050505050565b3390565b6001600160a01b038116620002bf5760405162461bcd60e51b8152600401620000c690620007d2565b6001600160a01b038116620002dc6001600160e01b03620003ab16565b6001600160a01b031660008051602062000f5f83398151915260405160405180910390a3600060405162000310906200076b565b6040519081900390209190915550565b6001600160a01b038116620003495760405162461bcd60e51b8152600401620000c690620007ae565b6001600160a01b038116620003666001600160e01b03620003cc16565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3600060405162000310906200075e565b600080604051620003bc906200076b565b6040519081900390205492915050565b600080604051620003bc906200075e565b8051620003ea816200082b565b92915050565b8051620003ea8162000845565b600080600080600080600060e0888a0312156200041957600080fd5b6000620004278a8a620003dd565b97505060206200043a8a828b01620003dd565b96505060406200044d8a828b01620003dd565b9550506060620004608a828b01620003dd565b9450506080620004738a828b01620003f0565b93505060a0620004868a828b01620003f0565b92505060c0620004998a828b01620003dd565b91505092959891949750929550565b600060208284031215620004bb57600080fd5b6000620004c98484620003f0565b949350505050565b6000620004e060288362000808565b7f6475726174696f6e206d6179206e6f742065786365656420746865206d617820815267323ab930ba34b7b760c11b602082015260400192915050565b60006200052c60328362000808565b7f6475726174696f6e206d75737420626520626967676572207468616e206f722081527132b8bab0b6103a37903a34329031b634b33360711b602082015260400192915050565b600062000582601b8362000808565b7f746f6b656e206f776e6572206164647265737320696e76616c69640000000000815260200192915050565b6000620005bd60298362000808565b7f50726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6981526864206164647265737360b81b602082015260400192915050565b60006200060a60128362000811565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006200063a60238362000808565b7f66656553686172696e67436f6c6c6563746f72206164647265737320696e76618152621b1a5960ea1b602082015260400192915050565b600062000681600f8362000811565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000620006ae60258362000808565b7f50726f78793a3a73657450726f78794f776e65723a20696e76616c6964206164815264647265737360d81b602082015260400192915050565b6000620006f760178362000808565b7f7374616b696e67206164647265737320696e76616c6964000000000000000000815260200192915050565b60006200073260138362000808565b7f534f56206164647265737320696e76616c696400000000000000000000000000815260200192915050565b6000620003ea82620005fb565b6000620003ea8262000672565b60208082528101620003ea81620004d1565b60208082528101620003ea816200051d565b60208082528101620003ea8162000573565b60208082528101620003ea81620005ae565b60208082528101620003ea816200062b565b60208082528101620003ea816200069f565b60208082528101620003ea81620006e8565b60208082528101620003ea8162000723565b90815260200190565b919050565b60006001600160a01b038216620003ea565b90565b620008368162000816565b81146200084257600080fd5b50565b620008368162000828565b6106ff80620008606000396000f3fe6080604052600436106100dd5760003560e01c806378f24bc61161007f578063a3e6761011610059578063a3e6761014610259578063aaf10f421461026e578063c24a0f8b14610283578063f2fde38b14610298576100dd565b806378f24bc6146102005780638da5cb5b146102225780638f32d59b14610237576100dd565b806313d033c0116100bb57806313d033c01461019f5780631ab7710d146101b45780634cf088d9146101d65780636b7dbb2d146101eb576100dd565b806308dcb3601461013d5780630b97bc86146101685780630fb5a6b41461018a575b60006100e76102b8565b90506001600160a01b0381166101185760405162461bcd60e51b815260040161010f90610652565b60405180910390fd5b60405136600082376000803683855af43d806000843e818015610139578184f35b8184fd5b34801561014957600080fd5b506101526102d7565b60405161015f9190610614565b60405180910390f35b34801561017457600080fd5b5061017d6102e6565b60405161015f9190610662565b34801561019657600080fd5b5061017d6102ec565b3480156101ab57600080fd5b5061017d6102f2565b3480156101c057600080fd5b506101c96102f8565b60405161015f91906105f8565b3480156101e257600080fd5b50610152610307565b3480156101f757600080fd5b50610152610316565b34801561020c57600080fd5b5061022061021b36600461044b565b610325565b005b34801561022e57600080fd5b506101c961033d565b34801561024357600080fd5b5061024c61034c565b60405161015f9190610606565b34801561026557600080fd5b506101c9610370565b34801561027a57600080fd5b506101c96102b8565b34801561028f57600080fd5b5061017d61037f565b3480156102a457600080fd5b506102206102b336600461044b565b610385565b6000806040516102c7906105e2565b6040519081900390205492915050565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b6000806040516102c7906105ed565b6002546001600160a01b031681565b6004546001600160a01b031681565b60405162461bcd60e51b815260040161010f90610642565b6000546001600160a01b031690565b600080546001600160a01b03166103616103b5565b6001600160a01b031614905090565b6003546001600160a01b031681565b60085481565b61038d61034c565b6103a95760405162461bcd60e51b815260040161010f90610632565b6103b2816103b9565b50565b3390565b6001600160a01b0381166103df5760405162461bcd60e51b815260040161010f90610622565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b8035610445816106a8565b92915050565b60006020828403121561045d57600080fd5b6000610469848461043a565b949350505050565b61047a8161067e565b82525050565b61047a81610689565b61047a8161069d565b600061049f602683610670565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b60006104e7600c83610670565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b600061050f601283610679565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b600061053d600f83610679565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000610568601783610670565b7f6f7065726174696f6e206e6f7420737570706f72746564000000000000000000815260200192915050565b60006105a1602383610670565b7f50726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f8152621d5b9960ea1b602082015260400192915050565b61047a8161069a565b600061044582610502565b600061044582610530565b602081016104458284610471565b602081016104458284610480565b602081016104458284610489565b6020808252810161044581610492565b60208082528101610445816104da565b602080825281016104458161055b565b6020808252810161044581610594565b6020810161044582846105d9565b90815260200190565b919050565b60006104458261068e565b151590565b6001600160a01b031690565b90565b60006104458261067e565b6106b18161067e565b81146103b257600080fdfea365627a7a72315820be360ea1d4e93148d403f9008d876b066a6c2d8288b504631d0dd9ff68dba3e06c6578706572696d656e74616cf564736f6c634300051100408be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0a365627a7a72315820263920a47b0db9ab876a46fbd30285526b6d23cf1cb18eda4e93022821d6c8c46c6578706572696d656e74616cf564736f6c63430005110040", + "deployedBytecode": "0x60806040523480156200001157600080fd5b50600436106200006a5760003560e01c8063546344f0146200006f5780638da5cb5b146200009e5780638f32d59b14620000a8578063c0cad24e14620000c1578063f2fde38b14620000cb578063fa5f771e14620000e4575b600080fd5b6200008662000080366004620003bc565b620000fb565b60405162000095919062000502565b60405180910390f35b62000086620001fd565b620000b26200020c565b60405162000095919062000588565b6200008662000232565b620000e2620000dc36600462000393565b62000241565b005b62000086620000f5366004620003bc565b62000278565b6000620001076200020c565b6200012f5760405162461bcd60e51b81526004016200012690620005aa565b60405180910390fd5b6000600160009054906101000a90046001600160a01b03168989898989896040516200015b9062000357565b6200016d979695949392919062000512565b604051809103906000f0801580156200018a573d6000803e3d6000fd5b5060405163f2fde38b60e01b81529091506001600160a01b0382169063f2fde38b90620001bc90869060040162000502565b600060405180830381600087803b158015620001d757600080fd5b505af1158015620001ec573d6000803e3d6000fd5b50929b9a5050505050505050505050565b6000546001600160a01b031690565b600080546001600160a01b031662000223620002cf565b6001600160a01b031614905090565b6001546001600160a01b031681565b6200024b6200020c565b6200026a5760405162461bcd60e51b81526004016200012690620005aa565b6200027581620002d3565b50565b6000620002846200020c565b620002a35760405162461bcd60e51b81526004016200012690620005aa565b6000600160009054906101000a90046001600160a01b03168989898989896040516200015b9062000365565b3390565b6001600160a01b038116620002fc5760405162461bcd60e51b8152600401620001269062000598565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b610ed5806200060983390190565b610f7f80620014de83390190565b80356200038081620005e6565b92915050565b80356200038081620005fd565b600060208284031215620003a657600080fd5b6000620003b4848462000373565b949350505050565b600080600080600080600060e0888a031215620003d857600080fd5b6000620003e68a8a62000373565b9750506020620003f98a828b0162000373565b96505060406200040c8a828b0162000373565b95505060606200041f8a828b0162000386565b9450506080620004328a828b0162000386565b93505060a0620004458a828b0162000373565b92505060c0620004588a828b0162000373565b91505092959891949750929550565b6200047281620005c5565b82525050565b6200047281620005d2565b600062000492602683620005bc565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000620004dc600c83620005bc565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6200047281620005e3565b6020810162000380828462000467565b60e0810162000522828a62000467565b62000531602083018962000467565b62000540604083018862000467565b6200054f606083018762000467565b6200055e6080830186620004f7565b6200056d60a0830185620004f7565b6200057c60c083018462000467565b98975050505050505050565b6020810162000380828462000478565b60208082528101620003808162000483565b602080825281016200038081620004cd565b90815260200190565b60006200038082620005d7565b151590565b6001600160a01b031690565b90565b620005f181620005c5565b81146200027557600080fd5b620005f181620005e356fe60806040523480156200001157600080fd5b5060405162000ed538038062000ed58339810160408190526200003491620003ef565b6000620000496001600160e01b036200028416565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062000eb5833981519152908290a35062000096336001600160e01b036200028816565b6001600160a01b038616620000c85760405162461bcd60e51b8152600401620000bf90620007e8565b60405180910390fd5b6001600160a01b038516620000f15760405162461bcd60e51b8152600401620000bf90620007d6565b6001600160a01b0384166200011a5760405162461bcd60e51b8152600401620000bf906200078e565b828210156200013d5760405162461bcd60e51b8152600401620000bf906200077c565b6001600160a01b038116620001665760405162461bcd60e51b8152600401620000bf90620007b2565b6200017a876001600160e01b036200031216565b600180546001600160a01b038089166001600160a01b0319928316179092556002805488841692169190911790819055604080516358b925a360e11b81529051919092169163b1724b46916004808301926020929190829003018186803b158015620001e557600080fd5b505afa158015620001fa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200022091908101906200049a565b821115620002425760405162461bcd60e51b8152600401620000bf906200076a565b600380546001600160a01b039586166001600160a01b031991821617909155600593909355600691909155600480549190931691161790555062000842915050565b3390565b6001600160a01b038116620002b15760405162461bcd60e51b8152600401620000bf90620007c4565b6001600160a01b038116620002ce6001600160e01b036200039d16565b6001600160a01b031660008051602062000eb583398151915260405160405180910390a3600060405162000302906200075d565b6040519081900390209190915550565b6001600160a01b0381166200033b5760405162461bcd60e51b8152600401620000bf90620007a0565b6001600160a01b038116620003586001600160e01b03620003be16565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a36000604051620003029062000750565b600080604051620003ae906200075d565b6040519081900390205492915050565b600080604051620003ae9062000750565b8051620003dc816200081d565b92915050565b8051620003dc8162000837565b600080600080600080600060e0888a0312156200040b57600080fd5b6000620004198a8a620003cf565b97505060206200042c8a828b01620003cf565b96505060406200043f8a828b01620003cf565b9550506060620004528a828b01620003cf565b9450506080620004658a828b01620003e2565b93505060a0620004788a828b01620003e2565b92505060c06200048b8a828b01620003cf565b91505092959891949750929550565b600060208284031215620004ad57600080fd5b6000620004bb8484620003e2565b949350505050565b6000620004d2602883620007fa565b7f6475726174696f6e206d6179206e6f742065786365656420746865206d617820815267323ab930ba34b7b760c11b602082015260400192915050565b60006200051e603283620007fa565b7f6475726174696f6e206d75737420626520626967676572207468616e206f722081527132b8bab0b6103a37903a34329031b634b33360711b602082015260400192915050565b600062000574601b83620007fa565b7f746f6b656e206f776e6572206164647265737320696e76616c69640000000000815260200192915050565b6000620005af602983620007fa565b7f50726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6981526864206164647265737360b81b602082015260400192915050565b6000620005fc60128362000803565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006200062c602383620007fa565b7f66656553686172696e67436f6c6c6563746f72206164647265737320696e76618152621b1a5960ea1b602082015260400192915050565b600062000673600f8362000803565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000620006a0602583620007fa565b7f50726f78793a3a73657450726f78794f776e65723a20696e76616c6964206164815264647265737360d81b602082015260400192915050565b6000620006e9601783620007fa565b7f7374616b696e67206164647265737320696e76616c6964000000000000000000815260200192915050565b600062000724601383620007fa565b7f534f56206164647265737320696e76616c696400000000000000000000000000815260200192915050565b6000620003dc82620005ed565b6000620003dc8262000664565b60208082528101620003dc81620004c3565b60208082528101620003dc816200050f565b60208082528101620003dc8162000565565b60208082528101620003dc81620005a0565b60208082528101620003dc816200061d565b60208082528101620003dc8162000691565b60208082528101620003dc81620006da565b60208082528101620003dc8162000715565b90815260200190565b919050565b60006001600160a01b038216620003dc565b90565b620008288162000808565b81146200083457600080fd5b50565b62000828816200081a565b61066380620008526000396000f3fe6080604052600436106100c25760003560e01c80636b7dbb2d1161007f578063a3e6761011610059578063a3e676101461021c578063aaf10f4214610231578063c24a0f8b14610246578063f2fde38b1461025b576100c2565b80636b7dbb2d146101d05780638da5cb5b146101e55780638f32d59b146101fa576100c2565b806308dcb360146101225780630b97bc861461014d5780630fb5a6b41461016f57806313d033c0146101845780631ab7710d146101995780634cf088d9146101bb575b60006100cc61027d565b90506001600160a01b0381166100fd5760405162461bcd60e51b81526004016100f4906105b6565b60405180910390fd5b60405136600082376000803683855af43d806000843e81801561011e578184f35b8184fd5b34801561012e57600080fd5b5061013761029c565b6040516101449190610588565b60405180910390f35b34801561015957600080fd5b506101626102ab565b60405161014491906105c6565b34801561017b57600080fd5b506101626102b1565b34801561019057600080fd5b506101626102b7565b3480156101a557600080fd5b506101ae6102bd565b604051610144919061056c565b3480156101c757600080fd5b506101376102cc565b3480156101dc57600080fd5b506101376102db565b3480156101f157600080fd5b506101ae6102ea565b34801561020657600080fd5b5061020f6102f9565b604051610144919061057a565b34801561022857600080fd5b506101ae61031d565b34801561023d57600080fd5b506101ae61027d565b34801561025257600080fd5b5061016261032c565b34801561026757600080fd5b5061027b6102763660046103f8565b610332565b005b60008060405161028c90610556565b6040519081900390205492915050565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b60008060405161028c90610561565b6002546001600160a01b031681565b6004546001600160a01b031681565b6000546001600160a01b031690565b600080546001600160a01b031661030e610362565b6001600160a01b031614905090565b6003546001600160a01b031681565b60085481565b61033a6102f9565b6103565760405162461bcd60e51b81526004016100f4906105a6565b61035f81610366565b50565b3390565b6001600160a01b03811661038c5760405162461bcd60e51b81526004016100f490610596565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b80356103f28161060c565b92915050565b60006020828403121561040a57600080fd5b600061041684846103e7565b949350505050565b610427816105e2565b82525050565b610427816105ed565b61042781610601565b600061044c6026836105d4565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000610494600c836105d4565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006104bc6012836105dd565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006104ea600f836105dd565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b60006105156023836105d4565b7f50726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f8152621d5b9960ea1b602082015260400192915050565b610427816105fe565b60006103f2826104af565b60006103f2826104dd565b602081016103f2828461041e565b602081016103f2828461042d565b602081016103f28284610436565b602080825281016103f28161043f565b602080825281016103f281610487565b602080825281016103f281610508565b602081016103f2828461054d565b90815260200190565b919050565b60006103f2826105f2565b151590565b6001600160a01b031690565b90565b60006103f2826105e2565b610615816105e2565b811461035f57600080fdfea365627a7a723158208fadf5a06e09bf0282ebdaf120f87f9d40a56739860e4c58f5e6f248e5be98c96c6578706572696d656e74616cf564736f6c634300051100408be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060806040523480156200001157600080fd5b5060405162000f7f38038062000f7f8339810160408190526200003491620003fd565b868686868686866000620000506001600160e01b036200029216565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062000f5f833981519152908290a3506200009d336001600160e01b036200029616565b6001600160a01b038616620000cf5760405162461bcd60e51b8152600401620000c690620007f6565b60405180910390fd5b6001600160a01b038516620000f85760405162461bcd60e51b8152600401620000c690620007e4565b6001600160a01b038416620001215760405162461bcd60e51b8152600401620000c6906200079c565b82821015620001445760405162461bcd60e51b8152600401620000c6906200078a565b6001600160a01b0381166200016d5760405162461bcd60e51b8152600401620000c690620007c0565b62000181876001600160e01b036200032016565b600180546001600160a01b038089166001600160a01b0319928316179092556002805488841692169190911790819055604080516358b925a360e11b81529051919092169163b1724b46916004808301926020929190829003018186803b158015620001ec57600080fd5b505afa15801562000201573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250620002279190810190620004a8565b821115620002495760405162461bcd60e51b8152600401620000c69062000778565b600380546001600160a01b039586166001600160a01b03199182161790915560059390935560069190915560048054919093169116179055506200085098505050505050505050565b3390565b6001600160a01b038116620002bf5760405162461bcd60e51b8152600401620000c690620007d2565b6001600160a01b038116620002dc6001600160e01b03620003ab16565b6001600160a01b031660008051602062000f5f83398151915260405160405180910390a3600060405162000310906200076b565b6040519081900390209190915550565b6001600160a01b038116620003495760405162461bcd60e51b8152600401620000c690620007ae565b6001600160a01b038116620003666001600160e01b03620003cc16565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3600060405162000310906200075e565b600080604051620003bc906200076b565b6040519081900390205492915050565b600080604051620003bc906200075e565b8051620003ea816200082b565b92915050565b8051620003ea8162000845565b600080600080600080600060e0888a0312156200041957600080fd5b6000620004278a8a620003dd565b97505060206200043a8a828b01620003dd565b96505060406200044d8a828b01620003dd565b9550506060620004608a828b01620003dd565b9450506080620004738a828b01620003f0565b93505060a0620004868a828b01620003f0565b92505060c0620004998a828b01620003dd565b91505092959891949750929550565b600060208284031215620004bb57600080fd5b6000620004c98484620003f0565b949350505050565b6000620004e060288362000808565b7f6475726174696f6e206d6179206e6f742065786365656420746865206d617820815267323ab930ba34b7b760c11b602082015260400192915050565b60006200052c60328362000808565b7f6475726174696f6e206d75737420626520626967676572207468616e206f722081527132b8bab0b6103a37903a34329031b634b33360711b602082015260400192915050565b600062000582601b8362000808565b7f746f6b656e206f776e6572206164647265737320696e76616c69640000000000815260200192915050565b6000620005bd60298362000808565b7f50726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6981526864206164647265737360b81b602082015260400192915050565b60006200060a60128362000811565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b60006200063a60238362000808565b7f66656553686172696e67436f6c6c6563746f72206164647265737320696e76618152621b1a5960ea1b602082015260400192915050565b600062000681600f8362000811565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000620006ae60258362000808565b7f50726f78793a3a73657450726f78794f776e65723a20696e76616c6964206164815264647265737360d81b602082015260400192915050565b6000620006f760178362000808565b7f7374616b696e67206164647265737320696e76616c6964000000000000000000815260200192915050565b60006200073260138362000808565b7f534f56206164647265737320696e76616c696400000000000000000000000000815260200192915050565b6000620003ea82620005fb565b6000620003ea8262000672565b60208082528101620003ea81620004d1565b60208082528101620003ea816200051d565b60208082528101620003ea8162000573565b60208082528101620003ea81620005ae565b60208082528101620003ea816200062b565b60208082528101620003ea816200069f565b60208082528101620003ea81620006e8565b60208082528101620003ea8162000723565b90815260200190565b919050565b60006001600160a01b038216620003ea565b90565b620008368162000816565b81146200084257600080fd5b50565b620008368162000828565b6106ff80620008606000396000f3fe6080604052600436106100dd5760003560e01c806378f24bc61161007f578063a3e6761011610059578063a3e6761014610259578063aaf10f421461026e578063c24a0f8b14610283578063f2fde38b14610298576100dd565b806378f24bc6146102005780638da5cb5b146102225780638f32d59b14610237576100dd565b806313d033c0116100bb57806313d033c01461019f5780631ab7710d146101b45780634cf088d9146101d65780636b7dbb2d146101eb576100dd565b806308dcb3601461013d5780630b97bc86146101685780630fb5a6b41461018a575b60006100e76102b8565b90506001600160a01b0381166101185760405162461bcd60e51b815260040161010f90610652565b60405180910390fd5b60405136600082376000803683855af43d806000843e818015610139578184f35b8184fd5b34801561014957600080fd5b506101526102d7565b60405161015f9190610614565b60405180910390f35b34801561017457600080fd5b5061017d6102e6565b60405161015f9190610662565b34801561019657600080fd5b5061017d6102ec565b3480156101ab57600080fd5b5061017d6102f2565b3480156101c057600080fd5b506101c96102f8565b60405161015f91906105f8565b3480156101e257600080fd5b50610152610307565b3480156101f757600080fd5b50610152610316565b34801561020c57600080fd5b5061022061021b36600461044b565b610325565b005b34801561022e57600080fd5b506101c961033d565b34801561024357600080fd5b5061024c61034c565b60405161015f9190610606565b34801561026557600080fd5b506101c9610370565b34801561027a57600080fd5b506101c96102b8565b34801561028f57600080fd5b5061017d61037f565b3480156102a457600080fd5b506102206102b336600461044b565b610385565b6000806040516102c7906105e2565b6040519081900390205492915050565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b6000806040516102c7906105ed565b6002546001600160a01b031681565b6004546001600160a01b031681565b60405162461bcd60e51b815260040161010f90610642565b6000546001600160a01b031690565b600080546001600160a01b03166103616103b5565b6001600160a01b031614905090565b6003546001600160a01b031681565b60085481565b61038d61034c565b6103a95760405162461bcd60e51b815260040161010f90610632565b6103b2816103b9565b50565b3390565b6001600160a01b0381166103df5760405162461bcd60e51b815260040161010f90610622565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b8035610445816106a8565b92915050565b60006020828403121561045d57600080fd5b6000610469848461043a565b949350505050565b61047a8161067e565b82525050565b61047a81610689565b61047a8161069d565b600061049f602683610670565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b60006104e7600c83610670565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b600061050f601283610679565b7135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815260120192915050565b600061053d600f83610679565b6e35b2bc97383937bc3c9737bbb732b960891b8152600f0192915050565b6000610568601783610670565b7f6f7065726174696f6e206e6f7420737570706f72746564000000000000000000815260200192915050565b60006105a1602383610670565b7f50726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f8152621d5b9960ea1b602082015260400192915050565b61047a8161069a565b600061044582610502565b600061044582610530565b602081016104458284610471565b602081016104458284610480565b602081016104458284610489565b6020808252810161044581610492565b60208082528101610445816104da565b602080825281016104458161055b565b6020808252810161044581610594565b6020810161044582846105d9565b90815260200190565b919050565b60006104458261068e565b151590565b6001600160a01b031690565b90565b60006104458261067e565b6106b18161067e565b81146103b257600080fdfea365627a7a72315820be360ea1d4e93148d403f9008d876b066a6c2d8288b504631d0dd9ff68dba3e06c6578706572696d656e74616cf564736f6c634300051100408be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0a365627a7a72315820263920a47b0db9ab876a46fbd30285526b6d23cf1cb18eda4e93022821d6c8c46c6578706572696d656e74616cf564736f6c63430005110040", + "devdoc": { + "methods": { + "deployTeamVesting(address,address,address,uint256,uint256,address,address)": { + "params": { + "_SOV": "The address of SOV token.", + "_cliff": "The time interval to the first withdraw in seconds.", + "_duration": "The total duration in seconds.", + "_feeSharing": "The address of fee sharing contract.", + "_staking": "The address of staking contract.", + "_tokenOwner": "The owner of the tokens.", + "_vestingOwner": "The address of an owner of vesting contract." + }, + "return": "The vesting contract address." + }, + "deployVesting(address,address,address,uint256,uint256,address,address)": { + "params": { + "_SOV": "the address of SOV token.", + "_cliff": "The time interval to the first withdraw in seconds.", + "_duration": "The total duration in seconds.", + "_feeSharing": "The address of fee sharing contract.", + "_staking": "The address of staking contract.", + "_tokenOwner": "The owner of the tokens.", + "_vestingOwner": "The address of an owner of vesting contract." + }, + "return": "The vesting contract address." + }, + "isOwner()": { + "details": "Returns true if the caller is the current owner." + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "title": "Vesting Factory: Contract to deploy vesting contracts of two types: vesting (TokenHolder) and team vesting (Multisig)." + }, + "userdoc": { + "methods": { + "deployTeamVesting(address,address,address,uint256,uint256,address,address)": { + "notice": "Deploys Team Vesting contract." + }, + "deployVesting(address,address,address,uint256,uint256,address,address)": { + "notice": "Deploys Vesting contract." + } + }, + "notice": "Factory pattern allows to create multiple instances of the same contract and keep track of them easier." + }, + "storageLayout": { + "storage": [ + { + "astId": 54767, + "contract": "contracts/governance/Vesting/VestingFactory.sol:VestingFactory", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 27890, + "contract": "contracts/governance/Vesting/VestingFactory.sol:VestingFactory", + "label": "vestingLogic", + "offset": 0, + "slot": "1", + "type": "t_address" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + } + } + } +} diff --git a/deployment/deployments/rskSovrynTestnet/VestingLogic.json b/deployment/deployments/rskSovrynTestnet/VestingLogic.json new file mode 100644 index 000000000..7f3d0186c --- /dev/null +++ b/deployment/deployments/rskSovrynTestnet/VestingLogic.json @@ -0,0 +1,687 @@ +{ + "address": "0x07ba5E5bD20810A0B00b0B22D55243aAdd3F33E4", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "loanPoolToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "maxCheckpoints", + "type": "uint32" + } + ], + "name": "DividendsCollected", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newStakingContract", + "type": "address" + } + ], + "name": "MigratedToNewStakingContract", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensStaked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "startFrom", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "end", + "type": "uint256" + } + ], + "name": "TokensWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "delegatee", + "type": "address" + } + ], + "name": "VotesDelegated", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "SOV", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "cliff", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_loanPoolToken", + "type": "address" + }, + { + "internalType": "uint32", + "name": "_maxCheckpoints", + "type": "uint32" + }, + { + "internalType": "address", + "name": "_receiver", + "type": "address" + } + ], + "name": "collectDividends", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_delegatee", + "type": "address" + } + ], + "name": "delegate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "duration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "endDate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "feeSharingCollector", + "outputs": [ + { + "internalType": "contract IFeeSharingCollector", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isOwner", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "migrateToNewStakingContract", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_token", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "receiveApproval", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "stakeTokens", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "_sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "stakeTokensWithApproval", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "staking", + "outputs": [ + { + "internalType": "contract IStaking", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "startDate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "tokenOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "withdrawTokens", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "startFrom", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxWithdrawIterations", + "type": "uint256" + } + ], + "name": "withdrawTokensStartingFrom", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x534e9713e7fdceb2e90483415fd56b2ab0bfed0c998c132cdbfa1f0c71ebc903", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0x07ba5E5bD20810A0B00b0B22D55243aAdd3F33E4", + "transactionIndex": 0, + "gasUsed": "1958750", + "logsBloom": "0x00000000000020000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000001000", + "blockHash": "0x0a3fcf86fca7d01077d5c373be8d674a95af26c6f843a11ceb7df2ffdfb8a106", + "transactionHash": "0x534e9713e7fdceb2e90483415fd56b2ab0bfed0c998c132cdbfa1f0c71ebc903", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4639916, + "transactionHash": "0x534e9713e7fdceb2e90483415fd56b2ab0bfed0c998c132cdbfa1f0c71ebc903", + "address": "0x07ba5E5bD20810A0B00b0B22D55243aAdd3F33E4", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x0a3fcf86fca7d01077d5c373be8d674a95af26c6f843a11ceb7df2ffdfb8a106" + } + ], + "blockNumber": 4639916, + "cumulativeGasUsed": "1958750", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "85e0140014063bf09a4ea91c8a627911", + "metadata": "{\"compiler\":{\"version\":\"0.5.17+commit.d19bba13\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"loanPoolToken\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"maxCheckpoints\",\"type\":\"uint32\"}],\"name\":\"DividendsCollected\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newStakingContract\",\"type\":\"address\"}],\"name\":\"MigratedToNewStakingContract\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"TokensStaked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"startFrom\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"name\":\"TokensWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"delegatee\",\"type\":\"address\"}],\"name\":\"VotesDelegated\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[],\"name\":\"SOV\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"cliff\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_loanPoolToken\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"_maxCheckpoints\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"_receiver\",\"type\":\"address\"}],\"name\":\"collectDividends\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_delegatee\",\"type\":\"address\"}],\"name\":\"delegate\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"duration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"endDate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"feeSharingCollector\",\"outputs\":[{\"internalType\":\"contract IFeeSharingCollector\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"isOwner\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"migrateToNewStakingContract\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"receiveApproval\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"stakeTokens\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"stakeTokensWithApproval\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"staking\",\"outputs\":[{\"internalType\":\"contract IStaking\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"startDate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"tokenOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"withdrawTokens\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"startFrom\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxWithdrawIterations\",\"type\":\"uint256\"}],\"name\":\"withdrawTokensStartingFrom\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Deployed by a VestingFactory contract.\",\"methods\":{\"collectDividends(address,uint32,address)\":{\"params\":{\"_loanPoolToken\":\"The loan pool token address.\",\"_maxCheckpoints\":\"Maximum number of checkpoints to be processed.\",\"_receiver\":\"The receiver of tokens or msg.sender\"}},\"delegate(address)\":{\"params\":{\"_delegatee\":\"The address to delegate votes to.\"}},\"isOwner()\":{\"details\":\"Returns true if the caller is the current owner.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"receiveApproval(address,uint256,address,bytes)\":{\"params\":{\"_data\":\"The data will be used for low level call.\"}},\"stakeTokens(uint256)\":{\"params\":{\"_amount\":\"The amount of tokens to stake.\"}},\"stakeTokensWithApproval(address,uint256)\":{\"details\":\"This function will be invoked from receiveApproval.SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\",\"params\":{\"_amount\":\"The amount of tokens to stake.\",\"_sender\":\"The sender of SOV.approveAndCall\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"withdrawTokens(address)\":{\"params\":{\"receiver\":\"The receiving address.\"}},\"withdrawTokensStartingFrom(address,uint256,uint256)\":{\"params\":{\"maxWithdrawIterations\":\"max withdrawal iteration to work around block gas limit issue.\",\"receiver\":\"The receiving address.\",\"startFrom\":\"The start value for the iterations.\"}}},\"title\":\"Vesting Logic contract.\"},\"userdoc\":{\"methods\":{\"collectDividends(address,uint32,address)\":{\"notice\":\"Collect dividends from fee sharing proxy.\"},\"delegate(address)\":{\"notice\":\"Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\"},\"migrateToNewStakingContract()\":{\"notice\":\"Allows the owners to migrate the positions to a new staking contract.\"},\"receiveApproval(address,uint256,address,bytes)\":{\"notice\":\"Receives approval from SOV token.\"},\"stakeTokens(uint256)\":{\"notice\":\"Stakes tokens according to the vesting schedule.\"},\"stakeTokensWithApproval(address,uint256)\":{\"notice\":\"Stakes tokens according to the vesting schedule.\"},\"withdrawTokens(address)\":{\"notice\":\"Withdraws unlocked tokens from the staking contract and forwards them to an address specified by the token owner.\"},\"withdrawTokensStartingFrom(address,uint256,uint256)\":{\"notice\":\"Withdraws unlocked tokens partially (based on the max withdraw iteration that has been set) from the staking contract and forwards them to an address specified by the token owner.\"}},\"notice\":\"Staking, delegating and withdrawal functionality.\"}},\"settings\":{\"compilationTarget\":{\"contracts/governance/Vesting/VestingLogic.sol\":\"VestingLogic\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/governance/ApprovalReceiver.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"./ErrorDecoder.sol\\\";\\nimport \\\"../token/IApproveAndCall.sol\\\";\\n\\n/**\\n * @title Base contract for receiving approval from SOV token.\\n */\\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\\n modifier onlyThisContract() {\\n // Accepts calls only from receiveApproval function.\\n require(msg.sender == address(this), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _data The data will be used for low level call.\\n */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external {\\n // Accepts calls only from SOV token.\\n require(msg.sender == _getToken(), \\\"unauthorized\\\");\\n require(msg.sender == _token, \\\"unauthorized\\\");\\n\\n // Only allowed methods.\\n bool isAllowed = false;\\n bytes4[] memory selectors = _getSelectors();\\n bytes4 sig = _getSig(_data);\\n for (uint256 i = 0; i < selectors.length; i++) {\\n if (sig == selectors[i]) {\\n isAllowed = true;\\n break;\\n }\\n }\\n require(isAllowed, \\\"method is not allowed\\\");\\n\\n // Check sender and amount.\\n address sender;\\n uint256 amount;\\n (, sender, amount) = abi.decode(\\n abi.encodePacked(bytes28(0), _data),\\n (bytes32, address, uint256)\\n );\\n require(sender == _sender, \\\"sender mismatch\\\");\\n require(amount == _amount, \\\"amount mismatch\\\");\\n\\n _call(_data);\\n }\\n\\n /**\\n * @notice Returns token address, only this address can be a sender for receiveApproval.\\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\\n * @return By default, 0x. When overriden, the token address making the call.\\n */\\n function _getToken() internal view returns (address) {\\n return address(0);\\n }\\n\\n /**\\n * @notice Returns list of function selectors allowed to be invoked.\\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\\n * @return By default, empty array. When overriden, allowed selectors.\\n */\\n function _getSelectors() internal pure returns (bytes4[] memory) {\\n return new bytes4[](0);\\n }\\n\\n /**\\n * @notice Makes call and reverts w/ enhanced error message.\\n * @param _data Error message as bytes.\\n */\\n function _call(bytes memory _data) internal {\\n (bool success, bytes memory returnData) = address(this).call(_data);\\n if (!success) {\\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\\n revert(\\\"receiveApproval: Transaction execution reverted.\\\");\\n } else {\\n revert(_addErrorMessage(\\\"receiveApproval: \\\", string(returnData)));\\n }\\n }\\n }\\n\\n /**\\n * @notice Extracts the called function selector, a hash of the signature.\\n * @dev The first four bytes of the call data for a function call specifies\\n * the function to be called. It is the first (left, high-order in big-endian)\\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\\n * Example:\\n * msg.data:\\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\\n * 000450000000000000000000000000000000000000000000000000000000000000001\\n * selector (or method ID): 0xcdcd77c0\\n * signature: baz(uint32,bool)\\n * @param _data The msg.data from the low level call.\\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\\n */\\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\\n assembly {\\n sig := mload(add(_data, 32))\\n }\\n }\\n}\\n\",\"keccak256\":\"0xfec344456774fa83b0885dd71825ccb6780be8db63c394f3ca09107977c65429\"},\"contracts/governance/ErrorDecoder.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Base contract to properly handle returned data on failed calls\\n * @dev On EVM if the return data length of a call is less than 68,\\n * then the transaction fails silently without a revert message!\\n *\\n * As described in the Solidity documentation\\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\\n * the revert reason is an ABI-encoded string consisting of:\\n * 0x08c379a0 // Function selector (method id) for \\\"Error(string)\\\" signature\\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\\n *\\n * Another example, debug data from test:\\n * 0x08c379a0\\n * 0000000000000000000000000000000000000000000000000000000000000020\\n * 0000000000000000000000000000000000000000000000000000000000000034\\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\\n *\\n * Parsed into:\\n * Data offset: 20\\n * Length: 34\\n * Error message:\\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\\n */\\ncontract ErrorDecoder {\\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\\n\\n /**\\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\\n * @param str1 First string, usually a hardcoded context written by dev.\\n * @param str2 Second string, usually the error message from the reverted call.\\n * @return The concatenated error string\\n */\\n function _addErrorMessage(string memory str1, string memory str2)\\n internal\\n pure\\n returns (string memory)\\n {\\n bytes memory bytesStr1 = bytes(str1);\\n bytes memory bytesStr2 = bytes(str2);\\n string memory str12 =\\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\\n bytes memory bytesStr12 = bytes(str12);\\n uint256 j = 0;\\n for (uint256 i = 0; i < bytesStr1.length; i++) {\\n bytesStr12[j++] = bytesStr1[i];\\n }\\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\\n bytesStr12[j++] = bytesStr2[i];\\n }\\n return string(bytesStr12);\\n }\\n}\\n\",\"keccak256\":\"0xa0fa7986924aab574ca9e7c265f8c7bf00671ba1d86dbad143df7c14455f1c6a\"},\"contracts/governance/IFeeSharingCollector.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n * */\\ninterface IFeeSharingCollector {\\n function withdrawFees(address[] calldata _token) external;\\n\\n function transferTokens(address _token, uint96 _amount) external;\\n\\n function withdraw(\\n address _loanPoolToken,\\n uint32 _maxCheckpoints,\\n address _receiver\\n ) external;\\n}\\n\",\"keccak256\":\"0x7794cb434d9395ea983dcf8ded48db5b68897a338429320f60172c4caa47fb40\"},\"contracts/governance/Staking/interfaces/IStaking.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\npragma experimental ABIEncoderV2;\\n\\n/**\\n * @title Interface for Staking modules governance/Staking/modules\\n */\\n\\ninterface IStaking {\\n /*************************** StakingAdminModule ***************************/\\n\\n /**\\n * @notice Add account to Admins ACL.\\n * @param _admin The addresses of the account to grant permissions.\\n * */\\n function addAdmin(address _admin) external;\\n\\n /**\\n * @notice Remove account from Admins ACL.\\n * @param _admin The addresses of the account to revoke permissions.\\n * */\\n function removeAdmin(address _admin) external;\\n\\n /**\\n * @notice Add account to pausers ACL.\\n * @param _pauser The address to grant pauser permissions.\\n * */\\n function addPauser(address _pauser) external;\\n\\n /**\\n * @notice Remove account from pausers ACL.\\n * @param _pauser The address to grant pauser permissions.\\n * */\\n function removePauser(address _pauser) external;\\n\\n /**\\n * @notice Pause/unpause contract\\n * @param _pause true when pausing, false when unpausing\\n * */\\n function pauseUnpause(bool _pause) external;\\n\\n /**\\n * @notice Freeze contract - disable all functions\\n * @param _freeze true when freezing, false when unfreezing\\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\\n * */\\n function freezeUnfreeze(bool _freeze) external;\\n\\n /**\\n * @notice Allows the owner to set a fee sharing proxy contract.\\n * We need it for unstaking with slashing.\\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\\n * */\\n function setFeeSharing(address _feeSharing) external;\\n\\n /**\\n * @notice Allow the owner to set weight scaling.\\n * We need it for unstaking with slashing.\\n * @param _weightScaling The weight scaling.\\n * */\\n function setWeightScaling(uint96 _weightScaling) external;\\n\\n /**\\n * @notice Allow the owner to set a new staking contract.\\n * As a consequence it allows the stakers to migrate their positions\\n * to the new contract.\\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\\n * is not implemented.\\n * @param _newStakingContract The address of the new staking contract.\\n * */\\n function setNewStakingContract(address _newStakingContract) external;\\n\\n /**\\n * @notice Allow a staker to migrate his positions to the new staking contract.\\n * @dev Staking contract needs to be set before by the owner.\\n * Currently not implemented, just needed for the interface.\\n * In case it's needed at some point in the future,\\n * the implementation needs to be changed first.\\n * */\\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\\n\\n /*************************** StakingGovernanceModule ***************************/\\n\\n /**\\n * @notice Compute the total voting power at a given time.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @param time The timestamp for which to calculate the total voting power.\\n * @return The total voting power at the given time.\\n * */\\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Get the current votes balance for a user account.\\n * @param account The address to get votes balance.\\n * @dev This is a wrapper to simplify arguments. The actual computation is\\n * performed on WeightedStaking parent contract.\\n * @return The number of current votes for a user account.\\n * */\\n function getCurrentVotes(address account) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of votes for a delegatee as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will revert\\n * to prevent misinformation.\\n * Used for Voting, not for fee sharing.\\n * @param account The address of the account to check.\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The staking date to compute the power for.\\n * @return The number of votes the delegatee had as of the given block.\\n * */\\n function getPriorVotes(\\n address account,\\n uint256 blockNumber,\\n uint256 date\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of stake for an account as of a block number.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * @param account The address of the account to check.\\n * @param date The staking date to compute the power for.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorStakeByDateForDelegatee(\\n address account,\\n uint256 date,\\n uint256 blockNumber\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\\n * be internal instead of a public function.\\n * @param date The date to check the stakes for.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\\n * @param delegatee The address to delegate votes to.\\n * @param lockDate the date if the position to delegate.\\n * */\\n function delegate(address delegatee, uint256 lockDate) external;\\n\\n /*************************** StakingStakeModule ***************************/\\n\\n event TokensStaked(\\n address indexed staker,\\n uint256 amount,\\n uint256 lockedUntil,\\n uint256 totalStaked\\n );\\n\\n /**\\n * @notice Stake the given amount for the given duration of time.\\n * @param amount The number of tokens to stake.\\n * @param until Timestamp indicating the date until which to stake.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stake(\\n uint96 amount,\\n uint256 until,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Stake the given amount for the given duration of time.\\n * @dev This function will be invoked from receiveApproval\\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\\n * @param sender The sender of SOV.approveAndCall\\n * @param amount The number of tokens to stake.\\n * @param until Timestamp indicating the date until which to stake.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stakeWithApproval(\\n address sender,\\n uint96 amount,\\n uint256 until,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _data The data will be used for low level call.\\n */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external;\\n\\n /**\\n * @notice Extend the staking duration until the specified date.\\n * @param previousLock The old unlocking timestamp.\\n * @param until The new unlocking timestamp in seconds.\\n * */\\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\\n\\n /**\\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\\n * */\\n function stakesBySchedule(\\n uint256 amount,\\n uint256 cliff,\\n uint256 duration,\\n uint256 intervalLength,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Stake tokens according to the vesting schedule.\\n * @param amount The amount of tokens to stake.\\n * @param cliff The time interval to the first withdraw.\\n * @param duration The staking duration.\\n * @param intervalLength The length of each staking interval when cliff passed.\\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\\n * @param delegatee The address of the delegatee or 0x0 if there is none.\\n * */\\n function stakeBySchedule(\\n uint256 amount,\\n uint256 cliff,\\n uint256 duration,\\n uint256 intervalLength,\\n address stakeFor,\\n address delegatee\\n ) external;\\n\\n /**\\n * @notice Get the number of staked tokens held by the user account.\\n * @dev Iterate checkpoints adding up stakes.\\n * @param account The address of the account to get the balance of.\\n * @return The number of tokens held.\\n * */\\n function balanceOf(address account) external view returns (uint96 balance);\\n\\n /**\\n * @notice Get the current number of tokens staked for a day.\\n * @param lockedTS The timestamp to get the staked tokens for.\\n * */\\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\\n\\n /**\\n * @notice Get list of stakes for a user account.\\n * @param account The address to get stakes.\\n * @return The arrays of dates and stakes.\\n * */\\n function getStakes(address account)\\n external\\n view\\n returns (uint256[] memory dates, uint96[] memory stakes);\\n\\n /**\\n * @notice Unstaking is possible every 2 weeks only. This means, to\\n * calculate the key value for the staking checkpoints, we need to\\n * map the intended timestamp to the closest available date.\\n * @param timestamp The unlocking timestamp.\\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\\n * */\\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\\n\\n /*************************** StakingStorageModule ***************************/\\n\\n /// @notice The maximum duration to stake tokens\\n /// @return MAX_DURATION to stake tokens\\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\\n\\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\\n /// @return uint256(MAX_VOTING_WEIGHT);\\n function getStorageMaxVotingWeight() external pure returns (uint256);\\n\\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\\n /// @return uint256(WEIGHT_FACTOR);\\n function getStorageWeightFactor() external pure returns (uint256);\\n\\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\\n function getStorageDefaultWeightScaling() external pure returns (uint256);\\n\\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\\n function getStorageRangeForWeightScaling()\\n external\\n pure\\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\\n\\n /// @notice The EIP-712 typehash for the contract's domain.\\n /// @return uint256(DOMAIN_TYPEHASH);\\n function getStorageDomainTypehash() external pure returns (uint256);\\n\\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\\n /// @return uint256(DELEGATION_TYPEHASH);\\n function getStorageDelegationTypehash() external pure returns (uint256);\\n\\n /// @return name;\\n function getStorageName() external view returns (string memory);\\n\\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\\n\\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\\n function kickoffTS() external view returns (uint256);\\n\\n /// @notice The token to be staked\\n function SOVToken() external view returns (address);\\n\\n /// @notice Stakers delegated voting power\\n /// @param staker - the delegating address\\n /// @param until - delegated voting\\n /// @return _delegate - voting power delegated to address\\n function delegates(address staker, uint256 until) external view returns (address _delegate);\\n\\n /// @notice If this flag is set to true, all tokens are unlocked immediately\\n /// see function unlockAllTokens() for details\\n function allUnlocked() external view returns (bool);\\n\\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\\n function newStakingContract() external view returns (address);\\n\\n /// CHECKPOINTS\\n struct Checkpoint {\\n uint32 fromBlock;\\n uint96 stake;\\n }\\n\\n /// @notice A record of tokens to be unstaked at a given time in total.\\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\\n function totalStakingCheckpoints(uint256 date, uint32 index)\\n external\\n view\\n returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date.\\n /// @dev numTotalStakingCheckpoints[date] is a number.\\n function numTotalStakingCheckpoints(uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\\n function delegateStakingCheckpoints(\\n address delagatee,\\n uint256 date,\\n uint32 index\\n ) external view returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date per delegate.\\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\\n function userStakingCheckpoints(\\n address user,\\n uint256 date,\\n uint32 index\\n ) external view returns (Checkpoint memory);\\n\\n /// @notice The number of total staking checkpoints for each date per user.\\n /// @dev numUserStakingCheckpoints[user][date] is a number\\n function numUserStakingCheckpoints(address user, uint256 date)\\n external\\n view\\n returns (uint32 checkpointsQty);\\n\\n /// @notice A record of states for signing / validating signatures\\n /// @dev nonces[user] is a number.\\n function nonces(address user) external view returns (uint256 nonce);\\n\\n /// SLASHING ///\\n\\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\\n function feeSharing() external view returns (address);\\n\\n /// @notice used for weight scaling when unstaking with slashing.\\n /// @return uint96 DEFAULT_WEIGHT_SCALING\\n function weightScaling() external view returns (uint96);\\n\\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\\n /// @dev vestingWhitelist[contract] is true/false.\\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\\n\\n /// @dev user => flag whether user has admin role.\\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\\n /// \\tthis function works only with Team Vesting contracts\\n function admins(address isAdmin) external view returns (bool);\\n\\n /// @dev vesting contract code hash => flag whether it's registered code hash\\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\\n\\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\\n function vestingCheckpoints(uint256 date, uint32 index)\\n external\\n view\\n returns (Checkpoint memory);\\n\\n /// @notice The number of total vesting checkpoints for each date.\\n /// @dev numVestingCheckpoints[date] is a number.\\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\\n\\n ///@notice vesting registry contract PROXY address\\n function vestingRegistryLogic() external view returns (address);\\n\\n /// @dev user => flag whether user has pauser role.\\n function pausers(address isPauser) external view returns (bool);\\n\\n /// @dev Staking contract is paused\\n function paused() external view returns (bool);\\n\\n /// @dev Staking contract is frozen\\n function frozen() external view returns (bool);\\n\\n /*************************** StakingVestingModule ***************************/\\n\\n event VestingStakeSet(uint256 lockedTS, uint96 value);\\n\\n /**\\n * @notice Return flag whether the given address is a registered vesting contract.\\n * @param stakerAddress the address to check\\n */\\n function isVestingContract(address stakerAddress) external view returns (bool);\\n\\n /**\\n * @notice Remove vesting contract's code hash to a map of code hashes.\\n * @param vesting The address of Vesting contract.\\n * @dev We need it to use isVestingContract() function instead of isContract()\\n */\\n function removeContractCodeHash(address vesting) external;\\n\\n /**\\n * @notice Add vesting contract's code hash to a map of code hashes.\\n * @param vesting The address of Vesting contract.\\n * @dev We need it to use isVestingContract() function instead of isContract()\\n */\\n function addContractCodeHash(address vesting) external;\\n\\n /**\\n * @notice Determine the prior number of vested stake for an account until a\\n * certain lock date as of a block number.\\n * @dev Block number must be a finalized block or else this function\\n * will revert to prevent misinformation.\\n * @param date The lock date.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\\n external\\n view\\n returns (uint96);\\n\\n /**\\n * @notice Compute the voting power for a specific date.\\n * Power = stake * weight\\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\\n * @param startDate The date for which we need to know the power of the stake.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @return The stacking power.\\n * */\\n function weightedVestingStakeByDate(\\n uint256 date,\\n uint256 startDate,\\n uint256 blockNumber\\n ) external view returns (uint96 power);\\n\\n /**\\n * @notice Determine the prior weighted vested amount for an account as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * Used for fee sharing, not voting.\\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \\\"votes\\\"\\n * to add up token stake, and that could be misleading.\\n *\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The staking date to compute the power for.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\\n external\\n view\\n returns (uint96 votes);\\n\\n /**\\n * @notice Determine the prior number of stake for an account until a\\n * certain lock date as of a block number.\\n * @dev Block number must be a finalized block or else this function\\n * will revert to prevent misinformation.\\n * @param account The address of the account to check.\\n * @param date The lock date.\\n * @param blockNumber The block number to get the vote balance at.\\n * @return The number of votes the account had as of the given block.\\n * */\\n function getPriorUserStakeByDate(\\n address account,\\n uint256 date,\\n uint256 blockNumber\\n ) external view returns (uint96);\\n\\n /**\\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\\n * @param lockedDates The arrays of lock dates.\\n * @param values The array of values to add to the staked balance.\\n */\\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\\n\\n /**\\n * @notice sets vesting registry\\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\\n * various other functionalities without the necessity of linking it with Vesting Registry\\n */\\n function setVestingRegistry(address _vestingRegistryProxy) external;\\n\\n /*************************** StakingWithdrawModule ***************************/\\n\\n /**\\n * @notice Withdraw the given amount of tokens if they are unlocked.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * */\\n function withdraw(\\n uint96 amount,\\n uint256 until,\\n address receiver\\n ) external;\\n\\n /**\\n * @notice Withdraw the given amount of tokens.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\\n * */\\n function governanceWithdraw(\\n uint96 amount,\\n uint256 until,\\n address receiver\\n ) external;\\n\\n /**\\n * @notice Withdraw tokens for vesting contract.\\n * @param vesting The address of Vesting contract.\\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\\n * */\\n function governanceWithdrawVesting(address vesting, address receiver) external;\\n\\n /**\\n * @notice Get available and punished amount for withdrawing.\\n * @param amount The number of tokens to withdraw.\\n * @param until The date until which the tokens were staked.\\n * */\\n function getWithdrawAmounts(uint96 amount, uint256 until)\\n external\\n view\\n returns (uint96, uint96);\\n\\n /**\\n * @notice Allow the owner to unlock all tokens in case the staking contract\\n * is going to be replaced\\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\\n * The owner should not be able to just quickly unlock to withdraw his own\\n * tokens and lock again.\\n * @dev Last resort.\\n * */\\n function unlockAllTokens() external;\\n\\n /*************************** WeightedStakingModule ***************************/\\n\\n /**\\n * @notice Determine the prior weighted stake for an account as of a block number.\\n * Iterate through checkpoints adding up voting power.\\n * @dev Block number must be a finalized block or else this function will\\n * revert to prevent misinformation.\\n * Used for fee sharing, not voting.\\n *\\n * @param account The address of the account to check.\\n * @param blockNumber The block number to get the vote balance at.\\n * @param date The date/timestamp of the unstaking time.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function getPriorWeightedStake(\\n address account,\\n uint256 blockNumber,\\n uint256 date\\n ) external view returns (uint96 priorWeightedStake);\\n\\n /**\\n * @notice Compute the voting power for a specific date.\\n * Power = stake * weight\\n * TODO: WeightedStaking::weightedStakeByDate should probably better\\n * be internal instead of a public function.\\n * @param account The user address.\\n * @param date The staking date to compute the power for.\\n * @param startDate The date for which we need to know the power of the stake.\\n * @param blockNumber The block number, needed for checkpointing.\\n * @return The stacking power.\\n * */\\n function weightedStakeByDate(\\n address account,\\n uint256 date,\\n uint256 startDate,\\n uint256 blockNumber\\n ) external view returns (uint96 power);\\n\\n /**\\n * @notice Compute the weight for a specific date.\\n * @param date The unlocking date.\\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\\n * @return The weighted stake the account had as of the given block.\\n * */\\n function computeWeightByDate(uint256 date, uint256 startDate)\\n external\\n pure\\n returns (uint96 weight);\\n\\n /**\\n * @notice Returns public constant MAX_DURATION\\n * preserved for backwards compatibility\\n * Use getStorageMaxDurationToStakeTokens()\\n * @return uint96 MAX_DURATION for staking\\n **/\\n function MAX_DURATION() external view returns (uint256);\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() external view returns (address);\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() external view returns (bool);\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) external;\\n\\n /**\\n * @notice Governance withdraw vesting directly through staking contract.\\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\\n * This function only allows cancelling vesting contract of the TeamVesting type.\\n *\\n * @param vesting The vesting address.\\n * @param receiver The receiving address.\\n * @param startFrom The start value for the iterations.\\n */\\n function cancelTeamVesting(\\n address vesting,\\n address receiver,\\n uint256 startFrom\\n ) external;\\n\\n /**\\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\\n *\\n * @return max iteration value.\\n */\\n function getMaxVestingWithdrawIterations() external view returns (uint256);\\n\\n /**\\n * @dev set max withdraw iterations.\\n *\\n * @param maxIterations new max iterations value.\\n */\\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\\n}\\n\",\"keccak256\":\"0x720bd2cc1042cb4abc2bd3a6839131638eafd3d224571ad9ac21cae36625ec2e\"},\"contracts/governance/Vesting/IVesting.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for Vesting contract.\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n * This interface is used by VestingLogic contract to implement stakeTokens function\\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\\n * at a vesting instance.\\n */\\ninterface IVesting {\\n function duration() external returns (uint256);\\n\\n function endDate() external returns (uint256);\\n\\n function stakeTokens(uint256 amount) external;\\n\\n function tokenOwner() external view returns (address);\\n}\\n\",\"keccak256\":\"0x3482a1e27402655f85f5ff2cb06e0876e9bb94e1a63446a09e33babd60274b4b\"},\"contracts/governance/Vesting/VestingLogic.sol\":{\"content\":\"pragma solidity ^0.5.17;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../../openzeppelin/Ownable.sol\\\";\\nimport \\\"../../interfaces/IERC20.sol\\\";\\nimport \\\"../Staking/interfaces/IStaking.sol\\\";\\nimport \\\"../IFeeSharingCollector.sol\\\";\\nimport \\\"./IVesting.sol\\\";\\nimport \\\"../ApprovalReceiver.sol\\\";\\nimport \\\"./VestingStorage.sol\\\";\\nimport \\\"../../openzeppelin/SafeMath.sol\\\";\\n\\n/**\\n * @title Vesting Logic contract.\\n * @notice Staking, delegating and withdrawal functionality.\\n * @dev Deployed by a VestingFactory contract.\\n * */\\ncontract VestingLogic is IVesting, VestingStorage, ApprovalReceiver {\\n using SafeMath for uint256;\\n /* Events */\\n\\n event TokensStaked(address indexed caller, uint256 amount);\\n event VotesDelegated(address indexed caller, address delegatee);\\n event TokensWithdrawn(\\n address indexed caller,\\n address receiver,\\n uint256 startFrom,\\n uint256 end\\n );\\n event DividendsCollected(\\n address indexed caller,\\n address loanPoolToken,\\n address receiver,\\n uint32 maxCheckpoints\\n );\\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\\n\\n /* Modifiers */\\n\\n /**\\n * @dev Throws if called by any account other than the token owner or the contract owner.\\n */\\n modifier onlyOwners() {\\n require(msg.sender == tokenOwner || isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the token owner.\\n */\\n modifier onlyTokenOwner() {\\n require(msg.sender == tokenOwner, \\\"unauthorized\\\");\\n _;\\n }\\n\\n /* Functions */\\n\\n /**\\n * @notice Stakes tokens according to the vesting schedule.\\n * @param _amount The amount of tokens to stake.\\n * */\\n function stakeTokens(uint256 _amount) public {\\n _stakeTokens(msg.sender, _amount);\\n }\\n\\n /**\\n * @notice Stakes tokens according to the vesting schedule.\\n * @dev This function will be invoked from receiveApproval.\\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\\n * @param _sender The sender of SOV.approveAndCall\\n * @param _amount The amount of tokens to stake.\\n * */\\n function stakeTokensWithApproval(address _sender, uint256 _amount) public onlyThisContract {\\n _stakeTokens(_sender, _amount);\\n }\\n\\n /**\\n * @notice Stakes tokens according to the vesting schedule. Low level function.\\n * @dev Once here the allowance of tokens is taken for granted.\\n * @param _sender The sender of tokens to stake.\\n * @param _amount The amount of tokens to stake.\\n * */\\n function _stakeTokens(address _sender, uint256 _amount) internal {\\n /// @dev Maybe better to allow staking unil the cliff was reached.\\n if (startDate == 0) {\\n startDate = staking.timestampToLockDate(block.timestamp);\\n }\\n endDate = staking.timestampToLockDate(block.timestamp + duration);\\n\\n /// @dev Transfer the tokens to this contract.\\n bool success = SOV.transferFrom(_sender, address(this), _amount);\\n require(success);\\n\\n /// @dev Allow the staking contract to access them.\\n SOV.approve(address(staking), _amount);\\n\\n staking.stakeBySchedule(_amount, cliff, duration, FOUR_WEEKS, address(this), tokenOwner);\\n\\n emit TokensStaked(_sender, _amount);\\n }\\n\\n /**\\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\\n * to `delegatee`.\\n * @param _delegatee The address to delegate votes to.\\n * */\\n function delegate(address _delegatee) public onlyTokenOwner {\\n require(_delegatee != address(0), \\\"delegatee address invalid\\\");\\n\\n /// @dev Withdraw for each unlocked position.\\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\\n ///\\t\\tworkaround found, but it doesn't work with TWO_WEEKS\\n for (uint256 i = startDate + cliff; i <= endDate; i += FOUR_WEEKS) {\\n staking.delegate(_delegatee, i);\\n }\\n emit VotesDelegated(msg.sender, _delegatee);\\n }\\n\\n /**\\n * @notice Withdraws unlocked tokens from the staking contract and\\n * forwards them to an address specified by the token owner.\\n * @param receiver The receiving address.\\n * */\\n function withdrawTokens(address receiver) public onlyOwners {\\n uint256 startFrom = startDate + cliff;\\n _withdrawTokens(receiver, startFrom, block.timestamp);\\n }\\n\\n /**\\n * @notice Withdraws unlocked tokens partially (based on the max withdraw iteration that has been set) from the staking contract and\\n * forwards them to an address specified by the token owner.\\n * @param receiver The receiving address.\\n * @param startFrom The start value for the iterations.\\n * @param maxWithdrawIterations max withdrawal iteration to work around block gas limit issue.\\n * */\\n function withdrawTokensStartingFrom(\\n address receiver,\\n uint256 startFrom,\\n uint256 maxWithdrawIterations\\n ) public onlyOwners {\\n uint256 defaultStartFrom = startDate + cliff;\\n\\n startFrom = _timestampToLockDate(startFrom);\\n startFrom = startFrom < defaultStartFrom ? defaultStartFrom : startFrom;\\n\\n // @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\\n uint256 maxWithdrawDate = (startFrom + (FOUR_WEEKS * (maxWithdrawIterations.sub(1))));\\n uint256 endAt = endDate < maxWithdrawDate ? endDate : maxWithdrawDate;\\n _withdrawTokens(receiver, startFrom, endAt);\\n }\\n\\n /**\\n * @notice Withdraws tokens from the staking contract and forwards them\\n * to an address specified by the token owner. Low level function.\\n * @dev Once here the caller permission is taken for granted.\\n * @param receiver The receiving address.\\n * @param startFrom start withdrawal from date.\\n * @param endAt end time for regular withdrawal\\n * or just unlocked tokens (false).\\n * */\\n function _withdrawTokens(\\n address receiver,\\n uint256 startFrom,\\n uint256 endAt\\n ) internal {\\n require(receiver != address(0), \\\"receiver address invalid\\\");\\n\\n uint96 stake;\\n\\n /// @dev Usually we just need to iterate over the possible dates until now.\\n uint256 end;\\n\\n if (staking.allUnlocked()) {\\n end = endAt < endDate ? endAt : endDate;\\n } else {\\n end = endAt < block.timestamp ? endAt : block.timestamp;\\n if (end > endDate) end = endDate;\\n }\\n\\n /// @dev Withdraw for each unlocked position.\\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\\n ///\\t\\tworkaround found, but it doesn't work with TWO_WEEKS\\n for (uint256 i = startFrom; i <= end; i += FOUR_WEEKS) {\\n /// @dev Read amount to withdraw.\\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number - 1);\\n\\n /// @dev Withdraw if > 0\\n if (stake > 0) {\\n staking.withdraw(stake, i, receiver);\\n }\\n }\\n\\n emit TokensWithdrawn(msg.sender, receiver, startFrom, end);\\n }\\n\\n /**\\n * @notice Collect dividends from fee sharing proxy.\\n * @param _loanPoolToken The loan pool token address.\\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\\n * @param _receiver The receiver of tokens or msg.sender\\n * */\\n function collectDividends(\\n address _loanPoolToken,\\n uint32 _maxCheckpoints,\\n address _receiver\\n ) public onlyOwners {\\n require(_receiver != address(0), \\\"receiver address invalid\\\");\\n\\n /// @dev Invokes the fee sharing proxy.\\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\\n\\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\\n }\\n\\n /**\\n * @notice Allows the owners to migrate the positions\\n * to a new staking contract.\\n * */\\n function migrateToNewStakingContract() public onlyOwners {\\n staking.migrateToNewStakingContract();\\n staking = IStaking(staking.newStakingContract());\\n emit MigratedToNewStakingContract(msg.sender, address(staking));\\n }\\n\\n /**\\n * @notice Overrides default ApprovalReceiver._getToken function to\\n * register SOV token on this contract.\\n * @return The address of SOV token.\\n * */\\n function _getToken() internal view returns (address) {\\n return address(SOV);\\n }\\n\\n /**\\n * @notice Overrides default ApprovalReceiver._getSelectors function to\\n * register stakeTokensWithApproval selector on this contract.\\n * @return The array of registered selectors on this contract.\\n * */\\n function _getSelectors() internal pure returns (bytes4[] memory) {\\n bytes4[] memory selectors = new bytes4[](1);\\n selectors[0] = this.stakeTokensWithApproval.selector;\\n return selectors;\\n }\\n\\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\\n // Optimize gas costs by reading kickoffTS from storage only once.\\n uint256 start = startDate + cliff;\\n require(timestamp >= start, \\\"timestamp < contract creation\\\"); // WS23\\n /**\\n * @dev If staking timestamp does not match any of the unstaking dates\\n * , set the lockDate to the closest one before the timestamp.\\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\\n * */\\n uint256 periodFromKickoff = (timestamp - start) / FOUR_WEEKS;\\n lockDate = periodFromKickoff * FOUR_WEEKS + start;\\n }\\n}\\n\",\"keccak256\":\"0x991b246a9930d8f2605d3088965159f15fd8a0e4ddbb64b9f21d4706d89a8ef8\"},\"contracts/governance/Vesting/VestingStorage.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\nimport \\\"../../openzeppelin/Ownable.sol\\\";\\nimport \\\"../../interfaces/IERC20.sol\\\";\\nimport \\\"../Staking/interfaces/IStaking.sol\\\";\\nimport \\\"../IFeeSharingCollector.sol\\\";\\n\\n/**\\n * @title Vesting Storage Contract.\\n *\\n * @notice This contract is just the storage required for vesting.\\n * It is parent of VestingLogic and TeamVesting.\\n *\\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\\n * */\\ncontract VestingStorage is Ownable {\\n /// @notice The SOV token contract.\\n IERC20 public SOV;\\n\\n /// @notice The staking contract address.\\n IStaking public staking;\\n\\n /// @notice The owner of the vested tokens.\\n address public tokenOwner;\\n\\n /// @notice Fee sharing Proxy.\\n IFeeSharingCollector public feeSharingCollector;\\n\\n /// @notice The cliff. After this time period the tokens begin to unlock.\\n uint256 public cliff;\\n\\n /// @notice The duration. After this period all tokens will have been unlocked.\\n uint256 public duration;\\n\\n /// @notice The start date of the vesting.\\n uint256 public startDate;\\n\\n /// @notice The end date of the vesting.\\n uint256 public endDate;\\n\\n /// @notice Constant used for computing the vesting dates.\\n uint256 constant FOUR_WEEKS = 4 weeks;\\n}\\n\",\"keccak256\":\"0xf70f579d357d8f0aa0839824c1a1d66713c3cd42a58118d2893a35b52baaa140\"},\"contracts/interfaces/IERC20.sol\":{\"content\":\"/**\\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\\n * Licensed under the Apache License, Version 2.0.\\n */\\n\\npragma solidity >=0.5.0 <0.6.0;\\n\\ncontract IERC20 {\\n string public name;\\n uint8 public decimals;\\n string public symbol;\\n\\n function totalSupply() external view returns (uint256);\\n\\n function balanceOf(address _who) external view returns (uint256);\\n\\n function allowance(address _owner, address _spender) external view returns (uint256);\\n\\n function approve(address _spender, uint256 _value) external returns (bool);\\n\\n function transfer(address _to, uint256 _value) external returns (bool);\\n\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _value\\n ) external returns (bool);\\n\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\\n\",\"keccak256\":\"0xbc0c9bb48f19651930ec9aff366b2e11a1abf89c846e4b2d52d8102b15ce6721\"},\"contracts/openzeppelin/Context.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/*\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with GSN meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\ncontract Context {\\n // Empty internal constructor, to prevent people from mistakenly deploying\\n // an instance of this contract, which should be used via inheritance.\\n constructor() internal {}\\n\\n // solhint-disable-previous-line no-empty-blocks\\n\\n function _msgSender() internal view returns (address payable) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view returns (bytes memory) {\\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0x7860cb1591dbd66bb497c60c46866d9fcdb56c73306ed86b25801000af1c7b2b\"},\"contracts/openzeppelin/Ownable.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\nimport \\\"./Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() internal {\\n address msgSender = _msgSender();\\n _owner = msgSender;\\n emit OwnershipTransferred(address(0), msgSender);\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(isOwner(), \\\"unauthorized\\\");\\n _;\\n }\\n\\n /**\\n * @dev Returns true if the caller is the current owner.\\n */\\n function isOwner() public view returns (bool) {\\n return _msgSender() == _owner;\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public onlyOwner {\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n */\\n function _transferOwnership(address newOwner) internal {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n emit OwnershipTransferred(_owner, newOwner);\\n _owner = newOwner;\\n }\\n}\\n\",\"keccak256\":\"0x94496c375b3e82d87d7f01ce1577f008fab374312cf93012a0eca716e6aadb3a\"},\"contracts/openzeppelin/SafeMath.sol\":{\"content\":\"pragma solidity >=0.5.0 <0.6.0;\\n\\n/**\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\\n return divCeil(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Integer division of two numbers, rounding up and truncating the quotient\\n */\\n function divCeil(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b != 0, errorMessage);\\n\\n if (a == 0) {\\n return 0;\\n }\\n uint256 c = ((a - 1) / b) + 1;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(\\n uint256 a,\\n uint256 b,\\n string memory errorMessage\\n ) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n\\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\\n return _a < _b ? _a : _b;\\n }\\n}\\n\",\"keccak256\":\"0xbff8d6273e1a6870d1a142c0c23acd63a4dd47760f250390f49ee56333bcb6e8\"},\"contracts/token/IApproveAndCall.sol\":{\"content\":\"pragma solidity ^0.5.17;\\n\\n/**\\n * @title Interface for contract governance/ApprovalReceiver.sol\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n */\\ninterface IApproveAndCall {\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _sender The sender of SOV.approveAndCall function.\\n * @param _amount The amount was approved.\\n * @param _token The address of token.\\n * @param _data The data will be used for low level call.\\n * */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x0ca93f8436a4d81d80de5ea9214139b490d96f708f09c975a0869ce9abc61635\"}},\"version\":1}", + "bytecode": "0x608060405260006100176001600160e01b0361006616565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35061006a565b3390565b611b7f806100796000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806362dc2f35116100ad5780638f32d59b116100715780638f32d59b1461020a5780638f4ffcb11461021f578063a3e6761014610232578063c24a0f8b1461023a578063f2fde38b1461024257610121565b806362dc2f35146101b45780636b7dbb2d146101c75780637547c7a3146101cf57806381e45268146101e25780638da5cb5b146101f557610121565b80634552a7ae116100f45780634552a7ae1461016957806349df728c1461017e5780634cf088d9146101915780635419675f146101995780635c19a95c146101a157610121565b806308dcb360146101265780630b97bc86146101445780630fb5a6b41461015957806313d033c014610161575b600080fd5b61012e610255565b60405161013b919061192c565b60405180910390f35b61014c610264565b60405161013b91906119db565b61014c61026a565b61014c610270565b61017c61017736600461141e565b610276565b005b61017c61018c366004611322565b610320565b61012e61036e565b61017c61037d565b61017c6101af366004611322565b6104fe565b61017c6101c236600461146b565b610615565b61012e610722565b61017c6101dd36600461150f565b610731565b61017c6101f0366004611366565b61073e565b6101fd610767565b60405161013b9190611862565b610212610776565b60405161013b919061191e565b61017c61022d3660046113a0565b61079a565b6101fd61098e565b61014c61099d565b61017c610250366004611322565b6109a3565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b6003546001600160a01b03163314806102925750610292610776565b6102b75760405162461bcd60e51b81526004016102ae9061199b565b60405180910390fd5b600554600754016102c7836109d0565b92508083106102d657826102d8565b805b925060006102ed83600163ffffffff610a1416565b6224ea00028401905060008160085410610307578161030b565b6008545b9050610318868683610a5f565b505050505050565b6003546001600160a01b031633148061033c575061033c610776565b6103585760405162461bcd60e51b81526004016102ae9061199b565b6005546007540161036a828242610a5f565b5050565b6002546001600160a01b031681565b6003546001600160a01b03163314806103995750610399610776565b6103b55760405162461bcd60e51b81526004016102ae9061199b565b600260009054906101000a90046001600160a01b03166001600160a01b0316635419675f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561040557600080fd5b505af1158015610419573d6000803e3d6000fd5b50505050600260009054906101000a90046001600160a01b03166001600160a01b031663ae81dfe46040518163ffffffff1660e01b815260040160206040518083038186803b15801561046b57600080fd5b505afa15801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506104a39190810190611348565b600280546001600160a01b0319166001600160a01b03928316179081905560405133927f9613f431247983a83a2b3667aa63a5174194ac89328dfadc69be44409521b3c1926104f492911690611862565b60405180910390a2565b6003546001600160a01b031633146105285760405162461bcd60e51b81526004016102ae9061199b565b6001600160a01b03811661054e5760405162461bcd60e51b81526004016102ae906119ab565b600554600754015b60085481116105d05760025460405163026e402b60e01b81526001600160a01b039091169063026e402b9061059190859085906004016118c0565b600060405180830381600087803b1580156105ab57600080fd5b505af11580156105bf573d6000803e3d6000fd5b505050506224ea0081019050610556565b50336001600160a01b03167f734a802cc194e2139bfcc08e10336f24dfa14fd2c5ab70268d8706c0558670668260405161060a9190611862565b60405180910390a250565b6003546001600160a01b03163314806106315750610631610776565b61064d5760405162461bcd60e51b81526004016102ae9061199b565b6001600160a01b0381166106735760405162461bcd60e51b81526004016102ae906119bb565b6004805460405163a965b3a960e01b81526001600160a01b039091169163a965b3a9916106a691879187918791016118f6565b600060405180830381600087803b1580156106c057600080fd5b505af11580156106d4573d6000803e3d6000fd5b50505050336001600160a01b03167f5fa0b381cb4bdbc7063d1e5c78b90a634a6d6a12d6cb6fabe450fd4b8d1eab0184838560405161071593929190611898565b60405180910390a2505050565b6004546001600160a01b031681565b61073b3382610cb2565b50565b33301461075d5760405162461bcd60e51b81526004016102ae9061199b565b61036a8282610cb2565b6000546001600160a01b031690565b600080546001600160a01b031661078b610f94565b6001600160a01b031614905090565b6107a2610f98565b6001600160a01b0316336001600160a01b0316146107d25760405162461bcd60e51b81526004016102ae9061199b565b336001600160a01b038416146107fa5760405162461bcd60e51b81526004016102ae9061199b565b60006060610806610fa7565b9050600061084985858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fff92505050565b905060005b82518110156108975782818151811061086357fe5b60200260200101516001600160e01b031916826001600160e01b031916141561088f5760019350610897565b60010161084e565b50826108b55760405162461bcd60e51b81526004016102ae9061197b565b600080600060201b87876040516020016108d193929190611830565b6040516020818303038152906040528060200190516108f391908101906114cc565b9093509150506001600160a01b03808316908b16146109245760405162461bcd60e51b81526004016102ae9061198b565b8881146109435760405162461bcd60e51b81526004016102ae906119cb565b61098287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061100692505050565b50505050505050505050565b6003546001600160a01b031681565b60085481565b6109ab610776565b6109c75760405162461bcd60e51b81526004016102ae9061199b565b61073b816110e0565b60055460075460009101808310156109fa5760405162461bcd60e51b81526004016102ae9061194b565b60006224ea00828503046224ea0002919091019392505050565b6000610a5683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611161565b90505b92915050565b6001600160a01b038316610a855760405162461bcd60e51b81526004016102ae906119bb565b600080600260009054906101000a90046001600160a01b03166001600160a01b0316639929e8866040518163ffffffff1660e01b815260040160206040518083038186803b158015610ad657600080fd5b505afa158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b0e91908101906114ae565b15610b2d576008548310610b2457600854610b26565b825b9050610b4d565b428310610b3a5742610b3c565b825b9050600854811115610b4d57506008545b835b818111610c65576002546040516367bdb42560e11b81526001600160a01b039091169063cf7b684a90610b8e90309085906000194301906004016118db565b60206040518083038186803b158015610ba657600080fd5b505afa158015610bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bde919081019061154b565b92506bffffffffffffffffffffffff831615610c5b576002546040516336adb29160e21b81526001600160a01b039091169063dab6ca4490610c2890869085908b90600401611a43565b600060405180830381600087803b158015610c4257600080fd5b505af1158015610c56573d6000803e3d6000fd5b505050505b6224ea0001610b4f565b50336001600160a01b03167f6b83b455c317523498e4e86849438d4356ad79ba6b355a5e6d5bc05eca6c780f868684604051610ca3939291906118db565b60405180910390a25050505050565b600754610d3d576002546040516372ec979560e01b81526001600160a01b03909116906372ec979590610ce99042906004016119db565b60206040518083038186803b158015610d0157600080fd5b505afa158015610d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d39919081019061152d565b6007555b6002546006546040516372ec979560e01b81526001600160a01b03909216916372ec979591610d739142909101906004016119db565b60206040518083038186803b158015610d8b57600080fd5b505afa158015610d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610dc3919081019061152d565b6008556001546040516323b872dd60e01b81526000916001600160a01b0316906323b872dd90610dfb90869030908790600401611870565b602060405180830381600087803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e4d91908101906114ae565b905080610e5957600080fd5b60015460025460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392610e8f9291169086906004016118c0565b602060405180830381600087803b158015610ea957600080fd5b505af1158015610ebd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ee191908101906114ae565b5060025460055460065460035460405163c1b79b0560e01b81526001600160a01b039485169463c1b79b0594610f29948994919390926224ea009230929116906004016119e9565b600060405180830381600087803b158015610f4357600080fd5b505af1158015610f57573d6000803e3d6000fd5b50505050826001600160a01b03167fb539ca1e5c8d398ddf1c41c30166f33404941683be4683319b57669a93dad4ef8360405161071591906119db565b3390565b6001546001600160a01b031690565b604080516001808252818301909252606091829190602080830190803883390190505090506381e4526860e01b81600081518110610fe157fe5b6001600160e01b031990921660209283029190910190910152905090565b6020015190565b60006060306001600160a01b0316836040516110229190611856565b6000604051808303816000865af19150503d806000811461105f576040519150601f19603f3d011682016040523d82523d6000602084013e611064565b606091505b5091509150816110db57604481511161108f5760405162461bcd60e51b81526004016102ae9061195b565b6110c26040518060400160405280601181526020017003932b1b2b4bb32a0b8383937bb30b61d1607d1b81525082611192565b60405162461bcd60e51b81526004016102ae919061193a565b505050565b6001600160a01b0381166111065760405162461bcd60e51b81526004016102ae9061196b565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b600081848411156111855760405162461bcd60e51b81526004016102ae919061193a565b50508183035b9392505050565b6060808390506060839050606060448251845101036040519080825280601f01601f1916602001820160405280156111d1576020820181803883390190505b509050806000805b855181101561122a578581815181106111ee57fe5b602001015160f81c60f81b83838060010194508151811061120b57fe5b60200101906001600160f81b031916908160001a9053506001016111d9565b5060445b845181101561127f5784818151811061124357fe5b602001015160f81c60f81b83838060010194508151811061126057fe5b60200101906001600160f81b031916908160001a90535060010161122e565b5090979650505050505050565b8035610a5981611b04565b8051610a5981611b04565b8051610a5981611b18565b8051610a5981611b21565b60008083601f8401126112ca57600080fd5b50813567ffffffffffffffff8111156112e257600080fd5b6020830191508360018202830111156112fa57600080fd5b9250929050565b8035610a5981611b21565b8035610a5981611b2a565b8051610a5981611b33565b60006020828403121561133457600080fd5b6000611340848461128c565b949350505050565b60006020828403121561135a57600080fd5b60006113408484611297565b6000806040838503121561137957600080fd5b6000611385858561128c565b925050602061139685828601611301565b9150509250929050565b6000806000806000608086880312156113b857600080fd5b60006113c4888861128c565b95505060206113d588828901611301565b94505060406113e68882890161128c565b935050606086013567ffffffffffffffff81111561140357600080fd5b61140f888289016112b8565b92509250509295509295909350565b60008060006060848603121561143357600080fd5b600061143f868661128c565b935050602061145086828701611301565b925050604061146186828701611301565b9150509250925092565b60008060006060848603121561148057600080fd5b600061148c868661128c565b935050602061149d8682870161130c565b92505060406114618682870161128c565b6000602082840312156114c057600080fd5b600061134084846112a2565b6000806000606084860312156114e157600080fd5b60006114ed86866112ad565b93505060206114fe86828701611297565b9250506040611461868287016112ad565b60006020828403121561152157600080fd5b60006113408484611301565b60006020828403121561153f57600080fd5b600061134084846112ad565b60006020828403121561155d57600080fd5b60006113408484611317565b61157281611a70565b82525050565b61157281611a7b565b61157261158d82611a80565b611a8a565b600061159e8385611a62565b93506115ab838584611abe565b50500190565b60006115bc82611a5e565b6115c68185611a62565b93506115d6818560208601611aca565b9290920192915050565b61157281611ab3565b60006115f482611a5e565b6115fe8185611a67565b935061160e818560208601611aca565b61161781611afa565b9093019392505050565b600061162e601d83611a67565b7f74696d657374616d70203c20636f6e7472616374206372656174696f6e000000815260200192915050565b6000611667603083611a67565b7f72656365697665417070726f76616c3a205472616e73616374696f6e2065786581526f31baba34b7b7103932bb32b93a32b21760811b602082015260400192915050565b60006116b9602683611a67565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000611701601583611a67565b741b595d1a1bd9081a5cc81b9bdd08185b1b1bddd959605a1b815260200192915050565b6000611732600f83611a67565b6e0e6cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b600061175d600c83611a67565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6000611785601983611a67565b7f64656c656761746565206164647265737320696e76616c696400000000000000815260200192915050565b60006117be601883611a67565b7f7265636569766572206164647265737320696e76616c69640000000000000000815260200192915050565b60006117f7600f83611a67565b6e0c2dadeeadce840dad2e6dac2e8c6d608b1b815260200192915050565b61157281611a8a565b61157281611a99565b61157281611aa2565b600061183c8286611581565b601c8201915061184d828486611592565b95945050505050565b600061118b82846115b1565b60208101610a598284611569565b6060810161187e8286611569565b61188b6020830185611569565b6113406040830184611815565b606081016118a68286611569565b6118b36020830185611569565b611340604083018461181e565b604081016118ce8285611569565b61118b6020830184611815565b606081016118e98286611569565b61188b6020830185611815565b606081016119048286611569565b611911602083018561181e565b6113406040830184611569565b60208101610a598284611578565b60208101610a5982846115e0565b60208082528101610a5681846115e9565b60208082528101610a5981611621565b60208082528101610a598161165a565b60208082528101610a59816116ac565b60208082528101610a59816116f4565b60208082528101610a5981611725565b60208082528101610a5981611750565b60208082528101610a5981611778565b60208082528101610a59816117b1565b60208082528101610a59816117ea565b60208101610a598284611815565b60c081016119f78289611815565b611a046020830188611815565b611a116040830187611815565b611a1e6060830186611815565b611a2b6080830185611569565b611a3860a0830184611569565b979650505050505050565b60608101611a518286611827565b6119116020830185611815565b5190565b919050565b90815260200190565b6000610a5982611a8d565b151590565b63ffffffff191690565b90565b6001600160a01b031690565b63ffffffff1690565b6bffffffffffffffffffffffff1690565b6000610a5982611a70565b82818337506000910152565b60005b83811015611ae5578181015183820152602001611acd565b83811115611af4576000848401525b50505050565b601f01601f191690565b611b0d81611a70565b811461073b57600080fd5b611b0d81611a7b565b611b0d81611a8a565b611b0d81611a99565b611b0d81611aa256fea365627a7a72315820a89ede248f65f6f968df90376cf30f13581a3027604ed8923bf505e54a09ee6b6c6578706572696d656e74616cf564736f6c63430005110040", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106101215760003560e01c806362dc2f35116100ad5780638f32d59b116100715780638f32d59b1461020a5780638f4ffcb11461021f578063a3e6761014610232578063c24a0f8b1461023a578063f2fde38b1461024257610121565b806362dc2f35146101b45780636b7dbb2d146101c75780637547c7a3146101cf57806381e45268146101e25780638da5cb5b146101f557610121565b80634552a7ae116100f45780634552a7ae1461016957806349df728c1461017e5780634cf088d9146101915780635419675f146101995780635c19a95c146101a157610121565b806308dcb360146101265780630b97bc86146101445780630fb5a6b41461015957806313d033c014610161575b600080fd5b61012e610255565b60405161013b919061192c565b60405180910390f35b61014c610264565b60405161013b91906119db565b61014c61026a565b61014c610270565b61017c61017736600461141e565b610276565b005b61017c61018c366004611322565b610320565b61012e61036e565b61017c61037d565b61017c6101af366004611322565b6104fe565b61017c6101c236600461146b565b610615565b61012e610722565b61017c6101dd36600461150f565b610731565b61017c6101f0366004611366565b61073e565b6101fd610767565b60405161013b9190611862565b610212610776565b60405161013b919061191e565b61017c61022d3660046113a0565b61079a565b6101fd61098e565b61014c61099d565b61017c610250366004611322565b6109a3565b6001546001600160a01b031681565b60075481565b60065481565b60055481565b6003546001600160a01b03163314806102925750610292610776565b6102b75760405162461bcd60e51b81526004016102ae9061199b565b60405180910390fd5b600554600754016102c7836109d0565b92508083106102d657826102d8565b805b925060006102ed83600163ffffffff610a1416565b6224ea00028401905060008160085410610307578161030b565b6008545b9050610318868683610a5f565b505050505050565b6003546001600160a01b031633148061033c575061033c610776565b6103585760405162461bcd60e51b81526004016102ae9061199b565b6005546007540161036a828242610a5f565b5050565b6002546001600160a01b031681565b6003546001600160a01b03163314806103995750610399610776565b6103b55760405162461bcd60e51b81526004016102ae9061199b565b600260009054906101000a90046001600160a01b03166001600160a01b0316635419675f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561040557600080fd5b505af1158015610419573d6000803e3d6000fd5b50505050600260009054906101000a90046001600160a01b03166001600160a01b031663ae81dfe46040518163ffffffff1660e01b815260040160206040518083038186803b15801561046b57600080fd5b505afa15801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506104a39190810190611348565b600280546001600160a01b0319166001600160a01b03928316179081905560405133927f9613f431247983a83a2b3667aa63a5174194ac89328dfadc69be44409521b3c1926104f492911690611862565b60405180910390a2565b6003546001600160a01b031633146105285760405162461bcd60e51b81526004016102ae9061199b565b6001600160a01b03811661054e5760405162461bcd60e51b81526004016102ae906119ab565b600554600754015b60085481116105d05760025460405163026e402b60e01b81526001600160a01b039091169063026e402b9061059190859085906004016118c0565b600060405180830381600087803b1580156105ab57600080fd5b505af11580156105bf573d6000803e3d6000fd5b505050506224ea0081019050610556565b50336001600160a01b03167f734a802cc194e2139bfcc08e10336f24dfa14fd2c5ab70268d8706c0558670668260405161060a9190611862565b60405180910390a250565b6003546001600160a01b03163314806106315750610631610776565b61064d5760405162461bcd60e51b81526004016102ae9061199b565b6001600160a01b0381166106735760405162461bcd60e51b81526004016102ae906119bb565b6004805460405163a965b3a960e01b81526001600160a01b039091169163a965b3a9916106a691879187918791016118f6565b600060405180830381600087803b1580156106c057600080fd5b505af11580156106d4573d6000803e3d6000fd5b50505050336001600160a01b03167f5fa0b381cb4bdbc7063d1e5c78b90a634a6d6a12d6cb6fabe450fd4b8d1eab0184838560405161071593929190611898565b60405180910390a2505050565b6004546001600160a01b031681565b61073b3382610cb2565b50565b33301461075d5760405162461bcd60e51b81526004016102ae9061199b565b61036a8282610cb2565b6000546001600160a01b031690565b600080546001600160a01b031661078b610f94565b6001600160a01b031614905090565b6107a2610f98565b6001600160a01b0316336001600160a01b0316146107d25760405162461bcd60e51b81526004016102ae9061199b565b336001600160a01b038416146107fa5760405162461bcd60e51b81526004016102ae9061199b565b60006060610806610fa7565b9050600061084985858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610fff92505050565b905060005b82518110156108975782818151811061086357fe5b60200260200101516001600160e01b031916826001600160e01b031916141561088f5760019350610897565b60010161084e565b50826108b55760405162461bcd60e51b81526004016102ae9061197b565b600080600060201b87876040516020016108d193929190611830565b6040516020818303038152906040528060200190516108f391908101906114cc565b9093509150506001600160a01b03808316908b16146109245760405162461bcd60e51b81526004016102ae9061198b565b8881146109435760405162461bcd60e51b81526004016102ae906119cb565b61098287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061100692505050565b50505050505050505050565b6003546001600160a01b031681565b60085481565b6109ab610776565b6109c75760405162461bcd60e51b81526004016102ae9061199b565b61073b816110e0565b60055460075460009101808310156109fa5760405162461bcd60e51b81526004016102ae9061194b565b60006224ea00828503046224ea0002919091019392505050565b6000610a5683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611161565b90505b92915050565b6001600160a01b038316610a855760405162461bcd60e51b81526004016102ae906119bb565b600080600260009054906101000a90046001600160a01b03166001600160a01b0316639929e8866040518163ffffffff1660e01b815260040160206040518083038186803b158015610ad657600080fd5b505afa158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610b0e91908101906114ae565b15610b2d576008548310610b2457600854610b26565b825b9050610b4d565b428310610b3a5742610b3c565b825b9050600854811115610b4d57506008545b835b818111610c65576002546040516367bdb42560e11b81526001600160a01b039091169063cf7b684a90610b8e90309085906000194301906004016118db565b60206040518083038186803b158015610ba657600080fd5b505afa158015610bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610bde919081019061154b565b92506bffffffffffffffffffffffff831615610c5b576002546040516336adb29160e21b81526001600160a01b039091169063dab6ca4490610c2890869085908b90600401611a43565b600060405180830381600087803b158015610c4257600080fd5b505af1158015610c56573d6000803e3d6000fd5b505050505b6224ea0001610b4f565b50336001600160a01b03167f6b83b455c317523498e4e86849438d4356ad79ba6b355a5e6d5bc05eca6c780f868684604051610ca3939291906118db565b60405180910390a25050505050565b600754610d3d576002546040516372ec979560e01b81526001600160a01b03909116906372ec979590610ce99042906004016119db565b60206040518083038186803b158015610d0157600080fd5b505afa158015610d15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d39919081019061152d565b6007555b6002546006546040516372ec979560e01b81526001600160a01b03909216916372ec979591610d739142909101906004016119db565b60206040518083038186803b158015610d8b57600080fd5b505afa158015610d9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610dc3919081019061152d565b6008556001546040516323b872dd60e01b81526000916001600160a01b0316906323b872dd90610dfb90869030908790600401611870565b602060405180830381600087803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610e4d91908101906114ae565b905080610e5957600080fd5b60015460025460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392610e8f9291169086906004016118c0565b602060405180830381600087803b158015610ea957600080fd5b505af1158015610ebd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ee191908101906114ae565b5060025460055460065460035460405163c1b79b0560e01b81526001600160a01b039485169463c1b79b0594610f29948994919390926224ea009230929116906004016119e9565b600060405180830381600087803b158015610f4357600080fd5b505af1158015610f57573d6000803e3d6000fd5b50505050826001600160a01b03167fb539ca1e5c8d398ddf1c41c30166f33404941683be4683319b57669a93dad4ef8360405161071591906119db565b3390565b6001546001600160a01b031690565b604080516001808252818301909252606091829190602080830190803883390190505090506381e4526860e01b81600081518110610fe157fe5b6001600160e01b031990921660209283029190910190910152905090565b6020015190565b60006060306001600160a01b0316836040516110229190611856565b6000604051808303816000865af19150503d806000811461105f576040519150601f19603f3d011682016040523d82523d6000602084013e611064565b606091505b5091509150816110db57604481511161108f5760405162461bcd60e51b81526004016102ae9061195b565b6110c26040518060400160405280601181526020017003932b1b2b4bb32a0b8383937bb30b61d1607d1b81525082611192565b60405162461bcd60e51b81526004016102ae919061193a565b505050565b6001600160a01b0381166111065760405162461bcd60e51b81526004016102ae9061196b565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b600081848411156111855760405162461bcd60e51b81526004016102ae919061193a565b50508183035b9392505050565b6060808390506060839050606060448251845101036040519080825280601f01601f1916602001820160405280156111d1576020820181803883390190505b509050806000805b855181101561122a578581815181106111ee57fe5b602001015160f81c60f81b83838060010194508151811061120b57fe5b60200101906001600160f81b031916908160001a9053506001016111d9565b5060445b845181101561127f5784818151811061124357fe5b602001015160f81c60f81b83838060010194508151811061126057fe5b60200101906001600160f81b031916908160001a90535060010161122e565b5090979650505050505050565b8035610a5981611b04565b8051610a5981611b04565b8051610a5981611b18565b8051610a5981611b21565b60008083601f8401126112ca57600080fd5b50813567ffffffffffffffff8111156112e257600080fd5b6020830191508360018202830111156112fa57600080fd5b9250929050565b8035610a5981611b21565b8035610a5981611b2a565b8051610a5981611b33565b60006020828403121561133457600080fd5b6000611340848461128c565b949350505050565b60006020828403121561135a57600080fd5b60006113408484611297565b6000806040838503121561137957600080fd5b6000611385858561128c565b925050602061139685828601611301565b9150509250929050565b6000806000806000608086880312156113b857600080fd5b60006113c4888861128c565b95505060206113d588828901611301565b94505060406113e68882890161128c565b935050606086013567ffffffffffffffff81111561140357600080fd5b61140f888289016112b8565b92509250509295509295909350565b60008060006060848603121561143357600080fd5b600061143f868661128c565b935050602061145086828701611301565b925050604061146186828701611301565b9150509250925092565b60008060006060848603121561148057600080fd5b600061148c868661128c565b935050602061149d8682870161130c565b92505060406114618682870161128c565b6000602082840312156114c057600080fd5b600061134084846112a2565b6000806000606084860312156114e157600080fd5b60006114ed86866112ad565b93505060206114fe86828701611297565b9250506040611461868287016112ad565b60006020828403121561152157600080fd5b60006113408484611301565b60006020828403121561153f57600080fd5b600061134084846112ad565b60006020828403121561155d57600080fd5b60006113408484611317565b61157281611a70565b82525050565b61157281611a7b565b61157261158d82611a80565b611a8a565b600061159e8385611a62565b93506115ab838584611abe565b50500190565b60006115bc82611a5e565b6115c68185611a62565b93506115d6818560208601611aca565b9290920192915050565b61157281611ab3565b60006115f482611a5e565b6115fe8185611a67565b935061160e818560208601611aca565b61161781611afa565b9093019392505050565b600061162e601d83611a67565b7f74696d657374616d70203c20636f6e7472616374206372656174696f6e000000815260200192915050565b6000611667603083611a67565b7f72656365697665417070726f76616c3a205472616e73616374696f6e2065786581526f31baba34b7b7103932bb32b93a32b21760811b602082015260400192915050565b60006116b9602683611a67565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181526564647265737360d01b602082015260400192915050565b6000611701601583611a67565b741b595d1a1bd9081a5cc81b9bdd08185b1b1bddd959605a1b815260200192915050565b6000611732600f83611a67565b6e0e6cadcc8cae440dad2e6dac2e8c6d608b1b815260200192915050565b600061175d600c83611a67565b6b1d5b985d5d1a1bdc9a5e995960a21b815260200192915050565b6000611785601983611a67565b7f64656c656761746565206164647265737320696e76616c696400000000000000815260200192915050565b60006117be601883611a67565b7f7265636569766572206164647265737320696e76616c69640000000000000000815260200192915050565b60006117f7600f83611a67565b6e0c2dadeeadce840dad2e6dac2e8c6d608b1b815260200192915050565b61157281611a8a565b61157281611a99565b61157281611aa2565b600061183c8286611581565b601c8201915061184d828486611592565b95945050505050565b600061118b82846115b1565b60208101610a598284611569565b6060810161187e8286611569565b61188b6020830185611569565b6113406040830184611815565b606081016118a68286611569565b6118b36020830185611569565b611340604083018461181e565b604081016118ce8285611569565b61118b6020830184611815565b606081016118e98286611569565b61188b6020830185611815565b606081016119048286611569565b611911602083018561181e565b6113406040830184611569565b60208101610a598284611578565b60208101610a5982846115e0565b60208082528101610a5681846115e9565b60208082528101610a5981611621565b60208082528101610a598161165a565b60208082528101610a59816116ac565b60208082528101610a59816116f4565b60208082528101610a5981611725565b60208082528101610a5981611750565b60208082528101610a5981611778565b60208082528101610a59816117b1565b60208082528101610a59816117ea565b60208101610a598284611815565b60c081016119f78289611815565b611a046020830188611815565b611a116040830187611815565b611a1e6060830186611815565b611a2b6080830185611569565b611a3860a0830184611569565b979650505050505050565b60608101611a518286611827565b6119116020830185611815565b5190565b919050565b90815260200190565b6000610a5982611a8d565b151590565b63ffffffff191690565b90565b6001600160a01b031690565b63ffffffff1690565b6bffffffffffffffffffffffff1690565b6000610a5982611a70565b82818337506000910152565b60005b83811015611ae5578181015183820152602001611acd565b83811115611af4576000848401525b50505050565b601f01601f191690565b611b0d81611a70565b811461073b57600080fd5b611b0d81611a7b565b611b0d81611a8a565b611b0d81611a99565b611b0d81611aa256fea365627a7a72315820a89ede248f65f6f968df90376cf30f13581a3027604ed8923bf505e54a09ee6b6c6578706572696d656e74616cf564736f6c63430005110040", + "devdoc": { + "details": "Deployed by a VestingFactory contract.", + "methods": { + "collectDividends(address,uint32,address)": { + "params": { + "_loanPoolToken": "The loan pool token address.", + "_maxCheckpoints": "Maximum number of checkpoints to be processed.", + "_receiver": "The receiver of tokens or msg.sender" + } + }, + "delegate(address)": { + "params": { + "_delegatee": "The address to delegate votes to." + } + }, + "isOwner()": { + "details": "Returns true if the caller is the current owner." + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "receiveApproval(address,uint256,address,bytes)": { + "params": { + "_data": "The data will be used for low level call." + } + }, + "stakeTokens(uint256)": { + "params": { + "_amount": "The amount of tokens to stake." + } + }, + "stakeTokensWithApproval(address,uint256)": { + "details": "This function will be invoked from receiveApproval.SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval", + "params": { + "_amount": "The amount of tokens to stake.", + "_sender": "The sender of SOV.approveAndCall" + } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + }, + "withdrawTokens(address)": { + "params": { + "receiver": "The receiving address." + } + }, + "withdrawTokensStartingFrom(address,uint256,uint256)": { + "params": { + "maxWithdrawIterations": "max withdrawal iteration to work around block gas limit issue.", + "receiver": "The receiving address.", + "startFrom": "The start value for the iterations." + } + } + }, + "title": "Vesting Logic contract." + }, + "userdoc": { + "methods": { + "collectDividends(address,uint32,address)": { + "notice": "Collect dividends from fee sharing proxy." + }, + "delegate(address)": { + "notice": "Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`." + }, + "migrateToNewStakingContract()": { + "notice": "Allows the owners to migrate the positions to a new staking contract." + }, + "receiveApproval(address,uint256,address,bytes)": { + "notice": "Receives approval from SOV token." + }, + "stakeTokens(uint256)": { + "notice": "Stakes tokens according to the vesting schedule." + }, + "stakeTokensWithApproval(address,uint256)": { + "notice": "Stakes tokens according to the vesting schedule." + }, + "withdrawTokens(address)": { + "notice": "Withdraws unlocked tokens from the staking contract and forwards them to an address specified by the token owner." + }, + "withdrawTokensStartingFrom(address,uint256,uint256)": { + "notice": "Withdraws unlocked tokens partially (based on the max withdraw iteration that has been set) from the staking contract and forwards them to an address specified by the token owner." + } + }, + "notice": "Staking, delegating and withdrawal functionality." + }, + "storageLayout": { + "storage": [ + { + "astId": 54766, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 32150, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "SOV", + "offset": 0, + "slot": "1", + "type": "t_contract(IERC20)33452" + }, + { + "astId": 32152, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "staking", + "offset": 0, + "slot": "2", + "type": "t_contract(IStaking)17840" + }, + { + "astId": 32154, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "tokenOwner", + "offset": 0, + "slot": "3", + "type": "t_address" + }, + { + "astId": 32156, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "feeSharingCollector", + "offset": 0, + "slot": "4", + "type": "t_contract(IFeeSharingCollector)17012" + }, + { + "astId": 32158, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "cliff", + "offset": 0, + "slot": "5", + "type": "t_uint256" + }, + { + "astId": 32160, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "duration", + "offset": 0, + "slot": "6", + "type": "t_uint256" + }, + { + "astId": 32162, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "startDate", + "offset": 0, + "slot": "7", + "type": "t_uint256" + }, + { + "astId": 32164, + "contract": "contracts/governance/Vesting/VestingLogic.sol:VestingLogic", + "label": "endDate", + "offset": 0, + "slot": "8", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_contract(IERC20)33452": { + "encoding": "inplace", + "label": "contract IERC20", + "numberOfBytes": "20" + }, + "t_contract(IFeeSharingCollector)17012": { + "encoding": "inplace", + "label": "contract IFeeSharingCollector", + "numberOfBytes": "20" + }, + "t_contract(IStaking)17840": { + "encoding": "inplace", + "label": "contract IStaking", + "numberOfBytes": "20" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/deployment/deployments/rskSovrynTestnet/solcInputs/444414c40f489390e118f5b65a5947cc.json b/deployment/deployments/rskSovrynTestnet/solcInputs/444414c40f489390e118f5b65a5947cc.json new file mode 100644 index 000000000..cc792c440 --- /dev/null +++ b/deployment/deployments/rskSovrynTestnet/solcInputs/444414c40f489390e118f5b65a5947cc.json @@ -0,0 +1,711 @@ +{ + "language": "Solidity", + "sources": { + "contracts/connectors/loantoken/AdvancedToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Advanced Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedToken implements standard ERC-20 approval, mint and burn token functionality.\n * Logic (AdvancedToken) is kept aside from storage (AdvancedTokenStorage).\n *\n * For example, LoanTokenLogicDai contract uses AdvancedToken::_mint() to mint\n * its Loan Dai iTokens.\n * */\ncontract AdvancedToken is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n /**\n * @notice Set an amount as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n *\n * @param _spender The account address that will be able to spend the tokens.\n * @param _value The amount of tokens allowed to spend.\n * */\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @notice The iToken minting process. Meant to issue Loan iTokens.\n * Lenders are able to open an iToken position, by minting them.\n * This function is called by LoanTokenLogicStandard::_mintToken\n * @param _to The recipient of the minted tTokens.\n * @param _tokenAmount The amount of iTokens to be minted.\n * @param _assetAmount The amount of lended tokens (asset to lend).\n * @param _price The price of the lended tokens.\n * @return The updated balance of the recipient.\n * */\n function _mint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n require(_to != address(0), \"15\");\n\n uint256 _balance = balances[_to].add(_tokenAmount);\n balances[_to] = _balance;\n\n totalSupply_ = totalSupply_.add(_tokenAmount);\n\n emit Mint(_to, _tokenAmount, _assetAmount, _price);\n emit Transfer(address(0), _to, _tokenAmount);\n\n return _balance;\n }\n\n /**\n * @notice The iToken burning process. Meant to destroy Loan iTokens.\n * Lenders are able to close an iToken position, by burning them.\n * This function is called by LoanTokenLogicStandard::_burnToken\n * @param _who The owner of the iTokens to burn.\n * @param _tokenAmount The amount of iTokens to burn.\n * @param _assetAmount The amount of lended tokens.\n * @param _price The price of the lended tokens.\n * @return The updated balance of the iTokens owner.\n * */\n function _burn(\n address _who,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n //bzx compare\n //TODO: Unit test\n uint256 _balance = balances[_who].sub(_tokenAmount, \"16\");\n\n // a rounding error may leave dust behind, so we clear this out\n if (_balance <= 10) {\n // We can't leave such small balance quantities.\n _tokenAmount = _tokenAmount.add(_balance);\n _balance = 0;\n }\n balances[_who] = _balance;\n\n totalSupply_ = totalSupply_.sub(_tokenAmount);\n\n emit Burn(_who, _tokenAmount, _assetAmount, _price);\n emit Transfer(_who, address(0), _tokenAmount);\n return _balance;\n }\n}\n" + }, + "contracts/connectors/loantoken/AdvancedTokenStorage.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./LoanTokenBase.sol\";\n\n/**\n * @title Advanced Token Storage contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedTokenStorage implements standard ERC-20 getters functionality:\n * totalSupply, balanceOf, allowance and some events.\n * iToken logic is divided into several contracts AdvancedToken,\n * AdvancedTokenStorage and LoanTokenBase.\n * */\ncontract AdvancedTokenStorage is LoanTokenBase {\n using SafeMath for uint256;\n\n /* Events */\n\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /* Storage */\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n /* Functions */\n\n /**\n * @notice Get the total supply of iTokens.\n * @return The total number of iTokens in existence as of now.\n * */\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n /**\n * @notice Get the amount of iTokens owned by an account.\n * @param _owner The account owner of the iTokens.\n * @return The number of iTokens an account owns.\n * */\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n /**\n * @notice Get the amount of iTokens allowed to be spent by a\n * given account on behalf of the owner.\n * @param _owner The account owner of the iTokens.\n * @param _spender The account allowed to send the iTokens.\n * @return The number of iTokens an account is allowing the spender\n * to send on its behalf.\n * */\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/connectors/loantoken/interfaces/FeedsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface FeedsLike {\n function queryRate(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 rate, uint256 precision);\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../lib/MarginTradeStructHelpers.sol\";\n\ninterface ProtocolLike {\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function priceFeeds() external view returns (address);\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function lendingFeePercent() external view returns (uint256);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function borrowerNonce(address) external view returns (uint256);\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata // for future use /*loanDataBytes*/\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolSettingsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../core/objects/LoanParamsStruct.sol\";\n\ninterface ProtocolSettingsLike {\n function setupLoanParams(LoanParamsStruct.LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n}\n" + }, + "contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol": { + "content": "pragma solidity 0.5.17;\n\nlibrary MarginTradeStructHelpers {\n struct SentAddresses {\n address lender;\n address borrower;\n address receiver;\n address manager;\n }\n\n struct SentAmounts {\n uint256 interestRate;\n uint256 newPrincipal;\n uint256 interestInitialAmount;\n uint256 loanTokenSent;\n uint256 collateralTokenSent;\n uint256 minEntryPrice;\n uint256 loanToCollateralSwapRate;\n uint256 interestDuration;\n uint256 entryLeverage;\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Loan Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * A loan token (iToken) is created as a proxy to an upgradable token contract.\n *\n * Examples of loan tokens on Sovryn are iRBTC, iDOC, iUSDT, iBPro,\n * iSOV (near future).\n *\n * Lenders receive iTokens that collect interest from the lending pool\n * which they can redeem by withdrawing them. The i in iToken stands for interest.\n *\n * Do not confuse iTokens with underlying tokens. iDOC is an iToken (loan token)\n * whilest DOC is the underlying token (currency).\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\n * */\ncontract LoanToken is AdvancedTokenStorage {\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n address public admin;\n\n /**\n * @notice Deploy loan token proxy.\n * Sets ERC20 parameters of the token.\n *\n * @param _newOwner The address of the new owner.\n * @param _newTarget The address of the new target contract instance.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice Public owner setter for target address.\n * @dev Calls internal setter.\n * @param _newTarget The address of the new target contract instance.\n * */\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n /**\n * @notice Internal setter for target address.\n * @param _newTarget The address of the new target contract instance.\n * */\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n /**\n * @notice Internal setter for sovrynContract address.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * */\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n /**\n * @notice Internal setter for wrBTC address.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n /**\n * @notice Public owner cloner for pointed loan token.\n * Sets ERC20 parameters of the token.\n *\n * @dev TODO: add check for double init.\n * idk but init usually can be called only once.\n *\n * @param _loanTokenAddress The address of the pointed loan token instance.\n * @param _name The ERC20 token name.\n * @param _symbol The ERC20 token symbol.\n * */\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; /// starting price of 1\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenBase.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SignedSafeMath.sol\";\nimport \"../../openzeppelin/ReentrancyGuard.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\nimport \"./Pausable.sol\";\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title Loan Token Base contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Specific loan related storage for iTokens.\n *\n * An loan token or iToken is a representation of a user funds in the pool and the\n * interest they've earned. The redemption value of iTokens continually increase\n * from the accretion of interest paid into the lending pool by borrowers. The user\n * can sell iTokens to exit its position. The user might potentially use them as\n * collateral wherever applicable.\n *\n * There are three main tokens in the bZx system, iTokens, pTokens, and BZRX tokens.\n * The bZx system of lending and borrowing depends on iTokens and pTokens, and when\n * users lend or borrow money on bZx, their crypto assets go into or come out of\n * global liquidity pools, which are pools of funds shared between many different\n * exchanges. When lenders supply funds into the global liquidity pools, they\n * automatically receive iTokens; When users borrow money to open margin trading\n * positions, they automatically receive pTokens. The system is also designed to\n * use the BZRX tokens, which are only used to pay fees on the network currently.\n * */\ncontract LoanTokenBase is ReentrancyGuard, SharedReentrancyGuard, Ownable, Pausable {\n uint256 internal constant WEI_PRECISION = 10**18;\n uint256 internal constant WEI_PERCENT_PRECISION = 10**20;\n\n int256 internal constant sWEI_PRECISION = 10**18;\n\n /// @notice Standard ERC-20 properties\n string public name;\n string public symbol;\n uint8 public decimals;\n\n /// @notice The address of the loan token (asset to lend) instance.\n address public loanTokenAddress;\n\n uint256 public baseRate;\n uint256 public rateMultiplier;\n uint256 public lowUtilBaseRate;\n uint256 public lowUtilRateMultiplier;\n\n uint256 public targetLevel;\n uint256 public kinkLevel;\n uint256 public maxScaleRate;\n\n uint256 internal _flTotalAssetSupply;\n uint256 public checkpointSupply;\n uint256 public initialPrice;\n\n /// uint88 for tight packing -> 8 + 88 + 160 = 256\n uint88 internal lastSettleTime_;\n\n /// Mapping of keccak256(collateralToken, isTorqueLoan) to loanParamsId.\n mapping(uint256 => bytes32) public loanParamsIds;\n\n /// Price of token at last user checkpoint.\n mapping(address => uint256) internal checkpointPrices_;\n\n // the maximum trading/borrowing/lending limit per token address\n mapping(address => uint256) public transactionLimit;\n // 0 -> no limit\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicBeacon.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../mixins/EnumerableBytes32Set.sol\";\nimport \"../../mixins/EnumerableBytes4Set.sol\";\nimport \"../../utils/PausableRole.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Loan Token Logic Beacon contract.\n *\n * @notice This contract stored the target logic implementation of LoanTokens which has the same logic implementation (LoanTokenLogicLM / LoanTokenLogicWrbtc)\n * Apart from storing the target logic implementation, this contract also has a pause functionality.\n * By implementing pause/unpause functionality in this beacon contract, we can pause the loan token that has the same Logic (LoanTokenLogicLM / LoanTokenLogicWrbtc) at one call.\n * Meanwhile the pause/unpause function in the LoanTokenLogicProxy is used to pause/unpause specific LoanToken\n */\n\ncontract LoanTokenLogicBeacon is PausableRole {\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; // enumerable map of bytes4 or addresses\n\n mapping(bytes4 => address) private logicTargets;\n\n struct LoanTokenLogicModuleUpdate {\n address implementation; // address implementaion of the module\n uint256 updateTimestamp; // time of update\n }\n\n mapping(bytes32 => LoanTokenLogicModuleUpdate[]) public moduleUpgradeLog; /** the module name as the key */\n\n mapping(bytes32 => uint256) public activeModuleIndex; /** To store the current active index log for module */\n\n mapping(bytes32 => EnumerableBytes4Set.Bytes4Set) private activeFuncSignatureList; /** Store the current active function signature */\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n * This is the overriden function from the pausable contract, so that we can use custom error message.\n */\n modifier whenNotPaused() {\n require(!_paused, \"LoanTokenLogicBeacon:paused mode\");\n _;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This function will store the updated protocol module to the storage (For rollback purposes)\n *\n * @param loanTokenModuleAddress The module target address\n */\n function registerLoanTokenModule(address loanTokenModuleAddress) external onlyOwner {\n bytes32 moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n\n // Store the upgrade to the log\n moduleUpgradeLog[moduleName].push(\n LoanTokenLogicModuleUpdate(loanTokenModuleAddress, block.timestamp)\n );\n activeModuleIndex[moduleName] = moduleUpgradeLog[moduleName].length - 1;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This registration will require target contract to have the exact function getListFunctionSignatures() which will return functionSignatureList and the moduleName in bytes32\n *\n * @param loanTokenModuleAddress the target logic of the loan token module\n *\n * @return the module name\n */\n function _registerLoanTokenModule(address loanTokenModuleAddress) private returns (bytes32) {\n require(\n Address.isContract(loanTokenModuleAddress),\n \"LoanTokenModuleAddress is not a contract\"\n );\n\n // Get the list of function signature on this loanTokenModulesAddress\n (bytes4[] memory functionSignatureList, bytes32 moduleName) =\n ILoanTokenLogicModules(loanTokenModuleAddress).getListFunctionSignatures();\n\n /// register / update the module function signature address implementation\n for (uint256 i; i < functionSignatureList.length; i++) {\n require(functionSignatureList[i] != bytes4(0x0), \"ERR_EMPTY_FUNC_SIGNATURE\");\n logicTargets[functionSignatureList[i]] = loanTokenModuleAddress;\n if (!activeFuncSignatureList[moduleName].contains(functionSignatureList[i]))\n activeFuncSignatureList[moduleName].addBytes4(functionSignatureList[i]);\n }\n\n /// delete the \"removed\" module function signature in the current implementation\n bytes4[] memory activeSignatureListEnum =\n activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n for (uint256 i; i < activeSignatureListEnum.length; i++) {\n bytes4 activeSigBytes = activeSignatureListEnum[i];\n if (logicTargets[activeSigBytes] != loanTokenModuleAddress) {\n logicTargets[activeSigBytes] = address(0);\n activeFuncSignatureList[moduleName].removeBytes4(activeSigBytes);\n }\n }\n\n return moduleName;\n }\n\n /**\n * @dev get all active function signature list based on the module name.\n *\n * @param moduleName in bytes32.\n *\n * @return the array of function signature.\n */\n function getActiveFuncSignatureList(bytes32 moduleName)\n public\n view\n returns (bytes4[] memory signatureList)\n {\n signatureList = activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n return signatureList;\n }\n\n /**\n * @dev Get total length of the module upgrade log.\n *\n * @param moduleName in bytes32.\n *\n * @return length of module upgrade log.\n */\n function getModuleUpgradeLogLength(bytes32 moduleName) external view returns (uint256) {\n return moduleUpgradeLog[moduleName].length;\n }\n\n /**\n * @notice This function will rollback particular module to the spesific index / version of deployment\n *\n * @param moduleName Name of module in bytes32 format\n * @param index index / version of previous deployment\n */\n function rollback(bytes32 moduleName, uint256 index) external onlyOwner {\n address loanTokenModuleAddress = moduleUpgradeLog[moduleName][index].implementation;\n moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n activeModuleIndex[moduleName] = index;\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(bytes4 sig) external view whenNotPaused returns (address) {\n return logicTargets[sig];\n }\n}\n\ninterface ILoanTokenLogicModules {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory, bytes32 moduleName);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicProxy.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./AdvancedTokenStorage.sol\";\nimport \"../../openzeppelin/Initializable.sol\";\n\n/**\n * @title Loan Token Logic Proxy contract.\n *\n * @notice This contract contains the proxy functionality and it will query the logic target from LoanTokenLogicBeacon\n * This contract will also has the pause/unpause functionality. The purpose of this pausability is so that we can pause/unpause from the loan token level.\n *\n */\ncontract LoanTokenLogicProxy is AdvancedTokenStorage {\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT\n */\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT (CONSTANT / IMMUTABLE)\n */\n\n bytes32 internal constant LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT =\n keccak256(\"LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT\");\n\n modifier onlyAdmin() {\n require(isOwner(), \"LoanTokenLogicProxy:unauthorized\");\n _;\n }\n\n /**\n * @notice Fallback function performs a logic implementation address query to LoanTokenLogicBeacon and then do delegate call to that query result address.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n // query the logic target implementation address from the LoanTokenLogicBeacon\n address target = ILoanTokenLogicBeacon(_beaconAddress()).getTarget(msg.sig);\n require(target != address(0), \"LoanTokenLogicProxy:target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @dev Returns the current Loan Token logic Beacon.\n * @return Address of the current LoanTokenLogicBeacon.\n */\n function _beaconAddress() internal view returns (address beaconAddress) {\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n assembly {\n beaconAddress := sload(slot)\n }\n }\n\n /**\n * @return The address of the current LoanTokenLogicBeacon.\n */\n function beaconAddress() external view returns (address) {\n return _beaconAddress();\n }\n\n /**\n * @dev Set/update the new beacon address.\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon.\n */\n function _setBeaconAddress(address _newBeaconAddress) private {\n require(\n Address.isContract(_newBeaconAddress),\n \"Cannot set beacon address to a non-contract address\"\n );\n\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n\n assembly {\n sstore(slot, _newBeaconAddress)\n }\n }\n\n /**\n * @dev External function to set the new LoanTokenLogicBeacon Address\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon\n */\n function setBeaconAddress(address _newBeaconAddress) external onlyAdmin {\n _setBeaconAddress(_newBeaconAddress);\n }\n\n /**\n * @dev External function to return the LoanTokenLogicProxy of loan token (target of LoanToken contract).\n * Ideally this getter should be added in the LoanToken contract\n * but since LoanToken contract can't be changed, adding the getter in this contract will do\n * because it will use the context of LoanToken contract.\n *\n * @return target address of LoanToken contract\n */\n function getTarget() external view returns (address) {\n return target_;\n }\n}\n\ninterface ILoanTokenLogicBeacon {\n function getTarget(bytes4 functionSignature)\n external\n view\n returns (address logicTargetAddress);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicShared.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicStorage.sol\";\nimport \"./interfaces/ProtocolLike.sol\";\nimport \"./interfaces/FeedsLike.sol\";\nimport \"./interfaces/ProtocolSettingsLike.sol\";\nimport \"../../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../../farm/ILiquidityMining.sol\";\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../governance/Vesting/IVesting.sol\";\n\n/**\n * @dev This contract shares functions used by both LoanTokenLogicSplit and LoanTokenLogicStandard\n */\ncontract LoanTokenLogicShared is LoanTokenLogicStorage {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /**\n * @notice Update the user's checkpoint price and profit so far.\n * In this loan token contract, whenever some tokens are minted or burned,\n * the _updateCheckpoints() function is invoked to update the stats to\n * reflect the balance changes.\n *\n * @param _user The user address.\n * @param _oldBalance The user's previous balance.\n * @param _newBalance The user's updated balance.\n * @param _currentPrice The current loan token price.\n * */\n function _updateCheckpoints(\n address _user,\n uint256 _oldBalance,\n uint256 _newBalance,\n uint256 _currentPrice\n ) internal {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(_user, iToken_ProfitSoFar));\n\n int256 _currentProfit;\n if (_newBalance == 0) {\n _currentPrice = 0;\n } else if (_oldBalance != 0) {\n _currentProfit = _profitOf(slot, _oldBalance, _currentPrice, checkpointPrices_[_user]);\n }\n\n assembly {\n sstore(slot, _currentProfit)\n }\n\n checkpointPrices_[_user] = _currentPrice;\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice Transfer tokens, low level.\n * Checks allowance, updates sender and recipient balances\n * and updates checkpoints too.\n *\n * @param _from The tokens' owner.\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @param _allowanceAmount The amount of tokens allowed to transfer.\n *\n * @return Success true/false.\n * */\n function _internalTransferFrom(\n address _from,\n address _to,\n uint256 _value,\n uint256 _allowanceAmount\n ) internal returns (bool) {\n if (_allowanceAmount != uint256(-1)) {\n allowed[_from][msg.sender] = _allowanceAmount.sub(_value, \"14\");\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, _allowanceAmount, allowed[_from][msg.sender]);\n }\n\n require(_to != address(0), \"15\");\n\n uint256 _balancesFrom = balances[_from];\n uint256 _balancesFromNew = _balancesFrom.sub(_value, \"16\");\n balances[_from] = _balancesFromNew;\n\n uint256 _balancesTo = balances[_to];\n uint256 _balancesToNew = _balancesTo.add(_value);\n balances[_to] = _balancesToNew;\n\n /// @dev Handle checkpoint update.\n uint256 _currentPrice = tokenPrice();\n\n //checkpoints are not being used by the smart contract logic itself, but just for external use (query the profit)\n //only update the checkpoints of a user if he's not depositing to / withdrawing from the lending pool\n if (_from != liquidityMiningAddress && _to != liquidityMiningAddress) {\n _updateCheckpoints(_from, _balancesFrom, _balancesFromNew, _currentPrice);\n _updateCheckpoints(_to, _balancesTo, _balancesToNew, _currentPrice);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n /**\n * @notice Profit calculation based on checkpoints of price.\n * @param slot The user slot.\n * @param _balance The user balance.\n * @param _currentPrice The current price of the loan token.\n * @param _checkpointPrice The price of the loan token on checkpoint.\n * @return The profit of a user.\n * */\n function _profitOf(\n bytes32 slot,\n uint256 _balance,\n uint256 _currentPrice,\n uint256 _checkpointPrice\n ) internal view returns (int256 profitSoFar) {\n if (_checkpointPrice == 0) {\n return 0;\n }\n\n assembly {\n profitSoFar := sload(slot)\n }\n\n profitSoFar = int256(_currentPrice)\n .sub(int256(_checkpointPrice))\n .mul(int256(_balance))\n .div(sWEI_PRECISION)\n .add(profitSoFar);\n }\n\n /**\n * @notice Loan token price calculation considering unpaid interests.\n * @return The loan token price.\n * */\n function tokenPrice() public view returns (uint256 price) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _tokenPrice(_totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Get the total amount of loan tokens on debt.\n * Calls protocol getTotalPrincipal function.\n * In the context of borrowing, principal is the initial size of a loan.\n * It can also be the amount still owed on a loan. If you take out a\n * $50,000 mortgage, for example, the principal is $50,000. If you pay off\n * $30,000, the principal balance now consists of the remaining $20,000.\n *\n * @return The total amount of loan tokens on debt.\n * */\n function totalAssetBorrow() public view returns (uint256) {\n return\n ProtocolLike(sovrynContractAddress).getTotalPrincipal(address(this), loanTokenAddress);\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice .\n *\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param withdrawalAmount The amount of tokens to withdraw.\n *\n * @return msgValue The amount of rBTC sent minus the collateral on tokens.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = loanTokenAddress;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n _safeTransfer(_loanTokenAddress, sentAddresses.receiver, withdrawalAmount, \"\");\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n /**\n * This is a critical piece of code!\n * rBTC are supposed to be held by the contract itself, while other tokens are being transfered from the sender directly.\n * */\n if (collateralTokenSent != 0) {\n if (\n collateralTokenAddress == _wrbtcToken &&\n msgValue != 0 &&\n msgValue >= collateralTokenSent\n ) {\n IWrbtc(_wrbtcToken).deposit.value(collateralTokenSent)();\n _safeTransfer(\n collateralTokenAddress,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-a\"\n );\n msgValue -= collateralTokenSent;\n } else {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-b\"\n );\n }\n }\n\n if (loanTokenSent != 0) {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n\n /**\n * @notice Withdraw loan token interests from protocol.\n * This function only operates once per block.\n * It asks protocol to withdraw accrued interests for the loan token.\n *\n * @dev Internal sync required on every loan trade before starting.\n * */\n function _settleInterest() internal {\n uint88 ts = uint88(block.timestamp);\n if (lastSettleTime_ != ts) {\n ProtocolLike(sovrynContractAddress).withdrawAccruedInterest(loanTokenAddress);\n\n lastSettleTime_ = ts;\n }\n }\n\n /**\n * @notice Imitate a Solidity high-level call (i.e. a regular function\n * call to a contract), relaxing the requirement on the return value:\n * the return value is optional (but if data is returned, it must not be\n * false).\n *\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n * @param errorMsg The error message on failure.\n * */\n function _callOptionalReturn(\n address token,\n bytes memory data,\n string memory errorMsg\n ) internal {\n require(Address.isContract(token), \"call to a non-contract address\");\n (bool success, bytes memory returndata) = token.call(data);\n require(success, errorMsg);\n\n if (returndata.length != 0) {\n require(abi.decode(returndata, (bool)), errorMsg);\n }\n }\n\n /**\n * @notice Execute the ERC20 token's `transfer` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransfer(\n address token,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transfer.selector, to, amount),\n errorMsg\n );\n }\n\n /**\n * @notice Execute the ERC20 token's `transferFrom` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param from The source address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransferFrom(\n address token,\n address from,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transferFrom.selector, from, to, amount),\n errorMsg\n );\n }\n\n /** Internal view function */\n /**\n * @notice Compute the token price.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The token price.\n * */\n function _tokenPrice(uint256 assetSupply) internal view returns (uint256) {\n uint256 totalTokenSupply = totalSupply_;\n\n return\n totalTokenSupply != 0 ? assetSupply.mul(10**18).div(totalTokenSupply) : initialPrice;\n }\n\n /**\n * @notice Get two kind of interests: owed per day and yet to be paid.\n * @return interestOwedPerDay The interest per day.\n * @return interestUnPaid The interest not yet paid.\n * */\n function _getAllInterest()\n internal\n view\n returns (uint256 interestOwedPerDay, uint256 interestUnPaid)\n {\n /// interestPaid, interestPaidDate, interestOwedPerDay, interestUnPaid, interestFeePercent, principalTotal\n uint256 interestFeePercent;\n (, , interestOwedPerDay, interestUnPaid, interestFeePercent, ) = ProtocolLike(\n sovrynContractAddress\n )\n .getLenderInterestData(address(this), loanTokenAddress);\n\n interestUnPaid = interestUnPaid.mul(SafeMath.sub(10**20, interestFeePercent)).div(10**20);\n }\n\n /**\n * @notice Compute the total amount of loan tokens on supply.\n * @param interestUnPaid The interest not yet paid.\n * @return assetSupply The total amount of loan tokens on supply.\n * */\n function _totalAssetSupply(uint256 interestUnPaid)\n internal\n view\n returns (uint256 assetSupply)\n {\n if (totalSupply_ != 0) {\n uint256 assetsBalance = _flTotalAssetSupply; /// Temporary locked totalAssetSupply during a flash loan transaction.\n if (assetsBalance == 0) {\n assetsBalance = _underlyingBalance().add(totalAssetBorrow());\n }\n\n return assetsBalance.add(interestUnPaid);\n }\n }\n\n /**\n * @notice Get the loan contract balance.\n * @return The balance of the loan token for this contract.\n * */\n function _underlyingBalance() internal view returns (uint256) {\n return IERC20(loanTokenAddress).balanceOf(address(this));\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicSplit.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\n/**\n * @title Loan Token Logic Standard contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Logic around loan tokens (iTokens) required to operate borrowing,\n * and margin trading financial processes.\n *\n * The user provides funds to the lending pool using the mint function and\n * withdraws funds from the lending pool using the burn function. Mint and\n * burn refer to minting and burning loan tokens. Loan tokens represent a\n * share of the pool and gather interest over time.\n *\n * Interest rates are determined by supply and demand. When a lender deposits\n * funds, the interest rates go down. When a trader borrows funds, the\n * interest rates go up. Fulcrum uses a simple linear interest rate formula\n * of the form y = mx + b. The interest rate starts at 1% when loans aren't\n * being utilized and scales up to 40% when all the funds in the loan pool\n * are being borrowed.\n *\n * The borrow rate is determined at the time of the loan and represents the\n * net contribution of each borrower. Each borrower's interest contribution\n * is determined by the utilization rate of the pool and is netted against\n * all prior borrows. This means that the total amount of interest flowing\n * into the lending pool is not directly changed by lenders entering or\n * exiting the pool. The entrance or exit of lenders only impacts how the\n * interest payments are split up.\n *\n * For example, if there are 2 lenders with equal holdings each earning\n * 5% APR, but one of the lenders leave, then the remaining lender will earn\n * 10% APR since the interest payments don't have to be split between two\n * individuals.\n * */\ncontract LoanTokenLogicSplit is LoanTokenLogicShared {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /* Public functions */\n\n /**\n * @notice Mint loan token wrapper.\n * Adds a check before calling low level _mintToken function.\n * The function retrieves the tokens from the message sender, so make sure\n * to first approve the loan token contract to access your funds. This is\n * done by calling approve(address spender, uint amount) on the ERC20\n * token contract, where spender is the loan token contract address and\n * amount is the amount to be deposited.\n *\n * @param receiver The account getting the minted tokens.\n * @param depositAmount The amount of underlying tokens provided on the\n * loan. (Not the number of loan tokens to mint).\n *\n * @return The amount of loan tokens minted.\n * */\n function mint(address receiver, uint256 depositAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice Burn loan token wrapper.\n * Adds a pay-out transfer after calling low level _burnToken function.\n * In order to withdraw funds to the pool, call burn on the respective\n * loan token contract. This will burn your loan tokens and send you the\n * underlying token in exchange.\n *\n * @param receiver The account getting the minted tokens.\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 loanAmountPaid)\n {\n loanAmountPaid = _burnToken(burnAmount);\n\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (loanAmountPaid != 0) {\n _safeTransfer(loanTokenAddress, receiver, loanAmountPaid, \"5\");\n }\n }\n\n /**\n * @notice transfers the underlying asset from the msg.sender and mints tokens for the receiver\n * @param receiver the address of the iToken receiver\n * @param depositAmount the amount of underlying assets to be deposited\n * @return the amount of iTokens issued\n */\n function _mintToken(address receiver, uint256 depositAmount)\n internal\n returns (uint256 mintAmount)\n {\n uint256 currentPrice;\n\n //calculate amount to mint and transfer the underlying asset\n (mintAmount, currentPrice) = _prepareMinting(depositAmount);\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n receiver\n );\n uint256 oldBalance = balances[receiver].add(balanceOnLM);\n uint256 newBalance = oldBalance.add(mintAmount);\n\n //mint the tokens to the receiver\n _mint(receiver, mintAmount, depositAmount, currentPrice);\n\n //update the checkpoint of the receiver\n _updateCheckpoints(receiver, oldBalance, newBalance, currentPrice);\n }\n\n /**\n * calculates the amount of tokens to mint and transfers the underlying asset to this contract\n * @param depositAmount the amount of the underyling asset deposited\n * @return the amount to be minted\n */\n function _prepareMinting(uint256 depositAmount)\n internal\n returns (uint256 mintAmount, uint256 currentPrice)\n {\n require(depositAmount != 0, \"17\");\n\n _settleInterest();\n\n currentPrice = _tokenPrice(_totalAssetSupply(0));\n mintAmount = depositAmount.mul(10**18).div(currentPrice);\n\n if (msg.value == 0) {\n _safeTransferFrom(loanTokenAddress, msg.sender, address(this), depositAmount, \"18\");\n } else {\n IWrbtc(wrbtcTokenAddress).deposit.value(depositAmount)();\n }\n }\n\n /**\n * @notice A wrapper for AdvancedToken::_burn\n *\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function _burnToken(uint256 burnAmount) internal returns (uint256 loanAmountPaid) {\n require(burnAmount != 0, \"19\");\n\n if (burnAmount > balanceOf(msg.sender)) {\n require(burnAmount == uint256(-1), \"32\");\n burnAmount = balanceOf(msg.sender);\n }\n\n _settleInterest();\n\n uint256 currentPrice = _tokenPrice(_totalAssetSupply(0));\n\n uint256 loanAmountOwed = burnAmount.mul(currentPrice).div(10**18);\n uint256 loanAmountAvailableInContract = _underlyingBalance();\n\n loanAmountPaid = loanAmountOwed;\n require(loanAmountPaid <= loanAmountAvailableInContract, \"37\");\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n uint256 oldBalance = balances[msg.sender].add(balanceOnLM);\n uint256 newBalance = oldBalance.sub(burnAmount);\n\n _burn(msg.sender, burnAmount, loanAmountPaid, currentPrice);\n\n //this function does not only update the checkpoints but also the current profit of the user\n //all for external use only\n _updateCheckpoints(msg.sender, oldBalance, newBalance, currentPrice);\n }\n\n function _mintWithLM(address receiver, uint256 depositAmount)\n internal\n returns (uint256 minted)\n {\n //mint the tokens for the receiver\n minted = _mintToken(receiver, depositAmount);\n\n //transfer the tokens from the receiver to the LM address\n _internalTransferFrom(receiver, liquidityMiningAddress, minted, minted);\n\n //inform the LM mining contract\n ILiquidityMining(liquidityMiningAddress).onTokensDeposited(receiver, minted);\n }\n\n function _burnFromLM(uint256 burnAmount) internal returns (uint256) {\n uint256 balanceOnLM =\n ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n require(balanceOnLM.add(balanceOf(msg.sender)) >= burnAmount, \"not enough balance\");\n\n if (balanceOnLM > 0) {\n //withdraw pool tokens and LM rewards to the passed address\n if (balanceOnLM < burnAmount) {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n balanceOnLM,\n msg.sender\n );\n } else {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n burnAmount,\n msg.sender\n );\n }\n }\n //burn the tokens of the msg.sender\n return _burnToken(burnAmount);\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStandard.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\ncontract LoanTokenLogicStandard is LoanTokenLogicShared {\n /**\n * @notice Transfer tokens wrapper.\n * Sets token owner the msg.sender.\n * Sets maximun allowance uint256(-1) to ensure tokens are always transferred.\n *\n * If the recipient (_to) is a vesting contract address, transfer the token to the tokenOwner of the vesting contract itself.\n *\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @return Success true/false.\n * */\n function transfer(address _to, uint256 _value) external returns (bool) {\n /** need additional check address(0) here to support backward compatibility\n * in case we don't want to activate this check, just need to set the stakingContractAddress to 0 address\n */\n if (\n stakingContractAddress != address(0) &&\n IStaking(stakingContractAddress).isVestingContract(_to)\n ) {\n (bool success, bytes memory data) =\n _to.staticcall(abi.encodeWithSelector(IVesting(_to).tokenOwner.selector));\n\n if (success) _to = abi.decode(data, (address));\n }\n\n return _internalTransferFrom(msg.sender, _to, _value, uint256(-1));\n }\n\n /**\n * @notice Moves `_value` loan tokens from `_from` to `_to` using the\n * allowance mechanism. Calls internal _internalTransferFrom function.\n *\n * @return A boolean value indicating whether the operation succeeded.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool) {\n return\n _internalTransferFrom(\n _from,\n _to,\n _value,\n //allowed[_from][msg.sender]\n ProtocolLike(sovrynContractAddress).isLoanPool(msg.sender)\n ? uint256(-1)\n : allowed[_from][msg.sender]\n );\n }\n\n /**\n * @notice Borrow funds from the pool.\n * The underlying loan token may not be used as collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * (150% of the withdrawn amount worth in collateral tokens).\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param borrower The one paying for the collateral.\n * @param receiver The one receiving the withdrawn amount.\n *\n * @return New principal and new collateral added to loan.\n * */\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes memory /// loanDataBytes: arbitrary order data (for future use).\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n )\n {\n require(withdrawAmount != 0, \"6\");\n\n _checkPause();\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n\n require(\n (msg.value == 0 || msg.value == collateralTokenSent) &&\n (collateralTokenSent != 0 || loanId != 0) &&\n (collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0) &&\n (loanId == 0 || msg.sender == borrower),\n \"7\"\n );\n\n /// @dev We have an issue regarding contract size code is too big. 1 of the solution is need to keep the error message 32 bytes length\n // Temporarily, we combine this require to the above, so can save the contract size code\n // require(collateralTokenSent != 0 || loanId != 0, \"8\");\n // require(collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0, \"9\");\n\n /// @dev Ensure authorized use of existing loan.\n // require(loanId == 0 || msg.sender == borrower, \"401 use of existing loan\");\n\n /// @dev The condition is never met.\n /// Address zero is not allowed by previous require validation.\n /// This check is unneeded and was lowering the test coverage index.\n // if (collateralTokenAddress == address(0)) {\n // \tcollateralTokenAddress = wrbtcTokenAddress;\n // }\n\n require(collateralTokenAddress != loanTokenAddress, \"10\");\n\n _settleInterest();\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this); /// The lender.\n sentAddresses.borrower = borrower;\n sentAddresses.receiver = receiver;\n /// sentAddresses.manager = address(0); /// The manager.\n\n sentAmounts.newPrincipal = withdrawAmount;\n\n /// interestRate, interestInitialAmount, borrowAmount (newBorrowAmount).\n (\n sentAmounts.interestRate,\n sentAmounts.interestInitialAmount,\n sentAmounts.newPrincipal\n ) = _getInterestRateAndBorrowAmount(\n sentAmounts.newPrincipal,\n _totalAssetSupply(0), /// Interest is settled above.\n initialLoanDuration\n );\n\n /// sentAmounts.loanTokenSent = 0; /// loanTokenSent\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n return\n _borrowOrTrade(\n loanId,\n withdrawAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ]\n ),\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Borrow and immediately get into a position.\n *\n * Trading on margin is used to increase an investor's buying power.\n * Margin is the amount of money required to open a position, while\n * leverage is the multiple of exposure to account equity.\n *\n * Leverage allows you to trade positions LARGER than the amount\n * of money in your trading account. Leverage is expressed as a ratio.\n *\n * When trading on margin, investors first deposit some token that then\n * serves as collateral for the loan, and then pay ongoing interest\n * payments on the money they borrow.\n *\n * Margin trading = taking a loan and swapping it:\n * In order to open a margin trade position,\n * 1.- The user calls marginTrade on the loan token contract.\n * 2.- The loan token contract provides the loan and sends it for processing\n * to the protocol proxy contract.\n * 3.- The protocol proxy contract uses the module LoanOpening to create a\n * position and swaps the loan tokens to collateral tokens.\n * 4.- The Sovryn Swap network looks up the correct converter and swaps the\n * tokens.\n * If successful, the position is being held by the protocol proxy contract,\n * which is why positions need to be closed at the protocol proxy contract.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n * */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // value of loan token in collateral\n bytes memory loanDataBytes /// Arbitrary order data.\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n _checkPause();\n\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n require(collateralTokenAddress != loanTokenAddress, \"11\");\n\n /// @dev Ensure authorized use of existing loan.\n require(loanId == 0 || msg.sender == trader, \"401 use of existing loan\");\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n if (transactionLimit[loanTokenAddress] > 0)\n require(loanTokenSent <= transactionLimit[loanTokenAddress]);\n\n /// @dev Compute the worth of the total deposit in loan tokens.\n /// (loanTokenSent + convert(collateralTokenSent))\n /// No actual swap happening here.\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n require(totalDeposit != 0, \"12\");\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this);\n sentAddresses.borrower = trader;\n sentAddresses.receiver = trader;\n /// sentAddresses.manager = address(0); /// The manager.\n\n /// sentAmounts.interestRate = 0; /// interestRate (found later).\n sentAmounts.newPrincipal = totalDeposit;\n /// sentAmounts.interestInitialAmount = 0; /// interestInitialAmount (interest is calculated based on fixed-term loan).\n sentAmounts.loanTokenSent = loanTokenSent;\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n _settleInterest();\n\n (sentAmounts.newPrincipal, sentAmounts.interestRate) = _getMarginBorrowAmountAndRate( /// borrowAmount, interestRate\n leverageAmount,\n sentAmounts.newPrincipal /// depositAmount\n );\n\n require(\n _getAmountInRbtc(loanTokenAddress, sentAmounts.newPrincipal) > TINY_AMOUNT,\n \"principal too small\"\n );\n\n /// @dev Converting to initialMargin\n leverageAmount = SafeMath.div(10**38, leverageAmount);\n sentAmounts.minEntryPrice = minEntryPrice;\n return\n _borrowOrTrade(\n loanId,\n 0, /// withdrawAmount\n leverageAmount, //initial margin\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n );\n }\n\n /**\n * @notice Wrapper for marginTrade invoking setAffiliatesReferrer to track\n * referral trade by affiliates program.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param affiliateReferrer The address of the referrer from affiliates program.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n */\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, /// Value of loan token in collateral\n address affiliateReferrer, /// The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n if (affiliateReferrer != address(0))\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(\n trader,\n affiliateReferrer\n );\n return\n marginTrade(\n loanId,\n leverageAmount,\n loanTokenSent,\n collateralTokenSent,\n collateralTokenAddress,\n trader,\n minEntryPrice,\n loanDataBytes\n );\n }\n\n /* Public View functions */\n\n /**\n * @notice Wrapper for internal _profitOf low level function.\n * @param user The user address.\n * @return The profit of a user.\n * */\n function profitOf(address user) external view returns (int256) {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(user, iToken_ProfitSoFar));\n //TODO + LM balance\n return _profitOf(slot, balances[user], tokenPrice(), checkpointPrices_[user]);\n }\n\n /**\n * @notice Getter for the price checkpoint mapping.\n * @param _user The user account as the mapping index.\n * @return The price on the checkpoint for this user.\n * */\n function checkpointPrice(address _user) public view returns (uint256 price) {\n return checkpointPrices_[_user];\n }\n\n /**\n * @notice Get current liquidity.\n * A part of total funds supplied are borrowed. Liquidity = supply - borrow\n * @return The market liquidity.\n * */\n function marketLiquidity() public view returns (uint256) {\n uint256 totalSupply = _totalAssetSupply(0);\n uint256 totalBorrow = totalAssetBorrow();\n if (totalSupply > totalBorrow) {\n return totalSupply - totalBorrow;\n }\n }\n\n /**\n * @notice Wrapper for average borrow interest.\n * @return The average borrow interest.\n * */\n function avgBorrowInterestRate() public view returns (uint256) {\n return _avgBorrowInterestRate(totalAssetBorrow());\n }\n\n /**\n * @notice Get borrow interest rate.\n * The minimum rate the next base protocol borrower will receive\n * for variable-rate loans.\n * @return The borrow interest rate.\n * */\n function borrowInterestRate() public view returns (uint256) {\n return _nextBorrowInterestRate(0);\n }\n\n /**\n * @notice Public wrapper for internal call.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest rate.\n * */\n function nextBorrowInterestRate(uint256 borrowAmount) public view returns (uint256) {\n return _nextBorrowInterestRate(borrowAmount);\n }\n\n /**\n * @notice Get interest rate.\n *\n * @return Interest that lenders are currently receiving when supplying to\n * the pool.\n * */\n function supplyInterestRate() public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0));\n }\n\n /**\n * @notice Get interest rate w/ added supply.\n * @param supplyAmount The amount of tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of tokens to the pool.\n * */\n function nextSupplyInterestRate(uint256 supplyAmount) public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0).add(supplyAmount));\n }\n\n /**\n * @notice Get interest rate w/ added supply assets.\n * @param assetSupply The amount of loan tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of loan tokens to the pool.\n * */\n function totalSupplyInterestRate(uint256 assetSupply) public view returns (uint256) {\n uint256 assetBorrow = totalAssetBorrow();\n if (assetBorrow != 0) {\n return calculateSupplyInterestRate(assetBorrow, assetSupply);\n }\n }\n\n /**\n * @notice Get the total amount of loan tokens on supply.\n * @dev Wrapper for internal _totalAssetSupply function.\n * @return The total amount of loan tokens on supply.\n * */\n function totalAssetSupply() public view returns (uint256) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _totalAssetSupply(interestUnPaid);\n }\n\n /**\n * @notice Compute the maximum deposit amount under current market conditions.\n * @dev maxEscrowAmount = liquidity * (100 - interestForDuration) / 100\n * @param leverageAmount The chosen multiplier with 18 decimals.\n * */\n function getMaxEscrowAmount(uint256 leverageAmount)\n public\n view\n returns (uint256 maxEscrowAmount)\n {\n /**\n * @dev Mathematical imperfection: depending on liquidity we might be able\n * to borrow more if utilization is below the kink level.\n * */\n uint256 interestForDuration = maxScaleRate.mul(28).div(365);\n uint256 factor = uint256(10**20).sub(interestForDuration);\n uint256 maxLoanSize = marketLiquidity().mul(factor).div(10**20);\n maxEscrowAmount = maxLoanSize.mul(10**18).div(leverageAmount);\n }\n\n /**\n * @notice Get loan token balance.\n * @return The user's balance of underlying token.\n * */\n function assetBalanceOf(address _owner) public view returns (uint256) {\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0)) {\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n _owner\n );\n }\n return balanceOf(_owner).add(balanceOnLM).mul(tokenPrice()).div(10**18);\n }\n\n /**\n * @notice Get margin information on a trade.\n *\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The principal, the collateral and the interestRate.\n * */\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n public\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n )\n {\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n\n (principal, interestRate) = _getMarginBorrowAmountAndRate(leverageAmount, totalDeposit);\n if (principal > _underlyingBalance()) {\n return (0, 0, 0);\n }\n\n loanTokenSent = loanTokenSent.add(principal);\n\n collateral = ProtocolLike(sovrynContractAddress).getEstimatedMarginExposure(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent,\n collateralTokenSent,\n interestRate,\n principal\n );\n }\n\n /**\n * @notice Calculate the deposit required to a given borrow.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param borrowAmount The amount of borrow.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of deposit required.\n * */\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 depositAmount) {\n if (borrowAmount != 0) {\n (, , uint256 newBorrowAmount) =\n _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (newBorrowAmount <= _underlyingBalance()) {\n if (collateralTokenAddress == address(0))\n collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ];\n return\n ProtocolLike(sovrynContractAddress)\n .getRequiredCollateral(\n loanTokenAddress,\n collateralTokenAddress,\n newBorrowAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin\n true /// isTorqueLoan\n )\n .add(10); /// Some dust to compensate for rounding errors.\n }\n }\n }\n\n /**\n * @notice Calculate the borrow allowed for a given deposit.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param depositAmount The amount of deposit.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of borrow allowed.\n * */\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 borrowAmount) {\n if (depositAmount != 0) {\n if (collateralTokenAddress == address(0)) collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))];\n borrowAmount = ProtocolLike(sovrynContractAddress).getBorrowAmount(\n loanTokenAddress,\n collateralTokenAddress,\n depositAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin,\n true /// isTorqueLoan\n );\n\n (, , borrowAmount) = _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (borrowAmount > _underlyingBalance()) {\n borrowAmount = 0;\n }\n }\n }\n\n /**\n * @notice Check if entry price lies above a minimum\n *\n * @param loanTokenSent The amount of deposit.\n * @param collateralTokenAddress The token address of collateral.\n * @param minEntryPrice Value of loan token in collateral\n * */\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) public view {\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokensReceived =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent\n );\n uint256 collateralTokenPrice =\n (collateralTokensReceived.mul(WEI_PRECISION)).div(loanTokenSent);\n require(collateralTokenPrice >= minEntryPrice, \"entry price above the minimum\");\n }\n\n /**\n * @notice Compute the next supply interest adjustment.\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next supply interest adjustment.\n * */\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n public\n view\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply >= assetBorrow) {\n return\n _avgBorrowInterestRate(assetBorrow)\n .mul(_utilizationRate(assetBorrow, assetSupply))\n .mul(\n SafeMath.sub(10**20, ProtocolLike(sovrynContractAddress).lendingFeePercent())\n )\n .div(10**40);\n }\n }\n\n /* Internal functions */\n\n /**\n * @notice Compute what the deposit is worth in loan tokens using the swap rate\n * used for loan size computation.\n *\n * @param collateralTokenAddress The token address of the collateral.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param loanTokenSent The number of loan tokens provided by the user.\n *\n * @return The value of the deposit in loan tokens.\n * */\n function _totalDeposit(\n address collateralTokenAddress,\n uint256 collateralTokenSent,\n uint256 loanTokenSent\n ) internal view returns (uint256 totalDeposit) {\n totalDeposit = loanTokenSent;\n\n if (collateralTokenSent != 0) {\n /// @dev Get the oracle rate from collateral -> loan\n (uint256 collateralToLoanRate, uint256 collateralToLoanPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n collateralTokenAddress,\n loanTokenAddress\n );\n require(\n (collateralToLoanRate != 0) && (collateralToLoanPrecision != 0),\n \"invalid rate collateral token\"\n );\n\n /// @dev Compute the loan token amount with the oracle rate.\n uint256 loanTokenAmount =\n collateralTokenSent.mul(collateralToLoanRate).div(collateralToLoanPrecision);\n\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokenAmount =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenAmount\n );\n\n /// @dev Probably not the same due to the price difference.\n if (collateralTokenAmount != collateralTokenSent) {\n //scale the loan token amount accordingly, so we'll get the expected position size in the end\n loanTokenAmount = loanTokenAmount.mul(collateralTokenAmount).div(\n collateralTokenSent\n );\n }\n\n totalDeposit = loanTokenAmount.add(totalDeposit);\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n asset,\n wrbtcTokenAddress\n );\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /*\n * @notice Compute interest rate and other loan parameters.\n *\n * @param borrowAmount The amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n *\n * @return The interest rate, the interest calculated based on fixed-term\n * loan, and the new borrow amount.\n * */\n function _getInterestRateAndBorrowAmount(\n uint256 borrowAmount,\n uint256 assetSupply,\n uint256 initialLoanDuration /// Duration in seconds.\n )\n internal\n view\n returns (\n uint256 interestRate,\n uint256 interestInitialAmount,\n uint256 newBorrowAmount\n )\n {\n interestRate = _nextBorrowInterestRate2(borrowAmount, assetSupply);\n\n /// newBorrowAmount = borrowAmount * 10^18 / (10^18 - interestRate * 7884000 * 10^18 / 31536000 / 10^20)\n newBorrowAmount = borrowAmount.mul(10**18).div(\n SafeMath.sub(\n 10**18,\n interestRate.mul(initialLoanDuration).mul(10**18).div(31536000 * 10**20) /// 365 * 86400 * 10**20\n )\n );\n\n interestInitialAmount = newBorrowAmount.sub(borrowAmount);\n }\n\n /**\n * @notice Compute principal and collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialMargin The initial margin with 18 decimals\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return The new principal and the new collateral. Principal is the\n * complete borrowed amount (in loan tokens). Collateral is the complete\n * position size (loan + margin) (in collateral tokens).\n * */\n function _borrowOrTrade(\n bytes32 loanId,\n uint256 withdrawAmount,\n uint256 initialMargin,\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n _checkPause();\n require(\n sentAmounts.newPrincipal <= _underlyingBalance() && /// newPrincipal (borrowed amount + fees)\n sentAddresses.borrower != address(0), /// The borrower.\n \"24\"\n );\n\n if (sentAddresses.receiver == address(0)) {\n sentAddresses.receiver = sentAddresses.borrower; /// The receiver = the borrower.\n }\n\n /// @dev Handle transfers prior to adding newPrincipal to loanTokenSent\n uint256 msgValue =\n _verifyTransfers(collateralTokenAddress, sentAddresses, sentAmounts, withdrawAmount);\n\n /**\n * @dev Adding the loan token portion from the lender to loanTokenSent\n * (add the loan to the loan tokens sent from the user).\n * */\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.add(sentAmounts.newPrincipal); /// newPrincipal\n\n if (withdrawAmount != 0) {\n /// @dev withdrawAmount already sent to the borrower, so we aren't sending it to the protocol.\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.sub(withdrawAmount);\n }\n\n bool withdrawAmountExist = false; /// Default is false, but added just as to make sure.\n\n if (withdrawAmount != 0) {\n withdrawAmountExist = true;\n }\n\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, withdrawAmountExist)))\n ];\n\n (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent) = ProtocolLike(\n sovrynContractAddress\n )\n .borrowOrTradeFromPool\n .value(msgValue)(\n loanParamsId,\n loanId,\n withdrawAmountExist,\n initialMargin,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n ); /// newPrincipal, newCollateral\n require(sentAmounts.newPrincipal != 0, \"25\");\n\n /// @dev Setting not-first-trade flag to prevent binding to an affiliate existing users post factum.\n /// @dev REFACTOR: move to a general interface: ProtocolSettingsLike?\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(\n sentAddresses.borrower\n );\n\n return (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent); // newPrincipal, newCollateral\n }\n\n /* Internal View functions */\n\n /**\n * @notice Compute the average borrow interest rate.\n * @param assetBorrow The amount of loan tokens on debt.\n * @return The average borrow interest rate.\n * */\n function _avgBorrowInterestRate(uint256 assetBorrow) internal view returns (uint256) {\n if (assetBorrow != 0) {\n (uint256 interestOwedPerDay, ) = _getAllInterest();\n return interestOwedPerDay.mul(10**20).mul(365).div(assetBorrow);\n }\n }\n\n /**\n * @notice Compute the next borrow interest adjustment.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate(uint256 borrowAmount) internal view returns (uint256) {\n uint256 interestUnPaid;\n if (borrowAmount != 0) {\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n uint256 balance = _underlyingBalance().add(interestUnPaid);\n if (borrowAmount > balance) {\n borrowAmount = balance;\n }\n }\n\n return _nextBorrowInterestRate2(borrowAmount, _totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Compute the next borrow interest adjustment under target-kink\n * level analysis.\n *\n * The \"kink\" in the cDAI interest rate model reflects the utilization rate\n * at which the slope of the interest rate goes from \"gradual\" to \"steep\".\n * That is, below this utilization rate, the slope of the interest rate\n * curve is gradual. Above this utilization rate, it is steep.\n *\n * Because of this dynamic between the interest rate curves before and\n * after the \"kink\", the \"kink\" can be thought of as the target utilization\n * rate. Above that rate, it quickly becomes expensive to borrow (and\n * commensurately lucrative for suppliers).\n *\n * @param newBorrowAmount The new amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate2(uint256 newBorrowAmount, uint256 assetSupply)\n internal\n view\n returns (uint256 nextRate)\n {\n uint256 utilRate = _utilizationRate(totalAssetBorrow().add(newBorrowAmount), assetSupply);\n\n uint256 thisMinRate;\n uint256 thisRateAtKink;\n uint256 thisBaseRate = baseRate;\n uint256 thisRateMultiplier = rateMultiplier;\n uint256 thisTargetLevel = targetLevel;\n uint256 thisKinkLevel = kinkLevel;\n uint256 thisMaxScaleRate = maxScaleRate;\n\n if (utilRate < thisTargetLevel) {\n // target targetLevel utilization when utilization is under targetLevel\n utilRate = thisTargetLevel;\n }\n\n if (utilRate > thisKinkLevel) {\n /// @dev Scale rate proportionally up to 100%\n uint256 thisMaxRange = WEI_PERCENT_PRECISION - thisKinkLevel; /// Will not overflow.\n\n utilRate -= thisKinkLevel;\n if (utilRate > thisMaxRange) utilRate = thisMaxRange;\n\n // Modified the rate calculation as it is slightly exaggerated around kink level\n // thisRateAtKink = thisRateMultiplier.add(thisBaseRate).mul(thisKinkLevel).div(WEI_PERCENT_PRECISION);\n thisRateAtKink = thisKinkLevel.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n nextRate = utilRate\n .mul(SafeMath.sub(thisMaxScaleRate, thisRateAtKink))\n .div(thisMaxRange)\n .add(thisRateAtKink);\n } else {\n nextRate = utilRate.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n thisMinRate = thisBaseRate;\n thisRateAtKink = thisRateMultiplier.add(thisBaseRate);\n\n if (nextRate < thisMinRate) nextRate = thisMinRate;\n else if (nextRate > thisRateAtKink) nextRate = thisRateAtKink;\n }\n }\n\n /**\n * @notice Compute the loan size and interest rate.\n * @param leverageAmount The leverage with 18 decimals.\n * @param depositAmount The amount the user deposited in underlying loan tokens.\n * @return borrowAmount The amount of tokens to borrow.\n * @return interestRate The interest rate to pay on the position.\n * */\n function _getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n internal\n view\n returns (uint256 borrowAmount, uint256 interestRate)\n {\n uint256 loanSizeBeforeInterest = depositAmount.mul(leverageAmount).div(10**18);\n /**\n * @dev Mathematical imperfection. we calculate the interest rate based on\n * the loanSizeBeforeInterest, but the actual borrowed amount will be bigger.\n * */\n interestRate = _nextBorrowInterestRate2(loanSizeBeforeInterest, _totalAssetSupply(0));\n /// @dev Assumes that loan, collateral, and interest token are the same.\n borrowAmount = _adjustLoanSize(interestRate, 28 days, loanSizeBeforeInterest);\n }\n\n /**\n * @notice Make sure call is not paused.\n * @dev Used for internal verification if the called function is paused.\n * It throws an exception in case it's not.\n * */\n function _checkPause() internal view {\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n msg.sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n bool isPaused;\n assembly {\n isPaused := sload(slot)\n }\n require(!isPaused, \"unauthorized\");\n }\n\n /**\n * @notice Adjusts the loan size to make sure the expected exposure remains after prepaying the interest.\n * @dev loanSizeWithInterest = loanSizeBeforeInterest * 100 / (100 - interestForDuration)\n * @param interestRate The interest rate to pay on the position.\n * @param maxDuration The maximum duration of the position (until rollover).\n * @param loanSizeBeforeInterest The loan size before interest is added.\n * */\n function _adjustLoanSize(\n uint256 interestRate,\n uint256 maxDuration,\n uint256 loanSizeBeforeInterest\n ) internal pure returns (uint256 loanSizeWithInterest) {\n uint256 interestForDuration = interestRate.mul(maxDuration).div(365 days);\n uint256 divisor = uint256(10**20).sub(interestForDuration);\n loanSizeWithInterest = loanSizeBeforeInterest.mul(10**20).div(divisor);\n }\n\n /**\n * @notice Calculate the utilization rate.\n * @dev Utilization rate = assetBorrow / assetSupply\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The utilization rate.\n * */\n function _utilizationRate(uint256 assetBorrow, uint256 assetSupply)\n internal\n pure\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply != 0) {\n /// U = total_borrow / total_supply\n return assetBorrow.mul(10**20).div(assetSupply);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./AdvancedToken.sol\";\n\ncontract LoanTokenLogicStorage is AdvancedToken {\n /// DO NOT ADD VARIABLES HERE - SEE BELOW\n\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /// @dev Add new variables here on the bottom.\n address public earlyAccessToken; //not used anymore, but staying for upgradability\n address public pauser;\n /** The address of the liquidity mining contract */\n address public liquidityMiningAddress;\n\n /** The address of the staking contract */\n address public stakingContractAddress;\n\n /// @dev Used by flashBorrow function.\n uint256 public constant VERSION = 6;\n /// @dev Used by flashBorrow function.\n address internal constant arbitraryCaller = 0x000F400e6818158D541C3EBE45FE3AA0d47372FF;\n bytes32 internal constant iToken_ProfitSoFar =\n 0x37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb6; // keccak256(\"iToken_ProfitSoFar\")\n uint256 public constant TINY_AMOUNT = 25e13;\n\n function stringToBytes32(string memory source) public pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"unauthorized\"); // SS02\n _;\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogic is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenMintAndBurn also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenLogicStandard also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\")); /// LoanTokenLogicStandard\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\")); /// LoanTokenLogicLM\n res[2] = bytes4(keccak256(\"burn(address,uint256)\")); /// LoanTokenLogicStandard\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\")); /// LoanTokenLogicLM\n\n return (res, stringToBytes32(\"LoanTokenLogicLM\"));\n }\n\n /**\n * @notice deposit into the lending pool and optionally participate at the Liquidity Mining Program\n * @param receiver the receiver of the tokens\n * @param depositAmount The amount of underlying tokens provided on the loan.\n *\t\t\t\t\t\t(Not the number of loan tokens to mint).\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 minted) {\n if (useLM) return _mintWithLM(receiver, depositAmount);\n else return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice withdraws from the lending pool and optionally retrieves the pool tokens from the\n * Liquidity Mining Contract\n * @param receiver the receiver of the underlying tokens. note: potetial LM rewards are always sent to the msg.sender\n * @param burnAmount The amount of pool tokens to redeem.\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 redeemed) {\n if (useLM) redeemed = _burnFromLM(burnAmount);\n else redeemed = _burnToken(burnAmount);\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (redeemed != 0) {\n _safeTransfer(loanTokenAddress, receiver, redeemed, \"asset transfer failed\");\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtc.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogicWrbtc is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtc\"));\n }\n\n /**\n * @dev internal override functions\n * @dev Put all of internal override function dedicated to the loanTokenWrtbc module here\n * e.g: _verifyTransfers will override the implementation of _verifyTransfers in loanTokenLogicSplit\n */\n\n /**\n * @notice Handle transfers prior to adding newPrincipal to loanTokenSent.\n *\n * @param collateralTokenAddress The address of the collateral token.\n * @param sentAddresses The struct which contains addresses of\n * - lender\n * - borrower\n * - receiver\n * - manager\n *\n * @param sentAmounts The struct which contains uint256 of:\n * - interestRate\n * - newPrincipal\n * - interestInitialAmount\n * - loanTokenSent\n * - collateralTokenSent\n *\n * @param withdrawalAmount The amount to withdraw.\n *\n * @return msgValue The amount of value sent.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = _wrbtcToken;\n address receiver = sentAddresses.receiver;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n IWrbtcERC20(_wrbtcToken).withdraw(withdrawalAmount);\n Address.sendValue(receiver, withdrawalAmount);\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n\n if (collateralTokenSent != 0) {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28\"\n );\n }\n\n if (loanTokenSent != 0) {\n if (msgValue != 0 && msgValue >= loanTokenSent) {\n IWrbtc(_wrbtcToken).deposit.value(loanTokenSent)();\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, loanTokenSent, \"29\");\n msgValue -= loanTokenSent;\n } else {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtcLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicWrbtcLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token Mint and Burn.\n res[0] = this.mint.selector;\n res[1] = this.burn.selector;\n\n // Loan Token WRBTC\n res[2] = this.mintWithBTC.selector;\n res[3] = this.burnToBTC.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtcLM\"));\n }\n\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n if (useLM) return _mintWithLM(receiver, msg.value);\n else return _mintToken(receiver, msg.value);\n }\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 loanAmountPaid) {\n loanAmountPaid = useLM ? _burnFromLM(burnAmount) : _burnToken(burnAmount);\n\n if (loanAmountPaid != 0) {\n IWrbtcERC20(wrbtcTokenAddress).withdraw(loanAmountPaid);\n Address.sendValue(receiver, loanAmountPaid);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/shared/LoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../AdvancedToken.sol\";\nimport \"../../interfaces/ProtocolSettingsLike.sol\";\nimport \"../../LoanTokenLogicStorage.sol\";\n\ncontract LoanTokenSettingsLowerAdmin is LoanTokenLogicStorage {\n using SafeMath for uint256;\n\n /// @dev TODO: Check for restrictions in this contract.\n modifier onlyAdmin() {\n require(isOwner() || msg.sender == admin, \"unauthorized\");\n _;\n }\n\n /* Events */\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](15);\n res[0] = this.setAdmin.selector;\n res[1] = this.setPauser.selector;\n res[2] = this.setupLoanParams.selector;\n res[3] = this.disableLoanParams.selector;\n res[4] = this.setDemandCurve.selector;\n res[5] = this.toggleFunctionPause.selector;\n res[6] = this.setTransactionLimits.selector;\n res[7] = this.changeLoanTokenNameAndSymbol.selector;\n res[8] = this.pauser.selector;\n res[9] = this.setLiquidityMiningAddress.selector;\n res[10] = this.withdrawRBTCTo.selector;\n res[11] = this.getLiquidityMiningAddress.selector;\n res[12] = this.checkPause.selector;\n res[13] = this.setStakingContractAddress.selector;\n res[14] = this.getStakingContractAddress.selector;\n return (res, stringToBytes32(\"LoanTokenSettingsLowerAdmin\"));\n }\n\n /**\n * @notice Set admin account.\n * @param _admin The address of the account to grant admin permissions.\n * */\n function setAdmin(address _admin) public onlyOwner {\n admin = _admin;\n }\n\n /**\n * @notice Set pauser account.\n * @param _pauser The address of the account to grant pause permissions.\n * */\n function setPauser(address _pauser) public onlyOwner {\n pauser = _pauser;\n }\n\n /**\n * @notice Fallback function not allowed\n * */\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n /**\n * @notice Set loan token parameters.\n *\n * @param loanParamsList The array of loan parameters.\n * @param areTorqueLoans Whether the loan is a torque loan.\n * */\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans /// isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n /**\n * @notice Disable loan token parameters.\n *\n * @param collateralTokens The array of collateral tokens.\n * @param isTorqueLoans Whether the loan is a torque loan.\n * */\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n /**\n * @notice Set loan token parameters about the demand curve.\n *\n * @dev These params should be percentages represented\n * like so: 5% = 5000000000000000000 /// 18 digits precision.\n * rateMultiplier + baseRate can't exceed 100%\n *\n * To maintain a healthy credit score, it's important to keep your\n * credit utilization rate (CUR) low (_lowUtilBaseRate). In general\n * you don't want your CUR to exceed 30%, but increasingly financial\n * experts are recommending that you don't want to go above 10% if you\n * really want an excellent credit score.\n *\n * Interest rates tend to cluster around the kink level of a kinked\n * interest rate model. More info at https://arxiv.org/pdf/2006.13922.pdf\n * and https://compound.finance/governance/proposals/12\n *\n * @param _baseRate The interest rate.\n * @param _rateMultiplier The precision multiplier for base rate.\n * @param _lowUtilBaseRate The credit utilization rate (CUR) low value.\n * @param _lowUtilRateMultiplier The precision multiplier for low util base rate.\n * @param _targetLevel The target level.\n * @param _kinkLevel The level that interest rates cluster on kinked model.\n * @param _maxScaleRate The maximum rate of the scale.\n * */\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; /// 80 ether\n kinkLevel = _kinkLevel; /// 90 ether\n maxScaleRate = _maxScaleRate; /// 100 ether\n }\n\n /**\n * @notice Set the pause flag for a function to true or false.\n *\n * @dev Combining the hash of \"iToken_FunctionPause\" string and a function\n * selector gets a slot to write a flag for pause state.\n *\n * @param funcId The ID of a function, the selector.\n * @param isPaused true/false value of the flag.\n * */\n function toggleFunctionPause(\n string memory funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyPauserOrOwner {\n bool paused;\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n paused := sload(slot)\n }\n require(paused != isPaused, \"isPaused is already set to that value\");\n assembly {\n sstore(slot, isPaused)\n }\n emit ToggledFunctionPaused(funcId, !isPaused, isPaused);\n }\n\n /**\n * Set the transaction limit per token address.\n * @param addresses The token addresses.\n * @param limits The limit denominated in the currency of the token address.\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyAdmin\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n\n /**\n *\t@notice Update the loan token parameters.\n *\t@param _name The new name of the loan token.\n *\t@param _symbol The new symbol of the loan token.\n * */\n function changeLoanTokenNameAndSymbol(string memory _name, string memory _symbol)\n public\n onlyAdmin\n {\n name = _name;\n symbol = _symbol;\n }\n\n /**\n * @notice Withdraws RBTC from the contract by Multisig.\n * @param _receiverAddress The address where the rBTC has to be transferred.\n * @param _amount The amount of rBTC to be transferred.\n */\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external onlyOwner {\n require(_receiverAddress != address(0), \"receiver address invalid\");\n require(_amount > 0, \"non-zero withdraw amount expected\");\n require(_amount <= address(this).balance, \"withdraw amount cannot exceed balance\");\n _receiverAddress.transfer(_amount);\n emit WithdrawRBTCTo(_receiverAddress, _amount);\n }\n\n /**\n * @notice sets the liquidity mining contract address\n * @param LMAddress the address of the liquidity mining contract\n */\n function setLiquidityMiningAddress(address LMAddress) external onlyOwner {\n liquidityMiningAddress = LMAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for liquidityMiningAddress\n\n\t * @return liquidityMiningAddress\n\t */\n function getLiquidityMiningAddress() public view returns (address) {\n return liquidityMiningAddress;\n }\n\n /**\n * @notice sets the staking contract address\n * @param _stakingContractAddress the address of the staking contract\n */\n function setStakingContractAddress(address _stakingContractAddress) external onlyOwner {\n stakingContractAddress = _stakingContractAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for stakingContractAddress\n\n\t * @return stakingContractAddress\n\t */\n function getStakingContractAddress() public view returns (address) {\n return stakingContractAddress;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param funcId The function ID, the selector.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function checkPause(string memory funcId) public view returns (bool isPaused) {\n bytes4 sig = bytes4(keccak256(abi.encodePacked(funcId)));\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n isPaused := sload(slot)\n }\n return isPaused;\n }\n}\n" + }, + "contracts/connectors/loantoken/Pausable.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Pausable contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * The contract implements pausable functionality by reading on slots the\n * pause state of contract functions.\n * */\ncontract Pausable {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 internal constant Pausable_FunctionPause =\n 0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047;\n\n modifier pausable(bytes4 sig) {\n require(!_isPaused(sig), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param sig The function ID, the selector on bytes4.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function _isPaused(bytes4 sig) internal view returns (bool isPaused) {\n bytes32 slot = keccak256(abi.encodePacked(sig, Pausable_FunctionPause));\n assembly {\n isPaused := sload(slot)\n }\n }\n}\n" + }, + "contracts/core/Objects.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./objects/LoanStruct.sol\";\nimport \"./objects/LoanParamsStruct.sol\";\nimport \"./objects/OrderStruct.sol\";\nimport \"./objects/LenderInterestStruct.sol\";\nimport \"./objects/LoanInterestStruct.sol\";\n\n/**\n * @title Objects contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract inherints and aggregates several structures needed to handle\n * loans on the protocol.\n * */\ncontract Objects is\n LoanStruct,\n LoanParamsStruct,\n OrderStruct,\n LenderInterestStruct,\n LoanInterestStruct\n{\n\n}\n" + }, + "contracts/core/objects/LenderInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Lender Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Lender Interest.\n * */\ncontract LenderInterestStruct {\n struct LenderInterest {\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\n uint256 paidTotal; /// Total interest paid so far for asset.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Interest.\n * */\ncontract LoanInterestStruct {\n struct LoanInterest {\n uint256 owedPerDay; /// Interest owed per day for loan.\n uint256 depositTotal; /// Total escrowed interest for loan.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanParamsStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Parameters.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Parameters.\n * */\ncontract LoanParamsStruct {\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n}\n" + }, + "contracts/core/objects/LoanStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Object.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Object.\n * */\ncontract LoanStruct {\n struct Loan {\n bytes32 id; /// ID of the loan.\n bytes32 loanParamsId; /// The linked loan params ID.\n bytes32 pendingTradesId; /// The linked pending trades ID.\n bool active; /// If false, the loan has been fully closed.\n uint256 principal; /// Total borrowed amount outstanding.\n uint256 collateral; /// Total collateral escrowed for the loan.\n uint256 startTimestamp; /// Loan start time.\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\n uint256 startMargin; /// Initial margin when the loan opened.\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\n address borrower; /// Borrower of this loan.\n address lender; /// Lender of this loan.\n }\n}\n" + }, + "contracts/core/objects/OrderStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Order.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Order.\n * */\ncontract OrderStruct {\n struct Order {\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\n uint256 interestRate; /// Interest rate defined by the creator of this order.\n uint256 minLoanTerm; /// Minimum loan term allowed.\n uint256 maxLoanTerm; /// Maximum loan term allowed.\n uint256 createdTimestamp; /// Timestamp when this order was created.\n uint256 expirationTimestamp; /// Timestamp when this order expires.\n }\n}\n" + }, + "contracts/core/Protocol.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./State.sol\";\n\n/**\n * @title Sovryn Protocol contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the proxy functionality to deploy Protocol anchor\n * and logic apart, turning it upgradable.\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822\n * */\ncontract sovrynProtocol is State {\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = logicTargets[msg.sig];\n require(target != address(0), \"target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice External owner target initializer.\n * @param target The target addresses.\n * */\n function replaceContract(address target) external onlyOwner {\n (bool success, ) =\n target.delegatecall(abi.encodeWithSignature(\"initialize(address)\", target));\n require(success, \"setup failed\");\n }\n\n /**\n * @notice External owner setter for target addresses.\n * @param sigsArr The array of signatures.\n * @param targetsArr The array of addresses.\n * */\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr)\n external\n onlyOwner\n {\n require(sigsArr.length == targetsArr.length, \"count mismatch\");\n\n for (uint256 i = 0; i < sigsArr.length; i++) {\n _setTarget(bytes4(keccak256(abi.encodePacked(sigsArr[i]))), targetsArr[i]);\n }\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(string calldata sig) external view returns (address) {\n return logicTargets[bytes4(keccak256(abi.encodePacked(sig)))];\n }\n}\n" + }, + "contracts/core/State.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./Objects.sol\";\nimport \"../mixins/EnumerableAddressSet.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/ReentrancyGuard.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title State contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage values of the Protocol.\n * */\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\n using SafeMath for uint256;\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n\n /// Handles asset reference price lookups.\n address public priceFeeds;\n\n /// Handles asset swaps using dex liquidity.\n address public swapsImpl;\n\n /// Contract registry address of the Sovryn swap network.\n address public sovrynSwapContractRegistryAddress;\n\n /// Implementations of protocol functions.\n mapping(bytes4 => address) public logicTargets;\n\n /// Loans: loanId => Loan\n mapping(bytes32 => Loan) public loans;\n\n /// Loan parameters: loanParamsId => LoanParams\n mapping(bytes32 => LoanParams) public loanParams;\n\n /// lender => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\n\n /// borrower => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\n\n /// loanId => delegated => approved\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\n\n /**\n *** Interest ***\n **/\n\n /// lender => loanToken => LenderInterest object\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\n\n /// loanId => LoanInterest object\n mapping(bytes32 => LoanInterest) public loanInterest;\n\n /**\n *** Internals ***\n **/\n\n /// Implementations set.\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\n\n /// Active loans set.\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\n\n /// Lender loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\n\n /// Borrow loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\n\n /// User loan params set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\n\n /// Address controlling fee withdrawals.\n address public feesController;\n\n /// 10% fee /// Fee taken from lender interest payments.\n uint256 public lendingFeePercent = 10**19;\n\n /// Total interest fees received and not withdrawn per asset.\n mapping(address => uint256) public lendingFeeTokensHeld;\n\n /// Total interest fees withdraw per asset.\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\n mapping(address => uint256) public lendingFeeTokensPaid;\n\n /// 0.15% fee /// Fee paid for each trade.\n uint256 public tradingFeePercent = 15 * 10**16;\n\n /// Total trading fees received and not withdrawn per asset.\n mapping(address => uint256) public tradingFeeTokensHeld;\n\n /// Total trading fees withdraw per asset\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\n mapping(address => uint256) public tradingFeeTokensPaid;\n\n /// 0.09% fee /// Origination fee paid for each loan.\n uint256 public borrowingFeePercent = 9 * 10**16;\n\n /// Total borrowing fees received and not withdrawn per asset.\n mapping(address => uint256) public borrowingFeeTokensHeld;\n\n /// Total borrowing fees withdraw per asset.\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\n mapping(address => uint256) public borrowingFeeTokensPaid;\n\n /// Current protocol token deposit balance.\n uint256 public protocolTokenHeld;\n\n /// Lifetime total payout of protocol token.\n uint256 public protocolTokenPaid;\n\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\n uint256 public affiliateFeePercent = 5 * 10**18;\n\n /// 5% collateral discount /// Discount on collateral for liquidators.\n uint256 public liquidationIncentivePercent = 5 * 10**18;\n\n /// loanPool => underlying\n mapping(address => address) public loanPoolToUnderlying;\n\n /// underlying => loanPool\n mapping(address => address) public underlyingToLoanPool;\n\n /// Loan pools set.\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\n\n /// Supported tokens for swaps.\n mapping(address => bool) public supportedTokens;\n\n /// % disagreement between swap rate and reference rate.\n uint256 public maxDisagreement = 5 * 10**18;\n\n /// Used as buffer for swap source amount estimations.\n uint256 public sourceBuffer = 10000;\n\n /// Maximum support swap size in rBTC\n uint256 public maxSwapSize = 50 ether;\n\n /// Nonce per borrower. Used for loan id creation.\n mapping(address => uint256) public borrowerNonce;\n\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\n uint256 public rolloverBaseReward = 16800000000000;\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\n\n IWrbtcERC20 public wrbtcToken;\n address public protocolTokenAddress;\n\n /// 50% fee rebate\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\n uint256 public feeRebatePercent = 50 * 10**18;\n\n address public admin;\n\n /// For modules interaction.\n address public protocolAddress;\n\n /**\n *** Affiliates ***\n **/\n\n /// The flag is set on the user's first trade.\n mapping(address => bool) public userNotFirstTradeFlag;\n\n /// User => referrer (affiliate).\n mapping(address => address) public affiliatesUserReferrer;\n\n /// List of referral addresses affiliated to the referrer.\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\n\n /// @dev Referral threshold for paying out to the referrer.\n /// The referrer reward is being accumulated and locked until the threshold is passed.\n uint256 public minReferralsToPayout = 3;\n\n /// @dev Total affiliate SOV rewards that held in the protocol\n /// (Because the minimum referrals is less than the rule)\n mapping(address => uint256) public affiliateRewardsHeld;\n\n /// @dev For affiliates SOV Bonus proccess.\n address public sovTokenAddress;\n address public lockedSOVAddress;\n\n /// @dev 20% fee share of trading token fee.\n /// Fee share of trading token fee for affiliate program.\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\n\n /// @dev Addresses of tokens in which commissions were paid to referrers.\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\n\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\n\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\n bool public pause; //Flag to pause all protocol modules\n\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\n\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\n uint256 internal tradingRebateRewardsBasisPoint;\n\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\n /// Will be used in internal swap.\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\n\n address internal pauser;\n\n /**\n * @notice Add signature and target to storage.\n * @dev Protocol is a proxy and requires a way to add every\n * module function dynamically during deployment.\n * */\n function _setTarget(bytes4 sig, address target) internal {\n logicTargets[sig] = target;\n\n if (target != address(0)) {\n logicTargetsSet.addBytes32(bytes32(sig));\n } else {\n logicTargetsSet.removeBytes32(bytes32(sig));\n }\n }\n\n modifier onlyAdminOrOwner() {\n require(isOwner() || admin == (msg.sender), \"unauthorized\");\n _;\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || pauser == (msg.sender), \"unauthorized\");\n _;\n }\n}\n" + }, + "contracts/escrow/Escrow.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Ethereum Pool to accept SOV Token.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice You can use this contract for deposit of SOV tokens for some time and withdraw later.\n */\ncontract Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalDeposit;\n /// @notice The release timestamp for the tokens deposited.\n uint256 public releaseTime;\n /// @notice The amount of token we would be accepting as deposit at max.\n uint256 public depositLimit;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The multisig contract which handles the fund.\n address public multisig;\n\n /// @notice The user balances.\n mapping(address => uint256) userBalances;\n\n /// @notice The current contract status.\n /// @notice Deployed - Deployed the contract.\n /// @notice Deposit - Time to deposit in the contract by the users.\n /// @notice Holding - Deposit is closed and now the holding period starts.\n /// @notice Withdraw - Time to withdraw in the contract by the users.\n /// @notice Expired - The contract is now closed completely.\n enum Status { Deployed, Deposit, Holding, Withdraw, Expired }\n Status public status;\n\n /* Events */\n\n /// @notice Emitted when the contract deposit starts.\n event EscrowActivated();\n\n /// @notice Emitted when the contract is put in holding state. No new token deposit accepted by User.\n event EscrowInHoldingState();\n\n /// @notice Emitted when the contract is put in withdraw state. Users can now withdraw tokens.\n event EscrowInWithdrawState();\n\n /// @notice Emitted when the contract is expired after withdraws are made/total token transfer.\n event EscrowFundExpired();\n\n /// @notice Emitted when a new multisig is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newMultisig The address which is added as the new multisig.\n /// @dev Can only be initiated by the current multisig.\n event NewMultisig(address indexed _initiator, address indexed _newMultisig);\n\n /// @notice Emitted when the release timestamp is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseTimestamp The updated release timestamp for the withdraw.\n event TokenReleaseUpdated(address indexed _initiator, uint256 _releaseTimestamp);\n\n /// @notice Emitted when the deposit limit is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _depositLimit The updated deposit limit.\n event TokenDepositLimitUpdated(address indexed _initiator, uint256 _depositLimit);\n\n /// @notice Emitted when a new token deposit is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when we reach the token deposit limit.\n event DepositLimitReached();\n\n /// @notice Emitted when a token withdraw is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdrawByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyMultisig() {\n require(msg.sender == multisig, \"Only Multisig can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n modifier checkRelease() {\n require(\n releaseTime != 0 && releaseTime <= block.timestamp,\n \"The release time has not started yet.\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_multisig != address(0), \"Invalid Multisig Address.\");\n\n SOV = IERC20(_SOV);\n multisig = _multisig;\n\n emit NewMultisig(msg.sender, _multisig);\n\n releaseTime = _releaseTime;\n depositLimit = _depositLimit;\n\n status = Status.Deployed;\n }\n\n /**\n * @notice This function is called once after deployment for starting the deposit action.\n * @dev Without calling this function, the contract will not start accepting tokens.\n */\n function init() external onlyMultisig checkStatus(Status.Deployed) {\n status = Status.Deposit;\n\n emit EscrowActivated();\n }\n\n /**\n * @notice Update Multisig.\n * @param _newMultisig The new owner of the tokens & contract.\n */\n function updateMultisig(address _newMultisig) external onlyMultisig {\n require(_newMultisig != address(0), \"New Multisig address invalid.\");\n\n multisig = _newMultisig;\n\n emit NewMultisig(msg.sender, _newMultisig);\n }\n\n /**\n * @notice Update Release Timestamp.\n * @param _newReleaseTime The new release timestamp for token release.\n * @dev Zero is also a valid timestamp, if the release time is not scheduled yet.\n */\n function updateReleaseTimestamp(uint256 _newReleaseTime) external onlyMultisig {\n releaseTime = _newReleaseTime;\n\n emit TokenReleaseUpdated(msg.sender, _newReleaseTime);\n }\n\n /**\n * @notice Update Deposit Limit.\n * @param _newDepositLimit The new deposit limit.\n * @dev IMPORTANT: Should not decrease than already deposited.\n */\n function updateDepositLimit(uint256 _newDepositLimit) external onlyMultisig {\n require(\n _newDepositLimit >= totalDeposit,\n \"Deposit already higher than the limit trying to be set.\"\n );\n depositLimit = _newDepositLimit;\n\n emit TokenDepositLimitUpdated(msg.sender, _newDepositLimit);\n }\n\n /**\n * @notice Deposit tokens to this contract by User.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the user inorder for this function to work.\n * These tokens can be withdrawn/transferred during Holding State by the Multisig.\n */\n function depositTokens(uint256 _amount) external checkStatus(Status.Deposit) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n uint256 amount = _amount;\n\n if (totalDeposit.add(_amount) >= depositLimit) {\n amount = depositLimit.sub(totalDeposit);\n emit DepositLimitReached();\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n userBalances[msg.sender] = userBalances[msg.sender].add(amount);\n totalDeposit = totalDeposit.add(amount);\n\n emit TokenDeposit(msg.sender, amount);\n }\n\n /**\n * @notice Update contract state to Holding.\n * @dev Once called, the contract no longer accepts any more deposits.\n * The multisig can now withdraw tokens from the contract after the contract is in Holding State.\n */\n function changeStateToHolding() external onlyMultisig checkStatus(Status.Deposit) {\n status = Status.Holding;\n\n emit EscrowInHoldingState();\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred. Zero address if the withdraw is to be done in Multisig.\n * @dev Can only be called after the token state is changed to Holding.\n */\n function withdrawTokensByMultisig(address _receiverAddress)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n address receiverAddress = msg.sender;\n if (_receiverAddress != address(0)) {\n receiverAddress = _receiverAddress;\n }\n\n uint256 value = SOV.balanceOf(address(this));\n /// Sending the amount to multisig.\n bool txStatus = SOV.transfer(receiverAddress, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdrawByMultisig(msg.sender, value);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n * Once the token deposit is higher than the total deposits done, the contract state is changed to Withdraw.\n */\n function depositTokensByMultisig(uint256 _amount)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDepositByMultisig(msg.sender, _amount);\n\n if (SOV.balanceOf(address(this)) >= totalDeposit) {\n status = Status.Withdraw;\n emit EscrowInWithdrawState();\n }\n }\n\n /**\n * @notice Withdraws token from the contract by User.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokens() public checkRelease checkStatus(Status.Withdraw) {\n uint256 amount = userBalances[msg.sender];\n userBalances[msg.sender] = 0;\n bool txStatus = SOV.transfer(msg.sender, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdraw(msg.sender, amount);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token balance of a particular user.\n * @return _addr The user address whose balance has to be checked.\n */\n function getUserBalance(address _addr) external view returns (uint256 balance) {\n return userBalances[_addr];\n }\n}\n" + }, + "contracts/escrow/EscrowReward.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Escrow.sol\";\nimport \"../locked/ILockedSOV.sol\";\n\n/**\n * @title A reward distribution contract for Sovryn Ethereum Pool Escrow Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice Multisig can use this contract for depositing of Reward tokens based on the total token deposit.\n */\ncontract EscrowReward is Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total reward tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalRewardDeposit;\n\n /// @notice The Locked SOV contract.\n ILockedSOV public lockedSOV;\n\n /* Events */\n\n /// @notice Emitted when the Locked SOV Contract address is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _lockedSOV The address of the Locked SOV Contract.\n event LockedSOVUpdated(address indexed _initiator, address indexed _lockedSOV);\n\n /// @notice Emitted when a new reward token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event RewardDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a Reward token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event RewardTokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _lockedSOV The Locked SOV Contract address.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _lockedSOV,\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public Escrow(_SOV, _multisig, _releaseTime, _depositLimit) {\n if (_lockedSOV != address(0)) {\n lockedSOV = ILockedSOV(_lockedSOV);\n }\n }\n\n /**\n * @notice Set the Locked SOV Contract Address if not already done.\n * @param _lockedSOV The Locked SOV Contract address.\n */\n function updateLockedSOV(address _lockedSOV) external onlyMultisig {\n require(_lockedSOV != address(0), \"Invalid Reward Token Address.\");\n\n lockedSOV = ILockedSOV(_lockedSOV);\n\n emit LockedSOVUpdated(msg.sender, _lockedSOV);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n */\n function depositRewardByMultisig(uint256 _amount) external onlyMultisig {\n require(\n status != Status.Withdraw,\n \"Reward Token deposit is only allowed before User Withdraw starts.\"\n );\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n totalRewardDeposit = totalRewardDeposit.add(_amount);\n txStatus = SOV.approve(address(lockedSOV), totalRewardDeposit);\n require(txStatus, \"Token Approval was not successful.\");\n\n emit RewardDepositByMultisig(msg.sender, _amount);\n }\n\n /**\n * @notice Withdraws token and reward from the contract by User. Reward is gone to lockedSOV contract for future vesting.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokensAndReward() external checkRelease checkStatus(Status.Withdraw) {\n // Reward calculation have to be done initially as the User Balance is zeroed out .\n uint256 reward = userBalances[msg.sender].mul(totalRewardDeposit).div(totalDeposit);\n withdrawTokens();\n\n lockedSOV.depositSOV(msg.sender, reward);\n\n emit RewardTokenWithdraw(msg.sender, reward);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the reward a particular user can get.\n * @param _addr The address of the user whose reward is to be read.\n * @return reward The reward received by the user.\n */\n function getReward(address _addr) external view returns (uint256 reward) {\n if (userBalances[_addr].mul(totalRewardDeposit) == 0) {\n return 0;\n }\n return userBalances[_addr].mul(totalRewardDeposit).div(totalDeposit);\n }\n}\n" + }, + "contracts/events/AffiliatesEvents.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\ncontract AffiliatesEvents is ModulesCommonEvents {\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\n\n event SetAffiliatesReferrerFail(\n address indexed user,\n address indexed referrer,\n bool alreadySet,\n bool userNotFirstTrade\n );\n\n event SetUserNotFirstTradeFlag(address indexed user);\n\n event PayTradingFeeToAffiliate(\n address indexed referrer,\n address trader,\n address indexed token,\n bool indexed isHeld,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountPaid\n );\n\n event PayTradingFeeToAffiliateFail(\n address indexed referrer,\n address trader,\n address indexed token,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountTryingToPaid\n );\n\n event WithdrawAffiliatesReferrerTokenFees(\n address indexed referrer,\n address indexed receiver,\n address indexed tokenAddress,\n uint256 amount\n );\n}\n" + }, + "contracts/events/FeesEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Fees Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for fee payments.\n * */\ncontract FeesEvents {\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\n\n event PayTradingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event PayBorrowingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event EarnReward(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n\n event EarnRewardFail(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n}\n" + }, + "contracts/events/LoanClosingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Closing Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan closing operations.\n * */\ncontract LoanClosingsEvents is ModulesCommonEvents {\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\n event CloseWithDeposit(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address closer,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\n event CloseWithSwap(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n address closer,\n uint256 positionCloseSize,\n uint256 loanCloseAmount,\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\n uint256 currentLeverage\n );\n\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\n event Liquidate(\n address indexed user,\n address indexed liquidator,\n bytes32 indexed loanId,\n address lender,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n event Rollover(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n uint256 principal,\n uint256 collateral,\n uint256 endTimestamp,\n address rewardReceiver,\n uint256 reward\n );\n\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\n}\n" + }, + "contracts/events/LoanMaintenanceEvents.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Maintenance Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan maintenance operations.\n * */\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\n}\n" + }, + "contracts/events/LoanOpeningsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Openings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan openings operations.\n * */\ncontract LoanOpeningsEvents is ModulesCommonEvents {\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\n event Borrow(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 newCollateral,\n uint256 interestRate,\n uint256 interestDuration,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\n event Trade(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n uint256 positionSize,\n uint256 borrowedAmount,\n uint256 interestRate,\n uint256 settlementDate,\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\n uint256 entryLeverage,\n uint256 currentLeverage\n );\n\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\n event DelegatedManagerSet(\n bytes32 indexed loanId,\n address indexed delegator,\n address indexed delegated,\n bool isActive\n );\n}\n" + }, + "contracts/events/LoanSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan settings operations.\n * */\ncontract LoanSettingsEvents is ModulesCommonEvents {\n event LoanParamsSetup(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\n\n event LoanParamsDisabled(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\n}\n" + }, + "contracts/events/ModulesCommonEvents.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title The common events for all modules\n * @notice This contract contains the events which will be used by all modules\n **/\n\ncontract ModulesCommonEvents {\n event ProtocolModuleContractReplaced(\n address indexed prevModuleContractAddress,\n address indexed newModuleContractAddress,\n bytes32 indexed module\n );\n}\n" + }, + "contracts/events/ProtocolSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title The Protocol Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for protocol settings operations.\n * */\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\n\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\n\n event SetLoanPool(\n address indexed sender,\n address indexed loanPool,\n address indexed underlying\n );\n\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\n\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateTradingTokenFeePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetLiquidationIncentivePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetFeesController(\n address indexed sender,\n address indexed oldController,\n address indexed newController\n );\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWethToken,\n address indexed newWethToken\n );\n\n event SetSovrynSwapContractRegistryAddress(\n address indexed sender,\n address indexed oldSovrynSwapContractRegistryAddress,\n address indexed newSovrynSwapContractRegistryAddress\n );\n\n event SetProtocolTokenAddress(\n address indexed sender,\n address indexed oldProtocolToken,\n address indexed newProtocolToken\n );\n\n event WithdrawFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 lendingAmount,\n uint256 tradingAmount,\n uint256 borrowingAmount,\n uint256 wRBTCConverted\n );\n\n event WithdrawLendingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawTradingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawBorrowingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetRebatePercent(\n address indexed sender,\n uint256 oldRebatePercent,\n uint256 newRebatePercent\n );\n\n event SetSpecialRebates(\n address indexed sender,\n address indexed sourceToken,\n address indexed destToken,\n uint256 oldSpecialRebatesPercent,\n uint256 newSpecialRebatesPercent\n );\n\n event SetProtocolAddress(\n address indexed sender,\n address indexed oldProtocol,\n address indexed newProtocol\n );\n\n event SetMinReferralsToPayoutAffiliates(\n address indexed sender,\n uint256 oldMinReferrals,\n uint256 newMinReferrals\n );\n\n event SetSOVTokenAddress(\n address indexed sender,\n address indexed oldTokenAddress,\n address indexed newTokenAddress\n );\n\n event SetLockedSOVAddress(\n address indexed sender,\n address indexed oldAddress,\n address indexed newAddress\n );\n\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\n\n event SetTradingRebateRewardsBasisPoint(\n address indexed sender,\n uint256 oldBasisPoint,\n uint256 newBasisPoint\n );\n\n event SetRolloverFlexFeePercent(\n address indexed sender,\n uint256 oldRolloverFlexFeePercent,\n uint256 newRolloverFlexFeePercent\n );\n\n event SetDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event RemoveDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n}\n" + }, + "contracts/events/SwapsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Swaps Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for swap operations.\n * */\ncontract SwapsEvents is ModulesCommonEvents {\n event LoanSwap(\n bytes32 indexed loanId,\n address indexed sourceToken,\n address indexed destToken,\n address borrower,\n uint256 sourceAmount,\n uint256 destAmount\n );\n\n event ExternalSwap(\n address indexed user,\n address indexed sourceToken,\n address indexed destToken,\n uint256 sourceAmount,\n uint256 destAmount\n );\n}\n" + }, + "contracts/farm/ILiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\n\ninterface ILiquidityMining {\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external;\n\n function onTokensDeposited(address _user, uint256 _amount) external;\n\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/farm/LiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./LiquidityMiningStorage.sol\";\nimport \"./ILiquidityMining.sol\";\n\ncontract LiquidityMining is ILiquidityMining, LiquidityMiningStorage {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n /* Constants */\n\n uint256 public constant PRECISION = 1e12;\n // Bonus multiplier for early liquidity providers.\n // During bonus period each passed block will be calculated like N passed blocks, where N = BONUS_MULTIPLIER\n uint256 public constant BONUS_BLOCK_MULTIPLIER = 10;\n\n uint256 public constant SECONDS_PER_BLOCK = 30;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event PoolTokenAdded(address indexed user, address indexed poolToken, uint256 allocationPoint);\n event PoolTokenUpdated(\n address indexed user,\n address indexed poolToken,\n uint256 newAllocationPoint,\n uint256 oldAllocationPoint\n );\n event Deposit(address indexed user, address indexed poolToken, uint256 amount);\n event RewardClaimed(address indexed user, address indexed poolToken, uint256 amount);\n event Withdraw(address indexed user, address indexed poolToken, uint256 amount);\n event EmergencyWithdraw(\n address indexed user,\n address indexed poolToken,\n uint256 amount,\n uint256 accumulatedReward\n );\n\n /* Functions */\n\n /**\n * @notice Initialize mining.\n *\n * @param _SOV The SOV token.\n * @param _rewardTokensPerBlock The number of reward tokens per block.\n * @param _startDelayBlocks The number of blocks should be passed to start\n * mining.\n * @param _numberOfBonusBlocks The number of blocks when each block will\n * be calculated as N blocks (BONUS_BLOCK_MULTIPLIER).\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n * SOV rewards are not paid directly to liquidity providers. Instead they\n * are deposited into a lockedSOV vault contract.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n */\n function initialize(\n IERC20 _SOV,\n uint256 _rewardTokensPerBlock,\n uint256 _startDelayBlocks,\n uint256 _numberOfBonusBlocks,\n address _wrapper,\n ILockedSOV _lockedSOV,\n uint256 _unlockedImmediatelyPercent\n ) external onlyAuthorized {\n /// @dev Non-idempotent function. Must be called just once.\n require(address(SOV) == address(0), \"Already initialized\");\n require(address(_SOV) != address(0), \"Invalid token address\");\n require(_startDelayBlocks > 0, \"Invalid start block\");\n require(\n _unlockedImmediatelyPercent < 10000,\n \"Unlocked immediately percent has to be less than 10000.\"\n );\n\n SOV = _SOV;\n rewardTokensPerBlock = _rewardTokensPerBlock;\n startBlock = block.number + _startDelayBlocks;\n bonusEndBlock = startBlock + _numberOfBonusBlocks;\n wrapper = _wrapper;\n lockedSOV = _lockedSOV;\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets lockedSOV contract.\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n */\n function setLockedSOV(ILockedSOV _lockedSOV) external onlyAuthorized {\n require(address(_lockedSOV) != address(0), \"Invalid lockedSOV Address.\");\n lockedSOV = _lockedSOV;\n }\n\n /**\n * @notice Sets unlocked immediately percent.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setUnlockedImmediatelyPercent(uint256 _unlockedImmediatelyPercent)\n external\n onlyAuthorized\n {\n require(\n _unlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets unlocked immediately percent overwrite for specific pool token.\n * @param _poolToken the address of pool token\n * @param _poolTokenUnlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setPoolTokenUnlockedImmediatelyPercent(\n address _poolToken,\n uint256 _poolTokenUnlockedImmediatelyPercent\n ) external onlyAuthorized {\n require(\n _poolTokenUnlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n poolTokensUnlockedImmediatelyPercent[_poolToken] = _poolTokenUnlockedImmediatelyPercent;\n }\n\n /**\n * @notice sets wrapper proxy contract\n * @dev can be set to zero address to remove wrapper\n */\n function setWrapper(address _wrapper) external onlyAuthorized {\n wrapper = _wrapper;\n }\n\n /**\n * @notice stops mining by setting end block\n */\n function stopMining() external onlyAuthorized {\n require(endBlock == 0, \"Already stopped\");\n\n endBlock = block.number;\n }\n\n /**\n * @notice Transfers SOV tokens to given address.\n * Owner use this function to withdraw SOV from LM contract\n * into another account.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) external onlyAuthorized {\n require(_receiver != address(0), \"Receiver address invalid\");\n require(_amount != 0, \"Amount invalid\");\n\n /// @dev Do not transfer more SOV than available.\n uint256 SOVBal = SOV.balanceOf(address(this));\n if (_amount > SOVBal) {\n _amount = SOVBal;\n }\n\n /// @dev The actual transfer.\n require(SOV.transfer(_receiver, _amount), \"Transfer failed\");\n\n /// @dev Event log.\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Get the missed SOV balance of LM contract.\n *\n * @return The amount of SOV tokens according to totalUsersBalance\n * in excess of actual SOV balance of the LM contract.\n * */\n function getMissedBalance() external view returns (uint256) {\n uint256 balance = SOV.balanceOf(address(this));\n return balance >= totalUsersBalance ? 0 : totalUsersBalance.sub(balance);\n }\n\n /**\n * @notice adds a new lp to the pool. Can only be called by the owner or an admin\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _withUpdate the flag whether we need to update all pools\n */\n function add(\n address _poolToken,\n uint96 _allocationPoint,\n bool _withUpdate\n ) external onlyAuthorized {\n require(_allocationPoint > 0, \"Invalid allocation point\");\n require(_poolToken != address(0), \"Invalid token address\");\n require(poolIdList[_poolToken] == 0, \"Token already added\");\n\n if (_withUpdate) {\n updateAllPools();\n }\n\n uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;\n totalAllocationPoint = totalAllocationPoint.add(_allocationPoint);\n\n poolInfoList.push(\n PoolInfo({\n poolToken: IERC20(_poolToken),\n allocationPoint: _allocationPoint,\n lastRewardBlock: lastRewardBlock,\n accumulatedRewardPerShare: 0\n })\n );\n //indexing starts from 1 in order to check whether token was already added\n poolIdList[_poolToken] = poolInfoList.length;\n\n emit PoolTokenAdded(msg.sender, _poolToken, _allocationPoint);\n }\n\n /**\n * @notice updates the given pool's reward tokens allocation point\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function update(\n address _poolToken,\n uint96 _allocationPoint,\n bool _updateAllFlag\n ) external onlyAuthorized {\n if (_updateAllFlag) {\n updateAllPools();\n } else {\n updatePool(_poolToken);\n }\n _updateToken(_poolToken, _allocationPoint);\n }\n\n function _updateToken(address _poolToken, uint96 _allocationPoint) internal {\n uint256 poolId = _getPoolId(_poolToken);\n\n uint256 previousAllocationPoint = poolInfoList[poolId].allocationPoint;\n totalAllocationPoint = totalAllocationPoint.sub(previousAllocationPoint).add(\n _allocationPoint\n );\n poolInfoList[poolId].allocationPoint = _allocationPoint;\n\n emit PoolTokenUpdated(msg.sender, _poolToken, _allocationPoint, previousAllocationPoint);\n }\n\n /**\n * @notice updates the given pools' reward tokens allocation points\n * @param _poolTokens array of addresses of pool tokens\n * @param _allocationPoints array of allocation points (weight) for the given pools\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function updateTokens(\n address[] calldata _poolTokens,\n uint96[] calldata _allocationPoints,\n bool _updateAllFlag\n ) external onlyAuthorized {\n require(_poolTokens.length == _allocationPoints.length, \"Arrays mismatch\");\n\n if (_updateAllFlag) {\n updateAllPools();\n }\n uint256 length = _poolTokens.length;\n for (uint256 i = 0; i < length; i++) {\n if (!_updateAllFlag) {\n updatePool(_poolTokens[i]);\n }\n _updateToken(_poolTokens[i], _allocationPoints[i]);\n }\n }\n\n /**\n * @notice returns reward multiplier over the given _from to _to block\n * @param _from the first block for a calculation\n * @param _to the last block for a calculation\n */\n function _getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n internal\n view\n returns (uint256)\n {\n if (_from < startBlock) {\n _from = startBlock;\n }\n if (endBlock > 0 && _to > endBlock) {\n _to = endBlock;\n }\n if (_to <= bonusEndBlock) {\n return _to.sub(_from).mul(BONUS_BLOCK_MULTIPLIER);\n } else if (_from >= bonusEndBlock) {\n return _to.sub(_from);\n } else {\n return\n bonusEndBlock.sub(_from).mul(BONUS_BLOCK_MULTIPLIER).add(_to.sub(bonusEndBlock));\n }\n }\n\n function _getUserAccumulatedReward(uint256 _poolId, address _user)\n internal\n view\n returns (uint256)\n {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_user];\n\n uint256 accumulatedRewardPerShare = pool.accumulatedRewardPerShare;\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (block.number > pool.lastRewardBlock && poolTokenBalance != 0) {\n (, uint256 accumulatedRewardPerShare_) = _getPoolAccumulatedReward(pool);\n accumulatedRewardPerShare = accumulatedRewardPerShare.add(accumulatedRewardPerShare_);\n }\n\n return\n user.accumulatedReward.add(\n user.amount.mul(accumulatedRewardPerShare).div(PRECISION).sub(user.rewardDebt)\n );\n }\n\n /**\n * @notice returns accumulated reward\n * @param _poolToken the address of pool token\n * @param _user the user address\n */\n function getUserAccumulatedReward(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n uint256 poolId = _getPoolId(_poolToken);\n return _getUserAccumulatedReward(poolId, _user);\n }\n\n /**\n * @notice returns estimated reward\n * @param _poolToken the address of pool token\n * @param _amount the amount of tokens to be deposited\n * @param _duration the duration of liquidity providing in seconds\n */\n function getEstimatedReward(\n address _poolToken,\n uint256 _amount,\n uint256 _duration\n ) external view returns (uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n uint256 start = block.number;\n uint256 end = start.add(_duration.div(SECONDS_PER_BLOCK));\n (, uint256 accumulatedRewardPerShare) =\n _getPoolAccumulatedReward(pool, _amount, start, end);\n return _amount.mul(accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Updates reward variables for all pools.\n * @dev Be careful of gas spending!\n */\n function updateAllPools() public {\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n _updatePool(i);\n }\n }\n\n /**\n * @notice Updates reward variables of the given pool to be up-to-date\n * @param _poolToken the address of pool token\n */\n function updatePool(address _poolToken) public {\n uint256 poolId = _getPoolId(_poolToken);\n _updatePool(poolId);\n }\n\n function _updatePool(uint256 _poolId) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n\n //this pool has been updated recently\n if (block.number <= pool.lastRewardBlock) {\n return;\n }\n\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (poolTokenBalance == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n (uint256 accumulatedReward_, uint256 accumulatedRewardPerShare_) =\n _getPoolAccumulatedReward(pool);\n pool.accumulatedRewardPerShare = pool.accumulatedRewardPerShare.add(\n accumulatedRewardPerShare_\n );\n pool.lastRewardBlock = block.number;\n\n totalUsersBalance = totalUsersBalance.add(accumulatedReward_);\n }\n\n function _getPoolAccumulatedReward(PoolInfo storage _pool)\n internal\n view\n returns (uint256, uint256)\n {\n return _getPoolAccumulatedReward(_pool, 0, _pool.lastRewardBlock, block.number);\n }\n\n function _getPoolAccumulatedReward(\n PoolInfo storage _pool,\n uint256 _additionalAmount,\n uint256 _startBlock,\n uint256 _endBlock\n ) internal view returns (uint256, uint256) {\n uint256 passedBlocks = _getPassedBlocksWithBonusMultiplier(_startBlock, _endBlock);\n uint256 accumulatedReward =\n passedBlocks.mul(rewardTokensPerBlock).mul(_pool.allocationPoint).div(\n totalAllocationPoint\n );\n\n uint256 poolTokenBalance = _pool.poolToken.balanceOf(address(this));\n poolTokenBalance = poolTokenBalance.add(_additionalAmount);\n uint256 accumulatedRewardPerShare = accumulatedReward.mul(PRECISION).div(poolTokenBalance);\n return (accumulatedReward, accumulatedRewardPerShare);\n }\n\n /**\n * @notice deposits pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it or to msg.sender\n */\n function deposit(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n _deposit(_poolToken, _amount, _user, false);\n }\n\n /**\n * @notice if the lending pools directly mint/transfer tokens to this address, process it like a user deposit\n * @dev only callable by the pool which issues the tokens\n * @param _user the user address\n * @param _amount the minted amount\n */\n function onTokensDeposited(address _user, uint256 _amount) external {\n //the msg.sender is the pool token. if the msg.sender is not a valid pool token, _deposit will revert\n _deposit(msg.sender, _amount, _user, true);\n }\n\n /**\n * @notice internal function for depositing pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it\n * @param alreadyTransferred true if the pool tokens have already been transferred\n */\n function _deposit(\n address _poolToken,\n uint256 _amount,\n address _user,\n bool alreadyTransferred\n ) internal {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _user != address(0) ? _user : msg.sender;\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n\n _updatePool(poolId);\n //sends reward directly to the user\n _updateReward(pool, user);\n\n if (_amount > 0) {\n //receives pool tokens from msg.sender, it can be user or WrapperProxy contract\n if (!alreadyTransferred)\n pool.poolToken.safeTransferFrom(address(msg.sender), address(this), _amount);\n user.amount = user.amount.add(_amount);\n }\n _updateRewardDebt(pool, user);\n emit Deposit(userAddress, _poolToken, _amount);\n }\n\n /**\n * @notice transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimReward(address _poolToken, address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n _claimReward(poolId, userAddress, true);\n }\n\n function _claimReward(\n uint256 _poolId,\n address _userAddress,\n bool _isStakingTokens\n ) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_userAddress];\n\n _updatePool(_poolId);\n _updateReward(pool, user);\n _transferReward(address(pool.poolToken), user, _userAddress, _isStakingTokens, true);\n _updateRewardDebt(pool, user);\n }\n\n /**\n * @notice transfers reward tokens from all pools\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimRewardFromAllPools(address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n uint256 poolId = i;\n _claimReward(poolId, userAddress, false);\n }\n\n if (\n lockedSOV.getLockedBalance(userAddress) > 0 ||\n lockedSOV.getUnlockedBalance(userAddress) > 0\n ) {\n lockedSOV.withdrawAndStakeTokensFrom(userAddress);\n }\n }\n\n /**\n * @notice withdraws pool tokens and transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the user address will be used to process a withdrawal (can be passed only by wrapper contract)\n */\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n require(user.amount >= _amount, \"Not enough balance\");\n\n _updatePool(poolId);\n _updateReward(pool, user);\n _transferReward(_poolToken, user, userAddress, false, false);\n\n user.amount = user.amount.sub(_amount);\n\n //msg.sender is wrapper -> send to wrapper\n if (msg.sender == wrapper) {\n pool.poolToken.safeTransfer(address(msg.sender), _amount);\n }\n //msg.sender is user or pool token (lending pool) -> send to user\n else {\n pool.poolToken.safeTransfer(userAddress, _amount);\n }\n\n _updateRewardDebt(pool, user);\n emit Withdraw(userAddress, _poolToken, _amount);\n }\n\n function _getUserAddress(address _user) internal view returns (address) {\n address userAddress = msg.sender;\n if (_user != address(0)) {\n //only wrapper can pass _user parameter\n require(\n msg.sender == wrapper || poolIdList[msg.sender] != 0,\n \"only wrapper or pools may withdraw for a user\"\n );\n userAddress = _user;\n }\n return userAddress;\n }\n\n function _updateReward(PoolInfo storage pool, UserInfo storage user) internal {\n //update user accumulated reward\n if (user.amount > 0) {\n //add reward for the previous amount of deposited tokens\n uint256 accumulatedReward =\n user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION).sub(\n user.rewardDebt\n );\n user.accumulatedReward = user.accumulatedReward.add(accumulatedReward);\n }\n }\n\n function _updateRewardDebt(PoolInfo storage pool, UserInfo storage user) internal {\n //reward accumulated before amount update (should be subtracted during next reward calculation)\n user.rewardDebt = user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Send reward in SOV to the lockedSOV vault.\n * @param _user The user info, to get its reward share.\n * @param _userAddress The address of the user, to send SOV in its behalf.\n * @param _isStakingTokens The flag whether we need to stake tokens\n * @param _isCheckingBalance The flag whether we need to throw error or don't process reward if SOV balance isn't enough\n */\n function _transferReward(\n address _poolToken,\n UserInfo storage _user,\n address _userAddress,\n bool _isStakingTokens,\n bool _isCheckingBalance\n ) internal {\n uint256 userAccumulatedReward = _user.accumulatedReward;\n /// @dev get unlock immediate percent of the pool token.\n uint256 calculatedUnlockedImmediatelyPercent = calcUnlockedImmediatelyPercent(_poolToken);\n\n /// @dev Transfer if enough SOV balance on this LM contract.\n uint256 balance = SOV.balanceOf(address(this));\n if (balance >= userAccumulatedReward) {\n totalUsersBalance = totalUsersBalance.sub(userAccumulatedReward);\n _user.accumulatedReward = 0;\n\n /// @dev If calculatedUnlockedImmediatelyPercent is 100%, transfer the reward to the LP (user).\n /// else, deposit it into lockedSOV vault contract, but first\n /// SOV deposit must be approved to move the SOV tokens\n /// from this LM contract into the lockedSOV vault.\n if (calculatedUnlockedImmediatelyPercent == 10000) {\n SOV.transfer(_userAddress, userAccumulatedReward);\n } else {\n require(SOV.approve(address(lockedSOV), userAccumulatedReward), \"Approve failed\");\n lockedSOV.deposit(\n _userAddress,\n userAccumulatedReward,\n calculatedUnlockedImmediatelyPercent\n );\n\n if (_isStakingTokens) {\n lockedSOV.withdrawAndStakeTokensFrom(_userAddress);\n }\n }\n\n /// @dev Event log.\n emit RewardClaimed(_userAddress, _poolToken, userAccumulatedReward);\n } else {\n require(!_isCheckingBalance, \"Claiming reward failed\");\n }\n }\n\n /**\n * @notice withdraws pool tokens without transferring reward tokens\n * @param _poolToken the address of pool token\n * @dev EMERGENCY ONLY\n */\n function emergencyWithdraw(address _poolToken) external {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][msg.sender];\n\n _updatePool(poolId);\n _updateReward(pool, user);\n\n totalUsersBalance = totalUsersBalance.sub(user.accumulatedReward);\n uint256 userAmount = user.amount;\n uint256 userAccumulatedReward = user.accumulatedReward;\n user.amount = 0;\n user.rewardDebt = 0;\n user.accumulatedReward = 0;\n pool.poolToken.safeTransfer(address(msg.sender), userAmount);\n\n emit EmergencyWithdraw(msg.sender, _poolToken, userAmount, userAccumulatedReward);\n }\n\n /**\n * @notice returns pool id\n * @param _poolToken the address of pool token\n */\n function getPoolId(address _poolToken) external view returns (uint256) {\n return _getPoolId(_poolToken);\n }\n\n function _getPoolId(address _poolToken) internal view returns (uint256) {\n uint256 poolId = poolIdList[_poolToken];\n require(poolId > 0, \"Pool token not found\");\n return poolId - 1;\n }\n\n /**\n * @notice returns count of pool tokens\n */\n function getPoolLength() external view returns (uint256) {\n return poolInfoList.length;\n }\n\n /**\n * @notice returns list of pool token's info\n */\n function getPoolInfoList() external view returns (PoolInfo[] memory) {\n return poolInfoList;\n }\n\n /**\n * @notice returns pool info for the given token\n * @param _poolToken the address of pool token\n */\n function getPoolInfo(address _poolToken) external view returns (PoolInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return poolInfoList[poolId];\n }\n\n /**\n * @notice returns list of [amount, accumulatedReward] for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserBalanceList(address _user) external view returns (uint256[2][] memory) {\n uint256 length = poolInfoList.length;\n uint256[2][] memory userBalanceList = new uint256[2][](length);\n for (uint256 i = 0; i < length; i++) {\n userBalanceList[i][0] = userInfoMap[i][_user].amount;\n userBalanceList[i][1] = _getUserAccumulatedReward(i, _user);\n }\n return userBalanceList;\n }\n\n /**\n * @notice returns UserInfo for the given pool and user\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserInfo(address _poolToken, address _user) public view returns (UserInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return userInfoMap[poolId][_user];\n }\n\n /**\n * @notice returns list of UserInfo for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserInfoList(address _user) external view returns (UserInfo[] memory) {\n uint256 length = poolInfoList.length;\n UserInfo[] memory userInfoList = new UserInfo[](length);\n for (uint256 i = 0; i < length; i++) {\n userInfoList[i] = userInfoMap[i][_user];\n }\n return userInfoList;\n }\n\n /**\n * @notice returns accumulated reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardList(address _user) external view returns (uint256[] memory) {\n uint256 length = poolInfoList.length;\n uint256[] memory rewardList = new uint256[](length);\n for (uint256 i = 0; i < length; i++) {\n rewardList[i] = _getUserAccumulatedReward(i, _user);\n }\n return rewardList;\n }\n\n /**\n * @notice returns the pool token balance a user has on the contract\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n UserInfo memory ui = getUserInfo(_poolToken, _user);\n return ui.amount;\n }\n\n /**\n * @notice returns the accumulated liquid reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBePaidLiquid(address _user)\n external\n view\n returns (uint256)\n {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n calculatedUnlockedImmediatelyPercent.mul(_getUserAccumulatedReward(i, _user)).div(\n 10000\n )\n );\n }\n\n return result;\n }\n\n /**\n * @notice returns the accumulated vested reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBeVested(address _user) external view returns (uint256) {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n (10000 - calculatedUnlockedImmediatelyPercent)\n .mul(_getUserAccumulatedReward(i, _user))\n .div(10000)\n );\n }\n\n return result;\n }\n\n /**\n * @dev calculate the unlocked immediate percentage of specific pool token\n * use the poolTokensUnlockedImmediatelyPercent by default, if it is not set, then use the unlockedImmediatelyPercent\n */\n function calcUnlockedImmediatelyPercent(address _poolToken) public view returns (uint256) {\n uint256 poolTokenUnlockedImmediatelyPercent =\n poolTokensUnlockedImmediatelyPercent[_poolToken];\n return\n poolTokenUnlockedImmediatelyPercent > 0\n ? poolTokenUnlockedImmediatelyPercent\n : unlockedImmediatelyPercent;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningConfigToken.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/IERC20_.sol\";\n\n/**\n * @title Dummy token with 0 total supply.\n *\n * @dev We need this token for having a flexibility with LiquidityMining configuration\n */\ncontract LiquidityMiningConfigToken is IERC20_ {\n function totalSupply() external view returns (uint256) {\n return 0;\n }\n\n function balanceOf(address account) external view returns (uint256) {\n return 0;\n }\n\n function transfer(address recipient, uint256 amount) external returns (bool) {\n return false;\n }\n\n function allowance(address owner, address spender) external view returns (uint256) {\n return 0;\n }\n\n function approve(address spender, uint256 amount) external returns (bool) {\n return false;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool) {\n return false;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./LiquidityMiningStorage.sol\";\nimport \"../proxy/UpgradableProxy.sol\";\n\n/**\n * @dev LiquidityMining contract should be upgradable, use UpgradableProxy\n */\ncontract LiquidityMiningProxy is LiquidityMiningStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/farm/LiquidityMiningStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../utils/AdminRole.sol\";\n\ncontract LiquidityMiningStorage is AdminRole {\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many pool tokens the user has provided.\n uint256 rewardDebt; // Reward debt. See explanation below.\n uint256 accumulatedReward; //Reward that's ready to be transferred\n //\n // We do some fancy math here. Basically, any point in time, the amount of reward tokens\n // entitled to a user but is accumulated to be distributed is:\n //\n // accumulated reward = (user.amount * pool.accumulatedRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accumulatedRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the accumulated reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 poolToken; // Address of LP token contract.\n uint96 allocationPoint; // How many allocation points assigned to this pool. Amount of reward tokens to distribute per block.\n uint256 lastRewardBlock; // Last block number that reward tokens distribution occurs.\n uint256 accumulatedRewardPerShare; // Accumulated amount of reward tokens per share, times 1e12. See below.\n }\n\n // Rewards tokens created per block.\n uint256 public rewardTokensPerBlock;\n // The block number when reward token mining starts.\n uint256 public startBlock;\n // Block number when bonus reward token period ends.\n uint256 public bonusEndBlock;\n // Block number when reward token period ends.\n uint256 public endBlock;\n\n //Wrapper contract which will be a proxy between user and LM\n address public wrapper;\n\n // Info of each pool.\n PoolInfo[] public poolInfoList;\n // Mapping pool token address => pool id\n mapping(address => uint256) poolIdList;\n // Total allocation points. Must be the sum of all allocation points in all pools.\n uint256 public totalAllocationPoint;\n\n // Info of each user that stakes LP tokens.\n mapping(uint256 => mapping(address => UserInfo)) public userInfoMap;\n // Total balance this contract should have to handle withdrawal for all users\n uint256 public totalUsersBalance;\n\n /// @dev The SOV token\n IERC20 public SOV;\n\n /// @dev The locked vault contract to deposit LP's rewards into.\n ILockedSOV public lockedSOV;\n\n // The % which determines how much will be unlocked immediately.\n /// @dev 10000 is 100%\n uint256 public unlockedImmediatelyPercent;\n\n /// @dev overwrite the unlockedImmediatelyPercent for specific token.\n mapping(address => uint256) public poolTokensUnlockedImmediatelyPercent;\n}\n" + }, + "contracts/feeds/BProPriceFeed.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IMoCState.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The BPro Price Feed contract.\n *\n * This contract gets/sets the MoC (Money on Chain) address of its state\n * contract and queries its method bproUsdPrice to get bPro/USD valuation.\n * */\ncontract BProPriceFeed is IPriceFeedsExt, Ownable {\n address public mocStateAddress;\n\n event SetMoCStateAddress(address indexed mocStateAddress, address changerAddress);\n\n /**\n * @notice Initializes a new MoC state.\n *\n * @param _mocStateAddress MoC state address\n * */\n constructor(address _mocStateAddress) public {\n setMoCStateAddress(_mocStateAddress);\n }\n\n /**\n * @notice Get BPro USD price.\n *\n * @return the BPro USD Price [using mocPrecision]\n */\n function latestAnswer() external view returns (uint256) {\n IMoCState _mocState = IMoCState(mocStateAddress);\n return _mocState.bproUsdPrice();\n }\n\n /**\n * @notice Supposed to get the MoC update time, but instead\n * get the current timestamp.\n *\n * @return Always returns current block's timestamp.\n * */\n function latestTimestamp() external view returns (uint256) {\n return now; /// MoC state doesn't return update timestamp.\n }\n\n /**\n * @notice Set MoC state address.\n *\n * @param _mocStateAddress The MoC state address.\n * */\n function setMoCStateAddress(address _mocStateAddress) public onlyOwner {\n require(Address.isContract(_mocStateAddress), \"_mocStateAddress not a contract\");\n mocStateAddress = _mocStateAddress;\n emit SetMoCStateAddress(mocStateAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/IMoCState.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IMoCState {\n function getRbtcInBitPro(bytes32 bucket) external view returns (uint256);\n\n function globalMaxBPro() external view returns (uint256);\n\n function maxBPro(bytes32 bucket) external view returns (uint256);\n\n function absoluteMaxBPro() external view returns (uint256);\n\n function maxBProWithDiscount() external view returns (uint256);\n\n function bproTecPrice() external view returns (uint256);\n\n function bucketBProTecPrice(bytes32 bucket) external view returns (uint256);\n\n function bproDiscountPrice() external view returns (uint256);\n\n function bproUsdPrice() external view returns (uint256);\n\n function bproSpotDiscountRate() external view returns (uint256);\n\n function getBucketNBPro(bytes32 bucket) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IPriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface IPriceFeeds {\n function queryRate(address sourceToken, address destToken)\n external\n view\n returns (uint256 rate, uint256 precision);\n\n function queryPrecision(address sourceToken, address destToken)\n external\n view\n returns (uint256 precision);\n\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) external view returns (uint256 destAmount);\n\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) external view returns (uint256 sourceToDestSwapRate);\n\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\n\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (uint256);\n\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\n\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\n\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (bool);\n\n function getFastGasPrice(address payToken) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IRSKOracle {\n function updatePrice(uint256 price, uint256 timestamp) external;\n\n function getPricing() external view returns (uint256, uint256);\n\n function setOracleAddress(address addr) external;\n\n function clearOracleAddress() external;\n}\n" + }, + "contracts/feeds/IV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IV1PoolOracle {\n function read(uint256 price, uint256 timestamp)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function latestAnswer() external view returns (uint256);\n\n function liquidityPool() external view returns (address);\n\n function latestPrice(address _baseToken) external view returns (uint256 answer);\n}\n\ninterface ILiquidityPoolV1Converter {\n function reserveTokens(uint256 index) external view returns (address);\n}\n" + }, + "contracts/feeds/PriceFeedRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IRSKOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @notice The Price Feed RSK Oracle contract.\n *\n * This contract implements RSK Oracle query functionality,\n * getting the price and the last timestamp from an external oracle contract.\n * */\ncontract PriceFeedRSKOracle is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public rskOracleAddress;\n\n /* Events */\n\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new RSK Oracle.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _rskOracleAddress) public {\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256 _price) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (_price, ) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestTimestamp() external view returns (uint256 _timestamp) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (, _timestamp) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/PriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./PriceFeedsConstants.sol\";\n\ninterface IPriceFeedsExt {\n function latestAnswer() external view returns (uint256);\n}\n\n/**\n * @title The Price Feeds contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract queries the price feeds contracts where\n * oracles updates token prices computing relative token prices.\n * And besides it includes some calculations about loans such as\n * drawdown, margin and collateral.\n * */\ncontract PriceFeeds is Constants, Ownable {\n using SafeMath for uint256;\n\n /* Events */\n\n event GlobalPricingPaused(address indexed sender, bool indexed isPaused);\n\n /* Storage */\n\n /// Mapping of PriceFeedsExt instances.\n /// token => pricefeed\n mapping(address => IPriceFeedsExt) public pricesFeeds;\n\n /// Decimals of supported tokens.\n mapping(address => uint256) public decimals;\n\n /// Value on rBTC weis for the protocol token.\n uint256 public protocolTokenEthPrice = 0.0002 ether;\n\n /// Flag to pause pricings.\n bool public globalPricingPaused = false;\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires 3 parameters.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * @param _protocolTokenAddress The address of the protocol token.\n * @param _baseTokenAddress The address of the base token.\n * */\n constructor(\n address _wrbtcTokenAddress,\n address _protocolTokenAddress,\n address _baseTokenAddress\n ) public {\n /// Set decimals for this token.\n decimals[address(0)] = 18;\n decimals[_wrbtcTokenAddress] = 18;\n _setWrbtcToken(_wrbtcTokenAddress);\n _setProtocolTokenAddress(_protocolTokenAddress);\n _setBaseToken(_baseTokenAddress);\n }\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @dev Public wrapper for _queryRate internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function queryRate(address sourceToken, address destToken)\n public\n view\n returns (uint256 rate, uint256 precision)\n {\n return _queryRate(sourceToken, destToken);\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @dev Public wrapper for _getDecimalPrecision internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function queryPrecision(address sourceToken, address destToken) public view returns (uint256) {\n return sourceToken != destToken ? _getDecimalPrecision(sourceToken, destToken) : 10**18;\n }\n\n /**\n * @notice Price conversor: Calculate the price of an amount of source\n * tokens in destiny token units.\n *\n * @dev NOTE: This function returns 0 during a pause, rather than a revert.\n * Ensure calling contracts handle correctly.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of the source tokens.\n *\n * @return destAmount The amount of destiny tokens equivalent in price\n * to the amount of source tokens.\n * */\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) public view returns (uint256 destAmount) {\n if (globalPricingPaused) {\n return 0;\n }\n\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n destAmount = sourceAmount.mul(rate).div(precision);\n }\n\n /**\n * @notice Calculate the swap rate between two tokens.\n *\n * Regarding slippage, there is a hardcoded slippage limit of 5%, enforced\n * by this function for all borrowing, lending and margin trading\n * originated swaps performed in the Sovryn exchange.\n *\n * This means all operations in the Sovryn exchange are subject to losing\n * up to 5% from the internal swap performed.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of source tokens.\n * @param destAmount The amount of destiny tokens.\n * @param maxSlippage The maximum slippage limit.\n *\n * @return sourceToDestSwapRate The swap rate between tokens.\n * */\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) public view returns (uint256 sourceToDestSwapRate) {\n require(!globalPricingPaused, \"pricing is paused\");\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n sourceToDestSwapRate = destAmount.mul(precision).div(sourceAmount);\n\n if (rate > sourceToDestSwapRate) {\n uint256 spreadValue = rate - sourceToDestSwapRate;\n spreadValue = spreadValue.mul(10**20).div(sourceToDestSwapRate);\n require(spreadValue <= maxSlippage, \"price disagreement\");\n }\n }\n\n /**\n * @notice Calculate the rBTC amount equivalent to a given token amount.\n * Native coin on RSK is rBTC. This code comes from Ethereum applications,\n * so Eth refers to 10**18 weis of native coin, i.e.: 1 rBTC.\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n *\n * @return ethAmount The amount of rBTC equivalent.\n * */\n function amountInEth(address tokenAddress, uint256 amount)\n public\n view\n returns (uint256 ethAmount)\n {\n /// Token is wrBTC, amount in rBTC is the same.\n if (tokenAddress == address(wrbtcToken)) {\n ethAmount = amount;\n } else {\n (uint256 toEthRate, uint256 toEthPrecision) =\n queryRate(tokenAddress, address(wrbtcToken));\n ethAmount = amount.mul(toEthRate).div(toEthPrecision);\n }\n }\n\n /**\n * @notice Calculate the maximum drawdown of a loan.\n *\n * A drawdown is commonly defined as the decline from a high peak to a\n * pullback low of a specific investment or equity in an account.\n *\n * Drawdown magnitude refers to the amount of value that a user loses\n * during the drawdown period.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param margin The relation between the position size and the loan.\n * margin = (total position size - loan) / loan\n *\n * @return maxDrawdown The maximum drawdown.\n * */\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 margin\n ) public view returns (uint256 maxDrawdown) {\n uint256 loanToCollateralAmount;\n if (collateralToken == loanToken) {\n loanToCollateralAmount = loanAmount;\n } else {\n (uint256 rate, uint256 precision) = queryRate(loanToken, collateralToken);\n loanToCollateralAmount = loanAmount.mul(rate).div(precision);\n }\n\n uint256 combined =\n loanToCollateralAmount.add(loanToCollateralAmount.mul(margin).div(10**20));\n\n maxDrawdown = collateralAmount > combined ? collateralAmount - combined : 0;\n }\n\n /**\n * @notice Calculate the margin and the collateral on rBTC.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralInEthAmount The amount of collateral on rBTC.\n * */\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralInEthAmount) {\n (currentMargin, ) = getCurrentMargin(\n loanToken,\n collateralToken,\n loanAmount,\n collateralAmount\n );\n\n collateralInEthAmount = amountInEth(collateralToken, collateralAmount);\n }\n\n /**\n * @notice Calculate the margin of a loan.\n *\n * @dev current margin = (total position size - loan) / loan\n * The collateral amount passed as parameter equals the total position size.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralToLoanRate The price ratio between collateral and\n * loan tokens.\n * */\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralToLoanRate) {\n uint256 collateralToLoanAmount;\n if (collateralToken == loanToken) {\n collateralToLoanAmount = collateralAmount;\n collateralToLoanRate = 10**18;\n } else {\n uint256 collateralToLoanPrecision;\n (collateralToLoanRate, collateralToLoanPrecision) = queryRate(\n collateralToken,\n loanToken\n );\n\n collateralToLoanRate = collateralToLoanRate.mul(10**18).div(collateralToLoanPrecision);\n\n collateralToLoanAmount = collateralAmount.mul(collateralToLoanRate).div(10**18);\n }\n\n if (loanAmount != 0 && collateralToLoanAmount >= loanAmount) {\n return (\n collateralToLoanAmount.sub(loanAmount).mul(10**20).div(loanAmount),\n collateralToLoanRate\n );\n } else {\n return (0, collateralToLoanRate);\n }\n }\n\n /**\n * @notice Get assessment about liquidating a loan.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param maintenanceMargin The minimum margin before liquidation.\n *\n * @return True/false to liquidate the loan.\n * */\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) public view returns (bool) {\n (uint256 currentMargin, ) =\n getCurrentMargin(loanToken, collateralToken, loanAmount, collateralAmount);\n\n return currentMargin <= maintenanceMargin;\n }\n\n /*\n * Owner functions\n */\n\n /**\n * @notice Set new value for protocolTokenEthPrice\n *\n * @param newPrice The new value for protocolTokenEthPrice\n * */\n function setProtocolTokenEthPrice(uint256 newPrice) external onlyOwner {\n require(newPrice != 0, \"invalid price\");\n protocolTokenEthPrice = newPrice;\n }\n\n /**\n * @notice Populate pricesFeeds mapping w/ values from feeds[]\n *\n * @param tokens The array of tokens to loop and get addresses.\n * @param feeds The array of contract instances for every token.\n * */\n function setPriceFeed(address[] calldata tokens, IPriceFeedsExt[] calldata feeds)\n external\n onlyOwner\n {\n require(tokens.length == feeds.length, \"count mismatch\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n pricesFeeds[tokens[i]] = feeds[i];\n }\n }\n\n /**\n * @notice Populate decimals mapping w/ values from tokens[].decimals\n *\n * @param tokens The array of tokens to loop and get values from.\n * */\n function setDecimals(IERC20[] calldata tokens) external onlyOwner {\n for (uint256 i = 0; i < tokens.length; i++) {\n decimals[address(tokens[i])] = tokens[i].decimals();\n }\n }\n\n /**\n * @notice Set flag globalPricingPaused\n *\n * @param isPaused The new status of pause (true/false).\n * */\n function setGlobalPricingPaused(bool isPaused) external onlyOwner {\n if (globalPricingPaused != isPaused) {\n globalPricingPaused = isPaused;\n\n emit GlobalPricingPaused(msg.sender, isPaused);\n }\n }\n\n /*\n * Internal functions\n */\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n /// Different tokens, query prices and perform division.\n if (sourceToken != destToken) {\n uint256 sourceRate;\n if (sourceToken != address(baseToken) && sourceToken != protocolTokenAddress) {\n IPriceFeedsExt _sourceFeed = pricesFeeds[sourceToken];\n require(address(_sourceFeed) != address(0), \"unsupported src feed\");\n\n /// Query token price on priceFeedsExt instance.\n sourceRate = _sourceFeed.latestAnswer();\n require(sourceRate != 0 && (sourceRate >> 128) == 0, \"price error\");\n } else {\n sourceRate = sourceToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n uint256 destRate;\n if (destToken != address(baseToken) && destToken != protocolTokenAddress) {\n IPriceFeedsExt _destFeed = pricesFeeds[destToken];\n require(address(_destFeed) != address(0), \"unsupported dst feed\");\n\n /// Query token price on priceFeedsExt instance.\n destRate = _destFeed.latestAnswer();\n require(destRate != 0 && (destRate >> 128) == 0, \"price error\");\n } else {\n destRate = destToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n rate = sourceRate.mul(10**18).div(destRate);\n\n precision = _getDecimalPrecision(sourceToken, destToken);\n\n /// Same tokens, return 1 with decimals.\n } else {\n rate = 10**18;\n precision = 10**18;\n }\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function _getDecimalPrecision(address sourceToken, address destToken)\n internal\n view\n returns (uint256)\n {\n /// Same tokens, return 1 with decimals.\n if (sourceToken == destToken) {\n return 10**18;\n\n /// Different tokens, query ERC20 precisions and return 18 +- diff.\n } else {\n uint256 sourceTokenDecimals = decimals[sourceToken];\n if (sourceTokenDecimals == 0) sourceTokenDecimals = IERC20(sourceToken).decimals();\n\n uint256 destTokenDecimals = decimals[destToken];\n if (destTokenDecimals == 0) destTokenDecimals = IERC20(destToken).decimals();\n\n if (destTokenDecimals >= sourceTokenDecimals)\n return 10**(SafeMath.sub(18, destTokenDecimals - sourceTokenDecimals));\n else return 10**(SafeMath.add(18, sourceTokenDecimals - destTokenDecimals));\n }\n }\n}\n" + }, + "contracts/feeds/PriceFeedsConstants.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The Price Feeds Constants contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract keep the addresses of token instances for wrBTC, base token\n * and protocol token.\n * */\ncontract Constants {\n IWrbtcERC20 public wrbtcToken;\n IWrbtcERC20 public baseToken;\n address internal protocolTokenAddress;\n\n /**\n * @notice Set wrBTC token address.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * */\n function _setWrbtcToken(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"_wrbtcTokenAddress not a contract\");\n wrbtcToken = IWrbtcERC20(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Set protocol token address.\n *\n * @param _protocolTokenAddress The address of the protocol token.\n * */\n function _setProtocolTokenAddress(address _protocolTokenAddress) internal {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n protocolTokenAddress = _protocolTokenAddress;\n }\n\n /**\n * @notice Set base token address.\n *\n * @param _baseTokenAddress The address of the base token.\n * */\n function _setBaseToken(address _baseTokenAddress) internal {\n require(Address.isContract(_baseTokenAddress), \"_baseTokenAddress not a contract\");\n baseToken = IWrbtcERC20(_baseTokenAddress);\n }\n}\n" + }, + "contracts/feeds/PriceFeedV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IV1PoolOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./IPriceFeeds.sol\";\n\n/**\n * @notice The Price Feed V1 Pool Oracle contract.\n *\n * This contract implements V1 Pool Oracle query functionality,\n * getting the price from v1 pool oracle.\n * */\ncontract PriceFeedV1PoolOracle is IPriceFeedsExt, Ownable {\n using SafeMath for uint256;\n /* Storage */\n\n address public v1PoolOracleAddress;\n address public wRBTCAddress;\n address public docAddress;\n address public baseCurrency;\n\n /* Events */\n event SetV1PoolOracleAddress(address indexed v1PoolOracleAddress, address changerAddress);\n event SetWRBTCAddress(address indexed wRBTCAddress, address changerAddress);\n event SetDOCAddress(address indexed docAddress, address changerAddress);\n event SetBaseCurrency(address indexed baseCurrency, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new V1 Pool Oracle.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n * @param _wRBTCAddress The wrbtc token address.\n * @param _docAddress The doc token address.\n * */\n constructor(\n address _v1PoolOracleAddress,\n address _wRBTCAddress,\n address _docAddress,\n address _baseCurrency\n ) public {\n setRBTCAddress(_wRBTCAddress);\n setDOCAddress(_docAddress);\n setV1PoolOracleAddress(_v1PoolOracleAddress);\n setBaseCurrency(_baseCurrency);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256) {\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(v1PoolOracleAddress);\n\n uint256 _price = _v1PoolOracle.latestPrice(baseCurrency);\n\n // Need to convert to USD, since the V1 pool return value is based on BTC\n uint256 priceInUSD = _convertAnswerToUsd(_price);\n require(priceInUSD != 0, \"price error\");\n\n return priceInUSD;\n }\n\n function _convertAnswerToUsd(uint256 _valueInBTC) private view returns (uint256) {\n address _priceFeeds = msg.sender;\n\n uint256 precision = IPriceFeeds(_priceFeeds).queryPrecision(wRBTCAddress, docAddress);\n uint256 valueInUSD =\n IPriceFeeds(_priceFeeds).queryReturn(wRBTCAddress, docAddress, _valueInBTC);\n\n /// Need to multiply by query precision (doc's precision) and divide by 1*10^18 (Because the based price in v1 pool is using 18 decimals)\n return valueInUSD.mul(precision).div(1e18);\n }\n\n /**\n * @notice Set the V1 Pool Oracle address.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n */\n function setV1PoolOracleAddress(address _v1PoolOracleAddress) public onlyOwner {\n require(Address.isContract(_v1PoolOracleAddress), \"_v1PoolOracleAddress not a contract\");\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(_v1PoolOracleAddress);\n address liquidityPool = _v1PoolOracle.liquidityPool();\n require(\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(0) == wRBTCAddress ||\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(1) == wRBTCAddress,\n \"one of the two reserves needs to be wrbtc\"\n );\n v1PoolOracleAddress = _v1PoolOracleAddress;\n emit SetV1PoolOracleAddress(v1PoolOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the rBtc address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the rBtc\n *\n * @param _wRBTCAddress The rBTC address\n */\n function setRBTCAddress(address _wRBTCAddress) public onlyOwner {\n require(_wRBTCAddress != address(0), \"wRBTC address cannot be zero address\");\n wRBTCAddress = _wRBTCAddress;\n emit SetWRBTCAddress(wRBTCAddress, msg.sender);\n }\n\n /**\n * @notice Set the DoC address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the DoC\n *\n * @param _docAddress The DoC address\n */\n function setDOCAddress(address _docAddress) public onlyOwner {\n require(_docAddress != address(0), \"DOC address cannot be zero address\");\n docAddress = _docAddress;\n emit SetDOCAddress(_docAddress, msg.sender);\n }\n\n /**\n * @notice Set the base currency address. That's the reserve address which is not WRBTC\n *\n * @param _baseCurrency The base currency address\n */\n function setBaseCurrency(address _baseCurrency) public onlyOwner {\n require(_baseCurrency != address(0), \"Base currency address cannot be zero address\");\n baseCurrency = _baseCurrency;\n emit SetBaseCurrency(_baseCurrency, msg.sender);\n }\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsLocal.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\n\n/**\n * @title Price Feeds Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the logic of setting and getting rates between two tokens.\n * */\ncontract PriceFeedsLocal is PriceFeeds {\n mapping(address => mapping(address => uint256)) public rates;\n\n /// uint256 public slippageMultiplier = 100 ether;\n\n /**\n * @notice Deploy local price feed contract.\n *\n * @param _wrbtcTokenAddress The address of the wrBTC instance.\n * @param _protocolTokenAddress The address of the protocol token instance.\n * */\n constructor(address _wrbtcTokenAddress, address _protocolTokenAddress)\n public\n PriceFeeds(_wrbtcTokenAddress, _protocolTokenAddress, _wrbtcTokenAddress)\n {}\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n if (sourceToken == destToken) {\n rate = 10**18;\n precision = 10**18;\n } else {\n if (sourceToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = protocolTokenEthPrice;\n } else if (destToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = SafeMath.div(10**36, protocolTokenEthPrice);\n } else {\n if (rates[sourceToken][destToken] != 0) {\n rate = rates[sourceToken][destToken];\n } else {\n uint256 sourceToEther =\n rates[sourceToken][address(wrbtcToken)] != 0\n ? rates[sourceToken][address(wrbtcToken)]\n : 10**18;\n uint256 etherToDest =\n rates[address(wrbtcToken)][destToken] != 0\n ? rates[address(wrbtcToken)][destToken]\n : 10**18;\n\n rate = sourceToEther.mul(etherToDest).div(10**18);\n }\n }\n precision = _getDecimalPrecision(sourceToken, destToken);\n }\n }\n\n /**\n * @notice Owner set price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param rate The price ratio source/dest.\n * */\n function setRates(\n address sourceToken,\n address destToken,\n uint256 rate\n ) public onlyOwner {\n if (sourceToken != destToken) {\n rates[sourceToken][destToken] = rate;\n rates[destToken][sourceToken] = SafeMath.div(10**36, rate);\n }\n }\n\n /*function setSlippageMultiplier(\n uint256 _slippageMultiplier)\n public\n onlyOwner\n {\n require (slippageMultiplier != _slippageMultiplier && _slippageMultiplier <= 100 ether);\n slippageMultiplier = _slippageMultiplier;\n }*/\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsMoC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\nimport \"../IRSKOracle.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\ninterface Medianizer {\n function peek() external view returns (bytes32, bool);\n}\n\n/**\n * @title Price Feed of MoC (Money on Chain) contract.\n *\n * This contract contains the logic to set MoC oracles\n * and query last price update.\n * */\ncontract PriceFeedsMoC is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public mocOracleAddress;\n address public rskOracleAddress;\n\n /* Events */\n\n event SetMoCOracleAddress(address indexed mocOracleAddress, address changerAddress);\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new MoC Oracle.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _mocOracleAddress, address _rskOracleAddress) public {\n setMoCOracleAddress(_mocOracleAddress);\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestAnswer() external view returns (uint256) {\n (bytes32 value, bool hasValue) = Medianizer(mocOracleAddress).peek();\n if (hasValue) {\n return uint256(value);\n } else {\n (uint256 price, ) = IRSKOracle(rskOracleAddress).getPricing();\n return price;\n }\n }\n\n /**\n * @notice Set the MoC Oracle address.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n */\n function setMoCOracleAddress(address _mocOracleAddress) public onlyOwner {\n require(Address.isContract(_mocOracleAddress), \"_mocOracleAddress not a contract\");\n mocOracleAddress = _mocOracleAddress;\n emit SetMoCOracleAddress(mocOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/USDTPriceFeed.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./PriceFeeds.sol\";\n\n/**\n * @notice The Price Feed USDT contract.\n *\n * This contract implements USDT query functionality,\n * getting the price and the last timestamp from a\n * trivial formula, always returning 1 and now.\n * */\ncontract USDTPriceFeed is IPriceFeedsExt {\n uint256 private constant USDT_RATE = 1 ether;\n\n /**\n * @notice Get the USDT price.\n *\n * @return Always returns the trivial rate of 1.\n * */\n function latestAnswer() external view returns (uint256) {\n return USDT_RATE;\n }\n\n /**\n * @notice Get the las time the price was updated.\n * @return Always trivial current block's timestamp.\n */\n function latestTimestamp() external view returns (uint256) {\n return now;\n }\n}\n" + }, + "contracts/governance/ApprovalReceiver.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./ErrorDecoder.sol\";\nimport \"../token/IApproveAndCall.sol\";\n\n/**\n * @title Base contract for receiving approval from SOV token.\n */\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\n modifier onlyThisContract() {\n // Accepts calls only from receiveApproval function.\n require(msg.sender == address(this), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external {\n // Accepts calls only from SOV token.\n require(msg.sender == _getToken(), \"unauthorized\");\n require(msg.sender == _token, \"unauthorized\");\n\n // Only allowed methods.\n bool isAllowed = false;\n bytes4[] memory selectors = _getSelectors();\n bytes4 sig = _getSig(_data);\n for (uint256 i = 0; i < selectors.length; i++) {\n if (sig == selectors[i]) {\n isAllowed = true;\n break;\n }\n }\n require(isAllowed, \"method is not allowed\");\n\n // Check sender and amount.\n address sender;\n uint256 amount;\n (, sender, amount) = abi.decode(\n abi.encodePacked(bytes28(0), _data),\n (bytes32, address, uint256)\n );\n require(sender == _sender, \"sender mismatch\");\n require(amount == _amount, \"amount mismatch\");\n\n _call(_data);\n }\n\n /**\n * @notice Returns token address, only this address can be a sender for receiveApproval.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, 0x. When overriden, the token address making the call.\n */\n function _getToken() internal view returns (address) {\n return address(0);\n }\n\n /**\n * @notice Returns list of function selectors allowed to be invoked.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, empty array. When overriden, allowed selectors.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n return new bytes4[](0);\n }\n\n /**\n * @notice Makes call and reverts w/ enhanced error message.\n * @param _data Error message as bytes.\n */\n function _call(bytes memory _data) internal {\n (bool success, bytes memory returnData) = address(this).call(_data);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"receiveApproval: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"receiveApproval: \", string(returnData)));\n }\n }\n }\n\n /**\n * @notice Extracts the called function selector, a hash of the signature.\n * @dev The first four bytes of the call data for a function call specifies\n * the function to be called. It is the first (left, high-order in big-endian)\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\n * Example:\n * msg.data:\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\n * 000450000000000000000000000000000000000000000000000000000000000000001\n * selector (or method ID): 0xcdcd77c0\n * signature: baz(uint32,bool)\n * @param _data The msg.data from the low level call.\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\n */\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\n assembly {\n sig := mload(add(_data, 32))\n }\n }\n}\n" + }, + "contracts/governance/ErrorDecoder.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base contract to properly handle returned data on failed calls\n * @dev On EVM if the return data length of a call is less than 68,\n * then the transaction fails silently without a revert message!\n *\n * As described in the Solidity documentation\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\n * the revert reason is an ABI-encoded string consisting of:\n * 0x08c379a0 // Function selector (method id) for \"Error(string)\" signature\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\n *\n * Another example, debug data from test:\n * 0x08c379a0\n * 0000000000000000000000000000000000000000000000000000000000000020\n * 0000000000000000000000000000000000000000000000000000000000000034\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n *\n * Parsed into:\n * Data offset: 20\n * Length: 34\n * Error message:\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n */\ncontract ErrorDecoder {\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\n\n /**\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\n * @param str1 First string, usually a hardcoded context written by dev.\n * @param str2 Second string, usually the error message from the reverted call.\n * @return The concatenated error string\n */\n function _addErrorMessage(string memory str1, string memory str2)\n internal\n pure\n returns (string memory)\n {\n bytes memory bytesStr1 = bytes(str1);\n bytes memory bytesStr2 = bytes(str2);\n string memory str12 =\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\n bytes memory bytesStr12 = bytes(str12);\n uint256 j = 0;\n for (uint256 i = 0; i < bytesStr1.length; i++) {\n bytesStr12[j++] = bytesStr1[i];\n }\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\n bytesStr12[j++] = bytesStr2[i];\n }\n return string(bytesStr12);\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../Staking/SafeMath96.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../interfaces/IConverterAMM.sol\";\n\n/**\n * @title The FeeSharingCollector contract.\n * @notice This contract withdraws fees to be paid to SOV Stakers from the protocol.\n * Stakers call withdraw() to get their share of the fees.\n *\n * @notice Staking is not only granting voting rights, but also access to fee\n * sharing according to the own voting power in relation to the total. Whenever\n * somebody decides to collect the fees from the protocol, they get transferred\n * to a proxy contract which invests the funds in the lending pool and keeps\n * the pool tokens.\n *\n * The fee sharing proxy will be set as feesController of the protocol contract.\n * This allows the fee sharing proxy to withdraw the fees. The fee sharing\n * proxy holds the pool tokens and keeps track of which user owns how many\n * tokens. In order to know how many tokens a user owns, the fee sharing proxy\n * needs to know the user’s weighted stake in relation to the total weighted\n * stake (aka total voting power).\n *\n * Because both values are subject to change, they may be different on each fee\n * withdrawal. To be able to calculate a user’s share of tokens when he wants\n * to withdraw, we need checkpoints.\n *\n * This contract is intended to be set as the protocol fee collector.\n * Anybody can invoke the withdrawFees function which uses\n * protocol.withdrawFees to obtain available fees from operations on a\n * certain token. These fees are deposited in the corresponding loanPool.\n * Also, the staking contract sends slashed tokens to this contract.\n * When a user calls the withdraw function, the contract transfers the fee sharing\n * rewards in proportion to the user’s weighted stake since the last withdrawal.\n *\n * The protocol initially collects fees in all tokens.\n * Then the FeeSharingCollector wihtdraws fees from the protocol.\n * When the fees are withdrawn all the tokens except SOV will be converted to wRBTC\n * and then transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n * */\ncontract FeeSharingCollector is\n SafeMath96,\n IFeeSharingCollector,\n Ownable,\n FeeSharingCollectorStorage\n{\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n address constant ZERO_ADDRESS = address(0);\n address public constant RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT =\n address(uint160(uint256(keccak256(\"RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\"))));\n\n /* Events */\n\n /// @notice Deprecated event after the unification between wrbtc & rbtc\n // event FeeWithdrawn(address indexed sender, address indexed token, uint256 amount);\n event FeeWithdrawnInRBTC(address indexed sender, uint256 amount);\n\n /// @notice An event emitted when tokens transferred.\n event TokensTransferred(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when checkpoint added.\n event CheckpointAdded(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeWithdrawn(\n address indexed sender,\n address indexed receiver,\n address indexed token,\n uint256 amount\n );\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeProcessedNoWithdraw(\n address indexed sender,\n address indexed token,\n uint256 prevProcessedCheckpoints,\n uint256 newProcessedCheckpoints\n );\n\n /**\n * @notice An event emitted when fee from AMM get withdrawn.\n *\n * @param sender sender who initiate the withdrawn amm fees.\n * @param converter the converter address.\n * @param amount total amount of fee (Already converted to WRBTC).\n */\n event FeeAMMWithdrawn(address indexed sender, address indexed converter, uint256 amount);\n\n /// @notice An event emitted when converter address has been registered to be whitelisted.\n event WhitelistedConverter(address indexed sender, address converter);\n\n /// @notice An event emitted when converter address has been removed from whitelist.\n event UnwhitelistedConverter(address indexed sender, address converter);\n\n event RBTCWithdrawn(address indexed sender, address indexed receiver, uint256 amount);\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWrbtcToken,\n address indexed newWrbtcToken\n );\n\n event SetLoanTokenWrbtc(\n address indexed sender,\n address indexed oldLoanTokenWrbtc,\n address indexed newLoanTokenWrbtc\n );\n\n /* Modifier */\n modifier oneTimeExecution(bytes4 _funcSig) {\n require(\n !isFunctionExecuted[_funcSig],\n \"FeeSharingCollector: function can only be called once\"\n );\n _;\n isFunctionExecuted[_funcSig] = true;\n }\n\n /* Functions */\n\n /// @dev fallback function to support rbtc transfer when unwrap the wrbtc.\n function() external payable {}\n\n /**\n * @dev initialize function for fee sharing collector proxy\n * @param wrbtcToken wrbtc token address\n * @param loanWrbtcToken address of loan token wrbtc (IWrbtc)\n */\n function initialize(address wrbtcToken, address loanWrbtcToken)\n external\n onlyOwner\n oneTimeExecution(this.initialize.selector)\n {\n require(\n wrbtcTokenAddress == address(0) && loanTokenWrbtcAddress == address(0),\n \"wrbtcToken or loanWrbtcToken has been initialized\"\n );\n setWrbtcToken(wrbtcToken);\n setLoanTokenWrbtc(loanWrbtcToken);\n }\n\n /**\n * @notice Set the wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newWrbtcTokenAddress The new address of the wrbtc token.\n * */\n function setWrbtcToken(address newWrbtcTokenAddress) public onlyOwner {\n require(Address.isContract(newWrbtcTokenAddress), \"newWrbtcTokenAddress not a contract\");\n emit SetWrbtcToken(msg.sender, wrbtcTokenAddress, newWrbtcTokenAddress);\n wrbtcTokenAddress = newWrbtcTokenAddress;\n }\n\n /**\n * @notice Set the loan wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newLoanTokenWrbtcAddress The new address of the loan wrbtc token.\n * */\n function setLoanTokenWrbtc(address newLoanTokenWrbtcAddress) public onlyOwner {\n require(\n Address.isContract(newLoanTokenWrbtcAddress),\n \"newLoanTokenWrbtcAddress not a contract\"\n );\n emit SetLoanTokenWrbtc(msg.sender, loanTokenWrbtcAddress, newLoanTokenWrbtcAddress);\n loanTokenWrbtcAddress = newLoanTokenWrbtcAddress;\n }\n\n /**\n * @notice Withdraw fees for the given token:\n * lendingFee + tradingFee + borrowingFee\n * the fees (except SOV) will be converted in wRBTC form, and then will be transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n *\n * @param _tokens array address of the token\n * */\n function withdrawFees(address[] calldata _tokens) external {\n for (uint256 i = 0; i < _tokens.length; i++) {\n require(\n Address.isContract(_tokens[i]),\n \"FeeSharingCollector::withdrawFees: token is not a contract\"\n );\n }\n\n uint256 wrbtcAmountWithdrawn = protocol.withdrawFees(_tokens, address(this));\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap the wrbtc to rbtc, and hold the rbtc.\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFees: wrbtc token amount exceeds 96 bits\"\n );\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, amount96);\n }\n\n // note deprecated event since we unify the wrbtc & rbtc\n // emit FeeWithdrawn(msg.sender, RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, poolTokenAmount);\n\n // note new emitted event\n emit FeeWithdrawnInRBTC(msg.sender, wrbtcAmountWithdrawn);\n }\n\n /**\n * @notice Withdraw amm fees for the given converter addresses:\n * protocolFee from the conversion\n * the fees will be converted in wRBTC form, and then will be transferred to wRBTC loan pool\n *\n * @param _converters array addresses of the converters\n * */\n function withdrawFeesAMM(address[] memory _converters) public {\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n // Validate\n _validateWhitelistedConverter(_converters);\n\n uint96 totalPoolTokenAmount;\n for (uint256 i = 0; i < _converters.length; i++) {\n uint256 wrbtcAmountWithdrawn =\n IConverterAMM(_converters[i]).withdrawFees(address(this));\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap wrbtc to rbtc, and hold the rbtc\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFeesAMM: wrbtc token amount exceeds 96 bits\"\n );\n\n totalPoolTokenAmount = add96(\n totalPoolTokenAmount,\n amount96,\n \"FeeSharingCollector::withdrawFeesAMM: total wrbtc token amount exceeds 96 bits\"\n );\n\n emit FeeAMMWithdrawn(msg.sender, _converters[i], wrbtcAmountWithdrawn);\n }\n }\n\n if (totalPoolTokenAmount > 0) {\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, totalPoolTokenAmount);\n }\n }\n\n /**\n * @notice Transfer tokens to this contract.\n * @dev We just update amount of tokens here and write checkpoint in a separate methods\n * in order to prevent adding checkpoints too often.\n * @param _token Address of the token.\n * @param _amount Amount to be transferred.\n * */\n function transferTokens(address _token, uint96 _amount) public {\n require(_token != ZERO_ADDRESS, \"FeeSharingCollector::transferTokens: invalid address\");\n require(_amount > 0, \"FeeSharingCollector::transferTokens: invalid amount\");\n\n /// @notice Transfer tokens from msg.sender\n bool success = IERC20(_token).transferFrom(address(msg.sender), address(this), _amount);\n require(success, \"Staking::transferTokens: token transfer failed\");\n\n // if _token is wrbtc, need to unwrap it to rbtc\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n if (_token == address(wrbtcToken)) {\n wrbtcToken.withdraw(_amount);\n _token = RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT;\n }\n\n _addCheckpoint(_token, _amount);\n\n emit TokensTransferred(msg.sender, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC / native tokens to this contract.\n * @dev We just write checkpoint here (based on the rbtc value that is sent) in a separate methods\n * in order to prevent adding checkpoints too often.\n * */\n function transferRBTC() external payable {\n uint96 _amount = uint96(msg.value);\n require(_amount > 0, \"FeeSharingCollector::transferRBTC: invalid value\");\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, _amount);\n\n emit TokensTransferred(msg.sender, ZERO_ADDRESS, _amount);\n }\n\n /**\n * @notice Add checkpoint with accumulated amount by function invocation.\n * @param _token Address of the token.\n * */\n function _addCheckpoint(address _token, uint96 _amount) internal {\n if (block.timestamp - lastFeeWithdrawalTime[_token] >= FEE_WITHDRAWAL_INTERVAL) {\n lastFeeWithdrawalTime[_token] = block.timestamp;\n uint96 amount =\n add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: amount exceeds 96 bits\"\n );\n\n /// @notice Reset unprocessed amount of tokens to zero.\n unprocessedAmount[_token] = 0;\n\n /// @notice Write a regular checkpoint.\n _writeTokenCheckpoint(_token, amount);\n } else {\n unprocessedAmount[_token] = add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: unprocessedAmount exceeds 96 bits\"\n );\n }\n }\n\n function _withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n /// @dev Prevents block gas limit hit when processing checkpoints\n require(\n _maxCheckpoints > 0,\n \"FeeSharingCollector::withdraw: _maxCheckpoints should be positive\"\n );\n\n address user = msg.sender;\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n uint256 processedUserCheckpoints = processedCheckpoints[user][_token];\n (uint256 amount, uint256 end) =\n _getAccumulatedFees(user, _token, processedUserCheckpoints, _maxCheckpoints);\n if (amount == 0) {\n if (end > processedUserCheckpoints) {\n emit UserFeeProcessedNoWithdraw(msg.sender, _token, processedUserCheckpoints, end);\n processedCheckpoints[user][_token] = end;\n return (0, end);\n } else {\n // getting here most likely means smth wrong with the state\n revert(\"FeeSharingCollector::withdrawFees: no tokens for withdrawal\");\n }\n }\n\n processedCheckpoints[user][_token] = end;\n if (loanTokenWrbtcAddress == _token) {\n // We will change, so that feeSharingCollector will directly burn then loanToken (IWRBTC) to rbtc and send to the user --- by call burnToBTC function\n ILoanTokenWRBTC(_token).burnToBTC(_receiver, amount, false);\n } else {\n // Previously it directly send the loanToken to the user\n require(\n IERC20(_token).transfer(_receiver, amount),\n \"FeeSharingCollector::withdraw: withdrawal failed\"\n );\n }\n\n emit UserFeeWithdrawn(msg.sender, _receiver, _token, amount);\n\n return (amount, end);\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power. Therefore, staking more\n * SOV and/or staking for longer will increase your share of the fees\n * generated, meaning you will earn more from staking.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed. Must be positive value.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public nonReentrant {\n _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n /// @notice Validates if the checkpoint is payable for the user\n function validFromCheckpointsParam(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n address _user\n ) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n // _fromCheckpoint is checkpoint number, not array index, so should be > 1\n require(tokenData.fromCheckpoint > 1, \"_fromCheckpoint param must be > 1\");\n uint256 fromCheckpointIndex = tokenData.fromCheckpoint - 1;\n require(\n tokenData.fromCheckpoint > processedCheckpoints[_user][tokenData.tokenAddress],\n \"_fromCheckpoint param must be > userProcessedCheckpoints\"\n );\n require(\n tokenData.fromCheckpoint <= totalTokenCheckpoints[tokenData.tokenAddress],\n \"_fromCheckpoint should be <= totalTokenCheckpoints\"\n );\n\n Checkpoint memory prevCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex - 1];\n\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n prevCheckpoint.blockNumber - 1,\n prevCheckpoint.timestamp\n );\n require(\n weightedStake == 0,\n \"User weighted stake should be zero at previous checkpoint\"\n );\n\n Checkpoint memory fromCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex];\n weightedStake = staking.getPriorWeightedStake(\n _user,\n fromCheckpoint.blockNumber - 1,\n fromCheckpoint.timestamp\n );\n\n require(weightedStake > 0, \"User weighted stake should be > 0 at _fromCheckpoint\");\n }\n }\n\n function validRBTCBasedTokens(address[] memory _tokens) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n address _token = _tokens[i];\n if (\n _token != RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT &&\n _token != wrbtcTokenAddress &&\n _token != loanTokenWrbtcAddress\n ) {\n revert(\"only rbtc-based tokens are allowed\");\n }\n }\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender/receiver.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @dev WARNING! This function skips all the checkpoints before '_fromCheckpoint' irreversibly, use with care\n *\n * @param _tokens Array of TokenWithSkippedCheckpointsWithdraw struct, which contains the token address, and fromCheckpoiint\n * fromCheckpoints Skips all the checkpoints before '_fromCheckpoint'\n * should be calculated offchain with getNextPositiveUserCheckpoint function\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n *\n * @return total processed checkpoints\n * */\n function _withdrawStartingFromCheckpoints(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validFromCheckpointsParam(_tokens, msg.sender);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n if (_maxCheckpoints == 0) break;\n uint256 endToken;\n uint256 totalAmount;\n\n uint256 previousProcessedUserCheckpoints =\n processedCheckpoints[msg.sender][tokenData.tokenAddress];\n uint256 startingCheckpoint =\n tokenData.fromCheckpoint > previousProcessedUserCheckpoints\n ? tokenData.fromCheckpoint\n : previousProcessedUserCheckpoints;\n\n if (\n tokenData.tokenAddress == wrbtcTokenAddress ||\n tokenData.tokenAddress == loanTokenWrbtcAddress ||\n tokenData.tokenAddress == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\n ) {\n (totalAmount, endToken) = _withdrawRbtcTokenStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n } else {\n (, endToken) = _withdrawStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n }\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint).add(1);\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n if (rbtcAmountToSend > 0) {\n // send all rbtc withdrawal\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Function to wrap:\n * 1. regular withdrawal for both rbtc & non-rbtc token\n * 2. skipped checkpoints withdrawal for both rbtc & non-rbtc token\n *\n * @param _nonRbtcTokensRegularWithdraw array of non-rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _rbtcTokensRegularWithdraw array of rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _tokensWithSkippedCheckpoints array of rbtc & non-rbtc TokenWithSkippedCheckpointsWithdraw struct, which has skipped checkpoints that will be withdrawn\n *\n */\n function claimAllCollectedFees(\n address[] calldata _nonRbtcTokensRegularWithdraw,\n address[] calldata _rbtcTokensRegularWithdraw,\n TokenWithSkippedCheckpointsWithdraw[] calldata _tokensWithSkippedCheckpoints,\n uint32 _maxCheckpoints,\n address _receiver\n ) external nonReentrant {\n uint256 totalProcessedCheckpoints;\n\n /** Process normal multiple withdrawal for RBTC based tokens */\n if (_rbtcTokensRegularWithdraw.length > 0) {\n totalProcessedCheckpoints = _withdrawRbtcTokens(\n _rbtcTokensRegularWithdraw,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process normal non-rbtc token withdrawal */\n for (uint256 i = 0; i < _nonRbtcTokensRegularWithdraw.length; i++) {\n if (_maxCheckpoints == 0) break;\n uint256 endTokenCheckpoint;\n\n address _nonRbtcTokenAddress = _nonRbtcTokensRegularWithdraw[i];\n\n /** starting checkpoint is the previous processedCheckpoints for token */\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_nonRbtcTokenAddress];\n\n (, endTokenCheckpoint) = _withdraw(_nonRbtcTokenAddress, _maxCheckpoints, _receiver);\n\n uint256 _previousUsedCheckpoint = endTokenCheckpoint.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n _previousUsedCheckpoint.add(1);\n }\n\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process token with skipped checkpoints withdrawal */\n if (_tokensWithSkippedCheckpoints.length > 0) {\n totalProcessedCheckpoints = _withdrawStartingFromCheckpoints(\n _tokensWithSkippedCheckpoints,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n }\n\n function _withdrawStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10 meaning we should set 9 user's processed checkpoints\n // after _withdraw() the user's processedCheckpoints should be 10\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n (totalAmount, endTokenCheckpoint) = _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function _withdrawRbtcToken(address _token, uint32 _maxCheckpoints)\n internal\n returns (uint256 totalAmount, uint256 endTokenCheckpoint)\n {\n address user = msg.sender;\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n (totalAmount, endTokenCheckpoint) = _getRBTCBalance(_token, user, _maxCheckpoints);\n\n if (totalAmount > 0) {\n processedCheckpoints[user][_token] = endTokenCheckpoint;\n if (_token == address(wrbtcToken)) {\n // unwrap the wrbtc\n wrbtcToken.withdraw(totalAmount);\n } else if (_token == loanTokenWrbtcAddress) {\n // pull out the iWRBTC to rbtc to this feeSharingCollector contract\n /** @dev will use the burned result from IWRBTC to RBTC as return total amount */\n totalAmount = ILoanTokenWRBTC(loanTokenWrbtcAddress).burnToBTC(\n address(this),\n totalAmount,\n false\n );\n }\n }\n }\n\n /**\n * @dev withdraw all of the RBTC balance based on particular checkpoints\n *\n * This function will withdraw RBTC balance which is passed as _token param, so it could be either of these:\n * - rbtc balance or\n * - wrbtc balance which will be unwrapped to rbtc or\n * - iwrbtc balance which will be unwrapped to rbtc or\n *\n *\n * @param _tokens array of either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _maxCheckpoints Maximum number of checkpoints to be processed to workaround block gas limit\n * @param _receiver An optional tokens receiver (msg.sender used if 0)\n */\n function _withdrawRbtcTokens(\n address[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validRBTCBasedTokens(_tokens);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n if (_maxCheckpoints == 0) break;\n address _token = _tokens[i];\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_token];\n\n (uint256 totalAmount, uint256 endToken) =\n _withdrawRbtcToken(_tokens[i], _maxCheckpoints);\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n // we only need to add used checkpoint by 1 only if starting checkpoint > 0\n _previousUsedCheckpoint.add(1);\n }\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n // send all rbtc\n if (rbtcAmountToSend > 0) {\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Withdraw either specific RBTC related token balance or all RBTC related tokens balances.\n * RBTC related here means, it could be either rbtc, wrbtc, or iwrbtc, depends on the _token param.\n */\n function _withdrawRbtcTokenStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) private returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10\n // after _withdraw() user's processedCheckpoints should be 10 =>\n // set processed checkpoints = 9, next maping index = 9 (10th checkpoint)\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n return _withdrawRbtcToken(_token, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n external\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n return _getNextPositiveUserCheckpoint(_user, _token, _startFrom, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function _getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n internal\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n if (staking.isVestingContract(_user)) {\n return (0, false, false);\n }\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n\n if (processedUserCheckpoints >= totalCheckpoints || totalCheckpoints == 0) {\n return (totalCheckpoints, false, false);\n }\n\n uint256 startFrom =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n\n uint256 end = startFrom.add(_maxCheckpoints);\n if (end >= totalCheckpoints) {\n end = totalCheckpoints;\n }\n\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startFrom; i < end; i++) {\n Checkpoint storage tokenCheckpoint = tokenCheckpoints[_token][i];\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n tokenCheckpoint.blockNumber - 1,\n tokenCheckpoint.timestamp\n );\n if (weightedStake > 0) {\n // i is the index and we need to return checkpoint num which is i + 1\n return (i + 1, i > processedUserCheckpoints, true);\n }\n }\n return (end, end > processedUserCheckpoints, false);\n }\n\n /**\n * @notice Get the accumulated loan pool fee of the message sender.\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @return The accumulated fee for the message sender.\n * */\n function getAccumulatedFees(address _user, address _token) public view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: 0\n });\n return amount;\n }\n\n /**\n * @notice Get the accumulated fee rewards for the message sender for a checkpoints range\n *\n * @dev This function is required to keep consistent with caching of weighted voting power when claiming fees\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The accumulated fees rewards for the _user in the given checkpoints interval: [_startFrom, _startFrom + maxCheckpoints].\n * */\n function getAccumulatedFeesForCheckpointsRange(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees(_user, _token, _startFrom, _maxCheckpoints);\n return amount;\n }\n\n /**\n * @dev Get all user fees reward per maxCheckpoint starting from latest processed checkpoint\n *\n * @dev e.g: Total user checkpoint for the particualar token = 300,\n * when we call this function with 50 maxCheckpoint, it will return 6 fee values in array form.\n * if there is no more fees, it will return empty array.\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The next checkpoint num which is the starting point to fetch all of the fees, array of calculated fees.\n * */\n function getAllUserFeesPerMaxCheckpoints(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256[] memory fees) {\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 totalTokensCheckpointsIndex = totalCheckpoints > 0 ? totalCheckpoints - 1 : 0;\n\n if (totalTokensCheckpointsIndex < _startFrom) return fees;\n\n uint256 arrSize = totalTokensCheckpointsIndex.sub(_startFrom).div(_maxCheckpoints) + 1;\n\n fees = new uint256[](arrSize);\n\n for (uint256 i = 0; i < fees.length; i++) {\n (uint256 fee, ) =\n _getAccumulatedFees(\n _user,\n _token,\n _startFrom + i * _maxCheckpoints,\n _maxCheckpoints\n );\n fees[i] = fee;\n }\n\n return fees;\n }\n\n /**\n * @notice Gets accumulated fees for a user starting from a given checkpoint\n *\n * @param _user Address of the user's account.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Max checkpoints to process at once to fit into block gas limit\n * @param _startFrom Checkpoint num to start calculations from\n *\n * @return feesAmount - accumulated fees amount\n * @return endCheckpoint - last checkpoint of fees calculation\n * */\n function _getAccumulatedFees(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 feesAmount, uint256 endCheckpoint) {\n if (staking.isVestingContract(_user)) {\n return (0, 0);\n }\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n uint256 startOfRange =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n endCheckpoint = _maxCheckpoints > 0\n ? _getEndOfRange(startOfRange, _token, _maxCheckpoints)\n : totalTokenCheckpoints[_token];\n\n if (startOfRange >= totalTokenCheckpoints[_token]) {\n return (0, endCheckpoint);\n }\n\n uint256 cachedLockDate = 0;\n uint96 cachedWeightedStake = 0;\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startOfRange; i < endCheckpoint; i++) {\n Checkpoint memory checkpoint = tokenCheckpoints[_token][i];\n uint256 lockDate = staking.timestampToLockDate(checkpoint.timestamp);\n uint96 weightedStake;\n if (lockDate == cachedLockDate) {\n weightedStake = cachedWeightedStake;\n } else {\n /// @dev We need to use \"checkpoint.blockNumber - 1\" here to calculate weighted stake\n /// For the same block like we did for total voting power in _writeTokenCheckpoint\n weightedStake = staking.getPriorWeightedStake(\n _user,\n checkpoint.blockNumber - 1,\n checkpoint.timestamp\n );\n cachedWeightedStake = weightedStake;\n cachedLockDate = lockDate;\n }\n uint256 share =\n uint256(checkpoint.numTokens).mul(weightedStake).div(\n uint256(checkpoint.totalWeightedStake)\n );\n feesAmount = feesAmount.add(share);\n }\n return (feesAmount, endCheckpoint);\n }\n\n /**\n * @notice Withdrawal should only be possible for blocks which were already\n * mined. If the fees are withdrawn in the same block as the user withdrawal\n * they are not considered by the withdrawing logic (to avoid inconsistencies).\n *\n * @param _start Start of the range.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of a pool token.\n * @param _maxCheckpoints Checkpoint index incremental.\n * */\n function _getEndOfRange(\n uint256 _start,\n address _token,\n uint32 _maxCheckpoints\n ) internal view returns (uint256) {\n uint256 nextCheckpointIndex = totalTokenCheckpoints[_token];\n if (nextCheckpointIndex == 0) {\n return 0;\n }\n uint256 end;\n\n if (_maxCheckpoints == 0) {\n /// @dev All checkpoints will be processed (only for getter outside of a transaction).\n end = nextCheckpointIndex;\n } else {\n end = safe32(\n _start + _maxCheckpoints,\n \"FeeSharingCollector::withdraw: checkpoint index exceeds 32 bits\"\n );\n if (end > nextCheckpointIndex) {\n end = nextCheckpointIndex;\n }\n }\n\n /// @dev Withdrawal should only be possible for blocks which were already mined.\n uint32 lastBlockNumber = tokenCheckpoints[_token][end - 1].blockNumber;\n if (block.number == lastBlockNumber) {\n end--;\n }\n return end;\n }\n\n /**\n * @notice Write a regular checkpoint w/ the foolowing data:\n * block number, block timestamp, total weighted stake and num of tokens.\n * @param _token The pool token address.\n * @param _numTokens The amount of pool tokens.\n * */\n function _writeTokenCheckpoint(address _token, uint96 _numTokens) internal {\n uint32 blockNumber =\n safe32(\n block.number,\n \"FeeSharingCollector::_writeCheckpoint: block number exceeds 32 bits\"\n );\n uint32 blockTimestamp =\n safe32(\n block.timestamp,\n \"FeeSharingCollector::_writeCheckpoint: block timestamp exceeds 32 bits\"\n );\n uint256 nextCheckpointsIndex = totalTokenCheckpoints[_token];\n\n uint96 totalWeightedStake = _getVoluntaryWeightedStake(blockNumber - 1, block.timestamp);\n require(totalWeightedStake > 0, \"Invalid totalWeightedStake\");\n if (\n nextCheckpointsIndex > 0 &&\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].blockNumber == blockNumber\n ) {\n tokenCheckpoints[_token][nextCheckpointsIndex - 1]\n .totalWeightedStake = totalWeightedStake;\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].numTokens = _numTokens;\n } else {\n tokenCheckpoints[_token][nextCheckpointsIndex] = Checkpoint(\n blockNumber,\n blockTimestamp,\n totalWeightedStake,\n _numTokens\n );\n totalTokenCheckpoints[_token] = nextCheckpointsIndex + 1;\n }\n emit CheckpointAdded(msg.sender, _token, _numTokens);\n }\n\n /**\n * Queries the total weighted stake and the weighted stake of vesting contracts and returns the difference\n * @param blockNumber the blocknumber\n * @param timestamp the timestamp\n */\n function _getVoluntaryWeightedStake(uint32 blockNumber, uint256 timestamp)\n internal\n view\n returns (uint96 totalWeightedStake)\n {\n uint96 vestingWeightedStake = staking.getPriorVestingWeightedStake(blockNumber, timestamp);\n totalWeightedStake = staking.getPriorTotalVotingPower(blockNumber, timestamp);\n totalWeightedStake = sub96(\n totalWeightedStake,\n vestingWeightedStake,\n \"FeeSharingCollector::_getTotalVoluntaryWeightedStake: vested stake exceeds total stake\"\n );\n }\n\n /**\n * @dev Whitelisting converter address.\n *\n * @param converterAddress converter address to be whitelisted.\n */\n function addWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n require(Address.isContract(converterAddress), \"Non contract address given\");\n whitelistedConverterList.add(converterAddress);\n emit WhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @dev Removing converter address from whitelist.\n *\n * @param converterAddress converter address to be removed from whitelist.\n */\n function removeWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n whitelistedConverterList.remove(converterAddress);\n emit UnwhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @notice Getter to query all of the whitelisted converter.\n * @return All of the whitelisted converter list.\n */\n function getWhitelistedConverterList() external view returns (address[] memory converterList) {\n converterList = whitelistedConverterList.enumerate();\n }\n\n /**\n * @dev validate array of given address whether is whitelisted or not.\n * @dev if one of them is not whitelisted, then revert.\n *\n * @param converterAddresses array of converter addresses.\n */\n function _validateWhitelistedConverter(address[] memory converterAddresses) private view {\n for (uint256 i = 0; i < converterAddresses.length; i++) {\n require(whitelistedConverterList.contains(converterAddresses[i]), \"Invalid Converter\");\n }\n }\n\n function withdrawWRBTC(address receiver, uint256 wrbtcAmount) external onlyOwner {\n IERC20 wrbtcToken = IERC20(wrbtcTokenAddress);\n\n uint256 balance = wrbtcToken.balanceOf(address(this));\n require(wrbtcAmount <= balance, \"Insufficient balance\");\n\n wrbtcToken.safeTransfer(receiver, wrbtcAmount);\n }\n\n /**\n * @dev This function is dedicated to recover the wrong fee allocation for the 4 year vesting contracts.\n * This function can only be called once\n * The affected tokens to be withdrawn\n * 1. RBTC\n * 2. ZUSD\n * 3. SOV\n * The amount for all of the tokens above is hardcoded\n * The withdrawn tokens will be sent to the owner.\n */\n function recoverIncorrectAllocatedFees()\n external\n oneTimeExecution(this.recoverIncorrectAllocatedFees.selector)\n onlyOwner\n {\n uint256 rbtcAmount = 878778886164898400;\n uint256 zusdAmount = 16658600400155126000000;\n uint256 sovAmount = 6275898259771202000000;\n\n address zusdToken = 0xdB107FA69E33f05180a4C2cE9c2E7CB481645C2d;\n address sovToken = 0xEFc78fc7d48b64958315949279Ba181c2114ABBd;\n\n // Withdraw rbtc\n (bool success, ) = owner().call.value(rbtcAmount)(\"\");\n require(\n success,\n \"FeeSharingCollector::recoverIncorrectAllocatedFees: Withdrawal rbtc failed\"\n );\n\n // Withdraw ZUSD\n IERC20(zusdToken).safeTransfer(owner(), zusdAmount);\n\n // Withdraw SOV\n IERC20(sovToken).safeTransfer(owner(), sovAmount);\n }\n\n /**\n * @dev view function that calculate the total RBTC that includes:\n * - RBTC\n * - WRBTC\n * - iWRBTC * iWRBTC.tokenPrice()\n * @param _user address of the user.\n * @return rbtc balance of the given user's address.\n */\n function getAccumulatedRBTCFeeBalances(address _user) external view returns (uint256) {\n (uint256 _rbtcAmount, uint256 _wrbtcAmount, uint256 _iWrbtcAmount, , , ) =\n _getRBTCBalances(_user, 0);\n uint256 iWRBTCAmountInRBTC =\n _iWrbtcAmount.mul(ILoanTokenWRBTC(loanTokenWrbtcAddress).tokenPrice()).div(1e18);\n return _rbtcAmount.add(_wrbtcAmount).add(iWRBTCAmountInRBTC);\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _rbtcAmount rbtc amount\n * @return _wrbtcAmount wrbtc amount\n * @return _iWrbtcAmount iWrbtc (wrbtc lending pool token) amount * token price\n * @return _endRBTC end time of accumulated fee calculation for rbtc\n * @return _endWRBTC end time of accumulated fee calculation for wrbtc\n * @return _endIWRBTC end time of accumulated fee calculation for iwrbtc\n */\n function _getRBTCBalances(address _user, uint32 _maxCheckpoints)\n private\n view\n returns (\n uint256 _rbtcAmount,\n uint256 _wrbtcAmount,\n uint256 _iWrbtcAmount,\n uint256 _endRBTC,\n uint256 _endWRBTC,\n uint256 _endIWRBTC\n )\n {\n (_rbtcAmount, _endRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n\n (_wrbtcAmount, _endWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: wrbtcTokenAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n (_iWrbtcAmount, _endIWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: loanTokenWrbtcAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _token either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _tokenAmount token (rbtc, or wrbtc, or iwrbtc) amount\n * @return _endToken end time of accumulated fee calculation for token (rbtc, or wrbtc, or iwrbtc )\n */\n function _getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 _tokenAmount, uint256 _endToken) {\n if (\n _token == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT ||\n _token == wrbtcTokenAddress ||\n _token == loanTokenWrbtcAddress\n ) {\n (_tokenAmount, _endToken) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n } else {\n revert(\"FeeSharingCollector::_getRBTCBalance: only rbtc-based tokens are allowed\");\n }\n }\n\n // @todo update dependency `numTokenCheckpoints` -> `totalTokenCheckpoints` and deprecate numTokenCheckpoints function\n /**\n * @dev This getter function `numTokenCheckpoints` is added for backwards compatibility\n * broken when renamed `numTokenCheckpoints` storage variable to `totalTokenCheckpoints`.\n *\n * @param _token token address to get checkpoints for\n *\n * @return Total token checkpoints\n */\n function numTokenCheckpoints(address _token) external view returns (uint256) {\n return totalTokenCheckpoints[_token];\n }\n}\n\n/* Interfaces */\ninterface ILoanToken {\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n}\n\ninterface ILoanTokenWRBTC {\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function tokenPrice() external view returns (uint256 price);\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title FeeSharingCollectorProxy contract.\n * @dev FeeSharingCollectorProxy contract should be upgradable, use UpgradableProxy.\n * FeeSharingCollectorStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract FeeSharingCollectorProxy is FeeSharingCollectorStorage, UpgradableProxy {\n /**\n * @notice Construct a new feeSharingCollectorProxy contract.\n * @param _protocol The address of the sovryn protocol.\n * @param _staking The address of the staking\n */\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorStorage.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../mixins/EnumerableAddressSet.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\n\n/**\n * @title FeeSharingCollectorStorage contact\n * @notice Just the storage part of FeeSharingCollector contract, and FeeSharingCollectorProxy. No functions,\n * only constant, variables and required structures (mappings)\n * */\ncontract FeeSharingCollectorStorage is Ownable {\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet;\n uint256 constant FEE_WITHDRAWAL_INTERVAL = 172800;\n\n IProtocol public protocol;\n IStaking public staking;\n\n /// @notice Checkpoints by index per pool token address\n mapping(address => mapping(uint256 => Checkpoint)) public tokenCheckpoints;\n\n /// @notice The number of checkpoints for each token address.\n mapping(address => uint256) public totalTokenCheckpoints;\n\n /// @notice\n /// user => token => processed checkpoints\n mapping(address => mapping(address => uint256)) public processedCheckpoints;\n\n /// @notice Last time fees were withdrawn per pool token address:\n /// token => time\n mapping(address => uint256) public lastFeeWithdrawalTime;\n\n /// @notice Amount of tokens that were transferred, but not saved in checkpoints.\n /// token => amount\n mapping(address => uint96) public unprocessedAmount;\n\n struct Checkpoint {\n uint32 blockNumber;\n uint32 timestamp;\n uint96 totalWeightedStake;\n uint96 numTokens;\n }\n\n struct TokenWithSkippedCheckpointsWithdraw {\n address tokenAddress;\n uint256 fromCheckpoint;\n }\n\n /**\n * @dev Add extra modifier (Reentrancy) below.\n * Because we cannot add any additional storage slot before this storage contract after initial deployment\n */\n\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Additional storage for converter whitelist mechanism.\n * @dev Initialization here does not works. We need to create a separate setter & getter.\n * @dev Just set the visibility to internal should be fine.\n */\n EnumerableAddressSet.AddressSet internal whitelistedConverterList;\n\n mapping(bytes4 => bool) public isFunctionExecuted;\n\n /**\n * @dev Wrbtc token address\n */\n address public wrbtcTokenAddress;\n\n /**\n * @dev iWrbtc loan token address\n */\n address public loanTokenWrbtcAddress;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n\n/* Interfaces */\n\ninterface IProtocol {\n /**\n *\n * @param tokens The array address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function underlyingToLoanPool(address token) external view returns (address);\n\n function wrbtcToken() external view returns (IWrbtcERC20);\n\n function getSovTokenAddress() external view returns (address);\n}\n" + }, + "contracts/governance/GovernorAlpha.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./Staking/SafeMath96.sol\";\nimport \"./Timelock.sol\";\nimport \"./Staking/interfaces/IStaking.sol\";\nimport \"../rsk/RSKAddrValidator.sol\";\n\n/**\n * @title Governance Contract.\n * @notice This is an adapted clone of compound’s governance model. In general,\n * the process is the same: Token holders can make (executable) proposals if\n * they possess enough voting power, vote on proposals during a predefined\n * voting period and in the end evaluate the outcome. If successful, the\n * proposal will be scheduled on the timelock contract. Only after sufficient\n * time passed, it can be executed. A minimum voting power is required for\n * making a proposal as well as a minimum quorum.\n *\n * Voting power in the Bitocracy:\n * Stakers will receive voting power in the Bitocracy in return for their\n * staking commitment. This voting power is weighted by how much SOV is staked\n * and for how long the staking period is - staking more SOV over longer staking\n * periods results in higher voting power. With this voting power, users can\n * vote for or against any SIP in bitocracy.sovryn.app.\n * */\ncontract GovernorAlpha is SafeMath96 {\n /* Storage */\n\n /// @notice The name of this contract.\n string public constant NAME = \"Sovryn Governor Alpha\";\n\n /// @notice The maximum number of actions that can be included in a proposal.\n function proposalMaxOperations() public pure returns (uint256) {\n return 10;\n } // 10 actions\n\n /// @notice The delay before voting on a proposal may take place, once proposed.\n function votingDelay() public pure returns (uint256) {\n return 1;\n } // 1 block\n\n /// @notice The duration of voting on a proposal, in blocks.\n function votingPeriod() public pure returns (uint256) {\n return 2880;\n } // ~1 day in blocks (assuming 30s blocks)\n\n /// @notice The address of the Sovryn Protocol Timelock.\n ITimelock public timelock;\n\n /// @notice The address of the Sovryn staking contract.\n IStaking public staking;\n\n /// @notice The address of the Governor Guardian.\n address public guardian;\n\n /// @notice The total number of proposals.\n uint256 public proposalCount;\n\n /// @notice Percentage of current total voting power require to vote.\n uint96 public quorumPercentageVotes;\n\n // @notice Majority percentage.\n uint96 public majorityPercentageVotes;\n\n struct Proposal {\n /// @notice Unique id for looking up a proposal.\n uint256 id;\n /// @notice The block at which voting begins: holders must delegate their votes prior to this block.\n uint32 startBlock;\n /// @notice The block at which voting ends: votes must be cast prior to this block.\n uint32 endBlock;\n /// @notice Current number of votes in favor of this proposal.\n uint96 forVotes;\n /// @notice Current number of votes in opposition to this proposal.\n uint96 againstVotes;\n ///@notice the quorum required for this proposal.\n uint96 quorum;\n ///@notice the majority percentage required for this proposal.\n uint96 majorityPercentage;\n /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds.\n uint64 eta;\n /// @notice the start time is required for the staking contract.\n uint64 startTime;\n /// @notice Flag marking whether the proposal has been canceled.\n bool canceled;\n /// @notice Flag marking whether the proposal has been executed.\n bool executed;\n /// @notice Creator of the proposal.\n address proposer;\n /// @notice the ordered list of target addresses for calls to be made.\n address[] targets;\n /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made.\n uint256[] values;\n /// @notice The ordered list of function signatures to be called.\n string[] signatures;\n /// @notice The ordered list of calldata to be passed to each call.\n bytes[] calldatas;\n /// @notice Receipts of ballots for the entire set of voters.\n mapping(address => Receipt) receipts;\n }\n\n /// @notice Ballot receipt record for a voter\n struct Receipt {\n /// @notice Whether or not a vote has been cast.\n bool hasVoted;\n /// @notice Whether or not the voter supports the proposal.\n bool support;\n /// @notice The number of votes the voter had, which were cast.\n uint96 votes;\n }\n\n /// @notice Possible states that a proposal may be in.\n enum ProposalState {\n Pending,\n Active,\n Canceled,\n Defeated,\n Succeeded,\n Queued,\n Expired,\n Executed\n }\n\n /// @notice The official record of all proposals ever proposed.\n mapping(uint256 => Proposal) public proposals;\n\n /// @notice The latest proposal for each proposer.\n mapping(address => uint256) public latestProposalIds;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the ballot struct used by the contract.\n bytes32 public constant BALLOT_TYPEHASH = keccak256(\"Ballot(uint256 proposalId,bool support)\");\n\n /* Events */\n\n /// @notice An event emitted when a new proposal is created.\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint256 startBlock,\n uint256 endBlock,\n string description\n );\n\n /// @notice An event emitted when a vote has been cast on a proposal.\n event VoteCast(address voter, uint256 proposalId, bool support, uint256 votes);\n\n /// @notice An event emitted when a proposal has been canceled.\n event ProposalCanceled(uint256 id);\n\n /// @notice An event emitted when a proposal has been queued in the Timelock.\n event ProposalQueued(uint256 id, uint256 eta);\n\n /// @notice An event emitted when a proposal has been executed in the Timelock.\n event ProposalExecuted(uint256 id);\n\n /* Functions */\n\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 _quorumPercentageVotes,\n uint96 _majorityPercentageVotes\n ) public {\n timelock = ITimelock(timelock_);\n staking = IStaking(staking_);\n guardian = guardian_;\n quorumPercentageVotes = _quorumPercentageVotes;\n majorityPercentageVotes = _majorityPercentageVotes;\n }\n\n /// @notice The number of votes required in order for a voter to become a proposer.\n function proposalThreshold() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(\n block.number - 1,\n \"GovernorAlpha::proposalThreshold: block number overflow\"\n ),\n block.timestamp\n );\n // 1% of current total voting power.\n return totalVotingPower / 100;\n }\n\n /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.\n function quorumVotes() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(block.number - 1, \"GovernorAlpha::quorumVotes: block number overflow\"),\n block.timestamp\n );\n // 4% of current total voting power.\n return\n mul96(\n quorumPercentageVotes,\n totalVotingPower,\n \"GovernorAlpha::quorumVotes:multiplication overflow\"\n ) / 100;\n }\n\n /**\n * @notice Create a new proposal.\n * @param targets Array of contract addresses to perform proposal execution.\n * @param values Array of rBTC amounts to send on proposal execution.\n * @param signatures Array of function signatures to call on proposal execution.\n * @param calldatas Array of payloads for the calls on proposal execution.\n * @param description Text describing the purpose of the proposal.\n * */\n function propose(\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // note: passing this block's timestamp, but the number of the previous block.\n // todo: think if it would be better to pass block.timestamp - 30 (average block time)\n // (probably not because proposal starts in 1 block from now).\n uint96 threshold = proposalThreshold();\n require(\n staking.getPriorVotes(msg.sender, sub256(block.number, 1), block.timestamp) >\n threshold,\n \"GovernorAlpha::propose: proposer votes below proposal threshold\"\n );\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"GovernorAlpha::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"GovernorAlpha::propose: must provide actions\");\n require(\n targets.length <= proposalMaxOperations(),\n \"GovernorAlpha::propose: too many actions\"\n );\n\n uint256 latestProposalId = latestProposalIds[msg.sender];\n if (latestProposalId != 0) {\n ProposalState proposersLatestProposalState = state(latestProposalId);\n require(\n proposersLatestProposalState != ProposalState.Active,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already active proposal\"\n );\n require(\n proposersLatestProposalState != ProposalState.Pending,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal\"\n );\n }\n\n uint256 startBlock = add256(block.number, votingDelay());\n uint256 endBlock = add256(startBlock, votingPeriod());\n\n proposalCount++;\n\n /// @dev quorum: proposalThreshold is 1% of total votes, we can save gas using this pre calculated value.\n /// @dev startTime: Required by the staking contract. not used by the governance contract itself.\n Proposal memory newProposal =\n Proposal({\n id: proposalCount,\n startBlock: safe32(\n startBlock,\n \"GovernorAlpha::propose: start block number overflow\"\n ),\n endBlock: safe32(endBlock, \"GovernorAlpha::propose: end block number overflow\"),\n forVotes: 0,\n againstVotes: 0,\n quorum: mul96(\n quorumPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on quorum computation\"\n ),\n majorityPercentage: mul96(\n majorityPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on majorityPercentage computation\"\n ),\n eta: 0,\n startTime: safe64(block.timestamp, \"GovernorAlpha::propose: startTime overflow\"),\n canceled: false,\n executed: false,\n proposer: msg.sender,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas\n });\n\n proposals[newProposal.id] = newProposal;\n latestProposalIds[newProposal.proposer] = newProposal.id;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n values,\n signatures,\n calldatas,\n startBlock,\n endBlock,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Enqueue a proposal and everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function queue(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Succeeded,\n \"GovernorAlpha::queue: proposal can only be queued if it is succeeded\"\n );\n Proposal storage proposal = proposals[proposalId];\n uint256 eta = add256(block.timestamp, timelock.delay());\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n proposal.eta = safe64(eta, \"GovernorAlpha::queue: ETA overflow\");\n emit ProposalQueued(proposalId, eta);\n }\n\n /**\n * @notice Tries to enqueue a proposal, verifying it has not been previously queued.\n * @param target Contract addresses to perform proposal execution.\n * @param value rBTC amount to send on proposal execution.\n * @param signature Function signature to call on proposal execution.\n * @param data Payload for the call on proposal execution.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function _queueOrRevert(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !timelock.queuedTransactions(\n keccak256(abi.encode(target, value, signature, data, eta))\n ),\n \"GovernorAlpha::_queueOrRevert: proposal action already queued at eta\"\n );\n timelock.queueTransaction(target, value, signature, data, eta);\n }\n\n /**\n * @notice Execute a proposal by looping and performing everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function execute(uint256 proposalId) public payable {\n require(\n state(proposalId) == ProposalState.Queued,\n \"GovernorAlpha::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.executeTransaction.value(proposal.values[i])(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal by looping and cancelling everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function cancel(uint256 proposalId) public {\n ProposalState state = state(proposalId);\n require(\n state != ProposalState.Executed,\n \"GovernorAlpha::cancel: cannot cancel executed proposal\"\n );\n\n Proposal storage proposal = proposals[proposalId];\n /// @notice Cancel only if sent by the guardian.\n require(msg.sender == guardian, \"GovernorAlpha::cancel: sender isn't a guardian\");\n\n proposal.canceled = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalCanceled(proposalId);\n }\n\n /**\n * @notice Get a proposal list of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return Arrays of the 4 call parameters: targets, values, signatures, calldatas.\n * */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.values, p.signatures, p.calldatas);\n }\n\n /**\n * @notice Get a proposal receipt.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param voter A governance stakeholder with voting power.\n * @return The voter receipt of the proposal.\n * */\n function getReceipt(uint256 proposalId, address voter) public view returns (Receipt memory) {\n return proposals[proposalId].receipts[voter];\n }\n\n /**\n * @notice Casts a vote by sender.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function castVote(uint256 proposalId, bool support) public {\n return _castVote(msg.sender, proposalId, support);\n }\n\n /**\n * @notice Voting with EIP-712 Signatures.\n *\n * Voting power can be delegated to any address, and then can be used to\n * vote on proposals. A key benefit to users of by-signature functionality\n * is that they can create a signed vote transaction for free, and have a\n * trusted third-party spend rBTC(or ETH) on gas fees and write it to the\n * blockchain for them.\n *\n * The third party in this scenario, submitting the SOV-holder’s signed\n * transaction holds a voting power that is for only a single proposal.\n * The signatory still holds the power to vote on their own behalf in\n * the proposal if the third party has not yet published the signed\n * transaction that was given to them.\n *\n * @dev The signature needs to be broken up into 3 parameters, known as\n * v, r and s:\n * const r = '0x' + sig.substring(2).substring(0, 64);\n * const s = '0x' + sig.substring(2).substring(64, 128);\n * const v = '0x' + sig.substring(2).substring(128, 130);\n *\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * @param v The recovery byte of the signature.\n * @param r Half of the ECDSA signature pair.\n * @param s Half of the ECDSA signature pair.\n * */\n function castVoteBySig(\n uint256 proposalId,\n bool support,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public {\n /**\n * @dev The DOMAIN_SEPARATOR is a hash that uniquely identifies a\n * smart contract. It is built from a string denoting it as an\n * EIP712 Domain, the name of the token contract, the version,\n * the chainId in case it changes, and the address that the\n * contract is deployed at.\n * */\n bytes32 domainSeparator =\n keccak256(\n abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this))\n );\n\n /// @dev GovernorAlpha uses BALLOT_TYPEHASH, while Staking uses DELEGATION_TYPEHASH\n bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support));\n\n bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n address signatory = ecrecover(digest, v, r, s);\n\n /// @dev Verify address is not null and PK is not null either.\n require(\n RSKAddrValidator.checkPKNotZero(signatory),\n \"GovernorAlpha::castVoteBySig: invalid signature\"\n );\n return _castVote(signatory, proposalId, support);\n }\n\n /**\n * @notice Cast a vote, adding it to the total counting.\n * @param voter A governance stakeholder with voting power that is casting the vote.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function _castVote(\n address voter,\n uint256 proposalId,\n bool support\n ) internal {\n require(\n state(proposalId) == ProposalState.Active,\n \"GovernorAlpha::_castVote: voting is closed\"\n );\n Proposal storage proposal = proposals[proposalId];\n Receipt storage receipt = proposal.receipts[voter];\n require(receipt.hasVoted == false, \"GovernorAlpha::_castVote: voter already voted\");\n uint96 votes = staking.getPriorVotes(voter, proposal.startBlock, proposal.startTime);\n\n if (support) {\n proposal.forVotes = add96(\n proposal.forVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n } else {\n proposal.againstVotes = add96(\n proposal.againstVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n }\n\n receipt.hasVoted = true;\n receipt.support = support;\n receipt.votes = votes;\n\n emit VoteCast(voter, proposalId, support, votes);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __acceptAdmin() public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__acceptAdmin: sender must be gov guardian\"\n );\n timelock.acceptAdmin();\n }\n\n /// @notice Sets guardian address to zero.\n function __abdicate() public {\n require(msg.sender == guardian, \"GovernorAlpha::__abdicate: sender must be gov guardian\");\n guardian = address(0);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.queueTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.executeTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /**\n * @notice Get a proposal state.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return The state of the proposal: Canceled, Pending, Active, Defeated,\n * Succeeded, Executed, Expired.\n * */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"GovernorAlpha::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n\n if (proposal.canceled) {\n return ProposalState.Canceled;\n }\n\n if (block.number <= proposal.startBlock) {\n return ProposalState.Pending;\n }\n\n if (block.number <= proposal.endBlock) {\n return ProposalState.Active;\n }\n\n uint96 totalVotes =\n add96(\n proposal.forVotes,\n proposal.againstVotes,\n \"GovernorAlpha:: state: forVotes + againstVotes > uint96\"\n );\n uint96 totalVotesMajorityPercentage =\n div96(totalVotes, 100, \"GovernorAlpha:: state: division error\");\n totalVotesMajorityPercentage = mul96(\n totalVotesMajorityPercentage,\n majorityPercentageVotes,\n \"GovernorAlpha:: state: totalVotes * majorityPercentage > uint96\"\n );\n if (proposal.forVotes <= totalVotesMajorityPercentage || totalVotes < proposal.quorum) {\n return ProposalState.Defeated;\n }\n\n if (proposal.eta == 0) {\n return ProposalState.Succeeded;\n }\n\n if (proposal.executed) {\n return ProposalState.Executed;\n }\n\n if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) {\n return ProposalState.Expired;\n }\n\n return ProposalState.Queued;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function add256(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"addition overflow\");\n return c;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function sub256(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b <= a, \"subtraction underflow\");\n return a - b;\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n}\n\n/* Interfaces */\n\ninterface TimelockInterface {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\ninterface StakingInterface {\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n}\n" + }, + "contracts/governance/GovernorVault.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title Governance Vault.\n * @notice This contract stores tokens and rBTC only transfereble by owner,\n * i.e. Sovryn governance.\n * */\ncontract GovernorVault is Ownable {\n /* Events */\n\n event Deposited(address indexed sender, uint256 amount);\n event TokensTransferred(address indexed receiver, address indexed token, uint256 amount);\n event RbtcTransferred(address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer tokens.\n * @param _receiver The receiver of tokens.\n * @param _token The address of token contract.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _receiver,\n address _token,\n uint256 _amount\n ) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n require(_token != address(0), \"Invalid token address\");\n\n require(IERC20(_token).transfer(_receiver, _amount), \"Transfer failed\");\n emit TokensTransferred(_receiver, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC.\n * @param _receiver The receiver of RBTC.\n * @param _amount The amount to be transferred.\n * */\n function transferRbtc(address payable _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n\n address(_receiver).transfer(_amount);\n emit RbtcTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {\n if (msg.value > 0) {\n emit Deposited(msg.sender, msg.value);\n }\n }\n}\n" + }, + "contracts/governance/IFeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * */\ninterface IFeeSharingCollector {\n function withdrawFees(address[] calldata _token) external;\n\n function transferTokens(address _token, uint96 _amount) external;\n\n function withdraw(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external;\n}\n" + }, + "contracts/governance/Staking/interfaces/IStaking.sol": { + "content": "pragma solidity ^0.5.17;\n\npragma experimental ABIEncoderV2;\n\n/**\n * @title Interface for Staking modules governance/Staking/modules\n */\n\ninterface IStaking {\n /*************************** StakingAdminModule ***************************/\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external;\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external;\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external;\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external;\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) external;\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external;\n\n /**\n * @notice Allows the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external;\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external;\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external;\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\n\n /*************************** StakingGovernanceModule ***************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\n * be internal instead of a public function.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external;\n\n /*************************** StakingStakeModule ***************************/\n\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance);\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes);\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\n\n /*************************** StakingStorageModule ***************************/\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n /// @return uint256(MAX_VOTING_WEIGHT);\n function getStorageMaxVotingWeight() external pure returns (uint256);\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n /// @return uint256(WEIGHT_FACTOR);\n function getStorageWeightFactor() external pure returns (uint256);\n\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\n function getStorageDefaultWeightScaling() external pure returns (uint256);\n\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\n\n /// @notice The EIP-712 typehash for the contract's domain.\n /// @return uint256(DOMAIN_TYPEHASH);\n function getStorageDomainTypehash() external pure returns (uint256);\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n /// @return uint256(DELEGATION_TYPEHASH);\n function getStorageDelegationTypehash() external pure returns (uint256);\n\n /// @return name;\n function getStorageName() external view returns (string memory);\n\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n function kickoffTS() external view returns (uint256);\n\n /// @notice The token to be staked\n function SOVToken() external view returns (address);\n\n /// @notice Stakers delegated voting power\n /// @param staker - the delegating address\n /// @param until - delegated voting\n /// @return _delegate - voting power delegated to address\n function delegates(address staker, uint256 until) external view returns (address _delegate);\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately\n /// see function unlockAllTokens() for details\n function allUnlocked() external view returns (bool);\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\n function newStakingContract() external view returns (address);\n\n /// CHECKPOINTS\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\n function totalStakingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n function numTotalStakingCheckpoints(uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n function delegateStakingCheckpoints(\n address delagatee,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n function userStakingCheckpoints(\n address user,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number\n function numUserStakingCheckpoints(address user, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n function nonces(address user) external view returns (uint256 nonce);\n\n /// SLASHING ///\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n function feeSharing() external view returns (address);\n\n /// @notice used for weight scaling when unstaking with slashing.\n /// @return uint96 DEFAULT_WEIGHT_SCALING\n function weightScaling() external view returns (uint96);\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n function admins(address isAdmin) external view returns (bool);\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n function vestingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\n\n ///@notice vesting registry contract PROXY address\n function vestingRegistryLogic() external view returns (address);\n\n /// @dev user => flag whether user has pauser role.\n function pausers(address isPauser) external view returns (bool);\n\n /// @dev Staking contract is paused\n function paused() external view returns (bool);\n\n /// @dev Staking contract is frozen\n function frozen() external view returns (bool);\n\n /*************************** StakingVestingModule ***************************/\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool);\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external;\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external;\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes);\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n /*************************** StakingWithdrawModule ***************************/\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * */\n function governanceWithdrawVesting(address vesting, address receiver) external;\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96);\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external;\n\n /*************************** WeightedStakingModule ***************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The date/timestamp of the unstaking time.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * TODO: WeightedStaking::weightedStakeByDate should probably better\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Returns public constant MAX_DURATION\n * preserved for backwards compatibility\n * Use getStorageMaxDurationToStakeTokens()\n * @return uint96 MAX_DURATION for staking\n **/\n function MAX_DURATION() external view returns (uint256);\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() external view returns (address);\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() external view returns (bool);\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) external;\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external;\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() external view returns (uint256);\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param maxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\n}\n" + }, + "contracts/governance/Staking/modules/shared/CheckpointsShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\n\n/**\n * @title Checkpoints contract.\n * @notice Increases and decreases storage values for users, delegatees and\n * total daily stake.\n * */\ncontract CheckpointsShared is StakingStorageShared, SafeMath96 {\n /// @notice An event emitted when an account changes its delegate.\n event DelegateChanged(\n address indexed delegator,\n uint256 lockedUntil,\n address indexed fromDelegate,\n address indexed toDelegate\n );\n\n /// @notice An event emitted when a delegate account's stake balance changes.\n event DelegateStakeChanged(\n address indexed delegate,\n uint256 lockedUntil,\n uint256 previousBalance,\n uint256 newBalance\n );\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n event ContractCodeHashAdded(bytes32 hash);\n\n event ContractCodeHashRemoved(bytes32 hash);\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n event TeamVestingCancelled(address indexed caller, address receiver);\n\n event TeamVestingPartiallyCancelled(\n address indexed caller,\n address receiver,\n uint256 lastProcessedDate\n );\n\n constructor() internal {\n // abstract\n }\n\n /**\n * @notice Increases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = add96(vested, value, \"CP01\"); // vested overflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Decreases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = sub96(vested, value, \"CP02\"); // vested underflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Writes on storage the user vested amount.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newVest The new vest balance.\n * */\n function _writeVestingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newVest\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP03\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n vestingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n vestingCheckpoints[lockedTS][nCheckpoints - 1].stake = newVest;\n } else {\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newVest);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP04\"); // staked overflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP05\"); // staked underflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the user stake.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeUserCheckpoint(\n address account,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP06\"); // block number > 32 bits\n\n if (\n nCheckpoints > 0 &&\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n userStakingCheckpoints[account][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numUserStakingCheckpoints[account][lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP07\"); // block number > 32 bits\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = 0;\n // @dev We need to check delegate checkpoint value here,\n //\t\tbecause we had an issue in `stake` function:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n // @dev It can be greater than 0, but inconsistent after 3 transactions\n if (staked > value) {\n newStake = sub96(staked, value, \"CP08\"); // staked underflow\n }\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the delegate stake.\n * @param delegatee The delegate address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeDelegateCheckpoint(\n address delegatee,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP09\"); // block numb > 32 bits\n uint96 oldStake = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n\n if (\n nCheckpoints > 0 &&\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].fromBlock ==\n blockNumber\n ) {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numDelegateStakingCheckpoints[delegatee][lockedTS] = nCheckpoints + 1;\n }\n emit DelegateStakeChanged(delegatee, lockedTS, oldStake, newStake);\n }\n\n /**\n * @notice Increases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP10\"); // staked overflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP11\"); // staked underflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the total stake.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeStakingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP12\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n totalStakingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newStake);\n numTotalStakingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Get the current balance of an account locked until a certain date.\n * @param account The user address.\n * @param lockDate The lock date.\n * @return The stake amount.\n * */\n function _currentBalance(address account, uint256 lockDate) internal view returns (uint96) {\n uint32 _numUnserStakingCheckpoints = numUserStakingCheckpoints[account][lockDate] - 1;\n return userStakingCheckpoints[account][lockDate][_numUnserStakingCheckpoints].stake;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\nimport \"../../../../openzeppelin/SafeMath.sol\";\nimport \"../../../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking modules shared functionality\n */\ncontract StakingShared is StakingStorageShared, SafeMath96 {\n using SafeMath for uint256;\n\n uint256 internal constant FOUR_WEEKS = 4 weeks;\n\n /**\n * @dev Throws if paused.\n */\n modifier whenNotPaused() {\n require(!paused, \"paused\"); // SS03\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\"); // SS01\n _;\n }\n\n /**\n\t * @dev Throws if called by any account other than the owner or admin or pauser.\n\t \n\tmodifier onlyAuthorizedOrPauser() {\n\t\trequire(isOwner() || admins[msg.sender] || pausers[msg.sender], \"unauthorized\"); // WS02\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if called by any account other than the owner or pauser.\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || pausers[msg.sender], \"unauthorized\"); // SS02\n _;\n }\n\n /**\n * @dev Throws if called by any account other than pauser.\n * @notice Uncomment when needed\n */\n /*\n\tmodifier onlyPauser() {\n\t\trequire(pausers[msg.sender], \"Not pauser\");\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if frozen.\n */\n modifier whenNotFrozen() {\n require(!frozen, \"paused\"); // SS04\n _;\n }\n\n constructor() internal {\n // abstract\n }\n\n function _notSameBlockAsStakingCheckpoint(uint256 lockDate, address stakeFor) internal view {\n uint32 nCheckpoints = numUserStakingCheckpoints[stakeFor][lockDate];\n bool notSameBlock =\n userStakingCheckpoints[stakeFor][lockDate][nCheckpoints - 1].fromBlock != block.number;\n require(notSameBlock, \"cannot be mined in the same block as last stake\"); // S20\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = kickoffTS;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / TWO_WEEKS;\n lockDate = periodFromKickoff * TWO_WEEKS + start;\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS14\n\n date = _adjustDateForOrigin(date);\n uint32 nCheckpoints = numUserStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (userStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return userStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (userStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = userStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return userStakingCheckpoints[account][date][lower].stake;\n }\n\n /**\n * @dev origin vesting contracts have different dates\n * we need to add 2 weeks to get end of period (by default, it's start)\n * @param date The staking date to compute the power for.\n * @return unlocking date.\n */\n function _adjustDateForOrigin(uint256 date) internal view returns (uint256) {\n uint256 adjustedDate = _timestampToLockDate(date);\n //origin vesting contracts have different dates\n //we need to add 2 weeks to get end of period (by default, it's start)\n if (adjustedDate != date) {\n date = adjustedDate + TWO_WEEKS;\n }\n return date;\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function _computeWeightByDate(uint256 date, uint256 startDate)\n internal\n pure\n returns (uint96 weight)\n {\n require(date >= startDate, \"date < startDate\"); // WS18\n uint256 remainingTime = (date - startDate);\n require(MAX_DURATION >= remainingTime, \"remaining time > max duration\"); // WS19\n /// @dev x = max days - remaining days\n uint96 x = uint96(MAX_DURATION - remainingTime) / (1 days);\n /// @dev w = (m^2 - x^2)/m^2 +1 (multiplied by the weight factor)\n weight = add96(\n WEIGHT_FACTOR,\n mul96(\n MAX_VOTING_WEIGHT * WEIGHT_FACTOR,\n sub96(\n MAX_DURATION_POW_2,\n x * x,\n \"weight underflow\" // WS20\n ),\n \"weight mul overflow\" // WS21\n ) / MAX_DURATION_POW_2,\n \"overflow on weight\" // WS22\n );\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function _isVestingContract(address stakerAddress) internal view returns (bool) {\n bool isVesting;\n bytes32 codeHash;\n\n assembly {\n codeHash := extcodehash(stakerAddress)\n }\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingStorageShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../../openzeppelin/Ownable.sol\";\nimport \"../../../../interfaces/IERC20.sol\";\nimport \"../../../IFeeSharingCollector.sol\";\nimport \"../../../Vesting/IVestingRegistry.sol\";\n\n/**\n * @title StakingStorageShared contract is inherited by Staking modules.\n * @notice Just the storage part of stacking contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingProxy and Checkpoints contracts.\n *\n * What is SOV staking?\n * The purpose of the SOV token is to provide a pseudonymous,\n * censorship-resistant mechanism for governing the parameters of the Sovryn\n * protocol, while aligning the incentives of protocol governors with the\n * long-term success of the protocol. Any SOV token holder can choose to\n * stake (lock up) their tokens for a fixed period of time in return for\n * voting rights in the Bitocracy. Stakers are further incentivised through\n * fee and slashing rewards.\n * */\ncontract StakingStorageShared is Ownable {\n /// @notice 2 weeks in seconds.\n uint256 constant TWO_WEEKS = 1209600;\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n uint96 public constant MAX_VOTING_WEIGHT = 9;\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n uint96 public constant WEIGHT_FACTOR = 10;\n\n /// @notice The maximum duration to stake tokens for.\n uint256 public constant MAX_DURATION = 1092 days;\n\n /// @notice The maximum duration ^2\n uint96 constant MAX_DURATION_POW_2 = 1092 * 1092;\n\n /// @notice Default weight scaling.\n uint96 constant DEFAULT_WEIGHT_SCALING = 3;\n\n /// @notice Range for weight scaling.\n uint96 constant MIN_WEIGHT_SCALING = 1;\n uint96 constant MAX_WEIGHT_SCALING = 9;\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n uint256 public kickoffTS;\n\n string name = \"SOVStaking\";\n\n /// @notice The token to be staked.\n IERC20 public SOVToken;\n\n /// @notice A record of each accounts delegate.\n mapping(address => mapping(uint256 => address)) public delegates;\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately.\n bool public allUnlocked = false;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n bytes32 public constant DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 lockDate,uint256 nonce,uint256 expiry)\");\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure.\n address public newStakingContract;\n\n /*************************** Checkpoints *******************************/\n\n /// @notice A checkpoint for marking the stakes from a given block\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public totalStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numTotalStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public delegateStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numDelegateStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public userStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numUserStakingCheckpoints;\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n mapping(address => uint256) public nonces;\n\n /*************************** Slashing *******************************/\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n IFeeSharingCollector public feeSharing;\n\n /// @notice used for weight scaling when unstaking with slashing.\n uint96 public weightScaling = DEFAULT_WEIGHT_SCALING;\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n mapping(address => bool) public vestingWhitelist;\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n mapping(address => bool) public admins;\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n mapping(bytes32 => bool) public vestingCodeHashes;\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public vestingCheckpoints;\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numVestingCheckpoints;\n\n ///@notice vesting registry contract\n IVestingRegistry public vestingRegistryLogic;\n\n /// @dev user => flag whether user has pauser role.\n mapping(address => bool) public pausers;\n\n /// @dev Staking contract is paused\n bool public paused;\n\n /// @dev Staking contract is frozen\n bool public frozen;\n\n /// @dev max iterations that can be supported in 1 tx for the withdrawal\n uint256 internal maxVestingWithdrawIterations;\n\n constructor() internal {\n //abstract\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingAdminModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Admin Module.\n * @notice Implements administrative functionality pause, freeze and setting addresses and parameters\n * related to staking\n * */\ncontract StakingAdminModule is IFunctionsList, StakingShared {\n using Address for address payable;\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(_admin != address(0), \"cannot add the zero address as an admin\");\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(admins[_admin], \"address is not an admin\");\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external onlyOwner whenNotFrozen {\n require(_pauser != address(0), \"cannot add the zero address as a pauser\");\n pausers[_pauser] = true;\n emit PauserAddedOrRemoved(_pauser, true);\n }\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external onlyOwner whenNotFrozen {\n require(pausers[_pauser], \"address is not a pauser\");\n delete pausers[_pauser];\n emit PauserAddedOrRemoved(_pauser, false);\n }\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) public onlyPauserOrOwner whenNotFrozen {\n paused = _pause;\n emit StakingPaused(_pause);\n }\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external onlyPauserOrOwner {\n require(_freeze != frozen, \"Cannot freeze/unfreeze to the same state\"); // WS25\n if (_freeze) pauseUnpause(true);\n frozen = _freeze;\n emit StakingFrozen(_freeze);\n }\n\n /**\n * @notice Allow the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external onlyOwner whenNotFrozen {\n require(_feeSharing != address(0), \"FeeSharing address shouldn't be 0\"); // S17\n feeSharing = IFeeSharingCollector(_feeSharing);\n }\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external onlyOwner whenNotFrozen {\n require(\n MIN_WEIGHT_SCALING <= _weightScaling && _weightScaling <= MAX_WEIGHT_SCALING,\n \"scaling doesn't belong to range [1, 9]\" // S18\n );\n weightScaling = _weightScaling;\n }\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external onlyOwner whenNotFrozen {\n require(_newStakingContract != address(0), \"can't reset the new staking contract to 0\"); // S16\n newStakingContract = _newStakingContract;\n }\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external whenNotFrozen {\n require(newStakingContract != address(0), \"there is no new staking contract set\"); // S19\n revert(\"not implemented\");\n /// @dev implementation:\n /// @dev Iterate over all possible lock dates from now until now + MAX_DURATION.\n /// @dev Read the stake & delegate of the msg.sender\n /// @dev If stake > 0, stake it at the new contract until the lock date with the current delegate.\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](13);\n functionsList[0] = this.addAdmin.selector;\n functionsList[1] = this.removeAdmin.selector;\n functionsList[2] = this.addPauser.selector;\n functionsList[3] = this.removePauser.selector;\n functionsList[4] = this.pauseUnpause.selector;\n functionsList[5] = this.freezeUnfreeze.selector;\n functionsList[6] = this.setFeeSharing.selector;\n functionsList[7] = this.setWeightScaling.selector;\n functionsList[8] = this.setNewStakingContract.selector;\n functionsList[9] = this.owner.selector;\n functionsList[10] = this.isOwner.selector;\n functionsList[11] = this.transferOwnership.selector;\n functionsList[12] = this.migrateToNewStakingContract.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingGovernanceModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/IVesting.sol\";\n\n/**\n * @title Staking Governance Module contract\n * @notice Implements voting power and delegation functionality\n * */\ncontract StakingGovernanceModule is IFunctionsList, StakingShared, CheckpointsShared {\n using Address for address payable;\n\n /************* TOTAL VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n /// @dev Start the computation with the exact or previous unlocking date (voting weight remians the same until the next break point).\n uint256 start = _timestampToLockDate(time);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n totalVotingPower = add96(\n totalVotingPower,\n _totalPowerByDate(i, start, blockNumber),\n \"arrays mismatch\"\n ); // WS06\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorTotalStakesForDate(date, blockNumber);\n /// @dev weight is multiplied by some factor to allow decimals.\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS07\n }\n\n /****************************** DELEGATED VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96) {\n return getPriorVotes(account, block.number - 1, block.timestamp);\n }\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96 votes) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n votes = add96(\n votes,\n _totalPowerByDateForDelegatee(account, i, start, blockNumber),\n \"overflow - total VP\"\n ); // WS09\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDateForDelegatee(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS10\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n date = _adjustDateForOrigin(date);\n return _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined yet\"); // WS11\n\n uint32 nCheckpoints = numDelegateStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (delegateStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return delegateStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (delegateStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = delegateStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return delegateStakingCheckpoints[account][date][lower].stake;\n }\n\n /**************** SHARED FUNCTIONS *********************/\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for. Adjusted to the next valid lock date, as necessary\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n public\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorTotalStakesForDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function _getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS08\n\n uint32 nCheckpoints = numTotalStakingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (totalStakingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return totalStakingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n // Next check implicit zero balance\n if (totalStakingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Checkpoint memory cp = totalStakingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return totalStakingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Set new delegatee. Move from user's current delegate to a new\n * delegatee the stake balance.\n * @param delegator The user address to move stake balance from its current delegatee.\n * @param delegatee The new delegatee. The address to move stake balance to.\n * @param lockedTS The lock date.\n * @dev Reverts if delegator balance or delegatee is not valid, unless the sender is a vesting contract.\n * */\n function _delegate(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n address currentDelegate = delegates[delegator][lockedTS];\n uint96 delegatorBalance = _currentBalance(delegator, lockedTS);\n\n // vesting contracts will in multiple cases try to delegate a zero balance\n // or to the existing delegatee\n if (_isVestingContract(msg.sender)) {\n if (delegatorBalance == 0 || currentDelegate == delegatee) {\n return;\n }\n } else {\n require(delegatorBalance > 0, \"no stake to delegate\");\n require(currentDelegate != delegatee, \"cannot delegate to the existing delegatee\");\n }\n\n delegates[delegator][lockedTS] = delegatee;\n\n emit DelegateChanged(delegator, lockedTS, currentDelegate, delegatee);\n\n _moveDelegates(currentDelegate, delegatee, delegatorBalance, lockedTS);\n }\n\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n function _delegateNext(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n if (_isVestingContract(msg.sender)) {\n uint256 nextLock = lockedTS.add(TWO_WEEKS);\n address currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n\n // @dev workaround for the issue with a delegation of the latest stake\n uint256 endDate = IVesting(msg.sender).endDate();\n nextLock = lockedTS.add(FOUR_WEEKS);\n if (nextLock == endDate) {\n currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n }\n }\n }\n\n /**\n * @notice Move an amount of delegate stake from a source address to a\n * destination address.\n * @param srcRep The address to get the staked amount from.\n * @param dstRep The address to send the staked amount to.\n * @param amount The staked amount to move.\n * @param lockedTS The lock date.\n * */\n function _moveDelegates(\n address srcRep,\n address dstRep,\n uint96 amount,\n uint256 lockedTS\n ) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) _decreaseDelegateStake(srcRep, lockedTS, amount);\n\n if (dstRep != address(0)) _increaseDelegateStake(dstRep, lockedTS, amount);\n }\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function _getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external whenNotPaused {\n require(delegatee != address(0), \"cannot delegate to the zero address\");\n _notSameBlockAsStakingCheckpoint(lockDate, msg.sender);\n\n _delegate(msg.sender, delegatee, lockDate);\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n _delegateNext(msg.sender, delegatee, lockDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](6);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStakeModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking contract staking functionality module\n * @notice Implements staking functionality\n **/\ncontract StakingStakeModule is IFunctionsList, StakingShared, CheckpointsShared, ApprovalReceiver {\n using SafeMath for uint256;\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stake(msg.sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external onlyThisContract whenNotPaused whenNotFrozen {\n _stake(sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * */\n function _stake(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted\n ) internal {\n _stakeOptionalTokenTransfer(\n sender,\n amount,\n until,\n stakeFor,\n delegatee,\n timeAdjusted,\n true // transfer SOV\n );\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * @param transferToken Should transfer SOV - false for multiple iterations like in stakeBySchedule\n * */\n function _stakeOptionalTokenTransfer(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted,\n bool transferToken\n ) internal {\n require(amount > 0, \"amount needs to be bigger than 0\"); // S01\n\n if (!timeAdjusted) {\n until = _timestampToLockDate(until);\n }\n require(\n until > block.timestamp,\n \"Staking::_timestampToLockDate: staking period too short\"\n ); // S02\n\n /// @dev Stake for the sender if not specified otherwise.\n if (stakeFor == address(0)) {\n stakeFor = sender;\n }\n // must wait a block before staking again for that same deadline\n _notSameBlockAsStakingCheckpoint(until, stakeFor);\n\n /// @dev Delegate for stakeFor if not specified otherwise.\n if (delegatee == address(0)) {\n delegatee = stakeFor;\n }\n\n /// @dev Do not stake longer than the max duration.\n if (!timeAdjusted) {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n }\n\n uint96 previousBalance = _currentBalance(stakeFor, until);\n\n /// @dev Increase stake.\n _increaseStake(sender, amount, stakeFor, until, transferToken);\n\n // @dev Previous version wasn't working properly for the following case:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n address previousDelegatee = delegates[stakeFor][until];\n\n if (previousDelegatee != delegatee) {\n // @dev only the user that stakes for himself is allowed to delegate VP to another address\n // which works with vesting stakes and prevents vulnerability of delegating VP to an arbitrary address from\n // any address\n\n if (delegatee != stakeFor) {\n require(\n stakeFor == sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n } else if (sender != stakeFor && previousDelegatee != address(0)) {\n require(stakeFor == sender, \"Only sender is allowed to change delegatee\");\n }\n\n /// @dev Update delegatee.\n delegates[stakeFor][until] = delegatee;\n\n /// @dev Decrease stake on previous balance for previous delegatee.\n _decreaseDelegateStake(previousDelegatee, until, previousBalance);\n\n /// @dev Add previousBalance to amount.\n amount = add96(previousBalance, amount, \"add amounts failed\");\n }\n\n /// @dev Increase stake.\n _increaseDelegateStake(delegatee, until, amount);\n emit DelegateChanged(stakeFor, until, previousDelegatee, delegatee);\n }\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until)\n external\n whenNotPaused\n whenNotFrozen\n {\n previousLock = _timestampToLockDate(previousLock);\n until = _timestampToLockDate(until);\n\n _notSameBlockAsStakingCheckpoint(previousLock, msg.sender);\n\n /// @dev Do not exceed the max duration, no overflow possible.\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n\n require(previousLock < until, \"must increase staking duration\"); // S04\n\n /// @dev Update checkpoints.\n /// @dev TODO James: Can reading stake at block.number -1 cause trouble with multiple tx in a block?\n uint96 amount = _getPriorUserStakeByDate(msg.sender, previousLock, block.number - 1);\n require(amount > 0, \"no stakes till the prev lock date\"); // S05\n _decreaseUserStake(msg.sender, previousLock, amount);\n _increaseUserStake(msg.sender, until, amount);\n\n if (_isVestingContract(msg.sender)) {\n _decreaseVestingStake(previousLock, amount);\n _increaseVestingStake(until, amount);\n }\n\n _decreaseDailyStake(previousLock, amount);\n _increaseDailyStake(until, amount);\n\n /// @dev Delegate might change: if there is already a delegate set for the until date, it will remain the delegate for this position\n address delegateFrom = delegates[msg.sender][previousLock];\n delegates[msg.sender][previousLock] = address(0); //the previousLock delegates nullifying before reading that form `until` guards in case delegateTo == until\n address delegateTo = delegates[msg.sender][until];\n if (delegateTo == address(0)) {\n delegateTo = delegateFrom;\n delegates[msg.sender][until] = delegateFrom;\n }\n _decreaseDelegateStake(delegateFrom, previousLock, amount);\n _increaseDelegateStake(delegateTo, until, amount);\n\n emit ExtendedStakingDuration(msg.sender, previousLock, until, amount);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param until The date until which the tokens will be staked.\n * @param transferToken if false - token transfer should be handled separately\n * */\n function _increaseStake(\n address sender,\n uint96 amount,\n address stakeFor,\n uint256 until,\n bool transferToken\n ) internal {\n /// @dev Retrieve the SOV tokens.\n if (transferToken)\n require(\n SOVToken.transferFrom(sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // IS10\n\n /// @dev Increase staked balance.\n uint96 balance = _currentBalance(stakeFor, until);\n balance = add96(balance, amount, \"increaseStake: overflow\"); // IS20\n\n /// @dev Update checkpoints.\n _increaseDailyStake(until, amount);\n _increaseUserStake(stakeFor, until, amount);\n\n if (_isVestingContract(stakeFor)) _increaseVestingStake(until, amount);\n\n emit TokensStaked(stakeFor, amount, until, balance);\n }\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function _stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) internal {\n require(amount > 0, \"Invalid amount\");\n require(duration <= MAX_DURATION, \"Invalid duration\");\n require(intervalLength > 0, \"Invalid interval length\");\n require(intervalLength % TWO_WEEKS == 0, \"Invalid interval length\");\n if (delegatee != stakeFor && delegatee != address(0)) {\n require(\n stakeFor == msg.sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n }\n /**\n * @dev Stake them until lock dates according to the vesting schedule.\n * Note: because staking is only possible in periods of 2 weeks,\n * the total duration might end up a bit shorter than specified\n * depending on the date of staking.\n * */\n uint256 start = _timestampToLockDate(block.timestamp + cliff);\n uint256 end = _timestampToLockDate(block.timestamp + duration);\n require(start <= end, \"Invalid schedule\");\n uint256 numIntervals;\n if (start < end) {\n numIntervals = (end - start) / intervalLength + 1;\n } else {\n numIntervals = 1;\n }\n uint256 stakedPerInterval = amount / numIntervals;\n\n /// @dev transferring total SOV amount before staking\n require(\n SOVToken.transferFrom(msg.sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // SS10\n /// @dev stakedPerInterval might lose some dust on rounding. Add it to the first staking date.\n if (numIntervals >= 1) {\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(amount - stakedPerInterval * (numIntervals - 1)),\n start,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n /// @dev Stake the rest in 4 week intervals.\n for (uint256 i = start + intervalLength; i <= end; i += intervalLength) {\n /// @dev Stakes for itself, delegates to the owner.\n _notSameBlockAsStakingCheckpoint(i, stakeFor); // must wait a block before staking again for that same deadline\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(stakedPerInterval),\n i,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n }\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance) {\n for (uint256 i = kickoffTS; i <= block.timestamp + MAX_DURATION; i += TWO_WEEKS) {\n balance = add96(balance, _currentBalance(account, i), \"Staking::balanceOf: overflow\"); // S12\n }\n }\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96) {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n return nCheckpoints > 0 ? totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake : 0;\n }\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes)\n {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n\n /// @dev Calculate stakes.\n uint256 count = 0;\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n if (_currentBalance(account, i) > 0) {\n count++;\n }\n }\n dates = new uint256[](count);\n stakes = new uint96[](count);\n\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n uint256 j = 0;\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n uint96 balance = _currentBalance(account, i);\n if (balance > 0) {\n dates[j] = i;\n stakes[j] = balance;\n j++;\n }\n }\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOVToken);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeWithApproval.selector;\n return selectors;\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256) {\n return _timestampToLockDate(timestamp);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](10);\n functionsList[0] = this.stake.selector;\n functionsList[1] = this.stakeWithApproval.selector;\n functionsList[2] = this.extendStakingDuration.selector;\n functionsList[3] = this.stakesBySchedule.selector;\n functionsList[4] = this.stakeBySchedule.selector;\n functionsList[5] = this.balanceOf.selector;\n functionsList[6] = this.getCurrentStakedUntil.selector;\n functionsList[7] = this.getStakes.selector;\n functionsList[8] = this.timestampToLockDate.selector;\n functionsList[9] = this.receiveApproval.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStorageModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/StakingStorageShared.sol\";\n\n/**\n * @title Staking Storage Module\n * @notice Provides getters for public storage variables\n **/\ncontract StakingStorageModule is IFunctionsList, StakingStorageShared {\n function getStorageDefaultWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256) {\n return MAX_DURATION;\n }\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n function getStorageMaxVotingWeight() external pure returns (uint256) {\n return uint256(MAX_VOTING_WEIGHT);\n }\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n function getStorageWeightFactor() external pure returns (uint256) {\n return uint256(WEIGHT_FACTOR);\n }\n\n /// @notice Default weight scaling.\n function getStorageDefaulWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling)\n {\n return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING));\n }\n\n /// @notice The EIP-712 typehash for the contract's domain.\n function getStorageDomainTypehash() external pure returns (uint256) {\n return uint256(DOMAIN_TYPEHASH);\n }\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n function getStorageDelegationTypehash() external pure returns (uint256) {\n return uint256(DELEGATION_TYPEHASH);\n }\n\n function getStorageName() external view returns (string memory) {\n return name;\n }\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() public view returns (uint256) {\n return maxVestingWithdrawIterations;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](32);\n functionsList[0] = this.getStorageMaxDurationToStakeTokens.selector;\n functionsList[1] = this.getStorageMaxVotingWeight.selector;\n functionsList[2] = this.getStorageWeightFactor.selector;\n functionsList[3] = this.getStorageDefaulWeightScaling.selector;\n functionsList[4] = this.getStorageRangeForWeightScaling.selector;\n functionsList[5] = this.getStorageDomainTypehash.selector;\n functionsList[6] = this.getStorageDelegationTypehash.selector;\n functionsList[7] = this.getStorageName.selector;\n functionsList[8] = this.kickoffTS.selector;\n functionsList[9] = this.SOVToken.selector;\n functionsList[10] = this.delegates.selector;\n functionsList[11] = this.allUnlocked.selector;\n functionsList[12] = this.newStakingContract.selector;\n functionsList[13] = this.totalStakingCheckpoints.selector;\n functionsList[14] = this.numTotalStakingCheckpoints.selector;\n functionsList[15] = this.delegateStakingCheckpoints.selector;\n functionsList[16] = this.numDelegateStakingCheckpoints.selector;\n functionsList[17] = this.userStakingCheckpoints.selector;\n functionsList[18] = this.numUserStakingCheckpoints.selector;\n functionsList[19] = this.nonces.selector;\n functionsList[20] = this.feeSharing.selector;\n functionsList[21] = this.weightScaling.selector;\n functionsList[22] = this.vestingWhitelist.selector;\n functionsList[23] = this.admins.selector;\n functionsList[24] = this.vestingCodeHashes.selector;\n functionsList[25] = this.vestingCheckpoints.selector;\n functionsList[26] = this.numVestingCheckpoints.selector;\n functionsList[27] = this.vestingRegistryLogic.selector;\n functionsList[28] = this.pausers.selector;\n functionsList[29] = this.paused.selector;\n functionsList[30] = this.frozen.selector;\n functionsList[31] = this.getMaxVestingWithdrawIterations.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingVestingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Vesting Module contract\n * @notice Implements interaction with Vesting functionality: vesting registry, vesting staking\n * */\ncontract StakingVestingModule is IFunctionsList, StakingShared {\n event ContractCodeHashAdded(bytes32 hash);\n event ContractCodeHashRemoved(bytes32 hash);\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external onlyOwner whenNotFrozen {\n vestingRegistryLogic = IVestingRegistry(_vestingRegistryProxy);\n }\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(lockedDates.length == values.length, \"arrays mismatch\"); // WS05\n\n uint256 length = lockedDates.length;\n for (uint256 i = 0; i < length; i++) {\n _setVestingStake(lockedDates[i], values[i]);\n }\n }\n\n /**\n * @notice Sets the users' vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to be set.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function _setVestingStake(uint256 lockedTS, uint96 value) internal {\n require(\n lockedTS > kickoffTS,\n \"Invalid lock dates: must greater than contract creation timestamp\"\n );\n\n // locked date must be multiples of 14 days / TWO_WEEKS\n require(\n (lockedTS - kickoffTS) % TWO_WEEKS == 0,\n \"Invalid lock dates: not multiples of 14 days\"\n );\n\n // locked date must not exceed the MAX_DURATION\n if (lockedTS > block.timestamp) {\n require(\n lockedTS - block.timestamp <= MAX_DURATION,\n \"Invalid lock dates: exceed max duration\"\n );\n }\n\n // the value must not exceed the total staked at the given locked date\n uint32 nStakeCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 totalStaked = totalStakingCheckpoints[lockedTS][nStakeCheckpoints - 1].stake;\n require(\n value <= totalStaked,\n \"Invalid stake amount: greater than the total staked for given date\"\n );\n\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint32 blockNumber;\n\n Checkpoint memory recentCP = vestingCheckpoints[lockedTS][nCheckpoints - 1];\n if (nCheckpoints == 0) blockNumber = uint32(block.number) - 1;\n else blockNumber = recentCP.fromBlock + 1;\n\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, value);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n\n emit VestingStakeSet(lockedTS, value);\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n uint96 priorStake = _getPriorUserStakeByDate(account, date, blockNumber);\n // @dev we need to modify function in order to workaround issue with Vesting.withdrawTokens:\n //\t\treturn 1 instead of 0 if message sender is a contract.\n if (priorStake == 0 && _isVestingContract(msg.sender)) {\n priorStake = 1;\n }\n return priorStake;\n }\n\n /*************************** Weighted Vesting Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes)\n {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedVestingStakeByDate(i, start, blockNumber);\n if (weightedStake > 0) {\n votes = add96(votes, weightedStake, \"overflow on total weight\"); // WS15\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n power = _weightedVestingStakeByDate(date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorVestingStakeByDate(date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul oveflow\") / WEIGHT_FACTOR; // WS16\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorVestingStakeByDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS17\n\n uint32 nCheckpoints = numVestingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (vestingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return vestingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (vestingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = vestingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return vestingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n require(vestingCodeHashes[codeHash], \"not a registered vesting code hash\");\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool) {\n bool isVesting;\n bytes32 codeHash = _getCodeHash(stakerAddress);\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](9);\n functionsList[0] = this.setVestingRegistry.selector;\n functionsList[1] = this.setVestingStakes.selector;\n functionsList[2] = this.getPriorUserStakeByDate.selector;\n functionsList[3] = this.getPriorVestingWeightedStake.selector;\n functionsList[4] = this.getPriorVestingStakeByDate.selector;\n functionsList[5] = this.addContractCodeHash.selector;\n functionsList[6] = this.removeContractCodeHash.selector;\n functionsList[7] = this.isVestingContract.selector;\n functionsList[8] = this.weightedVestingStakeByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingWithdrawModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/ITeamVesting.sol\";\nimport \"../../Vesting/IVesting.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking withdrawal functionality module\n **/\ncontract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShared {\n using SafeMath for uint256;\n\n event MaxVestingWithdrawIterationsUpdated(uint256 oldMaxIterations, uint256 newMaxIterations);\n\n /// @dev Struct for direct withdraw function -- to avoid stack too deep issue\n struct VestingConfig {\n address vestingAddress;\n uint256 startDate;\n uint256 endDate;\n uint256 cliff;\n uint256 duration;\n address tokenOwner;\n }\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev If until is not a valid lock date, the next lock date after until is used.\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n // adjust until here to avoid adjusting multiple times, and to make sure an adjusted date is passed to\n // _notSameBlockAsStakingCheckpoint\n until = _adjustDateForOrigin(until);\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, false);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe need to check block.timestamp here\n _withdrawNext(until, receiver, false);\n }\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external onlyAuthorized whenNotFrozen {\n /// require the caller only for team vesting contract.\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n _cancelTeamVesting(vesting, receiver, startFrom);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param _vesting The vesting address.\n * @param _receiver The receiving address.\n * @param _startFrom The start value for the iterations.\n * or just unlocked tokens (false).\n * */\n function _cancelTeamVesting(\n address _vesting,\n address _receiver,\n uint256 _startFrom\n ) private {\n require(_receiver != address(0), \"receiver address invalid\");\n\n ITeamVesting teamVesting = ITeamVesting(_vesting);\n\n VestingConfig memory vestingConfig =\n VestingConfig(\n _vesting,\n teamVesting.startDate(),\n teamVesting.endDate(),\n teamVesting.cliff(),\n teamVesting.duration(),\n teamVesting.tokenOwner()\n );\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them, as long as the itrations less than maxVestingWithdrawIterations.\n uint256 end = vestingConfig.endDate;\n\n uint256 defaultStart = vestingConfig.startDate + vestingConfig.cliff;\n\n _startFrom = _startFrom >= defaultStart ? _startFrom : defaultStart;\n\n /// @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 totalIterationValue =\n (_startFrom + (TWO_WEEKS * (maxVestingWithdrawIterations - 1)));\n uint256 adjustedEnd = end < totalIterationValue ? end : totalIterationValue;\n\n /// @dev Withdraw for each unlocked position.\n for (uint256 i = _startFrom; i <= adjustedEnd; i += TWO_WEEKS) {\n /// @dev Read amount to withdraw.\n uint96 tempStake = _getPriorUserStakeByDate(_vesting, i, block.number - 1);\n\n if (tempStake > 0) {\n /// @dev do governance direct withdraw for team vesting\n _withdrawFromTeamVesting(tempStake, i, _receiver, vestingConfig);\n }\n }\n\n if (adjustedEnd < end) {\n emit TeamVestingPartiallyCancelled(msg.sender, _receiver, adjustedEnd);\n } else {\n emit TeamVestingCancelled(msg.sender, _receiver);\n }\n }\n\n /**\n * @notice Send user' staked tokens to a receiver taking into account punishments.\n * Sovryn encourages long-term commitment and thinking. When/if you unstake before\n * the end of the staking period, a percentage of the original staking amount will\n * be slashed. This amount is also added to the reward pool and is distributed\n * between all other stakers.\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * Needs to be adjusted to the next valid lock date before calling this function.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdraw(\n uint96 amount,\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n // @dev it's very unlikely some one will have 1/10**18 SOV staked in Vesting contract\n //\t\tthis check is a part of workaround for Vesting.withdrawTokens issue\n if (amount == 1 && _isVestingContract(msg.sender)) {\n return;\n }\n _validateWithdrawParams(msg.sender, amount, until);\n\n /// @dev Determine the receiver.\n if (receiver == address(0)) receiver = msg.sender;\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(msg.sender, until, amount);\n if (_isVestingContract(msg.sender)) _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[msg.sender][until], until, amount);\n\n /// @dev Early unstaking should be punished.\n if (block.timestamp < until && !allUnlocked && !isGovernance) {\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n amount -= punishedAmount;\n\n /// @dev punishedAmount can be 0 if block.timestamp are very close to 'until'\n if (punishedAmount > 0) {\n require(address(feeSharing) != address(0), \"FeeSharing address wasn't set\"); // S08\n /// @dev Move punished amount to fee sharing.\n /// @dev Approve transfer here and let feeSharing do transfer and write checkpoint.\n SOVToken.approve(address(feeSharing), punishedAmount);\n feeSharing.transferTokens(address(SOVToken), punishedAmount);\n }\n }\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(msg.sender, amount, until, receiver, isGovernance);\n }\n\n /**\n * @notice Send user' staked tokens to a receiver.\n * This function is dedicated only for direct withdrawal from staking contract.\n * Currently only being used by cancelTeamVesting()\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender.\n * @param vestingConfig The vesting config.\n * @dev VestingConfig struct intended to avoid stack too deep issue, and it contains this properties:\n address vestingAddress; // vesting contract address\n uint256 startDate; //start date of vesting\n uint256 endDate; // end date of vesting\n uint256 cliff; // after this time period the tokens begin to unlock\n uint256 duration; // after this period all the tokens will be unlocked\n address tokenOwner; // owner of the vested tokens\n * */\n function _withdrawFromTeamVesting(\n uint96 amount,\n uint256 until,\n address receiver,\n VestingConfig memory vestingConfig\n ) internal {\n address vesting = vestingConfig.vestingAddress;\n\n until = _timestampToLockDate(until);\n _validateWithdrawParams(vesting, amount, until);\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(vesting, until, amount);\n\n _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[vesting][until], until, amount);\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(vesting, amount, until, receiver, true);\n }\n\n // @dev withdraws tokens for lock date 2 weeks later than given lock date\n function _withdrawNext(\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n if (_isVestingContract(msg.sender)) {\n // nextLock needs to be adjusted to the next valid lock date to make sure we don't accidentally\n // withdraw stakes that are in the future and would get slashed (if until is not\n // a valid lock date). but until is already handled in the withdraw function\n uint256 nextLock = until.add(TWO_WEEKS);\n if (isGovernance || block.timestamp >= nextLock) {\n uint96 stakes = _getPriorUserStakeByDate(msg.sender, nextLock, block.number - 1);\n if (stakes > 0) {\n _withdraw(stakes, nextLock, receiver, isGovernance);\n }\n }\n }\n }\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked. Adjusted to the next valid lock date, if necessary.\n * @return Amount to withraw and penalty amount\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96)\n {\n until = _adjustDateForOrigin(until);\n _validateWithdrawParams(msg.sender, amount, until);\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n return (amount - punishedAmount, punishedAmount);\n }\n\n /**\n * @notice Get punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _getPunishedAmount(uint96 amount, uint256 until) internal view returns (uint96) {\n uint256 date = _timestampToLockDate(block.timestamp);\n uint96 weight = _computeWeightByDate(until, date); /// @dev (10 - 1) * WEIGHT_FACTOR\n weight = weight * weightScaling;\n return (amount * weight) / WEIGHT_FACTOR / 100;\n }\n\n /**\n * @notice Validate withdraw parameters.\n * @param account Address to be validated.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _validateWithdrawParams(\n address account,\n uint96 amount,\n uint256 until\n ) internal view {\n require(amount > 0, \"Amount of tokens to withdraw must be > 0\"); // S10\n uint96 balance = _getPriorUserStakeByDate(account, until, block.number - 1);\n require(amount <= balance, \"Staking::withdraw: not enough balance\"); // S11\n }\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external onlyOwner whenNotFrozen {\n allUnlocked = true;\n emit TokensUnlocked(SOVToken.balanceOf(address(this)));\n }\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param newMaxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 newMaxIterations)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(newMaxIterations > 0, \"Invalid max iterations\");\n emit MaxVestingWithdrawIterationsUpdated(maxVestingWithdrawIterations, newMaxIterations);\n maxVestingWithdrawIterations = newMaxIterations;\n }\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * @dev This function is dedicated only to support backward compatibility for sovryn ecosystem that has been implementing this staking contract.\n * @dev Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/4bbfe5bd0311ca71e4ef0e3af810d3791d8e4061/contracts/governance/Staking/modules/StakingWithdrawModule.sol#L78\n * */\n function governanceWithdrawVesting(address vesting, address receiver)\n public\n onlyAuthorized\n whenNotFrozen\n {\n vestingWhitelist[vesting] = true;\n ITeamVesting(vesting).governanceWithdrawTokens(receiver);\n vestingWhitelist[vesting] = false;\n\n emit VestingTokensWithdrawn(vesting, receiver);\n }\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n require(vestingWhitelist[msg.sender], \"unauthorized\"); // S07\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, true);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe don't need to check block.timestamp here\n _withdrawNext(until, receiver, true);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.withdraw.selector;\n functionsList[1] = this.cancelTeamVesting.selector;\n functionsList[2] = this.getWithdrawAmounts.selector;\n functionsList[3] = this.unlockAllTokens.selector;\n functionsList[4] = this.setMaxVestingWithdrawIterations.selector;\n functionsList[5] = this.governanceWithdraw.selector;\n functionsList[6] = this.governanceWithdrawVesting.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/WeightedStakingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Weighted Staking module contract.\n * @notice Implements getters for weighted staking functionality\n * */\ncontract WeightedStakingModule is IFunctionsList, StakingShared, CheckpointsShared {\n /*************************** User Weighted Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The start date/timestamp from which to calculate the weighted stake.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake) {\n return _getPriorWeightedStake(account, blockNumber, date);\n }\n\n function _getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) internal view returns (uint96 priorWeightedStake) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedStakeByDate(account, i, start, blockNumber);\n if (weightedStake > 0) {\n priorWeightedStake = add96(\n priorWeightedStake,\n weightedStake,\n \"overflow on total weight calc\"\n ); // WS12\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n return _weightedStakeByDate(account, date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function _weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorUserStakeByDate(account, date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS13\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight)\n {\n return _computeWeightByDate(date, startDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](3);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/SafeMath96.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n/**\n * @title SafeMath96 contract.\n * @notice Improved Solidity's arithmetic operations with added overflow checks.\n * @dev SafeMath96 uses uint96, unsigned integers of 96 bits length, so every\n * integer from 0 to 2^96-1 can be operated.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * SafeMath restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this contract instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n * */\ncontract SafeMath96 {\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function safe64(uint256 n, string memory errorMessage) internal pure returns (uint64) {\n require(n < 2**64, errorMessage);\n return uint64(n);\n }\n\n function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) {\n require(n < 2**96, errorMessage);\n return uint96(n);\n }\n\n /**\n * @notice Adds two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `+` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe addition a+b.\n * */\n function add96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n uint96 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n /**\n * @notice Substracts two unsigned integers, reverting on underflow.\n * @dev Counterpart to Solidity's `-` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on underflow.\n * @return The safe substraction a-b.\n * */\n function sub96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n require(b <= a, errorMessage);\n return a - b;\n }\n\n /**\n * @notice Multiplies two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `*` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe product a*b.\n * */\n function mul96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n if (a == 0) {\n return 0;\n }\n\n uint96 c = a * b;\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @notice Divides two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `/` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe division a/b.\n * */\n function div96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint96 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n}\n" + }, + "contracts/governance/Staking/StakingProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./modules/shared/StakingStorageShared.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Staking Proxy contract.\n * @dev Staking contract should be upgradable, use UpgradableProxy.\n * StakingStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingProxy is StakingStorageShared, UpgradableProxy {\n /**\n * @notice Construct a new staking contract.\n * @param SOV The address of the SOV token address.\n */\n constructor(address SOV) public {\n SOVToken = IERC20(SOV);\n kickoffTS = block.timestamp;\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewards.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Staking Rewards Contract.\n * @notice This is a trial incentive program.\n * In this, the SOV emitted and becoming liquid from the Adoption Fund could be utilized\n * to offset the higher APY's offered for Liquidity Mining events.\n * Vesting contract stakes are excluded from these rewards.\n * Only wallets which have staked previously liquid SOV are eligible for these rewards.\n * Tokenholders who stake their SOV receive staking rewards, a pro-rata share\n * of the revenue that the platform generates from various transaction fees\n * plus revenues from stakers who have a portion of their SOV slashed for\n * early unstaking.\n * */\ncontract StakingRewards is StakingRewardsStorage {\n using SafeMath for uint256;\n\n /// @notice Emitted when SOV is withdrawn\n /// @param receiver The address which recieves the SOV\n /// @param amount The amount withdrawn from the Smart Contract\n event RewardWithdrawn(address indexed receiver, uint256 amount);\n\n /**\n * @notice Replacement of constructor by initialize function for Upgradable Contracts\n * This function will be called only once by the owner.\n * @param _SOV SOV token address\n * @param _staking StakingProxy address should be passed\n * */\n function initialize(address _SOV, IStaking _staking) external onlyOwner {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n SOV = IERC20(_SOV);\n staking = _staking;\n startTime = staking.timestampToLockDate(block.timestamp);\n setMaxDuration(15 * TWO_WEEKS);\n deploymentBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Stops the current rewards program.\n * @dev All stakes existing on the contract at the point in time of\n * cancellation continue accruing rewards until the end of the staking\n * period being rewarded\n * */\n function stop() external onlyOwner {\n require(stopBlock == 0, \"Already stopped\");\n stopBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Collect rewards\n * @dev User calls this function to collect SOV staking rewards as per the SIP-0024 program.\n * The weighted stake is calculated using getPriorWeightedStake. Block number sent to the functon\n * must be a finalised block, hence we deduct 1 from the current block. User is only allowed to withdraw\n * after intervals of 14 days.\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * The issue is that we can only run for a max duration and if someone stakes for the\n * first time after the max duration is over, the reward will always return 0. Thus, we need to restart\n * from the duration that elapsed without generating rewards.\n * */\n function collectReward(uint256 restartTime) external {\n (uint256 withdrawalTime, uint256 amount) = getStakerCurrentReward(true, restartTime);\n require(withdrawalTime > 0 && amount > 0, \"no valid reward\");\n withdrawals[msg.sender] = withdrawalTime;\n _payReward(msg.sender, amount);\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred.\n */\n function withdrawTokensByOwner(address _receiverAddress) external onlyOwner {\n uint256 value = SOV.balanceOf(address(this));\n _transferSOV(_receiverAddress, value);\n }\n\n /**\n * @notice Changes average block time - based on blockchain\n * @dev If average block time significantly changes, we can update it here and use for block number calculation\n */\n function setAverageBlockTime(uint256 _averageBlockTime) external onlyOwner {\n averageBlockTime = _averageBlockTime;\n }\n\n /**\n * @notice This function computes the last staking checkpoint and calculates the corresponding\n * block number using the average block time which is then added to the mapping `checkpointBlockDetails`.\n */\n function setBlock() external {\n uint256 lastCheckpointTime = staking.timestampToLockDate(block.timestamp);\n _setBlock(lastCheckpointTime);\n }\n\n /**\n * @notice This function computes the block number using the average block time for a given historical\n * checkpoint which is added to the mapping `checkpointBlockDetails`.\n * @param _time Exact staking checkpoint time\n */\n function setHistoricalBlock(uint256 _time) external {\n _setBlock(_time);\n }\n\n /**\n * @notice Sets the max duration\n * @dev Rewards can be collected for a maximum duration at a time. This\n * is to avoid Block Gas Limit failures. Setting it zero would mean that it will loop\n * through the entire duration since the start of rewards program.\n * It should ideally be set to a value, for which the rewards can be easily processed.\n * @param _duration Max duration for which rewards can be collected at a go (in seconds)\n * */\n function setMaxDuration(uint256 _duration) public onlyOwner {\n maxDuration = _duration;\n }\n\n /**\n * @notice Internal function to calculate weighted stake\n * @dev If the rewards program is stopped, the user will still continue to\n * earn till the end of staking period based on the stop block.\n * @param _staker Staker address\n * @param _block Last finalised block\n * @param _date The date to compute prior weighted stakes\n * @return The weighted stake\n * */\n function _computeRewardForDate(\n address _staker,\n uint256 _block,\n uint256 _date\n ) internal view returns (uint256 weightedStake) {\n weightedStake = staking.getPriorWeightedStake(_staker, _block, _date);\n if (stopBlock > 0 && stopBlock < _block) {\n uint256 previousWeightedStake =\n staking.getPriorWeightedStake(_staker, stopBlock, _date);\n if (previousWeightedStake < weightedStake) {\n weightedStake = previousWeightedStake;\n }\n }\n }\n\n /**\n * @notice Internal function to pay rewards\n * @dev Base rate is annual, but we pay interest for 14 days,\n * which is 1/26 of one staking year (1092 days)\n * @param _staker User address\n * @param amount the reward amount\n * */\n function _payReward(address _staker, uint256 amount) internal {\n require(SOV.balanceOf(address(this)) >= amount, \"not enough funds to reward user\");\n claimedBalances[_staker] = claimedBalances[_staker].add(amount);\n _transferSOV(_staker, amount);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit RewardWithdrawn(_receiver, _amount);\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Internal function to calculate and set block\n * */\n function _setBlock(uint256 _checkpointTime) internal {\n uint256 currentTS = block.timestamp;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n require(checkpointBlockDetails[_checkpointTime] == 0, \"block number already set\");\n uint256 checkpointBlock =\n lastFinalisedBlock.sub(((currentTS.sub(_checkpointTime)).div(averageBlockTime)));\n checkpointBlockDetails[_checkpointTime] = checkpointBlock;\n }\n\n /**\n * @notice Get staker's current accumulated reward\n * @dev The collectReward() function internally calls this function to calculate reward amount\n * @param considerMaxDuration True: Runs for the maximum duration - used in tx not to run out of gas\n * False - to query total rewards\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * @return The timestamp of last withdrawal\n * @return The accumulated reward\n */\n function getStakerCurrentReward(bool considerMaxDuration, uint256 restartTime)\n public\n view\n returns (uint256 lastWithdrawalInterval, uint256 amount)\n {\n uint256 weightedStake;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n uint256 currentTS = block.timestamp;\n uint256 duration;\n address staker = msg.sender;\n uint256 lastWithdrawal = withdrawals[staker];\n\n uint256 lastStakingInterval = staking.timestampToLockDate(currentTS);\n lastWithdrawalInterval = lastWithdrawal > 0 ? lastWithdrawal : startTime;\n if (lastStakingInterval <= lastWithdrawalInterval) return (0, 0);\n /* Normally the restart time is 0. If this function returns a valid lastWithdrawalInterval\n\t\tand zero amount - that means there were no valid rewards for that period. So the new period must start\n\t\tfrom the end of the last interval or till the time no rewards are accumulated i.e. restartTime */\n if (restartTime >= lastWithdrawalInterval) {\n uint256 latestRestartTime = staking.timestampToLockDate(restartTime);\n lastWithdrawalInterval = latestRestartTime;\n }\n\n if (considerMaxDuration) {\n uint256 addedMaxDuration = lastWithdrawalInterval.add(maxDuration);\n duration = addedMaxDuration < currentTS\n ? staking.timestampToLockDate(addedMaxDuration)\n : lastStakingInterval;\n } else {\n duration = lastStakingInterval;\n }\n for (uint256 i = lastWithdrawalInterval; i < duration; i += TWO_WEEKS) {\n uint256 referenceBlock = checkpointBlockDetails[i];\n if (referenceBlock == 0) {\n referenceBlock = lastFinalisedBlock.sub(\n ((currentTS.sub(i)).div(averageBlockTime))\n );\n }\n if (referenceBlock < deploymentBlock) referenceBlock = deploymentBlock;\n weightedStake = weightedStake.add(_computeRewardForDate(staker, referenceBlock, i));\n }\n lastWithdrawalInterval = duration;\n amount = weightedStake.mul(BASE_RATE).div(DIVISOR);\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title StakingRewards Proxy contract.\n * @dev StakingRewards contract should be upgradable. Used UpgradableProxy.\n * StakingRewardsStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy with\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingRewardsProxy is StakingRewardsStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking Rewards Storage Contract.\n * @notice Just the storage part of staking rewards contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingRewardsProxy.\n *\n * What is SOV staking rewards - SIP-0024?\n * The purpose of the SOV staking rewards - SIP-0024 is to reward,\n * \"marginal stakers\" (ie, stakers by choice, not currently vesting) with liquid SOV\n * at the beginning of each new staking interval.\n * */\ncontract StakingRewardsStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n ///@notice the staking proxy contract address\n IStaking public staking;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 1209600;\n\n /// @notice Annual Base Rate - it is the maximum interest rate(APY)\n uint256 public constant BASE_RATE = 2975;\n\n /// @notice DIVISOR is set as 2600000 = 26 (num periods per year) * 10 (max voting weight) * 10000 (2975 -> 0.2975)\n uint256 public constant DIVISOR = 2600000;\n\n /// @notice Maximum duration to collect rewards at one go\n uint256 public maxDuration;\n\n /// @notice Represents the time when the contract is deployed\n uint256 public startTime;\n\n /// @notice Represents the block when the Staking Rewards pogram is stopped\n uint256 public stopBlock;\n\n /// @notice User Address -> Last Withdrawn Timestamp\n mapping(address => uint256) public withdrawals;\n\n /// @notice User Address -> Claimed Balance\n mapping(address => uint256) public claimedBalances;\n\n /// @notice Represents the block when the StakingRwards Program is started\n uint256 public deploymentBlock;\n\n /// Moved the variables from Initializable contract to resolve issue caused by incorrect Inheritance Order\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /// @notice BlockTime -> BlockNumber for a Staking Checkpoint\n mapping(uint256 => uint256) public checkpointBlockDetails;\n\n /// @notice Average Block Time - making it flexible\n uint256 public averageBlockTime;\n}\n" + }, + "contracts/governance/Timelock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./ErrorDecoder.sol\";\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\n/**\n * @title Sovryn Protocol Timelock contract, based on Compound system.\n *\n * @notice This contract lets Sovryn governance system set up its\n * own Time Lock instance to execute transactions proposed through the\n * GovernorAlpha contract instance.\n *\n * The Timelock contract allows its admin (Sovryn governance on\n * GovernorAlpha contract) to add arbitrary function calls to a\n * queue. This contract can only execute a function call if the\n * function call has been in the queue for at least 3 hours.\n *\n * Anytime the Timelock contract makes a function call, it must be the\n * case that the function call was first made public by having been publicly\n * added to the queue at least 3 hours prior.\n *\n * The intention is to provide GovernorAlpha contract the functionality to\n * queue proposal actions. This would mean that any changes made by Sovryn\n * governance of any contract would necessarily come with at least an\n * advanced warning. This makes the Sovryn system follow a “time-delayed,\n * opt-out” upgrade pattern (rather than an “instant, forced” upgrade pattern).\n *\n * Time-delaying admin actions gives users a chance to exit system if its\n * admins become malicious or compromised (or make a change that the users\n * do not like). Downside is that honest admins would be unable\n * to lock down functionality to protect users if a critical bug was found.\n *\n * Delayed transactions reduce the amount of trust required by users of Sovryn\n * and the overall risk for contracts building on top of it, as GovernorAlpha.\n * */\ncontract Timelock is ErrorDecoder, ITimelock {\n using SafeMath for uint256;\n\n uint256 public constant GRACE_PERIOD = 14 days;\n uint256 public constant MINIMUM_DELAY = 3 hours;\n uint256 public constant MAXIMUM_DELAY = 30 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /**\n * @notice Function called on instance deployment of the contract.\n * @param admin_ Governance contract address.\n * @param delay_ Time to wait for queued transactions to be executed.\n * */\n constructor(address admin_, uint256 delay_) public {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {}\n\n /**\n * @notice Set a new delay when executing the contract calls.\n * @param delay_ The amount of time to wait until execution.\n * */\n function setDelay(uint256 delay_) public {\n require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n require(delay_ >= MINIMUM_DELAY, \"Timelock::setDelay: Delay must exceed minimum delay.\");\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n /**\n * @notice Accept a new admin for the timelock.\n * */\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n /**\n * @notice Set a new pending admin for the timelock.\n * @param pendingAdmin_ The new pending admin address.\n * */\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n /**\n * @notice Queue a new transaction from the governance contract.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function queueTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public returns (bytes32) {\n require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n /**\n * @notice Cancel a transaction.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function cancelTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public {\n require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n /**\n * @notice Executes a previously queued transaction from the governance.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function executeTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public payable returns (bytes memory) {\n require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call.value(value)(callData);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"Timelock::executeTransaction: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"Timelock::executeTransaction: \", string(returnData)));\n }\n }\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n /**\n * @notice A function used to get the current Block Timestamp.\n * @dev Timestamp of the current block in seconds since the epoch.\n * It is a Unix time stamp. So, it has the complete information about\n * the date, hours, minutes, and seconds (in UTC) when the block was\n * created.\n * */\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" + }, + "contracts/governance/Vesting/DevelopmentFund.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Development Fund.\n * @author Franklin Richards\n * @notice You can use this contract for timed token release from Dev Fund.\n */\ncontract DevelopmentFund {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The current contract status.\n enum Status { Deployed, Active, Expired }\n Status public status;\n\n /// @notice The owner of the locked tokens (usually Governance).\n address public lockedTokenOwner;\n /// @notice The owner of the unlocked tokens (usually MultiSig).\n address public unlockedTokenOwner;\n /// @notice The emergency transfer wallet/contract.\n address public safeVault;\n /// @notice The new locked token owner waiting to be approved.\n address public newLockedTokenOwner;\n\n /// @notice The last token release timestamp or the time of contract creation.\n uint256 public lastReleaseTime;\n\n /// @notice The release duration array in seconds.\n uint256[] public releaseDuration;\n /// @notice The release token amount.\n uint256[] public releaseTokenAmount;\n\n /* Events */\n\n /// @notice Emitted when the contract is activated.\n event DevelopmentFundActivated();\n\n /// @notice Emitted when the contract is expired due to total token transfer.\n event DevelopmentFundExpired();\n\n /// @notice Emitted when a new locked owner is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current locked owner.\n event NewLockedOwnerAdded(address indexed _initiator, address indexed _newLockedOwner);\n\n /// @notice Emitted when a new locked owner is approved to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _oldLockedOwner The address of the previous locked owner.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current unlocked owner.\n event NewLockedOwnerApproved(\n address indexed _initiator,\n address indexed _oldLockedOwner,\n address indexed _newLockedOwner\n );\n\n /// @notice Emitted when a new unlocked owner is updated in the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newUnlockedOwner The address which is updated as the new unlocked owner.\n /// @dev Can only be initiated by the current locked owner.\n event UnlockedOwnerUpdated(address indexed _initiator, address indexed _newUnlockedOwner);\n\n /// @notice Emitted when a new token deposit is done.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new release schedule is created.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseCount The number of releases planned in the schedule.\n event TokenReleaseChanged(address indexed _initiator, uint256 _releaseCount);\n\n /// @notice Emitted when a unlocked owner transfers all the tokens to a safe vault.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token withdrawn.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done in an emergency situation only to a predetermined wallet by locked token owner.\n event LockedTokenTransferByUnlockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /// @notice Emitted when a unlocked owner withdraws the released tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token withdrawn.\n /// @param _releaseCount The total number of releases done based on duration.\n event UnlockedTokenWithdrawalByUnlockedOwner(\n address indexed _initiator,\n uint256 _amount,\n uint256 _releaseCount\n );\n\n /// @notice Emitted when a locked owner transfers all the tokens to a receiver.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token transfer.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done only by locked token owner.\n event LockedTokenTransferByLockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /* Modifiers */\n\n modifier onlyLockedTokenOwner() {\n require(msg.sender == lockedTokenOwner, \"Only Locked Token Owner can call this.\");\n _;\n }\n\n modifier onlyUnlockedTokenOwner() {\n require(msg.sender == unlockedTokenOwner, \"Only Unlocked Token Owner can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _lockedTokenOwner The owner of the locked tokens & contract.\n * @param _safeVault The emergency wallet/contract to transfer token.\n * @param _unlockedTokenOwner The owner of the unlocked tokens.\n * @param _lastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev Initial release schedule should be verified, error will result in either redeployment or calling changeTokenReleaseSchedule() after init() along with token transfer.\n */\n constructor(\n address _SOV,\n address _lockedTokenOwner,\n address _safeVault,\n address _unlockedTokenOwner,\n uint256 _lastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_lockedTokenOwner != address(0), \"Locked token & contract owner address invalid.\");\n require(_safeVault != address(0), \"Safe Vault address invalid.\");\n require(_unlockedTokenOwner != address(0), \"Unlocked token address invalid.\");\n\n SOV = IERC20(_SOV);\n lockedTokenOwner = _lockedTokenOwner;\n safeVault = _safeVault;\n unlockedTokenOwner = _unlockedTokenOwner;\n\n lastReleaseTime = _lastReleaseTime;\n /// If last release time passed is zero, then current time stamp will be used as the last release time.\n if (_lastReleaseTime == 0) {\n lastReleaseTime = block.timestamp;\n }\n\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n }\n\n /**\n * @notice This function is called once after deployment for token transfer based on schedule.\n * @dev Without calling this function, the contract will not work.\n */\n function init() public checkStatus(Status.Deployed) {\n uint256[] memory _releaseTokenAmount = releaseTokenAmount;\n require(_releaseTokenAmount.length != 0, \"Release Schedule not set.\");\n\n /// Getting the current release schedule total token amount.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _releaseTotalTokenAmount);\n require(txStatus, \"Not enough token sent to change release schedule.\");\n\n status = Status.Active;\n\n emit DevelopmentFundActivated();\n }\n\n /**\n * @notice Update Locked Token Owner.\n * @param _newLockedTokenOwner The owner of the locked tokens & contract.\n */\n function updateLockedTokenOwner(address _newLockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newLockedTokenOwner != address(0), \"New locked token owner address invalid.\");\n\n newLockedTokenOwner = _newLockedTokenOwner;\n\n emit NewLockedOwnerAdded(msg.sender, _newLockedTokenOwner);\n }\n\n /**\n * @notice Approve Locked Token Owner.\n * @dev This approval is an added security to avoid development fund takeover by a compromised locked token owner.\n */\n function approveLockedTokenOwner() public onlyUnlockedTokenOwner checkStatus(Status.Active) {\n require(newLockedTokenOwner != address(0), \"No new locked owner added.\");\n\n emit NewLockedOwnerApproved(msg.sender, lockedTokenOwner, newLockedTokenOwner);\n\n lockedTokenOwner = newLockedTokenOwner;\n\n newLockedTokenOwner = address(0);\n }\n\n /**\n * @notice Update Unlocked Token Owner.\n * @param _newUnlockedTokenOwner The new unlocked token owner.\n */\n function updateUnlockedTokenOwner(address _newUnlockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newUnlockedTokenOwner != address(0), \"New unlocked token owner address invalid.\");\n\n unlockedTokenOwner = _newUnlockedTokenOwner;\n\n emit UnlockedOwnerUpdated(msg.sender, _newUnlockedTokenOwner);\n }\n\n /**\n * @notice Deposit tokens to this contract.\n * @param _amount the amount of tokens deposited.\n * @dev These tokens can be withdrawn/transferred any time by the lockedTokenOwner.\n */\n function depositTokens(uint256 _amount) public checkStatus(Status.Active) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDeposit(msg.sender, _amount);\n }\n\n /**\n * @notice Change the Token release schedule. It creates a completely new schedule, and does not append on the previous one.\n * @param _newLastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev _releaseDuration and _releaseTokenAmount should be specified in reverse order of release.\n */\n function changeTokenReleaseSchedule(\n uint256 _newLastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public onlyLockedTokenOwner checkStatus(Status.Active) {\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// If the last release time has to be changed, then you can pass a new one here.\n /// Or else, the duration of release will be calculated based on this timestamp.\n /// Even a future timestamp can be mentioned here.\n if (_newLastReleaseTime != 0) {\n lastReleaseTime = _newLastReleaseTime;\n }\n\n /// Checking if the contract have enough token balance for the release.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n /// Getting the current token balance of the contract.\n uint256 remainingTokens = SOV.balanceOf(address(this));\n\n /// If the token balance is not sufficient, then we transfer the change to contract.\n if (remainingTokens < _releaseTotalTokenAmount) {\n bool txStatus =\n SOV.transferFrom(\n msg.sender,\n address(this),\n _releaseTotalTokenAmount.sub(remainingTokens)\n );\n require(txStatus, \"Not enough token sent to change release schedule.\");\n } else if (remainingTokens > _releaseTotalTokenAmount) {\n /// If there are more tokens than required, send the extra tokens back.\n bool txStatus =\n SOV.transfer(msg.sender, remainingTokens.sub(_releaseTotalTokenAmount));\n require(txStatus, \"Token not received by the Locked Owner.\");\n }\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n\n emit TokenReleaseChanged(msg.sender, _releaseDuration.length);\n }\n\n /**\n * @notice Transfers all of the remaining tokens in an emergency situation.\n * @dev This could be called when governance or development fund might be compromised.\n */\n function transferTokensByUnlockedTokenOwner()\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(safeVault, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByUnlockedOwner(msg.sender, safeVault, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /**\n * @notice Withdraws all unlocked/released token.\n * @param _amount The amount to be withdrawn.\n */\n function withdrawTokensByUnlockedTokenOwner(uint256 _amount)\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_amount > 0, \"Zero can't be withdrawn.\");\n\n uint256 count; /// To know how many elements to be removed from the release schedule.\n uint256 amount = _amount; /// To know the total amount to be transferred.\n uint256 newLastReleaseTimeMemory = lastReleaseTime; /// Better to use memory than storage.\n uint256 releaseLength = releaseDuration.length.sub(1); /// Also checks if there are any elements in the release schedule.\n\n /// Getting the amount of tokens, the number of releases and calculating the total duration.\n while (\n amount > 0 &&\n newLastReleaseTimeMemory.add(releaseDuration[releaseLength]) < block.timestamp\n ) {\n if (amount >= releaseTokenAmount[releaseLength]) {\n amount = amount.sub(releaseTokenAmount[releaseLength]);\n newLastReleaseTimeMemory = newLastReleaseTimeMemory.add(\n releaseDuration[releaseLength]\n );\n count++;\n } else {\n /// This will be the last case, if correct amount is passed.\n releaseTokenAmount[releaseLength] = releaseTokenAmount[releaseLength].sub(amount);\n amount = 0;\n }\n releaseLength--;\n }\n\n /// Checking to see if atleast a single schedule was reached or not.\n require(count > 0 || amount == 0, \"No release schedule reached.\");\n\n /// If locked token owner tries to send a higher amount that schedule\n uint256 value = _amount.sub(amount);\n\n /// Now clearing up the release schedule.\n releaseDuration.length -= count;\n releaseTokenAmount.length -= count;\n\n /// Updating the last release time.\n lastReleaseTime = newLastReleaseTimeMemory;\n\n /// Sending the amount to unlocked token owner.\n bool txStatus = SOV.transfer(msg.sender, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit UnlockedTokenWithdrawalByUnlockedOwner(msg.sender, value, count);\n }\n\n /**\n * @notice Transfers all of the remaining tokens by the owner maybe for an upgrade.\n * @dev This could be called when the current development fund has to be upgraded.\n * @param _receiver The address which receives this token transfer.\n */\n function transferTokensByLockedTokenOwner(address _receiver)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(_receiver, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByLockedOwner(msg.sender, _receiver, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token release duration.\n * @return _currentReleaseDuration The current release duration.\n */\n function getReleaseDuration() public view returns (uint256[] memory _releaseTokenDuration) {\n return releaseDuration;\n }\n\n /**\n * @notice Function to read the current token release amount.\n * @return _currentReleaseTokenAmount The current release token amount.\n */\n function getReleaseTokenAmount()\n public\n view\n returns (uint256[] memory _currentReleaseTokenAmount)\n {\n return releaseTokenAmount;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../IFeeSharingCollector.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../proxy/UpgradableProxy.sol\";\nimport \"../../../openzeppelin/Address.sol\";\n\n/**\n * @title Four Year Vesting Contract.\n *\n * @notice A four year vesting contract.\n *\n * @dev Vesting contract is upgradable,\n * Make sure the vesting owner is multisig otherwise it will be\n * catastrophic.\n * */\ncontract FourYearVesting is FourYearVestingStorage, UpgradableProxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharingCollector Fee sharing proxy address.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n address _feeSharingCollector,\n uint256 _extendDurationFor\n ) public {\n require(Address.isContract(_logic), \"_logic not a contract\");\n require(_SOV != address(0), \"SOV address invalid\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(Address.isContract(_stakingAddress), \"_stakingAddress not a contract\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(Address.isContract(_feeSharingCollector), \"_feeSharingCollector not a contract\");\n require((_extendDurationFor % FOUR_WEEKS) == 0, \"invalid duration\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n tokenOwner = _tokenOwner;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n maxInterval = 18 * FOUR_WEEKS;\n extendDurationFor = _extendDurationFor;\n }\n\n /**\n * @notice Set address of the implementation - vesting owner.\n * @dev Overriding setImplementation function of UpgradableProxy. The logic can only be\n * modified when both token owner and veting owner approve. Since\n * setImplementation can only be called by vesting owner, we also need to check\n * if the new logic is already approved by the token owner.\n * @param _implementation Address of the implementation. Must match with what is set by token owner.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n require(Address.isContract(_implementation), \"_implementation not a contract\");\n require(newImplementation == _implementation, \"address mismatch\");\n _setImplementation(_implementation);\n newImplementation = address(0);\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"./FourYearVesting.sol\";\nimport \"./IFourYearVestingFactory.sol\";\n\n/**\n * @title Four Year Vesting Factory: Contract to deploy four year vesting contracts.\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract FourYearVestingFactory is IFourYearVestingFactory, Ownable {\n /// @dev Added an event to keep track of the vesting contract created for a token owner\n event FourYearVestingCreated(address indexed tokenOwner, address indexed vestingAddress);\n\n /**\n * @notice Deploys four year vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwnerMultisig The address of an owner of vesting contract.\n * @dev _vestingOwnerMultisig should ALWAYS be multisig.\n * @param _fourYearVestingLogic The implementation contract.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * @return The four year vesting contract address.\n * */\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external onlyOwner returns (address) {\n address fourYearVesting =\n address(\n new FourYearVesting(\n _fourYearVestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _feeSharing,\n _extendDurationFor\n )\n );\n Ownable(fourYearVesting).transferOwnership(_vestingOwnerMultisig);\n emit FourYearVestingCreated(_tokenOwner, fourYearVesting);\n return fourYearVesting;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./IFourYearVesting.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Four Year Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by FourYearVestingFactory contract.\n * */\ncontract FourYearVestingLogic is IFourYearVesting, FourYearVestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n\n /* Events */\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n event TokenOwnerChanged(address indexed newOwner, address indexed oldOwner);\n\n /* Modifiers */\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Sets the max interval.\n * @param _interval Max interval for which tokens scheduled shall be staked.\n * */\n function setMaxInterval(uint256 _interval) external onlyOwner {\n require(_interval.mod(FOUR_WEEKS) == 0, \"invalid interval\");\n maxInterval = _interval;\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount)\n {\n (lastSchedule, remainingAmount) = _stakeTokens(msg.sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokensWithApproval(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) external onlyThisContract returns (uint256 lastSchedule, uint256 remainingAmount) {\n (lastSchedule, remainingAmount) = _stakeTokens(_sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) external onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n uint256 stakingEndDate = endDate;\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate.add(cliff); i <= stakingEndDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) external onlyTokenOwner {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external onlyTokenOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Change token owner - only vesting owner is allowed to change.\n * @dev Modifies token owner. This must be followed by approval\n * from token owner.\n * @param _newTokenOwner Address of new token owner.\n * */\n function changeTokenOwner(address _newTokenOwner) public onlyOwner {\n require(_newTokenOwner != address(0), \"invalid new token owner address\");\n require(_newTokenOwner != tokenOwner, \"same owner not allowed\");\n newTokenOwner = _newTokenOwner;\n }\n\n /**\n * @notice Approve token owner change - only token Owner.\n * @dev Token owner can only be modified\n * when both vesting owner and token owner have approved. This\n * function ascertains the approval of token owner.\n * */\n function approveOwnershipTransfer() public onlyTokenOwner {\n require(newTokenOwner != address(0), \"invalid address\");\n tokenOwner = newTokenOwner;\n newTokenOwner = address(0);\n emit TokenOwnerChanged(tokenOwner, msg.sender);\n }\n\n /**\n * @notice Set address of the implementation - only Token Owner.\n * @dev This function sets the new implementation address.\n * It must also be approved by the Vesting owner.\n * @param _newImplementation Address of the new implementation.\n * */\n function setImpl(address _newImplementation) public onlyTokenOwner {\n require(_newImplementation != address(0), \"invalid new implementation address\");\n newImplementation = _newImplementation;\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() external onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Extends stakes(unlocked till timeDuration) for four year vesting contracts.\n * @dev Tokens are vested for 4 years. Since the max staking\n * period is 3 years and the tokens are unlocked only after the first year(timeDuration) is\n * passed, hence, we usually extend the duration of staking for all unlocked tokens for the first\n * year by 3 years. In some cases, the timeDuration can differ.\n * */\n function extendStaking() external {\n uint256 timeDuration = startDate.add(extendDurationFor);\n uint256[] memory dates;\n uint96[] memory stakes;\n (dates, stakes) = staking.getStakes(address(this));\n\n for (uint256 i = 0; i < dates.length; i++) {\n if ((dates[i] < block.timestamp) && (dates[i] <= timeDuration) && (stakes[i] > 0)) {\n staking.extendStakingDuration(dates[i], dates[i].add(156 weeks));\n endDate = dates[i].add(156 weeks);\n } else {\n break;\n }\n }\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function _stakeTokens(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) internal returns (uint256 lastSchedule, uint256 remainingAmount) {\n // Creating a new staking schedule for the same vesting contract is disallowed unlike normal vesting\n require(\n (startDate == 0) ||\n (startDate > 0 && remainingStakeAmount > 0 && _restartStakeSchedule > 0),\n \"create new vesting address\"\n );\n uint256 restartDate;\n uint256 relativeAmount;\n // Calling the _stakeTokens function first time for the vesting contract\n // Runs for maxInterval only (consider maxInterval = 18 * 4 = 72 weeks)\n if (startDate == 0 && _restartStakeSchedule == 0) {\n startDate = staking.timestampToLockDate(block.timestamp); // Set only once\n durationLeft = duration; // We do not touch duration and cliff as they are used throughout\n cliffAdded = cliff; // Hence, durationLeft and cliffAdded is created\n }\n // Calling the _stakeTokens second/third time - we start from the end of previous interval\n // and the remaining amount(amount left after tokens are staked in the previous interval)\n if (_restartStakeSchedule > 0) {\n require(\n _restartStakeSchedule == lastStakingSchedule && _amount == remainingStakeAmount,\n \"invalid params\"\n );\n restartDate = _restartStakeSchedule;\n } else {\n restartDate = startDate;\n }\n // Runs only once when the _stakeTokens is called for the first time\n if (endDate == 0) {\n endDate = staking.timestampToLockDate(block.timestamp.add(duration));\n }\n uint256 addedMaxInterval = restartDate.add(maxInterval); // run for maxInterval\n if (addedMaxInterval < endDate) {\n // Runs for max interval\n lastStakingSchedule = addedMaxInterval;\n relativeAmount = (_amount.mul(maxInterval)).div(durationLeft); // (_amount * 18) / 39\n durationLeft = durationLeft.sub(maxInterval); // durationLeft - 18 periods(72 weeks)\n remainingStakeAmount = _amount.sub(relativeAmount); // Amount left to be staked in subsequent intervals\n } else {\n // Normal run\n lastStakingSchedule = endDate; // if staking intervals left < 18 periods(72 weeks)\n remainingStakeAmount = 0;\n durationLeft = 0;\n relativeAmount = _amount; // Stake all amount left\n }\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), relativeAmount);\n require(success, \"transfer failed\");\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), relativeAmount);\n\n staking.stakesBySchedule(\n relativeAmount,\n cliffAdded,\n duration.sub(durationLeft),\n FOUR_WEEKS,\n address(this),\n tokenOwner\n );\n if (durationLeft == 0) {\n // All tokens staked\n cliffAdded = 0;\n } else {\n cliffAdded = cliffAdded.add(maxInterval); // Add cliff to the end of previous maxInterval\n }\n\n emit TokensStaked(_sender, relativeAmount);\n return (lastStakingSchedule, remainingStakeAmount);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n /// @dev For four year vesting, withdrawal of stakes for the first year is not allowed. These\n /// stakes are extended for three years. In some cases the withdrawal may be allowed at a different\n /// time and hence we use extendDurationFor.\n for (uint256 i = startDate.add(extendDurationFor); i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number.sub(1));\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../Staking/interfaces/IStaking.sol\";\nimport \"../../IFeeSharingCollector.sol\";\n\n/**\n * @title Four Year Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for four year vesting.\n * It is parent of FourYearVestingLogic and FourYearVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract FourYearVestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n // Used lower case for cliff and duration to maintain consistency with normal vesting\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public constant cliff = 4 weeks;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public constant duration = 156 weeks;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n /// @notice Maximum interval to stake tokens at one go\n uint256 public maxInterval;\n\n /// @notice End of previous staking schedule.\n uint256 public lastStakingSchedule;\n\n /// @notice Amount of shares left to be staked.\n uint256 public remainingStakeAmount;\n\n /// @notice Durations left.\n uint256 public durationLeft;\n\n /// @notice Cliffs added.\n uint256 public cliffAdded;\n\n /// @notice Address of new token owner.\n address public newTokenOwner;\n\n /// @notice Address of new implementation.\n address public newImplementation;\n\n /// @notice Duration(from start) till the time unlocked tokens are extended(for 3 years)\n uint256 public extendDurationFor;\n\n /// @dev Please add new state variables below this line. Mark them internal and\n /// add a getter function while upgrading the contracts.\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IFourYearVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IFourYearVesting {\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount);\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingFactory contract to override empty\n * implemention of deployFourYearVesting function\n * and use an instance of FourYearVestingFactory.\n */\ninterface IFourYearVestingFactory {\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/GenericTokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\n\n/**\n * @title Token sender contract.\n *\n * @notice This contract includes functions to transfer tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract GenericTokenSender is AdminRole {\n /* Events */\n\n event TokensTransferred(address indexed token, address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer given amounts of tokens to the given addresses.\n * @param _token The address of the token.\n * @param _receivers The addresses of the receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferTokensUsingList(\n address _token,\n address[] calldata _receivers,\n uint256[] calldata _amounts\n ) external onlyAuthorized {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferTokens(_token, _receivers[i], _amounts[i]);\n }\n }\n\n function() external payable {}\n\n /**\n * @notice Transfer tokens to given address.\n * @param _token The address of the token.\n * @param _receiver The address of the token receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) external onlyAuthorized {\n _transferTokens(_token, _receiver, _amount);\n }\n\n function _transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n if (_token != address(0)) {\n require(IERC20(_token).transfer(_receiver, _amount), \"transfer failed\");\n } else {\n (bool success, ) = _receiver.call.value(_amount)(\"\");\n require(success, \"RBTC transfer failed\");\n }\n emit TokensTransferred(_token, _receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/ITeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for TeamVesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by Staking contract to call governanceWithdrawTokens\n * function having the vesting contract instance address.\n */\ninterface ITeamVesting {\n function startDate() external view returns (uint256);\n\n function cliff() external view returns (uint256);\n\n function endDate() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function tokenOwner() external view returns (address);\n\n function governanceWithdrawTokens(address receiver) external;\n}\n" + }, + "contracts/governance/Vesting/IVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IVesting {\n function duration() external returns (uint256);\n\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 amount) external;\n\n function tokenOwner() external view returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingFactory contract to override empty\n * implemention of deployVesting and deployTeamVesting functions\n * and on VestingRegistry contract to use an instance of VestingFactory.\n */\ninterface IVestingFactory {\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for upgradable Vesting Registry contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IVestingRegistry {\n function getVesting(address _tokenOwner) external view returns (address);\n\n function getTeamVesting(address _tokenOwner) external view returns (address);\n\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n function isVestingAddress(address _vestingAddress) external view returns (bool);\n\n function isTeamVesting(address _vestingAddress) external view returns (bool);\n}\n" + }, + "contracts/governance/Vesting/OrigingVestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./VestingRegistry.sol\";\n\n/**\n * @title Temp contract for checking address, creating and staking tokens.\n * @notice It casts an instance of vestingRegistry and by using createVesting\n * function it creates a vesting, gets it and stakes some tokens w/ this vesting.\n * */\ncontract OrigingVestingCreator is Ownable {\n VestingRegistry public vestingRegistry;\n\n mapping(address => bool) processedList;\n\n constructor(address _vestingRegistry) public {\n vestingRegistry = VestingRegistry(_vestingRegistry);\n }\n\n /**\n * @notice Create a vesting, get it and stake some tokens w/ this vesting.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount of tokens to be vested.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyOwner {\n require(_tokenOwner != address(0), \"Invalid address\");\n require(!processedList[_tokenOwner], \"Already processed\");\n\n processedList[_tokenOwner] = true;\n\n vestingRegistry.createVesting(_tokenOwner, _amount, _cliff, _duration);\n address vesting = vestingRegistry.getVesting(_tokenOwner);\n vestingRegistry.stakeTokens(vesting, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/OriginInvestorsClaim.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./VestingRegistry.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\n\n/**\n * @title Origin investors claim vested cSOV tokens.\n * @notice // TODO: fund this contract with a total amount of SOV needed to distribute.\n * */\ncontract OriginInvestorsClaim is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// VestingRegistry public constant vestingRegistry = VestingRegistry(0x80B036ae59B3e38B573837c01BB1DB95515b7E6B);\n\n uint256 public totalAmount;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant SOV_VESTING_CLIFF = 6 weeks;\n\n uint256 public kickoffTS;\n uint256 public vestingTerm;\n uint256 public investorsQty;\n bool public investorsListInitialized;\n VestingRegistry public vestingRegistry;\n IStaking public staking;\n IERC20 public SOVToken;\n\n /// @dev user => flag : Whether user has admin role.\n mapping(address => bool) public admins;\n\n /// @dev investor => Amount : Origin investors entitled to claim SOV.\n mapping(address => uint256) public investorsAmountsList;\n\n /* Events */\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n event InvestorsAmountsListAppended(uint256 qty, uint256 amount);\n event ClaimVested(address indexed investor, uint256 amount);\n event ClaimTransferred(address indexed investor, uint256 amount);\n event InvestorsAmountsListInitialized(uint256 qty, uint256 totalAmount);\n\n /* Modifiers */\n\n /// @dev Throws if called by any account other than the owner or admin.\n modifier onlyAuthorized() {\n require(\n isOwner() || admins[msg.sender],\n \"OriginInvestorsClaim::onlyAuthorized: should be authorized\"\n );\n _;\n }\n\n /// @dev Throws if called by any account not whitelisted.\n modifier onlyWhitelisted() {\n require(\n investorsAmountsList[msg.sender] != 0,\n \"OriginInvestorsClaim::onlyWhitelisted: not whitelisted or already claimed\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an initialized investors list.\n modifier notInitialized() {\n require(\n !investorsListInitialized,\n \"OriginInvestorsClaim::notInitialized: the investors list should not be set as initialized\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an uninitialized investors list.\n modifier initialized() {\n require(\n investorsListInitialized,\n \"OriginInvestorsClaim::initialized: the investors list has not been set yet\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires one parameter:\n * @param vestingRegistryAddress The vestingRegistry contract instance address.\n * */\n constructor(address vestingRegistryAddress) public {\n vestingRegistry = VestingRegistry(vestingRegistryAddress);\n staking = IStaking(vestingRegistry.staking());\n kickoffTS = staking.kickoffTS();\n SOVToken = IERC20(staking.SOVToken());\n vestingTerm = kickoffTS + SOV_VESTING_CLIFF;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice In case we have unclaimed tokens or in emergency case\n * this function transfers all SOV tokens to a given address.\n * @param toAddress The recipient address of all this contract tokens.\n * */\n function authorizedBalanceWithdraw(address toAddress) public onlyAuthorized {\n require(\n SOVToken.transfer(toAddress, SOVToken.balanceOf(address(this))),\n \"OriginInvestorsClaim::authorizedTransferBalance: transfer failed\"\n );\n }\n\n /**\n * @notice Should be called after the investors list setup completed.\n * This function checks whether the SOV token balance of the contract is\n * enough and sets status list to initialized.\n * */\n function setInvestorsAmountsListInitialized() public onlyAuthorized notInitialized {\n require(\n SOVToken.balanceOf(address(this)) >= totalAmount,\n \"OriginInvestorsClaim::setInvestorsAmountsList: the contract is not enough financed\"\n );\n\n investorsListInitialized = true;\n\n emit InvestorsAmountsListInitialized(investorsQty, totalAmount);\n }\n\n /**\n * @notice The contract should be approved or transferred necessary\n * amount of SOV prior to calling the function.\n * @param investors The list of investors addresses to add to the list.\n * Duplicates will be skipped.\n * @param claimAmounts The list of amounts for investors investors[i]\n * will receive claimAmounts[i] of SOV.\n * */\n function appendInvestorsAmountsList(\n address[] calldata investors,\n uint256[] calldata claimAmounts\n ) external onlyAuthorized notInitialized {\n uint256 subQty;\n uint256 sumAmount;\n require(\n investors.length == claimAmounts.length,\n \"OriginInvestorsClaim::appendInvestorsAmountsList: investors.length != claimAmounts.length\"\n );\n\n for (uint256 i = 0; i < investors.length; i++) {\n if (investorsAmountsList[investors[i]] == 0) {\n investorsAmountsList[investors[i]] = claimAmounts[i];\n sumAmount = sumAmount.add(claimAmounts[i]);\n } else {\n subQty = subQty.add(1);\n }\n }\n\n investorsQty = investorsQty.add(investors.length.sub(subQty));\n totalAmount = totalAmount.add(sumAmount);\n emit InvestorsAmountsListAppended(investors.length.sub(subQty), sumAmount);\n }\n\n /**\n * @notice Claim tokens from this contract.\n * If vestingTerm is not yet achieved a vesting is created.\n * Otherwise tokens are tranferred.\n * */\n function claim() external onlyWhitelisted initialized {\n if (now < vestingTerm) {\n createVesting();\n } else {\n transfer();\n }\n }\n\n /**\n * @notice Transfer tokens from this contract to a vestingRegistry contract.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to vesting contract.\n * */\n function createVesting() internal {\n uint256 cliff = vestingTerm.sub(now);\n uint256 duration = cliff;\n uint256 amount = investorsAmountsList[msg.sender];\n address vestingContractAddress;\n\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n vestingContractAddress == address(0),\n \"OriginInvestorsClaim::withdraw: the claimer has an active vesting contract\"\n );\n\n delete investorsAmountsList[msg.sender];\n\n vestingRegistry.createVesting(msg.sender, amount, cliff, duration);\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n SOVToken.transfer(address(vestingRegistry), amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n vestingRegistry.stakeTokens(vestingContractAddress, amount);\n\n emit ClaimVested(msg.sender, amount);\n }\n\n /**\n * @notice Transfer tokens from this contract to the sender.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to its account.\n * */\n function transfer() internal {\n uint256 amount = investorsAmountsList[msg.sender];\n\n delete investorsAmountsList[msg.sender];\n\n /**\n * @dev Withdraw only for those claiming after the cliff, i.e. without vesting contracts.\n * Those with vestingContracts should withdraw using Vesting.withdrawTokens\n * from Vesting (VestingLogic) contract.\n * */\n require(\n SOVToken.transfer(msg.sender, amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n\n emit ClaimTransferred(msg.sender, amount);\n }\n}\n" + }, + "contracts/governance/Vesting/TeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n//import \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../proxy/Proxy.sol\";\n\n/**\n * @title Team Vesting Contract.\n *\n * @notice A regular vesting contract, but the owner (governance) is able to\n * withdraw earlier without a slashing.\n *\n * @dev Vesting contracts shouldn't be upgradable,\n * use Proxy instead of UpgradableProxy.\n * */\ncontract TeamVesting is VestingStorage, Proxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollector\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_duration >= _cliff, \"duration must be bigger than or equal to the cliff\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n require(_duration <= staking.MAX_DURATION(), \"duration may not exceed the max duration\");\n tokenOwner = _tokenOwner;\n cliff = _cliff;\n duration = _duration;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n }\n}\n" + }, + "contracts/governance/Vesting/TokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title SOV Token sender contract.\n *\n * @notice This contract includes functions to transfer SOV tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract TokenSender is Ownable {\n /* Storage */\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @dev user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n constructor(address _SOV) public {\n require(_SOV != address(0), \"SOV address invalid\");\n\n SOV = _SOV;\n }\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Transfer given amounts of SOV to the given addresses.\n * @param _receivers The addresses of the SOV receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferSOVusingList(address[] memory _receivers, uint256[] memory _amounts)\n public\n onlyAuthorized\n {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferSOV(_receivers[i], _amounts[i]);\n }\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyAuthorized {\n _transferSOV(_receiver, _amount);\n }\n\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/Vesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./TeamVesting.sol\";\n\n/**\n * @title Vesting Contract.\n * @notice Team tokens and investor tokens are vested. Therefore, a smart\n * contract needs to be developed to enforce the vesting schedule.\n *\n * @dev TODO add tests for governanceWithdrawTokens.\n * */\ncontract Vesting is TeamVesting {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollectorProxy\n )\n public\n TeamVesting(\n _logic,\n _SOV,\n _stakingAddress,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharingCollectorProxy\n )\n {}\n\n /**\n * @dev We need to add this implementation to prevent proxy call VestingLogic.governanceWithdrawTokens\n * @param receiver The receiver of the token withdrawal.\n * */\n function governanceWithdrawTokens(address receiver) public {\n revert(\"operation not supported\");\n }\n}\n" + }, + "contracts/governance/Vesting/VestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"./VestingRegistryLogic.sol\";\nimport \"./VestingLogic.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingCreator is AdminRole {\n using SafeMath for uint256;\n\n ///@notice Boolean to check both vesting creation and staking is completed for a record\n bool vestingCreated;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 2 weeks;\n\n ///@notice the SOV token contract\n IERC20 public SOV;\n\n ///@notice the vesting registry contract\n VestingRegistryLogic public vestingRegistryLogic;\n\n ///@notice Holds Vesting Data\n struct VestingData {\n uint256 amount;\n uint256 cliff;\n uint256 duration;\n bool governanceControl; ///@dev true - tokens can be withdrawn by governance\n address tokenOwner;\n uint256 vestingCreationType;\n }\n\n ///@notice list of vesting to be processed\n VestingData[] public vestingDataList;\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event TokensStaked(address indexed vesting, address indexed tokenOwner, uint256 amount);\n event VestingDataRemoved(address indexed caller, address indexed tokenOwner);\n event DataCleared(address indexed caller);\n\n constructor(address _SOV, address _vestingRegistryProxy) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_vestingRegistryProxy != address(0), \"Vesting registry address invalid\");\n\n SOV = IERC20(_SOV);\n vestingRegistryLogic = VestingRegistryLogic(_vestingRegistryProxy);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings to be processed to the list\n */\n function addVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _amounts,\n uint256[] calldata _cliffs,\n uint256[] calldata _durations,\n bool[] calldata _governanceControls,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n require(\n _tokenOwners.length == _amounts.length &&\n _tokenOwners.length == _cliffs.length &&\n _tokenOwners.length == _durations.length &&\n _tokenOwners.length == _governanceControls.length,\n \"arrays mismatch\"\n );\n\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(\n _durations[i] >= _cliffs[i],\n \"duration must be bigger than or equal to the cliff\"\n );\n require(_amounts[i] > 0, \"vesting amount cannot be 0\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_cliffs[i].mod(TWO_WEEKS) == 0, \"cliffs should have intervals of two weeks\");\n require(\n _durations[i].mod(TWO_WEEKS) == 0,\n \"durations should have intervals of two weeks\"\n );\n VestingData memory vestingData =\n VestingData({\n amount: _amounts[i],\n cliff: _cliffs[i],\n duration: _durations[i],\n governanceControl: _governanceControls[i],\n tokenOwner: _tokenOwners[i],\n vestingCreationType: _vestingCreationTypes[i]\n });\n vestingDataList.push(vestingData);\n }\n }\n\n /**\n * @notice Creates vesting contract and stakes tokens\n * @dev Vesting and Staking are merged for calls that fits the gas limit\n */\n function processNextVesting() external {\n processVestingCreation();\n processStaking();\n }\n\n /**\n * @notice Creates vesting contract without staking any tokens\n * @dev Separating the Vesting and Staking to tackle Block Gas Limit\n */\n function processVestingCreation() public {\n require(!vestingCreated, \"staking not done for the previous vesting\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n _createAndGetVesting(vestingData);\n vestingCreated = true;\n }\n }\n\n /**\n * @notice Staking vested tokens\n * @dev it can be the case when vesting creation and tokens staking can't be done in one transaction because of block gas limit\n */\n function processStaking() public {\n require(vestingCreated, \"cannot stake without vesting creation\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n address vestingAddress =\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n require(SOV.approve(address(vesting), vestingData.amount), \"Approve failed\");\n vesting.stakeTokens(vestingData.amount);\n emit TokensStaked(vestingAddress, vestingData.tokenOwner, vestingData.amount);\n address tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n vestingCreated = false;\n }\n\n /**\n * @notice removes next vesting data from the list\n * @dev we process inverted list\n * @dev we should be able to remove incorrect vesting data that can't be processed\n */\n function removeNextVesting() external onlyAuthorized {\n address tokenOwnerDetails;\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n\n /**\n * @notice removes all data about unprocessed vestings to be processed\n */\n function clearVestingDataList() public onlyAuthorized {\n delete vestingDataList;\n emit DataCleared(msg.sender);\n }\n\n /**\n * @notice returns address after vesting creation\n */\n function getVestingAddress() external view returns (address) {\n return\n _getVesting(\n vestingDataList[vestingDataList.length - 1].tokenOwner,\n vestingDataList[vestingDataList.length - 1].cliff,\n vestingDataList[vestingDataList.length - 1].duration,\n vestingDataList[vestingDataList.length - 1].governanceControl,\n vestingDataList[vestingDataList.length - 1].vestingCreationType\n );\n }\n\n /**\n * @notice returns period i.e. ((duration - cliff) / 4 WEEKS)\n * @dev will be used for deciding if vesting and staking needs to be processed\n * in a single transaction or separate transactions\n */\n function getVestingPeriod() external view returns (uint256) {\n uint256 duration = vestingDataList[vestingDataList.length - 1].duration;\n uint256 cliff = vestingDataList[vestingDataList.length - 1].cliff;\n uint256 fourWeeks = TWO_WEEKS.mul(2);\n uint256 period = duration.sub(cliff).div(fourWeeks);\n return period;\n }\n\n /**\n * @notice returns count of vestings to be processed\n */\n function getUnprocessedCount() external view returns (uint256) {\n return vestingDataList.length;\n }\n\n /**\n * @notice returns total amount of vestings to be processed\n */\n function getUnprocessedAmount() public view returns (uint256) {\n uint256 amount = 0;\n uint256 length = vestingDataList.length;\n for (uint256 i = 0; i < length; i++) {\n amount = amount.add(vestingDataList[i].amount);\n }\n return amount;\n }\n\n /**\n * @notice checks if contract balance is enough to process all vestings\n */\n function isEnoughBalance() public view returns (bool) {\n return SOV.balanceOf(address(this)) >= getUnprocessedAmount();\n }\n\n /**\n * @notice returns missed balance to process all vestings\n */\n function getMissingBalance() external view returns (uint256) {\n if (isEnoughBalance()) {\n return 0;\n }\n return getUnprocessedAmount() - SOV.balanceOf(address(this));\n }\n\n /**\n * @notice creates TeamVesting or Vesting contract\n * @dev new contract won't be created if account already has contract of the same type\n */\n function _createAndGetVesting(VestingData memory vestingData)\n internal\n returns (address vesting)\n {\n if (vestingData.governanceControl) {\n vestingRegistryLogic.createTeamVesting(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n } else {\n vestingRegistryLogic.createVestingAddr(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n }\n return\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n }\n\n /**\n * @notice returns an address of TeamVesting or Vesting contract (depends on a governance control)\n */\n function _getVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n bool _governanceControl,\n uint256 _vestingCreationType\n ) internal view returns (address vestingAddress) {\n if (_governanceControl) {\n vestingAddress = vestingRegistryLogic.getTeamVesting(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n } else {\n vestingAddress = vestingRegistryLogic.getVestingAddr(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n }\n }\n}\n" + }, + "contracts/governance/Vesting/VestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./Vesting.sol\";\nimport \"./TeamVesting.sol\";\nimport \"./IVestingFactory.sol\";\n\n/**\n * @title Vesting Factory: Contract to deploy vesting contracts\n * of two types: vesting (TokenHolder) and team vesting (Multisig).\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract VestingFactory is IVestingFactory, Ownable {\n address public vestingLogic;\n\n constructor(address _vestingLogic) public {\n require(_vestingLogic != address(0), \"invalid vesting logic address\");\n vestingLogic = _vestingLogic;\n }\n\n /**\n * @notice Deploys Vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner /// @dev owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new Vesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n\n /**\n * @notice Deploys Team Vesting contract.\n * @param _SOV The address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner //owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new TeamVesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\n\n/**\n * @title Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by a VestingFactory contract.\n * */\ncontract VestingLogic is IVesting, VestingStorage, ApprovalReceiver {\n /* Events */\n\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(uint256 _amount) public {\n _stakeTokens(msg.sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokensWithApproval(address _sender, uint256 _amount) public onlyThisContract {\n _stakeTokens(_sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * */\n function _stakeTokens(address _sender, uint256 _amount) internal {\n /// @dev Maybe better to allow staking unil the cliff was reached.\n if (startDate == 0) {\n startDate = staking.timestampToLockDate(block.timestamp);\n }\n endDate = staking.timestampToLockDate(block.timestamp + duration);\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), _amount);\n require(success);\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), _amount);\n\n staking.stakeBySchedule(_amount, cliff, duration, FOUR_WEEKS, address(this), tokenOwner);\n\n emit TokensStaked(_sender, _amount);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws all tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * @dev Can be called only by owner.\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdrawTokens(address receiver) public {\n require(msg.sender == address(staking), \"unauthorized\");\n\n _withdrawTokens(receiver, true);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) public onlyOwners {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number - 1);\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n if (isGovernance) {\n staking.governanceWithdraw(stake, i, receiver);\n } else {\n staking.withdraw(stake, i, receiver);\n }\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) public onlyOwners {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() public onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Registry contract.\n *\n * @notice On January 25, 2020, Sovryn launched the Genesis Reservation system.\n * Sovryn community members who controlled a special NFT were granted access to\n * stake BTC or rBTC for cSOV tokens at a rate of 2500 satoshis per cSOV. Per\n * SIP-0003, up to 2,000,000 cSOV were made available in the Genesis event,\n * which will be redeemable on a 1:1 basis for cSOV, subject to approval by\n * existing SOV holders.\n *\n * On 15 Feb 2021 Sovryn is taking another step in its journey to decentralized\n * financial sovereignty with the vote on SIP 0005. This proposal will enable\n * participants of the Genesis Reservation system to redeem their reserved cSOV\n * tokens for SOV. They will also have the choice to redeem cSOV for rBTC if\n * they decide to exit the system.\n *\n * This contract deals with the vesting and redemption of cSOV tokens.\n * */\ncontract VestingRegistry is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The cSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract.\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVReImburse(address from, uint256 CSOVamount, uint256 reImburseAmount);\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing collector proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n //---ACL------------------------------------------------------------------\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * TODO: This ACL logic should be available on OpenZeppeling Ownable.sol\n * or on our own overriding sovrynOwnable. This same logic is repeated\n * on OriginInvestorsClaim.sol, TokenSender.sol and VestingRegistry2.sol\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice cSOV payout to sender with rBTC currency.\n * 1.- Check holder cSOV balance by adding up every cSOV token balance.\n * 2.- ReImburse rBTC if funds available.\n * 3.- And store holder address in processedList.\n */\n function reImburse() public isNotProcessed isNotBlacklisted {\n uint256 CSOVAmountWei = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n CSOVAmountWei = CSOVAmountWei.add(balance);\n }\n\n require(CSOVAmountWei > lockedAmount[msg.sender], \"holder has no CSOV\");\n CSOVAmountWei -= lockedAmount[msg.sender];\n processedList[msg.sender] = true;\n\n /**\n * @dev Found and fixed the SIP-0007 bug on VestingRegistry::reImburse formula.\n * More details at Documenting Code issues at point 11 in\n * https://docs.google.com/document/d/10idTD1K6JvoBmtPKGuJ2Ub_mMh6qTLLlTP693GQKMyU/\n * Previous buggy code: uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**10);\n * */\n uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**8);\n require(address(this).balance >= reImburseAmount, \"Not enough funds to reimburse\");\n msg.sender.transfer(reImburseAmount);\n\n emit CSOVReImburse(msg.sender, CSOVAmountWei, reImburseAmount);\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Exchange cSOV to SOV with 1:1 rate\n */\n function exchangeAllCSOV() public isNotProcessed isNotBlacklisted {\n processedList[msg.sender] = true;\n\n uint256 amount = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n amount += balance;\n }\n\n require(amount > lockedAmount[msg.sender], \"amount invalid\");\n amount -= lockedAmount[msg.sender];\n\n _createVestingForCSOV(amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param _vesting The address of Vesting contract.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n /// @dev TODO: Owner of OwnerVesting contracts - the same address as tokenOwner.\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry2.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title VestingRegistry 2 contract.\n * @notice One time contract needed to distribute tokens to origin sales investors.\n * */\ncontract VestingRegistry2 is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The CSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry3.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingRegistry3 is Ownable {\n using SafeMath for uint256;\n\n IVestingFactory public vestingFactory;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n //@notice fee sharing proxy\n address public feeSharingCollector;\n //@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n //TODO add to the documentation: address can have only one vesting of each type\n //user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n //user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n constructor(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"./VestingRegistryStorage.sol\";\n\ncontract VestingRegistryLogic is VestingRegistryStorage {\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event VestingCreationAndTypesSet(\n address indexed vesting,\n VestingCreationAndTypeDetails vestingCreationAndType\n );\n\n /**\n * @notice Replace constructor with initialize function for Upgradable Contracts\n * This function will be called only once by the owner\n * */\n function initialize(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner,\n address _lockedSOV,\n address[] calldata _vestingRegistries\n ) external onlyOwner initializer {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n require(_lockedSOV != address(0), \"LockedSOV address invalid\");\n\n _setVestingFactory(_vestingFactory);\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n lockedSOV = LockedSOV(_lockedSOV);\n for (uint256 i = 0; i < _vestingRegistries.length; i++) {\n require(_vestingRegistries[i] != address(0), \"Vesting registry address invalid\");\n vestingRegistries.push(IVestingRegistry(_vestingRegistries[i]));\n }\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) external onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Internal function that sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings that were deployed in previous vesting registries\n * @dev migration of data from previous vesting registy contracts\n */\n function addDeployedVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingCreationTypes[i] > 0, \"vesting creation type must be greater than 0\");\n _addDeployedVestings(_tokenOwners[i], _vestingCreationTypes[i]);\n }\n }\n\n /**\n * @notice adds four year vestings to vesting registry logic\n * @param _tokenOwners array of token owners\n * @param _vestingAddresses array of vesting addresses\n */\n function addFourYearVestings(\n address[] calldata _tokenOwners,\n address[] calldata _vestingAddresses\n ) external onlyAuthorized {\n require(_tokenOwners.length == _vestingAddresses.length, \"arrays mismatch\");\n uint256 vestingCreationType = 4;\n uint256 cliff = 4 weeks;\n uint256 duration = 156 weeks;\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(!isVesting[_vestingAddresses[i]], \"vesting exists\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingAddresses[i] != address(0), \"vesting cannot be 0 address\");\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwners[i],\n uint256(VestingType.Vesting),\n cliff,\n duration,\n vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n vestingCreationType,\n _vestingAddresses[i]\n );\n vestingsOf[_tokenOwners[i]].push(uid);\n isVesting[_vestingAddresses[i]] = true;\n }\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @dev Calls a public createVestingAddr function with vestingCreationType. This is to accomodate the existing logic for LockedSOV\n * @dev vestingCreationType 0 = LockedSOV\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAuthorized {\n createVestingAddr(_tokenOwner, _amount, _cliff, _duration, 3);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createVestingAddr(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.Vesting),\n _vestingCreationType\n );\n\n emit VestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) external onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.TeamVesting),\n _vestingCreationType\n );\n\n emit TeamVestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) external onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n * @dev Calls a public getVestingAddr function with cliff and duration. This is to accomodate the existing logic for LockedSOV\n * @dev We need to use LockedSOV.changeRegistryCliffAndDuration function very judiciously\n * @dev vestingCreationType 0 - LockedSOV\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return getVestingAddr(_tokenOwner, lockedSOV.cliff(), lockedSOV.duration(), 3);\n }\n\n /**\n * @notice public function that returns vesting contract address for the given token owner, cliff, duration\n * @dev Important: Please use this instead of getVesting function\n */\n function getVestingAddr(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner, cliff, duration\n */\n function getTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @dev check if the specific vesting address is team vesting or not\n * @dev read the vestingType from vestingCreationAndTypes storage\n *\n * @param _vestingAddress address of vesting contract\n *\n * @return true for teamVesting, false for normal vesting\n */\n function isTeamVesting(address _vestingAddress) external view returns (bool) {\n return (vestingCreationAndTypes[_vestingAddress].isSet &&\n vestingCreationAndTypes[_vestingAddress].vestingType ==\n uint32(VestingType.TeamVesting));\n }\n\n /**\n * @dev setter function to register existing vesting contract to vestingCreationAndTypes storage\n * @dev need to set the function visilibty to public to support VestingCreationAndTypeDetails struct as parameter\n *\n * @param _vestingAddresses array of vesting address\n * @param _vestingCreationAndTypes array for VestingCreationAndTypeDetails struct\n */\n function registerVestingToVestingCreationAndTypes(\n address[] memory _vestingAddresses,\n VestingCreationAndTypeDetails[] memory _vestingCreationAndTypes\n ) public onlyAuthorized {\n require(_vestingAddresses.length == _vestingCreationAndTypes.length, \"Unmatched length\");\n for (uint256 i = 0; i < _vestingCreationAndTypes.length; i++) {\n VestingCreationAndTypeDetails memory _vestingCreationAndType =\n _vestingCreationAndTypes[i];\n address _vestingAddress = _vestingAddresses[i];\n\n vestingCreationAndTypes[_vestingAddress] = _vestingCreationAndType;\n\n emit VestingCreationAndTypesSet(\n _vestingAddress,\n vestingCreationAndTypes[_vestingAddress]\n );\n }\n }\n\n /**\n * @notice Internal function to deploy Vesting/Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _type the type of vesting\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _type,\n uint256 _vestingCreationType\n ) internal returns (address) {\n address vesting;\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, _type, _cliff, _duration, _vestingCreationType)\n )\n );\n if (vestings[uid].vestingAddress == address(0)) {\n if (_type == 1) {\n vesting = vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n } else {\n vesting = vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n }\n vestings[uid] = Vesting(_type, _vestingCreationType, vesting);\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vesting] = true;\n\n vestingCreationAndTypes[vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(_type),\n vestingCreationType: uint128(_vestingCreationType)\n });\n\n emit VestingCreationAndTypesSet(vesting, vestingCreationAndTypes[vesting]);\n }\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice stores the addresses of Vesting contracts from all three previous versions of Vesting Registry\n */\n function _addDeployedVestings(address _tokenOwner, uint256 _vestingCreationType) internal {\n uint256 uid;\n uint256 i = _vestingCreationType - 1;\n\n address vestingAddress = vestingRegistries[i].getVesting(_tokenOwner);\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.Vesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n _vestingCreationType,\n vestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vestingAddress] = true;\n }\n\n address teamVestingAddress = vestingRegistries[i].getTeamVesting(_tokenOwner);\n if (teamVestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(teamVestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.TeamVesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.TeamVesting),\n _vestingCreationType,\n teamVestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[teamVestingAddress] = true;\n }\n }\n\n /**\n * @notice returns all vesting details for the given token owner\n */\n function getVestingsOf(address _tokenOwner) external view returns (Vesting[] memory) {\n uint256[] memory vestingIds = vestingsOf[_tokenOwner];\n uint256 length = vestingIds.length;\n Vesting[] memory _vestings = new Vesting[](vestingIds.length);\n for (uint256 i = 0; i < length; i++) {\n _vestings[i] = vestings[vestingIds[i]];\n }\n return _vestings;\n }\n\n /**\n * @notice returns cliff and duration for Vesting & TeamVesting contracts\n */\n function getVestingDetails(address _vestingAddress)\n external\n view\n returns (uint256 cliff, uint256 duration)\n {\n VestingLogic vesting = VestingLogic(_vestingAddress);\n return (vesting.cliff(), vesting.duration());\n }\n\n /**\n * @notice returns if the address is a vesting address\n */\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return isVesting[_vestingAddress];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./VestingRegistryStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Vesting Registry Proxy contract.\n * @dev Vesting Registry contract should be upgradable, use UpgradableProxy.\n * VestingRegistryStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract VestingRegistryProxy is VestingRegistryStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Initializable.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"../../locked/LockedSOV.sol\";\nimport \"./IVestingRegistry.sol\";\n\n/**\n * @title Vesting Registry Storage Contract.\n *\n * @notice This contract is just the storage required for vesting registry.\n * It is parent of VestingRegistryProxy and VestingRegistryLogic.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\n\ncontract VestingRegistryStorage is Initializable, AdminRole {\n ///@notice the vesting factory contract\n IVestingFactory public vestingFactory;\n\n ///@notice the Locked SOV contract\n ///@dev NOTES: No need to update lockedSOV in this contract, since it might break the vestingRegistry if the new lockedSOV does not have the same value of cliff & duration.\n ILockedSOV public lockedSOV;\n\n ///@notice the list of vesting registries\n IVestingRegistry[] public vestingRegistries;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n\n ///@notice fee sharing proxy\n address public feeSharingCollector;\n\n ///@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n ///@notice Vesting details\n struct Vesting {\n uint256 vestingType;\n uint256 vestingCreationType;\n address vestingAddress;\n }\n\n ///@notice A record of vesting details for a unique id\n ///@dev vestings[uid] returns vesting data\n mapping(uint256 => Vesting) public vestings;\n\n ///@notice A record of all unique ids for a particular token owner\n ///@dev vestingsOf[tokenOwner] returns array of unique ids\n mapping(address => uint256[]) public vestingsOf;\n\n ///@notice A record of all vesting addresses\n ///@dev isVesting[address] returns if the address is a vesting address\n mapping(address => bool) public isVesting;\n\n /// @notice Store vesting creation type & vesting type information\n /// @dev it is packed into 1 single storage slot for cheaper gas usage\n struct VestingCreationAndTypeDetails {\n bool isSet;\n uint32 vestingType;\n uint128 vestingCreationType;\n }\n\n ///@notice A record of all vesting addresses with the detail\n ///@dev vestingDetail[vestingAddress] returns Vesting struct data\n ///@dev can be used to easily check the vesting type / creation type based on the vesting address itself\n mapping(address => VestingCreationAndTypeDetails) public vestingCreationAndTypes;\n}\n" + }, + "contracts/governance/Vesting/VestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\n\n/**\n * @title Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for vesting.\n * It is parent of VestingLogic and TeamVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract VestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public cliff;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 constant FOUR_WEEKS = 4 weeks;\n}\n" + }, + "contracts/interfaces/IChai.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IERC20.sol\";\n\ninterface IPot {\n function dsr() external view returns (uint256);\n\n function chi() external view returns (uint256);\n\n function rho() external view returns (uint256);\n}\n\ncontract IChai is IERC20 {\n function move(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function join(address dst, uint256 wad) external;\n\n function draw(address src, uint256 wad) external;\n\n function exit(address src, uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IConverterAMM.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IConverterAMM {\n function withdrawFees(address receiver) external returns (uint256);\n}\n" + }, + "contracts/interfaces/IERC20.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ncontract IERC20 {\n string public name;\n uint8 public decimals;\n string public symbol;\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address _who) external view returns (uint256);\n\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/interfaces/IERC777.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777Token standard as defined in the EIP.\n *\n * This contract uses the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let\n * token holders and recipients react to token movements by using setting implementers\n * for the associated interfaces in said registry. See {IERC1820Registry} and\n * {ERC1820Implementer}.\n */\ninterface IERC777 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the smallest part of the token that is not divisible. This\n * means all token operations (creation, movement and destruction) must have\n * amounts that are a multiple of this number.\n *\n * For most token contracts, this value will equal 1.\n */\n function granularity() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by an account (`owner`).\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * If send or receive hooks are registered for the caller and `recipient`,\n * the corresponding functions will be called with `data` and empty\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes calldata data\n ) external;\n\n /**\n * @dev Destroys `amount` tokens from the caller's account, reducing the\n * total supply.\n *\n * If a send hook is registered for the caller, the corresponding function\n * will be called with `data` and empty `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n */\n function burn(uint256 amount, bytes calldata data) external;\n\n /**\n * @dev Returns true if an account is an operator of `tokenHolder`.\n * Operators can send and burn tokens on behalf of their owners. All\n * accounts are their own operator.\n *\n * See {operatorSend} and {operatorBurn}.\n */\n function isOperatorFor(address operator, address tokenHolder) external view returns (bool);\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor}.\n *\n * Emits an {AuthorizedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function authorizeOperator(address operator) external;\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor} and {defaultOperators}.\n *\n * Emits a {RevokedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function revokeOperator(address operator) external;\n\n /**\n * @dev Returns the list of default operators. These accounts are operators\n * for all token holders, even if {authorizeOperator} was never called on\n * them.\n *\n * This list is immutable, but individual holders may revoke these via\n * {revokeOperator}, in which case {isOperatorFor} will return false.\n */\n function defaultOperators() external view returns (address[] memory);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must\n * be an operator of `sender`.\n *\n * If send or receive hooks are registered for `sender` and `recipient`,\n * the corresponding functions will be called with `data` and\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - `sender` cannot be the zero address.\n * - `sender` must have at least `amount` tokens.\n * - the caller must be an operator for `sender`.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n /**\n * @dev Destoys `amount` tokens from `account`, reducing the total supply.\n * The caller must be an operator of `account`.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `data` and `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n * - the caller must be an operator for `account`.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n event Sent(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Minted(\n address indexed operator,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Burned(\n address indexed operator,\n address indexed from,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event AuthorizedOperator(address indexed operator, address indexed tokenHolder);\n\n event RevokedOperator(address indexed operator, address indexed tokenHolder);\n}\n" + }, + "contracts/interfaces/IERC777Recipient.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.\n *\n * Accounts can be notified of {IERC777} tokens being sent to them by having a\n * contract implement this interface (contract holders can be their own\n * implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Recipient {\n /**\n * @dev Called by an {IERC777} token contract whenever tokens are being\n * moved or created into a registered account (`to`). The type of operation\n * is conveyed by `from` being the zero address or not.\n *\n * This call occurs _after_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the post-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/IERC777Sender.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensSender standard as defined in the EIP.\n *\n * {IERC777} Token holders can be notified of operations performed on their\n * tokens by having a contract implement this interface (contract holders can be\n * their own implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Sender {\n /**\n * @dev Called by an {IERC777} token contract whenever a registered holder's\n * (`from`) tokens are about to be moved or destroyed. The type of operation\n * is conveyed by `to` being the zero address or not.\n *\n * This call occurs _before_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the pre-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/ILoanPool.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface ILoanPool {\n function tokenPrice() external view returns (uint256 price);\n\n function borrowInterestRate() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/ILoanTokenModules.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\ninterface ILoanTokenModules {\n /** EVENT */\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /// topic: 0x9bbd2de400810774339120e2f8a2b517ed748595e944529bba8ebabf314d0591\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n\n /** INTERFACE */\n\n /** START LOAN TOKEN SETTINGS LOWER ADMIN */\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n\n function setAdmin(address _admin) external;\n\n function setPauser(address _pauser) external;\n\n function setupLoanParams(LoanParams[] calldata loanParamsList, bool areTorqueLoans) external;\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external;\n\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) external;\n\n function toggleFunctionPause(\n string calldata funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) external;\n\n function setTransactionLimits(address[] calldata addresses, uint256[] calldata limits)\n external;\n\n function changeLoanTokenNameAndSymbol(string calldata _name, string calldata _symbol) external;\n\n /** END LOAN TOKEN SETTINGS LOWER ADMIN */\n\n /** START LOAN TOKEN LOGIC STANDARD */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n address affiliateReferrer, // The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes // Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function borrowInterestRate() external view returns (uint256);\n\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n\n function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid);\n\n function checkPause(string calldata funcId) external view returns (bool isPaused);\n\n function nextBorrowInterestRate(uint256 borrowAmount) external view returns (uint256);\n\n function totalAssetBorrow() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes calldata /// loanDataBytes: arbitrary order data (for future use).\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n );\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function setLiquidityMiningAddress(address LMAddress) external;\n\n function getLiquidityMiningAddress() external view returns (address);\n\n function setStakingContractAddress(address _stakingContractAddress) external;\n\n function getStakingContractAddress() external view returns (address);\n\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n external\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n );\n\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 depositAmount);\n\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 borrowAmount);\n\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) external view;\n\n function getMaxEscrowAmount(uint256 leverageAmount)\n external\n view\n returns (uint256 maxEscrowAmount);\n\n function checkpointPrice(address _user) external view returns (uint256 price);\n\n function assetBalanceOf(address _owner) external view returns (uint256);\n\n function profitOf(address user) external view returns (int256);\n\n function tokenPrice() external view returns (uint256 price);\n\n function avgBorrowInterestRate() external view returns (uint256);\n\n function supplyInterestRate() external view returns (uint256);\n\n function nextSupplyInterestRate(uint256 supplyAmount) external view returns (uint256);\n\n function totalSupplyInterestRate(uint256 assetSupply) external view returns (uint256);\n\n function loanTokenAddress() external view returns (address);\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n external\n view\n returns (uint256, uint256);\n\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external;\n\n /** START LOAN TOKEN BASE */\n function initialPrice() external view returns (uint256);\n\n /** START LOAN TOKEN LOGIC LM */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external returns (uint256 minted);\n\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 redeemed);\n\n /** START LOAN TOKEN LOGIC WRBTC */\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n returns (uint256 mintAmount);\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function marketLiquidity() external view returns (uint256);\n\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n external\n view\n returns (uint256);\n\n /** START LOAN TOKEN LOGIC STORAGE */\n function pauser() external view returns (address);\n\n function liquidityMiningAddress() external view returns (address);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n /** START ADVANCED TOKEN */\n function approve(address _spender, uint256 _value) external returns (bool);\n\n /** START ADVANCED TOKEN STORAGE */\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function balanceOf(address _owner) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function loanParamsIds(uint256) external view returns (bytes32);\n}\n" + }, + "contracts/interfaces/ISovryn.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\npragma experimental ABIEncoderV2;\n//TODO: stored in ./interfaces only while brownie isn't removed\n//TODO: move to contracts/interfaces after with brownie is removed\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\ncontract ISovryn is\n State,\n ProtocolSettingsEvents,\n LoanSettingsEvents,\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n LoanClosingsEvents,\n SwapsEvents,\n AffiliatesEvents,\n FeesEvents\n{\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n ////// Protocol //////\n\n function replaceContract(address target) external;\n\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\n\n function getTarget(string calldata sig) external view returns (address);\n\n ////// Protocol Settings //////\n\n function setSovrynProtocolAddress(address newProtocolAddress) external;\n\n function setSOVTokenAddress(address newSovTokenAddress) external;\n\n function setLockedSOVAddress(address newSOVLockedAddress) external;\n\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\n\n function setPriceFeedContract(address newContract) external;\n\n function setSwapsImplContract(address newContract) external;\n\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\n\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\n\n function setLendingFeePercent(uint256 newValue) external;\n\n function setTradingFeePercent(uint256 newValue) external;\n\n function setBorrowingFeePercent(uint256 newValue) external;\n\n function setSwapExternalFeePercent(uint256 newValue) external;\n\n function setAffiliateFeePercent(uint256 newValue) external;\n\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\n\n function setLiquidationIncentivePercent(uint256 newAmount) external;\n\n function setMaxDisagreement(uint256 newAmount) external;\n\n function setSourceBuffer(uint256 newAmount) external;\n\n function setMaxSwapSize(uint256 newAmount) external;\n\n function setFeesController(address newController) external;\n\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n returns (address, bool);\n\n function depositProtocolToken(uint256 amount) external;\n\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function setWrbtcToken(address wrbtcTokenAddress) external;\n\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\n\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\n\n function setRolloverBaseReward(uint256 transactionCost) external;\n\n function setRebatePercent(uint256 rebatePercent) external;\n\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external;\n\n function getSpecialRebates(address sourceToken, address destToken)\n external\n view\n returns (uint256 specialRebatesPercent);\n\n function togglePaused(bool paused) external;\n\n function isProtocolPaused() external view returns (bool);\n\n ////// SwapsImplSovrynSwapModule //////\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (address);\n\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\n\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn);\n\n ////// Loan Settings //////\n\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function getLoanParams(bytes32[] calldata loanParamsIdList)\n external\n view\n returns (LoanParams[] memory loanParamsList);\n\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n\n ////// Loan Openings //////\n\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external;\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n ////// Loan Closings //////\n\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n );\n\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata loanDataBytes\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n ////// Loan Maintenance //////\n\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount // must match msg.value if ether is sent\n ) external payable;\n\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 actualWithdrawAmount);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n );\n\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; // collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\n\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\n\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external returns (uint256 secondsExtended);\n\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 secondsReduced);\n\n ////// Swaps External //////\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view;\n\n ////// Affiliates Module //////\n\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\n\n function setUserNotFirstTradeFlag(address user) external;\n\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\n\n function getReferralsList(address referrer) external view returns (address[] memory refList);\n\n function getAffiliatesReferrerBalances(address referrer)\n external\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\n\n function getAffiliatesReferrerTokensList(address referrer)\n external\n view\n returns (address[] memory tokensList);\n\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n external\n view\n returns (uint256);\n\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) external;\n\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\n\n function getProtocolAddress() external view returns (address);\n\n function getSovTokenAddress() external view returns (address);\n\n function getLockedSOVAddress() external view returns (address);\n\n function getFeeRebatePercent() external view returns (uint256);\n\n function getMinReferralsToPayout() external view returns (uint256);\n\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\n\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\n\n function getAffiliateTradingTokenFeePercent()\n external\n view\n returns (uint256 affiliateTradingTokenFeePercent);\n\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount);\n\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\n\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\n\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\n\n function getDedicatedSOVRebate() external view returns (uint256);\n\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\n\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory);\n\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\n\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external;\n\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\n\n function setAdmin(address newAdmin) external;\n\n function getAdmin() external view returns (address);\n\n function setPauser(address newPauser) external;\n\n function getPauser() external view returns (address);\n}\n" + }, + "contracts/interfaces/IWrbtc.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface IWrbtc {\n function deposit() external payable;\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IWrbtcERC20.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IWrbtc.sol\";\nimport \"./IERC20.sol\";\n\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\n" + }, + "contracts/locked/ILockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title The Locked SOV Interface.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This interface is an incomplete yet useful for future migration of LockedSOV Contract.\n * @dev Only use it if you know what you are doing.\n */\ninterface ILockedSOV {\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external;\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external;\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external;\n\n function cliff() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function getLockedBalance(address _addr) external view returns (uint256 _balance);\n\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance);\n}\n" + }, + "contracts/locked/LockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../governance/Vesting/VestingRegistry.sol\";\nimport \"../governance/Vesting/VestingLogic.sol\";\nimport \"./ILockedSOV.sol\";\n\n/**\n * @title The Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This contract is used to receive reward from other contracts, Create Vesting and Stake Tokens.\n */\ncontract LockedSOV is ILockedSOV {\n using SafeMath for uint256;\n\n uint256 public constant MAX_BASIS_POINT = 10000;\n uint256 public constant MAX_DURATION = 37;\n\n /* Storage */\n\n /// @notice True if the migration to a new Locked SOV Contract has started.\n bool public migration;\n\n /// @notice The cliff is the time period after which the tokens begin to unlock.\n uint256 public cliff;\n /// @notice The duration is the time period after all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n /// @notice The Vesting registry contract.\n VestingRegistry public vestingRegistry;\n /// @notice The New (Future) Locked SOV.\n ILockedSOV public newLockedSOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) private lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) private unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) private isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /// @notice Emitted when Vesting Registry, Duration and/or Cliff is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vestingRegistry The Vesting Registry Contract.\n /// @param _cliff The time period after which the tokens begin to unlock.\n /// @param _duration The time period after all tokens will have been unlocked.\n event RegistryCliffAndDurationUpdated(\n address indexed _initiator,\n address indexed _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n );\n\n /// @notice Emitted when a new deposit is made.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user to whose un/locked balance a new deposit was made.\n /// @param _sovAmount The amount of SOV to be added to the un/locked balance.\n /// @param _basisPoint The % (in Basis Point) which determines how much will be unlocked immediately.\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n /// @notice Emitted when a user withdraws the fund.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _sovAmount The amount of SOV withdrawn from the unlocked balance.\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n /// @notice Emitted when a user creates a vesting for himself.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _vesting The Vesting Contract.\n event VestingCreated(\n address indexed _initiator,\n address indexed _userAddress,\n address indexed _vesting\n );\n\n /// @notice Emitted when a user stakes tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vesting The Vesting Contract.\n /// @param _amount The amount of locked tokens staked by the user.\n event TokenStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /// @notice Emitted when an admin initiates a migration to new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedSOV The address of the new Locked SOV Contract.\n event MigrationStarted(address indexed _initiator, address indexed _newLockedSOV);\n\n /// @notice Emitted when a user initiates the transfer to a new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of locked tokens to transfer from this contract to the new one.\n event UserTransfered(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n modifier migrationAllowed {\n require(migration, \"Migration has not yet started.\");\n _;\n }\n\n /* Constructor */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV Token Address.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @param _admins The list of Admins to be added.\n */\n constructor(\n address _SOV,\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration,\n address[] memory _admins\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_vestingRegistry != address(0), \"Vesting registry address is invalid.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n SOV = IERC20(_SOV);\n vestingRegistry = VestingRegistry(_vestingRegistry);\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /* Public or External Functions */\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n * @dev Only callable by an Admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address.\");\n require(!isAdmin[_newAdmin], \"Address is already admin.\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n * @dev Only callable by an Admin.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin.\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice The function to update the Vesting Registry, Duration and Cliff.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @dev IMPORTANT 1: You have to change Vesting Registry if you want to change Duration and/or Cliff.\n * IMPORTANT 2: `_cliff` and `_duration` is multiplied by 4 weeks in this function.\n */\n function changeRegistryCliffAndDuration(\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAdmin {\n require(\n address(vestingRegistry) != _vestingRegistry,\n \"Vesting Registry has to be different for changing duration and cliff.\"\n );\n /// If duration is also zero, then it is similar to Unlocked SOV.\n require(_duration != 0, \"Duration cannot be zero.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n vestingRegistry = VestingRegistry(_vestingRegistry);\n\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n emit RegistryCliffAndDurationUpdated(msg.sender, _vestingRegistry, _cliff, _duration);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // MAX_BASIS_POINT is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < MAX_BASIS_POINT, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(MAX_BASIS_POINT);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice A function to withdraw the unlocked balance.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdraw(address _receiverAddress) public {\n _withdraw(msg.sender, _receiverAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n /**\n * @notice Creates vesting if not already created and Stakes tokens for a user.\n * @dev Only use this function if the `duration` is small.\n */\n function createVestingAndStake() public {\n _createVestingAndStake(msg.sender);\n }\n\n function _createVestingAndStake(address _sender) private {\n address vestingAddr = _getVesting(_sender);\n\n if (vestingAddr == address(0)) {\n vestingAddr = _createVesting(_sender);\n }\n\n _stakeTokens(_sender, vestingAddr);\n }\n\n /**\n * @notice Creates vesting contract (if it hasn't been created yet) for the calling user.\n * @return _vestingAddress The New Vesting Contract Created.\n */\n function createVesting() public returns (address _vestingAddress) {\n _vestingAddress = _createVesting(msg.sender);\n }\n\n /**\n * @notice Stakes tokens for a user who already have a vesting created.\n * @dev The user should already have a vesting created, else this function will throw error.\n */\n function stakeTokens() public {\n VestingLogic vesting = VestingLogic(_getVesting(msg.sender));\n\n require(\n cliff == vesting.cliff() && duration == vesting.duration(),\n \"Wrong Vesting Schedule.\"\n );\n\n _stakeTokens(msg.sender, address(vesting));\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdrawAndStakeTokens(address _receiverAddress) external {\n _withdraw(msg.sender, _receiverAddress);\n _createVestingAndStake(msg.sender);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n /**\n * @notice Function to start the process of migration to new contract.\n * @param _newLockedSOV The new locked sov contract address.\n */\n function startMigration(address _newLockedSOV) external onlyAdmin {\n require(_newLockedSOV != address(0), \"New Locked SOV Address is Invalid.\");\n newLockedSOV = ILockedSOV(_newLockedSOV);\n SOV.approve(_newLockedSOV, SOV.balanceOf(address(this)));\n migration = true;\n\n emit MigrationStarted(msg.sender, _newLockedSOV);\n }\n\n /**\n * @notice Function to transfer the locked balance from this contract to new LockedSOV Contract.\n * @dev Address is not specified to discourage selling lockedSOV to other address.\n */\n function transfer() external migrationAllowed {\n uint256 amount = lockedBalances[msg.sender];\n lockedBalances[msg.sender] = 0;\n\n newLockedSOV.depositSOV(msg.sender, amount);\n\n emit UserTransfered(msg.sender, amount);\n }\n\n /* Internal Functions */\n\n /**\n * @notice Creates a Vesting Contract for a user.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n * @dev Does not do anything if Vesting Contract was already created.\n */\n function _createVesting(address _tokenOwner) internal returns (address _vestingAddress) {\n /// Here zero is given in place of amount, as amount is not really used in `vestingRegistry.createVesting()`.\n vestingRegistry.createVesting(_tokenOwner, 0, cliff, duration);\n _vestingAddress = _getVesting(_tokenOwner);\n emit VestingCreated(msg.sender, _tokenOwner, _vestingAddress);\n }\n\n /**\n * @notice Returns the Vesting Contract Address.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n */\n function _getVesting(address _tokenOwner) internal view returns (address _vestingAddress) {\n return vestingRegistry.getVesting(_tokenOwner);\n }\n\n /**\n * @notice Stakes the tokens in a particular vesting contract.\n * @param _vesting The Vesting Contract Address.\n */\n function _stakeTokens(address _sender, address _vesting) internal {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n require(SOV.approve(_vesting, amount), \"Approve failed.\");\n VestingLogic(_vesting).stakeTokens(amount);\n\n emit TokenStaked(_sender, _vesting, amount);\n }\n\n /* Getter or Read Functions */\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) external view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n\n /**\n * @notice The function to check is an address is admin or not.\n * @param _addr The address of the user to check the admin status.\n * @return _status True if admin, False otherwise.\n */\n function adminStatus(address _addr) external view returns (bool _status) {\n return isAdmin[_addr];\n }\n}\n" + }, + "contracts/mixins/EnumerableAddressSet.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Based on Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * As of v2.5.0, only `address` sets are supported.\n *\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\n *\n * _Available since v2.5.0._\n */\nlibrary EnumerableAddressSet {\n struct AddressSet {\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(address => uint256) index;\n address[] values;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n * Returns false if the value was already in the set.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n * Returns false if the value was not present in the set.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n // If the element we're deleting is the last one, we can just remove it without doing a swap\n if (lastIndex != toDeleteIndex) {\n address lastValue = set.values[lastIndex];\n\n // Move the last value to the index where the deleted value is\n set.values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n // Delete the index entry for the deleted value\n delete set.index[value];\n\n // Delete the old entry for the moved value\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns an array with all values in the set. O(N).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\n address[] memory output = new address[](set.values.length);\n for (uint256 i; i < set.values.length; i++) {\n output[i] = set.values[i];\n }\n return output;\n }\n\n /**\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n \n * @param start start index of chunk\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\n */\n function enumerateChunk(\n AddressSet storage set,\n uint256 start,\n uint256 count\n ) internal view returns (address[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = (set.values.length < end || count == 0) ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new address[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @dev Returns the number of elements on the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /** @dev Returns the element stored at position `index` in the set. O(1).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes32Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\n * */\nlibrary EnumerableBytes32Set {\n struct Bytes32Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes32 => uint256) index;\n bytes32[] values;\n }\n\n /**\n * @notice Add an address value to a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to add.\n *\n * @return False if the value was already in the set.\n */\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return addBytes32(set, value);\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove an address value from a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to remove.\n *\n * @return False if the address was not present in the set.\n */\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return removeBytes32(set, value);\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function containsAddress(Bytes32Set storage set, address addrvalue)\n internal\n view\n returns (bool)\n {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes32Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes32[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes32[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes4Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`.\n * */\nlibrary EnumerableBytes4Set {\n struct Bytes4Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes4 => uint256) index;\n bytes4[] values;\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes4 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes4Set storage set, bytes4 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes4Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes4[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes4[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes4Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes4Set storage set, uint256 index) internal view returns (bytes4) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/FeesHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ISovryn.sol\";\nimport \"../core/objects/LoanParamsStruct.sol\";\n\n/**\n * @title The Fees Helper contract.\n *\n * This contract calculates and pays lending/borrow fees and rewards.\n * */\ncontract FeesHelper is State, FeesEvents {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Calculate trading fee.\n * @param feeTokenAmount The amount of tokens to trade.\n * @return The fee of the trade.\n * */\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\n }\n\n /**\n * @notice Calculate swap external fee.\n * @param feeTokenAmount The amount of token to swap.\n * @return The fee of the swap.\n */\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\n }\n\n /*\n\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - tradingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);\n\t}*/\n\n /**\n * @notice Calculate the loan origination fee.\n * @param feeTokenAmount The amount of tokens to borrow.\n * @return The fee of the loan.\n * */\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\n /*\n\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - borrowingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);*/\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\n *\n * @param referrer The affiliate referrer address to send the reward to.\n * @param trader The account that performs this trade.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n *\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\n * */\n function _payTradingFeeToAffiliate(\n address referrer,\n address trader,\n address feeToken,\n uint256 tradingFee\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\n address(this)\n )\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n * */\n function _payTradingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 tradingFee\n ) internal {\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\n if (tradingFee != 0) {\n if (affiliatesUserReferrer[user] != address(0)) {\n _payTradingFeeToAffiliate(\n affiliatesUserReferrer[user],\n user,\n feeToken,\n protocolTradingFee\n );\n protocolTradingFee = (\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\n )\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\n }\n\n /// Increase the storage variable keeping track of the accumulated fees.\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\n protocolTradingFee\n );\n\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\n }\n }\n\n /**\n * @notice Settle the borrowing fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the borrowig fee is paid.\n * @param borrowingFee The height of the fee.\n * */\n function _payBorrowingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 borrowingFee\n ) internal {\n if (borrowingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\n\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\n }\n }\n\n /**\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\n * @param user The address to send the reward to.\n * @param feeToken The address of the token in which the lending fee is paid.\n * @param lendingFee The height of the fee.\n * */\n function _payLendingFee(\n address user,\n address feeToken,\n uint256 lendingFee\n ) internal {\n if (lendingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\n\n emit PayLendingFee(user, feeToken, lendingFee);\n\n //// NOTE: Lenders do not receive a fee reward ////\n }\n }\n\n /// Settle and pay borrowers based on the fees generated by their interest payments.\n function _settleFeeRewardForInterestExpense(\n LoanInterest storage loanInterestLocal,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n address user,\n uint256 interestTime\n ) internal {\n /// This represents the fee generated by a borrower's interest payment.\n uint256 interestExpenseFee =\n interestTime\n .sub(loanInterestLocal.updatedTimestamp)\n .mul(loanInterestLocal.owedPerDay)\n .mul(lendingFeePercent)\n .div(1 days * 10**20);\n\n loanInterestLocal.updatedTimestamp = interestTime;\n\n if (interestExpenseFee != 0) {\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\n }\n }\n\n /**\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associeated loan - used for logging only.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * */\n function _payFeeReward(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 feeAmount\n ) internal {\n uint256 rewardAmount;\n uint256 _feeRebatePercent = feeRebatePercent;\n address _priceFeeds = priceFeeds;\n\n if (specialRebates[feeToken][feeTokenPair] > 0) {\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\n }\n\n /// Note: this should be refactored.\n /// Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\n feeAmount.mul(_feeRebatePercent).div(10**20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n // Check the dedicated SOV that is used to pay trading rebate rewards\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"deposit(address,uint256,uint256)\",\n user,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n )\n );\n\n if (success) {\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\n\n emit EarnReward(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n } else {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n }\n}\n" + }, + "contracts/mixins/InterestUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"./FeesHelper.sol\";\n\n/**\n * @title The Interest User contract.\n *\n * This contract pays loan interests.\n * */\ncontract InterestUser is VaultController, FeesHelper {\n using SafeERC20 for IERC20;\n\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n /**\n * @notice Internal function to pay interest of a loan.\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * */\n function _payInterest(address lender, address interestToken) internal {\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\n\n uint256 interestOwedNow = 0;\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\n interestOwedNow = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(1 days);\n\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n\n if (interestOwedNow > lenderInterestLocal.owedTotal)\n interestOwedNow = lenderInterestLocal.owedTotal;\n\n if (interestOwedNow != 0) {\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\n\n _payInterestTransfer(lender, interestToken, interestOwedNow);\n }\n } else {\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n }\n }\n\n /**\n * @notice Internal function to transfer tokens for the interest of a loan.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * @param interestOwedNow The amount of interest to pay.\n * */\n function _payInterestTransfer(\n address lender,\n address interestToken,\n uint256 interestOwedNow\n ) internal {\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\n /// TODO: refactor: data incapsulation violation and DRY design principles\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\n\n _payLendingFee(lender, interestToken, lendingFee);\n\n /// Transfers the interest to the lender, less the interest fee.\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\n\n /// Event Log\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\n }\n}\n" + }, + "contracts/mixins/LiquidationHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\n/**\n * @title The Liquidation Helper contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract computes the liquidation amount.\n * */\ncontract LiquidationHelper is State {\n /**\n * @notice Compute how much needs to be liquidated in order to restore the\n * desired margin (maintenance + 5%).\n *\n * @param principal The total borrowed amount (in loan tokens).\n * @param collateral The collateral (in collateral tokens).\n * @param currentMargin The current margin.\n * @param maintenanceMargin The maintenance (minimum) margin.\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n *\n * @return maxLiquidatable The collateral you can get liquidating.\n * @return maxSeizable The loan you available for liquidation.\n * @return incentivePercent The discount on collateral.\n * */\n function _getLiquidationAmounts(\n uint256 principal,\n uint256 collateral,\n uint256 currentMargin,\n uint256 maintenanceMargin,\n uint256 collateralToLoanRate\n )\n internal\n view\n returns (\n uint256 maxLiquidatable,\n uint256 maxSeizable,\n uint256 incentivePercent\n )\n {\n incentivePercent = liquidationIncentivePercent;\n if (currentMargin > maintenanceMargin || collateralToLoanRate == 0) {\n return (maxLiquidatable, maxSeizable, incentivePercent);\n } else if (currentMargin <= incentivePercent) {\n return (principal, collateral, currentMargin);\n }\n\n /// 5 percentage points above maintenance.\n uint256 desiredMargin = maintenanceMargin.add(5 ether);\n\n /// maxLiquidatable = ((1 + desiredMargin)*principal - collateralToLoanRate*collateral) / (desiredMargin - 0.05)\n maxLiquidatable = desiredMargin.add(10**20).mul(principal).div(10**20);\n maxLiquidatable = maxLiquidatable.sub(collateral.mul(collateralToLoanRate).div(10**18));\n maxLiquidatable = maxLiquidatable.mul(10**20).div(desiredMargin.sub(incentivePercent));\n if (maxLiquidatable > principal) {\n maxLiquidatable = principal;\n }\n\n /// maxSeizable = maxLiquidatable * (1 + incentivePercent) / collateralToLoanRate\n maxSeizable = maxLiquidatable.mul(incentivePercent.add(10**20));\n maxSeizable = maxSeizable.div(collateralToLoanRate).div(100);\n if (maxSeizable > collateral) {\n maxSeizable = collateral;\n }\n\n return (maxLiquidatable, maxSeizable, incentivePercent);\n }\n}\n" + }, + "contracts/mixins/ModuleCommonFunctionalities.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\ncontract ModuleCommonFunctionalities is State {\n modifier whenNotPaused() {\n require(!pause, \"Paused\");\n _;\n }\n}\n" + }, + "contracts/mixins/ProtocolTokenUser.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\n\n/**\n * @title The Protocol Token User contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to withdraw protocol tokens.\n * */\ncontract ProtocolTokenUser is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Internal function to withdraw an amount of protocol tokens from this contract.\n *\n * @param receiver The address of the recipient.\n * @param amount The amount of tokens to withdraw.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function _withdrawProtocolToken(address receiver, uint256 amount)\n internal\n returns (address, bool)\n {\n uint256 withdrawAmount = amount;\n\n uint256 tokenBalance = protocolTokenHeld;\n if (withdrawAmount > tokenBalance) {\n withdrawAmount = tokenBalance;\n }\n if (withdrawAmount == 0) {\n return (protocolTokenAddress, false);\n }\n\n protocolTokenHeld = tokenBalance.sub(withdrawAmount);\n\n IERC20(protocolTokenAddress).safeTransfer(receiver, withdrawAmount);\n\n return (protocolTokenAddress, true);\n }\n}\n" + }, + "contracts/mixins/RewardHelper.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title The Reward Helper contract.\n * @notice This contract calculates the reward for rollover transactions.\n *\n * A rollover is a renewal of a deposit. Instead of liquidating a deposit\n * on maturity, you can roll it over into a new deposit. The outstanding\n * principal of the old deposit is rolled over with or without the interest\n * outstanding on it.\n * */\ncontract RewardHelper is State {\n using SafeMath for uint256;\n\n /**\n * @notice Calculate the reward of a rollover transaction.\n *\n * @param collateralToken The address of the collateral token.\n * @param loanToken The address of the loan token.\n * @param positionSize The amount of value of the position.\n *\n * @return The base fee + the flex fee.\n */\n function _getRolloverReward(\n address collateralToken,\n address loanToken,\n uint256 positionSize\n ) internal view returns (uint256 reward) {\n uint256 positionSizeInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(loanToken, collateralToken, positionSize);\n uint256 rolloverBaseRewardInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(\n address(wrbtcToken),\n collateralToken,\n rolloverBaseReward\n );\n\n return\n rolloverBaseRewardInCollateralToken\n .mul(2) /// baseFee\n .add(positionSizeInCollateralToken.mul(rolloverFlexFeePercent).div(10**20)); /// flexFee = 0.1% of position size\n }\n}\n" + }, + "contracts/mixins/VaultController.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\n\n/**\n * @title The Vault Controller contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to deposit and withdraw wrBTC and\n * other tokens from the vault.\n * */\ncontract VaultController is State {\n using SafeERC20 for IERC20;\n\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\n\n /**\n * @notice Deposit wrBTC into the vault.\n *\n * @param from The address of the account paying the deposit.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherDeposit(address from, uint256 value) internal {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n _wrbtcToken.deposit.value(value)();\n\n emit VaultDeposit(address(_wrbtcToken), from, value);\n }\n\n /**\n * @notice Withdraw wrBTC from the vault.\n *\n * @param to The address of the recipient.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherWithdraw(address to, uint256 value) internal {\n if (value != 0) {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n uint256 balance = address(this).balance;\n if (value > balance) {\n _wrbtcToken.withdraw(value - balance);\n }\n Address.sendValue(to, value);\n\n emit VaultWithdraw(address(_wrbtcToken), to, value);\n }\n }\n\n /**\n * @notice Deposit tokens into the vault.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying the deposit.\n * @param value The amount of tokens to transfer.\n */\n function vaultDeposit(\n address token,\n address from,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransferFrom(from, address(this), value);\n\n emit VaultDeposit(token, from, value);\n }\n }\n\n /**\n * @notice Withdraw tokens from the vault.\n *\n * @param token The address of the token instance.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultWithdraw(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransfer(to, value);\n\n emit VaultWithdraw(token, to, value);\n }\n }\n\n /**\n * @notice Transfer tokens from an account into another one.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultTransfer(\n address token,\n address from,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n if (from == address(this)) {\n IERC20(token).safeTransfer(to, value);\n } else {\n IERC20(token).safeTransferFrom(from, to, value);\n }\n }\n }\n\n /**\n * @notice Approve an allowance of tokens to be spent by an account.\n *\n * @param token The address of the token instance.\n * @param to The address of the spender.\n * @param value The amount of tokens to allow.\n */\n function vaultApprove(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\n IERC20(token).safeApprove(to, 0);\n }\n IERC20(token).safeApprove(to, value);\n }\n}\n" + }, + "contracts/mockup/BlockMockUp.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title Used to get and set mock block number.\n */\ncontract BlockMockUp {\n uint256 public blockNum;\n\n /**\n * @notice To get the `blockNum`.\n * @return _blockNum The block number.\n */\n function getBlockNum() public view returns (uint256 _blockNum) {\n return blockNum;\n }\n\n /**\n * @notice To set the `blockNum`.\n * @param _blockNum The block number.\n */\n function setBlockNum(uint256 _blockNum) public {\n blockNum = _blockNum;\n }\n}\n" + }, + "contracts/mockup/FeeSharingCollectorMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/FeeSharingCollector/FeeSharingCollector.sol\";\n\ncontract FeeSharingCollectorMockup is FeeSharingCollector {\n struct TestData {\n address loanPoolToken;\n uint32 maxCheckpoints;\n address receiver;\n }\n\n TestData public testData;\n\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n testData = TestData(_token, _maxCheckpoints, _receiver);\n }\n\n function trueWithdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function addCheckPoint(address loanPoolToken, uint256 poolTokenAmount) public {\n uint96 amount96 =\n safe96(\n poolTokenAmount,\n \"FeeSharingCollectorProxy::withdrawFees: pool token amount exceeds 96 bits\"\n );\n _addCheckpoint(loanPoolToken, amount96);\n }\n\n function setTotalTokenCheckpoints(address _token, uint256 qty) public {\n totalTokenCheckpoints[_token] = qty;\n }\n\n function setUserProcessedCheckpoints(\n address _user,\n address _token,\n uint256 num\n ) public {\n processedCheckpoints[_user][_token] = num;\n }\n\n function getFullAccumulatedFees(\n address _user,\n address _token,\n uint32 _maxCheckpoints\n ) public view returns (uint256 amount, uint256 end) {\n (amount, end) = _getAccumulatedFees(_user, _token, 0, _maxCheckpoints);\n }\n\n function endOfRangeWithZeroMaxCheckpoint(address _token) public view returns (uint256) {\n return _getEndOfRange(0, _token, 0);\n }\n\n function getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) public view returns (uint256 _tokenAmount, uint256 _endToken) {\n return _getRBTCBalance(_token, _user, _maxCheckpoints);\n }\n\n function testWithdrawReentrancy(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n}\n" + }, + "contracts/mockup/GovernorAlphaMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/GovernorAlpha.sol\";\n\ncontract GovernorAlphaMockup is GovernorAlpha {\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 quorumVotes_,\n uint96 _minPercentageVotes\n ) public GovernorAlpha(timelock_, staking_, guardian_, quorumVotes_, _minPercentageVotes) {}\n\n function votingPeriod() public pure returns (uint256) {\n return 10;\n }\n\n function queueProposals(uint256[] calldata proposalIds) external {\n for (uint256 i = 0; i < proposalIds.length; i++) {\n queue(proposalIds[i]);\n }\n }\n}\n" + }, + "contracts/mockup/LiquidityMiningMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract LiquidityMiningMockup is LiquidityMining {\n function getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n public\n view\n returns (uint256)\n {\n return _getPassedBlocksWithBonusMultiplier(_from, _to);\n }\n\n function getPoolAccumulatedReward(address _poolToken) public view returns (uint256, uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n return _getPoolAccumulatedReward(pool);\n }\n}\n" + }, + "contracts/mockup/LiquidityPoolV1ConverterMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/IERC20.sol\";\n\ncontract LiquidityPoolV1ConverterMockup {\n IERC20[] public reserveTokens;\n IERC20 wrbtcToken;\n uint256 totalFeeMockupValue;\n address feesController;\n\n constructor(IERC20 _token0, IERC20 _token1) public {\n reserveTokens.push(_token0);\n reserveTokens.push(_token1);\n }\n\n function setFeesController(address _feesController) public {\n feesController = _feesController;\n }\n\n function setWrbtcToken(IERC20 _wrbtcToken) public {\n wrbtcToken = _wrbtcToken;\n }\n\n function setTotalFeeMockupValue(uint256 _totalFeeMockupValue) public {\n totalFeeMockupValue = _totalFeeMockupValue;\n }\n\n function withdrawFees(address _receiver) external returns (uint256) {\n require(msg.sender == feesController, \"unauthorized\");\n\n // transfer wrbtc\n wrbtcToken.transfer(_receiver, totalFeeMockupValue);\n return totalFeeMockupValue;\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/LoanClosingsWith.sol\";\n\ncontract LoanClosingsWithMockup is LoanClosingsWith {\n function worthTheTransfer(address, uint256) internal returns (bool) {\n return true;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithoutInvariantCheck.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanClosingsWithMockup.sol\";\n\ncontract LoanClosingsWithoutInvariantCheck is LoanClosingsWithMockup {\n /** Override the modifier of invariant check so that we can test the shared reentrancy guard */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n _;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicLMMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\n\ncontract LoanTokenLogicLMMockup is LoanTokenLogicLM {\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n returns (uint256 loanAmountPaid)\n {\n _callOptionalReturn(\n 0x2c34D66a5ca8686330e100372Eb3FDFB5aEECD0B, //Random EOA for testing\n abi.encodeWithSelector(IERC20(receiver).transfer.selector, receiver, burnAmount),\n \"error\"\n );\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicV2Mockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicV1Mockup is LoanTokenLogicStandard {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](27);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n // res[31] = this.totalSupply.selector;\n res[25] = this.balanceOf.selector;\n res[26] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n\ncontract LoanTokenLogicV2Mockup is LoanTokenLogicStandard {\n function testNewFunction() external pure returns (bool) {\n return true;\n }\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](29);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mockup\n res[28] = this.testNewFunction.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/mockup/lockedSOVFailedMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An interface for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete interface of the Locked SOV Contract.\n */\ncontract LockedSOVFailedMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The user balances.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n revert(\"For testing purposes\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/LockedSOVMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An mockup for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete mockup of the Locked SOV Contract.\n */\ncontract LockedSOVMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n event TokensStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // 10000 is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < 10000, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(10000);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n function _createVestingAndStake(address _sender) private {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n emit TokensStaked(_sender, address(0), amount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/MockAffiliates.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/Affiliates.sol\";\n\ncontract MockAffiliates is Affiliates {\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n }\n}\n" + }, + "contracts/mockup/MockFourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/Vesting/fouryear/FourYearVestingLogic.sol\";\n\ncontract MockFourYearVestingLogic is FourYearVestingLogic {\n /**\n * @notice gets duration left\n */\n function getDurationLeft() external view returns (uint256) {\n return durationLeft;\n }\n}\n" + }, + "contracts/mockup/MockLoanTokenLogic.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogic is LoanTokenLogic {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](31);\n\n // Loan Token Logic\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mock\n res[28] = this.setAffiliatesReferrer.selector;\n res[29] = this.setUserNotFirstTradeFlag.selector;\n res[30] = this.getMarginBorrowAmountAndRate.selector;\n\n return (res, stringToBytes32(\"MockLoanTokenLogic\"));\n }\n\n function setAffiliatesReferrer(address user, address referrer) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(user, referrer);\n }\n\n function setUserNotFirstTradeFlag(address user) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(user);\n }\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n\n /*function initialize(address target) external onlyOwner {\n\t\t_setTarget(this.setAffiliatesUserReferrer.selector, target);\n\t}*/\n}\n\ncontract ILoanTokenModulesMock is ILoanTokenModules {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user) external;\n}\n" + }, + "contracts/mockup/MockLoanTokenLogicLM.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogicLM is LoanTokenLogicLM {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n /** LoanTokenLogicLM function signature */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\"));\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\"));\n res[2] = bytes4(keccak256(\"burn(address,uint256)\"));\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\"));\n\n return (res, stringToBytes32(\"MockLoanTokenLogicLM\"));\n }\n}\n" + }, + "contracts/mockup/modules/IWeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract IWeightedStakingModuleMockup {\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) external;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) external;\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external;\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) external;\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/mockup/modules/StakingModuleBlockMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/StakingGovernanceModule.sol\";\nimport \"../../governance/Staking/modules/StakingStakeModule.sol\";\nimport \"../../governance/Staking/modules/StakingVestingModule.sol\";\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../BlockMockUp.sol\";\n\ncontract StakingModuleBlockMockup is\n IFunctionsList,\n StakingGovernanceModule,\n StakingStakeModule,\n StakingVestingModule,\n WeightedStakingModule\n{\n uint96 public priorWeightedStake;\n mapping(uint256 => uint96) public priorWeightedStakeAtBlock;\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n function balanceOf_MultipliedByTwo(address account) external view returns (uint256) {\n return this.balanceOf(account) * 2;\n }\n\n uint96 priorTotalVotingPower;\n\n function MOCK_priorTotalVotingPower(uint96 _priorTotalVotingPower) public {\n priorTotalVotingPower = _priorTotalVotingPower;\n }\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n return\n priorTotalVotingPower != 0\n ? priorTotalVotingPower\n : super.getPriorTotalVotingPower(blockNumber, time);\n }\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) public view returns (bool) {\n bytes32 codeHash = _getCodeHash(stakerAddress);\n return vestingCodeHashes[codeHash];\n }\n\n function getPriorWeightedStakeAtBlock(uint256 blockNum) public view returns (uint256) {\n return uint256(priorWeightedStakeAtBlock[blockNum]);\n }\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n // StakingGovernanceModule\n bytes4[] memory functionsList = new bytes4[](31);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n\n // StakingStakeModule\n functionsList[6] = this.stake.selector;\n functionsList[7] = this.stakeWithApproval.selector;\n functionsList[8] = this.extendStakingDuration.selector;\n functionsList[9] = this.stakesBySchedule.selector;\n functionsList[10] = this.stakeBySchedule.selector;\n functionsList[11] = this.balanceOf.selector;\n functionsList[12] = this.getCurrentStakedUntil.selector;\n functionsList[13] = this.getStakes.selector;\n functionsList[14] = this.timestampToLockDate.selector;\n\n //StakingVestingModule\n functionsList[15] = this.setVestingRegistry.selector;\n functionsList[16] = this.setVestingStakes.selector;\n functionsList[17] = this.getPriorUserStakeByDate.selector;\n functionsList[18] = this.getPriorVestingWeightedStake.selector;\n functionsList[19] = this.getPriorVestingStakeByDate.selector;\n functionsList[20] = this.addContractCodeHash.selector;\n functionsList[21] = this.removeContractCodeHash.selector;\n functionsList[22] = this.isVestingContract.selector;\n\n //BlockMockup\n functionsList[23] = this.setBlockMockUpAddr.selector;\n functionsList[24] = this.MOCK_priorWeightedStake.selector;\n functionsList[25] = this.MOCK_priorWeightedStakeAtBlock.selector;\n\n //WeightedStakingModule\n functionsList[26] = this.getPriorWeightedStake.selector;\n functionsList[27] = this.weightedStakeByDate.selector;\n functionsList[28] = this.computeWeightByDate.selector;\n functionsList[29] = this.priorWeightedStakeAtBlock.selector;\n functionsList[30] = this.getPriorWeightedStakeAtBlock.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/modules/StakingSharedModuleMock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/shared/StakingShared.sol\";\nimport \"../BlockMockUp.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\n\ncontract StakingModuleMock is IFunctionsList, StakingShared {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](1);\n functionList[0] = this.setBlockMockUpAddr.selector;\n }\n}\n" + }, + "contracts/mockup/modules/StakingWrapperMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\ncontract StakingWrapperMockup {\n uint256 constant TWO_WEEKS = 1209600;\n\n IStaking staking;\n IERC20 token;\n\n constructor(IStaking _staking, IERC20 _token) public {\n staking = _staking;\n token = _token;\n }\n\n function stake2times(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stake(amount, until, stakeFor, delegatee);\n }\n\n function stakeAndExtend(uint96 amount, uint256 until) external {\n require(token.transferFrom(msg.sender, address(this), amount));\n token.approve(address(staking), amount);\n\n staking.stake(amount, until, address(this), address(this));\n staking.extendStakingDuration(until, until + TWO_WEEKS);\n }\n\n function stakeAndStakeBySchedule(\n uint96 amount,\n uint256 until,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n}\n" + }, + "contracts/mockup/modules/WeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract WeightedStakingModuleMockup is WeightedStakingModule {\n uint96 priorWeightedStake;\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n mapping(uint256 => uint96) priorWeightedStakeAtBlock;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n functionsList[3] = this.MOCK_priorWeightedStake.selector;\n functionsList[4] = this.MOCK_priorWeightedStakeAtBlock.selector;\n functionsList[5] = this.calculatePriorWeightedStake.selector;\n functionsList[6] = this.setDelegateStake.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n//@todo can I change this proxy to EIP-1822 proxy standard, please. https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\ncontract PreviousLoanToken is AdvancedTokenStorage {\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../connectors/loantoken/interfaces/ProtocolSettingsLike.sol\";\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n// It is a LoanToken implementation!\ncontract PreviousLoanTokenSettingsLowerAdmin is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress\n\n // ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n // ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n //@todo check for restrictions in this contract\n modifier onlyAdmin() {\n require(msg.sender == address(this) || msg.sender == owner(), \"unauthorized\");\n _;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function init(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans // isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n // These params should be percentages represented like so: 5% = 5000000000000000000\n // rateMultiplier + baseRate can't exceed 100%\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; // 80 ether\n kinkLevel = _kinkLevel; // 90 ether\n maxScaleRate = _maxScaleRate; // 100 ether\n }\n\n function toggleFunctionPause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyAdmin {\n // keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /**\n * sets the transaction limit per token address\n * @param addresses the token addresses\n * @param limits the limit denominated in the currency of the token address\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyOwner\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n}\n" + }, + "contracts/mockup/PriceFeedsMoCMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../feeds/testnet/PriceFeedsMoC.sol\";\n\n// This contract is only for test purposes\n// https://github.com/money-on-chain/Amphiraos-Oracle/blob/master/contracts/medianizer/medianizer.sol\ncontract PriceFeedsMoCMockup is Medianizer {\n uint256 public value;\n bool public has;\n\n function peek() external view returns (bytes32, bool) {\n return (bytes32(value), has);\n }\n\n function setValue(uint256 _value) public {\n value = _value;\n }\n\n function setHas(bool _has) public {\n has = _has;\n }\n}\n" + }, + "contracts/mockup/ProtocolSettingsMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/ProtocolSettings.sol\";\n\ncontract ProtocolSettingsMockup is ProtocolSettings {\n function setLendingFeeTokensHeld(address token, uint256 amout) public {\n lendingFeeTokensHeld[token] = amout;\n }\n\n function setTradingFeeTokensHeld(address token, uint256 amout) public {\n tradingFeeTokensHeld[token] = amout;\n }\n\n function setBorrowingFeeTokensHeld(address token, uint256 amout) public {\n borrowingFeeTokensHeld[token] = amout;\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n\n _setTarget(this.setLendingFeeTokensHeld.selector, target);\n _setTarget(this.setTradingFeeTokensHeld.selector, target);\n _setTarget(this.setBorrowingFeeTokensHeld.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n\n _setTarget(this.getDefaultPathConversion.selector, target);\n }\n}\n" + }, + "contracts/mockup/proxy/ImplementationMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\n\ncontract ImplementationMockup is StorageMockup {\n function setValue(uint256 _value) public {\n value = _value;\n emit ValueChanged(_value);\n }\n\n function getValue() public view returns (uint256) {\n return value;\n }\n}\n" + }, + "contracts/mockup/proxy/ProxyMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract ProxyMockup is StorageMockup, UpgradableProxy {}\n" + }, + "contracts/mockup/proxy/StorageMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\ncontract StorageMockup {\n uint256 value;\n\n event ValueChanged(uint256 value);\n}\n" + }, + "contracts/mockup/RBTCWrapperProxyMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract RBTCWrapperProxyMockup {\n LiquidityMining public liquidityMining;\n\n constructor(LiquidityMining _liquidityMining) public {\n liquidityMining = _liquidityMining;\n }\n\n function claimReward(address _poolToken) public {\n liquidityMining.claimReward(_poolToken, msg.sender);\n }\n\n function claimRewardFromAllPools() public {\n liquidityMining.claimRewardFromAllPools(msg.sender);\n }\n\n function withdraw(address _poolToken, uint256 _amount) public {\n liquidityMining.withdraw(_poolToken, _amount, msg.sender);\n }\n}\n" + }, + "contracts/mockup/StakingRewardsMockUp.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/StakingRewards/StakingRewards.sol\";\nimport \"./BlockMockUp.sol\";\n\n/**\n * @title Staking Rewards Contract MockUp\n * @notice This is used for Testing\n * */\ncontract StakingRewardsMockUp is StakingRewards {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n using SafeMath for uint256;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n}\n" + }, + "contracts/mockup/TimelockHarness.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"../governance/Timelock.sol\";\n\ninterface Administered {\n function _acceptAdmin() external returns (uint256);\n}\n\ncontract TimelockHarness is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, delay_) {}\n\n function setDelayWithoutChecking(uint256 delay_) public {\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function harnessSetPendingAdmin(address pendingAdmin_) public {\n pendingAdmin = pendingAdmin_;\n }\n\n function harnessSetAdmin(address admin_) public {\n admin = admin_;\n }\n}\n\ncontract TimelockTest is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, 2 days) {\n delay = delay_;\n }\n\n function harnessSetAdmin(address admin_) public {\n require(msg.sender == admin);\n admin = admin_;\n }\n\n function harnessAcceptAdmin(Administered administered) public {\n administered._acceptAdmin();\n }\n}\n" + }, + "contracts/mockup/VestingLogicMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/Vesting/VestingLogic.sol\";\n\ncontract VestingLogicMockup is VestingLogic {\n /**\n * @dev we had a bug in a loop: \"i < endDate\" instead of \"i <= endDate\"\n */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n}\n" + }, + "contracts/mockup/VestingRegistryLogicMockUp.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\nimport \"../governance/Vesting/VestingRegistryLogic.sol\";\n\ncontract VestingRegistryLogicMockup is VestingRegistryLogic {\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return true;\n }\n\n function setTeamVesting(address _vesting, uint256 _vestingCreationType) external {\n vestingCreationAndTypes[_vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(VestingType.TeamVesting),\n vestingCreationType: uint128(_vestingCreationType)\n });\n }\n}\n" + }, + "contracts/modules/Affiliates.sol": { + "content": "/**\n * Copyright 2017-2020, Sovryn, All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Affiliates contract.\n * @notice Track referrals and reward referrers (affiliates) with tokens.\n * In-detail specifications are found at https://wiki.sovryn.app/en/community/Affiliates\n * @dev Module: Affiliates upgradable\n * Storage: from State, functions called from Protocol by delegatecall\n */\ncontract Affiliates is State, AffiliatesEvents, ModuleCommonFunctionalities {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Void constructor.\n */\n // solhint-disable-next-line no-empty-blocks\n constructor() public {}\n\n /**\n * @notice Avoid calls to this contract except for those explicitly declared.\n */\n function() external {\n revert(\"Affiliates - fallback not allowed\");\n }\n\n /**\n * @notice Set delegate callable functions by proxy contract.\n * @dev This contract is designed as a module, this way logic can be\n * expanded and upgraded w/o losing storage that is kept in the protocol (State.sol)\n * initialize() is used to register in the proxy external (module) functions\n * to be called via the proxy.\n * @param target The address of a new logic implementation.\n */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setAffiliatesReferrer.selector];\n _setTarget(this.setAffiliatesReferrer.selector, target);\n _setTarget(this.getUserNotFirstTradeFlag.selector, target);\n _setTarget(this.getReferralsList.selector, target);\n _setTarget(this.setUserNotFirstTradeFlag.selector, target);\n _setTarget(this.payTradingFeeToAffiliatesReferrer.selector, target);\n _setTarget(this.getAffiliatesReferrerBalances.selector, target);\n _setTarget(this.getAffiliatesReferrerTokenBalance.selector, target);\n _setTarget(this.getAffiliatesReferrerTokensList.selector, target);\n _setTarget(this.withdrawAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.withdrawAllAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.getMinReferralsToPayout.selector, target);\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n _setTarget(this.getAffiliateRewardsHeld.selector, target);\n _setTarget(this.getAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.getAffiliatesTokenRewardsValueInRbtc.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"Affiliates\");\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from loan pools.\n */\n modifier onlyCallableByLoanPools() {\n require(loanPoolToUnderlying[msg.sender] != address(0), \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from within protocol functions.\n */\n modifier onlyCallableInternal() {\n require(msg.sender == protocolAddress, \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Data structure comprised of 3 flags to compute the result of setting a referrer.\n */\n struct SetAffiliatesReferrerResult {\n bool success;\n bool alreadySet;\n bool userNotFirstTradeFlag;\n }\n\n /**\n * @notice Loan pool calls this function to tell affiliates\n * a user coming from a referrer is trading and should be registered if not yet.\n * Taking into account some user status flags may lead to the user and referrer\n * become added or not to the affiliates record.\n *\n * @param user The address of the user that is trading on loan pools.\n * @param referrer The address of the referrer the user is coming from.\n */\n function setAffiliatesReferrer(address user, address referrer)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n SetAffiliatesReferrerResult memory result;\n\n result.userNotFirstTradeFlag = getUserNotFirstTradeFlag(user);\n result.alreadySet = affiliatesUserReferrer[user] != address(0);\n result.success = !(result.userNotFirstTradeFlag || result.alreadySet || user == referrer);\n if (result.success) {\n affiliatesUserReferrer[user] = referrer;\n referralsList[referrer].add(user);\n emit SetAffiliatesReferrer(user, referrer);\n } else {\n emit SetAffiliatesReferrerFail(\n user,\n referrer,\n result.alreadySet,\n result.userNotFirstTradeFlag\n );\n }\n }\n\n /**\n * @notice Getter to query the referrals coming from a referrer.\n * @param referrer The address of a given referrer.\n * @return The referralsList mapping value by referrer.\n */\n function getReferralsList(address referrer) external view returns (address[] memory refList) {\n refList = referralsList[referrer].enumerate();\n return refList;\n }\n\n /**\n * @notice Getter to query the not-first-trade flag of a user.\n * @param user The address of a given user.\n * @return The userNotFirstTradeFlag mapping value by user.\n */\n function getUserNotFirstTradeFlag(address user) public view returns (bool) {\n return userNotFirstTradeFlag[user];\n }\n\n /**\n * @notice Setter to toggle on the not-first-trade flag of a user.\n * @param user The address of a given user.\n */\n function setUserNotFirstTradeFlag(address user)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n if (!userNotFirstTradeFlag[user]) {\n userNotFirstTradeFlag[user] = true;\n emit SetUserNotFirstTradeFlag(user);\n }\n }\n\n /**\n * @notice Internal getter to query the fee share for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function _getAffiliatesTradingFeePercentForSOV() internal view returns (uint256) {\n return affiliateFeePercent;\n }\n\n /**\n * @notice Internal to calculate the affiliates trading token fee amount.\n * Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * This _getReferrerTradingFeeForToken calculates the first one\n * by applying a custom percentage multiplier.\n * @param feeTokenAmount The trading token fee amount.\n * @return The affiliates share of the trading token fee amount.\n */\n function _getReferrerTradingFeeForToken(uint256 feeTokenAmount)\n internal\n view\n returns (uint256)\n {\n return feeTokenAmount.mul(getAffiliateTradingTokenFeePercent()).div(10**20);\n }\n\n /**\n * @notice Getter to query the fee share of trading token fee for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function getAffiliateTradingTokenFeePercent() public view returns (uint256) {\n return affiliateTradingTokenFeePercent;\n }\n\n /**\n * @notice Getter to query referral threshold for paying out to the referrer.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The minimum number of referrals set by Protocol.\n */\n function getMinReferralsToPayout() public view returns (uint256) {\n return minReferralsToPayout;\n }\n\n /**\n * @notice Get the sovToken reward of a trade.\n * @dev The reward is worth x% of the trading fee.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * @return The reward amount.\n * */\n function _getSovBonusAmount(address feeToken, uint256 feeAmount)\n internal\n view\n returns (uint256)\n {\n uint256 rewardAmount;\n address _priceFeeds = priceFeeds;\n\n /// @dev Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// dest token = SOV\n feeAmount.mul(_getAffiliatesTradingFeePercentForSOV()).div(1e20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n return rewardAmount;\n }\n\n /**\n * @notice Protocol calls this function to pay the affiliates rewards to a user (referrer).\n *\n * @dev Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * Both are paid in this function.\n *\n * @dev Actually they are not paid, but just holded by protocol until user claims them by\n * actively calling withdrawAffiliatesReferrerTokenFees() function,\n * and/or when unvesting lockedSOV.\n *\n * @dev To be precise, what this function does is updating the registers of the rewards\n * for the referrer including the assignment of the SOV tokens as rewards to the\n * referrer's vesting contract.\n *\n * @param referrer The address of the referrer.\n * @param trader The address of the trader.\n * @param token The address of the token in which the trading/borrowing fee was paid.\n * @param tradingFeeTokenBaseAmount Total trading fee amount, the base for calculating referrer's fees.\n *\n * @return referrerBonusSovAmount The amount of SOV tokens paid to the referrer (through a vesting contract, lockedSOV).\n * @return referrerBonusTokenAmount The amount of trading tokens paid directly to the referrer.\n */\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n )\n external\n onlyCallableInternal\n whenNotPaused\n returns (uint256 referrerBonusSovAmount, uint256 referrerBonusTokenAmount)\n {\n bool isHeld = referralsList[referrer].length() < getMinReferralsToPayout();\n bool bonusPaymentIsSuccess = true;\n uint256 paidReferrerBonusSovAmount;\n\n /// Process token fee rewards first.\n referrerBonusTokenAmount = _getReferrerTradingFeeForToken(tradingFeeTokenBaseAmount);\n if (!affiliatesReferrerTokensList[referrer].contains(token))\n affiliatesReferrerTokensList[referrer].add(token);\n affiliatesReferrerBalances[referrer][token] = affiliatesReferrerBalances[referrer][token]\n .add(referrerBonusTokenAmount);\n\n /// Then process SOV rewards.\n referrerBonusSovAmount = _getSovBonusAmount(token, tradingFeeTokenBaseAmount);\n uint256 rewardsHeldByProtocol = affiliateRewardsHeld[referrer];\n\n if (isHeld) {\n /// If referrals less than minimum, temp the rewards SOV to the storage\n affiliateRewardsHeld[referrer] = rewardsHeldByProtocol.add(referrerBonusSovAmount);\n } else {\n /// If referrals >= minimum, directly send all of the remain rewards to locked sov\n /// Call depositSOV() in LockedSov contract\n /// Set the affiliaterewardsheld = 0\n if (affiliateRewardsHeld[referrer] > 0) {\n affiliateRewardsHeld[referrer] = 0;\n }\n\n paidReferrerBonusSovAmount = referrerBonusSovAmount.add(rewardsHeldByProtocol);\n IERC20(sovTokenAddress).approve(lockedSOVAddress, paidReferrerBonusSovAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"depositSOV(address,uint256)\",\n referrer,\n paidReferrerBonusSovAmount\n )\n );\n\n if (!success) {\n bonusPaymentIsSuccess = false;\n }\n }\n\n if (bonusPaymentIsSuccess) {\n emit PayTradingFeeToAffiliate(\n referrer,\n trader, // trader\n token,\n isHeld,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n } else {\n emit PayTradingFeeToAffiliateFail(\n referrer,\n trader, // trader\n token,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n }\n\n return (referrerBonusSovAmount, referrerBonusTokenAmount);\n }\n\n /**\n * @notice Referrer calls this function to receive its reward in a given token.\n * It will send the other (non-SOV) reward tokens from trading protocol fees,\n * to the referrer’s wallet.\n * @dev Rewards are held by protocol in different tokens coming from trading fees.\n * Referrer has to claim them one by one for every token with accumulated balance.\n * @param token The address of the token to withdraw.\n * @param receiver The address of the withdrawal beneficiary.\n * @param amount The amount of tokens to claim. If greater than balance, just sends balance.\n */\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) public whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n uint256 referrerTokenBalance = affiliatesReferrerBalances[referrer][token];\n uint256 withdrawAmount = referrerTokenBalance > amount ? amount : referrerTokenBalance;\n\n require(withdrawAmount > 0, \"Affiliates: cannot withdraw zero amount\");\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n uint256 newReferrerTokenBalance = referrerTokenBalance.sub(withdrawAmount);\n\n if (newReferrerTokenBalance == 0) {\n _removeAffiliatesReferrerToken(referrer, token);\n } else {\n affiliatesReferrerBalances[referrer][token] = newReferrerTokenBalance;\n }\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawAffiliatesReferrerTokenFees(referrer, receiver, token, withdrawAmount);\n }\n\n /**\n * @notice Withdraw to msg.sender all token fees for a referrer.\n * @dev It's done by looping through its available tokens.\n * @param receiver The address of the withdrawal beneficiary.\n */\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n (address[] memory tokenAddresses, uint256[] memory tokenBalances) =\n getAffiliatesReferrerBalances(referrer);\n for (uint256 i; i < tokenAddresses.length; i++) {\n withdrawAffiliatesReferrerTokenFees(tokenAddresses[i], receiver, tokenBalances[i]);\n }\n }\n\n /**\n * @notice Internal function to delete a referrer's token balance.\n * @param referrer The address of the referrer.\n * @param token The address of the token specifying the balance to remove.\n */\n function _removeAffiliatesReferrerToken(address referrer, address token) internal {\n delete affiliatesReferrerBalances[referrer][token];\n affiliatesReferrerTokensList[referrer].remove(token);\n }\n\n /**\n * @notice Get all token balances of a referrer.\n * @param referrer The address of the referrer.\n * @return referrerTokensList The array of available tokens (keys).\n * @return referrerTokensBalances The array of token balances (values).\n */\n function getAffiliatesReferrerBalances(address referrer)\n public\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances)\n {\n referrerTokensList = getAffiliatesReferrerTokensList(referrer);\n referrerTokensBalances = new uint256[](referrerTokensList.length);\n for (uint256 i; i < referrerTokensList.length; i++) {\n referrerTokensBalances[i] = getAffiliatesReferrerTokenBalance(\n referrer,\n referrerTokensList[i]\n );\n }\n return (referrerTokensList, referrerTokensBalances);\n }\n\n /**\n * @dev Get all token rewards estimation value in rbtc.\n *\n * @param referrer Address of referrer.\n *\n * @return The value estimation in rbtc.\n */\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount)\n {\n address[] memory tokensList = getAffiliatesReferrerTokensList(referrer);\n address _priceFeeds = priceFeeds;\n\n for (uint256 i; i < tokensList.length; i++) {\n // Get the value of each token in rbtc\n\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n tokensList[i], // source token\n address(wrbtcToken), // dest token = SOV\n affiliatesReferrerBalances[referrer][tokensList[i]] // total token rewards\n )\n );\n\n assembly {\n if eq(success, 1) {\n rbtcTotalAmount := add(rbtcTotalAmount, mload(add(data, 32)))\n }\n }\n }\n }\n\n /**\n * @notice Get all available tokens at the affiliates program for a given referrer.\n * @param referrer The address of a given referrer.\n * @return tokensList The list of available tokens.\n */\n function getAffiliatesReferrerTokensList(address referrer)\n public\n view\n returns (address[] memory tokensList)\n {\n tokensList = affiliatesReferrerTokensList[referrer].enumerate();\n return tokensList;\n }\n\n /**\n * @notice Getter to query the affiliate balance for a given referrer and token.\n * @param referrer The address of the referrer.\n * @param token The address of the token to get balance for.\n * @return The affiliatesReferrerBalances mapping value by referrer and token keys.\n */\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n public\n view\n returns (uint256)\n {\n return affiliatesReferrerBalances[referrer][token];\n }\n\n /**\n * @notice Getter to query the address of referrer for a given user.\n * @param user The address of the user.\n * @return The address on affiliatesUserReferrer mapping value by user key.\n */\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user];\n }\n\n /**\n * @notice Getter to query the reward amount held for a given referrer.\n * @param referrer The address of the referrer.\n * @return The affiliateRewardsHeld mapping value by referrer key.\n */\n function getAffiliateRewardsHeld(address referrer) public view returns (uint256) {\n return affiliateRewardsHeld[referrer];\n }\n}\n" + }, + "contracts/modules/interfaces/ProtocolAffiliatesInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolAffiliatesInterface {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user_) external;\n\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\n\n function payTradingFeeToAffiliatesReferrer(\n address affiliate,\n address trader,\n address token,\n uint256 amount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n}\n" + }, + "contracts/modules/interfaces/ProtocolSwapExternalInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolSwapExternalInterface {\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n}\n" + }, + "contracts/modules/LoanClosingsLiquidation.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsLiquidation contract.\n * @notice Ways to close a loan: liquidation. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsLiquidation is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.liquidate.selector];\n _setTarget(this.liquidate.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsLiquidation\"\n );\n }\n\n /**\n * @notice Liquidate an unhealty loan.\n *\n * @dev Public wrapper for _liquidate internal function.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * loanId is the ID of the loan, which is created on loan opening.\n * It can be obtained either by parsing the Trade event or by reading\n * the open loans from the contract by calling getActiveLoans or getUserLoans.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n return _liquidate(loanId, receiver, closeAmount);\n }\n\n /**\n * @notice Internal function for liquidating an unhealthy loan.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function _liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin <= loanParamsLocal.maintenanceMargin, \"healthy position\");\n\n loanCloseAmount = closeAmount;\n\n //amounts to restore the desired margin (maintencance + 5%)\n (uint256 maxLiquidatable, uint256 maxSeizable, ) =\n _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n\n if (loanCloseAmount < maxLiquidatable) {\n //close maxLiquidatable if tiny position will remain\n uint256 remainingAmount = maxLiquidatable - loanCloseAmount;\n remainingAmount = _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingAmount <= TINY_AMOUNT) {\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable.mul(loanCloseAmount).div(maxLiquidatable);\n }\n } else if (loanCloseAmount > maxLiquidatable) {\n // adjust down the close amount to the max\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable;\n }\n\n require(loanCloseAmount != 0, \"nothing to liquidate\");\n\n // liquidator deposits the principal being closed\n _returnPrincipalWithDeposit(loanParamsLocal.loanToken, address(this), loanCloseAmount);\n\n // a portion of the principal is repaid to the lender out of interest refunded\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n loanLocal.borrower\n );\n\n if (loanCloseAmount > loanCloseAmountLessInterest) {\n // full interest refund goes to the borrower\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanCloseAmount - loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmountLessInterest != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n seizedToken = loanParamsLocal.collateralToken;\n\n if (seizedAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(seizedAmount);\n\n _withdrawAsset(seizedToken, receiver, seizedAmount);\n }\n\n _closeLoan(loanLocal, loanCloseAmount);\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n seizedAmount,\n collateralToLoanRate,\n 0,\n currentMargin,\n CloseTypes.Liquidation\n );\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsRollover.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsRollover contract.\n * @notice Ways to close a loan: rollover. Margin trade\n * positions are always closed with a swap.\n *\n * */\ncontract LoanClosingsRollover is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.rollover.selector];\n _setTarget(this.rollover.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsRollover\"\n );\n }\n\n /**\n * @notice Roll over a loan.\n *\n * @dev Public wrapper for _rollover internal function.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * The function rollover on the protocol contract extends the loan\n * duration by the maximum term (28 days for margin trades at the moment\n * of writing), pays the interest to the lender and refunds the caller\n * for the gas cost by sending 2 * the gas cost using the fast gas price\n * as base for the calculation.\n *\n * @param loanId The ID of the loan to roll over.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n * */\n function rollover(\n bytes32 loanId,\n bytes calldata // for future use /*loanDataBytes*/\n ) external nonReentrant globallyNonReentrant iTokenSupplyUnchanged(loanId) whenNotPaused {\n // restrict to EOAs to prevent griefing attacks, during interest rate recalculation\n require(msg.sender == tx.origin, \"EOAs call\");\n\n return\n _rollover(\n loanId,\n \"\" // loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for roll over a loan.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * @param loanId The ID of the loan to roll over.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n * */\n function _rollover(bytes32 loanId, bytes memory loanDataBytes) internal {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n require(block.timestamp > loanLocal.endTimestamp.sub(3600), \"healthy position\");\n require(loanPoolToUnderlying[loanLocal.lender] != address(0), \"invalid lender\");\n\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n // Handle back interest: calculates interest owned since the loan endtime passed but the loan remained open\n uint256 backInterestTime;\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestTime = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestTime.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(1 days);\n }\n\n //note: to avoid code duplication, it would be nicer to store loanParamsLocal.maxLoanTerm in a local variable\n //however, we've got stack too deep issues if we do so.\n if (loanParamsLocal.maxLoanTerm != 0) {\n // fixed-term loan, so need to query iToken for latest variable rate\n uint256 owedPerDay =\n loanLocal.principal.mul(ILoanPool(loanLocal.lender).borrowInterestRate()).div(\n 365 * 10**20\n );\n\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(\n loanInterestLocal.owedPerDay\n );\n\n loanInterestLocal.owedPerDay = owedPerDay;\n\n //if the loan has been open for longer than an additional period, add at least 1 additional day\n if (backInterestTime >= loanParamsLocal.maxLoanTerm) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n }\n //extend by the max loan term\n else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(loanParamsLocal.maxLoanTerm);\n }\n } else {\n // loanInterestLocal.owedPerDay doesn't change\n if (backInterestTime >= MONTH) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n } else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(MONTH);\n }\n }\n\n uint256 interestAmountRequired = loanLocal.endTimestamp.sub(block.timestamp);\n interestAmountRequired = interestAmountRequired.mul(loanInterestLocal.owedPerDay);\n interestAmountRequired = interestAmountRequired.div(1 days);\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n\n // add backInterestOwed\n interestAmountRequired = interestAmountRequired.add(backInterestOwed);\n\n // collect interest (needs to be converted from the collateral)\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n 0, //min swap 0 -> swap connector estimates the amount of source tokens to use\n interestAmountRequired, //required destination tokens\n true, // returnTokenIsCollateral\n loanDataBytes\n );\n\n //received more tokens than needed to pay the interest\n if (destTokenAmountReceived > interestAmountRequired) {\n // swap rest back to collateral, if the amount is big enough to cover gas cost\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n )\n ) {\n (destTokenAmountReceived, , ) = _swapBackExcess(\n loanLocal,\n loanParamsLocal,\n destTokenAmountReceived - interestAmountRequired, //amount to be swapped\n loanDataBytes\n );\n sourceTokenAmountUsed = sourceTokenAmountUsed.sub(destTokenAmountReceived);\n }\n //else give it to the protocol as a lending fee\n else {\n _payLendingFee(\n loanLocal.borrower,\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n );\n }\n }\n\n //subtract the interest from the collateral\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n if (backInterestOwed != 0) {\n // pay out backInterestOwed\n\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n uint256 rolloverReward =\n _getRolloverReward(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.principal\n );\n\n if (rolloverReward != 0) {\n // if the reward > collateral:\n if (rolloverReward > loanLocal.collateral) {\n // 1. pay back the remaining loan to the lender\n // 2. pay the remaining collateral to msg.sender\n // 3. close the position & emit close event\n _closeWithSwap(\n loanLocal.id,\n msg.sender,\n loanLocal.collateral,\n false,\n \"\" // loanDataBytes\n );\n } else {\n // pay out reward to caller\n loanLocal.collateral = loanLocal.collateral.sub(rolloverReward);\n\n _withdrawAsset(loanParamsLocal.collateralToken, msg.sender, rolloverReward);\n }\n }\n\n if (loanLocal.collateral > 0) {\n //close whole loan if tiny position will remain\n if (_getAmountInRbtc(loanParamsLocal.loanToken, loanLocal.principal) <= TINY_AMOUNT) {\n _closeWithSwap(\n loanLocal.id,\n loanLocal.borrower,\n loanLocal.collateral, // swap all collaterals\n false,\n \"\" /// loanDataBytes\n );\n } else {\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n require(\n currentMargin > 3 ether, // ensure there's more than 3% margin remaining\n \"unhealthy position\"\n );\n }\n }\n\n if (loanLocal.active) {\n emit Rollover(\n loanLocal.borrower, // user (borrower)\n loanLocal.lender, // lender\n loanLocal.id, // loanId\n loanLocal.principal, // principal\n loanLocal.collateral, // collateral\n loanLocal.endTimestamp, // endTimestamp\n msg.sender, // rewardReceiver\n rolloverReward // reward\n );\n }\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsShared.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/RewardHelper.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\n/**\n * @title LoanClosingsShared contract.\n * @notice This contract should only contains the internal function that is being used / utilized by\n * LoanClosingsLiquidation, LoanClosingsRollover & LoanClosingsWith contract\n *\n * */\ncontract LoanClosingsShared is\n LoanClosingsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n RewardHelper,\n ModuleCommonFunctionalities\n{\n uint256 internal constant MONTH = 365 days / 12;\n //0.00001 BTC, would be nicer in State.sol, but would require a redeploy of the complete protocol, so adding it here instead\n //because it's not shared state anyway and only used by this contract\n uint256 public constant paySwapExcessToBorrowerThreshold = 10000000000000;\n\n uint256 public constant TINY_AMOUNT = 25e13;\n\n enum CloseTypes { Deposit, Swap, Liquidation }\n\n /** modifier for invariant check */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n Loan storage loanLocal = loans[loanId];\n\n require(loanLocal.lender != address(0), \"Invalid loan token pool address\");\n\n uint256 previousITokenSupply = ILoanTokenModules(loanLocal.lender).totalSupply();\n\n _;\n\n /// Validate iToken total supply\n require(\n previousITokenSupply == ILoanTokenModules(loanLocal.lender).totalSupply(),\n \"loan token supply invariant check failure\"\n );\n }\n\n /**\n * @dev computes the interest which needs to be refunded to the borrower based on the amount he's closing and either\n * subtracts it from the amount which still needs to be paid back (in case outstanding amount > interest) or withdraws the\n * excess to the borrower (in case interest > outstanding).\n * @param loanLocal the loan\n * @param loanParamsLocal the loan params\n * @param loanCloseAmount the amount to be closed (base for the computation)\n * @param receiver the address of the receiver (usually the borrower)\n * */\n function _settleInterestToPrincipal(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 loanCloseAmount,\n address receiver\n ) internal returns (uint256) {\n uint256 loanCloseAmountLessInterest = loanCloseAmount;\n\n //compute the interest which neeeds to be refunded to the borrower (because full interest is paid on loan )\n uint256 interestRefundToBorrower =\n _settleInterest(loanParamsLocal, loanLocal, loanCloseAmountLessInterest);\n\n uint256 interestAppliedToPrincipal;\n //if the outstanding loan is bigger than the interest to be refunded, reduce the amount to be paid back / closed by the interest\n if (loanCloseAmountLessInterest >= interestRefundToBorrower) {\n // apply all of borrower interest refund torwards principal\n interestAppliedToPrincipal = interestRefundToBorrower;\n\n // principal needed is reduced by this amount\n loanCloseAmountLessInterest -= interestRefundToBorrower;\n\n // no interest refund remaining\n interestRefundToBorrower = 0;\n } else {\n //if the interest refund is bigger than the outstanding loan, the user needs to get back the interest\n // principal fully covered by excess interest\n interestAppliedToPrincipal = loanCloseAmountLessInterest;\n\n // amount refunded is reduced by this amount\n interestRefundToBorrower -= loanCloseAmountLessInterest;\n\n // principal fully covered by excess interest\n loanCloseAmountLessInterest = 0;\n\n if (interestRefundToBorrower != 0) {\n // refund overage\n _withdrawAsset(loanParamsLocal.loanToken, receiver, interestRefundToBorrower);\n }\n }\n\n //pay the interest to the lender\n //note: this is a waste of gas, because the loanCloseAmountLessInterest is withdrawn to the lender, too. It could be done at once.\n if (interestAppliedToPrincipal != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, interestAppliedToPrincipal);\n }\n\n return loanCloseAmountLessInterest;\n }\n\n // The receiver always gets back an ERC20 (even wrbtc)\n function _returnPrincipalWithDeposit(\n address loanToken,\n address receiver,\n uint256 principalNeeded\n ) internal {\n if (principalNeeded != 0) {\n if (msg.value == 0) {\n vaultTransfer(loanToken, msg.sender, receiver, principalNeeded);\n } else {\n require(loanToken == address(wrbtcToken), \"wrong asset sent\");\n require(msg.value >= principalNeeded, \"not enough ether\");\n wrbtcToken.deposit.value(principalNeeded)();\n if (receiver != address(this)) {\n vaultTransfer(loanToken, address(this), receiver, principalNeeded);\n }\n if (msg.value > principalNeeded) {\n // refund overage\n Address.sendValue(msg.sender, msg.value - principalNeeded);\n }\n }\n } else {\n require(msg.value == 0, \"wrong asset sent\");\n }\n }\n\n /**\n * @dev checks if the amount of the asset to be transfered is worth the transfer fee\n * @param asset the asset to be transfered\n * @param amount the amount to be transfered\n * @return True if the amount is bigger than the threshold\n * */\n function worthTheTransfer(address asset, uint256 amount) internal returns (bool) {\n uint256 amountInRbtc = _getAmountInRbtc(asset, amount);\n emit swapExcess(\n amountInRbtc > paySwapExcessToBorrowerThreshold,\n amount,\n amountInRbtc,\n paySwapExcessToBorrowerThreshold\n );\n\n return amountInRbtc > paySwapExcessToBorrowerThreshold;\n }\n\n /**\n * swaps collateral tokens for loan tokens\n * @param loanLocal the loan object\n * @param loanParamsLocal the loan parameters\n * @param swapAmount the amount to be swapped\n * @param principalNeeded the required destination token amount\n * @param returnTokenIsCollateral if true -> required destination token amount will be passed on, else not\n * note: quite dirty. should be refactored.\n * @param loanDataBytes additional loan data (not in use for token swaps)\n * */\n function _doCollateralSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n loanLocal.collateral, // maxSourceTokenAmount\n returnTokenIsCollateral\n ? principalNeeded // requiredDestTokenAmount\n : 0,\n false, // bypassFee\n loanDataBytes\n );\n require(destTokenAmountReceived >= principalNeeded, \"insufficient dest amount\");\n require(sourceTokenAmountUsed <= loanLocal.collateral, \"excessive source amount\");\n }\n\n /**\n * @notice Withdraw asset to receiver.\n *\n * @param assetToken The loan token.\n * @param receiver The address of the receiver.\n * @param assetAmount The loan token amount.\n * */\n function _withdrawAsset(\n address assetToken,\n address receiver,\n uint256 assetAmount\n ) internal {\n if (assetAmount != 0) {\n if (assetToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, assetAmount);\n } else {\n vaultWithdraw(assetToken, receiver, assetAmount);\n }\n }\n }\n\n /**\n * @notice Internal function to close a loan.\n *\n * @param loanLocal The loan object.\n * @param loanCloseAmount The amount to close: principal or lower.\n *\n * */\n function _closeLoan(Loan storage loanLocal, uint256 loanCloseAmount) internal {\n require(loanCloseAmount != 0, \"nothing to close\");\n\n if (loanCloseAmount == loanLocal.principal) {\n loanLocal.principal = 0;\n loanLocal.active = false;\n loanLocal.endTimestamp = block.timestamp;\n loanLocal.pendingTradesId = 0;\n activeLoansSet.removeBytes32(loanLocal.id);\n lenderLoanSets[loanLocal.lender].removeBytes32(loanLocal.id);\n borrowerLoanSets[loanLocal.borrower].removeBytes32(loanLocal.id);\n } else {\n loanLocal.principal = loanLocal.principal.sub(loanCloseAmount);\n }\n }\n\n function _settleInterest(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 closePrincipal\n ) internal returns (uint256) {\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 interestTime = block.timestamp;\n if (interestTime > loanLocal.endTimestamp) {\n interestTime = loanLocal.endTimestamp;\n }\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n interestTime\n );\n\n uint256 owedPerDayRefund;\n if (closePrincipal < loanLocal.principal) {\n owedPerDayRefund = loanInterestLocal.owedPerDay.mul(closePrincipal).div(\n loanLocal.principal\n );\n } else {\n owedPerDayRefund = loanInterestLocal.owedPerDay;\n }\n\n // update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.sub(owedPerDayRefund);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(owedPerDayRefund);\n\n // update borrower interest\n uint256 interestRefundToBorrower = loanLocal.endTimestamp.sub(interestTime);\n interestRefundToBorrower = interestRefundToBorrower.mul(owedPerDayRefund);\n interestRefundToBorrower = interestRefundToBorrower.div(1 days);\n\n if (closePrincipal < loanLocal.principal) {\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(\n interestRefundToBorrower\n );\n } else {\n loanInterestLocal.depositTotal = 0;\n }\n\n // update remaining lender interest values\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.sub(\n closePrincipal\n );\n\n uint256 owedTotal = lenderInterestLocal.owedTotal;\n lenderInterestLocal.owedTotal = owedTotal > interestRefundToBorrower\n ? owedTotal - interestRefundToBorrower\n : 0;\n\n return interestRefundToBorrower;\n }\n\n /**\n * @notice Check sender is borrower or delegatee and loan id exists.\n *\n * @param loanId byte32 of the loan id.\n * */\n function _checkAuthorized(bytes32 loanId) internal view {\n Loan storage loanLocal = loans[loanId];\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n }\n\n /**\n * @notice Internal function for closing a position by swapping the\n * collateral back to loan tokens, paying the lender and withdrawing\n * the remainder.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collatral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid\n * out in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(swapAmount != 0, \"swapAmount == 0\");\n\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't swap more than collateral.\n swapAmount = swapAmount > loanLocal.collateral ? loanLocal.collateral : swapAmount;\n\n //close whole loan if tiny position will remain\n if (loanLocal.collateral - swapAmount > 0) {\n if (\n _getAmountInRbtc(\n loanParamsLocal.collateralToken,\n loanLocal.collateral - swapAmount\n ) <= TINY_AMOUNT\n ) {\n swapAmount = loanLocal.collateral;\n }\n }\n\n uint256 loanCloseAmountLessInterest;\n if (swapAmount == loanLocal.collateral || returnTokenIsCollateral) {\n /// loanCloseAmountLessInterest will be passed as required amount amount of destination tokens.\n /// this means, the actual swapAmount passed to the swap contract does not matter at all.\n /// the source token amount will be computed depending on the required amount amount of destination tokens.\n loanCloseAmount = swapAmount == loanLocal.collateral\n ? loanLocal.principal\n : loanLocal.principal.mul(swapAmount).div(loanLocal.collateral);\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Computes the interest refund for the borrower and sends it to the lender to cover part of the principal.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n } else {\n /// loanCloseAmount is calculated after swap; for this case we want to swap the entire source amount\n /// and determine the loanCloseAmount and withdraw amount based on that.\n loanCloseAmountLessInterest = 0;\n }\n\n uint256 coveredPrincipal;\n uint256 usedCollateral;\n\n /// swapAmount repurposed for collateralToLoanSwapRate to avoid stack too deep error.\n (coveredPrincipal, usedCollateral, withdrawAmount, swapAmount) = _coverPrincipalWithSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount, /// The amount of source tokens to swap (only matters if !returnTokenIsCollateral or loanCloseAmountLessInterest = 0)\n loanCloseAmountLessInterest, /// This is the amount of destination tokens we want to receive (only matters if returnTokenIsCollateral)\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (loanCloseAmountLessInterest == 0) {\n /// Condition prior to swap: swapAmount != loanLocal.collateral && !returnTokenIsCollateral\n\n /// Amounts that is closed.\n loanCloseAmount = coveredPrincipal;\n if (coveredPrincipal != loanLocal.principal) {\n loanCloseAmount = loanCloseAmount.mul(usedCollateral).div(loanLocal.collateral);\n }\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Amount that is returned to the lender.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n\n /// Remaining amount withdrawn to the receiver.\n withdrawAmount = withdrawAmount.add(coveredPrincipal).sub(loanCloseAmountLessInterest);\n } else {\n /// Pay back the amount which was covered by the swap.\n loanCloseAmountLessInterest = coveredPrincipal;\n }\n\n require(loanCloseAmountLessInterest != 0, \"closeAmount is 0 after swap\");\n\n /// Reduce the collateral by the amount which was swapped for the closure.\n if (usedCollateral != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(usedCollateral);\n }\n\n /// Repays principal to lender.\n /// The lender always gets back an ERC20 (even wrbtc), so we call\n /// withdraw directly rather than use the _withdrawAsset helper function.\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, loanCloseAmountLessInterest);\n\n withdrawToken = returnTokenIsCollateral\n ? loanParamsLocal.collateralToken\n : loanParamsLocal.loanToken;\n\n if (withdrawAmount != 0) {\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n usedCollateral,\n swapAmount, /// collateralToLoanSwapRate\n CloseTypes.Swap\n );\n }\n\n /**\n * @notice Close a loan.\n *\n * @dev Wrapper for _closeLoan internal function.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan params.\n * @param loanCloseAmount The amount to close: principal or lower.\n * @param collateralCloseAmount The amount of collateral to close.\n * @param collateralToLoanSwapRate The price rate collateral/loan token.\n * @param closeType The type of loan close.\n * */\n function _finalizeClose(\n Loan storage loanLocal,\n LoanParams storage loanParamsLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanSwapRate,\n CloseTypes closeType\n ) internal {\n _closeLoan(loanLocal, loanCloseAmount);\n\n address _priceFeeds = priceFeeds;\n uint256 currentMargin;\n uint256 collateralToLoanRate;\n\n /// This is still called even with full loan close to return collateralToLoanRate\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).getCurrentMargin.selector,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n )\n );\n assembly {\n if eq(success, 1) {\n currentMargin := mload(add(data, 32))\n collateralToLoanRate := mload(add(data, 64))\n }\n }\n /// Note: We can safely skip the margin check if closing\n /// via closeWithDeposit or if closing the loan in full by any method.\n require(\n closeType == CloseTypes.Deposit ||\n loanLocal.principal == 0 || /// loan fully closed\n currentMargin > loanParamsLocal.maintenanceMargin,\n \"unhealthy position\"\n );\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n collateralCloseAmount,\n collateralToLoanRate,\n collateralToLoanSwapRate,\n currentMargin,\n closeType\n );\n }\n\n /**\n * swaps a share of a loan's collateral or the complete collateral in order to cover the principle.\n * @param loanLocal the loan\n * @param loanParamsLocal the loan parameters\n * @param swapAmount in case principalNeeded == 0 or !returnTokenIsCollateral, this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens needed for the swap is estimated by the connector.\n * @param principalNeeded the required amount of destination tokens in order to cover the principle (only used if returnTokenIsCollateral)\n * @param returnTokenIsCollateral tells if the user wants to withdraw his remaining collateral + profit in collateral tokens\n * @notice Swaps a share of a loan's collateral or the complete collateral\n * in order to cover the principle.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount In case principalNeeded == 0 or !returnTokenIsCollateral,\n * this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens\n * needed for the swap is estimated by the connector.\n * @param principalNeeded The required amount of destination tokens in order to\n * cover the principle (only used if returnTokenIsCollateral).\n * @param returnTokenIsCollateral Tells if the user wants to withdraw his\n * remaining collateral + profit in collateral tokens.\n *\n * @return coveredPrincipal The amount of principal that is covered.\n * @return usedCollateral The amount of collateral used.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _coverPrincipalWithSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 coveredPrincipal,\n uint256 usedCollateral,\n uint256 withdrawAmount,\n uint256 collateralToLoanSwapRate\n )\n {\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n (\n destTokenAmountReceived,\n sourceTokenAmountUsed,\n collateralToLoanSwapRate\n ) = _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount,\n principalNeeded,\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (returnTokenIsCollateral) {\n coveredPrincipal = principalNeeded;\n\n /// Better fill than expected.\n if (destTokenAmountReceived > coveredPrincipal) {\n /// Send excess to borrower if the amount is big enough to be\n /// worth the gas fees.\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - coveredPrincipal\n )\n ) {\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n destTokenAmountReceived - coveredPrincipal\n );\n }\n /// Else, give the excess to the lender (if it goes to the\n /// borrower, they're very confused. causes more trouble than it's worth)\n else {\n coveredPrincipal = destTokenAmountReceived;\n }\n }\n withdrawAmount = swapAmount > sourceTokenAmountUsed\n ? swapAmount - sourceTokenAmountUsed\n : 0;\n } else {\n require(sourceTokenAmountUsed == swapAmount, \"swap error\");\n\n if (swapAmount == loanLocal.collateral) {\n /// sourceTokenAmountUsed == swapAmount == loanLocal.collateral\n\n coveredPrincipal = principalNeeded;\n withdrawAmount = destTokenAmountReceived - principalNeeded;\n } else {\n /// sourceTokenAmountUsed == swapAmount < loanLocal.collateral\n\n if (destTokenAmountReceived >= loanLocal.principal) {\n /// Edge case where swap covers full principal.\n\n coveredPrincipal = loanLocal.principal;\n withdrawAmount = destTokenAmountReceived - loanLocal.principal;\n\n /// Excess collateral refunds to the borrower.\n _withdrawAsset(\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n loanLocal.collateral - sourceTokenAmountUsed\n );\n sourceTokenAmountUsed = loanLocal.collateral;\n } else {\n coveredPrincipal = destTokenAmountReceived;\n withdrawAmount = 0;\n }\n }\n }\n\n usedCollateral = sourceTokenAmountUsed > swapAmount ? sourceTokenAmountUsed : swapAmount;\n }\n\n function _emitClosingEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanRate,\n uint256 collateralToLoanSwapRate,\n uint256 currentMargin,\n CloseTypes closeType\n ) internal {\n if (closeType == CloseTypes.Deposit) {\n emit CloseWithDeposit(\n loanLocal.borrower, /// user (borrower)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n msg.sender, /// closer\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n loanCloseAmount, /// loanCloseAmount\n collateralCloseAmount, /// collateralCloseAmount\n collateralToLoanRate, /// collateralToLoanRate\n currentMargin /// currentMargin\n );\n } else if (closeType == CloseTypes.Swap) {\n /// exitPrice = 1 / collateralToLoanSwapRate\n if (collateralToLoanSwapRate != 0) {\n collateralToLoanSwapRate = SafeMath.div(10**36, collateralToLoanSwapRate);\n }\n\n /// currentLeverage = 100 / currentMargin\n if (currentMargin != 0) {\n currentMargin = SafeMath.div(10**38, currentMargin);\n }\n\n emit CloseWithSwap(\n loanLocal.borrower, /// user (trader)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n msg.sender, /// closer\n collateralCloseAmount, /// positionCloseSize\n loanCloseAmount, /// loanCloseAmount\n collateralToLoanSwapRate, /// exitPrice (1 / collateralToLoanSwapRate)\n currentMargin /// currentLeverage\n );\n } else if (closeType == CloseTypes.Liquidation) {\n emit Liquidate(\n loanLocal.borrower, // user (borrower)\n msg.sender, // liquidator\n loanLocal.id, // loanId\n loanLocal.lender, // lender\n loanParamsLocal.loanToken, // loanToken\n loanParamsLocal.collateralToken, // collateralToken\n loanCloseAmount, // loanCloseAmount\n collateralCloseAmount, // collateralCloseAmount\n collateralToLoanRate, // collateralToLoanRate\n currentMargin // currentMargin\n );\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal view returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n IPriceFeeds(priceFeeds).queryRate(asset, address(wrbtcToken));\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /**\n * @dev private function which check the loanLocal & loanParamsLocal does exist\n *\n * @param loanId bytes32 of loanId\n *\n * @return Loan storage\n * @return LoanParams storage\n */\n function _checkLoan(bytes32 loanId) internal view returns (Loan storage, LoanParams storage) {\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n return (loanLocal, loanParamsLocal);\n }\n}\n" + }, + "contracts/modules/LoanClosingsWith.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsWith contract.\n * @notice Close a loan w/deposit, close w/swap. There are 2 functions for ending a loan on the\n * protocol contract: closeWithSwap and closeWithDeposit. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsWith is LoanClosingsShared {\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n\n /**\n * @notice Closes a loan by doing a deposit.\n *\n * @dev Public wrapper for _closeWithDeposit internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens. (e.g. rBTC on a iSUSD contract).\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n public\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return _closeWithDeposit(loanId, receiver, depositAmount);\n }\n\n /**\n * @notice Close a position by swapping the collateral back to loan tokens\n * paying the lender and withdrawing the remainder.\n *\n * @dev Public wrapper for _closeWithSwap internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collateral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid out\n * in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes memory // for future use /*loanDataBytes*/\n )\n public\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return\n _closeWithSwap(\n loanId,\n receiver,\n swapAmount,\n returnTokenIsCollateral,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for closing a loan by doing a deposit.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens.\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(depositAmount != 0, \"depositAmount == 0\");\n\n //TODO should we skip this check if invoked from rollover ?\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't close more than the full principal.\n loanCloseAmount = depositAmount > loanLocal.principal\n ? loanLocal.principal\n : depositAmount;\n\n //revert if tiny position remains\n uint256 remainingAmount = loanLocal.principal - loanCloseAmount;\n if (remainingAmount > 0) {\n require(\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount) > TINY_AMOUNT,\n \"Tiny amount when closing with deposit\"\n );\n }\n\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(loanLocal, loanParamsLocal, loanCloseAmount, receiver);\n\n if (loanCloseAmountLessInterest != 0) {\n _returnPrincipalWithDeposit(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmount == loanLocal.principal) {\n withdrawAmount = loanLocal.collateral;\n } else {\n withdrawAmount = loanLocal.collateral.mul(loanCloseAmount).div(loanLocal.principal);\n }\n\n withdrawToken = loanParamsLocal.collateralToken;\n\n if (withdrawAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(withdrawAmount);\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n withdrawAmount, /// collateralCloseAmount\n 0, /// collateralToLoanSwapRate\n CloseTypes.Deposit\n );\n }\n\n /**\n * @notice Function to check whether the given loanId & deposit amount when closing with deposit will cause the tiny position\n *\n * @param loanId The id of the loan.\n * @param depositAmount Defines how much the deposit amount to close the position.\n *\n * @return isTinyPosition true is indicating tiny position, false otherwise.\n * @return tinyPositionAmount will return 0 for non tiny position, and will return the amount of tiny position if true\n */\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount)\n {\n (Loan memory loanLocal, LoanParams memory loanParamsLocal) = _checkLoan(loanId);\n\n if (depositAmount < loanLocal.principal) {\n uint256 remainingAmount = loanLocal.principal - depositAmount;\n uint256 remainingRBTCAmount =\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingRBTCAmount < TINY_AMOUNT) {\n isTinyPosition = true;\n tinyPositionAmount = remainingRBTCAmount;\n }\n }\n\n return (isTinyPosition, tinyPositionAmount);\n }\n}\n" + }, + "contracts/modules/LoanMaintenance.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Maintenance contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to query loan data and to modify its status\n * by withdrawing or depositing collateral.\n * */\ncontract LoanMaintenance is\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n LiquidationHelper,\n ModuleCommonFunctionalities\n{\n // Keep the old LoanReturnData for backward compatibility (especially for the watcher)\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n // The new struct which contained borrower & creation time of a loan\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set initial values of proxy targets.\n *\n * @param target The address of the logic contract instance.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.depositCollateral.selector];\n _setTarget(this.depositCollateral.selector, target);\n _setTarget(this.withdrawCollateral.selector, target);\n _setTarget(this.withdrawAccruedInterest.selector, target);\n _setTarget(this.extendLoanDuration.selector, target);\n _setTarget(this.reduceLoanDuration.selector, target);\n _setTarget(this.getLenderInterestData.selector, target);\n _setTarget(this.getLoanInterestData.selector, target);\n _setTarget(this.getUserLoans.selector, target);\n _setTarget(this.getUserLoansV2.selector, target);\n _setTarget(this.getLoan.selector, target);\n _setTarget(this.getLoanV2.selector, target);\n _setTarget(this.getActiveLoans.selector, target);\n _setTarget(this.getActiveLoansV2.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanMaintenance\");\n }\n\n /**\n * @notice Increase the margin of a position by depositing additional collateral.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount /// must match msg.value if ether is sent\n ) external payable nonReentrant whenNotPaused {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.value == 0 || loanParamsLocal.collateralToken == address(wrbtcToken),\n \"wrong asset sent\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(depositAmount);\n\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.collateralToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n\n (uint256 collateralToLoanRate, ) =\n IPriceFeeds(priceFeeds).queryRate(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n\n emit DepositCollateral(loanId, depositAmount, collateralToLoanRate);\n }\n\n /**\n * @notice Withdraw from the collateral. This reduces the margin of a position.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 actualWithdrawAmount) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral,\n loanParamsLocal.maintenanceMargin\n );\n\n if (withdrawAmount > maxDrawdown) {\n actualWithdrawAmount = maxDrawdown;\n } else {\n actualWithdrawAmount = withdrawAmount;\n }\n\n loanLocal.collateral = loanLocal.collateral.sub(actualWithdrawAmount);\n\n if (loanParamsLocal.collateralToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, actualWithdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.collateralToken, receiver, actualWithdrawAmount);\n }\n }\n\n /**\n * @notice Withdraw accrued loan interest.\n *\n * @dev Wrapper for _payInterest internal function.\n *\n * @param loanToken The loan token address.\n * */\n function withdrawAccruedInterest(address loanToken) external whenNotPaused {\n /// Pay outstanding interest to lender.\n _payInterest(\n msg.sender, /// Lender.\n loanToken\n );\n }\n\n /**\n * @notice Extend the loan duration by as much time as depositAmount can buy.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in loan tokens. Used to pay the interest for the new duration.\n * @param useCollateral Whether pay interests w/ the collateral. If true, depositAmount of loan tokens\n *\t\t\t\t\t\twill be purchased with the collateral.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n *\n * @return secondsExtended The amount of time in seconds the loan is extended.\n * */\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external payable nonReentrant whenNotPaused returns (uint256 secondsExtended) {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n !useCollateral ||\n msg.sender == loanLocal.borrower ||\n delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(\n msg.value == 0 || (!useCollateral && loanParamsLocal.loanToken == address(wrbtcToken)),\n \"wrong asset sent\"\n );\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n /// Handle back interest: calculates interest owned since the loan\n /// endtime passed but the loan remained open.\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestOwed = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestOwed.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(86400);\n\n require(depositAmount > backInterestOwed, \"deposit cannot cover back interest\");\n }\n\n /// Deposit interest.\n if (useCollateral) {\n /// Used the whole converted loanToken to extend the loan duration\n depositAmount = _doCollateralSwap(loanLocal, loanParamsLocal, depositAmount);\n } else {\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.loanToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n }\n\n if (backInterestOwed != 0) {\n depositAmount = depositAmount.sub(backInterestOwed);\n\n /// Pay out backInterestOwed\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n secondsExtended = depositAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(secondsExtended);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(depositAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .add(depositAmount);\n }\n\n /**\n * @notice Reduce the loan duration by withdrawing from the deposited interest.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in loan tokens.\n *\n * @return secondsReduced The amount of time in seconds the loan is reduced.\n * */\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 secondsReduced) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(loanLocal.endTimestamp > block.timestamp, \"loan term has ended\");\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 interestDepositRemaining =\n loanLocal.endTimestamp.sub(block.timestamp).mul(loanInterestLocal.owedPerDay).div(\n 86400\n );\n require(withdrawAmount < interestDepositRemaining, \"withdraw amount too high\");\n\n /// Withdraw interest.\n if (loanParamsLocal.loanToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, withdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.loanToken, receiver, withdrawAmount);\n }\n\n secondsReduced = withdrawAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n require(loanLocal.endTimestamp > secondsReduced, \"loan too short\");\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.sub(secondsReduced);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(withdrawAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .sub(withdrawAmount);\n }\n\n /**\n * @notice Get current lender interest data totals for all loans\n * with a specific oracle and interest token.\n *\n * @param lender The lender address.\n * @param loanToken The loan token address.\n *\n * @return interestPaid The total amount of interest that has been paid to a lender so far.\n * @return interestPaidDate The date of the last interest pay out, or 0 if no interest has been withdrawn yet.\n * @return interestOwedPerDay The amount of interest the lender is earning per day.\n * @return interestUnPaid The total amount of interest the lender is owned and not yet withdrawn.\n * @return interestFeePercent The fee retained by the protocol before interest is paid to the lender.\n * @return principalTotal The total amount of outstanding principal the lender has loaned.\n * */\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n )\n {\n LenderInterest memory lenderInterestLocal = lenderInterest[lender][loanToken];\n\n interestUnPaid = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(86400);\n if (interestUnPaid > lenderInterestLocal.owedTotal)\n interestUnPaid = lenderInterestLocal.owedTotal;\n\n return (\n lenderInterestLocal.paidTotal,\n lenderInterestLocal.paidTotal != 0 ? lenderInterestLocal.updatedTimestamp : 0,\n lenderInterestLocal.owedPerDay,\n lenderInterestLocal.updatedTimestamp != 0 ? interestUnPaid : 0,\n lendingFeePercent,\n lenderInterestLocal.principalTotal\n );\n }\n\n /**\n * @notice Get current interest data for a loan.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loanToken The loan token that interest is paid in.\n * @return interestOwedPerDay The amount of interest the borrower is paying per day.\n * @return interestDepositTotal The total amount of interest the borrower has deposited.\n * @return interestDepositRemaining The amount of deposited interest that is not yet owed to a lender.\n * */\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n )\n {\n loanToken = loanParams[loans[loanId].loanParamsId].loanToken;\n interestOwedPerDay = loanInterest[loanId].owedPerDay;\n interestDepositTotal = loanInterest[loanId].depositTotal;\n\n uint256 endTimestamp = loans[loanId].endTimestamp;\n uint256 interestTime = block.timestamp > endTimestamp ? endTimestamp : block.timestamp;\n interestDepositRemaining = endTimestamp > interestTime\n ? endTimestamp.sub(interestTime).mul(interestOwedPerDay).div(86400)\n : 0;\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData) {\n return\n _getLoan(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2) {\n return\n _getLoanV2(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get all active loans.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @dev New view function which will return the loan data.\n * @dev This function was created to support backward compatibility\n * @dev As in we the old getActiveLoans function is not expected to be changed by the wathcers.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loanData The data structure\n * @return extendedLoanData The data structure which contained (borrower & creation time)\n */\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Internal function to get one loan data structure.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ the loan information.\n * */\n function _getLoan(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnData memory loanData) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanData;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanData;\n }\n\n return\n LoanReturnData({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable\n });\n }\n\n /**\n * @notice Internal function to get one loan data structure v2.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data v2 structure w/ the loan information.\n * */\n function _getLoanV2(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnDataV2 memory loanDataV2) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanDataV2;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanDataV2;\n }\n\n return\n LoanReturnDataV2({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n borrower: loanLocal.borrower,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable,\n creationTimestamp: loanLocal.startTimestamp\n });\n }\n\n /**\n * @notice Internal function to collect interest from the collateral.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param depositAmount The amount of underlying tokens provided on the loan.\n * */\n function _doCollateralSwap(\n Loan storage loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 depositAmount\n ) internal returns (uint256 purchasedLoanToken) {\n /// Reverts in _loanSwap if amountNeeded can't be bought.\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanLocal.collateral, /// minSourceTokenAmount\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n depositAmount, /// requiredDestTokenAmount (partial spend of loanLocal.collateral to fill this amount)\n true, /// bypassFee\n \"\" /// loanDataBytes\n );\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n /// Ensure the loan is still healthy.\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n return destTokenAmountReceived;\n }\n}\n" + }, + "contracts/modules/LoanOpenings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\n/**\n * @title Loan Openings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to borrow and trade.\n * */\ncontract LoanOpenings is\n LoanOpeningsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n ModuleCommonFunctionalities\n{\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\n _setTarget(this.borrowOrTradeFromPool.selector, target);\n _setTarget(this.setDelegatedManager.selector, target);\n _setTarget(this.getEstimatedMarginExposure.selector, target);\n _setTarget(this.getRequiredCollateral.selector, target);\n _setTarget(this.getBorrowAmount.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanOpenings\");\n }\n\n /**\n * @notice Borrow or trade from pool.\n *\n * @dev Note: Only callable by loan pools (iTokens).\n * Wrapper to _borrowOrTrade internal function.\n *\n * @param loanParamsId The ID of the loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return newPrincipal The new loan size.\n * @return newCollateral The new collateral amount.\n * */\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n bytes calldata loanDataBytes\n )\n external\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 newPrincipal, uint256 newCollateral)\n {\n require(msg.value == 0 || loanDataBytes.length != 0, \"loanDataBytes required with ether\");\n\n /// Only callable by loan pools.\n require(loanPoolToUnderlying[msg.sender] != address(0), \"not authorized\");\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n /// Get required collateral.\n uint256 collateralAmountRequired =\n _getRequiredCollateral(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentValues.newPrincipal,\n initialMargin,\n isTorqueLoan\n );\n require(collateralAmountRequired != 0, \"collateral is 0\");\n\n return\n _borrowOrTrade(\n loanParamsLocal,\n loanId,\n isTorqueLoan,\n collateralAmountRequired,\n initialMargin,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @dev Wrapper for _setDelegatedManager internal function.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external whenNotPaused {\n require(loans[loanId].borrower == msg.sender, \"unauthorized\");\n\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\n }\n\n /**\n * @notice Get the estimated margin exposure.\n *\n * Margin is the money borrowed from a broker to purchase an investment\n * and is the difference between the total value of investment and the\n * loan amount. Margin trading refers to the practice of using borrowed\n * funds from a broker to trade a financial asset, which forms the\n * collateral for the loan from the broker.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param loanTokenSent The amount of loan tokens sent.\n * @param collateralTokenSent The amount of collateral tokens sent.\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\n * @param newPrincipal The updated amount of principal (current debt).\n *\n * @return The margin exposure.\n * */\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256) {\n uint256 maxLoanTerm = 2419200; // 28 days\n\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\n\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\n\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\n uint256 tradingFee = _getTradingFee(swapAmount);\n if (tradingFee != 0) {\n swapAmount = swapAmount.sub(tradingFee);\n }\n\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\n if (receivedAmount == 0) {\n return 0;\n } else {\n return collateralTokenSent.add(receivedAmount);\n }\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Calls internal _getRequiredCollateral and add fees.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralAmountRequired The required collateral.\n * */\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 collateralAmountRequired) {\n if (marginAmount != 0) {\n collateralAmountRequired = _getRequiredCollateral(\n loanToken,\n collateralToken,\n newPrincipal,\n marginAmount,\n isTorqueLoan\n );\n\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n // cannot be applied solely as it drives to some other tests failure\n /*\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (collateralAmountRequired != 0 && feePercent != 0) {\n\t\t\t\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t);\n\t\t\t}*/\n\n uint256 fee =\n isTorqueLoan\n ? _getBorrowingFee(collateralAmountRequired)\n : _getTradingFee(collateralAmountRequired);\n if (fee != 0) {\n collateralAmountRequired = collateralAmountRequired.add(fee);\n }\n }\n }\n\n /**\n * @notice Get the borrow amount of a trade loan.\n *\n * @dev Basically borrowAmount = collateral / marginAmount\n *\n * Collateral is something that helps secure a loan. When you borrow money,\n * you agree that your lender can take something and sell it to get their\n * money back if you fail to repay the loan. That's the collateral.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param collateralTokenAmount The amount of collateral.\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return borrowAmount The borrow amount.\n * */\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 borrowAmount) {\n if (marginAmount != 0) {\n if (isTorqueLoan) {\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\n }\n uint256 collateral = collateralTokenAmount;\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\n if (fee != 0) {\n collateral = collateral.sub(fee);\n }\n if (loanToken == collateralToken) {\n borrowAmount = collateral.mul(10**20).div(marginAmount);\n } else {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestPrecision != 0) {\n borrowAmount = collateral\n .mul(10**20)\n .mul(sourceToDestRate)\n .div(marginAmount)\n .div(sourceToDestPrecision);\n }\n }\n /*\n\t\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t\t// cannot be applied solely as it drives to some other tests failure\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (borrowAmount != 0 && feePercent != 0) {\n\t\t\t\tborrowAmount = borrowAmount\n\t\t\t\t\t.mul(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t)\n\t\t\t\t\t.divCeil(10**20);\n\t\t\t}*/\n }\n }\n\n /**\n * @notice Borrow or trade.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param collateralAmountRequired The required amount of collateral.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return The new loan size.\n * @return The new collateral amount.\n * */\n function _borrowOrTrade(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 collateralAmountRequired,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n require(\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\n \"collateral/loan match\"\n );\n require(initialMargin >= loanParamsLocal.minInitialMargin, \"initialMargin too low\");\n\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\n require(\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\n \"invalid interest\"\n );\n\n // @note this fix is for borrowing only\n uint256 sentNewPrincipal = isTorqueLoan ? sentValues.newPrincipal : 0;\n\n /// Initialize loan.\n Loan storage loanLocal =\n loans[\n _initializeLoan(\n loanParamsLocal,\n loanId,\n initialMargin,\n sentAddresses,\n sentValues.newPrincipal\n )\n ];\n\n // Get required interest.\n uint256 amount =\n _initializeInterest(\n loanParamsLocal,\n loanLocal,\n sentValues.interestRate, /// newRate\n sentValues.newPrincipal, /// newPrincipal,\n sentValues.interestInitialAmount /// torqueInterest\n );\n\n /// substract out interest from usable loanToken sent.\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\n\n if (isTorqueLoan) {\n require(sentValues.loanTokenSent == 0, \"surplus loan token\");\n\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\n // need to temp into local state to avoid\n address _collateralToken = loanParamsLocal.collateralToken;\n address _loanToken = loanParamsLocal.loanToken;\n if (borrowingFee != 0) {\n _payBorrowingFee(\n sentAddresses.borrower, /// borrower\n loanLocal.id,\n _collateralToken, /// fee token\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n borrowingFee\n );\n\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\n }\n } else {\n /// Update collateral after trade.\n sentValues = _updateCollateralAfterTrade(\n loanId,\n loanParamsLocal,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /// Settle collateral.\n require(\n _isCollateralSatisfied(\n loanParamsLocal,\n loanLocal,\n initialMargin,\n sentValues.collateralTokenSent,\n collateralAmountRequired,\n sentNewPrincipal\n ),\n \"collateral insufficient\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\n\n if (isTorqueLoan) {\n /// reclaiming variable -> interestDuration\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\n } else {\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\n }\n\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\n\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\n }\n\n function _updateCollateralAfterTrade(\n bytes32 loanId,\n LoanParams memory loanParamsLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (MarginTradeStructHelpers.SentAmounts memory) {\n uint256 receivedAmount;\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\n loanId,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentAddresses.borrower, /// borrower\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\n false, /// bypassFee\n loanDataBytes\n );\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\n\n /// Check the minEntryPrice with the rate\n require(\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\n \"entry price above the minimum\"\n );\n\n return sentValues;\n }\n\n /**\n * @notice Finalize an open loan.\n *\n * @dev Finalize it by updating local parameters of the loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _finalizeOpen(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bool isTorqueLoan\n ) internal {\n /// @dev TODO: here the actual used rate and margin should go.\n (uint256 initialMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(initialMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n if (loanLocal.startTimestamp == block.timestamp) {\n uint256 loanToCollateralPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken\n );\n uint256 collateralToLoanPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\n loanLocal.startRate = isTorqueLoan\n ? collateralToLoanRate\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\n }\n\n _emitOpeningEvents(\n loanParamsLocal,\n loanLocal,\n sentAddresses,\n sentValues,\n collateralToLoanRate,\n initialMargin,\n isTorqueLoan\n );\n }\n\n /**\n * @notice Emit the opening events.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n * @param margin The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _emitOpeningEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n uint256 collateralToLoanRate,\n uint256 margin,\n bool isTorqueLoan\n ) internal {\n if (isTorqueLoan) {\n emit Borrow(\n sentAddresses.borrower, /// user (borrower)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n sentValues.newPrincipal, /// newPrincipal\n sentValues.collateralTokenSent, /// newCollateral\n sentValues.interestRate, /// interestRate\n sentValues.interestDuration, /// interestDuration\n collateralToLoanRate, /// collateralToLoanRate,\n margin /// currentMargin\n );\n } else {\n /// currentLeverage = 100 / currentMargin\n margin = SafeMath.div(10**38, margin);\n\n emit Trade(\n sentAddresses.borrower, /// user (trader)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n sentValues.collateralTokenSent, /// positionSize\n sentValues.newPrincipal, /// borrowedAmount\n sentValues.interestRate, /// interestRate,\n loanLocal.endTimestamp, /// settlementDate\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\n sentValues.entryLeverage, /// entryLeverage\n margin /// currentLeverage\n );\n }\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegator The address of previous manager.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function _setDelegatedManager(\n bytes32 loanId,\n address delegator,\n address delegated,\n bool toggle\n ) internal {\n delegatedManagers[loanId][delegated] = toggle;\n\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\n }\n\n /**\n * @notice Calculate whether the collateral is satisfied.\n *\n * @dev Basically check collateral + drawdown >= 98% of required.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param initialMargin The initial amount of margin.\n * @param newCollateral The amount of new collateral.\n * @param collateralAmountRequired The amount of required collateral.\n * @param newPrincipal The amount to borrow.\n *\n * @return Whether the collateral is satisfied.\n * */\n function _isCollateralSatisfied(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 initialMargin,\n uint256 newCollateral,\n uint256 collateralAmountRequired,\n uint256 newPrincipal\n ) internal view returns (bool) {\n /// Allow at most 2% under-collateralized.\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\n\n if (newCollateral < collateralAmountRequired) {\n /// Check that existing collateral is sufficient coverage.\n if (loanLocal.collateral != 0) {\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal.sub(newPrincipal), // sub(newPrincipal) to exclude the new borrowed amount from the total principal to calculate maxDrawdown for existing loan\n loanLocal.collateral,\n initialMargin\n );\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\n } else {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @notice Initialize a loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan.\n * @param initialMargin The amount of margin of the trade.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\n * @return The loanId.\n * */\n function _initializeLoan(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n uint256 newPrincipal\n ) internal returns (bytes32) {\n require(loanParamsLocal.active, \"loanParams disabled\");\n\n address lender = sentAddresses.lender;\n address borrower = sentAddresses.borrower;\n address manager = sentAddresses.manager;\n\n Loan memory loanLocal;\n\n if (loanId == 0) {\n borrowerNonce[borrower]++;\n loanId = keccak256(\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\n );\n require(loans[loanId].id == 0, \"loan exists\");\n\n loanLocal = Loan({\n id: loanId,\n loanParamsId: loanParamsLocal.id,\n pendingTradesId: 0,\n active: true,\n principal: newPrincipal,\n collateral: 0, /// calculated later\n startTimestamp: block.timestamp,\n endTimestamp: 0, /// calculated later\n startMargin: initialMargin,\n startRate: 0, /// queried later\n borrower: borrower,\n lender: lender\n });\n\n activeLoansSet.addBytes32(loanId);\n lenderLoanSets[lender].addBytes32(loanId);\n borrowerLoanSets[borrower].addBytes32(loanId);\n } else {\n loanLocal = loans[loanId];\n require(\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\n \"loan has ended\"\n );\n require(loanLocal.borrower == borrower, \"borrower mismatch\");\n require(loanLocal.lender == lender, \"lender mismatch\");\n require(loanLocal.loanParamsId == loanParamsLocal.id, \"loanParams mismatch\");\n\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\n }\n\n if (manager != address(0)) {\n _setDelegatedManager(loanId, borrower, manager, true);\n }\n\n loans[loanId] = loanLocal;\n\n return loanId;\n }\n\n /**\n * @notice Initialize a loan interest.\n *\n * @dev A Torque loan is an indefinite-term loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param newRate The new interest rate of the loan.\n * @param newPrincipal The new principal amount of the loan.\n * @param torqueInterest The interest rate of the Torque loan.\n *\n * @return interestAmountRequired The interest amount required.\n * */\n function _initializeInterest(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n uint256 newRate,\n uint256 newPrincipal,\n uint256 torqueInterest /// ignored for fixed-term loans\n ) internal returns (uint256 interestAmountRequired) {\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 previousDepositRemaining;\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\n previousDepositRemaining = loanLocal\n .endTimestamp\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\n .mul(loanInterestLocal.owedPerDay)\n .div(86400);\n }\n\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\n\n /// Update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n\n if (maxLoanTerm == 0) {\n /// Indefinite-term (Torque) loan.\n\n /// torqueInterest != 0 was confirmed earlier.\n loanLocal.endTimestamp = torqueInterest\n .add(previousDepositRemaining)\n .mul(86400)\n .div(loanInterestLocal.owedPerDay)\n .add(block.timestamp);\n\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxLoanTerm > 3600, \"loan too short\");\n\n interestAmountRequired = torqueInterest;\n } else {\n /// Fixed-term loan.\n\n if (loanLocal.endTimestamp == 0) {\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\n }\n\n interestAmountRequired = loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(owedPerDay)\n .div(86400);\n }\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n /// Update remaining lender interest values.\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Basically collateral = newPrincipal * marginAmount\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralTokenAmount The required collateral.\n * */\n function _getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) internal view returns (uint256 collateralTokenAmount) {\n if (loanToken == collateralToken) {\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\n } else {\n /// Using the price feed instead of the swap expected return\n /// because we need the rate in the inverse direction\n /// so the swap is probably farther off than the price feed.\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestRate != 0) {\n collateralTokenAmount = newPrincipal\n .mul(sourceToDestPrecision)\n .div(sourceToDestRate)\n .mul(marginAmount)\n .div(10**20);\n /*TODO: review\n\t\t\t\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\n }\n }\n // ./tests/loan-token/TradingTestToken.test.js\n if (isTorqueLoan && collateralTokenAmount != 0) {\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\n collateralTokenAmount\n );\n }\n }\n}\n" + }, + "contracts/modules/LoanSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to get and set loan parameters.\n * */\ncontract LoanSettings is State, LoanSettingsEvents, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"LoanSettings - fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setupLoanParams.selector];\n _setTarget(this.setupLoanParams.selector, target);\n _setTarget(this.disableLoanParams.selector, target);\n _setTarget(this.getLoanParams.selector, target);\n _setTarget(this.getLoanParamsList.selector, target);\n _setTarget(this.getTotalPrincipal.selector, target);\n _setTarget(this.minInitialMargin.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanSettings\");\n }\n\n /**\n * @notice Setup loan parameters, by looping every loan\n * and populating its parameters.\n *\n * @dev For each loan calls _setupLoanParams internal function.\n *\n * @param loanParamsList The array of loan parameters.\n *\n * @return loanParamsIdList The array of loan parameters IDs.\n * */\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n whenNotPaused\n returns (bytes32[] memory loanParamsIdList)\n {\n loanParamsIdList = new bytes32[](loanParamsList.length);\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsIdList[i] = _setupLoanParams(loanParamsList[i]);\n }\n }\n\n /**\n * @notice Deactivate LoanParams for future loans. Active loans\n * using it are unaffected.\n *\n * @param loanParamsIdList The array of loan parameters IDs to deactivate.\n * */\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external whenNotPaused {\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n require(msg.sender == loanParams[loanParamsIdList[i]].owner, \"unauthorized owner\");\n loanParams[loanParamsIdList[i]].active = false;\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n emit LoanParamsDisabled(\n loanParamsLocal.id,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdDisabled(loanParamsLocal.id, loanParamsLocal.owner);\n }\n }\n\n /**\n * @notice Get loan parameters for every matching IDs.\n *\n * @param loanParamsIdList The array of loan parameters IDs to match.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParams(bytes32[] memory loanParamsIdList)\n public\n view\n returns (LoanParams[] memory loanParamsList)\n {\n loanParamsList = new LoanParams[](loanParamsIdList.length);\n uint256 itemCount;\n\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n if (loanParamsLocal.id == 0) {\n continue;\n }\n loanParamsList[itemCount] = loanParamsLocal;\n itemCount++;\n }\n\n if (itemCount < loanParamsList.length) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get loan parameters for an owner and a given page\n * defined by an offset and a limit.\n *\n * @param owner The address of the loan owner.\n * @param start The page offset.\n * @param count The page limit.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList) {\n EnumerableBytes32Set.Bytes32Set storage set = userLoanParamSets[owner];\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loanParamsList;\n }\n\n loanParamsList = new bytes32[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n loanParamsList[itemCount] = set.get(i + start - 1);\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get the total principal of the loans by a lender.\n *\n * @param lender The address of the lender.\n * @param loanToken The address of the token instance.\n *\n * @return The total principal of the loans.\n * */\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256) {\n return lenderInterest[lender][loanToken].principalTotal;\n }\n\n /**\n * @notice Setup a loan parameters.\n *\n * @param loanParamsLocal The loan parameters.\n *\n * @return loanParamsId The loan parameters ID.\n * */\n function _setupLoanParams(LoanParams memory loanParamsLocal) internal returns (bytes32) {\n bytes32 loanParamsId =\n keccak256(\n abi.encodePacked(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm,\n block.timestamp\n )\n );\n require(loanParams[loanParamsId].id == 0, \"loanParams exists\");\n\n require(\n loanParamsLocal.loanToken != address(0) &&\n loanParamsLocal.collateralToken != address(0) &&\n loanParamsLocal.minInitialMargin > loanParamsLocal.maintenanceMargin &&\n (loanParamsLocal.maxLoanTerm == 0 || loanParamsLocal.maxLoanTerm > 3600), /// A defined maxLoanTerm has to be greater than one hour.\n \"invalid params\"\n );\n\n loanParamsLocal.id = loanParamsId;\n loanParamsLocal.active = true;\n loanParamsLocal.owner = msg.sender;\n\n loanParams[loanParamsId] = loanParamsLocal;\n userLoanParamSets[msg.sender].addBytes32(loanParamsId);\n\n emit LoanParamsSetup(\n loanParamsId,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdSetup(loanParamsId, loanParamsLocal.owner);\n\n return loanParamsId;\n }\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256) {\n return loanParams[loanParamsId].minInitialMargin;\n }\n}\n" + }, + "contracts/modules/ProtocolSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../mixins/ProtocolTokenUser.sol\";\nimport \"../modules/interfaces/ProtocolSwapExternalInterface.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../governance/IFeeSharingCollector.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title Protocol Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to customize protocol settings.\n * */\ncontract ProtocolSettings is\n State,\n ProtocolTokenUser,\n ProtocolSettingsEvents,\n ModuleCommonFunctionalities\n{\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyAdminOrOwner {\n address prevModuleContractAddress = logicTargets[this.setPriceFeedContract.selector];\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n _setTarget(this.setRebatePercent.selector, target);\n _setTarget(this.setSpecialRebates.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.togglePaused.selector, target);\n _setTarget(this.isProtocolPaused.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n _setTarget(this.setRolloverFlexFeePercent.selector, target);\n _setTarget(this.getDefaultPathConversion.selector, target);\n _setTarget(this.setDefaultPathConversion.selector, target);\n _setTarget(this.removeDefaultPathConversion.selector, target);\n _setTarget(this.setAdmin.selector, target);\n _setTarget(this.getAdmin.selector, target);\n _setTarget(this.setPauser.selector, target);\n _setTarget(this.getPauser.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"ProtocolSettings\");\n }\n\n /**\n * setting wrong address will break inter module functions calling\n * should be set once\n */\n function setSovrynProtocolAddress(address newProtocolAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address oldProtocolAddress = protocolAddress;\n protocolAddress = newProtocolAddress;\n\n emit SetProtocolAddress(msg.sender, oldProtocolAddress, newProtocolAddress);\n }\n\n function setSOVTokenAddress(address newSovTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newSovTokenAddress), \"newSovTokenAddress not a contract\");\n\n address oldTokenAddress = sovTokenAddress;\n sovTokenAddress = newSovTokenAddress;\n\n emit SetSOVTokenAddress(msg.sender, oldTokenAddress, newSovTokenAddress);\n }\n\n function setLockedSOVAddress(address newLockedSOVAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newLockedSOVAddress), \"newLockSOVAddress not a contract\");\n\n address oldLockedSOVAddress = lockedSOVAddress;\n lockedSOVAddress = newLockedSOVAddress;\n\n emit SetLockedSOVAddress(msg.sender, oldLockedSOVAddress, newLockedSOVAddress);\n }\n\n /**\n * @notice Set the basis point of trading rebate rewards (SOV), max value is 9999 (99.99% liquid, 0.01% vested).\n *\n * @param newBasisPoint Basis point value.\n */\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newBasisPoint <= 9999, \"value too high\");\n\n uint256 oldBasisPoint = tradingRebateRewardsBasisPoint;\n tradingRebateRewardsBasisPoint = newBasisPoint;\n\n emit SetTradingRebateRewardsBasisPoint(msg.sender, oldBasisPoint, newBasisPoint);\n }\n\n /**\n * @notice Update the minimum number of referrals to get affiliates rewards.\n *\n * @param newMinReferrals The new minimum number of referrals.\n * */\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n uint256 oldMinReferrals = minReferralsToPayout;\n minReferralsToPayout = newMinReferrals;\n\n emit SetMinReferralsToPayoutAffiliates(msg.sender, oldMinReferrals, newMinReferrals);\n }\n\n /**\n * @notice Set the address of the Price Feed instance.\n *\n * @param newContract The address of the Price Feed new instance.\n * */\n function setPriceFeedContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = priceFeeds;\n priceFeeds = newContract;\n\n emit SetPriceFeedContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set the address of the asset swapper instance.\n *\n * @param newContract The address of the asset swapper new instance.\n * */\n function setSwapsImplContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = swapsImpl;\n swapsImpl = newContract;\n\n emit SetSwapsImplContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set a list of loan pools and its tokens.\n *\n * @param pools The array of addresses of new loan pool instances.\n * @param assets The array of addresses of the corresponding underlying tokens.\n * */\n function setLoanPool(address[] calldata pools, address[] calldata assets)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(pools.length == assets.length, \"count mismatch\");\n\n for (uint256 i = 0; i < pools.length; i++) {\n require(pools[i] != assets[i], \"pool == asset\");\n require(pools[i] != address(0), \"pool == 0\");\n require(\n assets[i] != address(0) || loanPoolToUnderlying[pools[i]] != address(0),\n \"pool not exists\"\n );\n if (assets[i] == address(0)) {\n underlyingToLoanPool[loanPoolToUnderlying[pools[i]]] = address(0);\n loanPoolToUnderlying[pools[i]] = address(0);\n loanPoolsSet.removeAddress(pools[i]);\n } else {\n loanPoolToUnderlying[pools[i]] = assets[i];\n underlyingToLoanPool[assets[i]] = pools[i];\n loanPoolsSet.addAddress(pools[i]);\n }\n\n emit SetLoanPool(msg.sender, pools[i], assets[i]);\n }\n }\n\n /**\n * @notice Set a list of supported tokens by populating the\n * storage supportedTokens mapping.\n *\n * @param addrs The array of addresses of the tokens.\n * @param toggles The array of flags indicating whether\n * the corresponding token is supported or not.\n * */\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(addrs.length == toggles.length, \"count mismatch\");\n\n for (uint256 i = 0; i < addrs.length; i++) {\n supportedTokens[addrs[i]] = toggles[i];\n\n emit SetSupportedTokens(msg.sender, addrs[i], toggles[i]);\n }\n }\n\n /**\n * @notice Set the value of lendingFeePercent storage variable.\n *\n * @param newValue The new value for lendingFeePercent.\n * */\n function setLendingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = lendingFeePercent;\n lendingFeePercent = newValue;\n\n emit SetLendingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of tradingFeePercent storage variable.\n *\n * @param newValue The new value for tradingFeePercent.\n * */\n function setTradingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = tradingFeePercent;\n tradingFeePercent = newValue;\n\n emit SetTradingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of borrowingFeePercent storage variable.\n *\n * @param newValue The new value for borrowingFeePercent.\n * */\n function setBorrowingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = borrowingFeePercent;\n borrowingFeePercent = newValue;\n\n emit SetBorrowingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of swapExtrernalFeePercent storage variable\n *\n * @param newValue the new value for swapExternalFeePercent\n */\n function setSwapExternalFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = swapExtrernalFeePercent;\n swapExtrernalFeePercent = newValue;\n\n emit SetSwapExternalFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateFeePercent storage variable.\n *\n * @param newValue The new value for affiliateFeePercent.\n * */\n function setAffiliateFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateFeePercent;\n affiliateFeePercent = newValue;\n\n emit SetAffiliateFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateTradingTokenFeePercent storage variable.\n *\n * @param newValue The new value for affiliateTradingTokenFeePercent.\n * */\n function setAffiliateTradingTokenFeePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateTradingTokenFeePercent;\n affiliateTradingTokenFeePercent = newValue;\n\n emit SetAffiliateTradingTokenFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of liquidationIncentivePercent storage variable.\n *\n * @param newValue The new value for liquidationIncentivePercent.\n * */\n function setLiquidationIncentivePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = liquidationIncentivePercent;\n liquidationIncentivePercent = newValue;\n\n emit SetLiquidationIncentivePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of the maximum swap spread.\n *\n * @param newValue The new value for maxDisagreement.\n * */\n function setMaxDisagreement(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n maxDisagreement = newValue;\n }\n\n /**\n * @notice Set the value of the maximum source buffer.\n *\n * @dev To avoid rounding issues on the swap rate a small buffer is implemented.\n *\n * @param newValue The new value for the maximum source buffer.\n * */\n function setSourceBuffer(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n sourceBuffer = newValue;\n }\n\n /**\n * @notice Set the value of the swap size limit.\n *\n * @param newValue The new value for the maximum swap size.\n * */\n function setMaxSwapSize(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n uint256 oldValue = maxSwapSize;\n maxSwapSize = newValue;\n\n emit SetMaxSwapSize(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the address of the feesController instance.\n *\n * @dev The fee sharing proxy must be the feesController of the\n * protocol contract. This allows the fee sharing proxy\n * to withdraw the fees.\n *\n * @param newController The new address of the feesController.\n * */\n function setFeesController(address newController) external onlyAdminOrOwner whenNotPaused {\n address oldController = feesController;\n feesController = newController;\n\n emit SetFeesController(msg.sender, oldController, newController);\n }\n\n /**\n * @notice Set the pauser address of sovryn protocol.\n *\n * only pauser or owner can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Get pauser address.\n *\n *\n * @return pauser address.\n */\n function getPauser() external view returns (address) {\n return pauser;\n }\n\n /*\n * @notice Set the admin address of sovryn protocol.\n *\n * only owner can perform this action.\n *\n * @param newAdmin The new address of the admin.\n * */\n function setAdmin(address newAdmin) external onlyOwner {\n emit SetAdmin(msg.sender, admin, newAdmin);\n admin = newAdmin;\n }\n\n /**\n * @dev Get admin address.\n *\n *\n * @return admin address.\n */\n function getAdmin() external view returns (address) {\n return admin;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * from three sources: lending, trading and borrowing.\n * The fees (except SOV) will be converted to wRBTC.\n * For SOV, it will be deposited directly to feeSharingCollector from the protocol.\n *\n * @param tokens The array of address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n whenNotPaused\n returns (uint256 totalWRBTCWithdrawn)\n {\n require(msg.sender == feesController, \"unauthorized\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n uint256 lendingBalance = lendingFeeTokensHeld[tokens[i]];\n if (lendingBalance > 0) {\n lendingFeeTokensHeld[tokens[i]] = 0;\n lendingFeeTokensPaid[tokens[i]] = lendingFeeTokensPaid[tokens[i]].add(\n lendingBalance\n );\n }\n\n uint256 tradingBalance = tradingFeeTokensHeld[tokens[i]];\n if (tradingBalance > 0) {\n tradingFeeTokensHeld[tokens[i]] = 0;\n tradingFeeTokensPaid[tokens[i]] = tradingFeeTokensPaid[tokens[i]].add(\n tradingBalance\n );\n }\n\n uint256 borrowingBalance = borrowingFeeTokensHeld[tokens[i]];\n if (borrowingBalance > 0) {\n borrowingFeeTokensHeld[tokens[i]] = 0;\n borrowingFeeTokensPaid[tokens[i]] = borrowingFeeTokensPaid[tokens[i]].add(\n borrowingBalance\n );\n }\n\n uint256 tempAmount = lendingBalance.add(tradingBalance).add(borrowingBalance);\n\n if (tempAmount == 0) {\n continue;\n }\n\n uint256 amountConvertedToWRBTC;\n if (tokens[i] == address(sovTokenAddress)) {\n IERC20(tokens[i]).approve(feesController, tempAmount);\n IFeeSharingCollector(feesController).transferTokens(\n address(sovTokenAddress),\n uint96(tempAmount)\n );\n amountConvertedToWRBTC = 0;\n } else {\n if (tokens[i] == address(wrbtcToken)) {\n amountConvertedToWRBTC = tempAmount;\n\n IERC20(address(wrbtcToken)).safeTransfer(receiver, amountConvertedToWRBTC);\n } else {\n IERC20(tokens[i]).approve(protocolAddress, tempAmount);\n\n (amountConvertedToWRBTC, ) = ProtocolSwapExternalInterface(protocolAddress)\n .swapExternal(\n tokens[i], // source token address\n address(wrbtcToken), // dest token address\n feesController, // set feeSharingCollector as receiver\n protocolAddress, // protocol as the sender\n tempAmount, // source token amount\n 0, // reqDestToken\n 0, // minReturn\n \"\" // loan data bytes\n );\n\n /// Will revert if disagreement found.\n IPriceFeeds(priceFeeds).checkPriceDisagreement(\n tokens[i],\n address(wrbtcToken),\n tempAmount,\n amountConvertedToWRBTC,\n maxDisagreement\n );\n }\n\n totalWRBTCWithdrawn = totalWRBTCWithdrawn.add(amountConvertedToWRBTC);\n }\n\n emit WithdrawFees(\n msg.sender,\n tokens[i],\n receiver,\n lendingBalance,\n tradingBalance,\n borrowingBalance,\n amountConvertedToWRBTC\n );\n }\n\n return totalWRBTCWithdrawn;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from lending operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = lendingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n lendingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n lendingFeeTokensPaid[token] = lendingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawLendingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from trading operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = tradingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n tradingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n tradingFeeTokensPaid[token] = tradingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawTradingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from borrowing operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = borrowingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n borrowingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n borrowingFeeTokensPaid[token] = borrowingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawBorrowingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The owner calls this function to withdraw protocol tokens.\n *\n * @dev Wrapper for ProtocolTokenUser::_withdrawProtocolToken internal function.\n *\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of tokens to get.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n onlyAdminOrOwner\n whenNotPaused\n returns (address, bool)\n {\n return _withdrawProtocolToken(receiver, amount);\n }\n\n /**\n * @notice The owner calls this function to deposit protocol tokens.\n *\n * @param amount The tokens of fees to send.\n * */\n function depositProtocolToken(uint256 amount) external onlyAdminOrOwner whenNotPaused {\n /// @dev Update local balance\n protocolTokenHeld = protocolTokenHeld.add(amount);\n\n /// @dev Send the tokens\n IERC20(protocolTokenAddress).safeTransferFrom(msg.sender, address(this), amount);\n }\n\n /**\n * @notice Get a list of loan pools.\n *\n * @param start The offset.\n * @param count The limit.\n *\n * @return The array of loan pools.\n * */\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory)\n {\n return loanPoolsSet.enumerate(start, count);\n }\n\n /**\n * @notice Check whether a token is a pool token.\n *\n * @dev By querying its underlying token.\n *\n * @param loanPool The token address to check.\n * */\n function isLoanPool(address loanPool) external view returns (bool) {\n return loanPoolToUnderlying[loanPool] != address(0);\n }\n\n /**\n * @notice Set the contract registry address of the SovrynSwap network.\n *\n * @param registryAddress the address of the registry contract.\n * */\n function setSovrynSwapContractRegistryAddress(address registryAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(registryAddress), \"registryAddress not a contract\");\n\n address oldSovrynSwapContractRegistryAddress = sovrynSwapContractRegistryAddress;\n sovrynSwapContractRegistryAddress = registryAddress;\n\n emit SetSovrynSwapContractRegistryAddress(\n msg.sender,\n oldSovrynSwapContractRegistryAddress,\n sovrynSwapContractRegistryAddress\n );\n }\n\n /**\n * @notice Set the wrBTC contract address.\n *\n * @param wrbtcTokenAddress The address of the wrBTC contract.\n * */\n function setWrbtcToken(address wrbtcTokenAddress) external onlyAdminOrOwner whenNotPaused {\n require(Address.isContract(wrbtcTokenAddress), \"wrbtcTokenAddress not a contract\");\n\n address oldwrbtcToken = address(wrbtcToken);\n wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n emit SetWrbtcToken(msg.sender, oldwrbtcToken, wrbtcTokenAddress);\n }\n\n /**\n * @notice Set the protocol token contract address.\n *\n * @param _protocolTokenAddress The address of the protocol token contract.\n * */\n function setProtocolTokenAddress(address _protocolTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n\n address oldProtocolTokenAddress = protocolTokenAddress;\n protocolTokenAddress = _protocolTokenAddress;\n\n emit SetProtocolTokenAddress(msg.sender, oldProtocolTokenAddress, _protocolTokenAddress);\n }\n\n /**\n * @notice Set rollover base reward. It should be denominated in wrBTC.\n *\n * @param baseRewardValue The base reward.\n * */\n function setRolloverBaseReward(uint256 baseRewardValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(baseRewardValue > 0, \"Base reward is zero\");\n\n uint256 oldValue = rolloverBaseReward;\n rolloverBaseReward = baseRewardValue;\n\n emit SetRolloverBaseReward(msg.sender, oldValue, rolloverBaseReward);\n }\n\n /**\n * @notice Set the fee rebate percent.\n *\n * @param rebatePercent The fee rebate percent.\n * */\n function setRebatePercent(uint256 rebatePercent) external onlyAdminOrOwner whenNotPaused {\n require(rebatePercent <= 10**20, \"Fee rebate is too high\");\n\n uint256 oldRebatePercent = feeRebatePercent;\n feeRebatePercent = rebatePercent;\n\n emit SetRebatePercent(msg.sender, oldRebatePercent, rebatePercent);\n }\n\n /**\n * @notice Set the special fee rebate percent for specific pair\n *\n * @param specialRebatesPercent The new special fee rebate percent.\n * */\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external onlyAdminOrOwner whenNotPaused {\n // Set max special rebates to 1000%\n require(specialRebatesPercent <= 1000e18, \"Special fee rebate is too high\");\n\n uint256 oldSpecialRebatesPercent = specialRebates[sourceToken][destToken];\n specialRebates[sourceToken][destToken] = specialRebatesPercent;\n\n emit SetSpecialRebates(\n msg.sender,\n sourceToken,\n destToken,\n oldSpecialRebatesPercent,\n specialRebatesPercent\n );\n }\n\n /**\n * @notice Get a rebate percent of specific pairs.\n *\n * @param sourceTokenAddress The source of pairs.\n * @param destTokenAddress The dest of pairs.\n *\n * @return The percent rebates of the pairs.\n * */\n function getSpecialRebates(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 specialRebatesPercent)\n {\n return specialRebates[sourceTokenAddress][destTokenAddress];\n }\n\n function getProtocolAddress() external view returns (address) {\n return protocolAddress;\n }\n\n function getSovTokenAddress() external view returns (address) {\n return sovTokenAddress;\n }\n\n function getLockedSOVAddress() external view returns (address) {\n return lockedSOVAddress;\n }\n\n function getFeeRebatePercent() external view returns (uint256) {\n return feeRebatePercent;\n }\n\n function togglePaused(bool paused) external onlyPauserOrOwner {\n require(paused != pause, \"Can't toggle\");\n pause = paused;\n emit TogglePaused(msg.sender, !paused, paused);\n }\n\n function isProtocolPaused() external view returns (bool) {\n return pause;\n }\n\n function getSwapExternalFeePercent() external view returns (uint256) {\n return swapExtrernalFeePercent;\n }\n\n /**\n * @notice Get the basis point of trading rebate rewards.\n *\n * @return The basis point value.\n */\n function getTradingRebateRewardsBasisPoint() external view returns (uint256) {\n return tradingRebateRewardsBasisPoint;\n }\n\n /**\n * @dev Get how much SOV that is dedicated to pay the trading rebate rewards.\n * @notice If SOV balance is less than the fees held, it will return 0.\n *\n * @return total dedicated SOV.\n */\n function getDedicatedSOVRebate() public view returns (uint256) {\n uint256 sovProtocolBalance = IERC20(sovTokenAddress).balanceOf(address(this));\n uint256 sovFees =\n lendingFeeTokensHeld[sovTokenAddress].add(tradingFeeTokensHeld[sovTokenAddress]).add(\n borrowingFeeTokensHeld[sovTokenAddress]\n );\n\n return sovProtocolBalance >= sovFees ? sovProtocolBalance.sub(sovFees) : 0;\n }\n\n /**\n * @notice Set rolloverFlexFeePercent (max value is 1%)\n *\n * @param newRolloverFlexFeePercent uint256 value of new rollover flex fee percentage (0.1 ether = 0.1%)\n */\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newRolloverFlexFeePercent <= 1e18, \"value too high\");\n uint256 oldRolloverFlexFeePercent = rolloverFlexFeePercent;\n rolloverFlexFeePercent = newRolloverFlexFeePercent;\n\n emit SetRolloverFlexFeePercent(\n msg.sender,\n oldRolloverFlexFeePercent,\n newRolloverFlexFeePercent\n );\n }\n\n /**\n * @dev Get default path conversion for pairs.\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address.\n *\n * @return default path of the conversion.\n */\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory)\n {\n return defaultPathConversion[sourceTokenAddress][destTokenAddress];\n }\n\n /**\n * @dev Set default path conversion for pairs.\n *\n * @param defaultPath array of addresses for the default path.\n *\n */\n function setDefaultPathConversion(IERC20[] calldata defaultPath)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address sourceTokenAddress = address(defaultPath[0]);\n address destTokenAddress = address(defaultPath[defaultPath.length - 1]);\n\n uint256 defaultPathLength = defaultPath.length;\n require(defaultPathLength >= 3, \"ERR_PATH_LENGTH\");\n\n for (uint256 i = 0; i < defaultPathLength; i++) {\n require(Address.isContract(address(defaultPath[i])), \"ERR_PATH_NON_CONTRACT_ADDR\");\n }\n\n defaultPathConversion[sourceTokenAddress][destTokenAddress] = defaultPath;\n\n emit SetDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPath\n );\n }\n\n /**\n * @dev Remove the default path conversion for pairs\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address\n */\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(\n defaultPathConversion[sourceTokenAddress][destTokenAddress].length > 0,\n \"DEFAULT_PATH_EMPTY\"\n );\n\n IERC20[] memory defaultPathValue =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n delete defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n emit RemoveDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPathValue\n );\n }\n}\n" + }, + "contracts/modules/SwapsExternal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Swaps External contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to calculate and execute swaps.\n * */\ncontract SwapsExternal is VaultController, SwapsUser, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.swapExternal.selector];\n _setTarget(this.swapExternal.selector, target);\n _setTarget(this.getSwapExpectedReturn.selector, target);\n _setTarget(this.checkPriceDivergence.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"SwapsExternal\");\n }\n\n /**\n * @notice Perform a swap w/ tokens or rBTC as source currency.\n *\n * @dev External wrapper that calls SwapsUser::_swapsCall\n * after turning potential incoming rBTC into wrBTC tokens.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param receiver The address of the recipient account.\n * @param returnToSender The address of the sender account.\n * @param sourceTokenAmount The amount of source tokens.\n * @param requiredDestTokenAmount The amount of required destiny tokens.\n * @param minReturn Minimum amount (position size) in the collateral tokens.\n * @param swapData Additional swap data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes memory swapData\n )\n public\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(sourceTokenAmount != 0, \"sourceTokenAmount == 0\");\n checkPriceDivergence(sourceToken, destToken, sourceTokenAmount, minReturn);\n\n /// @dev Get payed value, be it rBTC or tokenized.\n if (msg.value != 0) {\n if (sourceToken == address(0)) {\n sourceToken = address(wrbtcToken);\n }\n require(sourceToken == address(wrbtcToken), \"sourceToken mismatch\");\n require(msg.value == sourceTokenAmount, \"sourceTokenAmount mismatch\");\n\n /// @dev Update wrBTC balance for this contract.\n wrbtcToken.deposit.value(sourceTokenAmount)();\n } else {\n if (address(this) != msg.sender) {\n IERC20(sourceToken).safeTransferFrom(msg.sender, address(this), sourceTokenAmount);\n }\n }\n\n /// @dev Perform the swap w/ tokens.\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n receiver,\n returnToSender,\n msg.sender /// user\n ],\n [\n sourceTokenAmount, /// minSourceTokenAmount\n sourceTokenAmount, /// maxSourceTokenAmount\n requiredDestTokenAmount\n ],\n 0, /// loanId (not tied to a specific loan)\n false, /// bypassFee\n swapData,\n true // the flag for swapExternal (so that it will use the swapExternalFeePercent)\n );\n\n emit ExternalSwap(\n msg.sender, /// user\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Get the swap expected return value.\n *\n * @dev External wrapper that calls SwapsUser::_swapsExpectedReturn\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n *\n * @return The expected return value.\n * */\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n }\n\n /**\n * @notice Check the slippage based on the swapExpectedReturn.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n * @param minReturn The amount (max slippage) that will be compared to the swapsExpectedReturn.\n *\n */\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view {\n uint256 destTokenAmount = _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n require(destTokenAmount >= minReturn, \"destTokenAmountReceived too low\");\n }\n}\n" + }, + "contracts/modules/SwapsImplSovrynSwapModule.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../swaps/connectors/SwapsImplSovrynSwapLib.sol\";\nimport \"../events/ModulesCommonEvents.sol\";\n\ncontract SwapsImplSovrynSwapModule is State, ModulesCommonEvents {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress =\n logicTargets[this.getSovrynSwapNetworkContract.selector];\n _setTarget(this.getSovrynSwapNetworkContract.selector, target);\n _setTarget(this.getContractHexName.selector, target);\n _setTarget(this.swapsImplExpectedRate.selector, target);\n _setTarget(this.swapsImplExpectedReturn.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"SwapsImplSovrynSwapModule\"\n );\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n return SwapsImplSovrynSwapLib.getContractHexName(source);\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n return SwapsImplSovrynSwapLib.getSovrynSwapNetworkContract(sovrynSwapRegistryAddress);\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return\n SwapsImplSovrynSwapLib.getExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn) {\n return\n SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n}\n" + }, + "contracts/multisig/MultiSigKeyHolders.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/Ownable.sol\";\n\n/**\n * @title Multi Signature Key Holders contract.\n *\n * This contract contains the implementation of functions to add and remove\n * key holders w/ rBTC and BTC addresses.\n * */\ncontract MultiSigKeyHolders is Ownable {\n /* Storage */\n\n uint256 public constant MAX_OWNER_COUNT = 50;\n\n string private constant ERROR_INVALID_ADDRESS = \"Invalid address\";\n string private constant ERROR_INVALID_REQUIRED = \"Invalid required\";\n\n /// Flag and index for Ethereum address.\n mapping(address => Data) private isEthereumAddressAdded;\n\n /// List of Ethereum addresses.\n address[] private ethereumAddresses;\n\n /// Required number of signatures for the Ethereum multisig.\n uint256 public ethereumRequired = 2;\n\n /// Flag and index for Bitcoin address.\n mapping(string => Data) private isBitcoinAddressAdded;\n\n /// List of Bitcoin addresses.\n string[] private bitcoinAddresses;\n\n /// Required number of signatures for the Bitcoin multisig.\n uint256 public bitcoinRequired = 2;\n\n /// Helps removing items from array.\n struct Data {\n bool added;\n uint248 index;\n }\n\n /* Events */\n\n event EthereumAddressAdded(address indexed account);\n event EthereumAddressRemoved(address indexed account);\n event EthereumRequirementChanged(uint256 required);\n event BitcoinAddressAdded(string account);\n event BitcoinAddressRemoved(string account);\n event BitcoinRequirementChanged(uint256 required);\n\n /* Modifiers */\n\n modifier validRequirement(uint256 ownerCount, uint256 _required) {\n require(\n ownerCount <= MAX_OWNER_COUNT &&\n _required <= ownerCount &&\n _required != 0 &&\n ownerCount != 0,\n ERROR_INVALID_REQUIRED\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function addEthereumAddress(address _address) public onlyOwner {\n _addEthereumAddress(_address);\n }\n\n /**\n * @notice Add rBTC addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function _addEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (!isEthereumAddressAdded[_address].added) {\n isEthereumAddressAdded[_address] = Data({\n added: true,\n index: uint248(ethereumAddresses.length)\n });\n ethereumAddresses.push(_address);\n }\n\n emit EthereumAddressAdded(_address);\n }\n\n /**\n * @notice Remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeEthereumAddress(address _address) public onlyOwner {\n _removeEthereumAddress(_address);\n }\n\n /**\n * @notice Remove rBTC addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (isEthereumAddressAdded[_address].added) {\n uint248 index = isEthereumAddressAdded[_address].index;\n if (index != ethereumAddresses.length - 1) {\n ethereumAddresses[index] = ethereumAddresses[ethereumAddresses.length - 1];\n isEthereumAddressAdded[ethereumAddresses[index]].index = index;\n }\n ethereumAddresses.length--;\n delete isEthereumAddressAdded[_address];\n }\n\n emit EthereumAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether rBTC address is a key holder.\n * @param _address The rBTC address to be checked.\n * */\n function isEthereumAddressOwner(address _address) public view returns (bool) {\n return isEthereumAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of rBTC key holders.\n * */\n function getEthereumAddresses() public view returns (address[] memory) {\n return ethereumAddresses;\n }\n\n /**\n * @notice Set flag ethereumRequired to true/false.\n * @param _required The new value of the ethereumRequired flag.\n * */\n function changeEthereumRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(ethereumAddresses.length, _required)\n {\n ethereumRequired = _required;\n emit EthereumRequirementChanged(_required);\n }\n\n /**\n * @notice Add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function addBitcoinAddress(string memory _address) public onlyOwner {\n _addBitcoinAddress(_address);\n }\n\n /**\n * @notice Add bitcoin addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function _addBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (!isBitcoinAddressAdded[_address].added) {\n isBitcoinAddressAdded[_address] = Data({\n added: true,\n index: uint248(bitcoinAddresses.length)\n });\n bitcoinAddresses.push(_address);\n }\n\n emit BitcoinAddressAdded(_address);\n }\n\n /**\n * @notice Remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeBitcoinAddress(string memory _address) public onlyOwner {\n _removeBitcoinAddress(_address);\n }\n\n /**\n * @notice Remove bitcoin addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (isBitcoinAddressAdded[_address].added) {\n uint248 index = isBitcoinAddressAdded[_address].index;\n if (index != bitcoinAddresses.length - 1) {\n bitcoinAddresses[index] = bitcoinAddresses[bitcoinAddresses.length - 1];\n isBitcoinAddressAdded[bitcoinAddresses[index]].index = index;\n }\n bitcoinAddresses.length--;\n delete isBitcoinAddressAdded[_address];\n }\n\n emit BitcoinAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether bitcoin address is a key holder.\n * @param _address The bitcoin address to be checked.\n * */\n function isBitcoinAddressOwner(string memory _address) public view returns (bool) {\n return isBitcoinAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of bitcoin key holders.\n * */\n function getBitcoinAddresses() public view returns (string[] memory) {\n return bitcoinAddresses;\n }\n\n /**\n * @notice Set flag bitcoinRequired to true/false.\n * @param _required The new value of the bitcoinRequired flag.\n * */\n function changeBitcoinRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(bitcoinAddresses.length, _required)\n {\n bitcoinRequired = _required;\n emit BitcoinRequirementChanged(_required);\n }\n\n /**\n * @notice Add rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress the rBTC addresses to be added.\n * @param _bitcoinAddress the bitcoin addresses to be added.\n * */\n function addEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _addEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _addBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n\n /**\n * @notice Remove rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress The rBTC addresses to be removed.\n * @param _bitcoinAddress The bitcoin addresses to be removed.\n * */\n function removeEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _removeEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _removeBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n}\n" + }, + "contracts/openzeppelin/Address.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256('')`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n codehash := extcodehash(account)\n }\n return (codehash != accountHash && codehash != 0x0);\n }\n\n /**\n * @dev Converts an `address` into `address payable`. Note that this is\n * simply a type cast: the actual underlying value is not changed.\n *\n * _Available since v2.4.0._\n */\n function toPayable(address account) internal pure returns (address payable) {\n return address(uint160(account));\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n *\n * _Available since v2.4.0._\n */\n function sendValue(address recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-call-value\n (bool success, ) = recipient.call.value(amount)(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n}\n" + }, + "contracts/openzeppelin/Context.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n // Empty internal constructor, to prevent people from mistakenly deploying\n // an instance of this contract, which should be used via inheritance.\n constructor() internal {}\n\n // solhint-disable-previous-line no-empty-blocks\n\n function _msgSender() internal view returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n" + }, + "contracts/openzeppelin/ERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./Context.sol\";\nimport \"./IERC20_.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20Mintable}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20_ {\n using SafeMath for uint256;\n\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20};\n *\n * Requirements:\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for `sender`'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n _allowances[sender][_msgSender()].sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n _approve(\n _msgSender(),\n spender,\n _allowances[_msgSender()][spender].sub(\n subtractedValue,\n \"ERC20: decreased allowance below zero\"\n )\n );\n return true;\n }\n\n /**\n * @dev Moves tokens `amount` from `sender` to `recipient`.\n *\n * This is internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _balances[sender] = _balances[sender].sub(\n amount,\n \"ERC20: transfer amount exceeds balance\"\n );\n _balances[recipient] = _balances[recipient].add(amount);\n emit Transfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n *\n * This is internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`.`amount` is then deducted\n * from the caller's allowance.\n *\n * See {_burn} and {_approve}.\n */\n function _burnFrom(address account, uint256 amount) internal {\n _burn(account, amount);\n _approve(\n account,\n _msgSender(),\n _allowances[account][_msgSender()].sub(amount, \"ERC20: burn amount exceeds allowance\")\n );\n }\n}\n" + }, + "contracts/openzeppelin/ERC20Detailed.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20_.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n */\ncontract ERC20Detailed is IERC20_ {\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n */\n constructor(\n string memory name,\n string memory symbol,\n uint8 decimals\n ) public {\n _name = name;\n _symbol = symbol;\n _decimals = decimals;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/openzeppelin/IERC20_.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20_ {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/openzeppelin/Initializable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n */\ncontract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(_initializing || !_initialized, \"Initializable: contract is already initialized\");\n\n bool isTopLevelCall = !_initializing;\n if (isTopLevelCall) {\n _initializing = true;\n _initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n _initializing = false;\n }\n }\n}\n" + }, + "contracts/openzeppelin/Ownable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() public view returns (bool) {\n return _msgSender() == _owner;\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public onlyOwner {\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n */\n function _transferOwnership(address newOwner) internal {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n}\n" + }, + "contracts/openzeppelin/PausableOz.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./Ownable.sol\";\n\ncontract PausableOz is Ownable {\n /**\n * @dev Emitted when the pause is triggered by the owner (`account`).\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by the owner (`account`).\n */\n event Unpaused(address account);\n\n bool internal _paused;\n\n constructor() internal {}\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n */\n modifier whenNotPaused() {\n require(!_paused, \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n */\n modifier whenPaused() {\n require(_paused, \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/openzeppelin/ReentrancyGuard.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title Helps contracts guard against reentrancy attacks.\n * @author Remco Bloemen , Eenae \n * @dev If you mark a function `nonReentrant`, you should also\n * mark it `external`.\n */\ncontract ReentrancyGuard {\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n" + }, + "contracts/openzeppelin/SafeERC20.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./SafeMath.sol\";\nimport \"./Address.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\n );\n }\n\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n // solhint-disable-next-line max-line-length\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance =\n token.allowance(address(this), spender).sub(\n value,\n \"SafeERC20: decreased allowance below zero\"\n );\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves.\n\n // A Solidity high level call has three parts:\n // 1. The target address is checked to verify it contains contract code\n // 2. The call itself is made, and success asserted\n // 3. The return value is decoded, which in turn checks the size of the returned data.\n // solhint-disable-next-line max-line-length\n require(address(token).isContract(), \"SafeERC20: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(data);\n require(success, \"SafeERC20: low-level call failed\");\n\n if (returndata.length > 0) {\n // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "contracts/openzeppelin/SafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n *\n * _Available since v2.4.0._\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\n return divCeil(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n\n if (a == 0) {\n return 0;\n }\n uint256 c = ((a - 1) / b) + 1;\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\n return _a < _b ? _a : _b;\n }\n}\n" + }, + "contracts/openzeppelin/SignedSafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title SignedSafeMath\n * @dev Signed math operations with safety checks that revert on error.\n */\nlibrary SignedSafeMath {\n int256 private constant _INT256_MIN = -2**255;\n\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n require(!(a == -1 && b == _INT256_MIN), \"SignedSafeMath: multiplication overflow\");\n\n int256 c = a * b;\n require(c / a == b, \"SignedSafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n require(b != 0, \"SignedSafeMath: division by zero\");\n require(!(b == -1 && a == _INT256_MIN), \"SignedSafeMath: division overflow\");\n\n int256 c = a / b;\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a - b;\n require((b >= 0 && c <= a) || (b < 0 && c > a), \"SignedSafeMath: subtraction overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a + b;\n require((b >= 0 && c >= a) || (b < 0 && c < a), \"SignedSafeMath: addition overflow\");\n\n return c;\n }\n}\n" + }, + "contracts/proxy/modules/interfaces/IFunctionsList.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\ninterface IFunctionsList {\n function getFunctionsList() external pure returns (bytes4[] memory functionSignatures);\n}\n" + }, + "contracts/proxy/modules/interfaces/IModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\n/**\n * ModulesProxyRegistry Interface\n */\n\ncontract IModulesProxyRegistry {\n event AddModule(address indexed moduleAddress);\n event ReplaceModule(address indexed oldAddress, address indexed newAddress);\n event RemoveModule(address indexed moduleAddress);\n event SetModuleFuncImplementation(\n bytes4 indexed _funcSig,\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use ReplaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external;\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl) external;\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external;\n\n /// @notice to disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external;\n\n /// @param _sig function signature to get impmementation address for\n /// @return function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address);\n\n /// @notice verifies if no functions from the module deployed already registered\n /// @param _impl module implementation address to verify\n /// @return true if module can be added\n function canAddModule(address _impl) external view returns (bool);\n\n /// @notice Multiple modules verification if no functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return True if all modules can be added, false otherwise\n function canNotAddModules(address[] calldata _implementations)\n external\n view\n returns (address[] memory modules);\n\n /// @notice used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n );\n}\n" + }, + "contracts/proxy/modules/ModulesProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"./ModulesProxyRegistry.sol\";\n\n/**\n * ModulesProxy serves as a storage processed by a set of logic contracts - modules\n * Modules functions are registered in the contract's slots generated per func sig\n * All the function calls except for own Proxy functions are delegated to\n * the registered functions\n * The ModulesProxy is designed as a universal solution for refactorig contracts\n * reaching a 24K size limit (EIP-170)\n *\n * Upgradability is implemented at a module level to provide consistency\n * It does not allow to replace separate functions - only the whole module\n * meaning that if a module being registered contains other modules function signatures\n * then these modulea should be replaced completely - all the functions should be removed\n * to avoid leftovers or accidental replacements and therefore functional inconsistency.\n *\n * A module is either a new non-overlapping with registered modules\n * or a complete replacement of another registered module\n * in which case all the old module functions are unregistered and then\n * the new module functions are registered\n * There is also a separate function to unregister a module which unregisters all the functions\n * There is no option to unregister a subset of module functions - one should use pausable functionality\n * to achieve this\n */\n\ncontract ModulesProxy is ModulesProxyRegistry {\n // Uncomment for using beforeFallback() hook\n /*\n bytes private constant BEFORE_FALLBACK_SIG = abi.encodeWithSignature(\"beforeFallback()\");\n bytes4 private constant BEFORE_FALLBACK_SIG_BYTES4 = bytes4(keccak256(abi.encodePacked(\"beforeFallback()\")));\n */\n\n /**\n * @notice Fallback function delegates calls to modules.\n * Returns whatever the implementation call returns.\n * Has a hook to execute before delegating calls\n * To activate register a module with beforeFallback() function\n */\n function() external payable {\n /*\n // Commented to safe gas by default\n // Uncomment for using beforeFallback() hook \n // Implement and register beforeFallback() function in a module\n address beforeFallback = _getFuncImplementation(BEFORE_FALLBACK_SIG_BYTES4);\n if (beforeFallback != address(0)) {\n (bool success, ) = beforeFallback.delegatecall(bytes(0x39b0111a)); // abi.encodeWithSignature(\"beforeFallback()\")\n require(success, \"ModulesProxy::fallback: beforeFallback() fail\"); //MP02\n }\n */\n\n address target = _getFuncImplementation(msg.sig);\n require(target != address(0), \"ModulesProxy:target module not registered\"); // MP03\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/modules/ModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"../../utils/Utils.sol\";\nimport \"../../utils/ProxyOwnable.sol\";\nimport \"../modules/interfaces/IFunctionsList.sol\";\nimport \"../modules/interfaces/IModulesProxyRegistry.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * ModulesProxyRegistry provides modules registration/removing/replacing functionality to ModulesProxy\n * Designed to be inherited\n */\n\ncontract ModulesProxyRegistry is IModulesProxyRegistry, ProxyOwnable {\n using Address for address;\n\n bytes32 internal constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n\n ///@notice Constructor is internal to make contract abstract\n constructor() internal {\n // abstract\n }\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use replaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external onlyProxyOwner {\n _addModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external onlyProxyOwner {\n _addModules(_implementations);\n }\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl)\n external\n onlyProxyOwner\n {\n _replaceModule(_oldModuleImpl, _newModuleImpl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external onlyProxyOwner {\n require(\n _implementationsFrom.length == _implementationsTo.length,\n \"ModulesProxyRegistry::replaceModules: arrays sizes must be equal\"\n ); //MR10\n\n // because the order of addresses is arbitrary, all modules are removed first to avoid collisions\n _removeModules(_implementationsFrom);\n _addModules(_implementationsTo);\n }\n\n /// @notice To disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external onlyProxyOwner {\n _removeModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external onlyProxyOwner {\n _removeModules(_implementations);\n }\n\n /// @param _sig Function signature to get impmementation address for\n /// @return Function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address) {\n return _getFuncImplementation(_sig);\n }\n\n /// @notice Verifies if no functions from the module already registered\n /// @param _impl Module implementation address to verify\n /// @return True if module can be added\n function canAddModule(address _impl) external view returns (bool) {\n return _canAddModule(_impl);\n }\n\n /// @notice Multiple modules verification if there are functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return addresses of registered modules\n function canNotAddModules(address[] memory _implementations)\n public\n view\n returns (address[] memory)\n {\n for (uint256 i = 0; i < _implementations.length; i++) {\n if (_canAddModule(_implementations[i])) {\n delete _implementations[i];\n }\n }\n return _implementations;\n }\n\n /// @notice Used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return Clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n )\n {\n require(\n _newModule.isContract(),\n \"ModulesProxyRegistry::checkClashingFuncSelectors: address is not a contract\"\n ); //MR06\n bytes4[] memory newModuleFunctions = IFunctionsList(_newModule).getFunctionsList();\n bytes4[] memory proxyRegistryFunctions = _getFunctionsList(); //registry functions list\n uint256 clashingProxyRegistryFuncsSize;\n uint256 clashingArraySize;\n uint256 clashingArrayIndex;\n uint256 clashingRegistryArrayIndex;\n\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0) && funcImpl != _newModule) {\n clashingArraySize++;\n } else if (_isFuncClashingWithProxyFunctions(newModuleFunctions[i]))\n clashingProxyRegistryFuncsSize++;\n }\n clashingModules = new address[](clashingArraySize);\n clashingModulesFuncSelectors = new bytes4[](clashingArraySize);\n clashingProxyRegistryFuncSelectors = new bytes4[](clashingProxyRegistryFuncsSize);\n\n if (clashingArraySize == 0 && clashingProxyRegistryFuncsSize == 0)\n //return empty arrays\n return (\n clashingModules,\n clashingModulesFuncSelectors,\n clashingProxyRegistryFuncSelectors\n );\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0)) {\n clashingModules[clashingArrayIndex] = funcImpl;\n clashingModulesFuncSelectors[clashingArrayIndex] = newModuleFunctions[i];\n clashingArrayIndex++;\n }\n for (uint256 j = 0; j < proxyRegistryFunctions.length; j++) {\n //ModulesProxyRegistry has a clashing function selector\n if (proxyRegistryFunctions[j] == newModuleFunctions[i]) {\n clashingProxyRegistryFuncSelectors[\n clashingRegistryArrayIndex\n ] = proxyRegistryFunctions[j];\n clashingRegistryArrayIndex++;\n }\n }\n }\n }\n\n /// Verifies the deployed contract address is a registered module contract\n /// @param _impl deployment address to verify\n /// @return true if _impl address is a registered module\n function isModuleRegistered(address _impl) external view returns (bool) {\n return _getFirstRegisteredModuleAddress(_impl) == _impl;\n }\n\n /****************** INTERNAL FUNCTIONS ******************/\n\n function _getFirstRegisteredModuleAddress(address _impl) internal view returns (address) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_getRegisteredModuleAddress: address is not a contract\"\n );\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n address _moduleImpl = _getFuncImplementation(functions[i]);\n if (_moduleImpl != address(0)) {\n return (_moduleImpl);\n }\n }\n return address(0);\n }\n\n function _getFuncImplementation(bytes4 _sig) internal view returns (address) {\n //TODO: add querying Registry for logic address and then delegate call to it OR use proxy memory slots like this:\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n address implementation;\n assembly {\n implementation := sload(key)\n }\n return implementation;\n }\n\n function _addModule(address _impl) internal {\n require(_impl.isContract(), \"ModulesProxyRegistry::_addModule: address is not a contract\"); //MR01\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n require(\n _getFuncImplementation(functions[i]) == address(0),\n \"ModulesProxyRegistry::_addModule: function already registered - use replaceModule function\"\n ); //MR02\n require(functions[i] != bytes4(0), \"does not allow empty function id\"); // MR03\n require(\n !_isFuncClashingWithProxyFunctions(functions[i]),\n \"ModulesProxyRegistry::_addModule: has a function with the same signature\"\n ); //MR09\n _setModuleFuncImplementation(functions[i], _impl);\n }\n emit AddModule(_impl);\n }\n\n function _addModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _addModule(_implementations[i]);\n }\n }\n\n function _removeModule(address _impl) internal onlyProxyOwner {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_removeModule: address is not a contract\"\n ); //MR07\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n _setModuleFuncImplementation(functions[i], address(0));\n\n emit RemoveModule(_impl);\n }\n\n function _removeModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _removeModule(_implementations[i]);\n }\n }\n\n function _replaceModule(address _oldModuleImpl, address _newModuleImpl) internal {\n if (_oldModuleImpl != _newModuleImpl) {\n require(\n _newModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _newModuleImpl is not a contract\"\n ); //MR03\n require(\n _oldModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _oldModuleImpl is not a contract\"\n ); //MR04\n _removeModule(_oldModuleImpl);\n _addModule(_newModuleImpl);\n\n emit ReplaceModule(_oldModuleImpl, _newModuleImpl);\n }\n }\n\n function _setModuleFuncImplementation(bytes4 _sig, address _impl) internal {\n emit SetModuleFuncImplementation(_sig, _getFuncImplementation(_sig), _impl);\n\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n assembly {\n sstore(key, _impl)\n }\n }\n\n function _isFuncClashingWithProxyFunctions(bytes4 _sig) internal pure returns (bool) {\n bytes4[] memory functionList = _getFunctionsList();\n for (uint256 i = 0; i < functionList.length; i++) {\n if (_sig == functionList[i])\n //ModulesProxyRegistry has function with the same id\n return true;\n }\n return false;\n }\n\n function _canAddModule(address _impl) internal view returns (bool) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_canAddModule: address is not a contract\"\n ); //MR06\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n if (_getFuncImplementation(functions[i]) != address(0)) return (false);\n return true;\n }\n\n function _getFunctionsList() internal pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](13);\n functionList[0] = this.getFuncImplementation.selector;\n functionList[1] = this.addModule.selector;\n functionList[2] = this.addModules.selector;\n functionList[3] = this.removeModule.selector;\n functionList[4] = this.removeModules.selector;\n functionList[5] = this.replaceModule.selector;\n functionList[6] = this.replaceModules.selector;\n functionList[7] = this.canAddModule.selector;\n functionList[8] = this.canNotAddModules.selector;\n functionList[9] = this.setProxyOwner.selector;\n functionList[10] = this.getProxyOwner.selector;\n functionList[11] = this.checkClashingFuncSelectors.selector;\n functionList[12] = this.isModuleRegistered.selector;\n return functionList;\n }\n}\n" + }, + "contracts/proxy/Proxy.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base Proxy contract.\n * @notice The proxy performs delegated calls to the contract implementation\n * it is pointing to. This way upgradable contracts are possible on blockchain.\n *\n * Delegating proxy contracts are widely used for both upgradeability and gas\n * savings. These proxies rely on a logic contract (also known as implementation\n * contract or master copy) that is called using delegatecall. This allows\n * proxies to keep a persistent state (storage and balance) while the code is\n * delegated to the logic contract.\n *\n * Proxy contract is meant to be inherited and its internal functions\n * _setImplementation and _setProxyOwner to be called when upgrades become\n * neccessary.\n *\n * The loan token (iToken) contract as well as the protocol contract act as\n * proxies, delegating all calls to underlying contracts. Therefore, if you\n * want to interact with them using web3, you need to use the ABIs from the\n * contracts containing the actual logic or the interface contract.\n * ABI for LoanToken contracts: LoanTokenLogicStandard\n * ABI for Protocol contract: ISovryn\n *\n * @dev UpgradableProxy is the contract that inherits Proxy and wraps these\n * functions.\n * */\ncontract Proxy {\n bytes32 private constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);\n event ImplementationChanged(\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /**\n * @notice Set sender as an owner.\n * */\n constructor() public {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @notice Throw error if called not by an owner.\n * */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Proxy:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the implementation.\n * @param _implementation Address of the implementation.\n * */\n function _setImplementation(address _implementation) internal {\n require(_implementation != address(0), \"Proxy::setImplementation: invalid address\");\n emit ImplementationChanged(getImplementation(), _implementation);\n\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n sstore(key, _implementation)\n }\n }\n\n /**\n * @notice Return address of the implementation.\n * @return Address of the implementation.\n * */\n function getImplementation() public view returns (address _implementation) {\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n _implementation := sload(key)\n }\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"Proxy::setProxyOwner: invalid address\");\n emit OwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Return address of the owner.\n * @return Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n address implementation = getImplementation();\n require(implementation != address(0), \"Proxy::(): implementation not found\");\n\n assembly {\n let pointer := mload(0x40)\n calldatacopy(pointer, 0, calldatasize)\n let result := delegatecall(gas, implementation, pointer, calldatasize, 0, 0)\n let size := returndatasize\n returndatacopy(pointer, 0, size)\n\n switch result\n case 0 {\n revert(pointer, size)\n }\n default {\n return(pointer, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/UpgradableProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Proxy.sol\";\n\n/**\n * @title Upgradable Proxy contract.\n * @notice A disadvantage of the immutable ledger is that nobody can change the\n * source code of a smart contract after it’s been deployed. In order to fix\n * bugs or introduce new features, smart contracts need to be upgradable somehow.\n *\n * Although it is not possible to upgrade the code of an already deployed smart\n * contract, it is possible to set-up a proxy contract architecture that will\n * allow to use new deployed contracts as if the main logic had been upgraded.\n *\n * A proxy architecture pattern is such that all message calls go through a\n * Proxy contract that will redirect them to the latest deployed contract logic.\n * To upgrade, a new version of the contract is deployed, and the Proxy is\n * updated to reference the new contract address.\n * */\ncontract UpgradableProxy is Proxy {\n /**\n * @notice Set address of the implementation.\n * @dev Wrapper for _setImplementation that exposes the function\n * as public for owner to be able to set a new version of the\n * contract as current pointing implementation.\n * @param _implementation Address of the implementation.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n _setImplementation(_implementation);\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n}\n" + }, + "contracts/reentrancy/Mutex.sol": { + "content": "pragma solidity ^0.5.17;\n\n/*\n * @title Global Mutex contract\n *\n * @notice A mutex contract that allows only one function to be called at a time out\n * of a large set of functions. *Anyone* in the network can freely use any instance\n * of this contract to add a universal mutex to any function in any contract.\n */\ncontract Mutex {\n /*\n * We use an uint to store the mutex state.\n */\n uint256 public value;\n\n /*\n * @notice Increment the mutex state and return the new value.\n *\n * @dev This is the function that will be called by anyone to change the mutex\n * state. It is purposely not protected by any access control\n */\n function incrementAndGetValue() external returns (uint256) {\n /*\n * increment value using unsafe math. This is safe because we are\n * pretty certain no one will ever increment the value 2^256 times\n * in a single transaction.\n */\n return ++value;\n }\n}\n" + }, + "contracts/reentrancy/SharedReentrancyGuard.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Mutex.sol\";\n\n/*\n * @title Abstract contract for shared reentrancy guards\n *\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\n * that there's no reentrancy between *any* functions marked with the modifier.\n *\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\n */\ncontract SharedReentrancyGuard {\n /*\n * This is the address of the mutex contract that will be used as the\n * reentrancy guard.\n *\n * The address is hardcoded to avoid changing the memory layout of\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\n * because the Mutex contract is always deployed to the same address, with the\n * same method used in the deployment of ERC1820Registry.\n */\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\n\n /*\n * This is the modifier that will be used to protect functions from\n * reentrancy. It will call the mutex contract to increment the mutex\n * state and then revert if the mutex state was changed by another\n * nested call.\n */\n modifier globallyNonReentrant() {\n uint256 previous = MUTEX.incrementAndGetValue();\n\n _;\n\n /*\n * If the mutex state was changed by a nested function call, then\n * the value of the state variable will be different from the previous value.\n */\n require(previous == MUTEX.value(), \"reentrancy violation\");\n }\n}\n" + }, + "contracts/rsk/RSKAddrValidator.sol": { + "content": "// SPDX-License-Identifier:MIT\npragma solidity ^0.5.17;\n\nlibrary RSKAddrValidator {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n * */\n function checkPKNotZero(address addr) internal pure returns (bool) {\n return (addr != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && addr != address(0));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key.\n * */\n function safeEquals(address addr1, address addr2) internal pure returns (bool) {\n return (addr1 == addr2 &&\n addr1 != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\n addr1 != address(0));\n }\n}\n" + }, + "contracts/swaps/connectors/interfaces/IContractRegistry.sol": { + "content": "pragma solidity 0.5.17;\n\ncontract IContractRegistry {\n function addressOf(bytes32 contractName) public view returns (address);\n}\n" + }, + "contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol": { + "content": "pragma solidity >=0.5.8 <=0.5.17;\n\nimport \"../../../interfaces/IERC20.sol\";\n\ncontract ISovrynSwapNetwork {\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256);\n\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\n\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory);\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwap.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../../core/State.sol\";\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\n\n/**\n * @dev WARNING: This contract is deprecated, all public functions are moved to the protocol modules.\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\ncontract SwapsImplSovrynSwap is State {\n using SafeERC20 for IERC20;\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n constructor() internal {\n // abstract\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destination tokens.\n * @param receiverAddress The address who will received the swap token results\n * @param returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * @param minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * @param maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address receiverAddress,\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n require(\n supportedTokens[sourceTokenAddress] && supportedTokens[destTokenAddress],\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = estimateSourceTokenAmount(\n sourceTokenAddress,\n destTokenAddress,\n requiredDestTokenAmount,\n maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n allowTransfer(sourceTokenAmountUsed, sourceTokenAddress, address(sovrynSwapNetwork));\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n uint256 sourceToDestPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n internalExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n maxSourceTokenAmount,\n sovrynSwapContractRegistryAddress\n );\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > sourceBuffer) buffer = sourceBuffer;\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistryAddress\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * @param sovrynSwapContractRegistry The sovryn swap contract reigstry address.\n * @param defaultPath The default path for specific pairs.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistry,\n IERC20[] memory defaultPath\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistry);\n\n IERC20[] memory path =\n defaultPath.length >= 3\n ? defaultPath\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\nimport \"../../interfaces/ISovryn.sol\";\n\n/**\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\nlibrary SwapsImplSovrynSwapLib {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n struct SwapParams {\n address sourceTokenAddress;\n address destTokenAddress;\n address receiverAddress;\n address returnToSenderAddress;\n uint256 minSourceTokenAmount;\n uint256 maxSourceTokenAmount;\n uint256 requiredDestTokenAmount;\n }\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param params SwapParams struct\n * sourceTokenAddress The address of the source tokens.\n * destTokenAddress The address of the destination tokens.\n * receiverAddress The address who will received the swap token results\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * requiredDestTokenAmount The required amount of destination tokens.\n * */\n function swap(SwapParams memory params)\n public\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(params.sourceTokenAddress != params.destTokenAddress, \"source == dest\");\n\n ISovryn iSovryn = ISovryn(address(this));\n require(\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\n iSovryn.supportedTokens(params.destTokenAddress),\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\n\n IERC20[] memory path =\n _getConversionPath(\n params.sourceTokenAddress,\n params.destTokenAddress,\n sovrynSwapNetwork\n );\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = params.minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (params.requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\n params.sourceTokenAddress,\n params.destTokenAddress,\n params.requiredDestTokenAmount,\n params.maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n params.requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = params.requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n _allowTransfer(\n sourceTokenAmountUsed,\n params.sourceTokenAddress,\n address(sovrynSwapNetwork)\n );\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n params.receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (params.returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(params.sourceTokenAddress).safeTransfer(\n params.returnToSenderAddress,\n params.maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function _allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function _estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n ISovryn iSovryn = ISovryn(address(this));\n uint256 sourceToDestPrecision =\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function getExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function getExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function _getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/testnet/SwapsImplLocal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../../core/State.sol\";\nimport \"../../../openzeppelin/SafeERC20.sol\";\nimport \"../../../feeds/IPriceFeeds.sol\";\nimport \"../../../testhelpers/TestToken.sol\";\n\n/**\n * @title Swaps Implementation Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate calculations.\n * */\ncontract SwapsImplLocal is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Swap two tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address, /*receiverAddress*/\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n\n (uint256 tradeRate, uint256 precision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n if (requiredDestTokenAmount == 0) {\n sourceTokenAmountUsed = minSourceTokenAmount;\n destTokenAmountReceived = minSourceTokenAmount.mul(tradeRate).div(precision);\n } else {\n destTokenAmountReceived = requiredDestTokenAmount;\n sourceTokenAmountUsed = requiredDestTokenAmount.mul(precision).div(tradeRate);\n require(sourceTokenAmountUsed <= minSourceTokenAmount, \"destAmount too great\");\n }\n\n TestToken(sourceTokenAddress).burn(address(this), sourceTokenAmountUsed);\n TestToken(destTokenAddress).mint(address(this), destTokenAmountReceived);\n\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Calculate the expected price rate of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n *\n * @return precision The expected price rate.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * @notice Calculate the expected return of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n * @param defaultPath defaultPath for swap.\n *\n * @return precision The expected return.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused,\n IERC20[] memory defaultPath\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n}\n" + }, + "contracts/swaps/SwapsUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../mixins/FeesHelper.sol\";\nimport \"./connectors/SwapsImplSovrynSwapLib.sol\";\n\n/**\n * @title Perform token swaps for loans and trades.\n * */\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\n /**\n * @notice Internal loan swap.\n *\n * @param loanId The ID of the loan.\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of destination tokens.\n * @param user The user address.\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * @param bypassFee To bypass or not the fee.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived\n * @return sourceTokenAmountUsed\n * @return sourceToDestSwapRate\n * */\n function _loanSwap(\n bytes32 loanId,\n address sourceToken,\n address destToken,\n address user,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount,\n bool bypassFee,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 sourceToDestSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n address(this), // receiver\n address(this), // returnToSender\n user\n ],\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\n loanId,\n bypassFee,\n loanDataBytes,\n false // swap external flag, set to false so that it will use the tradingFeePercent\n );\n\n /// Will revert if swap size too large.\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\n\n /// Will revert if disagreement found.\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived,\n maxDisagreement\n );\n\n emit LoanSwap(\n loanId,\n sourceToken,\n destToken,\n user,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Wrapper for _swapsCall_internal function.\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n * @param loanId The Id of the associated loan.\n * @param miscBool True/false to bypassFee.\n * @param loanDataBytes Additional loan data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall(\n address[5] memory addrs,\n uint256[3] memory vals,\n bytes32 loanId,\n bool miscBool, /// bypassFee\n bytes memory loanDataBytes,\n bool isSwapExternal\n ) internal returns (uint256, uint256) {\n /// addrs[0]: sourceToken\n /// addrs[1]: destToken\n /// addrs[2]: receiver\n /// addrs[3]: returnToSender\n /// addrs[4]: user\n /// vals[0]: minSourceTokenAmount\n /// vals[1]: maxSourceTokenAmount\n /// vals[2]: requiredDestTokenAmount\n\n require(vals[0] != 0 || vals[1] != 0, \"min or max source token amount needs to be set\");\n\n if (vals[1] == 0) {\n vals[1] = vals[0];\n }\n require(vals[0] <= vals[1], \"sourceAmount larger than max\");\n\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n\n uint256 tradingFee;\n if (!miscBool) {\n /// bypassFee\n if (vals[2] == 0) {\n /// condition: vals[0] will always be used as sourceAmount\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[0]);\n } else {\n tradingFee = _getTradingFee(vals[0]);\n }\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId,\n addrs[0], /// sourceToken (feeToken)\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n vals[0] = vals[0].sub(tradingFee);\n }\n } else {\n /// Condition: unknown sourceAmount will be used.\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[2]);\n } else {\n tradingFee = _getTradingFee(vals[2]);\n }\n\n if (tradingFee != 0) {\n vals[2] = vals[2].add(tradingFee);\n }\n }\n }\n\n require(loanDataBytes.length == 0, \"invalid state\");\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\n\n if (vals[2] == 0) {\n /// There's no minimum destTokenAmount, but all of vals[0]\n /// (minSourceTokenAmount) must be spent.\n require(sourceTokenAmountUsed == vals[0], \"swap too large to fill\");\n\n if (tradingFee != 0) {\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\n }\n } else {\n /// There's a minimum destTokenAmount required, but\n /// sourceTokenAmountUsed won't be greater\n /// than vals[1] (maxSourceTokenAmount)\n require(sourceTokenAmountUsed <= vals[1], \"swap fill too large\");\n require(destTokenAmountReceived >= vals[2], \"insufficient swap liquidity\");\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId, /// loanId,\n addrs[1], /// destToken (feeToken)\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\n }\n }\n\n return (destTokenAmountReceived, sourceTokenAmountUsed);\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Calls swapsImpl::internalSwap\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\n internal\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n SwapsImplSovrynSwapLib.SwapParams memory swapParams;\n\n swapParams.sourceTokenAddress = addrs[0];\n swapParams.destTokenAddress = addrs[1];\n swapParams.receiverAddress = addrs[2];\n swapParams.returnToSenderAddress = addrs[3];\n swapParams.minSourceTokenAmount = vals[0];\n swapParams.maxSourceTokenAmount = vals[1];\n swapParams.requiredDestTokenAmount = vals[2];\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = SwapsImplSovrynSwapLib.swap(swapParams);\n }\n\n /**\n * @notice Calculate expected amount of destination tokens.\n *\n * @dev Calls swapsImpl::internalExpectedReturn\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destination tokens.\n * @param sourceTokenAmount The amount of the source tokens.\n *\n * @param destTokenAmount The amount of destination tokens.\n * */\n function _swapsExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) internal view returns (uint256 destTokenAmount) {\n destTokenAmount = SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceToken,\n destToken,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Verify that the amount of tokens are under the swap limit.\n *\n * @dev Calls priceFeeds::amountInEth\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n * */\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\n uint256 _maxSwapSize = maxSwapSize;\n if (_maxSwapSize != 0) {\n uint256 amountInEth;\n if (tokenAddress == address(wrbtcToken)) {\n amountInEth = amount;\n } else {\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\n }\n require(amountInEth <= _maxSwapSize, \"swap too large\");\n }\n }\n}\n" + }, + "contracts/testhelpers/FlashLoanerTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n// \"SPDX-License-Identifier: Apache-2.0\"\n\nimport \"../interfaces/IERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./ITokenFlashLoanTest.sol\";\n\ncontract FlashLoanerTest is Ownable {\n function initiateFlashLoanTest(\n address loanToken,\n address iToken,\n uint256 flashLoanAmount\n ) internal returns (bytes memory success) {\n ITokenFlashLoanTest iTokenContract = ITokenFlashLoanTest(iToken);\n return\n iTokenContract.flashBorrow(\n flashLoanAmount,\n address(this),\n address(this),\n \"\",\n abi.encodeWithSignature(\n \"executeOperation(address,address,uint256)\",\n loanToken,\n iToken,\n flashLoanAmount\n )\n );\n }\n\n function repayFlashLoan(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) internal {\n IERC20(loanToken).transfer(iToken, loanAmount);\n }\n\n function executeOperation(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) external returns (bytes memory success) {\n emit BalanceOf(IERC20(loanToken).balanceOf(address(this)));\n emit ExecuteOperation(loanToken, iToken, loanAmount);\n repayFlashLoan(loanToken, iToken, loanAmount);\n return bytes(\"1\");\n }\n\n function doStuffWithFlashLoan(\n address token,\n address iToken,\n uint256 amount\n ) external onlyOwner {\n bytes memory result;\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n result = initiateFlashLoanTest(token, iToken, amount);\n\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n // after loan checks and what not.\n if (hashCompareWithLengthCheck(bytes(\"1\"), result)) {\n revert(\"failed executeOperation\");\n }\n }\n\n function hashCompareWithLengthCheck(bytes memory a, bytes memory b)\n internal\n pure\n returns (bool)\n {\n if (a.length != b.length) {\n return false;\n } else {\n return keccak256(a) == keccak256(b);\n }\n }\n\n event ExecuteOperation(address loanToken, address iToken, uint256 loanAmount);\n\n event BalanceOf(uint256 balance);\n}\n" + }, + "contracts/testhelpers/interfaces/IERC1820Registry.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the global ERC1820 Registry, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register\n * implementers for interfaces in this registry, as well as query support.\n *\n * Implementers may be shared by multiple accounts, and can also implement more\n * than a single interface for each account. Contracts can implement interfaces\n * for themselves, but externally-owned accounts (EOA) must delegate this to a\n * contract.\n *\n * {IERC165} interfaces can also be queried via the registry.\n *\n * For an in-depth explanation and source code analysis, see the EIP text.\n */\ninterface IERC1820Registry {\n /**\n * @dev Sets `newManager` as the manager for `account`. A manager of an\n * account is able to set interface implementers for it.\n *\n * By default, each account is its own manager. Passing a value of `0x0` in\n * `newManager` will reset the manager to this initial state.\n *\n * Emits a {ManagerChanged} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n */\n function setManager(address account, address newManager) external;\n\n /**\n * @dev Returns the manager for `account`.\n *\n * See {setManager}.\n */\n function getManager(address account) external view returns (address);\n\n /**\n * @dev Sets the `implementer` contract as `account`'s implementer for\n * `interfaceHash`.\n *\n * `account` being the zero address is an alias for the caller's address.\n * The zero address can also be used in `implementer` to remove an old one.\n *\n * See {interfaceHash} to learn how these are created.\n *\n * Emits an {InterfaceImplementerSet} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not\n * end in 28 zeroes).\n * - `implementer` must implement {IERC1820Implementer} and return true when\n * queried for support, unless `implementer` is the caller. See\n * {IERC1820Implementer-canImplementInterfaceForAddress}.\n */\n function setInterfaceImplementer(\n address account,\n bytes32 interfaceHash,\n address implementer\n ) external;\n\n /**\n * @dev Returns the implementer of `interfaceHash` for `account`. If no such\n * implementer is registered, returns the zero address.\n *\n * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28\n * zeroes), `account` will be queried for support of it.\n *\n * `account` being the zero address is an alias for the caller's address.\n */\n function getInterfaceImplementer(address account, bytes32 interfaceHash)\n external\n view\n returns (address);\n\n /**\n * @dev Returns the interface hash for an `interfaceName`, as defined in the\n * corresponding\n * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].\n */\n function interfaceHash(string calldata interfaceName) external pure returns (bytes32);\n\n /**\n * @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n * @param account Address of the contract for which to update the cache.\n * @param interfaceId ERC165 interface for which to update the cache.\n */\n function updateERC165Cache(address account, bytes4 interfaceId) external;\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not.\n * If the result is not cached a direct lookup on the contract address is performed.\n * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n * {updateERC165Cache} with the contract address.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165Interface(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n event InterfaceImplementerSet(\n address indexed account,\n bytes32 indexed interfaceHash,\n address indexed implementer\n );\n\n event ManagerChanged(address indexed account, address indexed newManager);\n}\n" + }, + "contracts/testhelpers/ITokenFlashLoanTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n// \"SPDX-License-Identifier: Apache-2.0\"\n\ninterface ITokenFlashLoanTest {\n function flashBorrow(\n uint256 borrowAmount,\n address borrower,\n address target,\n string calldata signature,\n bytes calldata data\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/testhelpers/LoanTokenLogicTest.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicTest is LoanTokenLogic {\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestNonReentrantValueSetter.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\ncontract TestNonReentrantValueSetter is SharedReentrancyGuard {\n uint256 public value;\n\n // This will fail if another globallyNonReentrant function has already been entered\n function setValue(uint256 newValue) public globallyNonReentrant {\n value = newValue;\n }\n\n // this will always fail if `other.setValue` is globallyNonReentrant\n function setOtherContractValueNonReentrant(address other, uint256 newValue)\n external\n globallyNonReentrant\n {\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n\n // this is intentionally not globallyNonReentrant and should work even if both contracts are non-reentrant\n function setThisAndOtherContractValue(address other, uint256 newValue) external {\n setValue(newValue);\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestValueSetterProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract TestValueSetterProxy is UpgradableProxy {\n // This is here for the memory layout\n uint256 public value;\n}\n" + }, + "contracts/testhelpers/staking/StakingTester.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../TestToken.sol\";\n\ncontract StakingTester {\n IStaking public staking;\n TestToken public token;\n\n constructor(address _staking, address _token) public {\n staking = IStaking(_staking);\n token = TestToken(_token);\n }\n\n function stakeAndWithdraw(uint96 _amount, uint256 _until) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _until, address(this), address(this));\n staking.withdraw(_amount, _until, address(this));\n }\n\n function stakeAndDelegate(\n uint96 _amount,\n address _delegatee,\n uint256 _lockDate\n ) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _lockDate, address(this), address(this));\n staking.delegate(_delegatee, _lockDate);\n }\n}\n" + }, + "contracts/testhelpers/TestCoverage.sol": { + "content": "/**\n * In order to test some functionalities like Pausable::pausable() modifier,\n * it is required to add a contract to invoke them and get a full coverage on tests.\n */\n\npragma solidity 0.5.17;\n\nimport \"../connectors/loantoken/Pausable.sol\";\nimport \"../governance/Staking/SafeMath96.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../connectors/loantoken/AdvancedToken.sol\";\nimport \"../connectors/loantoken/LoanTokenLogicStorage.sol\";\n\ncontract TestCoverage is\n Pausable,\n SafeMath96,\n VaultController,\n AdvancedToken,\n LoanTokenLogicStorage\n{\n /// @dev Pausable is currently an unused contract that still is operative\n /// because margin trade flashloan functionality has been commented out.\n /// In case it were restored, contract would become used again, so for a\n /// complete test coverage it is required to test it.\n\n function dummyPausableFunction() external pausable(msg.sig) {\n /// @dev do nothing, just to check if modifier is working\n }\n\n /// @dev This function should be located on Pausable contract in the case\n /// it has to be used again by flashloan restoration.\n function togglePause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047)\n )\n );\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /// @dev Testing internal functions of governance/Staking/SafeMath96.sol\n function testSafeMath96_safe32(uint256 n) public pure returns (uint32) {\n // Public wrapper for SafeMath96 internal function\n return safe32(n, \"overflow\");\n }\n\n function testSafeMath96_safe64(uint256 n) public pure returns (uint64) {\n // Public wrapper for SafeMath96 internal function\n return safe64(n, \"overflow\");\n }\n\n function testSafeMath96_safe96(uint256 n) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return safe96(n, \"overflow\");\n }\n\n function testSafeMath96_sub96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return sub96(a, b, \"underflow\");\n }\n\n function testSafeMath96_mul96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return mul96(a, b, \"overflow\");\n }\n\n function testSafeMath96_div96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return div96(a, b, \"division by 0\");\n }\n\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;\n EnumerableBytes32Set.Bytes32Set internal aSet;\n\n function testEnum_AddRemove(bytes32 a, bytes32 b) public returns (bool) {\n aSet.addBytes32(a);\n return aSet.removeBytes32(b);\n }\n\n function testEnum_AddAddress(address a, address b) public returns (bool) {\n aSet.addAddress(a);\n return aSet.containsAddress(b);\n }\n\n function testEnum_AddAddressesAndEnumerate(\n address a,\n address b,\n uint256 start,\n uint256 count\n ) public returns (bytes32[] memory) {\n aSet.addAddress(a);\n aSet.addAddress(b);\n return aSet.enumerate(start, count);\n }\n\n /// @dev Wrapper to test internal function never called along current codebase\n function testVaultController_vaultApprove(\n address token,\n address to,\n uint256 value\n ) public {\n vaultApprove(token, to, value);\n }\n\n /// @dev mint wrapper w/o previous checks\n function testMint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) public {\n _mint(_to, _tokenAmount, _assetAmount, _price);\n }\n\n /// @dev wrapper for a function unreachable to tests\n function testStringToBytes32(string memory source) public pure returns (bytes32 result) {\n return stringToBytes32(source);\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some ERC777 from the lending pool.\n * 2. Close the loan with closeWithDeposit function in the protocol.\n * 3. Burn all iERC777.\n *\n * The cross-reentrancy happened in step#3. It might happened through a hook function (tokensToSend) that is implemented in this contract to support the ERC777 transfer.\n * Inside the hook function, it will try to mint the iERC777.\n * The details about the hook functions can be found here: https://eips.ethereum.org/EIPS/eip-777#hooks\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithDeposit function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyERC777 {\n address public loanToken;\n address public WRBTC;\n address public SUSD; /// ERC777\n ProtocolLike public sovrynProtocol;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iUSDTBalance;\n }\n\n function() external payable {}\n\n constructor(\n address _loanToken,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanToken = _loanToken;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777TokensSender\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: WRBTC has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n });\n\n IERC20(WRBTC).approve(loanToken, initial.susdBalance);\n\n ILoanTokenModules(loanToken).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n WRBTC,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanToken).loanParamsIds(\n uint256(keccak256(abi.encodePacked(WRBTC, true)))\n );\n bytes32 loan_id =\n keccak256(abi.encodePacked(loanParamsLocalId, loanToken, _borrower, _borrowerNonce));\n\n // STEP 3 close the borrowed position with a deposit\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(address(sovrynProtocol), _SUSDBalance);\n sovrynProtocol.closeWithDeposit(\n loan_id,\n address(this),\n collateralTokenSent.mul(20).div(100) // make it 20% higher from initial borrow amount\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iSUSD\n uint256 _iSUSDBalance = ILoanTokenModules(loanToken).balanceOf(_borrower);\n ILoanTokenModules(loanToken).burn(_receiver, _iSUSDBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n // });\n }\n\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256,\n bytes calldata,\n bytes calldata\n ) external {\n if (operator == address(sovrynProtocol) && to == loanToken && from == address(this)) {\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(loanToken, _SUSDBalance);\n\n ILoanTokenModules(loanToken).mint(address(this), 1000000 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyRBTC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some WRBTC from the lending pool.\n * 2. Close the loan with closeWithSwap function in the protocol.\n * 3. Burn all iWRBTC.\n *\n * The refund happened in step #3, which will send back the RBTC back to this contract.\n * Then, this contract will try to do another iWRBTC minting to the loan token --> this is where the cross-reentrancy happened between the protocol & the loan token contract.\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithSwap function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyRBTC {\n address public loanTokenWRBTC;\n address public WRBTC;\n address public SUSD;\n ProtocolLike public sovrynProtocol;\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iWRBTCBalance;\n }\n\n function() external payable {\n if (msg.sender == address(sovrynProtocol)) {\n uint256 latestRBTCBalance = address(this).balance;\n IWrbtcERC20(WRBTC).deposit.value(14 ether)();\n uint256 _WRBTCBalance = IERC20(WRBTC).balanceOf(address(this));\n IERC20(WRBTC).approve(loanTokenWRBTC, _WRBTCBalance);\n\n ILoanTokenModules(loanTokenWRBTC).mint(address(this), 14 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n\n constructor(\n address _loanTokenWRBTC,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanTokenWRBTC = _loanTokenWRBTC;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: SUSD has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n });\n\n IERC20(SUSD).approve(loanTokenWRBTC, initial.susdBalance);\n\n ILoanTokenModules(loanTokenWRBTC).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n SUSD,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanTokenWRBTC).loanParamsIds(\n uint256(keccak256(abi.encodePacked(SUSD, true)))\n );\n bytes32 loan_id =\n keccak256(\n abi.encodePacked(loanParamsLocalId, loanTokenWRBTC, _borrower, _borrowerNonce)\n );\n\n // STEP 3 close the borrowed position with a swap (probably works just as well with deposit)\n sovrynProtocol.closeWithSwap(\n loan_id,\n msg.sender,\n collateralTokenSent.mul(200).div(100), // make it 20% higher from initial collateral sent to make sure whole position is closed\n true,\n \"\"\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iRBTC\n uint256 _iWRBTCBalance = ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower);\n ILoanTokenModules(loanTokenWRBTC).burn(_receiver, _iWRBTCBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n // });\n }\n}\n" + }, + "contracts/testhelpers/TestLibraries.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../rsk/RSKAddrValidator.sol\";\n\n// contract for testing libraries\ncontract TestLibraries {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n */\n function RSKAddrValidator_checkPKNotZero(address addr) public pure returns (bool) {\n return (RSKAddrValidator.checkPKNotZero(addr));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key\n */\n function RSKAddrValidator_safeEquals(address addr1, address addr2) public pure returns (bool) {\n return (RSKAddrValidator.safeEquals(addr1, addr2));\n }\n}\n" + }, + "contracts/testhelpers/TestSovrynSwap.sol": { + "content": "/**\n * Test file simulating the SovrynSwap network\n * */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"./TestToken.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestSovrynSwap {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n address public priceFeeds;\n\n constructor(address feed) public {\n priceFeeds = feed;\n }\n\n /**\n * simulating the contract registry. always returns the address of this contract\n * */\n function addressOf(bytes32 contractName) public view returns (address) {\n return address(this);\n }\n\n /**\n * calculates the return tokens when swapping _amount, makes sure the return is bigger than _minReturn,\n * mints and burns the test tokens accordingly.\n * */\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256) {\n //compute the return for the amount of tokens provided\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n uint256 actualReturn = _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n\n require(actualReturn >= _minReturn, \"insufficient source tokens provided\");\n\n TestToken(address(_path[0])).burn(address(msg.sender), _amount);\n TestToken(address(_path[1])).mint(address(_beneficiary), actualReturn);\n return actualReturn;\n }\n\n /**\n * queries the rate from the Price Feed contract and computes the expected return amount based on the\n * amout of source tokens to be swapped.\n * */\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n\n return _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * returns the conversion path -> always a direct path\n * */\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory)\n {\n IERC20[] memory path = new IERC20[](2);\n path[0] = _sourceToken;\n path[1] = _targetToken;\n return path;\n }\n}\n" + }, + "contracts/testhelpers/TestToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestToken {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balances[_who], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[_who] = balances[_who].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(_who, _value);\n emit Transfer(_who, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/testhelpers/TestTokenERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Context.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../interfaces/IERC777.sol\";\nimport \"../interfaces/IERC777Recipient.sol\";\nimport \"../interfaces/IERC777Sender.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\n\ncontract TestTokenERC777 is Context, IERC777, IERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n mapping(address => uint256) private _balances;\n\n uint256 private _totalSupply;\n\n // We inline the result of the following hashes because Solidity doesn't resolve them at compile time.\n // See https://github.com/ethereum/solidity/issues/4024.\n\n // keccak256(\"ERC777TokensSender\")\n bytes32 private constant TOKENS_SENDER_INTERFACE_HASH =\n 0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895;\n\n // keccak256(\"ERC777TokensRecipient\")\n bytes32 private constant TOKENS_RECIPIENT_INTERFACE_HASH =\n 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;\n\n // This isn't ever read from - it's only used to respond to the defaultOperators query.\n address[] private _defaultOperatorsArray;\n\n // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).\n mapping(address => bool) private _defaultOperators;\n\n // For each account, a mapping of its operators and revoked default operators.\n mapping(address => mapping(address => bool)) private _operators;\n mapping(address => mapping(address => bool)) private _revokedDefaultOperators;\n\n // ERC20-allowances\n mapping(address => mapping(address => uint256)) private _allowances;\n\n /**\n * @dev `defaultOperators` may be an empty array.\n */\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _initialSupply,\n uint8 _decimals,\n address[] memory defaultOperators\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n _defaultOperatorsArray = defaultOperators;\n for (uint256 i = 0; i < _defaultOperatorsArray.length; i++) {\n _defaultOperators[_defaultOperatorsArray[i]] = true;\n }\n\n _mint(msg.sender, msg.sender, _initialSupply, \"\", \"\");\n\n // register interfaces\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777Token\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n /**\n * @dev See {IERC777-granularity}.\n *\n * This implementation always returns `1`.\n */\n function granularity() public view returns (uint256) {\n return 1;\n }\n\n /**\n * @dev See {IERC777-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev Returns the amount of tokens owned by an account (`tokenHolder`).\n */\n function balanceOf(address tokenHolder) public view returns (uint256) {\n return _balances[tokenHolder];\n }\n\n /**\n * @dev See {IERC777-send}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes memory data\n ) public {\n _send(_msgSender(), _msgSender(), recipient, amount, data, \"\", true);\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient}\n * interface if it is a contract.\n *\n * Also emits a {Sent} event.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n\n address from = _msgSender();\n\n _callTokensToSend(from, from, recipient, amount, \"\", \"\");\n\n _move(from, from, recipient, amount, \"\", \"\");\n\n _callTokensReceived(from, from, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev See {IERC777-burn}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function burn(uint256 amount, bytes memory data) public {\n _burn(_msgSender(), _msgSender(), amount, data, \"\");\n }\n\n /**\n * @dev See {IERC777-isOperatorFor}.\n */\n function isOperatorFor(address operator, address tokenHolder) public view returns (bool) {\n return\n operator == tokenHolder ||\n (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||\n _operators[tokenHolder][operator];\n }\n\n /**\n * @dev See {IERC777-authorizeOperator}.\n */\n function authorizeOperator(address operator) public {\n require(_msgSender() != operator, \"ERC777: authorizing self as operator\");\n\n if (_defaultOperators[operator]) {\n delete _revokedDefaultOperators[_msgSender()][operator];\n } else {\n _operators[_msgSender()][operator] = true;\n }\n\n emit AuthorizedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-revokeOperator}.\n */\n function revokeOperator(address operator) public {\n require(operator != _msgSender(), \"ERC777: revoking self as operator\");\n\n if (_defaultOperators[operator]) {\n _revokedDefaultOperators[_msgSender()][operator] = true;\n } else {\n delete _operators[_msgSender()][operator];\n }\n\n emit RevokedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-defaultOperators}.\n */\n function defaultOperators() public view returns (address[] memory) {\n return _defaultOperatorsArray;\n }\n\n /**\n * @dev See {IERC777-operatorSend}.\n *\n * Emits {Sent} and {IERC20-Transfer} events.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), sender),\n \"ERC777: caller is not an operator for holder\"\n );\n _send(_msgSender(), sender, recipient, amount, data, operatorData, true);\n }\n\n /**\n * @dev See {IERC777-operatorBurn}.\n *\n * Emits {Burned} and {IERC20-Transfer} events.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), account),\n \"ERC777: caller is not an operator for holder\"\n );\n _burn(_msgSender(), account, amount, data, operatorData);\n }\n\n /**\n * @dev See {IERC20-allowance}.\n *\n * Note that operator and allowance concepts are orthogonal: operators may\n * not have allowance, and accounts with allowance may not be operators\n * themselves.\n */\n function allowance(address holder, address spender) public view returns (uint256) {\n return _allowances[holder][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Note that accounts cannot have allowance issued by their operators.\n */\n function approve(address spender, uint256 value) public returns (bool) {\n address holder = _msgSender();\n _approve(holder, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Note that operator and allowance concepts are orthogonal: operators cannot\n * call `transferFrom` (unless they have allowance), and accounts with\n * allowance cannot call `operatorSend` (unless they are operators).\n *\n * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.\n */\n function transferFrom(\n address holder,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n require(holder != address(0), \"ERC777: transfer from the zero address\");\n\n address spender = _msgSender();\n\n _callTokensToSend(spender, holder, recipient, amount, \"\", \"\");\n\n _move(spender, holder, recipient, amount, \"\", \"\");\n\n _approve(\n holder,\n spender,\n _allowances[holder][spender].sub(amount, \"ERC777: transfer amount exceeds allowance\")\n );\n\n _callTokensReceived(spender, holder, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `operator`, `data` and `operatorData`.\n *\n * See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits {Minted} and {IERC20-Transfer} events.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - if `account` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function _mint(\n address operator,\n address account,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n require(account != address(0), \"ERC777: mint to the zero address\");\n\n // Update state variables\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n\n _callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);\n\n emit Minted(operator, account, amount, userData, operatorData);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Send tokens\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _send(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n require(from != address(0), \"ERC777: send from the zero address\");\n require(to != address(0), \"ERC777: send to the zero address\");\n\n _callTokensToSend(operator, from, to, amount, userData, operatorData);\n\n _move(operator, from, to, amount, userData, operatorData);\n\n _callTokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData,\n requireReceptionAck\n );\n }\n\n /**\n * @dev Burn tokens\n * @param operator address operator requesting the operation\n * @param from address token holder address\n * @param amount uint256 amount of tokens to burn\n * @param data bytes extra information provided by the token holder\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _burn(\n address operator,\n address from,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) internal {\n require(from != address(0), \"ERC777: burn from the zero address\");\n\n _callTokensToSend(operator, from, address(0), amount, data, operatorData);\n\n // Update state variables\n _balances[from] = _balances[from].sub(amount, \"ERC777: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n\n emit Burned(operator, from, amount, data, operatorData);\n emit Transfer(from, address(0), amount);\n }\n\n function _move(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) private {\n _balances[from] = _balances[from].sub(amount, \"ERC777: transfer amount exceeds balance\");\n _balances[to] = _balances[to].add(amount);\n\n emit Sent(operator, from, to, amount, userData, operatorData);\n emit Transfer(from, to, amount);\n }\n\n function _approve(\n address holder,\n address spender,\n uint256 value\n ) internal {\n // TODO: restore this require statement if this function becomes internal, or is called at a new callsite. It is\n // currently unnecessary.\n //require(holder != address(0), \"ERC777: approve from the zero address\");\n require(spender != address(0), \"ERC777: approve to the zero address\");\n\n _allowances[holder][spender] = value;\n emit Approval(holder, spender, value);\n }\n\n /**\n * @dev Call from.tokensToSend() if the interface is registered\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _callTokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Sender(implementer).tokensToSend(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n }\n }\n\n /**\n * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but\n * tokensReceived() was not registered for the recipient\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _callTokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Recipient(implementer).tokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n } else if (requireReceptionAck) {\n require(\n !to.isContract(),\n \"ERC777: token recipient contract has no implementer for ERC777TokensRecipient\"\n );\n }\n }\n\n function mint(address _to, uint256 _value) public {\n // Update state variables\n _totalSupply = _totalSupply.add(_value);\n _balances[_to] = _balances[_to].add(_value);\n\n emit Minted(msg.sender, _to, _value, \"\", \"\");\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balanceOf(_who), \"balance too low\");\n\n _burn(msg.sender, _who, _value, \"\", \"\");\n }\n}\n" + }, + "contracts/testhelpers/TestTokenLimited.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestTokenLimited {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n require(_value <= 100000 ether, \"max mint amount exceeded\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(uint256 _value) public {\n require(_value <= balances[msg.sender], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(msg.sender, _value);\n emit Transfer(msg.sender, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/token/IApproveAndCall.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/ApprovalReceiver.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IApproveAndCall {\n /**\n * @notice Receives approval from SOV token.\n * @param _sender The sender of SOV.approveAndCall function.\n * @param _amount The amount was approved.\n * @param _token The address of token.\n * @param _data The data will be used for low level call.\n * */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/token/SOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/ERC20Detailed.sol\";\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./IApproveAndCall.sol\";\n\n/**\n * @title Sovryn Token: SOV is an ERC-20 token contract for Sovryn governance.\n *\n * @notice This contract accounts for all holders' balances.\n *\n * @dev This contract represents a token with dynamic supply.\n * The owner of the token contract can mint/burn tokens to/from any account\n * based upon previous governance voting and approval.\n * */\ncontract SOV is ERC20, ERC20Detailed, Ownable {\n string constant NAME = \"Sovryn Token\";\n string constant SYMBOL = \"SOV\";\n uint8 constant DECIMALS = 18;\n\n /**\n * @notice Constructor called on deployment, initiates the contract.\n * @dev On deployment, some amount of tokens will be minted for the owner.\n * @param _initialAmount The amount of tokens to be minted on contract creation.\n * */\n constructor(uint256 _initialAmount) public ERC20Detailed(NAME, SYMBOL, DECIMALS) {\n if (_initialAmount != 0) {\n _mint(msg.sender, _initialAmount);\n }\n }\n\n /**\n * @notice Creates new tokens and sends them to the recipient.\n * @dev Don't create more than 2^96/10 tokens before updating the governance first.\n * @param _account The recipient address to get the minted tokens.\n * @param _amount The amount of tokens to be minted.\n * */\n function mint(address _account, uint256 _amount) public onlyOwner {\n _mint(_account, _amount);\n }\n\n /**\n * @notice Approves and then calls the receiving contract.\n * Useful to encapsulate sending tokens to a contract in one call.\n * Solidity has no native way to send tokens to contracts.\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\n * @param _spender The contract address to spend the tokens.\n * @param _amount The amount of tokens to be sent.\n * @param _data Parameters for the contract call, such as endpoint signature.\n * */\n function approveAndCall(\n address _spender,\n uint256 _amount,\n bytes memory _data\n ) public {\n approve(_spender, _amount);\n IApproveAndCall(_spender).receiveApproval(msg.sender, _amount, address(this), _data);\n }\n}\n" + }, + "contracts/utils/AdminRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\n\ncontract AdminRole is Ownable {\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * or on our own overriding sovrynOwnable.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n}\n" + }, + "contracts/utils/PausableRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/PausableOz.sol\";\n\ncontract PausableRole is PausableOz {\n address public pauser;\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n\n /**\n * @dev Modifier to make a function callable only when the caller is pauser or owner\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"Pausable: unauthorized\"); // SS02\n _;\n }\n\n /**\n * @notice Set the pauser address.\n *\n * only pauser can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyPauserOrOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyPauserOrOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/utils/ProxyOwnable.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\n/**\n * Based on OpenZeppelin's Ownable contract:\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\n *\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract ProxyOwnable {\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Ownable:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"ProxyOwnable::setProxyOwner: invalid address\");\n emit ProxyOwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Set address of the owner (only owner can call this function)\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n\n /**\n * @notice Return address of the owner.\n * @return _owner Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n}\n" + }, + "contracts/utils/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\nlibrary Utils {\n function stringToBytes32(string memory source) internal pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + }, + "remappings": [ + "ds-test/=foundry/lib/forge-std/lib/ds-test/src/", + "forge-std/=foundry/lib/forge-std/src/" + ] + } +} \ No newline at end of file diff --git a/deployment/deployments/rskSovrynTestnet/solcInputs/85e0140014063bf09a4ea91c8a627911.json b/deployment/deployments/rskSovrynTestnet/solcInputs/85e0140014063bf09a4ea91c8a627911.json new file mode 100644 index 000000000..e9018d1c9 --- /dev/null +++ b/deployment/deployments/rskSovrynTestnet/solcInputs/85e0140014063bf09a4ea91c8a627911.json @@ -0,0 +1,708 @@ +{ + "language": "Solidity", + "sources": { + "contracts/connectors/loantoken/AdvancedToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Advanced Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedToken implements standard ERC-20 approval, mint and burn token functionality.\n * Logic (AdvancedToken) is kept aside from storage (AdvancedTokenStorage).\n *\n * For example, LoanTokenLogicDai contract uses AdvancedToken::_mint() to mint\n * its Loan Dai iTokens.\n * */\ncontract AdvancedToken is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n /**\n * @notice Set an amount as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n *\n * @param _spender The account address that will be able to spend the tokens.\n * @param _value The amount of tokens allowed to spend.\n * */\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @notice The iToken minting process. Meant to issue Loan iTokens.\n * Lenders are able to open an iToken position, by minting them.\n * This function is called by LoanTokenLogicStandard::_mintToken\n * @param _to The recipient of the minted tTokens.\n * @param _tokenAmount The amount of iTokens to be minted.\n * @param _assetAmount The amount of lended tokens (asset to lend).\n * @param _price The price of the lended tokens.\n * @return The updated balance of the recipient.\n * */\n function _mint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n require(_to != address(0), \"15\");\n\n uint256 _balance = balances[_to].add(_tokenAmount);\n balances[_to] = _balance;\n\n totalSupply_ = totalSupply_.add(_tokenAmount);\n\n emit Mint(_to, _tokenAmount, _assetAmount, _price);\n emit Transfer(address(0), _to, _tokenAmount);\n\n return _balance;\n }\n\n /**\n * @notice The iToken burning process. Meant to destroy Loan iTokens.\n * Lenders are able to close an iToken position, by burning them.\n * This function is called by LoanTokenLogicStandard::_burnToken\n * @param _who The owner of the iTokens to burn.\n * @param _tokenAmount The amount of iTokens to burn.\n * @param _assetAmount The amount of lended tokens.\n * @param _price The price of the lended tokens.\n * @return The updated balance of the iTokens owner.\n * */\n function _burn(\n address _who,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n //bzx compare\n //TODO: Unit test\n uint256 _balance = balances[_who].sub(_tokenAmount, \"16\");\n\n // a rounding error may leave dust behind, so we clear this out\n if (_balance <= 10) {\n // We can't leave such small balance quantities.\n _tokenAmount = _tokenAmount.add(_balance);\n _balance = 0;\n }\n balances[_who] = _balance;\n\n totalSupply_ = totalSupply_.sub(_tokenAmount);\n\n emit Burn(_who, _tokenAmount, _assetAmount, _price);\n emit Transfer(_who, address(0), _tokenAmount);\n return _balance;\n }\n}\n" + }, + "contracts/connectors/loantoken/AdvancedTokenStorage.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./LoanTokenBase.sol\";\n\n/**\n * @title Advanced Token Storage contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedTokenStorage implements standard ERC-20 getters functionality:\n * totalSupply, balanceOf, allowance and some events.\n * iToken logic is divided into several contracts AdvancedToken,\n * AdvancedTokenStorage and LoanTokenBase.\n * */\ncontract AdvancedTokenStorage is LoanTokenBase {\n using SafeMath for uint256;\n\n /* Events */\n\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /* Storage */\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n /* Functions */\n\n /**\n * @notice Get the total supply of iTokens.\n * @return The total number of iTokens in existence as of now.\n * */\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n /**\n * @notice Get the amount of iTokens owned by an account.\n * @param _owner The account owner of the iTokens.\n * @return The number of iTokens an account owns.\n * */\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n /**\n * @notice Get the amount of iTokens allowed to be spent by a\n * given account on behalf of the owner.\n * @param _owner The account owner of the iTokens.\n * @param _spender The account allowed to send the iTokens.\n * @return The number of iTokens an account is allowing the spender\n * to send on its behalf.\n * */\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/connectors/loantoken/interfaces/FeedsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface FeedsLike {\n function queryRate(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 rate, uint256 precision);\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../lib/MarginTradeStructHelpers.sol\";\n\ninterface ProtocolLike {\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function priceFeeds() external view returns (address);\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function lendingFeePercent() external view returns (uint256);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function borrowerNonce(address) external view returns (uint256);\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata // for future use /*loanDataBytes*/\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolSettingsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../core/objects/LoanParamsStruct.sol\";\n\ninterface ProtocolSettingsLike {\n function setupLoanParams(LoanParamsStruct.LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n}\n" + }, + "contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol": { + "content": "pragma solidity 0.5.17;\n\nlibrary MarginTradeStructHelpers {\n struct SentAddresses {\n address lender;\n address borrower;\n address receiver;\n address manager;\n }\n\n struct SentAmounts {\n uint256 interestRate;\n uint256 newPrincipal;\n uint256 interestInitialAmount;\n uint256 loanTokenSent;\n uint256 collateralTokenSent;\n uint256 minEntryPrice;\n uint256 loanToCollateralSwapRate;\n uint256 interestDuration;\n uint256 entryLeverage;\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Loan Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * A loan token (iToken) is created as a proxy to an upgradable token contract.\n *\n * Examples of loan tokens on Sovryn are iRBTC, iDOC, iUSDT, iBPro,\n * iSOV (near future).\n *\n * Lenders receive iTokens that collect interest from the lending pool\n * which they can redeem by withdrawing them. The i in iToken stands for interest.\n *\n * Do not confuse iTokens with underlying tokens. iDOC is an iToken (loan token)\n * whilest DOC is the underlying token (currency).\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\n * */\ncontract LoanToken is AdvancedTokenStorage {\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n address public admin;\n\n /**\n * @notice Deploy loan token proxy.\n * Sets ERC20 parameters of the token.\n *\n * @param _newOwner The address of the new owner.\n * @param _newTarget The address of the new target contract instance.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice Public owner setter for target address.\n * @dev Calls internal setter.\n * @param _newTarget The address of the new target contract instance.\n * */\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n /**\n * @notice Internal setter for target address.\n * @param _newTarget The address of the new target contract instance.\n * */\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n /**\n * @notice Internal setter for sovrynContract address.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * */\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n /**\n * @notice Internal setter for wrBTC address.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n /**\n * @notice Public owner cloner for pointed loan token.\n * Sets ERC20 parameters of the token.\n *\n * @dev TODO: add check for double init.\n * idk but init usually can be called only once.\n *\n * @param _loanTokenAddress The address of the pointed loan token instance.\n * @param _name The ERC20 token name.\n * @param _symbol The ERC20 token symbol.\n * */\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; /// starting price of 1\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenBase.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SignedSafeMath.sol\";\nimport \"../../openzeppelin/ReentrancyGuard.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\nimport \"./Pausable.sol\";\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title Loan Token Base contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Specific loan related storage for iTokens.\n *\n * An loan token or iToken is a representation of a user funds in the pool and the\n * interest they've earned. The redemption value of iTokens continually increase\n * from the accretion of interest paid into the lending pool by borrowers. The user\n * can sell iTokens to exit its position. The user might potentially use them as\n * collateral wherever applicable.\n *\n * There are three main tokens in the bZx system, iTokens, pTokens, and BZRX tokens.\n * The bZx system of lending and borrowing depends on iTokens and pTokens, and when\n * users lend or borrow money on bZx, their crypto assets go into or come out of\n * global liquidity pools, which are pools of funds shared between many different\n * exchanges. When lenders supply funds into the global liquidity pools, they\n * automatically receive iTokens; When users borrow money to open margin trading\n * positions, they automatically receive pTokens. The system is also designed to\n * use the BZRX tokens, which are only used to pay fees on the network currently.\n * */\ncontract LoanTokenBase is ReentrancyGuard, SharedReentrancyGuard, Ownable, Pausable {\n uint256 internal constant WEI_PRECISION = 10**18;\n uint256 internal constant WEI_PERCENT_PRECISION = 10**20;\n\n int256 internal constant sWEI_PRECISION = 10**18;\n\n /// @notice Standard ERC-20 properties\n string public name;\n string public symbol;\n uint8 public decimals;\n\n /// @notice The address of the loan token (asset to lend) instance.\n address public loanTokenAddress;\n\n uint256 public baseRate;\n uint256 public rateMultiplier;\n uint256 public lowUtilBaseRate;\n uint256 public lowUtilRateMultiplier;\n\n uint256 public targetLevel;\n uint256 public kinkLevel;\n uint256 public maxScaleRate;\n\n uint256 internal _flTotalAssetSupply;\n uint256 public checkpointSupply;\n uint256 public initialPrice;\n\n /// uint88 for tight packing -> 8 + 88 + 160 = 256\n uint88 internal lastSettleTime_;\n\n /// Mapping of keccak256(collateralToken, isTorqueLoan) to loanParamsId.\n mapping(uint256 => bytes32) public loanParamsIds;\n\n /// Price of token at last user checkpoint.\n mapping(address => uint256) internal checkpointPrices_;\n\n // the maximum trading/borrowing/lending limit per token address\n mapping(address => uint256) public transactionLimit;\n // 0 -> no limit\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicBeacon.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../mixins/EnumerableBytes32Set.sol\";\nimport \"../../mixins/EnumerableBytes4Set.sol\";\nimport \"../../utils/PausableRole.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Loan Token Logic Beacon contract.\n *\n * @notice This contract stored the target logic implementation of LoanTokens which has the same logic implementation (LoanTokenLogicLM / LoanTokenLogicWrbtc)\n * Apart from storing the target logic implementation, this contract also has a pause functionality.\n * By implementing pause/unpause functionality in this beacon contract, we can pause the loan token that has the same Logic (LoanTokenLogicLM / LoanTokenLogicWrbtc) at one call.\n * Meanwhile the pause/unpause function in the LoanTokenLogicProxy is used to pause/unpause specific LoanToken\n */\n\ncontract LoanTokenLogicBeacon is PausableRole {\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; // enumerable map of bytes4 or addresses\n\n mapping(bytes4 => address) private logicTargets;\n\n struct LoanTokenLogicModuleUpdate {\n address implementation; // address implementaion of the module\n uint256 updateTimestamp; // time of update\n }\n\n mapping(bytes32 => LoanTokenLogicModuleUpdate[]) public moduleUpgradeLog; /** the module name as the key */\n\n mapping(bytes32 => uint256) public activeModuleIndex; /** To store the current active index log for module */\n\n mapping(bytes32 => EnumerableBytes4Set.Bytes4Set) private activeFuncSignatureList; /** Store the current active function signature */\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n * This is the overriden function from the pausable contract, so that we can use custom error message.\n */\n modifier whenNotPaused() {\n require(!_paused, \"LoanTokenLogicBeacon:paused mode\");\n _;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This function will store the updated protocol module to the storage (For rollback purposes)\n *\n * @param loanTokenModuleAddress The module target address\n */\n function registerLoanTokenModule(address loanTokenModuleAddress) external onlyOwner {\n bytes32 moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n\n // Store the upgrade to the log\n moduleUpgradeLog[moduleName].push(\n LoanTokenLogicModuleUpdate(loanTokenModuleAddress, block.timestamp)\n );\n activeModuleIndex[moduleName] = moduleUpgradeLog[moduleName].length - 1;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This registration will require target contract to have the exact function getListFunctionSignatures() which will return functionSignatureList and the moduleName in bytes32\n *\n * @param loanTokenModuleAddress the target logic of the loan token module\n *\n * @return the module name\n */\n function _registerLoanTokenModule(address loanTokenModuleAddress) private returns (bytes32) {\n require(\n Address.isContract(loanTokenModuleAddress),\n \"LoanTokenModuleAddress is not a contract\"\n );\n\n // Get the list of function signature on this loanTokenModulesAddress\n (bytes4[] memory functionSignatureList, bytes32 moduleName) =\n ILoanTokenLogicModules(loanTokenModuleAddress).getListFunctionSignatures();\n\n /// register / update the module function signature address implementation\n for (uint256 i; i < functionSignatureList.length; i++) {\n require(functionSignatureList[i] != bytes4(0x0), \"ERR_EMPTY_FUNC_SIGNATURE\");\n logicTargets[functionSignatureList[i]] = loanTokenModuleAddress;\n if (!activeFuncSignatureList[moduleName].contains(functionSignatureList[i]))\n activeFuncSignatureList[moduleName].addBytes4(functionSignatureList[i]);\n }\n\n /// delete the \"removed\" module function signature in the current implementation\n bytes4[] memory activeSignatureListEnum =\n activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n for (uint256 i; i < activeSignatureListEnum.length; i++) {\n bytes4 activeSigBytes = activeSignatureListEnum[i];\n if (logicTargets[activeSigBytes] != loanTokenModuleAddress) {\n logicTargets[activeSigBytes] = address(0);\n activeFuncSignatureList[moduleName].removeBytes4(activeSigBytes);\n }\n }\n\n return moduleName;\n }\n\n /**\n * @dev get all active function signature list based on the module name.\n *\n * @param moduleName in bytes32.\n *\n * @return the array of function signature.\n */\n function getActiveFuncSignatureList(bytes32 moduleName)\n public\n view\n returns (bytes4[] memory signatureList)\n {\n signatureList = activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n return signatureList;\n }\n\n /**\n * @dev Get total length of the module upgrade log.\n *\n * @param moduleName in bytes32.\n *\n * @return length of module upgrade log.\n */\n function getModuleUpgradeLogLength(bytes32 moduleName) external view returns (uint256) {\n return moduleUpgradeLog[moduleName].length;\n }\n\n /**\n * @notice This function will rollback particular module to the spesific index / version of deployment\n *\n * @param moduleName Name of module in bytes32 format\n * @param index index / version of previous deployment\n */\n function rollback(bytes32 moduleName, uint256 index) external onlyOwner {\n address loanTokenModuleAddress = moduleUpgradeLog[moduleName][index].implementation;\n moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n activeModuleIndex[moduleName] = index;\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(bytes4 sig) external view whenNotPaused returns (address) {\n return logicTargets[sig];\n }\n}\n\ninterface ILoanTokenLogicModules {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory, bytes32 moduleName);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicProxy.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./AdvancedTokenStorage.sol\";\nimport \"../../openzeppelin/Initializable.sol\";\n\n/**\n * @title Loan Token Logic Proxy contract.\n *\n * @notice This contract contains the proxy functionality and it will query the logic target from LoanTokenLogicBeacon\n * This contract will also has the pause/unpause functionality. The purpose of this pausability is so that we can pause/unpause from the loan token level.\n *\n */\ncontract LoanTokenLogicProxy is AdvancedTokenStorage {\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT\n */\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT (CONSTANT / IMMUTABLE)\n */\n\n bytes32 internal constant LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT =\n keccak256(\"LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT\");\n\n modifier onlyAdmin() {\n require(isOwner(), \"LoanTokenLogicProxy:unauthorized\");\n _;\n }\n\n /**\n * @notice Fallback function performs a logic implementation address query to LoanTokenLogicBeacon and then do delegate call to that query result address.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n // query the logic target implementation address from the LoanTokenLogicBeacon\n address target = ILoanTokenLogicBeacon(_beaconAddress()).getTarget(msg.sig);\n require(target != address(0), \"LoanTokenLogicProxy:target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @dev Returns the current Loan Token logic Beacon.\n * @return Address of the current LoanTokenLogicBeacon.\n */\n function _beaconAddress() internal view returns (address beaconAddress) {\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n assembly {\n beaconAddress := sload(slot)\n }\n }\n\n /**\n * @return The address of the current LoanTokenLogicBeacon.\n */\n function beaconAddress() external view returns (address) {\n return _beaconAddress();\n }\n\n /**\n * @dev Set/update the new beacon address.\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon.\n */\n function _setBeaconAddress(address _newBeaconAddress) private {\n require(\n Address.isContract(_newBeaconAddress),\n \"Cannot set beacon address to a non-contract address\"\n );\n\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n\n assembly {\n sstore(slot, _newBeaconAddress)\n }\n }\n\n /**\n * @dev External function to set the new LoanTokenLogicBeacon Address\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon\n */\n function setBeaconAddress(address _newBeaconAddress) external onlyAdmin {\n _setBeaconAddress(_newBeaconAddress);\n }\n\n /**\n * @dev External function to return the LoanTokenLogicProxy of loan token (target of LoanToken contract).\n * Ideally this getter should be added in the LoanToken contract\n * but since LoanToken contract can't be changed, adding the getter in this contract will do\n * because it will use the context of LoanToken contract.\n *\n * @return target address of LoanToken contract\n */\n function getTarget() external view returns (address) {\n return target_;\n }\n}\n\ninterface ILoanTokenLogicBeacon {\n function getTarget(bytes4 functionSignature)\n external\n view\n returns (address logicTargetAddress);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicShared.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicStorage.sol\";\nimport \"./interfaces/ProtocolLike.sol\";\nimport \"./interfaces/FeedsLike.sol\";\nimport \"./interfaces/ProtocolSettingsLike.sol\";\nimport \"../../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../../farm/ILiquidityMining.sol\";\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../governance/Vesting/IVesting.sol\";\n\n/**\n * @dev This contract shares functions used by both LoanTokenLogicSplit and LoanTokenLogicStandard\n */\ncontract LoanTokenLogicShared is LoanTokenLogicStorage {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /**\n * @notice Update the user's checkpoint price and profit so far.\n * In this loan token contract, whenever some tokens are minted or burned,\n * the _updateCheckpoints() function is invoked to update the stats to\n * reflect the balance changes.\n *\n * @param _user The user address.\n * @param _oldBalance The user's previous balance.\n * @param _newBalance The user's updated balance.\n * @param _currentPrice The current loan token price.\n * */\n function _updateCheckpoints(\n address _user,\n uint256 _oldBalance,\n uint256 _newBalance,\n uint256 _currentPrice\n ) internal {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(_user, iToken_ProfitSoFar));\n\n int256 _currentProfit;\n if (_newBalance == 0) {\n _currentPrice = 0;\n } else if (_oldBalance != 0) {\n _currentProfit = _profitOf(slot, _oldBalance, _currentPrice, checkpointPrices_[_user]);\n }\n\n assembly {\n sstore(slot, _currentProfit)\n }\n\n checkpointPrices_[_user] = _currentPrice;\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice Transfer tokens, low level.\n * Checks allowance, updates sender and recipient balances\n * and updates checkpoints too.\n *\n * @param _from The tokens' owner.\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @param _allowanceAmount The amount of tokens allowed to transfer.\n *\n * @return Success true/false.\n * */\n function _internalTransferFrom(\n address _from,\n address _to,\n uint256 _value,\n uint256 _allowanceAmount\n ) internal returns (bool) {\n if (_allowanceAmount != uint256(-1)) {\n allowed[_from][msg.sender] = _allowanceAmount.sub(_value, \"14\");\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, _allowanceAmount, allowed[_from][msg.sender]);\n }\n\n require(_to != address(0), \"15\");\n\n uint256 _balancesFrom = balances[_from];\n uint256 _balancesFromNew = _balancesFrom.sub(_value, \"16\");\n balances[_from] = _balancesFromNew;\n\n uint256 _balancesTo = balances[_to];\n uint256 _balancesToNew = _balancesTo.add(_value);\n balances[_to] = _balancesToNew;\n\n /// @dev Handle checkpoint update.\n uint256 _currentPrice = tokenPrice();\n\n //checkpoints are not being used by the smart contract logic itself, but just for external use (query the profit)\n //only update the checkpoints of a user if he's not depositing to / withdrawing from the lending pool\n if (_from != liquidityMiningAddress && _to != liquidityMiningAddress) {\n _updateCheckpoints(_from, _balancesFrom, _balancesFromNew, _currentPrice);\n _updateCheckpoints(_to, _balancesTo, _balancesToNew, _currentPrice);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n /**\n * @notice Profit calculation based on checkpoints of price.\n * @param slot The user slot.\n * @param _balance The user balance.\n * @param _currentPrice The current price of the loan token.\n * @param _checkpointPrice The price of the loan token on checkpoint.\n * @return The profit of a user.\n * */\n function _profitOf(\n bytes32 slot,\n uint256 _balance,\n uint256 _currentPrice,\n uint256 _checkpointPrice\n ) internal view returns (int256 profitSoFar) {\n if (_checkpointPrice == 0) {\n return 0;\n }\n\n assembly {\n profitSoFar := sload(slot)\n }\n\n profitSoFar = int256(_currentPrice)\n .sub(int256(_checkpointPrice))\n .mul(int256(_balance))\n .div(sWEI_PRECISION)\n .add(profitSoFar);\n }\n\n /**\n * @notice Loan token price calculation considering unpaid interests.\n * @return The loan token price.\n * */\n function tokenPrice() public view returns (uint256 price) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _tokenPrice(_totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Get the total amount of loan tokens on debt.\n * Calls protocol getTotalPrincipal function.\n * In the context of borrowing, principal is the initial size of a loan.\n * It can also be the amount still owed on a loan. If you take out a\n * $50,000 mortgage, for example, the principal is $50,000. If you pay off\n * $30,000, the principal balance now consists of the remaining $20,000.\n *\n * @return The total amount of loan tokens on debt.\n * */\n function totalAssetBorrow() public view returns (uint256) {\n return\n ProtocolLike(sovrynContractAddress).getTotalPrincipal(address(this), loanTokenAddress);\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice .\n *\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param withdrawalAmount The amount of tokens to withdraw.\n *\n * @return msgValue The amount of rBTC sent minus the collateral on tokens.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = loanTokenAddress;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n _safeTransfer(_loanTokenAddress, sentAddresses.receiver, withdrawalAmount, \"\");\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n /**\n * This is a critical piece of code!\n * rBTC are supposed to be held by the contract itself, while other tokens are being transfered from the sender directly.\n * */\n if (collateralTokenSent != 0) {\n if (\n collateralTokenAddress == _wrbtcToken &&\n msgValue != 0 &&\n msgValue >= collateralTokenSent\n ) {\n IWrbtc(_wrbtcToken).deposit.value(collateralTokenSent)();\n _safeTransfer(\n collateralTokenAddress,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-a\"\n );\n msgValue -= collateralTokenSent;\n } else {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-b\"\n );\n }\n }\n\n if (loanTokenSent != 0) {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n\n /**\n * @notice Withdraw loan token interests from protocol.\n * This function only operates once per block.\n * It asks protocol to withdraw accrued interests for the loan token.\n *\n * @dev Internal sync required on every loan trade before starting.\n * */\n function _settleInterest() internal {\n uint88 ts = uint88(block.timestamp);\n if (lastSettleTime_ != ts) {\n ProtocolLike(sovrynContractAddress).withdrawAccruedInterest(loanTokenAddress);\n\n lastSettleTime_ = ts;\n }\n }\n\n /**\n * @notice Imitate a Solidity high-level call (i.e. a regular function\n * call to a contract), relaxing the requirement on the return value:\n * the return value is optional (but if data is returned, it must not be\n * false).\n *\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n * @param errorMsg The error message on failure.\n * */\n function _callOptionalReturn(\n address token,\n bytes memory data,\n string memory errorMsg\n ) internal {\n require(Address.isContract(token), \"call to a non-contract address\");\n (bool success, bytes memory returndata) = token.call(data);\n require(success, errorMsg);\n\n if (returndata.length != 0) {\n require(abi.decode(returndata, (bool)), errorMsg);\n }\n }\n\n /**\n * @notice Execute the ERC20 token's `transfer` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransfer(\n address token,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transfer.selector, to, amount),\n errorMsg\n );\n }\n\n /**\n * @notice Execute the ERC20 token's `transferFrom` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param from The source address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransferFrom(\n address token,\n address from,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transferFrom.selector, from, to, amount),\n errorMsg\n );\n }\n\n /** Internal view function */\n /**\n * @notice Compute the token price.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The token price.\n * */\n function _tokenPrice(uint256 assetSupply) internal view returns (uint256) {\n uint256 totalTokenSupply = totalSupply_;\n\n return\n totalTokenSupply != 0 ? assetSupply.mul(10**18).div(totalTokenSupply) : initialPrice;\n }\n\n /**\n * @notice Get two kind of interests: owed per day and yet to be paid.\n * @return interestOwedPerDay The interest per day.\n * @return interestUnPaid The interest not yet paid.\n * */\n function _getAllInterest()\n internal\n view\n returns (uint256 interestOwedPerDay, uint256 interestUnPaid)\n {\n /// interestPaid, interestPaidDate, interestOwedPerDay, interestUnPaid, interestFeePercent, principalTotal\n uint256 interestFeePercent;\n (, , interestOwedPerDay, interestUnPaid, interestFeePercent, ) = ProtocolLike(\n sovrynContractAddress\n )\n .getLenderInterestData(address(this), loanTokenAddress);\n\n interestUnPaid = interestUnPaid.mul(SafeMath.sub(10**20, interestFeePercent)).div(10**20);\n }\n\n /**\n * @notice Compute the total amount of loan tokens on supply.\n * @param interestUnPaid The interest not yet paid.\n * @return assetSupply The total amount of loan tokens on supply.\n * */\n function _totalAssetSupply(uint256 interestUnPaid)\n internal\n view\n returns (uint256 assetSupply)\n {\n if (totalSupply_ != 0) {\n uint256 assetsBalance = _flTotalAssetSupply; /// Temporary locked totalAssetSupply during a flash loan transaction.\n if (assetsBalance == 0) {\n assetsBalance = _underlyingBalance().add(totalAssetBorrow());\n }\n\n return assetsBalance.add(interestUnPaid);\n }\n }\n\n /**\n * @notice Get the loan contract balance.\n * @return The balance of the loan token for this contract.\n * */\n function _underlyingBalance() internal view returns (uint256) {\n return IERC20(loanTokenAddress).balanceOf(address(this));\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicSplit.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\n/**\n * @title Loan Token Logic Standard contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Logic around loan tokens (iTokens) required to operate borrowing,\n * and margin trading financial processes.\n *\n * The user provides funds to the lending pool using the mint function and\n * withdraws funds from the lending pool using the burn function. Mint and\n * burn refer to minting and burning loan tokens. Loan tokens represent a\n * share of the pool and gather interest over time.\n *\n * Interest rates are determined by supply and demand. When a lender deposits\n * funds, the interest rates go down. When a trader borrows funds, the\n * interest rates go up. Fulcrum uses a simple linear interest rate formula\n * of the form y = mx + b. The interest rate starts at 1% when loans aren't\n * being utilized and scales up to 40% when all the funds in the loan pool\n * are being borrowed.\n *\n * The borrow rate is determined at the time of the loan and represents the\n * net contribution of each borrower. Each borrower's interest contribution\n * is determined by the utilization rate of the pool and is netted against\n * all prior borrows. This means that the total amount of interest flowing\n * into the lending pool is not directly changed by lenders entering or\n * exiting the pool. The entrance or exit of lenders only impacts how the\n * interest payments are split up.\n *\n * For example, if there are 2 lenders with equal holdings each earning\n * 5% APR, but one of the lenders leave, then the remaining lender will earn\n * 10% APR since the interest payments don't have to be split between two\n * individuals.\n * */\ncontract LoanTokenLogicSplit is LoanTokenLogicShared {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /* Public functions */\n\n /**\n * @notice Mint loan token wrapper.\n * Adds a check before calling low level _mintToken function.\n * The function retrieves the tokens from the message sender, so make sure\n * to first approve the loan token contract to access your funds. This is\n * done by calling approve(address spender, uint amount) on the ERC20\n * token contract, where spender is the loan token contract address and\n * amount is the amount to be deposited.\n *\n * @param receiver The account getting the minted tokens.\n * @param depositAmount The amount of underlying tokens provided on the\n * loan. (Not the number of loan tokens to mint).\n *\n * @return The amount of loan tokens minted.\n * */\n function mint(address receiver, uint256 depositAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice Burn loan token wrapper.\n * Adds a pay-out transfer after calling low level _burnToken function.\n * In order to withdraw funds to the pool, call burn on the respective\n * loan token contract. This will burn your loan tokens and send you the\n * underlying token in exchange.\n *\n * @param receiver The account getting the minted tokens.\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 loanAmountPaid)\n {\n loanAmountPaid = _burnToken(burnAmount);\n\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (loanAmountPaid != 0) {\n _safeTransfer(loanTokenAddress, receiver, loanAmountPaid, \"5\");\n }\n }\n\n /**\n * @notice transfers the underlying asset from the msg.sender and mints tokens for the receiver\n * @param receiver the address of the iToken receiver\n * @param depositAmount the amount of underlying assets to be deposited\n * @return the amount of iTokens issued\n */\n function _mintToken(address receiver, uint256 depositAmount)\n internal\n returns (uint256 mintAmount)\n {\n uint256 currentPrice;\n\n //calculate amount to mint and transfer the underlying asset\n (mintAmount, currentPrice) = _prepareMinting(depositAmount);\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n receiver\n );\n uint256 oldBalance = balances[receiver].add(balanceOnLM);\n uint256 newBalance = oldBalance.add(mintAmount);\n\n //mint the tokens to the receiver\n _mint(receiver, mintAmount, depositAmount, currentPrice);\n\n //update the checkpoint of the receiver\n _updateCheckpoints(receiver, oldBalance, newBalance, currentPrice);\n }\n\n /**\n * calculates the amount of tokens to mint and transfers the underlying asset to this contract\n * @param depositAmount the amount of the underyling asset deposited\n * @return the amount to be minted\n */\n function _prepareMinting(uint256 depositAmount)\n internal\n returns (uint256 mintAmount, uint256 currentPrice)\n {\n require(depositAmount != 0, \"17\");\n\n _settleInterest();\n\n currentPrice = _tokenPrice(_totalAssetSupply(0));\n mintAmount = depositAmount.mul(10**18).div(currentPrice);\n\n if (msg.value == 0) {\n _safeTransferFrom(loanTokenAddress, msg.sender, address(this), depositAmount, \"18\");\n } else {\n IWrbtc(wrbtcTokenAddress).deposit.value(depositAmount)();\n }\n }\n\n /**\n * @notice A wrapper for AdvancedToken::_burn\n *\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function _burnToken(uint256 burnAmount) internal returns (uint256 loanAmountPaid) {\n require(burnAmount != 0, \"19\");\n\n if (burnAmount > balanceOf(msg.sender)) {\n require(burnAmount == uint256(-1), \"32\");\n burnAmount = balanceOf(msg.sender);\n }\n\n _settleInterest();\n\n uint256 currentPrice = _tokenPrice(_totalAssetSupply(0));\n\n uint256 loanAmountOwed = burnAmount.mul(currentPrice).div(10**18);\n uint256 loanAmountAvailableInContract = _underlyingBalance();\n\n loanAmountPaid = loanAmountOwed;\n require(loanAmountPaid <= loanAmountAvailableInContract, \"37\");\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n uint256 oldBalance = balances[msg.sender].add(balanceOnLM);\n uint256 newBalance = oldBalance.sub(burnAmount);\n\n _burn(msg.sender, burnAmount, loanAmountPaid, currentPrice);\n\n //this function does not only update the checkpoints but also the current profit of the user\n //all for external use only\n _updateCheckpoints(msg.sender, oldBalance, newBalance, currentPrice);\n }\n\n function _mintWithLM(address receiver, uint256 depositAmount)\n internal\n returns (uint256 minted)\n {\n //mint the tokens for the receiver\n minted = _mintToken(receiver, depositAmount);\n\n //transfer the tokens from the receiver to the LM address\n _internalTransferFrom(receiver, liquidityMiningAddress, minted, minted);\n\n //inform the LM mining contract\n ILiquidityMining(liquidityMiningAddress).onTokensDeposited(receiver, minted);\n }\n\n function _burnFromLM(uint256 burnAmount) internal returns (uint256) {\n uint256 balanceOnLM =\n ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n require(balanceOnLM.add(balanceOf(msg.sender)) >= burnAmount, \"not enough balance\");\n\n if (balanceOnLM > 0) {\n //withdraw pool tokens and LM rewards to the passed address\n if (balanceOnLM < burnAmount) {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n balanceOnLM,\n msg.sender\n );\n } else {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n burnAmount,\n msg.sender\n );\n }\n }\n //burn the tokens of the msg.sender\n return _burnToken(burnAmount);\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStandard.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\ncontract LoanTokenLogicStandard is LoanTokenLogicShared {\n /**\n * @notice Transfer tokens wrapper.\n * Sets token owner the msg.sender.\n * Sets maximun allowance uint256(-1) to ensure tokens are always transferred.\n *\n * If the recipient (_to) is a vesting contract address, transfer the token to the tokenOwner of the vesting contract itself.\n *\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @return Success true/false.\n * */\n function transfer(address _to, uint256 _value) external returns (bool) {\n /** need additional check address(0) here to support backward compatibility\n * in case we don't want to activate this check, just need to set the stakingContractAddress to 0 address\n */\n if (\n stakingContractAddress != address(0) &&\n IStaking(stakingContractAddress).isVestingContract(_to)\n ) {\n (bool success, bytes memory data) =\n _to.staticcall(abi.encodeWithSelector(IVesting(_to).tokenOwner.selector));\n\n if (success) _to = abi.decode(data, (address));\n }\n\n return _internalTransferFrom(msg.sender, _to, _value, uint256(-1));\n }\n\n /**\n * @notice Moves `_value` loan tokens from `_from` to `_to` using the\n * allowance mechanism. Calls internal _internalTransferFrom function.\n *\n * @return A boolean value indicating whether the operation succeeded.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool) {\n return\n _internalTransferFrom(\n _from,\n _to,\n _value,\n //allowed[_from][msg.sender]\n ProtocolLike(sovrynContractAddress).isLoanPool(msg.sender)\n ? uint256(-1)\n : allowed[_from][msg.sender]\n );\n }\n\n /**\n * @notice Borrow funds from the pool.\n * The underlying loan token may not be used as collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * (150% of the withdrawn amount worth in collateral tokens).\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param borrower The one paying for the collateral.\n * @param receiver The one receiving the withdrawn amount.\n *\n * @return New principal and new collateral added to loan.\n * */\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes memory /// loanDataBytes: arbitrary order data (for future use).\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n )\n {\n require(withdrawAmount != 0, \"6\");\n\n _checkPause();\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n\n require(\n (msg.value == 0 || msg.value == collateralTokenSent) &&\n (collateralTokenSent != 0 || loanId != 0) &&\n (collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0) &&\n (loanId == 0 || msg.sender == borrower),\n \"7\"\n );\n\n /// @dev We have an issue regarding contract size code is too big. 1 of the solution is need to keep the error message 32 bytes length\n // Temporarily, we combine this require to the above, so can save the contract size code\n // require(collateralTokenSent != 0 || loanId != 0, \"8\");\n // require(collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0, \"9\");\n\n /// @dev Ensure authorized use of existing loan.\n // require(loanId == 0 || msg.sender == borrower, \"401 use of existing loan\");\n\n /// @dev The condition is never met.\n /// Address zero is not allowed by previous require validation.\n /// This check is unneeded and was lowering the test coverage index.\n // if (collateralTokenAddress == address(0)) {\n // \tcollateralTokenAddress = wrbtcTokenAddress;\n // }\n\n require(collateralTokenAddress != loanTokenAddress, \"10\");\n\n _settleInterest();\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this); /// The lender.\n sentAddresses.borrower = borrower;\n sentAddresses.receiver = receiver;\n /// sentAddresses.manager = address(0); /// The manager.\n\n sentAmounts.newPrincipal = withdrawAmount;\n\n /// interestRate, interestInitialAmount, borrowAmount (newBorrowAmount).\n (\n sentAmounts.interestRate,\n sentAmounts.interestInitialAmount,\n sentAmounts.newPrincipal\n ) = _getInterestRateAndBorrowAmount(\n sentAmounts.newPrincipal,\n _totalAssetSupply(0), /// Interest is settled above.\n initialLoanDuration\n );\n\n /// sentAmounts.loanTokenSent = 0; /// loanTokenSent\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n return\n _borrowOrTrade(\n loanId,\n withdrawAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ]\n ),\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Borrow and immediately get into a position.\n *\n * Trading on margin is used to increase an investor's buying power.\n * Margin is the amount of money required to open a position, while\n * leverage is the multiple of exposure to account equity.\n *\n * Leverage allows you to trade positions LARGER than the amount\n * of money in your trading account. Leverage is expressed as a ratio.\n *\n * When trading on margin, investors first deposit some token that then\n * serves as collateral for the loan, and then pay ongoing interest\n * payments on the money they borrow.\n *\n * Margin trading = taking a loan and swapping it:\n * In order to open a margin trade position,\n * 1.- The user calls marginTrade on the loan token contract.\n * 2.- The loan token contract provides the loan and sends it for processing\n * to the protocol proxy contract.\n * 3.- The protocol proxy contract uses the module LoanOpening to create a\n * position and swaps the loan tokens to collateral tokens.\n * 4.- The Sovryn Swap network looks up the correct converter and swaps the\n * tokens.\n * If successful, the position is being held by the protocol proxy contract,\n * which is why positions need to be closed at the protocol proxy contract.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n * */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // value of loan token in collateral\n bytes memory loanDataBytes /// Arbitrary order data.\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n _checkPause();\n\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n require(collateralTokenAddress != loanTokenAddress, \"11\");\n\n /// @dev Ensure authorized use of existing loan.\n require(loanId == 0 || msg.sender == trader, \"401 use of existing loan\");\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n if (transactionLimit[loanTokenAddress] > 0)\n require(loanTokenSent <= transactionLimit[loanTokenAddress]);\n\n /// @dev Compute the worth of the total deposit in loan tokens.\n /// (loanTokenSent + convert(collateralTokenSent))\n /// No actual swap happening here.\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n require(totalDeposit != 0, \"12\");\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this);\n sentAddresses.borrower = trader;\n sentAddresses.receiver = trader;\n /// sentAddresses.manager = address(0); /// The manager.\n\n /// sentAmounts.interestRate = 0; /// interestRate (found later).\n sentAmounts.newPrincipal = totalDeposit;\n /// sentAmounts.interestInitialAmount = 0; /// interestInitialAmount (interest is calculated based on fixed-term loan).\n sentAmounts.loanTokenSent = loanTokenSent;\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n _settleInterest();\n\n (sentAmounts.newPrincipal, sentAmounts.interestRate) = _getMarginBorrowAmountAndRate( /// borrowAmount, interestRate\n leverageAmount,\n sentAmounts.newPrincipal /// depositAmount\n );\n\n require(\n _getAmountInRbtc(loanTokenAddress, sentAmounts.newPrincipal) > TINY_AMOUNT,\n \"principal too small\"\n );\n\n /// @dev Converting to initialMargin\n leverageAmount = SafeMath.div(10**38, leverageAmount);\n sentAmounts.minEntryPrice = minEntryPrice;\n return\n _borrowOrTrade(\n loanId,\n 0, /// withdrawAmount\n leverageAmount, //initial margin\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n );\n }\n\n /**\n * @notice Wrapper for marginTrade invoking setAffiliatesReferrer to track\n * referral trade by affiliates program.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param affiliateReferrer The address of the referrer from affiliates program.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n */\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, /// Value of loan token in collateral\n address affiliateReferrer, /// The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n if (affiliateReferrer != address(0))\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(\n trader,\n affiliateReferrer\n );\n return\n marginTrade(\n loanId,\n leverageAmount,\n loanTokenSent,\n collateralTokenSent,\n collateralTokenAddress,\n trader,\n minEntryPrice,\n loanDataBytes\n );\n }\n\n /* Public View functions */\n\n /**\n * @notice Wrapper for internal _profitOf low level function.\n * @param user The user address.\n * @return The profit of a user.\n * */\n function profitOf(address user) external view returns (int256) {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(user, iToken_ProfitSoFar));\n //TODO + LM balance\n return _profitOf(slot, balances[user], tokenPrice(), checkpointPrices_[user]);\n }\n\n /**\n * @notice Getter for the price checkpoint mapping.\n * @param _user The user account as the mapping index.\n * @return The price on the checkpoint for this user.\n * */\n function checkpointPrice(address _user) public view returns (uint256 price) {\n return checkpointPrices_[_user];\n }\n\n /**\n * @notice Get current liquidity.\n * A part of total funds supplied are borrowed. Liquidity = supply - borrow\n * @return The market liquidity.\n * */\n function marketLiquidity() public view returns (uint256) {\n uint256 totalSupply = _totalAssetSupply(0);\n uint256 totalBorrow = totalAssetBorrow();\n if (totalSupply > totalBorrow) {\n return totalSupply - totalBorrow;\n }\n }\n\n /**\n * @notice Wrapper for average borrow interest.\n * @return The average borrow interest.\n * */\n function avgBorrowInterestRate() public view returns (uint256) {\n return _avgBorrowInterestRate(totalAssetBorrow());\n }\n\n /**\n * @notice Get borrow interest rate.\n * The minimum rate the next base protocol borrower will receive\n * for variable-rate loans.\n * @return The borrow interest rate.\n * */\n function borrowInterestRate() public view returns (uint256) {\n return _nextBorrowInterestRate(0);\n }\n\n /**\n * @notice Public wrapper for internal call.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest rate.\n * */\n function nextBorrowInterestRate(uint256 borrowAmount) public view returns (uint256) {\n return _nextBorrowInterestRate(borrowAmount);\n }\n\n /**\n * @notice Get interest rate.\n *\n * @return Interest that lenders are currently receiving when supplying to\n * the pool.\n * */\n function supplyInterestRate() public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0));\n }\n\n /**\n * @notice Get interest rate w/ added supply.\n * @param supplyAmount The amount of tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of tokens to the pool.\n * */\n function nextSupplyInterestRate(uint256 supplyAmount) public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0).add(supplyAmount));\n }\n\n /**\n * @notice Get interest rate w/ added supply assets.\n * @param assetSupply The amount of loan tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of loan tokens to the pool.\n * */\n function totalSupplyInterestRate(uint256 assetSupply) public view returns (uint256) {\n uint256 assetBorrow = totalAssetBorrow();\n if (assetBorrow != 0) {\n return calculateSupplyInterestRate(assetBorrow, assetSupply);\n }\n }\n\n /**\n * @notice Get the total amount of loan tokens on supply.\n * @dev Wrapper for internal _totalAssetSupply function.\n * @return The total amount of loan tokens on supply.\n * */\n function totalAssetSupply() public view returns (uint256) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _totalAssetSupply(interestUnPaid);\n }\n\n /**\n * @notice Compute the maximum deposit amount under current market conditions.\n * @dev maxEscrowAmount = liquidity * (100 - interestForDuration) / 100\n * @param leverageAmount The chosen multiplier with 18 decimals.\n * */\n function getMaxEscrowAmount(uint256 leverageAmount)\n public\n view\n returns (uint256 maxEscrowAmount)\n {\n /**\n * @dev Mathematical imperfection: depending on liquidity we might be able\n * to borrow more if utilization is below the kink level.\n * */\n uint256 interestForDuration = maxScaleRate.mul(28).div(365);\n uint256 factor = uint256(10**20).sub(interestForDuration);\n uint256 maxLoanSize = marketLiquidity().mul(factor).div(10**20);\n maxEscrowAmount = maxLoanSize.mul(10**18).div(leverageAmount);\n }\n\n /**\n * @notice Get loan token balance.\n * @return The user's balance of underlying token.\n * */\n function assetBalanceOf(address _owner) public view returns (uint256) {\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0)) {\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n _owner\n );\n }\n return balanceOf(_owner).add(balanceOnLM).mul(tokenPrice()).div(10**18);\n }\n\n /**\n * @notice Get margin information on a trade.\n *\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The principal, the collateral and the interestRate.\n * */\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n public\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n )\n {\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n\n (principal, interestRate) = _getMarginBorrowAmountAndRate(leverageAmount, totalDeposit);\n if (principal > _underlyingBalance()) {\n return (0, 0, 0);\n }\n\n loanTokenSent = loanTokenSent.add(principal);\n\n collateral = ProtocolLike(sovrynContractAddress).getEstimatedMarginExposure(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent,\n collateralTokenSent,\n interestRate,\n principal\n );\n }\n\n /**\n * @notice Calculate the deposit required to a given borrow.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param borrowAmount The amount of borrow.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of deposit required.\n * */\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 depositAmount) {\n if (borrowAmount != 0) {\n (, , uint256 newBorrowAmount) =\n _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (newBorrowAmount <= _underlyingBalance()) {\n if (collateralTokenAddress == address(0))\n collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ];\n return\n ProtocolLike(sovrynContractAddress)\n .getRequiredCollateral(\n loanTokenAddress,\n collateralTokenAddress,\n newBorrowAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin\n true /// isTorqueLoan\n )\n .add(10); /// Some dust to compensate for rounding errors.\n }\n }\n }\n\n /**\n * @notice Calculate the borrow allowed for a given deposit.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param depositAmount The amount of deposit.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of borrow allowed.\n * */\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 borrowAmount) {\n if (depositAmount != 0) {\n if (collateralTokenAddress == address(0)) collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))];\n borrowAmount = ProtocolLike(sovrynContractAddress).getBorrowAmount(\n loanTokenAddress,\n collateralTokenAddress,\n depositAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin,\n true /// isTorqueLoan\n );\n\n (, , borrowAmount) = _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (borrowAmount > _underlyingBalance()) {\n borrowAmount = 0;\n }\n }\n }\n\n /**\n * @notice Check if entry price lies above a minimum\n *\n * @param loanTokenSent The amount of deposit.\n * @param collateralTokenAddress The token address of collateral.\n * @param minEntryPrice Value of loan token in collateral\n * */\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) public view {\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokensReceived =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent\n );\n uint256 collateralTokenPrice =\n (collateralTokensReceived.mul(WEI_PRECISION)).div(loanTokenSent);\n require(collateralTokenPrice >= minEntryPrice, \"entry price above the minimum\");\n }\n\n /**\n * @notice Compute the next supply interest adjustment.\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next supply interest adjustment.\n * */\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n public\n view\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply >= assetBorrow) {\n return\n _avgBorrowInterestRate(assetBorrow)\n .mul(_utilizationRate(assetBorrow, assetSupply))\n .mul(\n SafeMath.sub(10**20, ProtocolLike(sovrynContractAddress).lendingFeePercent())\n )\n .div(10**40);\n }\n }\n\n /* Internal functions */\n\n /**\n * @notice Compute what the deposit is worth in loan tokens using the swap rate\n * used for loan size computation.\n *\n * @param collateralTokenAddress The token address of the collateral.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param loanTokenSent The number of loan tokens provided by the user.\n *\n * @return The value of the deposit in loan tokens.\n * */\n function _totalDeposit(\n address collateralTokenAddress,\n uint256 collateralTokenSent,\n uint256 loanTokenSent\n ) internal view returns (uint256 totalDeposit) {\n totalDeposit = loanTokenSent;\n\n if (collateralTokenSent != 0) {\n /// @dev Get the oracle rate from collateral -> loan\n (uint256 collateralToLoanRate, uint256 collateralToLoanPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n collateralTokenAddress,\n loanTokenAddress\n );\n require(\n (collateralToLoanRate != 0) && (collateralToLoanPrecision != 0),\n \"invalid rate collateral token\"\n );\n\n /// @dev Compute the loan token amount with the oracle rate.\n uint256 loanTokenAmount =\n collateralTokenSent.mul(collateralToLoanRate).div(collateralToLoanPrecision);\n\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokenAmount =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenAmount\n );\n\n /// @dev Probably not the same due to the price difference.\n if (collateralTokenAmount != collateralTokenSent) {\n //scale the loan token amount accordingly, so we'll get the expected position size in the end\n loanTokenAmount = loanTokenAmount.mul(collateralTokenAmount).div(\n collateralTokenSent\n );\n }\n\n totalDeposit = loanTokenAmount.add(totalDeposit);\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n asset,\n wrbtcTokenAddress\n );\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /*\n * @notice Compute interest rate and other loan parameters.\n *\n * @param borrowAmount The amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n *\n * @return The interest rate, the interest calculated based on fixed-term\n * loan, and the new borrow amount.\n * */\n function _getInterestRateAndBorrowAmount(\n uint256 borrowAmount,\n uint256 assetSupply,\n uint256 initialLoanDuration /// Duration in seconds.\n )\n internal\n view\n returns (\n uint256 interestRate,\n uint256 interestInitialAmount,\n uint256 newBorrowAmount\n )\n {\n interestRate = _nextBorrowInterestRate2(borrowAmount, assetSupply);\n\n /// newBorrowAmount = borrowAmount * 10^18 / (10^18 - interestRate * 7884000 * 10^18 / 31536000 / 10^20)\n newBorrowAmount = borrowAmount.mul(10**18).div(\n SafeMath.sub(\n 10**18,\n interestRate.mul(initialLoanDuration).mul(10**18).div(31536000 * 10**20) /// 365 * 86400 * 10**20\n )\n );\n\n interestInitialAmount = newBorrowAmount.sub(borrowAmount);\n }\n\n /**\n * @notice Compute principal and collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialMargin The initial margin with 18 decimals\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return The new principal and the new collateral. Principal is the\n * complete borrowed amount (in loan tokens). Collateral is the complete\n * position size (loan + margin) (in collateral tokens).\n * */\n function _borrowOrTrade(\n bytes32 loanId,\n uint256 withdrawAmount,\n uint256 initialMargin,\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n _checkPause();\n require(\n sentAmounts.newPrincipal <= _underlyingBalance() && /// newPrincipal (borrowed amount + fees)\n sentAddresses.borrower != address(0), /// The borrower.\n \"24\"\n );\n\n if (sentAddresses.receiver == address(0)) {\n sentAddresses.receiver = sentAddresses.borrower; /// The receiver = the borrower.\n }\n\n /// @dev Handle transfers prior to adding newPrincipal to loanTokenSent\n uint256 msgValue =\n _verifyTransfers(collateralTokenAddress, sentAddresses, sentAmounts, withdrawAmount);\n\n /**\n * @dev Adding the loan token portion from the lender to loanTokenSent\n * (add the loan to the loan tokens sent from the user).\n * */\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.add(sentAmounts.newPrincipal); /// newPrincipal\n\n if (withdrawAmount != 0) {\n /// @dev withdrawAmount already sent to the borrower, so we aren't sending it to the protocol.\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.sub(withdrawAmount);\n }\n\n bool withdrawAmountExist = false; /// Default is false, but added just as to make sure.\n\n if (withdrawAmount != 0) {\n withdrawAmountExist = true;\n }\n\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, withdrawAmountExist)))\n ];\n\n (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent) = ProtocolLike(\n sovrynContractAddress\n )\n .borrowOrTradeFromPool\n .value(msgValue)(\n loanParamsId,\n loanId,\n withdrawAmountExist,\n initialMargin,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n ); /// newPrincipal, newCollateral\n require(sentAmounts.newPrincipal != 0, \"25\");\n\n /// @dev Setting not-first-trade flag to prevent binding to an affiliate existing users post factum.\n /// @dev REFACTOR: move to a general interface: ProtocolSettingsLike?\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(\n sentAddresses.borrower\n );\n\n return (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent); // newPrincipal, newCollateral\n }\n\n /* Internal View functions */\n\n /**\n * @notice Compute the average borrow interest rate.\n * @param assetBorrow The amount of loan tokens on debt.\n * @return The average borrow interest rate.\n * */\n function _avgBorrowInterestRate(uint256 assetBorrow) internal view returns (uint256) {\n if (assetBorrow != 0) {\n (uint256 interestOwedPerDay, ) = _getAllInterest();\n return interestOwedPerDay.mul(10**20).mul(365).div(assetBorrow);\n }\n }\n\n /**\n * @notice Compute the next borrow interest adjustment.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate(uint256 borrowAmount) internal view returns (uint256) {\n uint256 interestUnPaid;\n if (borrowAmount != 0) {\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n uint256 balance = _underlyingBalance().add(interestUnPaid);\n if (borrowAmount > balance) {\n borrowAmount = balance;\n }\n }\n\n return _nextBorrowInterestRate2(borrowAmount, _totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Compute the next borrow interest adjustment under target-kink\n * level analysis.\n *\n * The \"kink\" in the cDAI interest rate model reflects the utilization rate\n * at which the slope of the interest rate goes from \"gradual\" to \"steep\".\n * That is, below this utilization rate, the slope of the interest rate\n * curve is gradual. Above this utilization rate, it is steep.\n *\n * Because of this dynamic between the interest rate curves before and\n * after the \"kink\", the \"kink\" can be thought of as the target utilization\n * rate. Above that rate, it quickly becomes expensive to borrow (and\n * commensurately lucrative for suppliers).\n *\n * @param newBorrowAmount The new amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate2(uint256 newBorrowAmount, uint256 assetSupply)\n internal\n view\n returns (uint256 nextRate)\n {\n uint256 utilRate = _utilizationRate(totalAssetBorrow().add(newBorrowAmount), assetSupply);\n\n uint256 thisMinRate;\n uint256 thisRateAtKink;\n uint256 thisBaseRate = baseRate;\n uint256 thisRateMultiplier = rateMultiplier;\n uint256 thisTargetLevel = targetLevel;\n uint256 thisKinkLevel = kinkLevel;\n uint256 thisMaxScaleRate = maxScaleRate;\n\n if (utilRate < thisTargetLevel) {\n // target targetLevel utilization when utilization is under targetLevel\n utilRate = thisTargetLevel;\n }\n\n if (utilRate > thisKinkLevel) {\n /// @dev Scale rate proportionally up to 100%\n uint256 thisMaxRange = WEI_PERCENT_PRECISION - thisKinkLevel; /// Will not overflow.\n\n utilRate -= thisKinkLevel;\n if (utilRate > thisMaxRange) utilRate = thisMaxRange;\n\n // Modified the rate calculation as it is slightly exaggerated around kink level\n // thisRateAtKink = thisRateMultiplier.add(thisBaseRate).mul(thisKinkLevel).div(WEI_PERCENT_PRECISION);\n thisRateAtKink = thisKinkLevel.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n nextRate = utilRate\n .mul(SafeMath.sub(thisMaxScaleRate, thisRateAtKink))\n .div(thisMaxRange)\n .add(thisRateAtKink);\n } else {\n nextRate = utilRate.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n thisMinRate = thisBaseRate;\n thisRateAtKink = thisRateMultiplier.add(thisBaseRate);\n\n if (nextRate < thisMinRate) nextRate = thisMinRate;\n else if (nextRate > thisRateAtKink) nextRate = thisRateAtKink;\n }\n }\n\n /**\n * @notice Compute the loan size and interest rate.\n * @param leverageAmount The leverage with 18 decimals.\n * @param depositAmount The amount the user deposited in underlying loan tokens.\n * @return borrowAmount The amount of tokens to borrow.\n * @return interestRate The interest rate to pay on the position.\n * */\n function _getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n internal\n view\n returns (uint256 borrowAmount, uint256 interestRate)\n {\n uint256 loanSizeBeforeInterest = depositAmount.mul(leverageAmount).div(10**18);\n /**\n * @dev Mathematical imperfection. we calculate the interest rate based on\n * the loanSizeBeforeInterest, but the actual borrowed amount will be bigger.\n * */\n interestRate = _nextBorrowInterestRate2(loanSizeBeforeInterest, _totalAssetSupply(0));\n /// @dev Assumes that loan, collateral, and interest token are the same.\n borrowAmount = _adjustLoanSize(interestRate, 28 days, loanSizeBeforeInterest);\n }\n\n /**\n * @notice Make sure call is not paused.\n * @dev Used for internal verification if the called function is paused.\n * It throws an exception in case it's not.\n * */\n function _checkPause() internal view {\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n msg.sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n bool isPaused;\n assembly {\n isPaused := sload(slot)\n }\n require(!isPaused, \"unauthorized\");\n }\n\n /**\n * @notice Adjusts the loan size to make sure the expected exposure remains after prepaying the interest.\n * @dev loanSizeWithInterest = loanSizeBeforeInterest * 100 / (100 - interestForDuration)\n * @param interestRate The interest rate to pay on the position.\n * @param maxDuration The maximum duration of the position (until rollover).\n * @param loanSizeBeforeInterest The loan size before interest is added.\n * */\n function _adjustLoanSize(\n uint256 interestRate,\n uint256 maxDuration,\n uint256 loanSizeBeforeInterest\n ) internal pure returns (uint256 loanSizeWithInterest) {\n uint256 interestForDuration = interestRate.mul(maxDuration).div(365 days);\n uint256 divisor = uint256(10**20).sub(interestForDuration);\n loanSizeWithInterest = loanSizeBeforeInterest.mul(10**20).div(divisor);\n }\n\n /**\n * @notice Calculate the utilization rate.\n * @dev Utilization rate = assetBorrow / assetSupply\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The utilization rate.\n * */\n function _utilizationRate(uint256 assetBorrow, uint256 assetSupply)\n internal\n pure\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply != 0) {\n /// U = total_borrow / total_supply\n return assetBorrow.mul(10**20).div(assetSupply);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./AdvancedToken.sol\";\n\ncontract LoanTokenLogicStorage is AdvancedToken {\n /// DO NOT ADD VARIABLES HERE - SEE BELOW\n\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /// @dev Add new variables here on the bottom.\n address public earlyAccessToken; //not used anymore, but staying for upgradability\n address public pauser;\n /** The address of the liquidity mining contract */\n address public liquidityMiningAddress;\n\n /** The address of the staking contract */\n address public stakingContractAddress;\n\n /// @dev Used by flashBorrow function.\n uint256 public constant VERSION = 6;\n /// @dev Used by flashBorrow function.\n address internal constant arbitraryCaller = 0x000F400e6818158D541C3EBE45FE3AA0d47372FF;\n bytes32 internal constant iToken_ProfitSoFar =\n 0x37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb6; // keccak256(\"iToken_ProfitSoFar\")\n uint256 public constant TINY_AMOUNT = 25e13;\n\n function stringToBytes32(string memory source) public pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"unauthorized\"); // SS02\n _;\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogic is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenMintAndBurn also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenLogicStandard also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\")); /// LoanTokenLogicStandard\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\")); /// LoanTokenLogicLM\n res[2] = bytes4(keccak256(\"burn(address,uint256)\")); /// LoanTokenLogicStandard\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\")); /// LoanTokenLogicLM\n\n return (res, stringToBytes32(\"LoanTokenLogicLM\"));\n }\n\n /**\n * @notice deposit into the lending pool and optionally participate at the Liquidity Mining Program\n * @param receiver the receiver of the tokens\n * @param depositAmount The amount of underlying tokens provided on the loan.\n *\t\t\t\t\t\t(Not the number of loan tokens to mint).\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 minted) {\n if (useLM) return _mintWithLM(receiver, depositAmount);\n else return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice withdraws from the lending pool and optionally retrieves the pool tokens from the\n * Liquidity Mining Contract\n * @param receiver the receiver of the underlying tokens. note: potetial LM rewards are always sent to the msg.sender\n * @param burnAmount The amount of pool tokens to redeem.\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 redeemed) {\n if (useLM) redeemed = _burnFromLM(burnAmount);\n else redeemed = _burnToken(burnAmount);\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (redeemed != 0) {\n _safeTransfer(loanTokenAddress, receiver, redeemed, \"asset transfer failed\");\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtc.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogicWrbtc is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtc\"));\n }\n\n /**\n * @dev internal override functions\n * @dev Put all of internal override function dedicated to the loanTokenWrtbc module here\n * e.g: _verifyTransfers will override the implementation of _verifyTransfers in loanTokenLogicSplit\n */\n\n /**\n * @notice Handle transfers prior to adding newPrincipal to loanTokenSent.\n *\n * @param collateralTokenAddress The address of the collateral token.\n * @param sentAddresses The struct which contains addresses of\n * - lender\n * - borrower\n * - receiver\n * - manager\n *\n * @param sentAmounts The struct which contains uint256 of:\n * - interestRate\n * - newPrincipal\n * - interestInitialAmount\n * - loanTokenSent\n * - collateralTokenSent\n *\n * @param withdrawalAmount The amount to withdraw.\n *\n * @return msgValue The amount of value sent.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = _wrbtcToken;\n address receiver = sentAddresses.receiver;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n IWrbtcERC20(_wrbtcToken).withdraw(withdrawalAmount);\n Address.sendValue(receiver, withdrawalAmount);\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n\n if (collateralTokenSent != 0) {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28\"\n );\n }\n\n if (loanTokenSent != 0) {\n if (msgValue != 0 && msgValue >= loanTokenSent) {\n IWrbtc(_wrbtcToken).deposit.value(loanTokenSent)();\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, loanTokenSent, \"29\");\n msgValue -= loanTokenSent;\n } else {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtcLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicWrbtcLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token Mint and Burn.\n res[0] = this.mint.selector;\n res[1] = this.burn.selector;\n\n // Loan Token WRBTC\n res[2] = this.mintWithBTC.selector;\n res[3] = this.burnToBTC.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtcLM\"));\n }\n\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n if (useLM) return _mintWithLM(receiver, msg.value);\n else return _mintToken(receiver, msg.value);\n }\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 loanAmountPaid) {\n loanAmountPaid = useLM ? _burnFromLM(burnAmount) : _burnToken(burnAmount);\n\n if (loanAmountPaid != 0) {\n IWrbtcERC20(wrbtcTokenAddress).withdraw(loanAmountPaid);\n Address.sendValue(receiver, loanAmountPaid);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/shared/LoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../AdvancedToken.sol\";\nimport \"../../interfaces/ProtocolSettingsLike.sol\";\nimport \"../../LoanTokenLogicStorage.sol\";\n\ncontract LoanTokenSettingsLowerAdmin is LoanTokenLogicStorage {\n using SafeMath for uint256;\n\n /// @dev TODO: Check for restrictions in this contract.\n modifier onlyAdmin() {\n require(isOwner() || msg.sender == admin, \"unauthorized\");\n _;\n }\n\n /* Events */\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](15);\n res[0] = this.setAdmin.selector;\n res[1] = this.setPauser.selector;\n res[2] = this.setupLoanParams.selector;\n res[3] = this.disableLoanParams.selector;\n res[4] = this.setDemandCurve.selector;\n res[5] = this.toggleFunctionPause.selector;\n res[6] = this.setTransactionLimits.selector;\n res[7] = this.changeLoanTokenNameAndSymbol.selector;\n res[8] = this.pauser.selector;\n res[9] = this.setLiquidityMiningAddress.selector;\n res[10] = this.withdrawRBTCTo.selector;\n res[11] = this.getLiquidityMiningAddress.selector;\n res[12] = this.checkPause.selector;\n res[13] = this.setStakingContractAddress.selector;\n res[14] = this.getStakingContractAddress.selector;\n return (res, stringToBytes32(\"LoanTokenSettingsLowerAdmin\"));\n }\n\n /**\n * @notice Set admin account.\n * @param _admin The address of the account to grant admin permissions.\n * */\n function setAdmin(address _admin) public onlyOwner {\n admin = _admin;\n }\n\n /**\n * @notice Set pauser account.\n * @param _pauser The address of the account to grant pause permissions.\n * */\n function setPauser(address _pauser) public onlyOwner {\n pauser = _pauser;\n }\n\n /**\n * @notice Fallback function not allowed\n * */\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n /**\n * @notice Set loan token parameters.\n *\n * @param loanParamsList The array of loan parameters.\n * @param areTorqueLoans Whether the loan is a torque loan.\n * */\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans /// isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n /**\n * @notice Disable loan token parameters.\n *\n * @param collateralTokens The array of collateral tokens.\n * @param isTorqueLoans Whether the loan is a torque loan.\n * */\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n /**\n * @notice Set loan token parameters about the demand curve.\n *\n * @dev These params should be percentages represented\n * like so: 5% = 5000000000000000000 /// 18 digits precision.\n * rateMultiplier + baseRate can't exceed 100%\n *\n * To maintain a healthy credit score, it's important to keep your\n * credit utilization rate (CUR) low (_lowUtilBaseRate). In general\n * you don't want your CUR to exceed 30%, but increasingly financial\n * experts are recommending that you don't want to go above 10% if you\n * really want an excellent credit score.\n *\n * Interest rates tend to cluster around the kink level of a kinked\n * interest rate model. More info at https://arxiv.org/pdf/2006.13922.pdf\n * and https://compound.finance/governance/proposals/12\n *\n * @param _baseRate The interest rate.\n * @param _rateMultiplier The precision multiplier for base rate.\n * @param _lowUtilBaseRate The credit utilization rate (CUR) low value.\n * @param _lowUtilRateMultiplier The precision multiplier for low util base rate.\n * @param _targetLevel The target level.\n * @param _kinkLevel The level that interest rates cluster on kinked model.\n * @param _maxScaleRate The maximum rate of the scale.\n * */\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; /// 80 ether\n kinkLevel = _kinkLevel; /// 90 ether\n maxScaleRate = _maxScaleRate; /// 100 ether\n }\n\n /**\n * @notice Set the pause flag for a function to true or false.\n *\n * @dev Combining the hash of \"iToken_FunctionPause\" string and a function\n * selector gets a slot to write a flag for pause state.\n *\n * @param funcId The ID of a function, the selector.\n * @param isPaused true/false value of the flag.\n * */\n function toggleFunctionPause(\n string memory funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyPauserOrOwner {\n bool paused;\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n paused := sload(slot)\n }\n require(paused != isPaused, \"isPaused is already set to that value\");\n assembly {\n sstore(slot, isPaused)\n }\n emit ToggledFunctionPaused(funcId, !isPaused, isPaused);\n }\n\n /**\n * Set the transaction limit per token address.\n * @param addresses The token addresses.\n * @param limits The limit denominated in the currency of the token address.\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyAdmin\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n\n /**\n *\t@notice Update the loan token parameters.\n *\t@param _name The new name of the loan token.\n *\t@param _symbol The new symbol of the loan token.\n * */\n function changeLoanTokenNameAndSymbol(string memory _name, string memory _symbol)\n public\n onlyAdmin\n {\n name = _name;\n symbol = _symbol;\n }\n\n /**\n * @notice Withdraws RBTC from the contract by Multisig.\n * @param _receiverAddress The address where the rBTC has to be transferred.\n * @param _amount The amount of rBTC to be transferred.\n */\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external onlyOwner {\n require(_receiverAddress != address(0), \"receiver address invalid\");\n require(_amount > 0, \"non-zero withdraw amount expected\");\n require(_amount <= address(this).balance, \"withdraw amount cannot exceed balance\");\n _receiverAddress.transfer(_amount);\n emit WithdrawRBTCTo(_receiverAddress, _amount);\n }\n\n /**\n * @notice sets the liquidity mining contract address\n * @param LMAddress the address of the liquidity mining contract\n */\n function setLiquidityMiningAddress(address LMAddress) external onlyOwner {\n liquidityMiningAddress = LMAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for liquidityMiningAddress\n\n\t * @return liquidityMiningAddress\n\t */\n function getLiquidityMiningAddress() public view returns (address) {\n return liquidityMiningAddress;\n }\n\n /**\n * @notice sets the staking contract address\n * @param _stakingContractAddress the address of the staking contract\n */\n function setStakingContractAddress(address _stakingContractAddress) external onlyOwner {\n stakingContractAddress = _stakingContractAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for stakingContractAddress\n\n\t * @return stakingContractAddress\n\t */\n function getStakingContractAddress() public view returns (address) {\n return stakingContractAddress;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param funcId The function ID, the selector.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function checkPause(string memory funcId) public view returns (bool isPaused) {\n bytes4 sig = bytes4(keccak256(abi.encodePacked(funcId)));\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n isPaused := sload(slot)\n }\n return isPaused;\n }\n}\n" + }, + "contracts/connectors/loantoken/Pausable.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Pausable contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * The contract implements pausable functionality by reading on slots the\n * pause state of contract functions.\n * */\ncontract Pausable {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 internal constant Pausable_FunctionPause =\n 0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047;\n\n modifier pausable(bytes4 sig) {\n require(!_isPaused(sig), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param sig The function ID, the selector on bytes4.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function _isPaused(bytes4 sig) internal view returns (bool isPaused) {\n bytes32 slot = keccak256(abi.encodePacked(sig, Pausable_FunctionPause));\n assembly {\n isPaused := sload(slot)\n }\n }\n}\n" + }, + "contracts/core/Objects.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./objects/LoanStruct.sol\";\nimport \"./objects/LoanParamsStruct.sol\";\nimport \"./objects/OrderStruct.sol\";\nimport \"./objects/LenderInterestStruct.sol\";\nimport \"./objects/LoanInterestStruct.sol\";\n\n/**\n * @title Objects contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract inherints and aggregates several structures needed to handle\n * loans on the protocol.\n * */\ncontract Objects is\n LoanStruct,\n LoanParamsStruct,\n OrderStruct,\n LenderInterestStruct,\n LoanInterestStruct\n{\n\n}\n" + }, + "contracts/core/objects/LenderInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Lender Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Lender Interest.\n * */\ncontract LenderInterestStruct {\n struct LenderInterest {\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\n uint256 paidTotal; /// Total interest paid so far for asset.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Interest.\n * */\ncontract LoanInterestStruct {\n struct LoanInterest {\n uint256 owedPerDay; /// Interest owed per day for loan.\n uint256 depositTotal; /// Total escrowed interest for loan.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanParamsStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Parameters.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Parameters.\n * */\ncontract LoanParamsStruct {\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n}\n" + }, + "contracts/core/objects/LoanStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Object.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Object.\n * */\ncontract LoanStruct {\n struct Loan {\n bytes32 id; /// ID of the loan.\n bytes32 loanParamsId; /// The linked loan params ID.\n bytes32 pendingTradesId; /// The linked pending trades ID.\n bool active; /// If false, the loan has been fully closed.\n uint256 principal; /// Total borrowed amount outstanding.\n uint256 collateral; /// Total collateral escrowed for the loan.\n uint256 startTimestamp; /// Loan start time.\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\n uint256 startMargin; /// Initial margin when the loan opened.\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\n address borrower; /// Borrower of this loan.\n address lender; /// Lender of this loan.\n }\n}\n" + }, + "contracts/core/objects/OrderStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Order.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Order.\n * */\ncontract OrderStruct {\n struct Order {\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\n uint256 interestRate; /// Interest rate defined by the creator of this order.\n uint256 minLoanTerm; /// Minimum loan term allowed.\n uint256 maxLoanTerm; /// Maximum loan term allowed.\n uint256 createdTimestamp; /// Timestamp when this order was created.\n uint256 expirationTimestamp; /// Timestamp when this order expires.\n }\n}\n" + }, + "contracts/core/Protocol.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./State.sol\";\n\n/**\n * @title Sovryn Protocol contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the proxy functionality to deploy Protocol anchor\n * and logic apart, turning it upgradable.\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822\n * */\ncontract sovrynProtocol is State {\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = logicTargets[msg.sig];\n require(target != address(0), \"target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice External owner target initializer.\n * @param target The target addresses.\n * */\n function replaceContract(address target) external onlyOwner {\n (bool success, ) =\n target.delegatecall(abi.encodeWithSignature(\"initialize(address)\", target));\n require(success, \"setup failed\");\n }\n\n /**\n * @notice External owner setter for target addresses.\n * @param sigsArr The array of signatures.\n * @param targetsArr The array of addresses.\n * */\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr)\n external\n onlyOwner\n {\n require(sigsArr.length == targetsArr.length, \"count mismatch\");\n\n for (uint256 i = 0; i < sigsArr.length; i++) {\n _setTarget(bytes4(keccak256(abi.encodePacked(sigsArr[i]))), targetsArr[i]);\n }\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(string calldata sig) external view returns (address) {\n return logicTargets[bytes4(keccak256(abi.encodePacked(sig)))];\n }\n}\n" + }, + "contracts/core/State.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./Objects.sol\";\nimport \"../mixins/EnumerableAddressSet.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/ReentrancyGuard.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title State contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage values of the Protocol.\n * */\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\n using SafeMath for uint256;\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n\n /// Handles asset reference price lookups.\n address public priceFeeds;\n\n /// Handles asset swaps using dex liquidity.\n address public swapsImpl;\n\n /// Contract registry address of the Sovryn swap network.\n address public sovrynSwapContractRegistryAddress;\n\n /// Implementations of protocol functions.\n mapping(bytes4 => address) public logicTargets;\n\n /// Loans: loanId => Loan\n mapping(bytes32 => Loan) public loans;\n\n /// Loan parameters: loanParamsId => LoanParams\n mapping(bytes32 => LoanParams) public loanParams;\n\n /// lender => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\n\n /// borrower => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\n\n /// loanId => delegated => approved\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\n\n /**\n *** Interest ***\n **/\n\n /// lender => loanToken => LenderInterest object\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\n\n /// loanId => LoanInterest object\n mapping(bytes32 => LoanInterest) public loanInterest;\n\n /**\n *** Internals ***\n **/\n\n /// Implementations set.\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\n\n /// Active loans set.\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\n\n /// Lender loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\n\n /// Borrow loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\n\n /// User loan params set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\n\n /// Address controlling fee withdrawals.\n address public feesController;\n\n /// 10% fee /// Fee taken from lender interest payments.\n uint256 public lendingFeePercent = 10**19;\n\n /// Total interest fees received and not withdrawn per asset.\n mapping(address => uint256) public lendingFeeTokensHeld;\n\n /// Total interest fees withdraw per asset.\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\n mapping(address => uint256) public lendingFeeTokensPaid;\n\n /// 0.15% fee /// Fee paid for each trade.\n uint256 public tradingFeePercent = 15 * 10**16;\n\n /// Total trading fees received and not withdrawn per asset.\n mapping(address => uint256) public tradingFeeTokensHeld;\n\n /// Total trading fees withdraw per asset\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\n mapping(address => uint256) public tradingFeeTokensPaid;\n\n /// 0.09% fee /// Origination fee paid for each loan.\n uint256 public borrowingFeePercent = 9 * 10**16;\n\n /// Total borrowing fees received and not withdrawn per asset.\n mapping(address => uint256) public borrowingFeeTokensHeld;\n\n /// Total borrowing fees withdraw per asset.\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\n mapping(address => uint256) public borrowingFeeTokensPaid;\n\n /// Current protocol token deposit balance.\n uint256 public protocolTokenHeld;\n\n /// Lifetime total payout of protocol token.\n uint256 public protocolTokenPaid;\n\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\n uint256 public affiliateFeePercent = 5 * 10**18;\n\n /// 5% collateral discount /// Discount on collateral for liquidators.\n uint256 public liquidationIncentivePercent = 5 * 10**18;\n\n /// loanPool => underlying\n mapping(address => address) public loanPoolToUnderlying;\n\n /// underlying => loanPool\n mapping(address => address) public underlyingToLoanPool;\n\n /// Loan pools set.\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\n\n /// Supported tokens for swaps.\n mapping(address => bool) public supportedTokens;\n\n /// % disagreement between swap rate and reference rate.\n uint256 public maxDisagreement = 5 * 10**18;\n\n /// Used as buffer for swap source amount estimations.\n uint256 public sourceBuffer = 10000;\n\n /// Maximum support swap size in rBTC\n uint256 public maxSwapSize = 50 ether;\n\n /// Nonce per borrower. Used for loan id creation.\n mapping(address => uint256) public borrowerNonce;\n\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\n uint256 public rolloverBaseReward = 16800000000000;\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\n\n IWrbtcERC20 public wrbtcToken;\n address public protocolTokenAddress;\n\n /// 50% fee rebate\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\n uint256 public feeRebatePercent = 50 * 10**18;\n\n address public admin;\n\n /// For modules interaction.\n address public protocolAddress;\n\n /**\n *** Affiliates ***\n **/\n\n /// The flag is set on the user's first trade.\n mapping(address => bool) public userNotFirstTradeFlag;\n\n /// User => referrer (affiliate).\n mapping(address => address) public affiliatesUserReferrer;\n\n /// List of referral addresses affiliated to the referrer.\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\n\n /// @dev Referral threshold for paying out to the referrer.\n /// The referrer reward is being accumulated and locked until the threshold is passed.\n uint256 public minReferralsToPayout = 3;\n\n /// @dev Total affiliate SOV rewards that held in the protocol\n /// (Because the minimum referrals is less than the rule)\n mapping(address => uint256) public affiliateRewardsHeld;\n\n /// @dev For affiliates SOV Bonus proccess.\n address public sovTokenAddress;\n address public lockedSOVAddress;\n\n /// @dev 20% fee share of trading token fee.\n /// Fee share of trading token fee for affiliate program.\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\n\n /// @dev Addresses of tokens in which commissions were paid to referrers.\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\n\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\n\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\n bool public pause; //Flag to pause all protocol modules\n\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\n\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\n uint256 internal tradingRebateRewardsBasisPoint;\n\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\n /// Will be used in internal swap.\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\n\n address internal pauser;\n\n /**\n * @notice Add signature and target to storage.\n * @dev Protocol is a proxy and requires a way to add every\n * module function dynamically during deployment.\n * */\n function _setTarget(bytes4 sig, address target) internal {\n logicTargets[sig] = target;\n\n if (target != address(0)) {\n logicTargetsSet.addBytes32(bytes32(sig));\n } else {\n logicTargetsSet.removeBytes32(bytes32(sig));\n }\n }\n\n modifier onlyAdminOrOwner() {\n require(isOwner() || admin == (msg.sender), \"unauthorized\");\n _;\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || pauser == (msg.sender), \"unauthorized\");\n _;\n }\n}\n" + }, + "contracts/escrow/Escrow.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Ethereum Pool to accept SOV Token.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice You can use this contract for deposit of SOV tokens for some time and withdraw later.\n */\ncontract Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalDeposit;\n /// @notice The release timestamp for the tokens deposited.\n uint256 public releaseTime;\n /// @notice The amount of token we would be accepting as deposit at max.\n uint256 public depositLimit;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The multisig contract which handles the fund.\n address public multisig;\n\n /// @notice The user balances.\n mapping(address => uint256) userBalances;\n\n /// @notice The current contract status.\n /// @notice Deployed - Deployed the contract.\n /// @notice Deposit - Time to deposit in the contract by the users.\n /// @notice Holding - Deposit is closed and now the holding period starts.\n /// @notice Withdraw - Time to withdraw in the contract by the users.\n /// @notice Expired - The contract is now closed completely.\n enum Status { Deployed, Deposit, Holding, Withdraw, Expired }\n Status public status;\n\n /* Events */\n\n /// @notice Emitted when the contract deposit starts.\n event EscrowActivated();\n\n /// @notice Emitted when the contract is put in holding state. No new token deposit accepted by User.\n event EscrowInHoldingState();\n\n /// @notice Emitted when the contract is put in withdraw state. Users can now withdraw tokens.\n event EscrowInWithdrawState();\n\n /// @notice Emitted when the contract is expired after withdraws are made/total token transfer.\n event EscrowFundExpired();\n\n /// @notice Emitted when a new multisig is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newMultisig The address which is added as the new multisig.\n /// @dev Can only be initiated by the current multisig.\n event NewMultisig(address indexed _initiator, address indexed _newMultisig);\n\n /// @notice Emitted when the release timestamp is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseTimestamp The updated release timestamp for the withdraw.\n event TokenReleaseUpdated(address indexed _initiator, uint256 _releaseTimestamp);\n\n /// @notice Emitted when the deposit limit is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _depositLimit The updated deposit limit.\n event TokenDepositLimitUpdated(address indexed _initiator, uint256 _depositLimit);\n\n /// @notice Emitted when a new token deposit is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when we reach the token deposit limit.\n event DepositLimitReached();\n\n /// @notice Emitted when a token withdraw is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdrawByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyMultisig() {\n require(msg.sender == multisig, \"Only Multisig can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n modifier checkRelease() {\n require(\n releaseTime != 0 && releaseTime <= block.timestamp,\n \"The release time has not started yet.\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_multisig != address(0), \"Invalid Multisig Address.\");\n\n SOV = IERC20(_SOV);\n multisig = _multisig;\n\n emit NewMultisig(msg.sender, _multisig);\n\n releaseTime = _releaseTime;\n depositLimit = _depositLimit;\n\n status = Status.Deployed;\n }\n\n /**\n * @notice This function is called once after deployment for starting the deposit action.\n * @dev Without calling this function, the contract will not start accepting tokens.\n */\n function init() external onlyMultisig checkStatus(Status.Deployed) {\n status = Status.Deposit;\n\n emit EscrowActivated();\n }\n\n /**\n * @notice Update Multisig.\n * @param _newMultisig The new owner of the tokens & contract.\n */\n function updateMultisig(address _newMultisig) external onlyMultisig {\n require(_newMultisig != address(0), \"New Multisig address invalid.\");\n\n multisig = _newMultisig;\n\n emit NewMultisig(msg.sender, _newMultisig);\n }\n\n /**\n * @notice Update Release Timestamp.\n * @param _newReleaseTime The new release timestamp for token release.\n * @dev Zero is also a valid timestamp, if the release time is not scheduled yet.\n */\n function updateReleaseTimestamp(uint256 _newReleaseTime) external onlyMultisig {\n releaseTime = _newReleaseTime;\n\n emit TokenReleaseUpdated(msg.sender, _newReleaseTime);\n }\n\n /**\n * @notice Update Deposit Limit.\n * @param _newDepositLimit The new deposit limit.\n * @dev IMPORTANT: Should not decrease than already deposited.\n */\n function updateDepositLimit(uint256 _newDepositLimit) external onlyMultisig {\n require(\n _newDepositLimit >= totalDeposit,\n \"Deposit already higher than the limit trying to be set.\"\n );\n depositLimit = _newDepositLimit;\n\n emit TokenDepositLimitUpdated(msg.sender, _newDepositLimit);\n }\n\n /**\n * @notice Deposit tokens to this contract by User.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the user inorder for this function to work.\n * These tokens can be withdrawn/transferred during Holding State by the Multisig.\n */\n function depositTokens(uint256 _amount) external checkStatus(Status.Deposit) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n uint256 amount = _amount;\n\n if (totalDeposit.add(_amount) >= depositLimit) {\n amount = depositLimit.sub(totalDeposit);\n emit DepositLimitReached();\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n userBalances[msg.sender] = userBalances[msg.sender].add(amount);\n totalDeposit = totalDeposit.add(amount);\n\n emit TokenDeposit(msg.sender, amount);\n }\n\n /**\n * @notice Update contract state to Holding.\n * @dev Once called, the contract no longer accepts any more deposits.\n * The multisig can now withdraw tokens from the contract after the contract is in Holding State.\n */\n function changeStateToHolding() external onlyMultisig checkStatus(Status.Deposit) {\n status = Status.Holding;\n\n emit EscrowInHoldingState();\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred. Zero address if the withdraw is to be done in Multisig.\n * @dev Can only be called after the token state is changed to Holding.\n */\n function withdrawTokensByMultisig(address _receiverAddress)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n address receiverAddress = msg.sender;\n if (_receiverAddress != address(0)) {\n receiverAddress = _receiverAddress;\n }\n\n uint256 value = SOV.balanceOf(address(this));\n /// Sending the amount to multisig.\n bool txStatus = SOV.transfer(receiverAddress, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdrawByMultisig(msg.sender, value);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n * Once the token deposit is higher than the total deposits done, the contract state is changed to Withdraw.\n */\n function depositTokensByMultisig(uint256 _amount)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDepositByMultisig(msg.sender, _amount);\n\n if (SOV.balanceOf(address(this)) >= totalDeposit) {\n status = Status.Withdraw;\n emit EscrowInWithdrawState();\n }\n }\n\n /**\n * @notice Withdraws token from the contract by User.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokens() public checkRelease checkStatus(Status.Withdraw) {\n uint256 amount = userBalances[msg.sender];\n userBalances[msg.sender] = 0;\n bool txStatus = SOV.transfer(msg.sender, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdraw(msg.sender, amount);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token balance of a particular user.\n * @return _addr The user address whose balance has to be checked.\n */\n function getUserBalance(address _addr) external view returns (uint256 balance) {\n return userBalances[_addr];\n }\n}\n" + }, + "contracts/escrow/EscrowReward.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Escrow.sol\";\nimport \"../locked/ILockedSOV.sol\";\n\n/**\n * @title A reward distribution contract for Sovryn Ethereum Pool Escrow Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice Multisig can use this contract for depositing of Reward tokens based on the total token deposit.\n */\ncontract EscrowReward is Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total reward tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalRewardDeposit;\n\n /// @notice The Locked SOV contract.\n ILockedSOV public lockedSOV;\n\n /* Events */\n\n /// @notice Emitted when the Locked SOV Contract address is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _lockedSOV The address of the Locked SOV Contract.\n event LockedSOVUpdated(address indexed _initiator, address indexed _lockedSOV);\n\n /// @notice Emitted when a new reward token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event RewardDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a Reward token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event RewardTokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _lockedSOV The Locked SOV Contract address.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _lockedSOV,\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public Escrow(_SOV, _multisig, _releaseTime, _depositLimit) {\n if (_lockedSOV != address(0)) {\n lockedSOV = ILockedSOV(_lockedSOV);\n }\n }\n\n /**\n * @notice Set the Locked SOV Contract Address if not already done.\n * @param _lockedSOV The Locked SOV Contract address.\n */\n function updateLockedSOV(address _lockedSOV) external onlyMultisig {\n require(_lockedSOV != address(0), \"Invalid Reward Token Address.\");\n\n lockedSOV = ILockedSOV(_lockedSOV);\n\n emit LockedSOVUpdated(msg.sender, _lockedSOV);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n */\n function depositRewardByMultisig(uint256 _amount) external onlyMultisig {\n require(\n status != Status.Withdraw,\n \"Reward Token deposit is only allowed before User Withdraw starts.\"\n );\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n totalRewardDeposit = totalRewardDeposit.add(_amount);\n txStatus = SOV.approve(address(lockedSOV), totalRewardDeposit);\n require(txStatus, \"Token Approval was not successful.\");\n\n emit RewardDepositByMultisig(msg.sender, _amount);\n }\n\n /**\n * @notice Withdraws token and reward from the contract by User. Reward is gone to lockedSOV contract for future vesting.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokensAndReward() external checkRelease checkStatus(Status.Withdraw) {\n // Reward calculation have to be done initially as the User Balance is zeroed out .\n uint256 reward = userBalances[msg.sender].mul(totalRewardDeposit).div(totalDeposit);\n withdrawTokens();\n\n lockedSOV.depositSOV(msg.sender, reward);\n\n emit RewardTokenWithdraw(msg.sender, reward);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the reward a particular user can get.\n * @param _addr The address of the user whose reward is to be read.\n * @return reward The reward received by the user.\n */\n function getReward(address _addr) external view returns (uint256 reward) {\n if (userBalances[_addr].mul(totalRewardDeposit) == 0) {\n return 0;\n }\n return userBalances[_addr].mul(totalRewardDeposit).div(totalDeposit);\n }\n}\n" + }, + "contracts/events/AffiliatesEvents.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\ncontract AffiliatesEvents is ModulesCommonEvents {\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\n\n event SetAffiliatesReferrerFail(\n address indexed user,\n address indexed referrer,\n bool alreadySet,\n bool userNotFirstTrade\n );\n\n event SetUserNotFirstTradeFlag(address indexed user);\n\n event PayTradingFeeToAffiliate(\n address indexed referrer,\n address trader,\n address indexed token,\n bool indexed isHeld,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountPaid\n );\n\n event PayTradingFeeToAffiliateFail(\n address indexed referrer,\n address trader,\n address indexed token,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountTryingToPaid\n );\n\n event WithdrawAffiliatesReferrerTokenFees(\n address indexed referrer,\n address indexed receiver,\n address indexed tokenAddress,\n uint256 amount\n );\n}\n" + }, + "contracts/events/FeesEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Fees Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for fee payments.\n * */\ncontract FeesEvents {\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\n\n event PayTradingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event PayBorrowingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event EarnReward(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n\n event EarnRewardFail(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n}\n" + }, + "contracts/events/LoanClosingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Closing Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan closing operations.\n * */\ncontract LoanClosingsEvents is ModulesCommonEvents {\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\n event CloseWithDeposit(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address closer,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\n event CloseWithSwap(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n address closer,\n uint256 positionCloseSize,\n uint256 loanCloseAmount,\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\n uint256 currentLeverage\n );\n\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\n event Liquidate(\n address indexed user,\n address indexed liquidator,\n bytes32 indexed loanId,\n address lender,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n event Rollover(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n uint256 principal,\n uint256 collateral,\n uint256 endTimestamp,\n address rewardReceiver,\n uint256 reward\n );\n\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\n}\n" + }, + "contracts/events/LoanMaintenanceEvents.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Maintenance Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan maintenance operations.\n * */\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\n}\n" + }, + "contracts/events/LoanOpeningsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Openings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan openings operations.\n * */\ncontract LoanOpeningsEvents is ModulesCommonEvents {\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\n event Borrow(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 newCollateral,\n uint256 interestRate,\n uint256 interestDuration,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\n event Trade(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n uint256 positionSize,\n uint256 borrowedAmount,\n uint256 interestRate,\n uint256 settlementDate,\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\n uint256 entryLeverage,\n uint256 currentLeverage\n );\n\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\n event DelegatedManagerSet(\n bytes32 indexed loanId,\n address indexed delegator,\n address indexed delegated,\n bool isActive\n );\n}\n" + }, + "contracts/events/LoanSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan settings operations.\n * */\ncontract LoanSettingsEvents is ModulesCommonEvents {\n event LoanParamsSetup(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\n\n event LoanParamsDisabled(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\n}\n" + }, + "contracts/events/ModulesCommonEvents.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title The common events for all modules\n * @notice This contract contains the events which will be used by all modules\n **/\n\ncontract ModulesCommonEvents {\n event ProtocolModuleContractReplaced(\n address indexed prevModuleContractAddress,\n address indexed newModuleContractAddress,\n bytes32 indexed module\n );\n}\n" + }, + "contracts/events/ProtocolSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title The Protocol Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for protocol settings operations.\n * */\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\n\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\n\n event SetLoanPool(\n address indexed sender,\n address indexed loanPool,\n address indexed underlying\n );\n\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\n\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateTradingTokenFeePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetLiquidationIncentivePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetFeesController(\n address indexed sender,\n address indexed oldController,\n address indexed newController\n );\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWethToken,\n address indexed newWethToken\n );\n\n event SetSovrynSwapContractRegistryAddress(\n address indexed sender,\n address indexed oldSovrynSwapContractRegistryAddress,\n address indexed newSovrynSwapContractRegistryAddress\n );\n\n event SetProtocolTokenAddress(\n address indexed sender,\n address indexed oldProtocolToken,\n address indexed newProtocolToken\n );\n\n event WithdrawFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 lendingAmount,\n uint256 tradingAmount,\n uint256 borrowingAmount,\n uint256 wRBTCConverted\n );\n\n event WithdrawLendingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawTradingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawBorrowingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetRebatePercent(\n address indexed sender,\n uint256 oldRebatePercent,\n uint256 newRebatePercent\n );\n\n event SetSpecialRebates(\n address indexed sender,\n address indexed sourceToken,\n address indexed destToken,\n uint256 oldSpecialRebatesPercent,\n uint256 newSpecialRebatesPercent\n );\n\n event SetProtocolAddress(\n address indexed sender,\n address indexed oldProtocol,\n address indexed newProtocol\n );\n\n event SetMinReferralsToPayoutAffiliates(\n address indexed sender,\n uint256 oldMinReferrals,\n uint256 newMinReferrals\n );\n\n event SetSOVTokenAddress(\n address indexed sender,\n address indexed oldTokenAddress,\n address indexed newTokenAddress\n );\n\n event SetLockedSOVAddress(\n address indexed sender,\n address indexed oldAddress,\n address indexed newAddress\n );\n\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\n\n event SetTradingRebateRewardsBasisPoint(\n address indexed sender,\n uint256 oldBasisPoint,\n uint256 newBasisPoint\n );\n\n event SetRolloverFlexFeePercent(\n address indexed sender,\n uint256 oldRolloverFlexFeePercent,\n uint256 newRolloverFlexFeePercent\n );\n\n event SetDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event RemoveDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n}\n" + }, + "contracts/events/SwapsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Swaps Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for swap operations.\n * */\ncontract SwapsEvents is ModulesCommonEvents {\n event LoanSwap(\n bytes32 indexed loanId,\n address indexed sourceToken,\n address indexed destToken,\n address borrower,\n uint256 sourceAmount,\n uint256 destAmount\n );\n\n event ExternalSwap(\n address indexed user,\n address indexed sourceToken,\n address indexed destToken,\n uint256 sourceAmount,\n uint256 destAmount\n );\n}\n" + }, + "contracts/farm/ILiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\n\ninterface ILiquidityMining {\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external;\n\n function onTokensDeposited(address _user, uint256 _amount) external;\n\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/farm/LiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./LiquidityMiningStorage.sol\";\nimport \"./ILiquidityMining.sol\";\n\ncontract LiquidityMining is ILiquidityMining, LiquidityMiningStorage {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n /* Constants */\n\n uint256 public constant PRECISION = 1e12;\n // Bonus multiplier for early liquidity providers.\n // During bonus period each passed block will be calculated like N passed blocks, where N = BONUS_MULTIPLIER\n uint256 public constant BONUS_BLOCK_MULTIPLIER = 10;\n\n uint256 public constant SECONDS_PER_BLOCK = 30;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event PoolTokenAdded(address indexed user, address indexed poolToken, uint256 allocationPoint);\n event PoolTokenUpdated(\n address indexed user,\n address indexed poolToken,\n uint256 newAllocationPoint,\n uint256 oldAllocationPoint\n );\n event Deposit(address indexed user, address indexed poolToken, uint256 amount);\n event RewardClaimed(address indexed user, address indexed poolToken, uint256 amount);\n event Withdraw(address indexed user, address indexed poolToken, uint256 amount);\n event EmergencyWithdraw(\n address indexed user,\n address indexed poolToken,\n uint256 amount,\n uint256 accumulatedReward\n );\n\n /* Functions */\n\n /**\n * @notice Initialize mining.\n *\n * @param _SOV The SOV token.\n * @param _rewardTokensPerBlock The number of reward tokens per block.\n * @param _startDelayBlocks The number of blocks should be passed to start\n * mining.\n * @param _numberOfBonusBlocks The number of blocks when each block will\n * be calculated as N blocks (BONUS_BLOCK_MULTIPLIER).\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n * SOV rewards are not paid directly to liquidity providers. Instead they\n * are deposited into a lockedSOV vault contract.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n */\n function initialize(\n IERC20 _SOV,\n uint256 _rewardTokensPerBlock,\n uint256 _startDelayBlocks,\n uint256 _numberOfBonusBlocks,\n address _wrapper,\n ILockedSOV _lockedSOV,\n uint256 _unlockedImmediatelyPercent\n ) external onlyAuthorized {\n /// @dev Non-idempotent function. Must be called just once.\n require(address(SOV) == address(0), \"Already initialized\");\n require(address(_SOV) != address(0), \"Invalid token address\");\n require(_startDelayBlocks > 0, \"Invalid start block\");\n require(\n _unlockedImmediatelyPercent < 10000,\n \"Unlocked immediately percent has to be less than 10000.\"\n );\n\n SOV = _SOV;\n rewardTokensPerBlock = _rewardTokensPerBlock;\n startBlock = block.number + _startDelayBlocks;\n bonusEndBlock = startBlock + _numberOfBonusBlocks;\n wrapper = _wrapper;\n lockedSOV = _lockedSOV;\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets lockedSOV contract.\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n */\n function setLockedSOV(ILockedSOV _lockedSOV) external onlyAuthorized {\n require(address(_lockedSOV) != address(0), \"Invalid lockedSOV Address.\");\n lockedSOV = _lockedSOV;\n }\n\n /**\n * @notice Sets unlocked immediately percent.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setUnlockedImmediatelyPercent(uint256 _unlockedImmediatelyPercent)\n external\n onlyAuthorized\n {\n require(\n _unlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets unlocked immediately percent overwrite for specific pool token.\n * @param _poolToken the address of pool token\n * @param _poolTokenUnlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setPoolTokenUnlockedImmediatelyPercent(\n address _poolToken,\n uint256 _poolTokenUnlockedImmediatelyPercent\n ) external onlyAuthorized {\n require(\n _poolTokenUnlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n poolTokensUnlockedImmediatelyPercent[_poolToken] = _poolTokenUnlockedImmediatelyPercent;\n }\n\n /**\n * @notice sets wrapper proxy contract\n * @dev can be set to zero address to remove wrapper\n */\n function setWrapper(address _wrapper) external onlyAuthorized {\n wrapper = _wrapper;\n }\n\n /**\n * @notice stops mining by setting end block\n */\n function stopMining() external onlyAuthorized {\n require(endBlock == 0, \"Already stopped\");\n\n endBlock = block.number;\n }\n\n /**\n * @notice Transfers SOV tokens to given address.\n * Owner use this function to withdraw SOV from LM contract\n * into another account.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) external onlyAuthorized {\n require(_receiver != address(0), \"Receiver address invalid\");\n require(_amount != 0, \"Amount invalid\");\n\n /// @dev Do not transfer more SOV than available.\n uint256 SOVBal = SOV.balanceOf(address(this));\n if (_amount > SOVBal) {\n _amount = SOVBal;\n }\n\n /// @dev The actual transfer.\n require(SOV.transfer(_receiver, _amount), \"Transfer failed\");\n\n /// @dev Event log.\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Get the missed SOV balance of LM contract.\n *\n * @return The amount of SOV tokens according to totalUsersBalance\n * in excess of actual SOV balance of the LM contract.\n * */\n function getMissedBalance() external view returns (uint256) {\n uint256 balance = SOV.balanceOf(address(this));\n return balance >= totalUsersBalance ? 0 : totalUsersBalance.sub(balance);\n }\n\n /**\n * @notice adds a new lp to the pool. Can only be called by the owner or an admin\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _withUpdate the flag whether we need to update all pools\n */\n function add(\n address _poolToken,\n uint96 _allocationPoint,\n bool _withUpdate\n ) external onlyAuthorized {\n require(_allocationPoint > 0, \"Invalid allocation point\");\n require(_poolToken != address(0), \"Invalid token address\");\n require(poolIdList[_poolToken] == 0, \"Token already added\");\n\n if (_withUpdate) {\n updateAllPools();\n }\n\n uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;\n totalAllocationPoint = totalAllocationPoint.add(_allocationPoint);\n\n poolInfoList.push(\n PoolInfo({\n poolToken: IERC20(_poolToken),\n allocationPoint: _allocationPoint,\n lastRewardBlock: lastRewardBlock,\n accumulatedRewardPerShare: 0\n })\n );\n //indexing starts from 1 in order to check whether token was already added\n poolIdList[_poolToken] = poolInfoList.length;\n\n emit PoolTokenAdded(msg.sender, _poolToken, _allocationPoint);\n }\n\n /**\n * @notice updates the given pool's reward tokens allocation point\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function update(\n address _poolToken,\n uint96 _allocationPoint,\n bool _updateAllFlag\n ) external onlyAuthorized {\n if (_updateAllFlag) {\n updateAllPools();\n } else {\n updatePool(_poolToken);\n }\n _updateToken(_poolToken, _allocationPoint);\n }\n\n function _updateToken(address _poolToken, uint96 _allocationPoint) internal {\n uint256 poolId = _getPoolId(_poolToken);\n\n uint256 previousAllocationPoint = poolInfoList[poolId].allocationPoint;\n totalAllocationPoint = totalAllocationPoint.sub(previousAllocationPoint).add(\n _allocationPoint\n );\n poolInfoList[poolId].allocationPoint = _allocationPoint;\n\n emit PoolTokenUpdated(msg.sender, _poolToken, _allocationPoint, previousAllocationPoint);\n }\n\n /**\n * @notice updates the given pools' reward tokens allocation points\n * @param _poolTokens array of addresses of pool tokens\n * @param _allocationPoints array of allocation points (weight) for the given pools\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function updateTokens(\n address[] calldata _poolTokens,\n uint96[] calldata _allocationPoints,\n bool _updateAllFlag\n ) external onlyAuthorized {\n require(_poolTokens.length == _allocationPoints.length, \"Arrays mismatch\");\n\n if (_updateAllFlag) {\n updateAllPools();\n }\n uint256 length = _poolTokens.length;\n for (uint256 i = 0; i < length; i++) {\n if (!_updateAllFlag) {\n updatePool(_poolTokens[i]);\n }\n _updateToken(_poolTokens[i], _allocationPoints[i]);\n }\n }\n\n /**\n * @notice returns reward multiplier over the given _from to _to block\n * @param _from the first block for a calculation\n * @param _to the last block for a calculation\n */\n function _getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n internal\n view\n returns (uint256)\n {\n if (_from < startBlock) {\n _from = startBlock;\n }\n if (endBlock > 0 && _to > endBlock) {\n _to = endBlock;\n }\n if (_to <= bonusEndBlock) {\n return _to.sub(_from).mul(BONUS_BLOCK_MULTIPLIER);\n } else if (_from >= bonusEndBlock) {\n return _to.sub(_from);\n } else {\n return\n bonusEndBlock.sub(_from).mul(BONUS_BLOCK_MULTIPLIER).add(_to.sub(bonusEndBlock));\n }\n }\n\n function _getUserAccumulatedReward(uint256 _poolId, address _user)\n internal\n view\n returns (uint256)\n {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_user];\n\n uint256 accumulatedRewardPerShare = pool.accumulatedRewardPerShare;\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (block.number > pool.lastRewardBlock && poolTokenBalance != 0) {\n (, uint256 accumulatedRewardPerShare_) = _getPoolAccumulatedReward(pool);\n accumulatedRewardPerShare = accumulatedRewardPerShare.add(accumulatedRewardPerShare_);\n }\n\n return\n user.accumulatedReward.add(\n user.amount.mul(accumulatedRewardPerShare).div(PRECISION).sub(user.rewardDebt)\n );\n }\n\n /**\n * @notice returns accumulated reward\n * @param _poolToken the address of pool token\n * @param _user the user address\n */\n function getUserAccumulatedReward(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n uint256 poolId = _getPoolId(_poolToken);\n return _getUserAccumulatedReward(poolId, _user);\n }\n\n /**\n * @notice returns estimated reward\n * @param _poolToken the address of pool token\n * @param _amount the amount of tokens to be deposited\n * @param _duration the duration of liquidity providing in seconds\n */\n function getEstimatedReward(\n address _poolToken,\n uint256 _amount,\n uint256 _duration\n ) external view returns (uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n uint256 start = block.number;\n uint256 end = start.add(_duration.div(SECONDS_PER_BLOCK));\n (, uint256 accumulatedRewardPerShare) =\n _getPoolAccumulatedReward(pool, _amount, start, end);\n return _amount.mul(accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Updates reward variables for all pools.\n * @dev Be careful of gas spending!\n */\n function updateAllPools() public {\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n _updatePool(i);\n }\n }\n\n /**\n * @notice Updates reward variables of the given pool to be up-to-date\n * @param _poolToken the address of pool token\n */\n function updatePool(address _poolToken) public {\n uint256 poolId = _getPoolId(_poolToken);\n _updatePool(poolId);\n }\n\n function _updatePool(uint256 _poolId) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n\n //this pool has been updated recently\n if (block.number <= pool.lastRewardBlock) {\n return;\n }\n\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (poolTokenBalance == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n (uint256 accumulatedReward_, uint256 accumulatedRewardPerShare_) =\n _getPoolAccumulatedReward(pool);\n pool.accumulatedRewardPerShare = pool.accumulatedRewardPerShare.add(\n accumulatedRewardPerShare_\n );\n pool.lastRewardBlock = block.number;\n\n totalUsersBalance = totalUsersBalance.add(accumulatedReward_);\n }\n\n function _getPoolAccumulatedReward(PoolInfo storage _pool)\n internal\n view\n returns (uint256, uint256)\n {\n return _getPoolAccumulatedReward(_pool, 0, _pool.lastRewardBlock, block.number);\n }\n\n function _getPoolAccumulatedReward(\n PoolInfo storage _pool,\n uint256 _additionalAmount,\n uint256 _startBlock,\n uint256 _endBlock\n ) internal view returns (uint256, uint256) {\n uint256 passedBlocks = _getPassedBlocksWithBonusMultiplier(_startBlock, _endBlock);\n uint256 accumulatedReward =\n passedBlocks.mul(rewardTokensPerBlock).mul(_pool.allocationPoint).div(\n totalAllocationPoint\n );\n\n uint256 poolTokenBalance = _pool.poolToken.balanceOf(address(this));\n poolTokenBalance = poolTokenBalance.add(_additionalAmount);\n uint256 accumulatedRewardPerShare = accumulatedReward.mul(PRECISION).div(poolTokenBalance);\n return (accumulatedReward, accumulatedRewardPerShare);\n }\n\n /**\n * @notice deposits pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it or to msg.sender\n */\n function deposit(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n _deposit(_poolToken, _amount, _user, false);\n }\n\n /**\n * @notice if the lending pools directly mint/transfer tokens to this address, process it like a user deposit\n * @dev only callable by the pool which issues the tokens\n * @param _user the user address\n * @param _amount the minted amount\n */\n function onTokensDeposited(address _user, uint256 _amount) external {\n //the msg.sender is the pool token. if the msg.sender is not a valid pool token, _deposit will revert\n _deposit(msg.sender, _amount, _user, true);\n }\n\n /**\n * @notice internal function for depositing pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it\n * @param alreadyTransferred true if the pool tokens have already been transferred\n */\n function _deposit(\n address _poolToken,\n uint256 _amount,\n address _user,\n bool alreadyTransferred\n ) internal {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _user != address(0) ? _user : msg.sender;\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n\n _updatePool(poolId);\n //sends reward directly to the user\n _updateReward(pool, user);\n\n if (_amount > 0) {\n //receives pool tokens from msg.sender, it can be user or WrapperProxy contract\n if (!alreadyTransferred)\n pool.poolToken.safeTransferFrom(address(msg.sender), address(this), _amount);\n user.amount = user.amount.add(_amount);\n }\n _updateRewardDebt(pool, user);\n emit Deposit(userAddress, _poolToken, _amount);\n }\n\n /**\n * @notice transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimReward(address _poolToken, address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n _claimReward(poolId, userAddress, true);\n }\n\n function _claimReward(\n uint256 _poolId,\n address _userAddress,\n bool _isStakingTokens\n ) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_userAddress];\n\n _updatePool(_poolId);\n _updateReward(pool, user);\n _transferReward(address(pool.poolToken), user, _userAddress, _isStakingTokens, true);\n _updateRewardDebt(pool, user);\n }\n\n /**\n * @notice transfers reward tokens from all pools\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimRewardFromAllPools(address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n uint256 poolId = i;\n _claimReward(poolId, userAddress, false);\n }\n\n if (\n lockedSOV.getLockedBalance(userAddress) > 0 ||\n lockedSOV.getUnlockedBalance(userAddress) > 0\n ) {\n lockedSOV.withdrawAndStakeTokensFrom(userAddress);\n }\n }\n\n /**\n * @notice withdraws pool tokens and transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the user address will be used to process a withdrawal (can be passed only by wrapper contract)\n */\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n require(user.amount >= _amount, \"Not enough balance\");\n\n _updatePool(poolId);\n _updateReward(pool, user);\n _transferReward(_poolToken, user, userAddress, false, false);\n\n user.amount = user.amount.sub(_amount);\n\n //msg.sender is wrapper -> send to wrapper\n if (msg.sender == wrapper) {\n pool.poolToken.safeTransfer(address(msg.sender), _amount);\n }\n //msg.sender is user or pool token (lending pool) -> send to user\n else {\n pool.poolToken.safeTransfer(userAddress, _amount);\n }\n\n _updateRewardDebt(pool, user);\n emit Withdraw(userAddress, _poolToken, _amount);\n }\n\n function _getUserAddress(address _user) internal view returns (address) {\n address userAddress = msg.sender;\n if (_user != address(0)) {\n //only wrapper can pass _user parameter\n require(\n msg.sender == wrapper || poolIdList[msg.sender] != 0,\n \"only wrapper or pools may withdraw for a user\"\n );\n userAddress = _user;\n }\n return userAddress;\n }\n\n function _updateReward(PoolInfo storage pool, UserInfo storage user) internal {\n //update user accumulated reward\n if (user.amount > 0) {\n //add reward for the previous amount of deposited tokens\n uint256 accumulatedReward =\n user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION).sub(\n user.rewardDebt\n );\n user.accumulatedReward = user.accumulatedReward.add(accumulatedReward);\n }\n }\n\n function _updateRewardDebt(PoolInfo storage pool, UserInfo storage user) internal {\n //reward accumulated before amount update (should be subtracted during next reward calculation)\n user.rewardDebt = user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Send reward in SOV to the lockedSOV vault.\n * @param _user The user info, to get its reward share.\n * @param _userAddress The address of the user, to send SOV in its behalf.\n * @param _isStakingTokens The flag whether we need to stake tokens\n * @param _isCheckingBalance The flag whether we need to throw error or don't process reward if SOV balance isn't enough\n */\n function _transferReward(\n address _poolToken,\n UserInfo storage _user,\n address _userAddress,\n bool _isStakingTokens,\n bool _isCheckingBalance\n ) internal {\n uint256 userAccumulatedReward = _user.accumulatedReward;\n /// @dev get unlock immediate percent of the pool token.\n uint256 calculatedUnlockedImmediatelyPercent = calcUnlockedImmediatelyPercent(_poolToken);\n\n /// @dev Transfer if enough SOV balance on this LM contract.\n uint256 balance = SOV.balanceOf(address(this));\n if (balance >= userAccumulatedReward) {\n totalUsersBalance = totalUsersBalance.sub(userAccumulatedReward);\n _user.accumulatedReward = 0;\n\n /// @dev If calculatedUnlockedImmediatelyPercent is 100%, transfer the reward to the LP (user).\n /// else, deposit it into lockedSOV vault contract, but first\n /// SOV deposit must be approved to move the SOV tokens\n /// from this LM contract into the lockedSOV vault.\n if (calculatedUnlockedImmediatelyPercent == 10000) {\n SOV.transfer(_userAddress, userAccumulatedReward);\n } else {\n require(SOV.approve(address(lockedSOV), userAccumulatedReward), \"Approve failed\");\n lockedSOV.deposit(\n _userAddress,\n userAccumulatedReward,\n calculatedUnlockedImmediatelyPercent\n );\n\n if (_isStakingTokens) {\n lockedSOV.withdrawAndStakeTokensFrom(_userAddress);\n }\n }\n\n /// @dev Event log.\n emit RewardClaimed(_userAddress, _poolToken, userAccumulatedReward);\n } else {\n require(!_isCheckingBalance, \"Claiming reward failed\");\n }\n }\n\n /**\n * @notice withdraws pool tokens without transferring reward tokens\n * @param _poolToken the address of pool token\n * @dev EMERGENCY ONLY\n */\n function emergencyWithdraw(address _poolToken) external {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][msg.sender];\n\n _updatePool(poolId);\n _updateReward(pool, user);\n\n totalUsersBalance = totalUsersBalance.sub(user.accumulatedReward);\n uint256 userAmount = user.amount;\n uint256 userAccumulatedReward = user.accumulatedReward;\n user.amount = 0;\n user.rewardDebt = 0;\n user.accumulatedReward = 0;\n pool.poolToken.safeTransfer(address(msg.sender), userAmount);\n\n emit EmergencyWithdraw(msg.sender, _poolToken, userAmount, userAccumulatedReward);\n }\n\n /**\n * @notice returns pool id\n * @param _poolToken the address of pool token\n */\n function getPoolId(address _poolToken) external view returns (uint256) {\n return _getPoolId(_poolToken);\n }\n\n function _getPoolId(address _poolToken) internal view returns (uint256) {\n uint256 poolId = poolIdList[_poolToken];\n require(poolId > 0, \"Pool token not found\");\n return poolId - 1;\n }\n\n /**\n * @notice returns count of pool tokens\n */\n function getPoolLength() external view returns (uint256) {\n return poolInfoList.length;\n }\n\n /**\n * @notice returns list of pool token's info\n */\n function getPoolInfoList() external view returns (PoolInfo[] memory) {\n return poolInfoList;\n }\n\n /**\n * @notice returns pool info for the given token\n * @param _poolToken the address of pool token\n */\n function getPoolInfo(address _poolToken) external view returns (PoolInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return poolInfoList[poolId];\n }\n\n /**\n * @notice returns list of [amount, accumulatedReward] for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserBalanceList(address _user) external view returns (uint256[2][] memory) {\n uint256 length = poolInfoList.length;\n uint256[2][] memory userBalanceList = new uint256[2][](length);\n for (uint256 i = 0; i < length; i++) {\n userBalanceList[i][0] = userInfoMap[i][_user].amount;\n userBalanceList[i][1] = _getUserAccumulatedReward(i, _user);\n }\n return userBalanceList;\n }\n\n /**\n * @notice returns UserInfo for the given pool and user\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserInfo(address _poolToken, address _user) public view returns (UserInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return userInfoMap[poolId][_user];\n }\n\n /**\n * @notice returns list of UserInfo for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserInfoList(address _user) external view returns (UserInfo[] memory) {\n uint256 length = poolInfoList.length;\n UserInfo[] memory userInfoList = new UserInfo[](length);\n for (uint256 i = 0; i < length; i++) {\n userInfoList[i] = userInfoMap[i][_user];\n }\n return userInfoList;\n }\n\n /**\n * @notice returns accumulated reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardList(address _user) external view returns (uint256[] memory) {\n uint256 length = poolInfoList.length;\n uint256[] memory rewardList = new uint256[](length);\n for (uint256 i = 0; i < length; i++) {\n rewardList[i] = _getUserAccumulatedReward(i, _user);\n }\n return rewardList;\n }\n\n /**\n * @notice returns the pool token balance a user has on the contract\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n UserInfo memory ui = getUserInfo(_poolToken, _user);\n return ui.amount;\n }\n\n /**\n * @notice returns the accumulated liquid reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBePaidLiquid(address _user)\n external\n view\n returns (uint256)\n {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n calculatedUnlockedImmediatelyPercent.mul(_getUserAccumulatedReward(i, _user)).div(\n 10000\n )\n );\n }\n\n return result;\n }\n\n /**\n * @notice returns the accumulated vested reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBeVested(address _user) external view returns (uint256) {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n (10000 - calculatedUnlockedImmediatelyPercent)\n .mul(_getUserAccumulatedReward(i, _user))\n .div(10000)\n );\n }\n\n return result;\n }\n\n /**\n * @dev calculate the unlocked immediate percentage of specific pool token\n * use the poolTokensUnlockedImmediatelyPercent by default, if it is not set, then use the unlockedImmediatelyPercent\n */\n function calcUnlockedImmediatelyPercent(address _poolToken) public view returns (uint256) {\n uint256 poolTokenUnlockedImmediatelyPercent =\n poolTokensUnlockedImmediatelyPercent[_poolToken];\n return\n poolTokenUnlockedImmediatelyPercent > 0\n ? poolTokenUnlockedImmediatelyPercent\n : unlockedImmediatelyPercent;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningConfigToken.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/IERC20_.sol\";\n\n/**\n * @title Dummy token with 0 total supply.\n *\n * @dev We need this token for having a flexibility with LiquidityMining configuration\n */\ncontract LiquidityMiningConfigToken is IERC20_ {\n function totalSupply() external view returns (uint256) {\n return 0;\n }\n\n function balanceOf(address account) external view returns (uint256) {\n return 0;\n }\n\n function transfer(address recipient, uint256 amount) external returns (bool) {\n return false;\n }\n\n function allowance(address owner, address spender) external view returns (uint256) {\n return 0;\n }\n\n function approve(address spender, uint256 amount) external returns (bool) {\n return false;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool) {\n return false;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./LiquidityMiningStorage.sol\";\nimport \"../proxy/UpgradableProxy.sol\";\n\n/**\n * @dev LiquidityMining contract should be upgradable, use UpgradableProxy\n */\ncontract LiquidityMiningProxy is LiquidityMiningStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/farm/LiquidityMiningStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../utils/AdminRole.sol\";\n\ncontract LiquidityMiningStorage is AdminRole {\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many pool tokens the user has provided.\n uint256 rewardDebt; // Reward debt. See explanation below.\n uint256 accumulatedReward; //Reward that's ready to be transferred\n //\n // We do some fancy math here. Basically, any point in time, the amount of reward tokens\n // entitled to a user but is accumulated to be distributed is:\n //\n // accumulated reward = (user.amount * pool.accumulatedRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accumulatedRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the accumulated reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 poolToken; // Address of LP token contract.\n uint96 allocationPoint; // How many allocation points assigned to this pool. Amount of reward tokens to distribute per block.\n uint256 lastRewardBlock; // Last block number that reward tokens distribution occurs.\n uint256 accumulatedRewardPerShare; // Accumulated amount of reward tokens per share, times 1e12. See below.\n }\n\n // Rewards tokens created per block.\n uint256 public rewardTokensPerBlock;\n // The block number when reward token mining starts.\n uint256 public startBlock;\n // Block number when bonus reward token period ends.\n uint256 public bonusEndBlock;\n // Block number when reward token period ends.\n uint256 public endBlock;\n\n //Wrapper contract which will be a proxy between user and LM\n address public wrapper;\n\n // Info of each pool.\n PoolInfo[] public poolInfoList;\n // Mapping pool token address => pool id\n mapping(address => uint256) poolIdList;\n // Total allocation points. Must be the sum of all allocation points in all pools.\n uint256 public totalAllocationPoint;\n\n // Info of each user that stakes LP tokens.\n mapping(uint256 => mapping(address => UserInfo)) public userInfoMap;\n // Total balance this contract should have to handle withdrawal for all users\n uint256 public totalUsersBalance;\n\n /// @dev The SOV token\n IERC20 public SOV;\n\n /// @dev The locked vault contract to deposit LP's rewards into.\n ILockedSOV public lockedSOV;\n\n // The % which determines how much will be unlocked immediately.\n /// @dev 10000 is 100%\n uint256 public unlockedImmediatelyPercent;\n\n /// @dev overwrite the unlockedImmediatelyPercent for specific token.\n mapping(address => uint256) public poolTokensUnlockedImmediatelyPercent;\n}\n" + }, + "contracts/feeds/BProPriceFeed.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IMoCState.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The BPro Price Feed contract.\n *\n * This contract gets/sets the MoC (Money on Chain) address of its state\n * contract and queries its method bproUsdPrice to get bPro/USD valuation.\n * */\ncontract BProPriceFeed is IPriceFeedsExt, Ownable {\n address public mocStateAddress;\n\n event SetMoCStateAddress(address indexed mocStateAddress, address changerAddress);\n\n /**\n * @notice Initializes a new MoC state.\n *\n * @param _mocStateAddress MoC state address\n * */\n constructor(address _mocStateAddress) public {\n setMoCStateAddress(_mocStateAddress);\n }\n\n /**\n * @notice Get BPro USD price.\n *\n * @return the BPro USD Price [using mocPrecision]\n */\n function latestAnswer() external view returns (uint256) {\n IMoCState _mocState = IMoCState(mocStateAddress);\n return _mocState.bproUsdPrice();\n }\n\n /**\n * @notice Supposed to get the MoC update time, but instead\n * get the current timestamp.\n *\n * @return Always returns current block's timestamp.\n * */\n function latestTimestamp() external view returns (uint256) {\n return now; /// MoC state doesn't return update timestamp.\n }\n\n /**\n * @notice Set MoC state address.\n *\n * @param _mocStateAddress The MoC state address.\n * */\n function setMoCStateAddress(address _mocStateAddress) public onlyOwner {\n require(Address.isContract(_mocStateAddress), \"_mocStateAddress not a contract\");\n mocStateAddress = _mocStateAddress;\n emit SetMoCStateAddress(mocStateAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/IMoCState.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IMoCState {\n function getRbtcInBitPro(bytes32 bucket) external view returns (uint256);\n\n function globalMaxBPro() external view returns (uint256);\n\n function maxBPro(bytes32 bucket) external view returns (uint256);\n\n function absoluteMaxBPro() external view returns (uint256);\n\n function maxBProWithDiscount() external view returns (uint256);\n\n function bproTecPrice() external view returns (uint256);\n\n function bucketBProTecPrice(bytes32 bucket) external view returns (uint256);\n\n function bproDiscountPrice() external view returns (uint256);\n\n function bproUsdPrice() external view returns (uint256);\n\n function bproSpotDiscountRate() external view returns (uint256);\n\n function getBucketNBPro(bytes32 bucket) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IPriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface IPriceFeeds {\n function queryRate(address sourceToken, address destToken)\n external\n view\n returns (uint256 rate, uint256 precision);\n\n function queryPrecision(address sourceToken, address destToken)\n external\n view\n returns (uint256 precision);\n\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) external view returns (uint256 destAmount);\n\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) external view returns (uint256 sourceToDestSwapRate);\n\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\n\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (uint256);\n\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\n\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\n\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (bool);\n\n function getFastGasPrice(address payToken) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IRSKOracle {\n function updatePrice(uint256 price, uint256 timestamp) external;\n\n function getPricing() external view returns (uint256, uint256);\n\n function setOracleAddress(address addr) external;\n\n function clearOracleAddress() external;\n}\n" + }, + "contracts/feeds/IV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IV1PoolOracle {\n function read(uint256 price, uint256 timestamp)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function latestAnswer() external view returns (uint256);\n\n function liquidityPool() external view returns (address);\n\n function latestPrice(address _baseToken) external view returns (uint256 answer);\n}\n\ninterface ILiquidityPoolV1Converter {\n function reserveTokens(uint256 index) external view returns (address);\n}\n" + }, + "contracts/feeds/PriceFeedRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IRSKOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @notice The Price Feed RSK Oracle contract.\n *\n * This contract implements RSK Oracle query functionality,\n * getting the price and the last timestamp from an external oracle contract.\n * */\ncontract PriceFeedRSKOracle is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public rskOracleAddress;\n\n /* Events */\n\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new RSK Oracle.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _rskOracleAddress) public {\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256 _price) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (_price, ) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestTimestamp() external view returns (uint256 _timestamp) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (, _timestamp) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/PriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./PriceFeedsConstants.sol\";\n\ninterface IPriceFeedsExt {\n function latestAnswer() external view returns (uint256);\n}\n\n/**\n * @title The Price Feeds contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract queries the price feeds contracts where\n * oracles updates token prices computing relative token prices.\n * And besides it includes some calculations about loans such as\n * drawdown, margin and collateral.\n * */\ncontract PriceFeeds is Constants, Ownable {\n using SafeMath for uint256;\n\n /* Events */\n\n event GlobalPricingPaused(address indexed sender, bool indexed isPaused);\n\n /* Storage */\n\n /// Mapping of PriceFeedsExt instances.\n /// token => pricefeed\n mapping(address => IPriceFeedsExt) public pricesFeeds;\n\n /// Decimals of supported tokens.\n mapping(address => uint256) public decimals;\n\n /// Value on rBTC weis for the protocol token.\n uint256 public protocolTokenEthPrice = 0.0002 ether;\n\n /// Flag to pause pricings.\n bool public globalPricingPaused = false;\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires 3 parameters.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * @param _protocolTokenAddress The address of the protocol token.\n * @param _baseTokenAddress The address of the base token.\n * */\n constructor(\n address _wrbtcTokenAddress,\n address _protocolTokenAddress,\n address _baseTokenAddress\n ) public {\n /// Set decimals for this token.\n decimals[address(0)] = 18;\n decimals[_wrbtcTokenAddress] = 18;\n _setWrbtcToken(_wrbtcTokenAddress);\n _setProtocolTokenAddress(_protocolTokenAddress);\n _setBaseToken(_baseTokenAddress);\n }\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @dev Public wrapper for _queryRate internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function queryRate(address sourceToken, address destToken)\n public\n view\n returns (uint256 rate, uint256 precision)\n {\n return _queryRate(sourceToken, destToken);\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @dev Public wrapper for _getDecimalPrecision internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function queryPrecision(address sourceToken, address destToken) public view returns (uint256) {\n return sourceToken != destToken ? _getDecimalPrecision(sourceToken, destToken) : 10**18;\n }\n\n /**\n * @notice Price conversor: Calculate the price of an amount of source\n * tokens in destiny token units.\n *\n * @dev NOTE: This function returns 0 during a pause, rather than a revert.\n * Ensure calling contracts handle correctly.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of the source tokens.\n *\n * @return destAmount The amount of destiny tokens equivalent in price\n * to the amount of source tokens.\n * */\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) public view returns (uint256 destAmount) {\n if (globalPricingPaused) {\n return 0;\n }\n\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n destAmount = sourceAmount.mul(rate).div(precision);\n }\n\n /**\n * @notice Calculate the swap rate between two tokens.\n *\n * Regarding slippage, there is a hardcoded slippage limit of 5%, enforced\n * by this function for all borrowing, lending and margin trading\n * originated swaps performed in the Sovryn exchange.\n *\n * This means all operations in the Sovryn exchange are subject to losing\n * up to 5% from the internal swap performed.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of source tokens.\n * @param destAmount The amount of destiny tokens.\n * @param maxSlippage The maximum slippage limit.\n *\n * @return sourceToDestSwapRate The swap rate between tokens.\n * */\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) public view returns (uint256 sourceToDestSwapRate) {\n require(!globalPricingPaused, \"pricing is paused\");\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n sourceToDestSwapRate = destAmount.mul(precision).div(sourceAmount);\n\n if (rate > sourceToDestSwapRate) {\n uint256 spreadValue = rate - sourceToDestSwapRate;\n spreadValue = spreadValue.mul(10**20).div(sourceToDestSwapRate);\n require(spreadValue <= maxSlippage, \"price disagreement\");\n }\n }\n\n /**\n * @notice Calculate the rBTC amount equivalent to a given token amount.\n * Native coin on RSK is rBTC. This code comes from Ethereum applications,\n * so Eth refers to 10**18 weis of native coin, i.e.: 1 rBTC.\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n *\n * @return ethAmount The amount of rBTC equivalent.\n * */\n function amountInEth(address tokenAddress, uint256 amount)\n public\n view\n returns (uint256 ethAmount)\n {\n /// Token is wrBTC, amount in rBTC is the same.\n if (tokenAddress == address(wrbtcToken)) {\n ethAmount = amount;\n } else {\n (uint256 toEthRate, uint256 toEthPrecision) =\n queryRate(tokenAddress, address(wrbtcToken));\n ethAmount = amount.mul(toEthRate).div(toEthPrecision);\n }\n }\n\n /**\n * @notice Calculate the maximum drawdown of a loan.\n *\n * A drawdown is commonly defined as the decline from a high peak to a\n * pullback low of a specific investment or equity in an account.\n *\n * Drawdown magnitude refers to the amount of value that a user loses\n * during the drawdown period.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param margin The relation between the position size and the loan.\n * margin = (total position size - loan) / loan\n *\n * @return maxDrawdown The maximum drawdown.\n * */\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 margin\n ) public view returns (uint256 maxDrawdown) {\n uint256 loanToCollateralAmount;\n if (collateralToken == loanToken) {\n loanToCollateralAmount = loanAmount;\n } else {\n (uint256 rate, uint256 precision) = queryRate(loanToken, collateralToken);\n loanToCollateralAmount = loanAmount.mul(rate).div(precision);\n }\n\n uint256 combined =\n loanToCollateralAmount.add(loanToCollateralAmount.mul(margin).div(10**20));\n\n maxDrawdown = collateralAmount > combined ? collateralAmount - combined : 0;\n }\n\n /**\n * @notice Calculate the margin and the collateral on rBTC.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralInEthAmount The amount of collateral on rBTC.\n * */\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralInEthAmount) {\n (currentMargin, ) = getCurrentMargin(\n loanToken,\n collateralToken,\n loanAmount,\n collateralAmount\n );\n\n collateralInEthAmount = amountInEth(collateralToken, collateralAmount);\n }\n\n /**\n * @notice Calculate the margin of a loan.\n *\n * @dev current margin = (total position size - loan) / loan\n * The collateral amount passed as parameter equals the total position size.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralToLoanRate The price ratio between collateral and\n * loan tokens.\n * */\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralToLoanRate) {\n uint256 collateralToLoanAmount;\n if (collateralToken == loanToken) {\n collateralToLoanAmount = collateralAmount;\n collateralToLoanRate = 10**18;\n } else {\n uint256 collateralToLoanPrecision;\n (collateralToLoanRate, collateralToLoanPrecision) = queryRate(\n collateralToken,\n loanToken\n );\n\n collateralToLoanRate = collateralToLoanRate.mul(10**18).div(collateralToLoanPrecision);\n\n collateralToLoanAmount = collateralAmount.mul(collateralToLoanRate).div(10**18);\n }\n\n if (loanAmount != 0 && collateralToLoanAmount >= loanAmount) {\n return (\n collateralToLoanAmount.sub(loanAmount).mul(10**20).div(loanAmount),\n collateralToLoanRate\n );\n } else {\n return (0, collateralToLoanRate);\n }\n }\n\n /**\n * @notice Get assessment about liquidating a loan.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param maintenanceMargin The minimum margin before liquidation.\n *\n * @return True/false to liquidate the loan.\n * */\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) public view returns (bool) {\n (uint256 currentMargin, ) =\n getCurrentMargin(loanToken, collateralToken, loanAmount, collateralAmount);\n\n return currentMargin <= maintenanceMargin;\n }\n\n /*\n * Owner functions\n */\n\n /**\n * @notice Set new value for protocolTokenEthPrice\n *\n * @param newPrice The new value for protocolTokenEthPrice\n * */\n function setProtocolTokenEthPrice(uint256 newPrice) external onlyOwner {\n require(newPrice != 0, \"invalid price\");\n protocolTokenEthPrice = newPrice;\n }\n\n /**\n * @notice Populate pricesFeeds mapping w/ values from feeds[]\n *\n * @param tokens The array of tokens to loop and get addresses.\n * @param feeds The array of contract instances for every token.\n * */\n function setPriceFeed(address[] calldata tokens, IPriceFeedsExt[] calldata feeds)\n external\n onlyOwner\n {\n require(tokens.length == feeds.length, \"count mismatch\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n pricesFeeds[tokens[i]] = feeds[i];\n }\n }\n\n /**\n * @notice Populate decimals mapping w/ values from tokens[].decimals\n *\n * @param tokens The array of tokens to loop and get values from.\n * */\n function setDecimals(IERC20[] calldata tokens) external onlyOwner {\n for (uint256 i = 0; i < tokens.length; i++) {\n decimals[address(tokens[i])] = tokens[i].decimals();\n }\n }\n\n /**\n * @notice Set flag globalPricingPaused\n *\n * @param isPaused The new status of pause (true/false).\n * */\n function setGlobalPricingPaused(bool isPaused) external onlyOwner {\n if (globalPricingPaused != isPaused) {\n globalPricingPaused = isPaused;\n\n emit GlobalPricingPaused(msg.sender, isPaused);\n }\n }\n\n /*\n * Internal functions\n */\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n /// Different tokens, query prices and perform division.\n if (sourceToken != destToken) {\n uint256 sourceRate;\n if (sourceToken != address(baseToken) && sourceToken != protocolTokenAddress) {\n IPriceFeedsExt _sourceFeed = pricesFeeds[sourceToken];\n require(address(_sourceFeed) != address(0), \"unsupported src feed\");\n\n /// Query token price on priceFeedsExt instance.\n sourceRate = _sourceFeed.latestAnswer();\n require(sourceRate != 0 && (sourceRate >> 128) == 0, \"price error\");\n } else {\n sourceRate = sourceToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n uint256 destRate;\n if (destToken != address(baseToken) && destToken != protocolTokenAddress) {\n IPriceFeedsExt _destFeed = pricesFeeds[destToken];\n require(address(_destFeed) != address(0), \"unsupported dst feed\");\n\n /// Query token price on priceFeedsExt instance.\n destRate = _destFeed.latestAnswer();\n require(destRate != 0 && (destRate >> 128) == 0, \"price error\");\n } else {\n destRate = destToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n rate = sourceRate.mul(10**18).div(destRate);\n\n precision = _getDecimalPrecision(sourceToken, destToken);\n\n /// Same tokens, return 1 with decimals.\n } else {\n rate = 10**18;\n precision = 10**18;\n }\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function _getDecimalPrecision(address sourceToken, address destToken)\n internal\n view\n returns (uint256)\n {\n /// Same tokens, return 1 with decimals.\n if (sourceToken == destToken) {\n return 10**18;\n\n /// Different tokens, query ERC20 precisions and return 18 +- diff.\n } else {\n uint256 sourceTokenDecimals = decimals[sourceToken];\n if (sourceTokenDecimals == 0) sourceTokenDecimals = IERC20(sourceToken).decimals();\n\n uint256 destTokenDecimals = decimals[destToken];\n if (destTokenDecimals == 0) destTokenDecimals = IERC20(destToken).decimals();\n\n if (destTokenDecimals >= sourceTokenDecimals)\n return 10**(SafeMath.sub(18, destTokenDecimals - sourceTokenDecimals));\n else return 10**(SafeMath.add(18, sourceTokenDecimals - destTokenDecimals));\n }\n }\n}\n" + }, + "contracts/feeds/PriceFeedsConstants.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The Price Feeds Constants contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract keep the addresses of token instances for wrBTC, base token\n * and protocol token.\n * */\ncontract Constants {\n IWrbtcERC20 public wrbtcToken;\n IWrbtcERC20 public baseToken;\n address internal protocolTokenAddress;\n\n /**\n * @notice Set wrBTC token address.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * */\n function _setWrbtcToken(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"_wrbtcTokenAddress not a contract\");\n wrbtcToken = IWrbtcERC20(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Set protocol token address.\n *\n * @param _protocolTokenAddress The address of the protocol token.\n * */\n function _setProtocolTokenAddress(address _protocolTokenAddress) internal {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n protocolTokenAddress = _protocolTokenAddress;\n }\n\n /**\n * @notice Set base token address.\n *\n * @param _baseTokenAddress The address of the base token.\n * */\n function _setBaseToken(address _baseTokenAddress) internal {\n require(Address.isContract(_baseTokenAddress), \"_baseTokenAddress not a contract\");\n baseToken = IWrbtcERC20(_baseTokenAddress);\n }\n}\n" + }, + "contracts/feeds/PriceFeedV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IV1PoolOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./IPriceFeeds.sol\";\n\n/**\n * @notice The Price Feed V1 Pool Oracle contract.\n *\n * This contract implements V1 Pool Oracle query functionality,\n * getting the price from v1 pool oracle.\n * */\ncontract PriceFeedV1PoolOracle is IPriceFeedsExt, Ownable {\n using SafeMath for uint256;\n /* Storage */\n\n address public v1PoolOracleAddress;\n address public wRBTCAddress;\n address public docAddress;\n address public baseCurrency;\n\n /* Events */\n event SetV1PoolOracleAddress(address indexed v1PoolOracleAddress, address changerAddress);\n event SetWRBTCAddress(address indexed wRBTCAddress, address changerAddress);\n event SetDOCAddress(address indexed docAddress, address changerAddress);\n event SetBaseCurrency(address indexed baseCurrency, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new V1 Pool Oracle.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n * @param _wRBTCAddress The wrbtc token address.\n * @param _docAddress The doc token address.\n * */\n constructor(\n address _v1PoolOracleAddress,\n address _wRBTCAddress,\n address _docAddress,\n address _baseCurrency\n ) public {\n setRBTCAddress(_wRBTCAddress);\n setDOCAddress(_docAddress);\n setV1PoolOracleAddress(_v1PoolOracleAddress);\n setBaseCurrency(_baseCurrency);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256) {\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(v1PoolOracleAddress);\n\n uint256 _price = _v1PoolOracle.latestPrice(baseCurrency);\n\n // Need to convert to USD, since the V1 pool return value is based on BTC\n uint256 priceInUSD = _convertAnswerToUsd(_price);\n require(priceInUSD != 0, \"price error\");\n\n return priceInUSD;\n }\n\n function _convertAnswerToUsd(uint256 _valueInBTC) private view returns (uint256) {\n address _priceFeeds = msg.sender;\n\n uint256 precision = IPriceFeeds(_priceFeeds).queryPrecision(wRBTCAddress, docAddress);\n uint256 valueInUSD =\n IPriceFeeds(_priceFeeds).queryReturn(wRBTCAddress, docAddress, _valueInBTC);\n\n /// Need to multiply by query precision (doc's precision) and divide by 1*10^18 (Because the based price in v1 pool is using 18 decimals)\n return valueInUSD.mul(precision).div(1e18);\n }\n\n /**\n * @notice Set the V1 Pool Oracle address.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n */\n function setV1PoolOracleAddress(address _v1PoolOracleAddress) public onlyOwner {\n require(Address.isContract(_v1PoolOracleAddress), \"_v1PoolOracleAddress not a contract\");\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(_v1PoolOracleAddress);\n address liquidityPool = _v1PoolOracle.liquidityPool();\n require(\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(0) == wRBTCAddress ||\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(1) == wRBTCAddress,\n \"one of the two reserves needs to be wrbtc\"\n );\n v1PoolOracleAddress = _v1PoolOracleAddress;\n emit SetV1PoolOracleAddress(v1PoolOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the rBtc address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the rBtc\n *\n * @param _wRBTCAddress The rBTC address\n */\n function setRBTCAddress(address _wRBTCAddress) public onlyOwner {\n require(_wRBTCAddress != address(0), \"wRBTC address cannot be zero address\");\n wRBTCAddress = _wRBTCAddress;\n emit SetWRBTCAddress(wRBTCAddress, msg.sender);\n }\n\n /**\n * @notice Set the DoC address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the DoC\n *\n * @param _docAddress The DoC address\n */\n function setDOCAddress(address _docAddress) public onlyOwner {\n require(_docAddress != address(0), \"DOC address cannot be zero address\");\n docAddress = _docAddress;\n emit SetDOCAddress(_docAddress, msg.sender);\n }\n\n /**\n * @notice Set the base currency address. That's the reserve address which is not WRBTC\n *\n * @param _baseCurrency The base currency address\n */\n function setBaseCurrency(address _baseCurrency) public onlyOwner {\n require(_baseCurrency != address(0), \"Base currency address cannot be zero address\");\n baseCurrency = _baseCurrency;\n emit SetBaseCurrency(_baseCurrency, msg.sender);\n }\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsLocal.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\n\n/**\n * @title Price Feeds Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the logic of setting and getting rates between two tokens.\n * */\ncontract PriceFeedsLocal is PriceFeeds {\n mapping(address => mapping(address => uint256)) public rates;\n\n /// uint256 public slippageMultiplier = 100 ether;\n\n /**\n * @notice Deploy local price feed contract.\n *\n * @param _wrbtcTokenAddress The address of the wrBTC instance.\n * @param _protocolTokenAddress The address of the protocol token instance.\n * */\n constructor(address _wrbtcTokenAddress, address _protocolTokenAddress)\n public\n PriceFeeds(_wrbtcTokenAddress, _protocolTokenAddress, _wrbtcTokenAddress)\n {}\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n if (sourceToken == destToken) {\n rate = 10**18;\n precision = 10**18;\n } else {\n if (sourceToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = protocolTokenEthPrice;\n } else if (destToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = SafeMath.div(10**36, protocolTokenEthPrice);\n } else {\n if (rates[sourceToken][destToken] != 0) {\n rate = rates[sourceToken][destToken];\n } else {\n uint256 sourceToEther =\n rates[sourceToken][address(wrbtcToken)] != 0\n ? rates[sourceToken][address(wrbtcToken)]\n : 10**18;\n uint256 etherToDest =\n rates[address(wrbtcToken)][destToken] != 0\n ? rates[address(wrbtcToken)][destToken]\n : 10**18;\n\n rate = sourceToEther.mul(etherToDest).div(10**18);\n }\n }\n precision = _getDecimalPrecision(sourceToken, destToken);\n }\n }\n\n /**\n * @notice Owner set price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param rate The price ratio source/dest.\n * */\n function setRates(\n address sourceToken,\n address destToken,\n uint256 rate\n ) public onlyOwner {\n if (sourceToken != destToken) {\n rates[sourceToken][destToken] = rate;\n rates[destToken][sourceToken] = SafeMath.div(10**36, rate);\n }\n }\n\n /*function setSlippageMultiplier(\n uint256 _slippageMultiplier)\n public\n onlyOwner\n {\n require (slippageMultiplier != _slippageMultiplier && _slippageMultiplier <= 100 ether);\n slippageMultiplier = _slippageMultiplier;\n }*/\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsMoC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\nimport \"../IRSKOracle.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\ninterface Medianizer {\n function peek() external view returns (bytes32, bool);\n}\n\n/**\n * @title Price Feed of MoC (Money on Chain) contract.\n *\n * This contract contains the logic to set MoC oracles\n * and query last price update.\n * */\ncontract PriceFeedsMoC is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public mocOracleAddress;\n address public rskOracleAddress;\n\n /* Events */\n\n event SetMoCOracleAddress(address indexed mocOracleAddress, address changerAddress);\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new MoC Oracle.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _mocOracleAddress, address _rskOracleAddress) public {\n setMoCOracleAddress(_mocOracleAddress);\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestAnswer() external view returns (uint256) {\n (bytes32 value, bool hasValue) = Medianizer(mocOracleAddress).peek();\n if (hasValue) {\n return uint256(value);\n } else {\n (uint256 price, ) = IRSKOracle(rskOracleAddress).getPricing();\n return price;\n }\n }\n\n /**\n * @notice Set the MoC Oracle address.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n */\n function setMoCOracleAddress(address _mocOracleAddress) public onlyOwner {\n require(Address.isContract(_mocOracleAddress), \"_mocOracleAddress not a contract\");\n mocOracleAddress = _mocOracleAddress;\n emit SetMoCOracleAddress(mocOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/USDTPriceFeed.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./PriceFeeds.sol\";\n\n/**\n * @notice The Price Feed USDT contract.\n *\n * This contract implements USDT query functionality,\n * getting the price and the last timestamp from a\n * trivial formula, always returning 1 and now.\n * */\ncontract USDTPriceFeed is IPriceFeedsExt {\n uint256 private constant USDT_RATE = 1 ether;\n\n /**\n * @notice Get the USDT price.\n *\n * @return Always returns the trivial rate of 1.\n * */\n function latestAnswer() external view returns (uint256) {\n return USDT_RATE;\n }\n\n /**\n * @notice Get the las time the price was updated.\n * @return Always trivial current block's timestamp.\n */\n function latestTimestamp() external view returns (uint256) {\n return now;\n }\n}\n" + }, + "contracts/governance/ApprovalReceiver.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./ErrorDecoder.sol\";\nimport \"../token/IApproveAndCall.sol\";\n\n/**\n * @title Base contract for receiving approval from SOV token.\n */\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\n modifier onlyThisContract() {\n // Accepts calls only from receiveApproval function.\n require(msg.sender == address(this), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external {\n // Accepts calls only from SOV token.\n require(msg.sender == _getToken(), \"unauthorized\");\n require(msg.sender == _token, \"unauthorized\");\n\n // Only allowed methods.\n bool isAllowed = false;\n bytes4[] memory selectors = _getSelectors();\n bytes4 sig = _getSig(_data);\n for (uint256 i = 0; i < selectors.length; i++) {\n if (sig == selectors[i]) {\n isAllowed = true;\n break;\n }\n }\n require(isAllowed, \"method is not allowed\");\n\n // Check sender and amount.\n address sender;\n uint256 amount;\n (, sender, amount) = abi.decode(\n abi.encodePacked(bytes28(0), _data),\n (bytes32, address, uint256)\n );\n require(sender == _sender, \"sender mismatch\");\n require(amount == _amount, \"amount mismatch\");\n\n _call(_data);\n }\n\n /**\n * @notice Returns token address, only this address can be a sender for receiveApproval.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, 0x. When overriden, the token address making the call.\n */\n function _getToken() internal view returns (address) {\n return address(0);\n }\n\n /**\n * @notice Returns list of function selectors allowed to be invoked.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, empty array. When overriden, allowed selectors.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n return new bytes4[](0);\n }\n\n /**\n * @notice Makes call and reverts w/ enhanced error message.\n * @param _data Error message as bytes.\n */\n function _call(bytes memory _data) internal {\n (bool success, bytes memory returnData) = address(this).call(_data);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"receiveApproval: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"receiveApproval: \", string(returnData)));\n }\n }\n }\n\n /**\n * @notice Extracts the called function selector, a hash of the signature.\n * @dev The first four bytes of the call data for a function call specifies\n * the function to be called. It is the first (left, high-order in big-endian)\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\n * Example:\n * msg.data:\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\n * 000450000000000000000000000000000000000000000000000000000000000000001\n * selector (or method ID): 0xcdcd77c0\n * signature: baz(uint32,bool)\n * @param _data The msg.data from the low level call.\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\n */\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\n assembly {\n sig := mload(add(_data, 32))\n }\n }\n}\n" + }, + "contracts/governance/ErrorDecoder.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base contract to properly handle returned data on failed calls\n * @dev On EVM if the return data length of a call is less than 68,\n * then the transaction fails silently without a revert message!\n *\n * As described in the Solidity documentation\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\n * the revert reason is an ABI-encoded string consisting of:\n * 0x08c379a0 // Function selector (method id) for \"Error(string)\" signature\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\n *\n * Another example, debug data from test:\n * 0x08c379a0\n * 0000000000000000000000000000000000000000000000000000000000000020\n * 0000000000000000000000000000000000000000000000000000000000000034\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n *\n * Parsed into:\n * Data offset: 20\n * Length: 34\n * Error message:\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n */\ncontract ErrorDecoder {\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\n\n /**\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\n * @param str1 First string, usually a hardcoded context written by dev.\n * @param str2 Second string, usually the error message from the reverted call.\n * @return The concatenated error string\n */\n function _addErrorMessage(string memory str1, string memory str2)\n internal\n pure\n returns (string memory)\n {\n bytes memory bytesStr1 = bytes(str1);\n bytes memory bytesStr2 = bytes(str2);\n string memory str12 =\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\n bytes memory bytesStr12 = bytes(str12);\n uint256 j = 0;\n for (uint256 i = 0; i < bytesStr1.length; i++) {\n bytesStr12[j++] = bytesStr1[i];\n }\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\n bytesStr12[j++] = bytesStr2[i];\n }\n return string(bytesStr12);\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../Staking/SafeMath96.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../interfaces/IConverterAMM.sol\";\n\n/**\n * @title The FeeSharingCollector contract.\n * @notice This contract withdraws fees to be paid to SOV Stakers from the protocol.\n * Stakers call withdraw() to get their share of the fees.\n *\n * @notice Staking is not only granting voting rights, but also access to fee\n * sharing according to the own voting power in relation to the total. Whenever\n * somebody decides to collect the fees from the protocol, they get transferred\n * to a proxy contract which invests the funds in the lending pool and keeps\n * the pool tokens.\n *\n * The fee sharing proxy will be set as feesController of the protocol contract.\n * This allows the fee sharing proxy to withdraw the fees. The fee sharing\n * proxy holds the pool tokens and keeps track of which user owns how many\n * tokens. In order to know how many tokens a user owns, the fee sharing proxy\n * needs to know the user’s weighted stake in relation to the total weighted\n * stake (aka total voting power).\n *\n * Because both values are subject to change, they may be different on each fee\n * withdrawal. To be able to calculate a user’s share of tokens when he wants\n * to withdraw, we need checkpoints.\n *\n * This contract is intended to be set as the protocol fee collector.\n * Anybody can invoke the withdrawFees function which uses\n * protocol.withdrawFees to obtain available fees from operations on a\n * certain token. These fees are deposited in the corresponding loanPool.\n * Also, the staking contract sends slashed tokens to this contract.\n * When a user calls the withdraw function, the contract transfers the fee sharing\n * rewards in proportion to the user’s weighted stake since the last withdrawal.\n *\n * The protocol initially collects fees in all tokens.\n * Then the FeeSharingCollector wihtdraws fees from the protocol.\n * When the fees are withdrawn all the tokens except SOV will be converted to wRBTC\n * and then transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n * */\ncontract FeeSharingCollector is\n SafeMath96,\n IFeeSharingCollector,\n Ownable,\n FeeSharingCollectorStorage\n{\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n address constant ZERO_ADDRESS = address(0);\n address public constant RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT =\n address(uint160(uint256(keccak256(\"RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\"))));\n\n /* Events */\n\n /// @notice Deprecated event after the unification between wrbtc & rbtc\n // event FeeWithdrawn(address indexed sender, address indexed token, uint256 amount);\n event FeeWithdrawnInRBTC(address indexed sender, uint256 amount);\n\n /// @notice An event emitted when tokens transferred.\n event TokensTransferred(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when checkpoint added.\n event CheckpointAdded(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeWithdrawn(\n address indexed sender,\n address indexed receiver,\n address indexed token,\n uint256 amount\n );\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeProcessedNoWithdraw(\n address indexed sender,\n address indexed token,\n uint256 prevProcessedCheckpoints,\n uint256 newProcessedCheckpoints\n );\n\n /**\n * @notice An event emitted when fee from AMM get withdrawn.\n *\n * @param sender sender who initiate the withdrawn amm fees.\n * @param converter the converter address.\n * @param amount total amount of fee (Already converted to WRBTC).\n */\n event FeeAMMWithdrawn(address indexed sender, address indexed converter, uint256 amount);\n\n /// @notice An event emitted when converter address has been registered to be whitelisted.\n event WhitelistedConverter(address indexed sender, address converter);\n\n /// @notice An event emitted when converter address has been removed from whitelist.\n event UnwhitelistedConverter(address indexed sender, address converter);\n\n event RBTCWithdrawn(address indexed sender, address indexed receiver, uint256 amount);\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWrbtcToken,\n address indexed newWrbtcToken\n );\n\n event SetLoanTokenWrbtc(\n address indexed sender,\n address indexed oldLoanTokenWrbtc,\n address indexed newLoanTokenWrbtc\n );\n\n /* Modifier */\n modifier oneTimeExecution(bytes4 _funcSig) {\n require(\n !isFunctionExecuted[_funcSig],\n \"FeeSharingCollector: function can only be called once\"\n );\n _;\n isFunctionExecuted[_funcSig] = true;\n }\n\n /* Functions */\n\n /// @dev fallback function to support rbtc transfer when unwrap the wrbtc.\n function() external payable {}\n\n /**\n * @dev initialize function for fee sharing collector proxy\n * @param wrbtcToken wrbtc token address\n * @param loanWrbtcToken address of loan token wrbtc (IWrbtc)\n */\n function initialize(address wrbtcToken, address loanWrbtcToken)\n external\n onlyOwner\n oneTimeExecution(this.initialize.selector)\n {\n require(\n wrbtcTokenAddress == address(0) && loanTokenWrbtcAddress == address(0),\n \"wrbtcToken or loanWrbtcToken has been initialized\"\n );\n setWrbtcToken(wrbtcToken);\n setLoanTokenWrbtc(loanWrbtcToken);\n }\n\n /**\n * @notice Set the wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newWrbtcTokenAddress The new address of the wrbtc token.\n * */\n function setWrbtcToken(address newWrbtcTokenAddress) public onlyOwner {\n require(Address.isContract(newWrbtcTokenAddress), \"newWrbtcTokenAddress not a contract\");\n emit SetWrbtcToken(msg.sender, wrbtcTokenAddress, newWrbtcTokenAddress);\n wrbtcTokenAddress = newWrbtcTokenAddress;\n }\n\n /**\n * @notice Set the loan wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newLoanTokenWrbtcAddress The new address of the loan wrbtc token.\n * */\n function setLoanTokenWrbtc(address newLoanTokenWrbtcAddress) public onlyOwner {\n require(\n Address.isContract(newLoanTokenWrbtcAddress),\n \"newLoanTokenWrbtcAddress not a contract\"\n );\n emit SetLoanTokenWrbtc(msg.sender, loanTokenWrbtcAddress, newLoanTokenWrbtcAddress);\n loanTokenWrbtcAddress = newLoanTokenWrbtcAddress;\n }\n\n /**\n * @notice Withdraw fees for the given token:\n * lendingFee + tradingFee + borrowingFee\n * the fees (except SOV) will be converted in wRBTC form, and then will be transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n *\n * @param _tokens array address of the token\n * */\n function withdrawFees(address[] calldata _tokens) external {\n for (uint256 i = 0; i < _tokens.length; i++) {\n require(\n Address.isContract(_tokens[i]),\n \"FeeSharingCollector::withdrawFees: token is not a contract\"\n );\n }\n\n uint256 wrbtcAmountWithdrawn = protocol.withdrawFees(_tokens, address(this));\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap the wrbtc to rbtc, and hold the rbtc.\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFees: wrbtc token amount exceeds 96 bits\"\n );\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, amount96);\n }\n\n // note deprecated event since we unify the wrbtc & rbtc\n // emit FeeWithdrawn(msg.sender, RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, poolTokenAmount);\n\n // note new emitted event\n emit FeeWithdrawnInRBTC(msg.sender, wrbtcAmountWithdrawn);\n }\n\n /**\n * @notice Withdraw amm fees for the given converter addresses:\n * protocolFee from the conversion\n * the fees will be converted in wRBTC form, and then will be transferred to wRBTC loan pool\n *\n * @param _converters array addresses of the converters\n * */\n function withdrawFeesAMM(address[] memory _converters) public {\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n // Validate\n _validateWhitelistedConverter(_converters);\n\n uint96 totalPoolTokenAmount;\n for (uint256 i = 0; i < _converters.length; i++) {\n uint256 wrbtcAmountWithdrawn =\n IConverterAMM(_converters[i]).withdrawFees(address(this));\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap wrbtc to rbtc, and hold the rbtc\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFeesAMM: wrbtc token amount exceeds 96 bits\"\n );\n\n totalPoolTokenAmount = add96(\n totalPoolTokenAmount,\n amount96,\n \"FeeSharingCollector::withdrawFeesAMM: total wrbtc token amount exceeds 96 bits\"\n );\n\n emit FeeAMMWithdrawn(msg.sender, _converters[i], wrbtcAmountWithdrawn);\n }\n }\n\n if (totalPoolTokenAmount > 0) {\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, totalPoolTokenAmount);\n }\n }\n\n /**\n * @notice Transfer tokens to this contract.\n * @dev We just update amount of tokens here and write checkpoint in a separate methods\n * in order to prevent adding checkpoints too often.\n * @param _token Address of the token.\n * @param _amount Amount to be transferred.\n * */\n function transferTokens(address _token, uint96 _amount) public {\n require(_token != ZERO_ADDRESS, \"FeeSharingCollector::transferTokens: invalid address\");\n require(_amount > 0, \"FeeSharingCollector::transferTokens: invalid amount\");\n\n /// @notice Transfer tokens from msg.sender\n bool success = IERC20(_token).transferFrom(address(msg.sender), address(this), _amount);\n require(success, \"Staking::transferTokens: token transfer failed\");\n\n // if _token is wrbtc, need to unwrap it to rbtc\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n if (_token == address(wrbtcToken)) {\n wrbtcToken.withdraw(_amount);\n _token = RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT;\n }\n\n _addCheckpoint(_token, _amount);\n\n emit TokensTransferred(msg.sender, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC / native tokens to this contract.\n * @dev We just write checkpoint here (based on the rbtc value that is sent) in a separate methods\n * in order to prevent adding checkpoints too often.\n * */\n function transferRBTC() external payable {\n uint96 _amount = uint96(msg.value);\n require(_amount > 0, \"FeeSharingCollector::transferRBTC: invalid value\");\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, _amount);\n\n emit TokensTransferred(msg.sender, ZERO_ADDRESS, _amount);\n }\n\n /**\n * @notice Add checkpoint with accumulated amount by function invocation.\n * @param _token Address of the token.\n * */\n function _addCheckpoint(address _token, uint96 _amount) internal {\n if (block.timestamp - lastFeeWithdrawalTime[_token] >= FEE_WITHDRAWAL_INTERVAL) {\n lastFeeWithdrawalTime[_token] = block.timestamp;\n uint96 amount =\n add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: amount exceeds 96 bits\"\n );\n\n /// @notice Reset unprocessed amount of tokens to zero.\n unprocessedAmount[_token] = 0;\n\n /// @notice Write a regular checkpoint.\n _writeTokenCheckpoint(_token, amount);\n } else {\n unprocessedAmount[_token] = add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: unprocessedAmount exceeds 96 bits\"\n );\n }\n }\n\n function _withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n /// @dev Prevents block gas limit hit when processing checkpoints\n require(\n _maxCheckpoints > 0,\n \"FeeSharingCollector::withdraw: _maxCheckpoints should be positive\"\n );\n\n address user = msg.sender;\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n uint256 processedUserCheckpoints = processedCheckpoints[user][_token];\n (uint256 amount, uint256 end) =\n _getAccumulatedFees(user, _token, processedUserCheckpoints, _maxCheckpoints);\n if (amount == 0) {\n if (end > processedUserCheckpoints) {\n emit UserFeeProcessedNoWithdraw(msg.sender, _token, processedUserCheckpoints, end);\n processedCheckpoints[user][_token] = end;\n return (0, end);\n } else {\n // getting here most likely means smth wrong with the state\n revert(\"FeeSharingCollector::withdrawFees: no tokens for withdrawal\");\n }\n }\n\n processedCheckpoints[user][_token] = end;\n if (loanTokenWrbtcAddress == _token) {\n // We will change, so that feeSharingCollector will directly burn then loanToken (IWRBTC) to rbtc and send to the user --- by call burnToBTC function\n ILoanTokenWRBTC(_token).burnToBTC(_receiver, amount, false);\n } else {\n // Previously it directly send the loanToken to the user\n require(\n IERC20(_token).transfer(_receiver, amount),\n \"FeeSharingCollector::withdraw: withdrawal failed\"\n );\n }\n\n emit UserFeeWithdrawn(msg.sender, _receiver, _token, amount);\n\n return (amount, end);\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power. Therefore, staking more\n * SOV and/or staking for longer will increase your share of the fees\n * generated, meaning you will earn more from staking.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed. Must be positive value.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public nonReentrant {\n _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n /// @notice Validates if the checkpoint is payable for the user\n function validFromCheckpointsParam(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n address _user\n ) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n // _fromCheckpoint is checkpoint number, not array index, so should be > 1\n require(tokenData.fromCheckpoint > 1, \"_fromCheckpoint param must be > 1\");\n uint256 fromCheckpointIndex = tokenData.fromCheckpoint - 1;\n require(\n tokenData.fromCheckpoint > processedCheckpoints[_user][tokenData.tokenAddress],\n \"_fromCheckpoint param must be > userProcessedCheckpoints\"\n );\n require(\n tokenData.fromCheckpoint <= totalTokenCheckpoints[tokenData.tokenAddress],\n \"_fromCheckpoint should be <= totalTokenCheckpoints\"\n );\n\n Checkpoint memory prevCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex - 1];\n\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n prevCheckpoint.blockNumber - 1,\n prevCheckpoint.timestamp\n );\n require(\n weightedStake == 0,\n \"User weighted stake should be zero at previous checkpoint\"\n );\n\n Checkpoint memory fromCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex];\n weightedStake = staking.getPriorWeightedStake(\n _user,\n fromCheckpoint.blockNumber - 1,\n fromCheckpoint.timestamp\n );\n\n require(weightedStake > 0, \"User weighted stake should be > 0 at _fromCheckpoint\");\n }\n }\n\n function validRBTCBasedTokens(address[] memory _tokens) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n address _token = _tokens[i];\n if (\n _token != RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT &&\n _token != wrbtcTokenAddress &&\n _token != loanTokenWrbtcAddress\n ) {\n revert(\"only rbtc-based tokens are allowed\");\n }\n }\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender/receiver.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @dev WARNING! This function skips all the checkpoints before '_fromCheckpoint' irreversibly, use with care\n *\n * @param _tokens Array of TokenWithSkippedCheckpointsWithdraw struct, which contains the token address, and fromCheckpoiint\n * fromCheckpoints Skips all the checkpoints before '_fromCheckpoint'\n * should be calculated offchain with getNextPositiveUserCheckpoint function\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n *\n * @return total processed checkpoints\n * */\n function _withdrawStartingFromCheckpoints(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validFromCheckpointsParam(_tokens, msg.sender);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n if (_maxCheckpoints == 0) break;\n uint256 endToken;\n uint256 totalAmount;\n\n uint256 previousProcessedUserCheckpoints =\n processedCheckpoints[msg.sender][tokenData.tokenAddress];\n uint256 startingCheckpoint =\n tokenData.fromCheckpoint > previousProcessedUserCheckpoints\n ? tokenData.fromCheckpoint\n : previousProcessedUserCheckpoints;\n\n if (\n tokenData.tokenAddress == wrbtcTokenAddress ||\n tokenData.tokenAddress == loanTokenWrbtcAddress ||\n tokenData.tokenAddress == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\n ) {\n (totalAmount, endToken) = _withdrawRbtcTokenStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n } else {\n (, endToken) = _withdrawStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n }\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint).add(1);\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n if (rbtcAmountToSend > 0) {\n // send all rbtc withdrawal\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Function to wrap:\n * 1. regular withdrawal for both rbtc & non-rbtc token\n * 2. skipped checkpoints withdrawal for both rbtc & non-rbtc token\n *\n * @param _nonRbtcTokensRegularWithdraw array of non-rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _rbtcTokensRegularWithdraw array of rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _tokensWithSkippedCheckpoints array of rbtc & non-rbtc TokenWithSkippedCheckpointsWithdraw struct, which has skipped checkpoints that will be withdrawn\n *\n */\n function claimAllCollectedFees(\n address[] calldata _nonRbtcTokensRegularWithdraw,\n address[] calldata _rbtcTokensRegularWithdraw,\n TokenWithSkippedCheckpointsWithdraw[] calldata _tokensWithSkippedCheckpoints,\n uint32 _maxCheckpoints,\n address _receiver\n ) external nonReentrant {\n uint256 totalProcessedCheckpoints;\n\n /** Process normal multiple withdrawal for RBTC based tokens */\n if (_rbtcTokensRegularWithdraw.length > 0) {\n totalProcessedCheckpoints = _withdrawRbtcTokens(\n _rbtcTokensRegularWithdraw,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process normal non-rbtc token withdrawal */\n for (uint256 i = 0; i < _nonRbtcTokensRegularWithdraw.length; i++) {\n if (_maxCheckpoints == 0) break;\n uint256 endTokenCheckpoint;\n\n address _nonRbtcTokenAddress = _nonRbtcTokensRegularWithdraw[i];\n\n /** starting checkpoint is the previous processedCheckpoints for token */\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_nonRbtcTokenAddress];\n\n (, endTokenCheckpoint) = _withdraw(_nonRbtcTokenAddress, _maxCheckpoints, _receiver);\n\n uint256 _previousUsedCheckpoint = endTokenCheckpoint.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n _previousUsedCheckpoint.add(1);\n }\n\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process token with skipped checkpoints withdrawal */\n if (_tokensWithSkippedCheckpoints.length > 0) {\n totalProcessedCheckpoints = _withdrawStartingFromCheckpoints(\n _tokensWithSkippedCheckpoints,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n }\n\n function _withdrawStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10 meaning we should set 9 user's processed checkpoints\n // after _withdraw() the user's processedCheckpoints should be 10\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n (totalAmount, endTokenCheckpoint) = _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function _withdrawRbtcToken(address _token, uint32 _maxCheckpoints)\n internal\n returns (uint256 totalAmount, uint256 endTokenCheckpoint)\n {\n address user = msg.sender;\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n (totalAmount, endTokenCheckpoint) = _getRBTCBalance(_token, user, _maxCheckpoints);\n\n if (totalAmount > 0) {\n processedCheckpoints[user][_token] = endTokenCheckpoint;\n if (_token == address(wrbtcToken)) {\n // unwrap the wrbtc\n wrbtcToken.withdraw(totalAmount);\n } else if (_token == loanTokenWrbtcAddress) {\n // pull out the iWRBTC to rbtc to this feeSharingCollector contract\n /** @dev will use the burned result from IWRBTC to RBTC as return total amount */\n totalAmount = ILoanTokenWRBTC(loanTokenWrbtcAddress).burnToBTC(\n address(this),\n totalAmount,\n false\n );\n }\n }\n }\n\n /**\n * @dev withdraw all of the RBTC balance based on particular checkpoints\n *\n * This function will withdraw RBTC balance which is passed as _token param, so it could be either of these:\n * - rbtc balance or\n * - wrbtc balance which will be unwrapped to rbtc or\n * - iwrbtc balance which will be unwrapped to rbtc or\n *\n *\n * @param _tokens array of either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _maxCheckpoints Maximum number of checkpoints to be processed to workaround block gas limit\n * @param _receiver An optional tokens receiver (msg.sender used if 0)\n */\n function _withdrawRbtcTokens(\n address[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validRBTCBasedTokens(_tokens);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n if (_maxCheckpoints == 0) break;\n address _token = _tokens[i];\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_token];\n\n (uint256 totalAmount, uint256 endToken) =\n _withdrawRbtcToken(_tokens[i], _maxCheckpoints);\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n // we only need to add used checkpoint by 1 only if starting checkpoint > 0\n _previousUsedCheckpoint.add(1);\n }\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n // send all rbtc\n if (rbtcAmountToSend > 0) {\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Withdraw either specific RBTC related token balance or all RBTC related tokens balances.\n * RBTC related here means, it could be either rbtc, wrbtc, or iwrbtc, depends on the _token param.\n */\n function _withdrawRbtcTokenStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) private returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10\n // after _withdraw() user's processedCheckpoints should be 10 =>\n // set processed checkpoints = 9, next maping index = 9 (10th checkpoint)\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n return _withdrawRbtcToken(_token, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n external\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n return _getNextPositiveUserCheckpoint(_user, _token, _startFrom, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function _getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n internal\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n if (staking.isVestingContract(_user)) {\n return (0, false, false);\n }\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n\n if (processedUserCheckpoints >= totalCheckpoints || totalCheckpoints == 0) {\n return (totalCheckpoints, false, false);\n }\n\n uint256 startFrom =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n\n uint256 end = startFrom.add(_maxCheckpoints);\n if (end >= totalCheckpoints) {\n end = totalCheckpoints;\n }\n\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startFrom; i < end; i++) {\n Checkpoint storage tokenCheckpoint = tokenCheckpoints[_token][i];\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n tokenCheckpoint.blockNumber - 1,\n tokenCheckpoint.timestamp\n );\n if (weightedStake > 0) {\n // i is the index and we need to return checkpoint num which is i + 1\n return (i + 1, i > processedUserCheckpoints, true);\n }\n }\n return (end, end > processedUserCheckpoints, false);\n }\n\n /**\n * @notice Get the accumulated loan pool fee of the message sender.\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @return The accumulated fee for the message sender.\n * */\n function getAccumulatedFees(address _user, address _token) public view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: 0\n });\n return amount;\n }\n\n /**\n * @notice Get the accumulated fee rewards for the message sender for a checkpoints range\n *\n * @dev This function is required to keep consistent with caching of weighted voting power when claiming fees\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The accumulated fees rewards for the _user in the given checkpoints interval: [_startFrom, _startFrom + maxCheckpoints].\n * */\n function getAccumulatedFeesForCheckpointsRange(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees(_user, _token, _startFrom, _maxCheckpoints);\n return amount;\n }\n\n /**\n * @dev Get all user fees reward per maxCheckpoint starting from latest processed checkpoint\n *\n * @dev e.g: Total user checkpoint for the particualar token = 300,\n * when we call this function with 50 maxCheckpoint, it will return 6 fee values in array form.\n * if there is no more fees, it will return empty array.\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The next checkpoint num which is the starting point to fetch all of the fees, array of calculated fees.\n * */\n function getAllUserFeesPerMaxCheckpoints(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256[] memory fees) {\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 totalTokensCheckpointsIndex = totalCheckpoints > 0 ? totalCheckpoints - 1 : 0;\n\n if (totalTokensCheckpointsIndex < _startFrom) return fees;\n\n uint256 arrSize = totalTokensCheckpointsIndex.sub(_startFrom).div(_maxCheckpoints) + 1;\n\n fees = new uint256[](arrSize);\n\n for (uint256 i = 0; i < fees.length; i++) {\n (uint256 fee, ) =\n _getAccumulatedFees(\n _user,\n _token,\n _startFrom + i * _maxCheckpoints,\n _maxCheckpoints\n );\n fees[i] = fee;\n }\n\n return fees;\n }\n\n /**\n * @notice Gets accumulated fees for a user starting from a given checkpoint\n *\n * @param _user Address of the user's account.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Max checkpoints to process at once to fit into block gas limit\n * @param _startFrom Checkpoint num to start calculations from\n *\n * @return feesAmount - accumulated fees amount\n * @return endCheckpoint - last checkpoint of fees calculation\n * */\n function _getAccumulatedFees(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 feesAmount, uint256 endCheckpoint) {\n if (staking.isVestingContract(_user)) {\n return (0, 0);\n }\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n uint256 startOfRange =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n endCheckpoint = _maxCheckpoints > 0\n ? _getEndOfRange(startOfRange, _token, _maxCheckpoints)\n : totalTokenCheckpoints[_token];\n\n if (startOfRange >= totalTokenCheckpoints[_token]) {\n return (0, endCheckpoint);\n }\n\n uint256 cachedLockDate = 0;\n uint96 cachedWeightedStake = 0;\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startOfRange; i < endCheckpoint; i++) {\n Checkpoint memory checkpoint = tokenCheckpoints[_token][i];\n uint256 lockDate = staking.timestampToLockDate(checkpoint.timestamp);\n uint96 weightedStake;\n if (lockDate == cachedLockDate) {\n weightedStake = cachedWeightedStake;\n } else {\n /// @dev We need to use \"checkpoint.blockNumber - 1\" here to calculate weighted stake\n /// For the same block like we did for total voting power in _writeTokenCheckpoint\n weightedStake = staking.getPriorWeightedStake(\n _user,\n checkpoint.blockNumber - 1,\n checkpoint.timestamp\n );\n cachedWeightedStake = weightedStake;\n cachedLockDate = lockDate;\n }\n uint256 share =\n uint256(checkpoint.numTokens).mul(weightedStake).div(\n uint256(checkpoint.totalWeightedStake)\n );\n feesAmount = feesAmount.add(share);\n }\n return (feesAmount, endCheckpoint);\n }\n\n /**\n * @notice Withdrawal should only be possible for blocks which were already\n * mined. If the fees are withdrawn in the same block as the user withdrawal\n * they are not considered by the withdrawing logic (to avoid inconsistencies).\n *\n * @param _start Start of the range.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of a pool token.\n * @param _maxCheckpoints Checkpoint index incremental.\n * */\n function _getEndOfRange(\n uint256 _start,\n address _token,\n uint32 _maxCheckpoints\n ) internal view returns (uint256) {\n uint256 nextCheckpointIndex = totalTokenCheckpoints[_token];\n if (nextCheckpointIndex == 0) {\n return 0;\n }\n uint256 end;\n\n if (_maxCheckpoints == 0) {\n /// @dev All checkpoints will be processed (only for getter outside of a transaction).\n end = nextCheckpointIndex;\n } else {\n end = safe32(\n _start + _maxCheckpoints,\n \"FeeSharingCollector::withdraw: checkpoint index exceeds 32 bits\"\n );\n if (end > nextCheckpointIndex) {\n end = nextCheckpointIndex;\n }\n }\n\n /// @dev Withdrawal should only be possible for blocks which were already mined.\n uint32 lastBlockNumber = tokenCheckpoints[_token][end - 1].blockNumber;\n if (block.number == lastBlockNumber) {\n end--;\n }\n return end;\n }\n\n /**\n * @notice Write a regular checkpoint w/ the foolowing data:\n * block number, block timestamp, total weighted stake and num of tokens.\n * @param _token The pool token address.\n * @param _numTokens The amount of pool tokens.\n * */\n function _writeTokenCheckpoint(address _token, uint96 _numTokens) internal {\n uint32 blockNumber =\n safe32(\n block.number,\n \"FeeSharingCollector::_writeCheckpoint: block number exceeds 32 bits\"\n );\n uint32 blockTimestamp =\n safe32(\n block.timestamp,\n \"FeeSharingCollector::_writeCheckpoint: block timestamp exceeds 32 bits\"\n );\n uint256 nextCheckpointsIndex = totalTokenCheckpoints[_token];\n\n uint96 totalWeightedStake = _getVoluntaryWeightedStake(blockNumber - 1, block.timestamp);\n require(totalWeightedStake > 0, \"Invalid totalWeightedStake\");\n if (\n nextCheckpointsIndex > 0 &&\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].blockNumber == blockNumber\n ) {\n tokenCheckpoints[_token][nextCheckpointsIndex - 1]\n .totalWeightedStake = totalWeightedStake;\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].numTokens = _numTokens;\n } else {\n tokenCheckpoints[_token][nextCheckpointsIndex] = Checkpoint(\n blockNumber,\n blockTimestamp,\n totalWeightedStake,\n _numTokens\n );\n totalTokenCheckpoints[_token] = nextCheckpointsIndex + 1;\n }\n emit CheckpointAdded(msg.sender, _token, _numTokens);\n }\n\n /**\n * Queries the total weighted stake and the weighted stake of vesting contracts and returns the difference\n * @param blockNumber the blocknumber\n * @param timestamp the timestamp\n */\n function _getVoluntaryWeightedStake(uint32 blockNumber, uint256 timestamp)\n internal\n view\n returns (uint96 totalWeightedStake)\n {\n uint96 vestingWeightedStake = staking.getPriorVestingWeightedStake(blockNumber, timestamp);\n totalWeightedStake = staking.getPriorTotalVotingPower(blockNumber, timestamp);\n totalWeightedStake = sub96(\n totalWeightedStake,\n vestingWeightedStake,\n \"FeeSharingCollector::_getTotalVoluntaryWeightedStake: vested stake exceeds total stake\"\n );\n }\n\n /**\n * @dev Whitelisting converter address.\n *\n * @param converterAddress converter address to be whitelisted.\n */\n function addWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n require(Address.isContract(converterAddress), \"Non contract address given\");\n whitelistedConverterList.add(converterAddress);\n emit WhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @dev Removing converter address from whitelist.\n *\n * @param converterAddress converter address to be removed from whitelist.\n */\n function removeWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n whitelistedConverterList.remove(converterAddress);\n emit UnwhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @notice Getter to query all of the whitelisted converter.\n * @return All of the whitelisted converter list.\n */\n function getWhitelistedConverterList() external view returns (address[] memory converterList) {\n converterList = whitelistedConverterList.enumerate();\n }\n\n /**\n * @dev validate array of given address whether is whitelisted or not.\n * @dev if one of them is not whitelisted, then revert.\n *\n * @param converterAddresses array of converter addresses.\n */\n function _validateWhitelistedConverter(address[] memory converterAddresses) private view {\n for (uint256 i = 0; i < converterAddresses.length; i++) {\n require(whitelistedConverterList.contains(converterAddresses[i]), \"Invalid Converter\");\n }\n }\n\n function withdrawWRBTC(address receiver, uint256 wrbtcAmount) external onlyOwner {\n IERC20 wrbtcToken = IERC20(wrbtcTokenAddress);\n\n uint256 balance = wrbtcToken.balanceOf(address(this));\n require(wrbtcAmount <= balance, \"Insufficient balance\");\n\n wrbtcToken.safeTransfer(receiver, wrbtcAmount);\n }\n\n /**\n * @dev This function is dedicated to recover the wrong fee allocation for the 4 year vesting contracts.\n * This function can only be called once\n * The affected tokens to be withdrawn\n * 1. RBTC\n * 2. ZUSD\n * 3. SOV\n * The amount for all of the tokens above is hardcoded\n * The withdrawn tokens will be sent to the owner.\n */\n function recoverIncorrectAllocatedFees()\n external\n oneTimeExecution(this.recoverIncorrectAllocatedFees.selector)\n onlyOwner\n {\n uint256 rbtcAmount = 878778886164898400;\n uint256 zusdAmount = 16658600400155126000000;\n uint256 sovAmount = 6275898259771202000000;\n\n address zusdToken = 0xdB107FA69E33f05180a4C2cE9c2E7CB481645C2d;\n address sovToken = 0xEFc78fc7d48b64958315949279Ba181c2114ABBd;\n\n // Withdraw rbtc\n (bool success, ) = owner().call.value(rbtcAmount)(\"\");\n require(\n success,\n \"FeeSharingCollector::recoverIncorrectAllocatedFees: Withdrawal rbtc failed\"\n );\n\n // Withdraw ZUSD\n IERC20(zusdToken).safeTransfer(owner(), zusdAmount);\n\n // Withdraw SOV\n IERC20(sovToken).safeTransfer(owner(), sovAmount);\n }\n\n /**\n * @dev view function that calculate the total RBTC that includes:\n * - RBTC\n * - WRBTC\n * - iWRBTC * iWRBTC.tokenPrice()\n * @param _user address of the user.\n * @return rbtc balance of the given user's address.\n */\n function getAccumulatedRBTCFeeBalances(address _user) external view returns (uint256) {\n (uint256 _rbtcAmount, uint256 _wrbtcAmount, uint256 _iWrbtcAmount, , , ) =\n _getRBTCBalances(_user, 0);\n uint256 iWRBTCAmountInRBTC =\n _iWrbtcAmount.mul(ILoanTokenWRBTC(loanTokenWrbtcAddress).tokenPrice()).div(1e18);\n return _rbtcAmount.add(_wrbtcAmount).add(iWRBTCAmountInRBTC);\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _rbtcAmount rbtc amount\n * @return _wrbtcAmount wrbtc amount\n * @return _iWrbtcAmount iWrbtc (wrbtc lending pool token) amount * token price\n * @return _endRBTC end time of accumulated fee calculation for rbtc\n * @return _endWRBTC end time of accumulated fee calculation for wrbtc\n * @return _endIWRBTC end time of accumulated fee calculation for iwrbtc\n */\n function _getRBTCBalances(address _user, uint32 _maxCheckpoints)\n private\n view\n returns (\n uint256 _rbtcAmount,\n uint256 _wrbtcAmount,\n uint256 _iWrbtcAmount,\n uint256 _endRBTC,\n uint256 _endWRBTC,\n uint256 _endIWRBTC\n )\n {\n (_rbtcAmount, _endRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n\n (_wrbtcAmount, _endWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: wrbtcTokenAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n (_iWrbtcAmount, _endIWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: loanTokenWrbtcAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _token either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _tokenAmount token (rbtc, or wrbtc, or iwrbtc) amount\n * @return _endToken end time of accumulated fee calculation for token (rbtc, or wrbtc, or iwrbtc )\n */\n function _getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 _tokenAmount, uint256 _endToken) {\n if (\n _token == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT ||\n _token == wrbtcTokenAddress ||\n _token == loanTokenWrbtcAddress\n ) {\n (_tokenAmount, _endToken) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n } else {\n revert(\"FeeSharingCollector::_getRBTCBalance: only rbtc-based tokens are allowed\");\n }\n }\n\n // @todo update dependency `numTokenCheckpoints` -> `totalTokenCheckpoints` and deprecate numTokenCheckpoints function\n /**\n * @dev This getter function `numTokenCheckpoints` is added for backwards compatibility\n * broken when renamed `numTokenCheckpoints` storage variable to `totalTokenCheckpoints`.\n *\n * @param _token token address to get checkpoints for\n *\n * @return Total token checkpoints\n */\n function numTokenCheckpoints(address _token) external view returns (uint256) {\n return totalTokenCheckpoints[_token];\n }\n}\n\n/* Interfaces */\ninterface ILoanToken {\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n}\n\ninterface ILoanTokenWRBTC {\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function tokenPrice() external view returns (uint256 price);\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title FeeSharingCollectorProxy contract.\n * @dev FeeSharingCollectorProxy contract should be upgradable, use UpgradableProxy.\n * FeeSharingCollectorStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract FeeSharingCollectorProxy is FeeSharingCollectorStorage, UpgradableProxy {\n /**\n * @notice Construct a new feeSharingCollectorProxy contract.\n * @param _protocol The address of the sovryn protocol.\n * @param _staking The address of the staking\n */\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorStorage.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../mixins/EnumerableAddressSet.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\n\n/**\n * @title FeeSharingCollectorStorage contact\n * @notice Just the storage part of FeeSharingCollector contract, and FeeSharingCollectorProxy. No functions,\n * only constant, variables and required structures (mappings)\n * */\ncontract FeeSharingCollectorStorage is Ownable {\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet;\n uint256 constant FEE_WITHDRAWAL_INTERVAL = 172800;\n\n IProtocol public protocol;\n IStaking public staking;\n\n /// @notice Checkpoints by index per pool token address\n mapping(address => mapping(uint256 => Checkpoint)) public tokenCheckpoints;\n\n /// @notice The number of checkpoints for each token address.\n mapping(address => uint256) public totalTokenCheckpoints;\n\n /// @notice\n /// user => token => processed checkpoints\n mapping(address => mapping(address => uint256)) public processedCheckpoints;\n\n /// @notice Last time fees were withdrawn per pool token address:\n /// token => time\n mapping(address => uint256) public lastFeeWithdrawalTime;\n\n /// @notice Amount of tokens that were transferred, but not saved in checkpoints.\n /// token => amount\n mapping(address => uint96) public unprocessedAmount;\n\n struct Checkpoint {\n uint32 blockNumber;\n uint32 timestamp;\n uint96 totalWeightedStake;\n uint96 numTokens;\n }\n\n struct TokenWithSkippedCheckpointsWithdraw {\n address tokenAddress;\n uint256 fromCheckpoint;\n }\n\n /**\n * @dev Add extra modifier (Reentrancy) below.\n * Because we cannot add any additional storage slot before this storage contract after initial deployment\n */\n\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Additional storage for converter whitelist mechanism.\n * @dev Initialization here does not works. We need to create a separate setter & getter.\n * @dev Just set the visibility to internal should be fine.\n */\n EnumerableAddressSet.AddressSet internal whitelistedConverterList;\n\n mapping(bytes4 => bool) public isFunctionExecuted;\n\n /**\n * @dev Wrbtc token address\n */\n address public wrbtcTokenAddress;\n\n /**\n * @dev iWrbtc loan token address\n */\n address public loanTokenWrbtcAddress;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n\n/* Interfaces */\n\ninterface IProtocol {\n /**\n *\n * @param tokens The array address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function underlyingToLoanPool(address token) external view returns (address);\n\n function wrbtcToken() external view returns (IWrbtcERC20);\n\n function getSovTokenAddress() external view returns (address);\n}\n" + }, + "contracts/governance/GovernorAlpha.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./Staking/SafeMath96.sol\";\nimport \"./Timelock.sol\";\nimport \"./Staking/interfaces/IStaking.sol\";\nimport \"../rsk/RSKAddrValidator.sol\";\n\n/**\n * @title Governance Contract.\n * @notice This is an adapted clone of compound’s governance model. In general,\n * the process is the same: Token holders can make (executable) proposals if\n * they possess enough voting power, vote on proposals during a predefined\n * voting period and in the end evaluate the outcome. If successful, the\n * proposal will be scheduled on the timelock contract. Only after sufficient\n * time passed, it can be executed. A minimum voting power is required for\n * making a proposal as well as a minimum quorum.\n *\n * Voting power in the Bitocracy:\n * Stakers will receive voting power in the Bitocracy in return for their\n * staking commitment. This voting power is weighted by how much SOV is staked\n * and for how long the staking period is - staking more SOV over longer staking\n * periods results in higher voting power. With this voting power, users can\n * vote for or against any SIP in bitocracy.sovryn.app.\n * */\ncontract GovernorAlpha is SafeMath96 {\n /* Storage */\n\n /// @notice The name of this contract.\n string public constant NAME = \"Sovryn Governor Alpha\";\n\n /// @notice The maximum number of actions that can be included in a proposal.\n function proposalMaxOperations() public pure returns (uint256) {\n return 10;\n } // 10 actions\n\n /// @notice The delay before voting on a proposal may take place, once proposed.\n function votingDelay() public pure returns (uint256) {\n return 1;\n } // 1 block\n\n /// @notice The duration of voting on a proposal, in blocks.\n function votingPeriod() public pure returns (uint256) {\n return 2880;\n } // ~1 day in blocks (assuming 30s blocks)\n\n /// @notice The address of the Sovryn Protocol Timelock.\n ITimelock public timelock;\n\n /// @notice The address of the Sovryn staking contract.\n IStaking public staking;\n\n /// @notice The address of the Governor Guardian.\n address public guardian;\n\n /// @notice The total number of proposals.\n uint256 public proposalCount;\n\n /// @notice Percentage of current total voting power require to vote.\n uint96 public quorumPercentageVotes;\n\n // @notice Majority percentage.\n uint96 public majorityPercentageVotes;\n\n struct Proposal {\n /// @notice Unique id for looking up a proposal.\n uint256 id;\n /// @notice The block at which voting begins: holders must delegate their votes prior to this block.\n uint32 startBlock;\n /// @notice The block at which voting ends: votes must be cast prior to this block.\n uint32 endBlock;\n /// @notice Current number of votes in favor of this proposal.\n uint96 forVotes;\n /// @notice Current number of votes in opposition to this proposal.\n uint96 againstVotes;\n ///@notice the quorum required for this proposal.\n uint96 quorum;\n ///@notice the majority percentage required for this proposal.\n uint96 majorityPercentage;\n /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds.\n uint64 eta;\n /// @notice the start time is required for the staking contract.\n uint64 startTime;\n /// @notice Flag marking whether the proposal has been canceled.\n bool canceled;\n /// @notice Flag marking whether the proposal has been executed.\n bool executed;\n /// @notice Creator of the proposal.\n address proposer;\n /// @notice the ordered list of target addresses for calls to be made.\n address[] targets;\n /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made.\n uint256[] values;\n /// @notice The ordered list of function signatures to be called.\n string[] signatures;\n /// @notice The ordered list of calldata to be passed to each call.\n bytes[] calldatas;\n /// @notice Receipts of ballots for the entire set of voters.\n mapping(address => Receipt) receipts;\n }\n\n /// @notice Ballot receipt record for a voter\n struct Receipt {\n /// @notice Whether or not a vote has been cast.\n bool hasVoted;\n /// @notice Whether or not the voter supports the proposal.\n bool support;\n /// @notice The number of votes the voter had, which were cast.\n uint96 votes;\n }\n\n /// @notice Possible states that a proposal may be in.\n enum ProposalState {\n Pending,\n Active,\n Canceled,\n Defeated,\n Succeeded,\n Queued,\n Expired,\n Executed\n }\n\n /// @notice The official record of all proposals ever proposed.\n mapping(uint256 => Proposal) public proposals;\n\n /// @notice The latest proposal for each proposer.\n mapping(address => uint256) public latestProposalIds;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the ballot struct used by the contract.\n bytes32 public constant BALLOT_TYPEHASH = keccak256(\"Ballot(uint256 proposalId,bool support)\");\n\n /* Events */\n\n /// @notice An event emitted when a new proposal is created.\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint256 startBlock,\n uint256 endBlock,\n string description\n );\n\n /// @notice An event emitted when a vote has been cast on a proposal.\n event VoteCast(address voter, uint256 proposalId, bool support, uint256 votes);\n\n /// @notice An event emitted when a proposal has been canceled.\n event ProposalCanceled(uint256 id);\n\n /// @notice An event emitted when a proposal has been queued in the Timelock.\n event ProposalQueued(uint256 id, uint256 eta);\n\n /// @notice An event emitted when a proposal has been executed in the Timelock.\n event ProposalExecuted(uint256 id);\n\n /* Functions */\n\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 _quorumPercentageVotes,\n uint96 _majorityPercentageVotes\n ) public {\n timelock = ITimelock(timelock_);\n staking = IStaking(staking_);\n guardian = guardian_;\n quorumPercentageVotes = _quorumPercentageVotes;\n majorityPercentageVotes = _majorityPercentageVotes;\n }\n\n /// @notice The number of votes required in order for a voter to become a proposer.\n function proposalThreshold() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(\n block.number - 1,\n \"GovernorAlpha::proposalThreshold: block number overflow\"\n ),\n block.timestamp\n );\n // 1% of current total voting power.\n return totalVotingPower / 100;\n }\n\n /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.\n function quorumVotes() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(block.number - 1, \"GovernorAlpha::quorumVotes: block number overflow\"),\n block.timestamp\n );\n // 4% of current total voting power.\n return\n mul96(\n quorumPercentageVotes,\n totalVotingPower,\n \"GovernorAlpha::quorumVotes:multiplication overflow\"\n ) / 100;\n }\n\n /**\n * @notice Create a new proposal.\n * @param targets Array of contract addresses to perform proposal execution.\n * @param values Array of rBTC amounts to send on proposal execution.\n * @param signatures Array of function signatures to call on proposal execution.\n * @param calldatas Array of payloads for the calls on proposal execution.\n * @param description Text describing the purpose of the proposal.\n * */\n function propose(\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // note: passing this block's timestamp, but the number of the previous block.\n // todo: think if it would be better to pass block.timestamp - 30 (average block time)\n // (probably not because proposal starts in 1 block from now).\n uint96 threshold = proposalThreshold();\n require(\n staking.getPriorVotes(msg.sender, sub256(block.number, 1), block.timestamp) >\n threshold,\n \"GovernorAlpha::propose: proposer votes below proposal threshold\"\n );\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"GovernorAlpha::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"GovernorAlpha::propose: must provide actions\");\n require(\n targets.length <= proposalMaxOperations(),\n \"GovernorAlpha::propose: too many actions\"\n );\n\n uint256 latestProposalId = latestProposalIds[msg.sender];\n if (latestProposalId != 0) {\n ProposalState proposersLatestProposalState = state(latestProposalId);\n require(\n proposersLatestProposalState != ProposalState.Active,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already active proposal\"\n );\n require(\n proposersLatestProposalState != ProposalState.Pending,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal\"\n );\n }\n\n uint256 startBlock = add256(block.number, votingDelay());\n uint256 endBlock = add256(startBlock, votingPeriod());\n\n proposalCount++;\n\n /// @dev quorum: proposalThreshold is 1% of total votes, we can save gas using this pre calculated value.\n /// @dev startTime: Required by the staking contract. not used by the governance contract itself.\n Proposal memory newProposal =\n Proposal({\n id: proposalCount,\n startBlock: safe32(\n startBlock,\n \"GovernorAlpha::propose: start block number overflow\"\n ),\n endBlock: safe32(endBlock, \"GovernorAlpha::propose: end block number overflow\"),\n forVotes: 0,\n againstVotes: 0,\n quorum: mul96(\n quorumPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on quorum computation\"\n ),\n majorityPercentage: mul96(\n majorityPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on majorityPercentage computation\"\n ),\n eta: 0,\n startTime: safe64(block.timestamp, \"GovernorAlpha::propose: startTime overflow\"),\n canceled: false,\n executed: false,\n proposer: msg.sender,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas\n });\n\n proposals[newProposal.id] = newProposal;\n latestProposalIds[newProposal.proposer] = newProposal.id;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n values,\n signatures,\n calldatas,\n startBlock,\n endBlock,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Enqueue a proposal and everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function queue(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Succeeded,\n \"GovernorAlpha::queue: proposal can only be queued if it is succeeded\"\n );\n Proposal storage proposal = proposals[proposalId];\n uint256 eta = add256(block.timestamp, timelock.delay());\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n proposal.eta = safe64(eta, \"GovernorAlpha::queue: ETA overflow\");\n emit ProposalQueued(proposalId, eta);\n }\n\n /**\n * @notice Tries to enqueue a proposal, verifying it has not been previously queued.\n * @param target Contract addresses to perform proposal execution.\n * @param value rBTC amount to send on proposal execution.\n * @param signature Function signature to call on proposal execution.\n * @param data Payload for the call on proposal execution.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function _queueOrRevert(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !timelock.queuedTransactions(\n keccak256(abi.encode(target, value, signature, data, eta))\n ),\n \"GovernorAlpha::_queueOrRevert: proposal action already queued at eta\"\n );\n timelock.queueTransaction(target, value, signature, data, eta);\n }\n\n /**\n * @notice Execute a proposal by looping and performing everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function execute(uint256 proposalId) public payable {\n require(\n state(proposalId) == ProposalState.Queued,\n \"GovernorAlpha::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.executeTransaction.value(proposal.values[i])(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal by looping and cancelling everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function cancel(uint256 proposalId) public {\n ProposalState state = state(proposalId);\n require(\n state != ProposalState.Executed,\n \"GovernorAlpha::cancel: cannot cancel executed proposal\"\n );\n\n Proposal storage proposal = proposals[proposalId];\n /// @notice Cancel only if sent by the guardian.\n require(msg.sender == guardian, \"GovernorAlpha::cancel: sender isn't a guardian\");\n\n proposal.canceled = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalCanceled(proposalId);\n }\n\n /**\n * @notice Get a proposal list of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return Arrays of the 4 call parameters: targets, values, signatures, calldatas.\n * */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.values, p.signatures, p.calldatas);\n }\n\n /**\n * @notice Get a proposal receipt.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param voter A governance stakeholder with voting power.\n * @return The voter receipt of the proposal.\n * */\n function getReceipt(uint256 proposalId, address voter) public view returns (Receipt memory) {\n return proposals[proposalId].receipts[voter];\n }\n\n /**\n * @notice Casts a vote by sender.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function castVote(uint256 proposalId, bool support) public {\n return _castVote(msg.sender, proposalId, support);\n }\n\n /**\n * @notice Voting with EIP-712 Signatures.\n *\n * Voting power can be delegated to any address, and then can be used to\n * vote on proposals. A key benefit to users of by-signature functionality\n * is that they can create a signed vote transaction for free, and have a\n * trusted third-party spend rBTC(or ETH) on gas fees and write it to the\n * blockchain for them.\n *\n * The third party in this scenario, submitting the SOV-holder’s signed\n * transaction holds a voting power that is for only a single proposal.\n * The signatory still holds the power to vote on their own behalf in\n * the proposal if the third party has not yet published the signed\n * transaction that was given to them.\n *\n * @dev The signature needs to be broken up into 3 parameters, known as\n * v, r and s:\n * const r = '0x' + sig.substring(2).substring(0, 64);\n * const s = '0x' + sig.substring(2).substring(64, 128);\n * const v = '0x' + sig.substring(2).substring(128, 130);\n *\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * @param v The recovery byte of the signature.\n * @param r Half of the ECDSA signature pair.\n * @param s Half of the ECDSA signature pair.\n * */\n function castVoteBySig(\n uint256 proposalId,\n bool support,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public {\n /**\n * @dev The DOMAIN_SEPARATOR is a hash that uniquely identifies a\n * smart contract. It is built from a string denoting it as an\n * EIP712 Domain, the name of the token contract, the version,\n * the chainId in case it changes, and the address that the\n * contract is deployed at.\n * */\n bytes32 domainSeparator =\n keccak256(\n abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this))\n );\n\n /// @dev GovernorAlpha uses BALLOT_TYPEHASH, while Staking uses DELEGATION_TYPEHASH\n bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support));\n\n bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n address signatory = ecrecover(digest, v, r, s);\n\n /// @dev Verify address is not null and PK is not null either.\n require(\n RSKAddrValidator.checkPKNotZero(signatory),\n \"GovernorAlpha::castVoteBySig: invalid signature\"\n );\n return _castVote(signatory, proposalId, support);\n }\n\n /**\n * @notice Cast a vote, adding it to the total counting.\n * @param voter A governance stakeholder with voting power that is casting the vote.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function _castVote(\n address voter,\n uint256 proposalId,\n bool support\n ) internal {\n require(\n state(proposalId) == ProposalState.Active,\n \"GovernorAlpha::_castVote: voting is closed\"\n );\n Proposal storage proposal = proposals[proposalId];\n Receipt storage receipt = proposal.receipts[voter];\n require(receipt.hasVoted == false, \"GovernorAlpha::_castVote: voter already voted\");\n uint96 votes = staking.getPriorVotes(voter, proposal.startBlock, proposal.startTime);\n\n if (support) {\n proposal.forVotes = add96(\n proposal.forVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n } else {\n proposal.againstVotes = add96(\n proposal.againstVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n }\n\n receipt.hasVoted = true;\n receipt.support = support;\n receipt.votes = votes;\n\n emit VoteCast(voter, proposalId, support, votes);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __acceptAdmin() public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__acceptAdmin: sender must be gov guardian\"\n );\n timelock.acceptAdmin();\n }\n\n /// @notice Sets guardian address to zero.\n function __abdicate() public {\n require(msg.sender == guardian, \"GovernorAlpha::__abdicate: sender must be gov guardian\");\n guardian = address(0);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.queueTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.executeTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /**\n * @notice Get a proposal state.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return The state of the proposal: Canceled, Pending, Active, Defeated,\n * Succeeded, Executed, Expired.\n * */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"GovernorAlpha::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n\n if (proposal.canceled) {\n return ProposalState.Canceled;\n }\n\n if (block.number <= proposal.startBlock) {\n return ProposalState.Pending;\n }\n\n if (block.number <= proposal.endBlock) {\n return ProposalState.Active;\n }\n\n uint96 totalVotes =\n add96(\n proposal.forVotes,\n proposal.againstVotes,\n \"GovernorAlpha:: state: forVotes + againstVotes > uint96\"\n );\n uint96 totalVotesMajorityPercentage =\n div96(totalVotes, 100, \"GovernorAlpha:: state: division error\");\n totalVotesMajorityPercentage = mul96(\n totalVotesMajorityPercentage,\n majorityPercentageVotes,\n \"GovernorAlpha:: state: totalVotes * majorityPercentage > uint96\"\n );\n if (proposal.forVotes <= totalVotesMajorityPercentage || totalVotes < proposal.quorum) {\n return ProposalState.Defeated;\n }\n\n if (proposal.eta == 0) {\n return ProposalState.Succeeded;\n }\n\n if (proposal.executed) {\n return ProposalState.Executed;\n }\n\n if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) {\n return ProposalState.Expired;\n }\n\n return ProposalState.Queued;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function add256(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"addition overflow\");\n return c;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function sub256(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b <= a, \"subtraction underflow\");\n return a - b;\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n}\n\n/* Interfaces */\n\ninterface TimelockInterface {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\ninterface StakingInterface {\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n}\n" + }, + "contracts/governance/GovernorVault.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title Governance Vault.\n * @notice This contract stores tokens and rBTC only transfereble by owner,\n * i.e. Sovryn governance.\n * */\ncontract GovernorVault is Ownable {\n /* Events */\n\n event Deposited(address indexed sender, uint256 amount);\n event TokensTransferred(address indexed receiver, address indexed token, uint256 amount);\n event RbtcTransferred(address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer tokens.\n * @param _receiver The receiver of tokens.\n * @param _token The address of token contract.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _receiver,\n address _token,\n uint256 _amount\n ) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n require(_token != address(0), \"Invalid token address\");\n\n require(IERC20(_token).transfer(_receiver, _amount), \"Transfer failed\");\n emit TokensTransferred(_receiver, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC.\n * @param _receiver The receiver of RBTC.\n * @param _amount The amount to be transferred.\n * */\n function transferRbtc(address payable _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n\n address(_receiver).transfer(_amount);\n emit RbtcTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {\n if (msg.value > 0) {\n emit Deposited(msg.sender, msg.value);\n }\n }\n}\n" + }, + "contracts/governance/IFeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * */\ninterface IFeeSharingCollector {\n function withdrawFees(address[] calldata _token) external;\n\n function transferTokens(address _token, uint96 _amount) external;\n\n function withdraw(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external;\n}\n" + }, + "contracts/governance/Staking/interfaces/IStaking.sol": { + "content": "pragma solidity ^0.5.17;\n\npragma experimental ABIEncoderV2;\n\n/**\n * @title Interface for Staking modules governance/Staking/modules\n */\n\ninterface IStaking {\n /*************************** StakingAdminModule ***************************/\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external;\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external;\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external;\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external;\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) external;\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external;\n\n /**\n * @notice Allows the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external;\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external;\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external;\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\n\n /*************************** StakingGovernanceModule ***************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\n * be internal instead of a public function.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external;\n\n /*************************** StakingStakeModule ***************************/\n\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance);\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes);\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\n\n /*************************** StakingStorageModule ***************************/\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n /// @return uint256(MAX_VOTING_WEIGHT);\n function getStorageMaxVotingWeight() external pure returns (uint256);\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n /// @return uint256(WEIGHT_FACTOR);\n function getStorageWeightFactor() external pure returns (uint256);\n\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\n function getStorageDefaultWeightScaling() external pure returns (uint256);\n\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\n\n /// @notice The EIP-712 typehash for the contract's domain.\n /// @return uint256(DOMAIN_TYPEHASH);\n function getStorageDomainTypehash() external pure returns (uint256);\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n /// @return uint256(DELEGATION_TYPEHASH);\n function getStorageDelegationTypehash() external pure returns (uint256);\n\n /// @return name;\n function getStorageName() external view returns (string memory);\n\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n function kickoffTS() external view returns (uint256);\n\n /// @notice The token to be staked\n function SOVToken() external view returns (address);\n\n /// @notice Stakers delegated voting power\n /// @param staker - the delegating address\n /// @param until - delegated voting\n /// @return _delegate - voting power delegated to address\n function delegates(address staker, uint256 until) external view returns (address _delegate);\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately\n /// see function unlockAllTokens() for details\n function allUnlocked() external view returns (bool);\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\n function newStakingContract() external view returns (address);\n\n /// CHECKPOINTS\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\n function totalStakingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n function numTotalStakingCheckpoints(uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n function delegateStakingCheckpoints(\n address delagatee,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n function userStakingCheckpoints(\n address user,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number\n function numUserStakingCheckpoints(address user, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n function nonces(address user) external view returns (uint256 nonce);\n\n /// SLASHING ///\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n function feeSharing() external view returns (address);\n\n /// @notice used for weight scaling when unstaking with slashing.\n /// @return uint96 DEFAULT_WEIGHT_SCALING\n function weightScaling() external view returns (uint96);\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n function admins(address isAdmin) external view returns (bool);\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n function vestingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\n\n ///@notice vesting registry contract PROXY address\n function vestingRegistryLogic() external view returns (address);\n\n /// @dev user => flag whether user has pauser role.\n function pausers(address isPauser) external view returns (bool);\n\n /// @dev Staking contract is paused\n function paused() external view returns (bool);\n\n /// @dev Staking contract is frozen\n function frozen() external view returns (bool);\n\n /*************************** StakingVestingModule ***************************/\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool);\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external;\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external;\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes);\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n /*************************** StakingWithdrawModule ***************************/\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * */\n function governanceWithdrawVesting(address vesting, address receiver) external;\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96);\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external;\n\n /*************************** WeightedStakingModule ***************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The date/timestamp of the unstaking time.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * TODO: WeightedStaking::weightedStakeByDate should probably better\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Returns public constant MAX_DURATION\n * preserved for backwards compatibility\n * Use getStorageMaxDurationToStakeTokens()\n * @return uint96 MAX_DURATION for staking\n **/\n function MAX_DURATION() external view returns (uint256);\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() external view returns (address);\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() external view returns (bool);\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) external;\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external;\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() external view returns (uint256);\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param maxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\n}\n" + }, + "contracts/governance/Staking/modules/shared/CheckpointsShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\n\n/**\n * @title Checkpoints contract.\n * @notice Increases and decreases storage values for users, delegatees and\n * total daily stake.\n * */\ncontract CheckpointsShared is StakingStorageShared, SafeMath96 {\n /// @notice An event emitted when an account changes its delegate.\n event DelegateChanged(\n address indexed delegator,\n uint256 lockedUntil,\n address indexed fromDelegate,\n address indexed toDelegate\n );\n\n /// @notice An event emitted when a delegate account's stake balance changes.\n event DelegateStakeChanged(\n address indexed delegate,\n uint256 lockedUntil,\n uint256 previousBalance,\n uint256 newBalance\n );\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n event ContractCodeHashAdded(bytes32 hash);\n\n event ContractCodeHashRemoved(bytes32 hash);\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n event TeamVestingCancelled(address indexed caller, address receiver);\n\n event TeamVestingPartiallyCancelled(\n address indexed caller,\n address receiver,\n uint256 nextStartFrom\n );\n\n constructor() internal {\n // abstract\n }\n\n /**\n * @notice Increases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = add96(vested, value, \"CP01\"); // vested overflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Decreases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = sub96(vested, value, \"CP02\"); // vested underflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Writes on storage the user vested amount.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newVest The new vest balance.\n * */\n function _writeVestingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newVest\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP03\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n vestingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n vestingCheckpoints[lockedTS][nCheckpoints - 1].stake = newVest;\n } else {\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newVest);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP04\"); // staked overflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP05\"); // staked underflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the user stake.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeUserCheckpoint(\n address account,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP06\"); // block number > 32 bits\n\n if (\n nCheckpoints > 0 &&\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n userStakingCheckpoints[account][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numUserStakingCheckpoints[account][lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP07\"); // block number > 32 bits\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = 0;\n // @dev We need to check delegate checkpoint value here,\n //\t\tbecause we had an issue in `stake` function:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n // @dev It can be greater than 0, but inconsistent after 3 transactions\n if (staked > value) {\n newStake = sub96(staked, value, \"CP08\"); // staked underflow\n }\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the delegate stake.\n * @param delegatee The delegate address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeDelegateCheckpoint(\n address delegatee,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP09\"); // block numb > 32 bits\n uint96 oldStake = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n\n if (\n nCheckpoints > 0 &&\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].fromBlock ==\n blockNumber\n ) {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numDelegateStakingCheckpoints[delegatee][lockedTS] = nCheckpoints + 1;\n }\n emit DelegateStakeChanged(delegatee, lockedTS, oldStake, newStake);\n }\n\n /**\n * @notice Increases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP10\"); // staked overflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP11\"); // staked underflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the total stake.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeStakingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP12\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n totalStakingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newStake);\n numTotalStakingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Get the current balance of an account locked until a certain date.\n * @param account The user address.\n * @param lockDate The lock date.\n * @return The stake amount.\n * */\n function _currentBalance(address account, uint256 lockDate) internal view returns (uint96) {\n uint32 _numUnserStakingCheckpoints = numUserStakingCheckpoints[account][lockDate] - 1;\n return userStakingCheckpoints[account][lockDate][_numUnserStakingCheckpoints].stake;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\nimport \"../../../../openzeppelin/SafeMath.sol\";\nimport \"../../../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking modules shared functionality\n */\ncontract StakingShared is StakingStorageShared, SafeMath96 {\n using SafeMath for uint256;\n\n uint256 internal constant FOUR_WEEKS = 4 weeks;\n\n /**\n * @dev Throws if paused.\n */\n modifier whenNotPaused() {\n require(!paused, \"paused\"); // SS03\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\"); // SS01\n _;\n }\n\n /**\n\t * @dev Throws if called by any account other than the owner or admin or pauser.\n\t \n\tmodifier onlyAuthorizedOrPauser() {\n\t\trequire(isOwner() || admins[msg.sender] || pausers[msg.sender], \"unauthorized\"); // WS02\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if called by any account other than the owner or pauser.\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || pausers[msg.sender], \"unauthorized\"); // SS02\n _;\n }\n\n /**\n * @dev Throws if called by any account other than pauser.\n * @notice Uncomment when needed\n */\n /*\n\tmodifier onlyPauser() {\n\t\trequire(pausers[msg.sender], \"Not pauser\");\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if frozen.\n */\n modifier whenNotFrozen() {\n require(!frozen, \"paused\"); // SS04\n _;\n }\n\n constructor() internal {\n // abstract\n }\n\n function _notSameBlockAsStakingCheckpoint(uint256 lockDate, address stakeFor) internal view {\n uint32 nCheckpoints = numUserStakingCheckpoints[stakeFor][lockDate];\n bool notSameBlock =\n userStakingCheckpoints[stakeFor][lockDate][nCheckpoints - 1].fromBlock != block.number;\n require(notSameBlock, \"cannot be mined in the same block as last stake\"); // S20\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = kickoffTS;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / TWO_WEEKS;\n lockDate = periodFromKickoff * TWO_WEEKS + start;\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS14\n\n date = _adjustDateForOrigin(date);\n uint32 nCheckpoints = numUserStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (userStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return userStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (userStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = userStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return userStakingCheckpoints[account][date][lower].stake;\n }\n\n /**\n * @dev origin vesting contracts have different dates\n * we need to add 2 weeks to get end of period (by default, it's start)\n * @param date The staking date to compute the power for.\n * @return unlocking date.\n */\n function _adjustDateForOrigin(uint256 date) internal view returns (uint256) {\n uint256 adjustedDate = _timestampToLockDate(date);\n //origin vesting contracts have different dates\n //we need to add 2 weeks to get end of period (by default, it's start)\n if (adjustedDate != date) {\n date = adjustedDate + TWO_WEEKS;\n }\n return date;\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function _computeWeightByDate(uint256 date, uint256 startDate)\n internal\n pure\n returns (uint96 weight)\n {\n require(date >= startDate, \"date < startDate\"); // WS18\n uint256 remainingTime = (date - startDate);\n require(MAX_DURATION >= remainingTime, \"remaining time > max duration\"); // WS19\n /// @dev x = max days - remaining days\n uint96 x = uint96(MAX_DURATION - remainingTime) / (1 days);\n /// @dev w = (m^2 - x^2)/m^2 +1 (multiplied by the weight factor)\n weight = add96(\n WEIGHT_FACTOR,\n mul96(\n MAX_VOTING_WEIGHT * WEIGHT_FACTOR,\n sub96(\n MAX_DURATION_POW_2,\n x * x,\n \"weight underflow\" // WS20\n ),\n \"weight mul overflow\" // WS21\n ) / MAX_DURATION_POW_2,\n \"overflow on weight\" // WS22\n );\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function _isVestingContract(address stakerAddress) internal view returns (bool) {\n bool isVesting;\n bytes32 codeHash;\n\n assembly {\n codeHash := extcodehash(stakerAddress)\n }\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingStorageShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../../openzeppelin/Ownable.sol\";\nimport \"../../../../interfaces/IERC20.sol\";\nimport \"../../../IFeeSharingCollector.sol\";\nimport \"../../../Vesting/IVestingRegistry.sol\";\n\n/**\n * @title StakingStorageShared contract is inherited by Staking modules.\n * @notice Just the storage part of stacking contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingProxy and Checkpoints contracts.\n *\n * What is SOV staking?\n * The purpose of the SOV token is to provide a pseudonymous,\n * censorship-resistant mechanism for governing the parameters of the Sovryn\n * protocol, while aligning the incentives of protocol governors with the\n * long-term success of the protocol. Any SOV token holder can choose to\n * stake (lock up) their tokens for a fixed period of time in return for\n * voting rights in the Bitocracy. Stakers are further incentivised through\n * fee and slashing rewards.\n * */\ncontract StakingStorageShared is Ownable {\n /// @notice 2 weeks in seconds.\n uint256 constant TWO_WEEKS = 1209600;\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n uint96 public constant MAX_VOTING_WEIGHT = 9;\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n uint96 public constant WEIGHT_FACTOR = 10;\n\n /// @notice The maximum duration to stake tokens for.\n uint256 public constant MAX_DURATION = 1092 days;\n\n /// @notice The maximum duration ^2\n uint96 constant MAX_DURATION_POW_2 = 1092 * 1092;\n\n /// @notice Default weight scaling.\n uint96 constant DEFAULT_WEIGHT_SCALING = 3;\n\n /// @notice Range for weight scaling.\n uint96 constant MIN_WEIGHT_SCALING = 1;\n uint96 constant MAX_WEIGHT_SCALING = 9;\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n uint256 public kickoffTS;\n\n string name = \"SOVStaking\";\n\n /// @notice The token to be staked.\n IERC20 public SOVToken;\n\n /// @notice A record of each accounts delegate.\n mapping(address => mapping(uint256 => address)) public delegates;\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately.\n bool public allUnlocked = false;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n bytes32 public constant DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 lockDate,uint256 nonce,uint256 expiry)\");\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure.\n address public newStakingContract;\n\n /*************************** Checkpoints *******************************/\n\n /// @notice A checkpoint for marking the stakes from a given block\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public totalStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numTotalStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public delegateStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numDelegateStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public userStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numUserStakingCheckpoints;\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n mapping(address => uint256) public nonces;\n\n /*************************** Slashing *******************************/\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n IFeeSharingCollector public feeSharing;\n\n /// @notice used for weight scaling when unstaking with slashing.\n uint96 public weightScaling = DEFAULT_WEIGHT_SCALING;\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n mapping(address => bool) public vestingWhitelist;\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n mapping(address => bool) public admins;\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n mapping(bytes32 => bool) public vestingCodeHashes;\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public vestingCheckpoints;\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numVestingCheckpoints;\n\n ///@notice vesting registry contract\n IVestingRegistry public vestingRegistryLogic;\n\n /// @dev user => flag whether user has pauser role.\n mapping(address => bool) public pausers;\n\n /// @dev Staking contract is paused\n bool public paused;\n\n /// @dev Staking contract is frozen\n bool public frozen;\n\n /// @dev max iterations that can be supported in 1 tx for the withdrawal\n uint256 internal maxVestingWithdrawIterations;\n\n constructor() internal {\n //abstract\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingAdminModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Admin Module.\n * @notice Implements administrative functionality pause, freeze and setting addresses and parameters\n * related to staking\n * */\ncontract StakingAdminModule is IFunctionsList, StakingShared {\n using Address for address payable;\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(_admin != address(0), \"cannot add the zero address as an admin\");\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(admins[_admin], \"address is not an admin\");\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external onlyOwner whenNotFrozen {\n require(_pauser != address(0), \"cannot add the zero address as a pauser\");\n pausers[_pauser] = true;\n emit PauserAddedOrRemoved(_pauser, true);\n }\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external onlyOwner whenNotFrozen {\n require(pausers[_pauser], \"address is not a pauser\");\n delete pausers[_pauser];\n emit PauserAddedOrRemoved(_pauser, false);\n }\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) public onlyPauserOrOwner whenNotFrozen {\n paused = _pause;\n emit StakingPaused(_pause);\n }\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external onlyPauserOrOwner {\n require(_freeze != frozen, \"Cannot freeze/unfreeze to the same state\"); // WS25\n if (_freeze) pauseUnpause(true);\n frozen = _freeze;\n emit StakingFrozen(_freeze);\n }\n\n /**\n * @notice Allow the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external onlyOwner whenNotFrozen {\n require(_feeSharing != address(0), \"FeeSharing address shouldn't be 0\"); // S17\n feeSharing = IFeeSharingCollector(_feeSharing);\n }\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external onlyOwner whenNotFrozen {\n require(\n MIN_WEIGHT_SCALING <= _weightScaling && _weightScaling <= MAX_WEIGHT_SCALING,\n \"scaling doesn't belong to range [1, 9]\" // S18\n );\n weightScaling = _weightScaling;\n }\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external onlyOwner whenNotFrozen {\n require(_newStakingContract != address(0), \"can't reset the new staking contract to 0\"); // S16\n newStakingContract = _newStakingContract;\n }\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external whenNotFrozen {\n require(newStakingContract != address(0), \"there is no new staking contract set\"); // S19\n revert(\"not implemented\");\n /// @dev implementation:\n /// @dev Iterate over all possible lock dates from now until now + MAX_DURATION.\n /// @dev Read the stake & delegate of the msg.sender\n /// @dev If stake > 0, stake it at the new contract until the lock date with the current delegate.\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](13);\n functionsList[0] = this.addAdmin.selector;\n functionsList[1] = this.removeAdmin.selector;\n functionsList[2] = this.addPauser.selector;\n functionsList[3] = this.removePauser.selector;\n functionsList[4] = this.pauseUnpause.selector;\n functionsList[5] = this.freezeUnfreeze.selector;\n functionsList[6] = this.setFeeSharing.selector;\n functionsList[7] = this.setWeightScaling.selector;\n functionsList[8] = this.setNewStakingContract.selector;\n functionsList[9] = this.owner.selector;\n functionsList[10] = this.isOwner.selector;\n functionsList[11] = this.transferOwnership.selector;\n functionsList[12] = this.migrateToNewStakingContract.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingGovernanceModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/IVesting.sol\";\n\n/**\n * @title Staking Governance Module contract\n * @notice Implements voting power and delegation functionality\n * */\ncontract StakingGovernanceModule is IFunctionsList, StakingShared, CheckpointsShared {\n using Address for address payable;\n\n /************* TOTAL VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n /// @dev Start the computation with the exact or previous unlocking date (voting weight remians the same until the next break point).\n uint256 start = _timestampToLockDate(time);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n totalVotingPower = add96(\n totalVotingPower,\n _totalPowerByDate(i, start, blockNumber),\n \"arrays mismatch\"\n ); // WS06\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorTotalStakesForDate(date, blockNumber);\n /// @dev weight is multiplied by some factor to allow decimals.\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS07\n }\n\n /****************************** DELEGATED VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96) {\n return getPriorVotes(account, block.number - 1, block.timestamp);\n }\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96 votes) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n votes = add96(\n votes,\n _totalPowerByDateForDelegatee(account, i, start, blockNumber),\n \"overflow - total VP\"\n ); // WS09\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDateForDelegatee(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS10\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n date = _adjustDateForOrigin(date);\n return _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined yet\"); // WS11\n\n uint32 nCheckpoints = numDelegateStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (delegateStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return delegateStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (delegateStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = delegateStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return delegateStakingCheckpoints[account][date][lower].stake;\n }\n\n /**************** SHARED FUNCTIONS *********************/\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for. Adjusted to the next valid lock date, as necessary\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n public\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorTotalStakesForDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function _getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS08\n\n uint32 nCheckpoints = numTotalStakingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (totalStakingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return totalStakingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n // Next check implicit zero balance\n if (totalStakingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Checkpoint memory cp = totalStakingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return totalStakingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Set new delegatee. Move from user's current delegate to a new\n * delegatee the stake balance.\n * @param delegator The user address to move stake balance from its current delegatee.\n * @param delegatee The new delegatee. The address to move stake balance to.\n * @param lockedTS The lock date.\n * @dev Reverts if delegator balance or delegatee is not valid, unless the sender is a vesting contract.\n * */\n function _delegate(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n address currentDelegate = delegates[delegator][lockedTS];\n uint96 delegatorBalance = _currentBalance(delegator, lockedTS);\n\n // vesting contracts will in multiple cases try to delegate a zero balance\n // or to the existing delegatee\n if (_isVestingContract(msg.sender)) {\n if (delegatorBalance == 0 || currentDelegate == delegatee) {\n return;\n }\n } else {\n require(delegatorBalance > 0, \"no stake to delegate\");\n require(currentDelegate != delegatee, \"cannot delegate to the existing delegatee\");\n }\n\n delegates[delegator][lockedTS] = delegatee;\n\n emit DelegateChanged(delegator, lockedTS, currentDelegate, delegatee);\n\n _moveDelegates(currentDelegate, delegatee, delegatorBalance, lockedTS);\n }\n\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n function _delegateNext(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n if (_isVestingContract(msg.sender)) {\n uint256 nextLock = lockedTS.add(TWO_WEEKS);\n address currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n\n // @dev workaround for the issue with a delegation of the latest stake\n uint256 endDate = IVesting(msg.sender).endDate();\n nextLock = lockedTS.add(FOUR_WEEKS);\n if (nextLock == endDate) {\n currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n }\n }\n }\n\n /**\n * @notice Move an amount of delegate stake from a source address to a\n * destination address.\n * @param srcRep The address to get the staked amount from.\n * @param dstRep The address to send the staked amount to.\n * @param amount The staked amount to move.\n * @param lockedTS The lock date.\n * */\n function _moveDelegates(\n address srcRep,\n address dstRep,\n uint96 amount,\n uint256 lockedTS\n ) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) _decreaseDelegateStake(srcRep, lockedTS, amount);\n\n if (dstRep != address(0)) _increaseDelegateStake(dstRep, lockedTS, amount);\n }\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function _getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external whenNotPaused {\n require(delegatee != address(0), \"cannot delegate to the zero address\");\n _notSameBlockAsStakingCheckpoint(lockDate, msg.sender);\n\n _delegate(msg.sender, delegatee, lockDate);\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n _delegateNext(msg.sender, delegatee, lockDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](6);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStakeModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking contract staking functionality module\n * @notice Implements staking functionality\n **/\ncontract StakingStakeModule is IFunctionsList, StakingShared, CheckpointsShared, ApprovalReceiver {\n using SafeMath for uint256;\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stake(msg.sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external onlyThisContract whenNotPaused whenNotFrozen {\n _stake(sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * */\n function _stake(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted\n ) internal {\n _stakeOptionalTokenTransfer(\n sender,\n amount,\n until,\n stakeFor,\n delegatee,\n timeAdjusted,\n true // transfer SOV\n );\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * @param transferToken Should transfer SOV - false for multiple iterations like in stakeBySchedule\n * */\n function _stakeOptionalTokenTransfer(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted,\n bool transferToken\n ) internal {\n require(amount > 0, \"amount needs to be bigger than 0\"); // S01\n\n if (!timeAdjusted) {\n until = _timestampToLockDate(until);\n }\n require(\n until > block.timestamp,\n \"Staking::_timestampToLockDate: staking period too short\"\n ); // S02\n\n /// @dev Stake for the sender if not specified otherwise.\n if (stakeFor == address(0)) {\n stakeFor = sender;\n }\n // must wait a block before staking again for that same deadline\n _notSameBlockAsStakingCheckpoint(until, stakeFor);\n\n /// @dev Delegate for stakeFor if not specified otherwise.\n if (delegatee == address(0)) {\n delegatee = stakeFor;\n }\n\n /// @dev Do not stake longer than the max duration.\n if (!timeAdjusted) {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n }\n\n uint96 previousBalance = _currentBalance(stakeFor, until);\n\n /// @dev Increase stake.\n _increaseStake(sender, amount, stakeFor, until, transferToken);\n\n // @dev Previous version wasn't working properly for the following case:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n address previousDelegatee = delegates[stakeFor][until];\n\n if (previousDelegatee != delegatee) {\n // @dev only the user that stakes for himself is allowed to delegate VP to another address\n // which works with vesting stakes and prevents vulnerability of delegating VP to an arbitrary address from\n // any address\n\n if (delegatee != stakeFor) {\n require(\n stakeFor == sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n } else if (sender != stakeFor && previousDelegatee != address(0)) {\n require(stakeFor == sender, \"Only sender is allowed to change delegatee\");\n }\n\n /// @dev Update delegatee.\n delegates[stakeFor][until] = delegatee;\n\n /// @dev Decrease stake on previous balance for previous delegatee.\n _decreaseDelegateStake(previousDelegatee, until, previousBalance);\n\n /// @dev Add previousBalance to amount.\n amount = add96(previousBalance, amount, \"add amounts failed\");\n }\n\n /// @dev Increase stake.\n _increaseDelegateStake(delegatee, until, amount);\n emit DelegateChanged(stakeFor, until, previousDelegatee, delegatee);\n }\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until)\n external\n whenNotPaused\n whenNotFrozen\n {\n previousLock = _timestampToLockDate(previousLock);\n until = _timestampToLockDate(until);\n\n _notSameBlockAsStakingCheckpoint(previousLock, msg.sender);\n\n /// @dev Do not exceed the max duration, no overflow possible.\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n\n require(previousLock < until, \"must increase staking duration\"); // S04\n\n /// @dev Update checkpoints.\n /// @dev TODO James: Can reading stake at block.number -1 cause trouble with multiple tx in a block?\n uint96 amount = _getPriorUserStakeByDate(msg.sender, previousLock, block.number - 1);\n require(amount > 0, \"no stakes till the prev lock date\"); // S05\n _decreaseUserStake(msg.sender, previousLock, amount);\n _increaseUserStake(msg.sender, until, amount);\n\n if (_isVestingContract(msg.sender)) {\n _decreaseVestingStake(previousLock, amount);\n _increaseVestingStake(until, amount);\n }\n\n _decreaseDailyStake(previousLock, amount);\n _increaseDailyStake(until, amount);\n\n /// @dev Delegate might change: if there is already a delegate set for the until date, it will remain the delegate for this position\n address delegateFrom = delegates[msg.sender][previousLock];\n delegates[msg.sender][previousLock] = address(0); //the previousLock delegates nullifying before reading that form `until` guards in case delegateTo == until\n address delegateTo = delegates[msg.sender][until];\n if (delegateTo == address(0)) {\n delegateTo = delegateFrom;\n delegates[msg.sender][until] = delegateFrom;\n }\n _decreaseDelegateStake(delegateFrom, previousLock, amount);\n _increaseDelegateStake(delegateTo, until, amount);\n\n emit ExtendedStakingDuration(msg.sender, previousLock, until, amount);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param until The date until which the tokens will be staked.\n * @param transferToken if false - token transfer should be handled separately\n * */\n function _increaseStake(\n address sender,\n uint96 amount,\n address stakeFor,\n uint256 until,\n bool transferToken\n ) internal {\n /// @dev Retrieve the SOV tokens.\n if (transferToken)\n require(\n SOVToken.transferFrom(sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // IS10\n\n /// @dev Increase staked balance.\n uint96 balance = _currentBalance(stakeFor, until);\n balance = add96(balance, amount, \"increaseStake: overflow\"); // IS20\n\n /// @dev Update checkpoints.\n _increaseDailyStake(until, amount);\n _increaseUserStake(stakeFor, until, amount);\n\n if (_isVestingContract(stakeFor)) _increaseVestingStake(until, amount);\n\n emit TokensStaked(stakeFor, amount, until, balance);\n }\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function _stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) internal {\n require(amount > 0, \"Invalid amount\");\n require(duration <= MAX_DURATION, \"Invalid duration\");\n require(intervalLength > 0, \"Invalid interval length\");\n require(intervalLength % TWO_WEEKS == 0, \"Invalid interval length\");\n if (delegatee != stakeFor && delegatee != address(0)) {\n require(\n stakeFor == msg.sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n }\n /**\n * @dev Stake them until lock dates according to the vesting schedule.\n * Note: because staking is only possible in periods of 2 weeks,\n * the total duration might end up a bit shorter than specified\n * depending on the date of staking.\n * */\n uint256 start = _timestampToLockDate(block.timestamp + cliff);\n uint256 end = _timestampToLockDate(block.timestamp + duration);\n require(start <= end, \"Invalid schedule\");\n uint256 numIntervals;\n if (start < end) {\n numIntervals = (end - start) / intervalLength + 1;\n } else {\n numIntervals = 1;\n }\n uint256 stakedPerInterval = amount / numIntervals;\n\n /// @dev transferring total SOV amount before staking\n require(\n SOVToken.transferFrom(msg.sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // SS10\n /// @dev stakedPerInterval might lose some dust on rounding. Add it to the first staking date.\n if (numIntervals >= 1) {\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(amount - stakedPerInterval * (numIntervals - 1)),\n start,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n /// @dev Stake the rest in 4 week intervals.\n for (uint256 i = start + intervalLength; i <= end; i += intervalLength) {\n /// @dev Stakes for itself, delegates to the owner.\n _notSameBlockAsStakingCheckpoint(i, stakeFor); // must wait a block before staking again for that same deadline\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(stakedPerInterval),\n i,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n }\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance) {\n for (uint256 i = kickoffTS; i <= block.timestamp + MAX_DURATION; i += TWO_WEEKS) {\n balance = add96(balance, _currentBalance(account, i), \"Staking::balanceOf: overflow\"); // S12\n }\n }\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96) {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n return nCheckpoints > 0 ? totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake : 0;\n }\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes)\n {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n\n /// @dev Calculate stakes.\n uint256 count = 0;\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n if (_currentBalance(account, i) > 0) {\n count++;\n }\n }\n dates = new uint256[](count);\n stakes = new uint96[](count);\n\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n uint256 j = 0;\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n uint96 balance = _currentBalance(account, i);\n if (balance > 0) {\n dates[j] = i;\n stakes[j] = balance;\n j++;\n }\n }\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOVToken);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeWithApproval.selector;\n return selectors;\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256) {\n return _timestampToLockDate(timestamp);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](10);\n functionsList[0] = this.stake.selector;\n functionsList[1] = this.stakeWithApproval.selector;\n functionsList[2] = this.extendStakingDuration.selector;\n functionsList[3] = this.stakesBySchedule.selector;\n functionsList[4] = this.stakeBySchedule.selector;\n functionsList[5] = this.balanceOf.selector;\n functionsList[6] = this.getCurrentStakedUntil.selector;\n functionsList[7] = this.getStakes.selector;\n functionsList[8] = this.timestampToLockDate.selector;\n functionsList[9] = this.receiveApproval.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStorageModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/StakingStorageShared.sol\";\n\n/**\n * @title Staking Storage Module\n * @notice Provides getters for public storage variables\n **/\ncontract StakingStorageModule is IFunctionsList, StakingStorageShared {\n function getStorageDefaultWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256) {\n return MAX_DURATION;\n }\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n function getStorageMaxVotingWeight() external pure returns (uint256) {\n return uint256(MAX_VOTING_WEIGHT);\n }\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n function getStorageWeightFactor() external pure returns (uint256) {\n return uint256(WEIGHT_FACTOR);\n }\n\n /// @notice Default weight scaling.\n function getStorageDefaulWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling)\n {\n return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING));\n }\n\n /// @notice The EIP-712 typehash for the contract's domain.\n function getStorageDomainTypehash() external pure returns (uint256) {\n return uint256(DOMAIN_TYPEHASH);\n }\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n function getStorageDelegationTypehash() external pure returns (uint256) {\n return uint256(DELEGATION_TYPEHASH);\n }\n\n function getStorageName() external view returns (string memory) {\n return name;\n }\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() public view returns (uint256) {\n return maxVestingWithdrawIterations;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](32);\n functionsList[0] = this.getStorageMaxDurationToStakeTokens.selector;\n functionsList[1] = this.getStorageMaxVotingWeight.selector;\n functionsList[2] = this.getStorageWeightFactor.selector;\n functionsList[3] = this.getStorageDefaulWeightScaling.selector;\n functionsList[4] = this.getStorageRangeForWeightScaling.selector;\n functionsList[5] = this.getStorageDomainTypehash.selector;\n functionsList[6] = this.getStorageDelegationTypehash.selector;\n functionsList[7] = this.getStorageName.selector;\n functionsList[8] = this.kickoffTS.selector;\n functionsList[9] = this.SOVToken.selector;\n functionsList[10] = this.delegates.selector;\n functionsList[11] = this.allUnlocked.selector;\n functionsList[12] = this.newStakingContract.selector;\n functionsList[13] = this.totalStakingCheckpoints.selector;\n functionsList[14] = this.numTotalStakingCheckpoints.selector;\n functionsList[15] = this.delegateStakingCheckpoints.selector;\n functionsList[16] = this.numDelegateStakingCheckpoints.selector;\n functionsList[17] = this.userStakingCheckpoints.selector;\n functionsList[18] = this.numUserStakingCheckpoints.selector;\n functionsList[19] = this.nonces.selector;\n functionsList[20] = this.feeSharing.selector;\n functionsList[21] = this.weightScaling.selector;\n functionsList[22] = this.vestingWhitelist.selector;\n functionsList[23] = this.admins.selector;\n functionsList[24] = this.vestingCodeHashes.selector;\n functionsList[25] = this.vestingCheckpoints.selector;\n functionsList[26] = this.numVestingCheckpoints.selector;\n functionsList[27] = this.vestingRegistryLogic.selector;\n functionsList[28] = this.pausers.selector;\n functionsList[29] = this.paused.selector;\n functionsList[30] = this.frozen.selector;\n functionsList[31] = this.getMaxVestingWithdrawIterations.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingVestingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Vesting Module contract\n * @notice Implements interaction with Vesting functionality: vesting registry, vesting staking\n * */\ncontract StakingVestingModule is IFunctionsList, StakingShared {\n event ContractCodeHashAdded(bytes32 hash);\n event ContractCodeHashRemoved(bytes32 hash);\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external onlyOwner whenNotFrozen {\n vestingRegistryLogic = IVestingRegistry(_vestingRegistryProxy);\n }\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(lockedDates.length == values.length, \"arrays mismatch\"); // WS05\n\n uint256 length = lockedDates.length;\n for (uint256 i = 0; i < length; i++) {\n _setVestingStake(lockedDates[i], values[i]);\n }\n }\n\n /**\n * @notice Sets the users' vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to be set.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function _setVestingStake(uint256 lockedTS, uint96 value) internal {\n require(\n lockedTS > kickoffTS,\n \"Invalid lock dates: must greater than contract creation timestamp\"\n );\n\n // locked date must be multiples of 14 days / TWO_WEEKS\n require(\n (lockedTS - kickoffTS) % TWO_WEEKS == 0,\n \"Invalid lock dates: not multiples of 14 days\"\n );\n\n // locked date must not exceed the MAX_DURATION\n if (lockedTS > block.timestamp) {\n require(\n lockedTS - block.timestamp <= MAX_DURATION,\n \"Invalid lock dates: exceed max duration\"\n );\n }\n\n // the value must not exceed the total staked at the given locked date\n uint32 nStakeCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 totalStaked = totalStakingCheckpoints[lockedTS][nStakeCheckpoints - 1].stake;\n require(\n value <= totalStaked,\n \"Invalid stake amount: greater than the total staked for given date\"\n );\n\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint32 blockNumber;\n\n Checkpoint memory recentCP = vestingCheckpoints[lockedTS][nCheckpoints - 1];\n if (nCheckpoints == 0) blockNumber = uint32(block.number) - 1;\n else blockNumber = recentCP.fromBlock + 1;\n\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, value);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n\n emit VestingStakeSet(lockedTS, value);\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n uint96 priorStake = _getPriorUserStakeByDate(account, date, blockNumber);\n // @dev we need to modify function in order to workaround issue with Vesting.withdrawTokens:\n //\t\treturn 1 instead of 0 if message sender is a contract.\n if (priorStake == 0 && _isVestingContract(msg.sender)) {\n priorStake = 1;\n }\n return priorStake;\n }\n\n /*************************** Weighted Vesting Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes)\n {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedVestingStakeByDate(i, start, blockNumber);\n if (weightedStake > 0) {\n votes = add96(votes, weightedStake, \"overflow on total weight\"); // WS15\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n power = _weightedVestingStakeByDate(date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorVestingStakeByDate(date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul oveflow\") / WEIGHT_FACTOR; // WS16\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorVestingStakeByDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS17\n\n uint32 nCheckpoints = numVestingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (vestingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return vestingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (vestingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = vestingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return vestingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n require(vestingCodeHashes[codeHash], \"not a registered vesting code hash\");\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool) {\n bool isVesting;\n bytes32 codeHash = _getCodeHash(stakerAddress);\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](9);\n functionsList[0] = this.setVestingRegistry.selector;\n functionsList[1] = this.setVestingStakes.selector;\n functionsList[2] = this.getPriorUserStakeByDate.selector;\n functionsList[3] = this.getPriorVestingWeightedStake.selector;\n functionsList[4] = this.getPriorVestingStakeByDate.selector;\n functionsList[5] = this.addContractCodeHash.selector;\n functionsList[6] = this.removeContractCodeHash.selector;\n functionsList[7] = this.isVestingContract.selector;\n functionsList[8] = this.weightedVestingStakeByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingWithdrawModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/ITeamVesting.sol\";\nimport \"../../Vesting/IVesting.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking withdrawal functionality module\n **/\ncontract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShared {\n using SafeMath for uint256;\n\n event MaxVestingWithdrawIterationsUpdated(uint256 oldMaxIterations, uint256 newMaxIterations);\n\n /// @dev Struct for direct withdraw function -- to avoid stack too deep issue\n struct VestingConfig {\n address vestingAddress;\n uint256 startDate;\n uint256 endDate;\n uint256 cliff;\n uint256 duration;\n address tokenOwner;\n }\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev If until is not a valid lock date, the next lock date after until is used.\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n // adjust until here to avoid adjusting multiple times, and to make sure an adjusted date is passed to\n // _notSameBlockAsStakingCheckpoint\n until = _adjustDateForOrigin(until);\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, false);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe need to check block.timestamp here\n _withdrawNext(until, receiver, false);\n }\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external onlyAuthorized whenNotFrozen {\n /// require the caller only for team vesting contract.\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n _cancelTeamVesting(vesting, receiver, startFrom);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param _vesting The vesting address.\n * @param _receiver The receiving address.\n * @param _startFrom The start value for the iterations.\n * or just unlocked tokens (false).\n *\n * @return nextStartFrom is a timestamp to be used for next withdrawal.\n * @return notCompleted flag that indicates that the cancel team vesting is not completely done.\n * */\n function _cancelTeamVesting(\n address _vesting,\n address _receiver,\n uint256 _startFrom\n ) private returns (uint256 nextStartFrom, bool notCompleted) {\n require(_receiver != address(0), \"receiver address invalid\");\n\n ITeamVesting teamVesting = ITeamVesting(_vesting);\n\n VestingConfig memory vestingConfig =\n VestingConfig(\n _vesting,\n teamVesting.startDate(),\n teamVesting.endDate(),\n teamVesting.cliff(),\n teamVesting.duration(),\n teamVesting.tokenOwner()\n );\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them, as long as the itrations less than maxVestingWithdrawIterations.\n uint256 end = vestingConfig.endDate;\n\n uint256 defaultStart = vestingConfig.startDate + vestingConfig.cliff;\n\n _startFrom = _startFrom >= defaultStart ? _startFrom : defaultStart;\n\n /// @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 totalIterationValue =\n (_startFrom + (TWO_WEEKS * (maxVestingWithdrawIterations - 1)));\n uint256 adjustedEnd = end < totalIterationValue ? end : totalIterationValue;\n\n /// @dev Withdraw for each unlocked position.\n for (uint256 i = _startFrom; i <= adjustedEnd; i += TWO_WEEKS) {\n /// @dev Read amount to withdraw.\n uint96 tempStake = _getPriorUserStakeByDate(_vesting, i, block.number - 1);\n\n if (tempStake > 0) {\n /// @dev do governance direct withdraw for team vesting\n _withdrawFromTeamVesting(tempStake, i, _receiver, vestingConfig);\n }\n }\n\n if (adjustedEnd < end) {\n nextStartFrom = adjustedEnd + TWO_WEEKS;\n emit TeamVestingPartiallyCancelled(msg.sender, _receiver, nextStartFrom);\n return (nextStartFrom, true);\n } else {\n emit TeamVestingCancelled(msg.sender, _receiver);\n return (end, false);\n }\n }\n\n /**\n * @notice Send user' staked tokens to a receiver taking into account punishments.\n * Sovryn encourages long-term commitment and thinking. When/if you unstake before\n * the end of the staking period, a percentage of the original staking amount will\n * be slashed. This amount is also added to the reward pool and is distributed\n * between all other stakers.\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * Needs to be adjusted to the next valid lock date before calling this function.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdraw(\n uint96 amount,\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n // @dev it's very unlikely some one will have 1/10**18 SOV staked in Vesting contract\n //\t\tthis check is a part of workaround for Vesting.withdrawTokens issue\n if (amount == 1 && _isVestingContract(msg.sender)) {\n return;\n }\n _validateWithdrawParams(msg.sender, amount, until);\n\n /// @dev Determine the receiver.\n if (receiver == address(0)) receiver = msg.sender;\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(msg.sender, until, amount);\n if (_isVestingContract(msg.sender)) _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[msg.sender][until], until, amount);\n\n /// @dev Early unstaking should be punished.\n if (block.timestamp < until && !allUnlocked && !isGovernance) {\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n amount -= punishedAmount;\n\n /// @dev punishedAmount can be 0 if block.timestamp are very close to 'until'\n if (punishedAmount > 0) {\n require(address(feeSharing) != address(0), \"FeeSharing address wasn't set\"); // S08\n /// @dev Move punished amount to fee sharing.\n /// @dev Approve transfer here and let feeSharing do transfer and write checkpoint.\n SOVToken.approve(address(feeSharing), punishedAmount);\n feeSharing.transferTokens(address(SOVToken), punishedAmount);\n }\n }\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(msg.sender, amount, until, receiver, isGovernance);\n }\n\n /**\n * @notice Send user' staked tokens to a receiver.\n * This function is dedicated only for direct withdrawal from staking contract.\n * Currently only being used by cancelTeamVesting()\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender.\n * @param vestingConfig The vesting config.\n * @dev VestingConfig struct intended to avoid stack too deep issue, and it contains this properties:\n address vestingAddress; // vesting contract address\n uint256 startDate; //start date of vesting\n uint256 endDate; // end date of vesting\n uint256 cliff; // after this time period the tokens begin to unlock\n uint256 duration; // after this period all the tokens will be unlocked\n address tokenOwner; // owner of the vested tokens\n * */\n function _withdrawFromTeamVesting(\n uint96 amount,\n uint256 until,\n address receiver,\n VestingConfig memory vestingConfig\n ) internal {\n address vesting = vestingConfig.vestingAddress;\n\n until = _timestampToLockDate(until);\n _validateWithdrawParams(vesting, amount, until);\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(vesting, until, amount);\n\n _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[vesting][until], until, amount);\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(vesting, amount, until, receiver, true);\n }\n\n // @dev withdraws tokens for lock date 2 weeks later than given lock date\n function _withdrawNext(\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n if (_isVestingContract(msg.sender)) {\n // nextLock needs to be adjusted to the next valid lock date to make sure we don't accidentally\n // withdraw stakes that are in the future and would get slashed (if until is not\n // a valid lock date). but until is already handled in the withdraw function\n uint256 nextLock = until.add(TWO_WEEKS);\n if (isGovernance || block.timestamp >= nextLock) {\n uint96 stakes = _getPriorUserStakeByDate(msg.sender, nextLock, block.number - 1);\n if (stakes > 0) {\n _withdraw(stakes, nextLock, receiver, isGovernance);\n }\n }\n }\n }\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked. Adjusted to the next valid lock date, if necessary.\n * @return Amount to withraw and penalty amount\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96)\n {\n until = _adjustDateForOrigin(until);\n _validateWithdrawParams(msg.sender, amount, until);\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n return (amount - punishedAmount, punishedAmount);\n }\n\n /**\n * @notice Get punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _getPunishedAmount(uint96 amount, uint256 until) internal view returns (uint96) {\n uint256 date = _timestampToLockDate(block.timestamp);\n uint96 weight = _computeWeightByDate(until, date); /// @dev (10 - 1) * WEIGHT_FACTOR\n weight = weight * weightScaling;\n return (amount * weight) / WEIGHT_FACTOR / 100;\n }\n\n /**\n * @notice Validate withdraw parameters.\n * @param account Address to be validated.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _validateWithdrawParams(\n address account,\n uint96 amount,\n uint256 until\n ) internal view {\n require(amount > 0, \"Amount of tokens to withdraw must be > 0\"); // S10\n uint96 balance = _getPriorUserStakeByDate(account, until, block.number - 1);\n require(amount <= balance, \"Staking::withdraw: not enough balance\"); // S11\n }\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external onlyOwner whenNotFrozen {\n allUnlocked = true;\n emit TokensUnlocked(SOVToken.balanceOf(address(this)));\n }\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param newMaxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 newMaxIterations)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(newMaxIterations > 0, \"Invalid max iterations\");\n emit MaxVestingWithdrawIterationsUpdated(maxVestingWithdrawIterations, newMaxIterations);\n maxVestingWithdrawIterations = newMaxIterations;\n }\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev This function is dedicated only to support backward compatibility for sovryn ecosystem that has been implementing this staking contract.\n * @dev Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/4bbfe5bd0311ca71e4ef0e3af810d3791d8e4061/contracts/governance/Staking/modules/StakingWithdrawModule.sol#L78\n * */\n function governanceWithdrawVesting(address vesting, address receiver)\n public\n onlyAuthorized\n whenNotFrozen\n {\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n ITeamVesting teamVesting = ITeamVesting(vesting);\n uint256 teamVestingStartDate = teamVesting.startDate();\n uint256 teamVestingCliff = teamVesting.cliff();\n\n uint256 nextStartFrom = teamVestingStartDate + teamVestingCliff;\n bool withdrawFlag = true;\n\n bool notCompleted;\n\n /**\n * The withdrawal is limited to certain iterations (set in maxVestingWithdrawIterations), so in order to withdraw all, we need to iterate until it is fully withdrawn.\n */\n while (withdrawFlag) {\n /**\n * notCompleted is the flag whether the withdrawal is fully withdrawn or not.\n * As long as the notCompleted is true, we will keep the iteration using the nextStartFrom.\n */\n (nextStartFrom, notCompleted) = _cancelTeamVesting(vesting, receiver, nextStartFrom);\n withdrawFlag = notCompleted ? true : false;\n }\n\n emit VestingTokensWithdrawn(vesting, receiver);\n }\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n require(vestingWhitelist[msg.sender], \"unauthorized\"); // S07\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, true);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe don't need to check block.timestamp here\n _withdrawNext(until, receiver, true);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.withdraw.selector;\n functionsList[1] = this.cancelTeamVesting.selector;\n functionsList[2] = this.getWithdrawAmounts.selector;\n functionsList[3] = this.unlockAllTokens.selector;\n functionsList[4] = this.setMaxVestingWithdrawIterations.selector;\n functionsList[5] = this.governanceWithdraw.selector;\n functionsList[6] = this.governanceWithdrawVesting.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/WeightedStakingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Weighted Staking module contract.\n * @notice Implements getters for weighted staking functionality\n * */\ncontract WeightedStakingModule is IFunctionsList, StakingShared, CheckpointsShared {\n /*************************** User Weighted Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The start date/timestamp from which to calculate the weighted stake.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake) {\n return _getPriorWeightedStake(account, blockNumber, date);\n }\n\n function _getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) internal view returns (uint96 priorWeightedStake) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedStakeByDate(account, i, start, blockNumber);\n if (weightedStake > 0) {\n priorWeightedStake = add96(\n priorWeightedStake,\n weightedStake,\n \"overflow on total weight calc\"\n ); // WS12\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n return _weightedStakeByDate(account, date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function _weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorUserStakeByDate(account, date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS13\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight)\n {\n return _computeWeightByDate(date, startDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](3);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/SafeMath96.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n/**\n * @title SafeMath96 contract.\n * @notice Improved Solidity's arithmetic operations with added overflow checks.\n * @dev SafeMath96 uses uint96, unsigned integers of 96 bits length, so every\n * integer from 0 to 2^96-1 can be operated.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * SafeMath restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this contract instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n * */\ncontract SafeMath96 {\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function safe64(uint256 n, string memory errorMessage) internal pure returns (uint64) {\n require(n < 2**64, errorMessage);\n return uint64(n);\n }\n\n function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) {\n require(n < 2**96, errorMessage);\n return uint96(n);\n }\n\n /**\n * @notice Adds two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `+` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe addition a+b.\n * */\n function add96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n uint96 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n /**\n * @notice Substracts two unsigned integers, reverting on underflow.\n * @dev Counterpart to Solidity's `-` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on underflow.\n * @return The safe substraction a-b.\n * */\n function sub96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n require(b <= a, errorMessage);\n return a - b;\n }\n\n /**\n * @notice Multiplies two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `*` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe product a*b.\n * */\n function mul96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n if (a == 0) {\n return 0;\n }\n\n uint96 c = a * b;\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @notice Divides two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `/` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe division a/b.\n * */\n function div96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint96 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n}\n" + }, + "contracts/governance/Staking/StakingProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./modules/shared/StakingStorageShared.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Staking Proxy contract.\n * @dev Staking contract should be upgradable, use UpgradableProxy.\n * StakingStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingProxy is StakingStorageShared, UpgradableProxy {\n /**\n * @notice Construct a new staking contract.\n * @param SOV The address of the SOV token address.\n */\n constructor(address SOV) public {\n SOVToken = IERC20(SOV);\n kickoffTS = block.timestamp;\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewards.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Staking Rewards Contract.\n * @notice This is a trial incentive program.\n * In this, the SOV emitted and becoming liquid from the Adoption Fund could be utilized\n * to offset the higher APY's offered for Liquidity Mining events.\n * Vesting contract stakes are excluded from these rewards.\n * Only wallets which have staked previously liquid SOV are eligible for these rewards.\n * Tokenholders who stake their SOV receive staking rewards, a pro-rata share\n * of the revenue that the platform generates from various transaction fees\n * plus revenues from stakers who have a portion of their SOV slashed for\n * early unstaking.\n * */\ncontract StakingRewards is StakingRewardsStorage {\n using SafeMath for uint256;\n\n /// @notice Emitted when SOV is withdrawn\n /// @param receiver The address which recieves the SOV\n /// @param amount The amount withdrawn from the Smart Contract\n event RewardWithdrawn(address indexed receiver, uint256 amount);\n\n /**\n * @notice Replacement of constructor by initialize function for Upgradable Contracts\n * This function will be called only once by the owner.\n * @param _SOV SOV token address\n * @param _staking StakingProxy address should be passed\n * */\n function initialize(address _SOV, IStaking _staking) external onlyOwner {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n SOV = IERC20(_SOV);\n staking = _staking;\n startTime = staking.timestampToLockDate(block.timestamp);\n setMaxDuration(15 * TWO_WEEKS);\n deploymentBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Stops the current rewards program.\n * @dev All stakes existing on the contract at the point in time of\n * cancellation continue accruing rewards until the end of the staking\n * period being rewarded\n * */\n function stop() external onlyOwner {\n require(stopBlock == 0, \"Already stopped\");\n stopBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Collect rewards\n * @dev User calls this function to collect SOV staking rewards as per the SIP-0024 program.\n * The weighted stake is calculated using getPriorWeightedStake. Block number sent to the functon\n * must be a finalised block, hence we deduct 1 from the current block. User is only allowed to withdraw\n * after intervals of 14 days.\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * The issue is that we can only run for a max duration and if someone stakes for the\n * first time after the max duration is over, the reward will always return 0. Thus, we need to restart\n * from the duration that elapsed without generating rewards.\n * */\n function collectReward(uint256 restartTime) external {\n (uint256 withdrawalTime, uint256 amount) = getStakerCurrentReward(true, restartTime);\n require(withdrawalTime > 0 && amount > 0, \"no valid reward\");\n withdrawals[msg.sender] = withdrawalTime;\n _payReward(msg.sender, amount);\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred.\n */\n function withdrawTokensByOwner(address _receiverAddress) external onlyOwner {\n uint256 value = SOV.balanceOf(address(this));\n _transferSOV(_receiverAddress, value);\n }\n\n /**\n * @notice Changes average block time - based on blockchain\n * @dev If average block time significantly changes, we can update it here and use for block number calculation\n */\n function setAverageBlockTime(uint256 _averageBlockTime) external onlyOwner {\n averageBlockTime = _averageBlockTime;\n }\n\n /**\n * @notice This function computes the last staking checkpoint and calculates the corresponding\n * block number using the average block time which is then added to the mapping `checkpointBlockDetails`.\n */\n function setBlock() external {\n uint256 lastCheckpointTime = staking.timestampToLockDate(block.timestamp);\n _setBlock(lastCheckpointTime);\n }\n\n /**\n * @notice This function computes the block number using the average block time for a given historical\n * checkpoint which is added to the mapping `checkpointBlockDetails`.\n * @param _time Exact staking checkpoint time\n */\n function setHistoricalBlock(uint256 _time) external {\n _setBlock(_time);\n }\n\n /**\n * @notice Sets the max duration\n * @dev Rewards can be collected for a maximum duration at a time. This\n * is to avoid Block Gas Limit failures. Setting it zero would mean that it will loop\n * through the entire duration since the start of rewards program.\n * It should ideally be set to a value, for which the rewards can be easily processed.\n * @param _duration Max duration for which rewards can be collected at a go (in seconds)\n * */\n function setMaxDuration(uint256 _duration) public onlyOwner {\n maxDuration = _duration;\n }\n\n /**\n * @notice Internal function to calculate weighted stake\n * @dev If the rewards program is stopped, the user will still continue to\n * earn till the end of staking period based on the stop block.\n * @param _staker Staker address\n * @param _block Last finalised block\n * @param _date The date to compute prior weighted stakes\n * @return The weighted stake\n * */\n function _computeRewardForDate(\n address _staker,\n uint256 _block,\n uint256 _date\n ) internal view returns (uint256 weightedStake) {\n weightedStake = staking.getPriorWeightedStake(_staker, _block, _date);\n if (stopBlock > 0 && stopBlock < _block) {\n uint256 previousWeightedStake =\n staking.getPriorWeightedStake(_staker, stopBlock, _date);\n if (previousWeightedStake < weightedStake) {\n weightedStake = previousWeightedStake;\n }\n }\n }\n\n /**\n * @notice Internal function to pay rewards\n * @dev Base rate is annual, but we pay interest for 14 days,\n * which is 1/26 of one staking year (1092 days)\n * @param _staker User address\n * @param amount the reward amount\n * */\n function _payReward(address _staker, uint256 amount) internal {\n require(SOV.balanceOf(address(this)) >= amount, \"not enough funds to reward user\");\n claimedBalances[_staker] = claimedBalances[_staker].add(amount);\n _transferSOV(_staker, amount);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit RewardWithdrawn(_receiver, _amount);\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Internal function to calculate and set block\n * */\n function _setBlock(uint256 _checkpointTime) internal {\n uint256 currentTS = block.timestamp;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n require(checkpointBlockDetails[_checkpointTime] == 0, \"block number already set\");\n uint256 checkpointBlock =\n lastFinalisedBlock.sub(((currentTS.sub(_checkpointTime)).div(averageBlockTime)));\n checkpointBlockDetails[_checkpointTime] = checkpointBlock;\n }\n\n /**\n * @notice Get staker's current accumulated reward\n * @dev The collectReward() function internally calls this function to calculate reward amount\n * @param considerMaxDuration True: Runs for the maximum duration - used in tx not to run out of gas\n * False - to query total rewards\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * @return The timestamp of last withdrawal\n * @return The accumulated reward\n */\n function getStakerCurrentReward(bool considerMaxDuration, uint256 restartTime)\n public\n view\n returns (uint256 lastWithdrawalInterval, uint256 amount)\n {\n uint256 weightedStake;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n uint256 currentTS = block.timestamp;\n uint256 duration;\n address staker = msg.sender;\n uint256 lastWithdrawal = withdrawals[staker];\n\n uint256 lastStakingInterval = staking.timestampToLockDate(currentTS);\n lastWithdrawalInterval = lastWithdrawal > 0 ? lastWithdrawal : startTime;\n if (lastStakingInterval <= lastWithdrawalInterval) return (0, 0);\n /* Normally the restart time is 0. If this function returns a valid lastWithdrawalInterval\n\t\tand zero amount - that means there were no valid rewards for that period. So the new period must start\n\t\tfrom the end of the last interval or till the time no rewards are accumulated i.e. restartTime */\n if (restartTime >= lastWithdrawalInterval) {\n uint256 latestRestartTime = staking.timestampToLockDate(restartTime);\n lastWithdrawalInterval = latestRestartTime;\n }\n\n if (considerMaxDuration) {\n uint256 addedMaxDuration = lastWithdrawalInterval.add(maxDuration);\n duration = addedMaxDuration < currentTS\n ? staking.timestampToLockDate(addedMaxDuration)\n : lastStakingInterval;\n } else {\n duration = lastStakingInterval;\n }\n for (uint256 i = lastWithdrawalInterval; i < duration; i += TWO_WEEKS) {\n uint256 referenceBlock = checkpointBlockDetails[i];\n if (referenceBlock == 0) {\n referenceBlock = lastFinalisedBlock.sub(\n ((currentTS.sub(i)).div(averageBlockTime))\n );\n }\n if (referenceBlock < deploymentBlock) referenceBlock = deploymentBlock;\n weightedStake = weightedStake.add(_computeRewardForDate(staker, referenceBlock, i));\n }\n lastWithdrawalInterval = duration;\n amount = weightedStake.mul(BASE_RATE).div(DIVISOR);\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title StakingRewards Proxy contract.\n * @dev StakingRewards contract should be upgradable. Used UpgradableProxy.\n * StakingRewardsStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy with\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingRewardsProxy is StakingRewardsStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking Rewards Storage Contract.\n * @notice Just the storage part of staking rewards contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingRewardsProxy.\n *\n * What is SOV staking rewards - SIP-0024?\n * The purpose of the SOV staking rewards - SIP-0024 is to reward,\n * \"marginal stakers\" (ie, stakers by choice, not currently vesting) with liquid SOV\n * at the beginning of each new staking interval.\n * */\ncontract StakingRewardsStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n ///@notice the staking proxy contract address\n IStaking public staking;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 1209600;\n\n /// @notice Annual Base Rate - it is the maximum interest rate(APY)\n uint256 public constant BASE_RATE = 2975;\n\n /// @notice DIVISOR is set as 2600000 = 26 (num periods per year) * 10 (max voting weight) * 10000 (2975 -> 0.2975)\n uint256 public constant DIVISOR = 2600000;\n\n /// @notice Maximum duration to collect rewards at one go\n uint256 public maxDuration;\n\n /// @notice Represents the time when the contract is deployed\n uint256 public startTime;\n\n /// @notice Represents the block when the Staking Rewards pogram is stopped\n uint256 public stopBlock;\n\n /// @notice User Address -> Last Withdrawn Timestamp\n mapping(address => uint256) public withdrawals;\n\n /// @notice User Address -> Claimed Balance\n mapping(address => uint256) public claimedBalances;\n\n /// @notice Represents the block when the StakingRwards Program is started\n uint256 public deploymentBlock;\n\n /// Moved the variables from Initializable contract to resolve issue caused by incorrect Inheritance Order\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /// @notice BlockTime -> BlockNumber for a Staking Checkpoint\n mapping(uint256 => uint256) public checkpointBlockDetails;\n\n /// @notice Average Block Time - making it flexible\n uint256 public averageBlockTime;\n}\n" + }, + "contracts/governance/Timelock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./ErrorDecoder.sol\";\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\n/**\n * @title Sovryn Protocol Timelock contract, based on Compound system.\n *\n * @notice This contract lets Sovryn governance system set up its\n * own Time Lock instance to execute transactions proposed through the\n * GovernorAlpha contract instance.\n *\n * The Timelock contract allows its admin (Sovryn governance on\n * GovernorAlpha contract) to add arbitrary function calls to a\n * queue. This contract can only execute a function call if the\n * function call has been in the queue for at least 3 hours.\n *\n * Anytime the Timelock contract makes a function call, it must be the\n * case that the function call was first made public by having been publicly\n * added to the queue at least 3 hours prior.\n *\n * The intention is to provide GovernorAlpha contract the functionality to\n * queue proposal actions. This would mean that any changes made by Sovryn\n * governance of any contract would necessarily come with at least an\n * advanced warning. This makes the Sovryn system follow a “time-delayed,\n * opt-out” upgrade pattern (rather than an “instant, forced” upgrade pattern).\n *\n * Time-delaying admin actions gives users a chance to exit system if its\n * admins become malicious or compromised (or make a change that the users\n * do not like). Downside is that honest admins would be unable\n * to lock down functionality to protect users if a critical bug was found.\n *\n * Delayed transactions reduce the amount of trust required by users of Sovryn\n * and the overall risk for contracts building on top of it, as GovernorAlpha.\n * */\ncontract Timelock is ErrorDecoder, ITimelock {\n using SafeMath for uint256;\n\n uint256 public constant GRACE_PERIOD = 14 days;\n uint256 public constant MINIMUM_DELAY = 3 hours;\n uint256 public constant MAXIMUM_DELAY = 30 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /**\n * @notice Function called on instance deployment of the contract.\n * @param admin_ Governance contract address.\n * @param delay_ Time to wait for queued transactions to be executed.\n * */\n constructor(address admin_, uint256 delay_) public {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {}\n\n /**\n * @notice Set a new delay when executing the contract calls.\n * @param delay_ The amount of time to wait until execution.\n * */\n function setDelay(uint256 delay_) public {\n require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n require(delay_ >= MINIMUM_DELAY, \"Timelock::setDelay: Delay must exceed minimum delay.\");\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n /**\n * @notice Accept a new admin for the timelock.\n * */\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n /**\n * @notice Set a new pending admin for the timelock.\n * @param pendingAdmin_ The new pending admin address.\n * */\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n /**\n * @notice Queue a new transaction from the governance contract.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function queueTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public returns (bytes32) {\n require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n /**\n * @notice Cancel a transaction.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function cancelTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public {\n require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n /**\n * @notice Executes a previously queued transaction from the governance.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function executeTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public payable returns (bytes memory) {\n require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call.value(value)(callData);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"Timelock::executeTransaction: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"Timelock::executeTransaction: \", string(returnData)));\n }\n }\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n /**\n * @notice A function used to get the current Block Timestamp.\n * @dev Timestamp of the current block in seconds since the epoch.\n * It is a Unix time stamp. So, it has the complete information about\n * the date, hours, minutes, and seconds (in UTC) when the block was\n * created.\n * */\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" + }, + "contracts/governance/Vesting/DevelopmentFund.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Development Fund.\n * @author Franklin Richards\n * @notice You can use this contract for timed token release from Dev Fund.\n */\ncontract DevelopmentFund {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The current contract status.\n enum Status { Deployed, Active, Expired }\n Status public status;\n\n /// @notice The owner of the locked tokens (usually Governance).\n address public lockedTokenOwner;\n /// @notice The owner of the unlocked tokens (usually MultiSig).\n address public unlockedTokenOwner;\n /// @notice The emergency transfer wallet/contract.\n address public safeVault;\n /// @notice The new locked token owner waiting to be approved.\n address public newLockedTokenOwner;\n\n /// @notice The last token release timestamp or the time of contract creation.\n uint256 public lastReleaseTime;\n\n /// @notice The release duration array in seconds.\n uint256[] public releaseDuration;\n /// @notice The release token amount.\n uint256[] public releaseTokenAmount;\n\n /* Events */\n\n /// @notice Emitted when the contract is activated.\n event DevelopmentFundActivated();\n\n /// @notice Emitted when the contract is expired due to total token transfer.\n event DevelopmentFundExpired();\n\n /// @notice Emitted when a new locked owner is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current locked owner.\n event NewLockedOwnerAdded(address indexed _initiator, address indexed _newLockedOwner);\n\n /// @notice Emitted when a new locked owner is approved to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _oldLockedOwner The address of the previous locked owner.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current unlocked owner.\n event NewLockedOwnerApproved(\n address indexed _initiator,\n address indexed _oldLockedOwner,\n address indexed _newLockedOwner\n );\n\n /// @notice Emitted when a new unlocked owner is updated in the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newUnlockedOwner The address which is updated as the new unlocked owner.\n /// @dev Can only be initiated by the current locked owner.\n event UnlockedOwnerUpdated(address indexed _initiator, address indexed _newUnlockedOwner);\n\n /// @notice Emitted when a new token deposit is done.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new release schedule is created.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseCount The number of releases planned in the schedule.\n event TokenReleaseChanged(address indexed _initiator, uint256 _releaseCount);\n\n /// @notice Emitted when a unlocked owner transfers all the tokens to a safe vault.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token withdrawn.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done in an emergency situation only to a predetermined wallet by locked token owner.\n event LockedTokenTransferByUnlockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /// @notice Emitted when a unlocked owner withdraws the released tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token withdrawn.\n /// @param _releaseCount The total number of releases done based on duration.\n event UnlockedTokenWithdrawalByUnlockedOwner(\n address indexed _initiator,\n uint256 _amount,\n uint256 _releaseCount\n );\n\n /// @notice Emitted when a locked owner transfers all the tokens to a receiver.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token transfer.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done only by locked token owner.\n event LockedTokenTransferByLockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /* Modifiers */\n\n modifier onlyLockedTokenOwner() {\n require(msg.sender == lockedTokenOwner, \"Only Locked Token Owner can call this.\");\n _;\n }\n\n modifier onlyUnlockedTokenOwner() {\n require(msg.sender == unlockedTokenOwner, \"Only Unlocked Token Owner can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _lockedTokenOwner The owner of the locked tokens & contract.\n * @param _safeVault The emergency wallet/contract to transfer token.\n * @param _unlockedTokenOwner The owner of the unlocked tokens.\n * @param _lastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev Initial release schedule should be verified, error will result in either redeployment or calling changeTokenReleaseSchedule() after init() along with token transfer.\n */\n constructor(\n address _SOV,\n address _lockedTokenOwner,\n address _safeVault,\n address _unlockedTokenOwner,\n uint256 _lastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_lockedTokenOwner != address(0), \"Locked token & contract owner address invalid.\");\n require(_safeVault != address(0), \"Safe Vault address invalid.\");\n require(_unlockedTokenOwner != address(0), \"Unlocked token address invalid.\");\n\n SOV = IERC20(_SOV);\n lockedTokenOwner = _lockedTokenOwner;\n safeVault = _safeVault;\n unlockedTokenOwner = _unlockedTokenOwner;\n\n lastReleaseTime = _lastReleaseTime;\n /// If last release time passed is zero, then current time stamp will be used as the last release time.\n if (_lastReleaseTime == 0) {\n lastReleaseTime = block.timestamp;\n }\n\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n }\n\n /**\n * @notice This function is called once after deployment for token transfer based on schedule.\n * @dev Without calling this function, the contract will not work.\n */\n function init() public checkStatus(Status.Deployed) {\n uint256[] memory _releaseTokenAmount = releaseTokenAmount;\n require(_releaseTokenAmount.length != 0, \"Release Schedule not set.\");\n\n /// Getting the current release schedule total token amount.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _releaseTotalTokenAmount);\n require(txStatus, \"Not enough token sent to change release schedule.\");\n\n status = Status.Active;\n\n emit DevelopmentFundActivated();\n }\n\n /**\n * @notice Update Locked Token Owner.\n * @param _newLockedTokenOwner The owner of the locked tokens & contract.\n */\n function updateLockedTokenOwner(address _newLockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newLockedTokenOwner != address(0), \"New locked token owner address invalid.\");\n\n newLockedTokenOwner = _newLockedTokenOwner;\n\n emit NewLockedOwnerAdded(msg.sender, _newLockedTokenOwner);\n }\n\n /**\n * @notice Approve Locked Token Owner.\n * @dev This approval is an added security to avoid development fund takeover by a compromised locked token owner.\n */\n function approveLockedTokenOwner() public onlyUnlockedTokenOwner checkStatus(Status.Active) {\n require(newLockedTokenOwner != address(0), \"No new locked owner added.\");\n\n emit NewLockedOwnerApproved(msg.sender, lockedTokenOwner, newLockedTokenOwner);\n\n lockedTokenOwner = newLockedTokenOwner;\n\n newLockedTokenOwner = address(0);\n }\n\n /**\n * @notice Update Unlocked Token Owner.\n * @param _newUnlockedTokenOwner The new unlocked token owner.\n */\n function updateUnlockedTokenOwner(address _newUnlockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newUnlockedTokenOwner != address(0), \"New unlocked token owner address invalid.\");\n\n unlockedTokenOwner = _newUnlockedTokenOwner;\n\n emit UnlockedOwnerUpdated(msg.sender, _newUnlockedTokenOwner);\n }\n\n /**\n * @notice Deposit tokens to this contract.\n * @param _amount the amount of tokens deposited.\n * @dev These tokens can be withdrawn/transferred any time by the lockedTokenOwner.\n */\n function depositTokens(uint256 _amount) public checkStatus(Status.Active) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDeposit(msg.sender, _amount);\n }\n\n /**\n * @notice Change the Token release schedule. It creates a completely new schedule, and does not append on the previous one.\n * @param _newLastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev _releaseDuration and _releaseTokenAmount should be specified in reverse order of release.\n */\n function changeTokenReleaseSchedule(\n uint256 _newLastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public onlyLockedTokenOwner checkStatus(Status.Active) {\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// If the last release time has to be changed, then you can pass a new one here.\n /// Or else, the duration of release will be calculated based on this timestamp.\n /// Even a future timestamp can be mentioned here.\n if (_newLastReleaseTime != 0) {\n lastReleaseTime = _newLastReleaseTime;\n }\n\n /// Checking if the contract have enough token balance for the release.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n /// Getting the current token balance of the contract.\n uint256 remainingTokens = SOV.balanceOf(address(this));\n\n /// If the token balance is not sufficient, then we transfer the change to contract.\n if (remainingTokens < _releaseTotalTokenAmount) {\n bool txStatus =\n SOV.transferFrom(\n msg.sender,\n address(this),\n _releaseTotalTokenAmount.sub(remainingTokens)\n );\n require(txStatus, \"Not enough token sent to change release schedule.\");\n } else if (remainingTokens > _releaseTotalTokenAmount) {\n /// If there are more tokens than required, send the extra tokens back.\n bool txStatus =\n SOV.transfer(msg.sender, remainingTokens.sub(_releaseTotalTokenAmount));\n require(txStatus, \"Token not received by the Locked Owner.\");\n }\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n\n emit TokenReleaseChanged(msg.sender, _releaseDuration.length);\n }\n\n /**\n * @notice Transfers all of the remaining tokens in an emergency situation.\n * @dev This could be called when governance or development fund might be compromised.\n */\n function transferTokensByUnlockedTokenOwner()\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(safeVault, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByUnlockedOwner(msg.sender, safeVault, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /**\n * @notice Withdraws all unlocked/released token.\n * @param _amount The amount to be withdrawn.\n */\n function withdrawTokensByUnlockedTokenOwner(uint256 _amount)\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_amount > 0, \"Zero can't be withdrawn.\");\n\n uint256 count; /// To know how many elements to be removed from the release schedule.\n uint256 amount = _amount; /// To know the total amount to be transferred.\n uint256 newLastReleaseTimeMemory = lastReleaseTime; /// Better to use memory than storage.\n uint256 releaseLength = releaseDuration.length.sub(1); /// Also checks if there are any elements in the release schedule.\n\n /// Getting the amount of tokens, the number of releases and calculating the total duration.\n while (\n amount > 0 &&\n newLastReleaseTimeMemory.add(releaseDuration[releaseLength]) < block.timestamp\n ) {\n if (amount >= releaseTokenAmount[releaseLength]) {\n amount = amount.sub(releaseTokenAmount[releaseLength]);\n newLastReleaseTimeMemory = newLastReleaseTimeMemory.add(\n releaseDuration[releaseLength]\n );\n count++;\n } else {\n /// This will be the last case, if correct amount is passed.\n releaseTokenAmount[releaseLength] = releaseTokenAmount[releaseLength].sub(amount);\n amount = 0;\n }\n releaseLength--;\n }\n\n /// Checking to see if atleast a single schedule was reached or not.\n require(count > 0 || amount == 0, \"No release schedule reached.\");\n\n /// If locked token owner tries to send a higher amount that schedule\n uint256 value = _amount.sub(amount);\n\n /// Now clearing up the release schedule.\n releaseDuration.length -= count;\n releaseTokenAmount.length -= count;\n\n /// Updating the last release time.\n lastReleaseTime = newLastReleaseTimeMemory;\n\n /// Sending the amount to unlocked token owner.\n bool txStatus = SOV.transfer(msg.sender, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit UnlockedTokenWithdrawalByUnlockedOwner(msg.sender, value, count);\n }\n\n /**\n * @notice Transfers all of the remaining tokens by the owner maybe for an upgrade.\n * @dev This could be called when the current development fund has to be upgraded.\n * @param _receiver The address which receives this token transfer.\n */\n function transferTokensByLockedTokenOwner(address _receiver)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(_receiver, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByLockedOwner(msg.sender, _receiver, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token release duration.\n * @return _currentReleaseDuration The current release duration.\n */\n function getReleaseDuration() public view returns (uint256[] memory _releaseTokenDuration) {\n return releaseDuration;\n }\n\n /**\n * @notice Function to read the current token release amount.\n * @return _currentReleaseTokenAmount The current release token amount.\n */\n function getReleaseTokenAmount()\n public\n view\n returns (uint256[] memory _currentReleaseTokenAmount)\n {\n return releaseTokenAmount;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../IFeeSharingCollector.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../proxy/UpgradableProxy.sol\";\nimport \"../../../openzeppelin/Address.sol\";\n\n/**\n * @title Four Year Vesting Contract.\n *\n * @notice A four year vesting contract.\n *\n * @dev Vesting contract is upgradable,\n * Make sure the vesting owner is multisig otherwise it will be\n * catastrophic.\n * */\ncontract FourYearVesting is FourYearVestingStorage, UpgradableProxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharingCollector Fee sharing proxy address.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n address _feeSharingCollector,\n uint256 _extendDurationFor\n ) public {\n require(Address.isContract(_logic), \"_logic not a contract\");\n require(_SOV != address(0), \"SOV address invalid\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(Address.isContract(_stakingAddress), \"_stakingAddress not a contract\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(Address.isContract(_feeSharingCollector), \"_feeSharingCollector not a contract\");\n require((_extendDurationFor % FOUR_WEEKS) == 0, \"invalid duration\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n tokenOwner = _tokenOwner;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n maxInterval = 18 * FOUR_WEEKS;\n extendDurationFor = _extendDurationFor;\n }\n\n /**\n * @notice Set address of the implementation - vesting owner.\n * @dev Overriding setImplementation function of UpgradableProxy. The logic can only be\n * modified when both token owner and veting owner approve. Since\n * setImplementation can only be called by vesting owner, we also need to check\n * if the new logic is already approved by the token owner.\n * @param _implementation Address of the implementation. Must match with what is set by token owner.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n require(Address.isContract(_implementation), \"_implementation not a contract\");\n require(newImplementation == _implementation, \"address mismatch\");\n _setImplementation(_implementation);\n newImplementation = address(0);\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"./FourYearVesting.sol\";\nimport \"./IFourYearVestingFactory.sol\";\n\n/**\n * @title Four Year Vesting Factory: Contract to deploy four year vesting contracts.\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract FourYearVestingFactory is IFourYearVestingFactory, Ownable {\n /// @dev Added an event to keep track of the vesting contract created for a token owner\n event FourYearVestingCreated(address indexed tokenOwner, address indexed vestingAddress);\n\n /**\n * @notice Deploys four year vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwnerMultisig The address of an owner of vesting contract.\n * @dev _vestingOwnerMultisig should ALWAYS be multisig.\n * @param _fourYearVestingLogic The implementation contract.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * @return The four year vesting contract address.\n * */\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external onlyOwner returns (address) {\n address fourYearVesting =\n address(\n new FourYearVesting(\n _fourYearVestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _feeSharing,\n _extendDurationFor\n )\n );\n Ownable(fourYearVesting).transferOwnership(_vestingOwnerMultisig);\n emit FourYearVestingCreated(_tokenOwner, fourYearVesting);\n return fourYearVesting;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./IFourYearVesting.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Four Year Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by FourYearVestingFactory contract.\n * */\ncontract FourYearVestingLogic is IFourYearVesting, FourYearVestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n\n /* Events */\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n event TokenOwnerChanged(address indexed newOwner, address indexed oldOwner);\n\n /* Modifiers */\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Sets the max interval.\n * @param _interval Max interval for which tokens scheduled shall be staked.\n * */\n function setMaxInterval(uint256 _interval) external onlyOwner {\n require(_interval.mod(FOUR_WEEKS) == 0, \"invalid interval\");\n maxInterval = _interval;\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount)\n {\n (lastSchedule, remainingAmount) = _stakeTokens(msg.sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokensWithApproval(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) external onlyThisContract returns (uint256 lastSchedule, uint256 remainingAmount) {\n (lastSchedule, remainingAmount) = _stakeTokens(_sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) external onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n uint256 stakingEndDate = endDate;\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate.add(cliff); i <= stakingEndDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) external onlyTokenOwner {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external onlyTokenOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Change token owner - only vesting owner is allowed to change.\n * @dev Modifies token owner. This must be followed by approval\n * from token owner.\n * @param _newTokenOwner Address of new token owner.\n * */\n function changeTokenOwner(address _newTokenOwner) public onlyOwner {\n require(_newTokenOwner != address(0), \"invalid new token owner address\");\n require(_newTokenOwner != tokenOwner, \"same owner not allowed\");\n newTokenOwner = _newTokenOwner;\n }\n\n /**\n * @notice Approve token owner change - only token Owner.\n * @dev Token owner can only be modified\n * when both vesting owner and token owner have approved. This\n * function ascertains the approval of token owner.\n * */\n function approveOwnershipTransfer() public onlyTokenOwner {\n require(newTokenOwner != address(0), \"invalid address\");\n tokenOwner = newTokenOwner;\n newTokenOwner = address(0);\n emit TokenOwnerChanged(tokenOwner, msg.sender);\n }\n\n /**\n * @notice Set address of the implementation - only Token Owner.\n * @dev This function sets the new implementation address.\n * It must also be approved by the Vesting owner.\n * @param _newImplementation Address of the new implementation.\n * */\n function setImpl(address _newImplementation) public onlyTokenOwner {\n require(_newImplementation != address(0), \"invalid new implementation address\");\n newImplementation = _newImplementation;\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() external onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Extends stakes(unlocked till timeDuration) for four year vesting contracts.\n * @dev Tokens are vested for 4 years. Since the max staking\n * period is 3 years and the tokens are unlocked only after the first year(timeDuration) is\n * passed, hence, we usually extend the duration of staking for all unlocked tokens for the first\n * year by 3 years. In some cases, the timeDuration can differ.\n * */\n function extendStaking() external {\n uint256 timeDuration = startDate.add(extendDurationFor);\n uint256[] memory dates;\n uint96[] memory stakes;\n (dates, stakes) = staking.getStakes(address(this));\n\n for (uint256 i = 0; i < dates.length; i++) {\n if ((dates[i] < block.timestamp) && (dates[i] <= timeDuration) && (stakes[i] > 0)) {\n staking.extendStakingDuration(dates[i], dates[i].add(156 weeks));\n endDate = dates[i].add(156 weeks);\n } else {\n break;\n }\n }\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function _stakeTokens(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) internal returns (uint256 lastSchedule, uint256 remainingAmount) {\n // Creating a new staking schedule for the same vesting contract is disallowed unlike normal vesting\n require(\n (startDate == 0) ||\n (startDate > 0 && remainingStakeAmount > 0 && _restartStakeSchedule > 0),\n \"create new vesting address\"\n );\n uint256 restartDate;\n uint256 relativeAmount;\n // Calling the _stakeTokens function first time for the vesting contract\n // Runs for maxInterval only (consider maxInterval = 18 * 4 = 72 weeks)\n if (startDate == 0 && _restartStakeSchedule == 0) {\n startDate = staking.timestampToLockDate(block.timestamp); // Set only once\n durationLeft = duration; // We do not touch duration and cliff as they are used throughout\n cliffAdded = cliff; // Hence, durationLeft and cliffAdded is created\n }\n // Calling the _stakeTokens second/third time - we start from the end of previous interval\n // and the remaining amount(amount left after tokens are staked in the previous interval)\n if (_restartStakeSchedule > 0) {\n require(\n _restartStakeSchedule == lastStakingSchedule && _amount == remainingStakeAmount,\n \"invalid params\"\n );\n restartDate = _restartStakeSchedule;\n } else {\n restartDate = startDate;\n }\n // Runs only once when the _stakeTokens is called for the first time\n if (endDate == 0) {\n endDate = staking.timestampToLockDate(block.timestamp.add(duration));\n }\n uint256 addedMaxInterval = restartDate.add(maxInterval); // run for maxInterval\n if (addedMaxInterval < endDate) {\n // Runs for max interval\n lastStakingSchedule = addedMaxInterval;\n relativeAmount = (_amount.mul(maxInterval)).div(durationLeft); // (_amount * 18) / 39\n durationLeft = durationLeft.sub(maxInterval); // durationLeft - 18 periods(72 weeks)\n remainingStakeAmount = _amount.sub(relativeAmount); // Amount left to be staked in subsequent intervals\n } else {\n // Normal run\n lastStakingSchedule = endDate; // if staking intervals left < 18 periods(72 weeks)\n remainingStakeAmount = 0;\n durationLeft = 0;\n relativeAmount = _amount; // Stake all amount left\n }\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), relativeAmount);\n require(success, \"transfer failed\");\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), relativeAmount);\n\n staking.stakesBySchedule(\n relativeAmount,\n cliffAdded,\n duration.sub(durationLeft),\n FOUR_WEEKS,\n address(this),\n tokenOwner\n );\n if (durationLeft == 0) {\n // All tokens staked\n cliffAdded = 0;\n } else {\n cliffAdded = cliffAdded.add(maxInterval); // Add cliff to the end of previous maxInterval\n }\n\n emit TokensStaked(_sender, relativeAmount);\n return (lastStakingSchedule, remainingStakeAmount);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n /// @dev For four year vesting, withdrawal of stakes for the first year is not allowed. These\n /// stakes are extended for three years. In some cases the withdrawal may be allowed at a different\n /// time and hence we use extendDurationFor.\n for (uint256 i = startDate.add(extendDurationFor); i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number.sub(1));\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../Staking/interfaces/IStaking.sol\";\nimport \"../../IFeeSharingCollector.sol\";\n\n/**\n * @title Four Year Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for four year vesting.\n * It is parent of FourYearVestingLogic and FourYearVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract FourYearVestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n // Used lower case for cliff and duration to maintain consistency with normal vesting\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public constant cliff = 4 weeks;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public constant duration = 156 weeks;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n /// @notice Maximum interval to stake tokens at one go\n uint256 public maxInterval;\n\n /// @notice End of previous staking schedule.\n uint256 public lastStakingSchedule;\n\n /// @notice Amount of shares left to be staked.\n uint256 public remainingStakeAmount;\n\n /// @notice Durations left.\n uint256 public durationLeft;\n\n /// @notice Cliffs added.\n uint256 public cliffAdded;\n\n /// @notice Address of new token owner.\n address public newTokenOwner;\n\n /// @notice Address of new implementation.\n address public newImplementation;\n\n /// @notice Duration(from start) till the time unlocked tokens are extended(for 3 years)\n uint256 public extendDurationFor;\n\n /// @dev Please add new state variables below this line. Mark them internal and\n /// add a getter function while upgrading the contracts.\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IFourYearVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IFourYearVesting {\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount);\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingFactory contract to override empty\n * implemention of deployFourYearVesting function\n * and use an instance of FourYearVestingFactory.\n */\ninterface IFourYearVestingFactory {\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/GenericTokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\n\n/**\n * @title Token sender contract.\n *\n * @notice This contract includes functions to transfer tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract GenericTokenSender is AdminRole {\n /* Events */\n\n event TokensTransferred(address indexed token, address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer given amounts of tokens to the given addresses.\n * @param _token The address of the token.\n * @param _receivers The addresses of the receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferTokensUsingList(\n address _token,\n address[] calldata _receivers,\n uint256[] calldata _amounts\n ) external onlyAuthorized {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferTokens(_token, _receivers[i], _amounts[i]);\n }\n }\n\n function() external payable {}\n\n /**\n * @notice Transfer tokens to given address.\n * @param _token The address of the token.\n * @param _receiver The address of the token receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) external onlyAuthorized {\n _transferTokens(_token, _receiver, _amount);\n }\n\n function _transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n if (_token != address(0)) {\n require(IERC20(_token).transfer(_receiver, _amount), \"transfer failed\");\n } else {\n (bool success, ) = _receiver.call.value(_amount)(\"\");\n require(success, \"RBTC transfer failed\");\n }\n emit TokensTransferred(_token, _receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/ITeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for TeamVesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by Staking contract to cancel the team vesting\n * function having the vesting contract instance address.\n */\ninterface ITeamVesting {\n function startDate() external view returns (uint256);\n\n function cliff() external view returns (uint256);\n\n function endDate() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function tokenOwner() external view returns (address);\n\n function governanceWithdrawTokens(address receiver) external;\n}\n" + }, + "contracts/governance/Vesting/IVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IVesting {\n function duration() external returns (uint256);\n\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 amount) external;\n\n function tokenOwner() external view returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingFactory contract to override empty\n * implemention of deployVesting and deployTeamVesting functions\n * and on VestingRegistry contract to use an instance of VestingFactory.\n */\ninterface IVestingFactory {\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for upgradable Vesting Registry contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IVestingRegistry {\n function getVesting(address _tokenOwner) external view returns (address);\n\n function getTeamVesting(address _tokenOwner) external view returns (address);\n\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n function isVestingAddress(address _vestingAddress) external view returns (bool);\n\n function isTeamVesting(address _vestingAddress) external view returns (bool);\n}\n" + }, + "contracts/governance/Vesting/OrigingVestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./VestingRegistry.sol\";\n\n/**\n * @title Temp contract for checking address, creating and staking tokens.\n * @notice It casts an instance of vestingRegistry and by using createVesting\n * function it creates a vesting, gets it and stakes some tokens w/ this vesting.\n * */\ncontract OrigingVestingCreator is Ownable {\n VestingRegistry public vestingRegistry;\n\n mapping(address => bool) processedList;\n\n constructor(address _vestingRegistry) public {\n vestingRegistry = VestingRegistry(_vestingRegistry);\n }\n\n /**\n * @notice Create a vesting, get it and stake some tokens w/ this vesting.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount of tokens to be vested.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyOwner {\n require(_tokenOwner != address(0), \"Invalid address\");\n require(!processedList[_tokenOwner], \"Already processed\");\n\n processedList[_tokenOwner] = true;\n\n vestingRegistry.createVesting(_tokenOwner, _amount, _cliff, _duration);\n address vesting = vestingRegistry.getVesting(_tokenOwner);\n vestingRegistry.stakeTokens(vesting, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/OriginInvestorsClaim.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./VestingRegistry.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\n\n/**\n * @title Origin investors claim vested cSOV tokens.\n * @notice // TODO: fund this contract with a total amount of SOV needed to distribute.\n * */\ncontract OriginInvestorsClaim is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// VestingRegistry public constant vestingRegistry = VestingRegistry(0x80B036ae59B3e38B573837c01BB1DB95515b7E6B);\n\n uint256 public totalAmount;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant SOV_VESTING_CLIFF = 6 weeks;\n\n uint256 public kickoffTS;\n uint256 public vestingTerm;\n uint256 public investorsQty;\n bool public investorsListInitialized;\n VestingRegistry public vestingRegistry;\n IStaking public staking;\n IERC20 public SOVToken;\n\n /// @dev user => flag : Whether user has admin role.\n mapping(address => bool) public admins;\n\n /// @dev investor => Amount : Origin investors entitled to claim SOV.\n mapping(address => uint256) public investorsAmountsList;\n\n /* Events */\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n event InvestorsAmountsListAppended(uint256 qty, uint256 amount);\n event ClaimVested(address indexed investor, uint256 amount);\n event ClaimTransferred(address indexed investor, uint256 amount);\n event InvestorsAmountsListInitialized(uint256 qty, uint256 totalAmount);\n\n /* Modifiers */\n\n /// @dev Throws if called by any account other than the owner or admin.\n modifier onlyAuthorized() {\n require(\n isOwner() || admins[msg.sender],\n \"OriginInvestorsClaim::onlyAuthorized: should be authorized\"\n );\n _;\n }\n\n /// @dev Throws if called by any account not whitelisted.\n modifier onlyWhitelisted() {\n require(\n investorsAmountsList[msg.sender] != 0,\n \"OriginInvestorsClaim::onlyWhitelisted: not whitelisted or already claimed\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an initialized investors list.\n modifier notInitialized() {\n require(\n !investorsListInitialized,\n \"OriginInvestorsClaim::notInitialized: the investors list should not be set as initialized\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an uninitialized investors list.\n modifier initialized() {\n require(\n investorsListInitialized,\n \"OriginInvestorsClaim::initialized: the investors list has not been set yet\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires one parameter:\n * @param vestingRegistryAddress The vestingRegistry contract instance address.\n * */\n constructor(address vestingRegistryAddress) public {\n vestingRegistry = VestingRegistry(vestingRegistryAddress);\n staking = IStaking(vestingRegistry.staking());\n kickoffTS = staking.kickoffTS();\n SOVToken = IERC20(staking.SOVToken());\n vestingTerm = kickoffTS + SOV_VESTING_CLIFF;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice In case we have unclaimed tokens or in emergency case\n * this function transfers all SOV tokens to a given address.\n * @param toAddress The recipient address of all this contract tokens.\n * */\n function authorizedBalanceWithdraw(address toAddress) public onlyAuthorized {\n require(\n SOVToken.transfer(toAddress, SOVToken.balanceOf(address(this))),\n \"OriginInvestorsClaim::authorizedTransferBalance: transfer failed\"\n );\n }\n\n /**\n * @notice Should be called after the investors list setup completed.\n * This function checks whether the SOV token balance of the contract is\n * enough and sets status list to initialized.\n * */\n function setInvestorsAmountsListInitialized() public onlyAuthorized notInitialized {\n require(\n SOVToken.balanceOf(address(this)) >= totalAmount,\n \"OriginInvestorsClaim::setInvestorsAmountsList: the contract is not enough financed\"\n );\n\n investorsListInitialized = true;\n\n emit InvestorsAmountsListInitialized(investorsQty, totalAmount);\n }\n\n /**\n * @notice The contract should be approved or transferred necessary\n * amount of SOV prior to calling the function.\n * @param investors The list of investors addresses to add to the list.\n * Duplicates will be skipped.\n * @param claimAmounts The list of amounts for investors investors[i]\n * will receive claimAmounts[i] of SOV.\n * */\n function appendInvestorsAmountsList(\n address[] calldata investors,\n uint256[] calldata claimAmounts\n ) external onlyAuthorized notInitialized {\n uint256 subQty;\n uint256 sumAmount;\n require(\n investors.length == claimAmounts.length,\n \"OriginInvestorsClaim::appendInvestorsAmountsList: investors.length != claimAmounts.length\"\n );\n\n for (uint256 i = 0; i < investors.length; i++) {\n if (investorsAmountsList[investors[i]] == 0) {\n investorsAmountsList[investors[i]] = claimAmounts[i];\n sumAmount = sumAmount.add(claimAmounts[i]);\n } else {\n subQty = subQty.add(1);\n }\n }\n\n investorsQty = investorsQty.add(investors.length.sub(subQty));\n totalAmount = totalAmount.add(sumAmount);\n emit InvestorsAmountsListAppended(investors.length.sub(subQty), sumAmount);\n }\n\n /**\n * @notice Claim tokens from this contract.\n * If vestingTerm is not yet achieved a vesting is created.\n * Otherwise tokens are tranferred.\n * */\n function claim() external onlyWhitelisted initialized {\n if (now < vestingTerm) {\n createVesting();\n } else {\n transfer();\n }\n }\n\n /**\n * @notice Transfer tokens from this contract to a vestingRegistry contract.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to vesting contract.\n * */\n function createVesting() internal {\n uint256 cliff = vestingTerm.sub(now);\n uint256 duration = cliff;\n uint256 amount = investorsAmountsList[msg.sender];\n address vestingContractAddress;\n\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n vestingContractAddress == address(0),\n \"OriginInvestorsClaim::withdraw: the claimer has an active vesting contract\"\n );\n\n delete investorsAmountsList[msg.sender];\n\n vestingRegistry.createVesting(msg.sender, amount, cliff, duration);\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n SOVToken.transfer(address(vestingRegistry), amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n vestingRegistry.stakeTokens(vestingContractAddress, amount);\n\n emit ClaimVested(msg.sender, amount);\n }\n\n /**\n * @notice Transfer tokens from this contract to the sender.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to its account.\n * */\n function transfer() internal {\n uint256 amount = investorsAmountsList[msg.sender];\n\n delete investorsAmountsList[msg.sender];\n\n /**\n * @dev Withdraw only for those claiming after the cliff, i.e. without vesting contracts.\n * Those with vestingContracts should withdraw using Vesting.withdrawTokens\n * from Vesting (VestingLogic) contract.\n * */\n require(\n SOVToken.transfer(msg.sender, amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n\n emit ClaimTransferred(msg.sender, amount);\n }\n}\n" + }, + "contracts/governance/Vesting/TeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n//import \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../proxy/Proxy.sol\";\n\n/**\n * @title Team Vesting Contract.\n *\n * @notice A regular vesting contract, but the owner (governance) is able to\n * withdraw earlier without a slashing.\n *\n * @dev Vesting contracts shouldn't be upgradable,\n * use Proxy instead of UpgradableProxy.\n * */\ncontract TeamVesting is VestingStorage, Proxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollector\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_duration >= _cliff, \"duration must be bigger than or equal to the cliff\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n require(_duration <= staking.MAX_DURATION(), \"duration may not exceed the max duration\");\n tokenOwner = _tokenOwner;\n cliff = _cliff;\n duration = _duration;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n }\n}\n" + }, + "contracts/governance/Vesting/TokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title SOV Token sender contract.\n *\n * @notice This contract includes functions to transfer SOV tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract TokenSender is Ownable {\n /* Storage */\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @dev user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n constructor(address _SOV) public {\n require(_SOV != address(0), \"SOV address invalid\");\n\n SOV = _SOV;\n }\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Transfer given amounts of SOV to the given addresses.\n * @param _receivers The addresses of the SOV receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferSOVusingList(address[] memory _receivers, uint256[] memory _amounts)\n public\n onlyAuthorized\n {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferSOV(_receivers[i], _amounts[i]);\n }\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyAuthorized {\n _transferSOV(_receiver, _amount);\n }\n\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/Vesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./TeamVesting.sol\";\n\n/**\n * @title Vesting Contract.\n * @notice Team tokens and investor tokens are vested. Therefore, a smart\n * contract needs to be developed to enforce the vesting schedule.\n *\n * */\ncontract Vesting is TeamVesting {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollectorProxy\n )\n public\n TeamVesting(\n _logic,\n _SOV,\n _stakingAddress,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharingCollectorProxy\n )\n {}\n\n /**\n * @dev We need to add this implementation to prevent proxy call VestingLogic.governanceWithdrawTokens\n * @param receiver The receiver of the token withdrawal.\n * */\n function governanceWithdrawTokens(address receiver) public {\n revert(\"operation not supported\");\n }\n}\n" + }, + "contracts/governance/Vesting/VestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"./VestingRegistryLogic.sol\";\nimport \"./VestingLogic.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingCreator is AdminRole {\n using SafeMath for uint256;\n\n ///@notice Boolean to check both vesting creation and staking is completed for a record\n bool vestingCreated;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 2 weeks;\n\n ///@notice the SOV token contract\n IERC20 public SOV;\n\n ///@notice the vesting registry contract\n VestingRegistryLogic public vestingRegistryLogic;\n\n ///@notice Holds Vesting Data\n struct VestingData {\n uint256 amount;\n uint256 cliff;\n uint256 duration;\n bool governanceControl; ///@dev true - tokens can be withdrawn by governance\n address tokenOwner;\n uint256 vestingCreationType;\n }\n\n ///@notice list of vesting to be processed\n VestingData[] public vestingDataList;\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event TokensStaked(address indexed vesting, address indexed tokenOwner, uint256 amount);\n event VestingDataRemoved(address indexed caller, address indexed tokenOwner);\n event DataCleared(address indexed caller);\n\n constructor(address _SOV, address _vestingRegistryProxy) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_vestingRegistryProxy != address(0), \"Vesting registry address invalid\");\n\n SOV = IERC20(_SOV);\n vestingRegistryLogic = VestingRegistryLogic(_vestingRegistryProxy);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings to be processed to the list\n */\n function addVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _amounts,\n uint256[] calldata _cliffs,\n uint256[] calldata _durations,\n bool[] calldata _governanceControls,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n require(\n _tokenOwners.length == _amounts.length &&\n _tokenOwners.length == _cliffs.length &&\n _tokenOwners.length == _durations.length &&\n _tokenOwners.length == _governanceControls.length,\n \"arrays mismatch\"\n );\n\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(\n _durations[i] >= _cliffs[i],\n \"duration must be bigger than or equal to the cliff\"\n );\n require(_amounts[i] > 0, \"vesting amount cannot be 0\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_cliffs[i].mod(TWO_WEEKS) == 0, \"cliffs should have intervals of two weeks\");\n require(\n _durations[i].mod(TWO_WEEKS) == 0,\n \"durations should have intervals of two weeks\"\n );\n VestingData memory vestingData =\n VestingData({\n amount: _amounts[i],\n cliff: _cliffs[i],\n duration: _durations[i],\n governanceControl: _governanceControls[i],\n tokenOwner: _tokenOwners[i],\n vestingCreationType: _vestingCreationTypes[i]\n });\n vestingDataList.push(vestingData);\n }\n }\n\n /**\n * @notice Creates vesting contract and stakes tokens\n * @dev Vesting and Staking are merged for calls that fits the gas limit\n */\n function processNextVesting() external {\n processVestingCreation();\n processStaking();\n }\n\n /**\n * @notice Creates vesting contract without staking any tokens\n * @dev Separating the Vesting and Staking to tackle Block Gas Limit\n */\n function processVestingCreation() public {\n require(!vestingCreated, \"staking not done for the previous vesting\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n _createAndGetVesting(vestingData);\n vestingCreated = true;\n }\n }\n\n /**\n * @notice Staking vested tokens\n * @dev it can be the case when vesting creation and tokens staking can't be done in one transaction because of block gas limit\n */\n function processStaking() public {\n require(vestingCreated, \"cannot stake without vesting creation\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n address vestingAddress =\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n require(SOV.approve(address(vesting), vestingData.amount), \"Approve failed\");\n vesting.stakeTokens(vestingData.amount);\n emit TokensStaked(vestingAddress, vestingData.tokenOwner, vestingData.amount);\n address tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n vestingCreated = false;\n }\n\n /**\n * @notice removes next vesting data from the list\n * @dev we process inverted list\n * @dev we should be able to remove incorrect vesting data that can't be processed\n */\n function removeNextVesting() external onlyAuthorized {\n address tokenOwnerDetails;\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n\n /**\n * @notice removes all data about unprocessed vestings to be processed\n */\n function clearVestingDataList() public onlyAuthorized {\n delete vestingDataList;\n emit DataCleared(msg.sender);\n }\n\n /**\n * @notice returns address after vesting creation\n */\n function getVestingAddress() external view returns (address) {\n return\n _getVesting(\n vestingDataList[vestingDataList.length - 1].tokenOwner,\n vestingDataList[vestingDataList.length - 1].cliff,\n vestingDataList[vestingDataList.length - 1].duration,\n vestingDataList[vestingDataList.length - 1].governanceControl,\n vestingDataList[vestingDataList.length - 1].vestingCreationType\n );\n }\n\n /**\n * @notice returns period i.e. ((duration - cliff) / 4 WEEKS)\n * @dev will be used for deciding if vesting and staking needs to be processed\n * in a single transaction or separate transactions\n */\n function getVestingPeriod() external view returns (uint256) {\n uint256 duration = vestingDataList[vestingDataList.length - 1].duration;\n uint256 cliff = vestingDataList[vestingDataList.length - 1].cliff;\n uint256 fourWeeks = TWO_WEEKS.mul(2);\n uint256 period = duration.sub(cliff).div(fourWeeks);\n return period;\n }\n\n /**\n * @notice returns count of vestings to be processed\n */\n function getUnprocessedCount() external view returns (uint256) {\n return vestingDataList.length;\n }\n\n /**\n * @notice returns total amount of vestings to be processed\n */\n function getUnprocessedAmount() public view returns (uint256) {\n uint256 amount = 0;\n uint256 length = vestingDataList.length;\n for (uint256 i = 0; i < length; i++) {\n amount = amount.add(vestingDataList[i].amount);\n }\n return amount;\n }\n\n /**\n * @notice checks if contract balance is enough to process all vestings\n */\n function isEnoughBalance() public view returns (bool) {\n return SOV.balanceOf(address(this)) >= getUnprocessedAmount();\n }\n\n /**\n * @notice returns missed balance to process all vestings\n */\n function getMissingBalance() external view returns (uint256) {\n if (isEnoughBalance()) {\n return 0;\n }\n return getUnprocessedAmount() - SOV.balanceOf(address(this));\n }\n\n /**\n * @notice creates TeamVesting or Vesting contract\n * @dev new contract won't be created if account already has contract of the same type\n */\n function _createAndGetVesting(VestingData memory vestingData)\n internal\n returns (address vesting)\n {\n if (vestingData.governanceControl) {\n vestingRegistryLogic.createTeamVesting(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n } else {\n vestingRegistryLogic.createVestingAddr(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n }\n return\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n }\n\n /**\n * @notice returns an address of TeamVesting or Vesting contract (depends on a governance control)\n */\n function _getVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n bool _governanceControl,\n uint256 _vestingCreationType\n ) internal view returns (address vestingAddress) {\n if (_governanceControl) {\n vestingAddress = vestingRegistryLogic.getTeamVesting(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n } else {\n vestingAddress = vestingRegistryLogic.getVestingAddr(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n }\n }\n}\n" + }, + "contracts/governance/Vesting/VestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./Vesting.sol\";\nimport \"./TeamVesting.sol\";\nimport \"./IVestingFactory.sol\";\n\n/**\n * @title Vesting Factory: Contract to deploy vesting contracts\n * of two types: vesting (TokenHolder) and team vesting (Multisig).\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract VestingFactory is IVestingFactory, Ownable {\n address public vestingLogic;\n\n constructor(address _vestingLogic) public {\n require(_vestingLogic != address(0), \"invalid vesting logic address\");\n vestingLogic = _vestingLogic;\n }\n\n /**\n * @notice Deploys Vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner /// @dev owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new Vesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n\n /**\n * @notice Deploys Team Vesting contract.\n * @param _SOV The address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner //owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new TeamVesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by a VestingFactory contract.\n * */\ncontract VestingLogic is IVesting, VestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n /* Events */\n\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(\n address indexed caller,\n address receiver,\n uint256 startFrom,\n uint256 end\n );\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(uint256 _amount) public {\n _stakeTokens(msg.sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokensWithApproval(address _sender, uint256 _amount) public onlyThisContract {\n _stakeTokens(_sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * */\n function _stakeTokens(address _sender, uint256 _amount) internal {\n /// @dev Maybe better to allow staking unil the cliff was reached.\n if (startDate == 0) {\n startDate = staking.timestampToLockDate(block.timestamp);\n }\n endDate = staking.timestampToLockDate(block.timestamp + duration);\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), _amount);\n require(success);\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), _amount);\n\n staking.stakeBySchedule(_amount, cliff, duration, FOUR_WEEKS, address(this), tokenOwner);\n\n emit TokensStaked(_sender, _amount);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) public onlyOwners {\n uint256 startFrom = startDate + cliff;\n _withdrawTokens(receiver, startFrom, block.timestamp);\n }\n\n /**\n * @notice Withdraws unlocked tokens partially (based on the max withdraw iteration that has been set) from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n * @param maxWithdrawIterations max withdrawal iteration to work around block gas limit issue.\n * */\n function withdrawTokensStartingFrom(\n address receiver,\n uint256 startFrom,\n uint256 maxWithdrawIterations\n ) public onlyOwners {\n uint256 defaultStartFrom = startDate + cliff;\n\n startFrom = _timestampToLockDate(startFrom);\n startFrom = startFrom < defaultStartFrom ? defaultStartFrom : startFrom;\n\n // @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 maxWithdrawDate = (startFrom + (FOUR_WEEKS * (maxWithdrawIterations.sub(1))));\n uint256 endAt = endDate < maxWithdrawDate ? endDate : maxWithdrawDate;\n _withdrawTokens(receiver, startFrom, endAt);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param startFrom start withdrawal from date.\n * @param endAt end time for regular withdrawal\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(\n address receiver,\n uint256 startFrom,\n uint256 endAt\n ) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n if (staking.allUnlocked()) {\n end = endAt < endDate ? endAt : endDate;\n } else {\n end = endAt < block.timestamp ? endAt : block.timestamp;\n if (end > endDate) end = endDate;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startFrom; i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number - 1);\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver, startFrom, end);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) public onlyOwners {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() public onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = startDate + cliff;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / FOUR_WEEKS;\n lockDate = periodFromKickoff * FOUR_WEEKS + start;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Registry contract.\n *\n * @notice On January 25, 2020, Sovryn launched the Genesis Reservation system.\n * Sovryn community members who controlled a special NFT were granted access to\n * stake BTC or rBTC for cSOV tokens at a rate of 2500 satoshis per cSOV. Per\n * SIP-0003, up to 2,000,000 cSOV were made available in the Genesis event,\n * which will be redeemable on a 1:1 basis for cSOV, subject to approval by\n * existing SOV holders.\n *\n * On 15 Feb 2021 Sovryn is taking another step in its journey to decentralized\n * financial sovereignty with the vote on SIP 0005. This proposal will enable\n * participants of the Genesis Reservation system to redeem their reserved cSOV\n * tokens for SOV. They will also have the choice to redeem cSOV for rBTC if\n * they decide to exit the system.\n *\n * This contract deals with the vesting and redemption of cSOV tokens.\n * */\ncontract VestingRegistry is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The cSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract.\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVReImburse(address from, uint256 CSOVamount, uint256 reImburseAmount);\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing collector proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n //---ACL------------------------------------------------------------------\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * TODO: This ACL logic should be available on OpenZeppeling Ownable.sol\n * or on our own overriding sovrynOwnable. This same logic is repeated\n * on OriginInvestorsClaim.sol, TokenSender.sol and VestingRegistry2.sol\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice cSOV payout to sender with rBTC currency.\n * 1.- Check holder cSOV balance by adding up every cSOV token balance.\n * 2.- ReImburse rBTC if funds available.\n * 3.- And store holder address in processedList.\n */\n function reImburse() public isNotProcessed isNotBlacklisted {\n uint256 CSOVAmountWei = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n CSOVAmountWei = CSOVAmountWei.add(balance);\n }\n\n require(CSOVAmountWei > lockedAmount[msg.sender], \"holder has no CSOV\");\n CSOVAmountWei -= lockedAmount[msg.sender];\n processedList[msg.sender] = true;\n\n /**\n * @dev Found and fixed the SIP-0007 bug on VestingRegistry::reImburse formula.\n * More details at Documenting Code issues at point 11 in\n * https://docs.google.com/document/d/10idTD1K6JvoBmtPKGuJ2Ub_mMh6qTLLlTP693GQKMyU/\n * Previous buggy code: uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**10);\n * */\n uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**8);\n require(address(this).balance >= reImburseAmount, \"Not enough funds to reimburse\");\n msg.sender.transfer(reImburseAmount);\n\n emit CSOVReImburse(msg.sender, CSOVAmountWei, reImburseAmount);\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Exchange cSOV to SOV with 1:1 rate\n */\n function exchangeAllCSOV() public isNotProcessed isNotBlacklisted {\n processedList[msg.sender] = true;\n\n uint256 amount = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n amount += balance;\n }\n\n require(amount > lockedAmount[msg.sender], \"amount invalid\");\n amount -= lockedAmount[msg.sender];\n\n _createVestingForCSOV(amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param _vesting The address of Vesting contract.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n /// @dev TODO: Owner of OwnerVesting contracts - the same address as tokenOwner.\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry2.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title VestingRegistry 2 contract.\n * @notice One time contract needed to distribute tokens to origin sales investors.\n * */\ncontract VestingRegistry2 is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The CSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry3.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingRegistry3 is Ownable {\n using SafeMath for uint256;\n\n IVestingFactory public vestingFactory;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n //@notice fee sharing proxy\n address public feeSharingCollector;\n //@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n //TODO add to the documentation: address can have only one vesting of each type\n //user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n //user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n constructor(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"./VestingRegistryStorage.sol\";\n\ncontract VestingRegistryLogic is VestingRegistryStorage {\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event VestingCreationAndTypesSet(\n address indexed vesting,\n VestingCreationAndTypeDetails vestingCreationAndType\n );\n\n /**\n * @notice Replace constructor with initialize function for Upgradable Contracts\n * This function will be called only once by the owner\n * */\n function initialize(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner,\n address _lockedSOV,\n address[] calldata _vestingRegistries\n ) external onlyOwner initializer {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n require(_lockedSOV != address(0), \"LockedSOV address invalid\");\n\n _setVestingFactory(_vestingFactory);\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n lockedSOV = LockedSOV(_lockedSOV);\n for (uint256 i = 0; i < _vestingRegistries.length; i++) {\n require(_vestingRegistries[i] != address(0), \"Vesting registry address invalid\");\n vestingRegistries.push(IVestingRegistry(_vestingRegistries[i]));\n }\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) external onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Internal function that sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings that were deployed in previous vesting registries\n * @dev migration of data from previous vesting registy contracts\n */\n function addDeployedVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingCreationTypes[i] > 0, \"vesting creation type must be greater than 0\");\n _addDeployedVestings(_tokenOwners[i], _vestingCreationTypes[i]);\n }\n }\n\n /**\n * @notice adds four year vestings to vesting registry logic\n * @param _tokenOwners array of token owners\n * @param _vestingAddresses array of vesting addresses\n */\n function addFourYearVestings(\n address[] calldata _tokenOwners,\n address[] calldata _vestingAddresses\n ) external onlyAuthorized {\n require(_tokenOwners.length == _vestingAddresses.length, \"arrays mismatch\");\n uint256 vestingCreationType = 4;\n uint256 cliff = 4 weeks;\n uint256 duration = 156 weeks;\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(!isVesting[_vestingAddresses[i]], \"vesting exists\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingAddresses[i] != address(0), \"vesting cannot be 0 address\");\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwners[i],\n uint256(VestingType.Vesting),\n cliff,\n duration,\n vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n vestingCreationType,\n _vestingAddresses[i]\n );\n vestingsOf[_tokenOwners[i]].push(uid);\n isVesting[_vestingAddresses[i]] = true;\n }\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @dev Calls a public createVestingAddr function with vestingCreationType. This is to accomodate the existing logic for LockedSOV\n * @dev vestingCreationType 0 = LockedSOV\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAuthorized {\n createVestingAddr(_tokenOwner, _amount, _cliff, _duration, 3);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createVestingAddr(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.Vesting),\n _vestingCreationType\n );\n\n emit VestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) external onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.TeamVesting),\n _vestingCreationType\n );\n\n emit TeamVestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) external onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n * @dev Calls a public getVestingAddr function with cliff and duration. This is to accomodate the existing logic for LockedSOV\n * @dev We need to use LockedSOV.changeRegistryCliffAndDuration function very judiciously\n * @dev vestingCreationType 0 - LockedSOV\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return getVestingAddr(_tokenOwner, lockedSOV.cliff(), lockedSOV.duration(), 3);\n }\n\n /**\n * @notice public function that returns vesting contract address for the given token owner, cliff, duration\n * @dev Important: Please use this instead of getVesting function\n */\n function getVestingAddr(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner, cliff, duration\n */\n function getTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @dev check if the specific vesting address is team vesting or not\n * @dev read the vestingType from vestingCreationAndTypes storage\n *\n * @param _vestingAddress address of vesting contract\n *\n * @return true for teamVesting, false for normal vesting\n */\n function isTeamVesting(address _vestingAddress) external view returns (bool) {\n return (vestingCreationAndTypes[_vestingAddress].isSet &&\n vestingCreationAndTypes[_vestingAddress].vestingType ==\n uint32(VestingType.TeamVesting));\n }\n\n /**\n * @dev setter function to register existing vesting contract to vestingCreationAndTypes storage\n * @dev need to set the function visilibty to public to support VestingCreationAndTypeDetails struct as parameter\n *\n * @param _vestingAddresses array of vesting address\n * @param _vestingCreationAndTypes array for VestingCreationAndTypeDetails struct\n */\n function registerVestingToVestingCreationAndTypes(\n address[] memory _vestingAddresses,\n VestingCreationAndTypeDetails[] memory _vestingCreationAndTypes\n ) public onlyAuthorized {\n require(_vestingAddresses.length == _vestingCreationAndTypes.length, \"Unmatched length\");\n for (uint256 i = 0; i < _vestingCreationAndTypes.length; i++) {\n VestingCreationAndTypeDetails memory _vestingCreationAndType =\n _vestingCreationAndTypes[i];\n address _vestingAddress = _vestingAddresses[i];\n\n vestingCreationAndTypes[_vestingAddress] = _vestingCreationAndType;\n\n emit VestingCreationAndTypesSet(\n _vestingAddress,\n vestingCreationAndTypes[_vestingAddress]\n );\n }\n }\n\n /**\n * @notice Internal function to deploy Vesting/Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _type the type of vesting\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _type,\n uint256 _vestingCreationType\n ) internal returns (address) {\n address vesting;\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, _type, _cliff, _duration, _vestingCreationType)\n )\n );\n if (vestings[uid].vestingAddress == address(0)) {\n if (_type == 1) {\n vesting = vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n } else {\n vesting = vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n }\n vestings[uid] = Vesting(_type, _vestingCreationType, vesting);\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vesting] = true;\n\n vestingCreationAndTypes[vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(_type),\n vestingCreationType: uint128(_vestingCreationType)\n });\n\n emit VestingCreationAndTypesSet(vesting, vestingCreationAndTypes[vesting]);\n }\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice stores the addresses of Vesting contracts from all three previous versions of Vesting Registry\n */\n function _addDeployedVestings(address _tokenOwner, uint256 _vestingCreationType) internal {\n uint256 uid;\n uint256 i = _vestingCreationType - 1;\n\n address vestingAddress = vestingRegistries[i].getVesting(_tokenOwner);\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.Vesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n _vestingCreationType,\n vestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vestingAddress] = true;\n }\n\n address teamVestingAddress = vestingRegistries[i].getTeamVesting(_tokenOwner);\n if (teamVestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(teamVestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.TeamVesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.TeamVesting),\n _vestingCreationType,\n teamVestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[teamVestingAddress] = true;\n }\n }\n\n /**\n * @notice returns all vesting details for the given token owner\n */\n function getVestingsOf(address _tokenOwner) external view returns (Vesting[] memory) {\n uint256[] memory vestingIds = vestingsOf[_tokenOwner];\n uint256 length = vestingIds.length;\n Vesting[] memory _vestings = new Vesting[](vestingIds.length);\n for (uint256 i = 0; i < length; i++) {\n _vestings[i] = vestings[vestingIds[i]];\n }\n return _vestings;\n }\n\n /**\n * @notice returns cliff and duration for Vesting & TeamVesting contracts\n */\n function getVestingDetails(address _vestingAddress)\n external\n view\n returns (uint256 cliff, uint256 duration)\n {\n VestingLogic vesting = VestingLogic(_vestingAddress);\n return (vesting.cliff(), vesting.duration());\n }\n\n /**\n * @notice returns if the address is a vesting address\n */\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return isVesting[_vestingAddress];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./VestingRegistryStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Vesting Registry Proxy contract.\n * @dev Vesting Registry contract should be upgradable, use UpgradableProxy.\n * VestingRegistryStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract VestingRegistryProxy is VestingRegistryStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Initializable.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"../../locked/LockedSOV.sol\";\nimport \"./IVestingRegistry.sol\";\n\n/**\n * @title Vesting Registry Storage Contract.\n *\n * @notice This contract is just the storage required for vesting registry.\n * It is parent of VestingRegistryProxy and VestingRegistryLogic.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\n\ncontract VestingRegistryStorage is Initializable, AdminRole {\n ///@notice the vesting factory contract\n IVestingFactory public vestingFactory;\n\n ///@notice the Locked SOV contract\n ///@dev NOTES: No need to update lockedSOV in this contract, since it might break the vestingRegistry if the new lockedSOV does not have the same value of cliff & duration.\n ILockedSOV public lockedSOV;\n\n ///@notice the list of vesting registries\n IVestingRegistry[] public vestingRegistries;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n\n ///@notice fee sharing proxy\n address public feeSharingCollector;\n\n ///@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n ///@notice Vesting details\n struct Vesting {\n uint256 vestingType;\n uint256 vestingCreationType;\n address vestingAddress;\n }\n\n ///@notice A record of vesting details for a unique id\n ///@dev vestings[uid] returns vesting data\n mapping(uint256 => Vesting) public vestings;\n\n ///@notice A record of all unique ids for a particular token owner\n ///@dev vestingsOf[tokenOwner] returns array of unique ids\n mapping(address => uint256[]) public vestingsOf;\n\n ///@notice A record of all vesting addresses\n ///@dev isVesting[address] returns if the address is a vesting address\n mapping(address => bool) public isVesting;\n\n /// @notice Store vesting creation type & vesting type information\n /// @dev it is packed into 1 single storage slot for cheaper gas usage\n struct VestingCreationAndTypeDetails {\n bool isSet;\n uint32 vestingType;\n uint128 vestingCreationType;\n }\n\n ///@notice A record of all vesting addresses with the detail\n ///@dev vestingDetail[vestingAddress] returns Vesting struct data\n ///@dev can be used to easily check the vesting type / creation type based on the vesting address itself\n mapping(address => VestingCreationAndTypeDetails) public vestingCreationAndTypes;\n}\n" + }, + "contracts/governance/Vesting/VestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\n\n/**\n * @title Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for vesting.\n * It is parent of VestingLogic and TeamVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract VestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public cliff;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 constant FOUR_WEEKS = 4 weeks;\n}\n" + }, + "contracts/interfaces/IChai.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IERC20.sol\";\n\ninterface IPot {\n function dsr() external view returns (uint256);\n\n function chi() external view returns (uint256);\n\n function rho() external view returns (uint256);\n}\n\ncontract IChai is IERC20 {\n function move(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function join(address dst, uint256 wad) external;\n\n function draw(address src, uint256 wad) external;\n\n function exit(address src, uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IConverterAMM.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IConverterAMM {\n function withdrawFees(address receiver) external returns (uint256);\n}\n" + }, + "contracts/interfaces/IERC20.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ncontract IERC20 {\n string public name;\n uint8 public decimals;\n string public symbol;\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address _who) external view returns (uint256);\n\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/interfaces/IERC777.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777Token standard as defined in the EIP.\n *\n * This contract uses the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let\n * token holders and recipients react to token movements by using setting implementers\n * for the associated interfaces in said registry. See {IERC1820Registry} and\n * {ERC1820Implementer}.\n */\ninterface IERC777 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the smallest part of the token that is not divisible. This\n * means all token operations (creation, movement and destruction) must have\n * amounts that are a multiple of this number.\n *\n * For most token contracts, this value will equal 1.\n */\n function granularity() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by an account (`owner`).\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * If send or receive hooks are registered for the caller and `recipient`,\n * the corresponding functions will be called with `data` and empty\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes calldata data\n ) external;\n\n /**\n * @dev Destroys `amount` tokens from the caller's account, reducing the\n * total supply.\n *\n * If a send hook is registered for the caller, the corresponding function\n * will be called with `data` and empty `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n */\n function burn(uint256 amount, bytes calldata data) external;\n\n /**\n * @dev Returns true if an account is an operator of `tokenHolder`.\n * Operators can send and burn tokens on behalf of their owners. All\n * accounts are their own operator.\n *\n * See {operatorSend} and {operatorBurn}.\n */\n function isOperatorFor(address operator, address tokenHolder) external view returns (bool);\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor}.\n *\n * Emits an {AuthorizedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function authorizeOperator(address operator) external;\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor} and {defaultOperators}.\n *\n * Emits a {RevokedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function revokeOperator(address operator) external;\n\n /**\n * @dev Returns the list of default operators. These accounts are operators\n * for all token holders, even if {authorizeOperator} was never called on\n * them.\n *\n * This list is immutable, but individual holders may revoke these via\n * {revokeOperator}, in which case {isOperatorFor} will return false.\n */\n function defaultOperators() external view returns (address[] memory);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must\n * be an operator of `sender`.\n *\n * If send or receive hooks are registered for `sender` and `recipient`,\n * the corresponding functions will be called with `data` and\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - `sender` cannot be the zero address.\n * - `sender` must have at least `amount` tokens.\n * - the caller must be an operator for `sender`.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n /**\n * @dev Destoys `amount` tokens from `account`, reducing the total supply.\n * The caller must be an operator of `account`.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `data` and `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n * - the caller must be an operator for `account`.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n event Sent(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Minted(\n address indexed operator,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Burned(\n address indexed operator,\n address indexed from,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event AuthorizedOperator(address indexed operator, address indexed tokenHolder);\n\n event RevokedOperator(address indexed operator, address indexed tokenHolder);\n}\n" + }, + "contracts/interfaces/IERC777Recipient.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.\n *\n * Accounts can be notified of {IERC777} tokens being sent to them by having a\n * contract implement this interface (contract holders can be their own\n * implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Recipient {\n /**\n * @dev Called by an {IERC777} token contract whenever tokens are being\n * moved or created into a registered account (`to`). The type of operation\n * is conveyed by `from` being the zero address or not.\n *\n * This call occurs _after_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the post-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/IERC777Sender.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensSender standard as defined in the EIP.\n *\n * {IERC777} Token holders can be notified of operations performed on their\n * tokens by having a contract implement this interface (contract holders can be\n * their own implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Sender {\n /**\n * @dev Called by an {IERC777} token contract whenever a registered holder's\n * (`from`) tokens are about to be moved or destroyed. The type of operation\n * is conveyed by `to` being the zero address or not.\n *\n * This call occurs _before_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the pre-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/ILoanPool.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface ILoanPool {\n function tokenPrice() external view returns (uint256 price);\n\n function borrowInterestRate() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/ILoanTokenModules.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\ninterface ILoanTokenModules {\n /** EVENT */\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /// topic: 0x9bbd2de400810774339120e2f8a2b517ed748595e944529bba8ebabf314d0591\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n\n /** INTERFACE */\n\n /** START LOAN TOKEN SETTINGS LOWER ADMIN */\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n\n function setAdmin(address _admin) external;\n\n function setPauser(address _pauser) external;\n\n function setupLoanParams(LoanParams[] calldata loanParamsList, bool areTorqueLoans) external;\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external;\n\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) external;\n\n function toggleFunctionPause(\n string calldata funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) external;\n\n function setTransactionLimits(address[] calldata addresses, uint256[] calldata limits)\n external;\n\n function changeLoanTokenNameAndSymbol(string calldata _name, string calldata _symbol) external;\n\n /** END LOAN TOKEN SETTINGS LOWER ADMIN */\n\n /** START LOAN TOKEN LOGIC STANDARD */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n address affiliateReferrer, // The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes // Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function borrowInterestRate() external view returns (uint256);\n\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n\n function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid);\n\n function checkPause(string calldata funcId) external view returns (bool isPaused);\n\n function nextBorrowInterestRate(uint256 borrowAmount) external view returns (uint256);\n\n function totalAssetBorrow() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes calldata /// loanDataBytes: arbitrary order data (for future use).\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n );\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function setLiquidityMiningAddress(address LMAddress) external;\n\n function getLiquidityMiningAddress() external view returns (address);\n\n function setStakingContractAddress(address _stakingContractAddress) external;\n\n function getStakingContractAddress() external view returns (address);\n\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n external\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n );\n\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 depositAmount);\n\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 borrowAmount);\n\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) external view;\n\n function getMaxEscrowAmount(uint256 leverageAmount)\n external\n view\n returns (uint256 maxEscrowAmount);\n\n function checkpointPrice(address _user) external view returns (uint256 price);\n\n function assetBalanceOf(address _owner) external view returns (uint256);\n\n function profitOf(address user) external view returns (int256);\n\n function tokenPrice() external view returns (uint256 price);\n\n function avgBorrowInterestRate() external view returns (uint256);\n\n function supplyInterestRate() external view returns (uint256);\n\n function nextSupplyInterestRate(uint256 supplyAmount) external view returns (uint256);\n\n function totalSupplyInterestRate(uint256 assetSupply) external view returns (uint256);\n\n function loanTokenAddress() external view returns (address);\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n external\n view\n returns (uint256, uint256);\n\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external;\n\n /** START LOAN TOKEN BASE */\n function initialPrice() external view returns (uint256);\n\n /** START LOAN TOKEN LOGIC LM */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external returns (uint256 minted);\n\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 redeemed);\n\n /** START LOAN TOKEN LOGIC WRBTC */\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n returns (uint256 mintAmount);\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function marketLiquidity() external view returns (uint256);\n\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n external\n view\n returns (uint256);\n\n /** START LOAN TOKEN LOGIC STORAGE */\n function pauser() external view returns (address);\n\n function liquidityMiningAddress() external view returns (address);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n /** START ADVANCED TOKEN */\n function approve(address _spender, uint256 _value) external returns (bool);\n\n /** START ADVANCED TOKEN STORAGE */\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function balanceOf(address _owner) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function loanParamsIds(uint256) external view returns (bytes32);\n}\n" + }, + "contracts/interfaces/ISovryn.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\npragma experimental ABIEncoderV2;\n//TODO: stored in ./interfaces only while brownie isn't removed\n//TODO: move to contracts/interfaces after with brownie is removed\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\ncontract ISovryn is\n State,\n ProtocolSettingsEvents,\n LoanSettingsEvents,\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n LoanClosingsEvents,\n SwapsEvents,\n AffiliatesEvents,\n FeesEvents\n{\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n ////// Protocol //////\n\n function replaceContract(address target) external;\n\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\n\n function getTarget(string calldata sig) external view returns (address);\n\n ////// Protocol Settings //////\n\n function setSovrynProtocolAddress(address newProtocolAddress) external;\n\n function setSOVTokenAddress(address newSovTokenAddress) external;\n\n function setLockedSOVAddress(address newSOVLockedAddress) external;\n\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\n\n function setPriceFeedContract(address newContract) external;\n\n function setSwapsImplContract(address newContract) external;\n\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\n\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\n\n function setLendingFeePercent(uint256 newValue) external;\n\n function setTradingFeePercent(uint256 newValue) external;\n\n function setBorrowingFeePercent(uint256 newValue) external;\n\n function setSwapExternalFeePercent(uint256 newValue) external;\n\n function setAffiliateFeePercent(uint256 newValue) external;\n\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\n\n function setLiquidationIncentivePercent(uint256 newAmount) external;\n\n function setMaxDisagreement(uint256 newAmount) external;\n\n function setSourceBuffer(uint256 newAmount) external;\n\n function setMaxSwapSize(uint256 newAmount) external;\n\n function setFeesController(address newController) external;\n\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n returns (address, bool);\n\n function depositProtocolToken(uint256 amount) external;\n\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function setWrbtcToken(address wrbtcTokenAddress) external;\n\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\n\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\n\n function setRolloverBaseReward(uint256 transactionCost) external;\n\n function setRebatePercent(uint256 rebatePercent) external;\n\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external;\n\n function getSpecialRebates(address sourceToken, address destToken)\n external\n view\n returns (uint256 specialRebatesPercent);\n\n function togglePaused(bool paused) external;\n\n function isProtocolPaused() external view returns (bool);\n\n ////// SwapsImplSovrynSwapModule //////\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (address);\n\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\n\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn);\n\n ////// Loan Settings //////\n\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function getLoanParams(bytes32[] calldata loanParamsIdList)\n external\n view\n returns (LoanParams[] memory loanParamsList);\n\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n\n ////// Loan Openings //////\n\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external;\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n ////// Loan Closings //////\n\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n );\n\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata loanDataBytes\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n ////// Loan Maintenance //////\n\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount // must match msg.value if ether is sent\n ) external payable;\n\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 actualWithdrawAmount);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n );\n\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; // collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\n\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\n\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external returns (uint256 secondsExtended);\n\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 secondsReduced);\n\n ////// Swaps External //////\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view;\n\n ////// Affiliates Module //////\n\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\n\n function setUserNotFirstTradeFlag(address user) external;\n\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\n\n function getReferralsList(address referrer) external view returns (address[] memory refList);\n\n function getAffiliatesReferrerBalances(address referrer)\n external\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\n\n function getAffiliatesReferrerTokensList(address referrer)\n external\n view\n returns (address[] memory tokensList);\n\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n external\n view\n returns (uint256);\n\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) external;\n\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\n\n function getProtocolAddress() external view returns (address);\n\n function getSovTokenAddress() external view returns (address);\n\n function getLockedSOVAddress() external view returns (address);\n\n function getFeeRebatePercent() external view returns (uint256);\n\n function getMinReferralsToPayout() external view returns (uint256);\n\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\n\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\n\n function getAffiliateTradingTokenFeePercent()\n external\n view\n returns (uint256 affiliateTradingTokenFeePercent);\n\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount);\n\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\n\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\n\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\n\n function getDedicatedSOVRebate() external view returns (uint256);\n\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\n\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory);\n\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\n\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external;\n\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\n\n function setAdmin(address newAdmin) external;\n\n function getAdmin() external view returns (address);\n\n function setPauser(address newPauser) external;\n\n function getPauser() external view returns (address);\n}\n" + }, + "contracts/interfaces/IWrbtc.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface IWrbtc {\n function deposit() external payable;\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IWrbtcERC20.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IWrbtc.sol\";\nimport \"./IERC20.sol\";\n\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\n" + }, + "contracts/locked/ILockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title The Locked SOV Interface.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This interface is an incomplete yet useful for future migration of LockedSOV Contract.\n * @dev Only use it if you know what you are doing.\n */\ninterface ILockedSOV {\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external;\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external;\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external;\n\n function cliff() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function getLockedBalance(address _addr) external view returns (uint256 _balance);\n\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance);\n}\n" + }, + "contracts/locked/LockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../governance/Vesting/VestingRegistry.sol\";\nimport \"../governance/Vesting/VestingLogic.sol\";\nimport \"./ILockedSOV.sol\";\n\n/**\n * @title The Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This contract is used to receive reward from other contracts, Create Vesting and Stake Tokens.\n */\ncontract LockedSOV is ILockedSOV {\n using SafeMath for uint256;\n\n uint256 public constant MAX_BASIS_POINT = 10000;\n uint256 public constant MAX_DURATION = 37;\n\n /* Storage */\n\n /// @notice True if the migration to a new Locked SOV Contract has started.\n bool public migration;\n\n /// @notice The cliff is the time period after which the tokens begin to unlock.\n uint256 public cliff;\n /// @notice The duration is the time period after all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n /// @notice The Vesting registry contract.\n VestingRegistry public vestingRegistry;\n /// @notice The New (Future) Locked SOV.\n ILockedSOV public newLockedSOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) private lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) private unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) private isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /// @notice Emitted when Vesting Registry, Duration and/or Cliff is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vestingRegistry The Vesting Registry Contract.\n /// @param _cliff The time period after which the tokens begin to unlock.\n /// @param _duration The time period after all tokens will have been unlocked.\n event RegistryCliffAndDurationUpdated(\n address indexed _initiator,\n address indexed _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n );\n\n /// @notice Emitted when a new deposit is made.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user to whose un/locked balance a new deposit was made.\n /// @param _sovAmount The amount of SOV to be added to the un/locked balance.\n /// @param _basisPoint The % (in Basis Point) which determines how much will be unlocked immediately.\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n /// @notice Emitted when a user withdraws the fund.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _sovAmount The amount of SOV withdrawn from the unlocked balance.\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n /// @notice Emitted when a user creates a vesting for himself.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _vesting The Vesting Contract.\n event VestingCreated(\n address indexed _initiator,\n address indexed _userAddress,\n address indexed _vesting\n );\n\n /// @notice Emitted when a user stakes tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vesting The Vesting Contract.\n /// @param _amount The amount of locked tokens staked by the user.\n event TokenStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /// @notice Emitted when an admin initiates a migration to new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedSOV The address of the new Locked SOV Contract.\n event MigrationStarted(address indexed _initiator, address indexed _newLockedSOV);\n\n /// @notice Emitted when a user initiates the transfer to a new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of locked tokens to transfer from this contract to the new one.\n event UserTransfered(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n modifier migrationAllowed {\n require(migration, \"Migration has not yet started.\");\n _;\n }\n\n /* Constructor */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV Token Address.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @param _admins The list of Admins to be added.\n */\n constructor(\n address _SOV,\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration,\n address[] memory _admins\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_vestingRegistry != address(0), \"Vesting registry address is invalid.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n SOV = IERC20(_SOV);\n vestingRegistry = VestingRegistry(_vestingRegistry);\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /* Public or External Functions */\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n * @dev Only callable by an Admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address.\");\n require(!isAdmin[_newAdmin], \"Address is already admin.\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n * @dev Only callable by an Admin.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin.\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice The function to update the Vesting Registry, Duration and Cliff.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @dev IMPORTANT 1: You have to change Vesting Registry if you want to change Duration and/or Cliff.\n * IMPORTANT 2: `_cliff` and `_duration` is multiplied by 4 weeks in this function.\n */\n function changeRegistryCliffAndDuration(\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAdmin {\n require(\n address(vestingRegistry) != _vestingRegistry,\n \"Vesting Registry has to be different for changing duration and cliff.\"\n );\n /// If duration is also zero, then it is similar to Unlocked SOV.\n require(_duration != 0, \"Duration cannot be zero.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n vestingRegistry = VestingRegistry(_vestingRegistry);\n\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n emit RegistryCliffAndDurationUpdated(msg.sender, _vestingRegistry, _cliff, _duration);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // MAX_BASIS_POINT is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < MAX_BASIS_POINT, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(MAX_BASIS_POINT);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice A function to withdraw the unlocked balance.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdraw(address _receiverAddress) public {\n _withdraw(msg.sender, _receiverAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n /**\n * @notice Creates vesting if not already created and Stakes tokens for a user.\n * @dev Only use this function if the `duration` is small.\n */\n function createVestingAndStake() public {\n _createVestingAndStake(msg.sender);\n }\n\n function _createVestingAndStake(address _sender) private {\n address vestingAddr = _getVesting(_sender);\n\n if (vestingAddr == address(0)) {\n vestingAddr = _createVesting(_sender);\n }\n\n _stakeTokens(_sender, vestingAddr);\n }\n\n /**\n * @notice Creates vesting contract (if it hasn't been created yet) for the calling user.\n * @return _vestingAddress The New Vesting Contract Created.\n */\n function createVesting() public returns (address _vestingAddress) {\n _vestingAddress = _createVesting(msg.sender);\n }\n\n /**\n * @notice Stakes tokens for a user who already have a vesting created.\n * @dev The user should already have a vesting created, else this function will throw error.\n */\n function stakeTokens() public {\n VestingLogic vesting = VestingLogic(_getVesting(msg.sender));\n\n require(\n cliff == vesting.cliff() && duration == vesting.duration(),\n \"Wrong Vesting Schedule.\"\n );\n\n _stakeTokens(msg.sender, address(vesting));\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdrawAndStakeTokens(address _receiverAddress) external {\n _withdraw(msg.sender, _receiverAddress);\n _createVestingAndStake(msg.sender);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n /**\n * @notice Function to start the process of migration to new contract.\n * @param _newLockedSOV The new locked sov contract address.\n */\n function startMigration(address _newLockedSOV) external onlyAdmin {\n require(_newLockedSOV != address(0), \"New Locked SOV Address is Invalid.\");\n newLockedSOV = ILockedSOV(_newLockedSOV);\n SOV.approve(_newLockedSOV, SOV.balanceOf(address(this)));\n migration = true;\n\n emit MigrationStarted(msg.sender, _newLockedSOV);\n }\n\n /**\n * @notice Function to transfer the locked balance from this contract to new LockedSOV Contract.\n * @dev Address is not specified to discourage selling lockedSOV to other address.\n */\n function transfer() external migrationAllowed {\n uint256 amount = lockedBalances[msg.sender];\n lockedBalances[msg.sender] = 0;\n\n newLockedSOV.depositSOV(msg.sender, amount);\n\n emit UserTransfered(msg.sender, amount);\n }\n\n /* Internal Functions */\n\n /**\n * @notice Creates a Vesting Contract for a user.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n * @dev Does not do anything if Vesting Contract was already created.\n */\n function _createVesting(address _tokenOwner) internal returns (address _vestingAddress) {\n /// Here zero is given in place of amount, as amount is not really used in `vestingRegistry.createVesting()`.\n vestingRegistry.createVesting(_tokenOwner, 0, cliff, duration);\n _vestingAddress = _getVesting(_tokenOwner);\n emit VestingCreated(msg.sender, _tokenOwner, _vestingAddress);\n }\n\n /**\n * @notice Returns the Vesting Contract Address.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n */\n function _getVesting(address _tokenOwner) internal view returns (address _vestingAddress) {\n return vestingRegistry.getVesting(_tokenOwner);\n }\n\n /**\n * @notice Stakes the tokens in a particular vesting contract.\n * @param _vesting The Vesting Contract Address.\n */\n function _stakeTokens(address _sender, address _vesting) internal {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n require(SOV.approve(_vesting, amount), \"Approve failed.\");\n VestingLogic(_vesting).stakeTokens(amount);\n\n emit TokenStaked(_sender, _vesting, amount);\n }\n\n /* Getter or Read Functions */\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) external view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n\n /**\n * @notice The function to check is an address is admin or not.\n * @param _addr The address of the user to check the admin status.\n * @return _status True if admin, False otherwise.\n */\n function adminStatus(address _addr) external view returns (bool _status) {\n return isAdmin[_addr];\n }\n}\n" + }, + "contracts/mixins/EnumerableAddressSet.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Based on Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * As of v2.5.0, only `address` sets are supported.\n *\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\n *\n * _Available since v2.5.0._\n */\nlibrary EnumerableAddressSet {\n struct AddressSet {\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(address => uint256) index;\n address[] values;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n * Returns false if the value was already in the set.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n * Returns false if the value was not present in the set.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n // If the element we're deleting is the last one, we can just remove it without doing a swap\n if (lastIndex != toDeleteIndex) {\n address lastValue = set.values[lastIndex];\n\n // Move the last value to the index where the deleted value is\n set.values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n // Delete the index entry for the deleted value\n delete set.index[value];\n\n // Delete the old entry for the moved value\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns an array with all values in the set. O(N).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\n address[] memory output = new address[](set.values.length);\n for (uint256 i; i < set.values.length; i++) {\n output[i] = set.values[i];\n }\n return output;\n }\n\n /**\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n \n * @param start start index of chunk\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\n */\n function enumerateChunk(\n AddressSet storage set,\n uint256 start,\n uint256 count\n ) internal view returns (address[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = (set.values.length < end || count == 0) ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new address[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @dev Returns the number of elements on the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /** @dev Returns the element stored at position `index` in the set. O(1).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes32Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\n * */\nlibrary EnumerableBytes32Set {\n struct Bytes32Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes32 => uint256) index;\n bytes32[] values;\n }\n\n /**\n * @notice Add an address value to a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to add.\n *\n * @return False if the value was already in the set.\n */\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return addBytes32(set, value);\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove an address value from a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to remove.\n *\n * @return False if the address was not present in the set.\n */\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return removeBytes32(set, value);\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function containsAddress(Bytes32Set storage set, address addrvalue)\n internal\n view\n returns (bool)\n {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes32Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes32[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes32[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes4Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`.\n * */\nlibrary EnumerableBytes4Set {\n struct Bytes4Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes4 => uint256) index;\n bytes4[] values;\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes4 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes4Set storage set, bytes4 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes4Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes4[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes4[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes4Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes4Set storage set, uint256 index) internal view returns (bytes4) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/FeesHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ISovryn.sol\";\nimport \"../core/objects/LoanParamsStruct.sol\";\n\n/**\n * @title The Fees Helper contract.\n *\n * This contract calculates and pays lending/borrow fees and rewards.\n * */\ncontract FeesHelper is State, FeesEvents {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Calculate trading fee.\n * @param feeTokenAmount The amount of tokens to trade.\n * @return The fee of the trade.\n * */\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\n }\n\n /**\n * @notice Calculate swap external fee.\n * @param feeTokenAmount The amount of token to swap.\n * @return The fee of the swap.\n */\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\n }\n\n /*\n\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - tradingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);\n\t}*/\n\n /**\n * @notice Calculate the loan origination fee.\n * @param feeTokenAmount The amount of tokens to borrow.\n * @return The fee of the loan.\n * */\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\n /*\n\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - borrowingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);*/\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\n *\n * @param referrer The affiliate referrer address to send the reward to.\n * @param trader The account that performs this trade.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n *\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\n * */\n function _payTradingFeeToAffiliate(\n address referrer,\n address trader,\n address feeToken,\n uint256 tradingFee\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\n address(this)\n )\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n * */\n function _payTradingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 tradingFee\n ) internal {\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\n if (tradingFee != 0) {\n if (affiliatesUserReferrer[user] != address(0)) {\n _payTradingFeeToAffiliate(\n affiliatesUserReferrer[user],\n user,\n feeToken,\n protocolTradingFee\n );\n protocolTradingFee = (\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\n )\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\n }\n\n /// Increase the storage variable keeping track of the accumulated fees.\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\n protocolTradingFee\n );\n\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\n }\n }\n\n /**\n * @notice Settle the borrowing fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the borrowig fee is paid.\n * @param borrowingFee The height of the fee.\n * */\n function _payBorrowingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 borrowingFee\n ) internal {\n if (borrowingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\n\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\n }\n }\n\n /**\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\n * @param user The address to send the reward to.\n * @param feeToken The address of the token in which the lending fee is paid.\n * @param lendingFee The height of the fee.\n * */\n function _payLendingFee(\n address user,\n address feeToken,\n uint256 lendingFee\n ) internal {\n if (lendingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\n\n emit PayLendingFee(user, feeToken, lendingFee);\n\n //// NOTE: Lenders do not receive a fee reward ////\n }\n }\n\n /// Settle and pay borrowers based on the fees generated by their interest payments.\n function _settleFeeRewardForInterestExpense(\n LoanInterest storage loanInterestLocal,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n address user,\n uint256 interestTime\n ) internal {\n /// This represents the fee generated by a borrower's interest payment.\n uint256 interestExpenseFee =\n interestTime\n .sub(loanInterestLocal.updatedTimestamp)\n .mul(loanInterestLocal.owedPerDay)\n .mul(lendingFeePercent)\n .div(1 days * 10**20);\n\n loanInterestLocal.updatedTimestamp = interestTime;\n\n if (interestExpenseFee != 0) {\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\n }\n }\n\n /**\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associeated loan - used for logging only.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * */\n function _payFeeReward(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 feeAmount\n ) internal {\n uint256 rewardAmount;\n uint256 _feeRebatePercent = feeRebatePercent;\n address _priceFeeds = priceFeeds;\n\n if (specialRebates[feeToken][feeTokenPair] > 0) {\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\n }\n\n /// Note: this should be refactored.\n /// Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\n feeAmount.mul(_feeRebatePercent).div(10**20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n // Check the dedicated SOV that is used to pay trading rebate rewards\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"deposit(address,uint256,uint256)\",\n user,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n )\n );\n\n if (success) {\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\n\n emit EarnReward(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n } else {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n }\n}\n" + }, + "contracts/mixins/InterestUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"./FeesHelper.sol\";\n\n/**\n * @title The Interest User contract.\n *\n * This contract pays loan interests.\n * */\ncontract InterestUser is VaultController, FeesHelper {\n using SafeERC20 for IERC20;\n\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n /**\n * @notice Internal function to pay interest of a loan.\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * */\n function _payInterest(address lender, address interestToken) internal {\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\n\n uint256 interestOwedNow = 0;\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\n interestOwedNow = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(1 days);\n\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n\n if (interestOwedNow > lenderInterestLocal.owedTotal)\n interestOwedNow = lenderInterestLocal.owedTotal;\n\n if (interestOwedNow != 0) {\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\n\n _payInterestTransfer(lender, interestToken, interestOwedNow);\n }\n } else {\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n }\n }\n\n /**\n * @notice Internal function to transfer tokens for the interest of a loan.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * @param interestOwedNow The amount of interest to pay.\n * */\n function _payInterestTransfer(\n address lender,\n address interestToken,\n uint256 interestOwedNow\n ) internal {\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\n /// TODO: refactor: data incapsulation violation and DRY design principles\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\n\n _payLendingFee(lender, interestToken, lendingFee);\n\n /// Transfers the interest to the lender, less the interest fee.\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\n\n /// Event Log\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\n }\n}\n" + }, + "contracts/mixins/LiquidationHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\n/**\n * @title The Liquidation Helper contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract computes the liquidation amount.\n * */\ncontract LiquidationHelper is State {\n /**\n * @notice Compute how much needs to be liquidated in order to restore the\n * desired margin (maintenance + 5%).\n *\n * @param principal The total borrowed amount (in loan tokens).\n * @param collateral The collateral (in collateral tokens).\n * @param currentMargin The current margin.\n * @param maintenanceMargin The maintenance (minimum) margin.\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n *\n * @return maxLiquidatable The collateral you can get liquidating.\n * @return maxSeizable The loan you available for liquidation.\n * @return incentivePercent The discount on collateral.\n * */\n function _getLiquidationAmounts(\n uint256 principal,\n uint256 collateral,\n uint256 currentMargin,\n uint256 maintenanceMargin,\n uint256 collateralToLoanRate\n )\n internal\n view\n returns (\n uint256 maxLiquidatable,\n uint256 maxSeizable,\n uint256 incentivePercent\n )\n {\n incentivePercent = liquidationIncentivePercent;\n if (currentMargin > maintenanceMargin || collateralToLoanRate == 0) {\n return (maxLiquidatable, maxSeizable, incentivePercent);\n } else if (currentMargin <= incentivePercent) {\n return (principal, collateral, currentMargin);\n }\n\n /// 5 percentage points above maintenance.\n uint256 desiredMargin = maintenanceMargin.add(5 ether);\n\n /// maxLiquidatable = ((1 + desiredMargin)*principal - collateralToLoanRate*collateral) / (desiredMargin - 0.05)\n maxLiquidatable = desiredMargin.add(10**20).mul(principal).div(10**20);\n maxLiquidatable = maxLiquidatable.sub(collateral.mul(collateralToLoanRate).div(10**18));\n maxLiquidatable = maxLiquidatable.mul(10**20).div(desiredMargin.sub(incentivePercent));\n if (maxLiquidatable > principal) {\n maxLiquidatable = principal;\n }\n\n /// maxSeizable = maxLiquidatable * (1 + incentivePercent) / collateralToLoanRate\n maxSeizable = maxLiquidatable.mul(incentivePercent.add(10**20));\n maxSeizable = maxSeizable.div(collateralToLoanRate).div(100);\n if (maxSeizable > collateral) {\n maxSeizable = collateral;\n }\n\n return (maxLiquidatable, maxSeizable, incentivePercent);\n }\n}\n" + }, + "contracts/mixins/ModuleCommonFunctionalities.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\ncontract ModuleCommonFunctionalities is State {\n modifier whenNotPaused() {\n require(!pause, \"Paused\");\n _;\n }\n}\n" + }, + "contracts/mixins/ProtocolTokenUser.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\n\n/**\n * @title The Protocol Token User contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to withdraw protocol tokens.\n * */\ncontract ProtocolTokenUser is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Internal function to withdraw an amount of protocol tokens from this contract.\n *\n * @param receiver The address of the recipient.\n * @param amount The amount of tokens to withdraw.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function _withdrawProtocolToken(address receiver, uint256 amount)\n internal\n returns (address, bool)\n {\n uint256 withdrawAmount = amount;\n\n uint256 tokenBalance = protocolTokenHeld;\n if (withdrawAmount > tokenBalance) {\n withdrawAmount = tokenBalance;\n }\n if (withdrawAmount == 0) {\n return (protocolTokenAddress, false);\n }\n\n protocolTokenHeld = tokenBalance.sub(withdrawAmount);\n\n IERC20(protocolTokenAddress).safeTransfer(receiver, withdrawAmount);\n\n return (protocolTokenAddress, true);\n }\n}\n" + }, + "contracts/mixins/RewardHelper.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title The Reward Helper contract.\n * @notice This contract calculates the reward for rollover transactions.\n *\n * A rollover is a renewal of a deposit. Instead of liquidating a deposit\n * on maturity, you can roll it over into a new deposit. The outstanding\n * principal of the old deposit is rolled over with or without the interest\n * outstanding on it.\n * */\ncontract RewardHelper is State {\n using SafeMath for uint256;\n\n /**\n * @notice Calculate the reward of a rollover transaction.\n *\n * @param collateralToken The address of the collateral token.\n * @param loanToken The address of the loan token.\n * @param positionSize The amount of value of the position.\n *\n * @return The base fee + the flex fee.\n */\n function _getRolloverReward(\n address collateralToken,\n address loanToken,\n uint256 positionSize\n ) internal view returns (uint256 reward) {\n uint256 positionSizeInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(loanToken, collateralToken, positionSize);\n uint256 rolloverBaseRewardInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(\n address(wrbtcToken),\n collateralToken,\n rolloverBaseReward\n );\n\n return\n rolloverBaseRewardInCollateralToken\n .mul(2) /// baseFee\n .add(positionSizeInCollateralToken.mul(rolloverFlexFeePercent).div(10**20)); /// flexFee = 0.1% of position size\n }\n}\n" + }, + "contracts/mixins/VaultController.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\n\n/**\n * @title The Vault Controller contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to deposit and withdraw wrBTC and\n * other tokens from the vault.\n * */\ncontract VaultController is State {\n using SafeERC20 for IERC20;\n\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\n\n /**\n * @notice Deposit wrBTC into the vault.\n *\n * @param from The address of the account paying the deposit.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherDeposit(address from, uint256 value) internal {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n _wrbtcToken.deposit.value(value)();\n\n emit VaultDeposit(address(_wrbtcToken), from, value);\n }\n\n /**\n * @notice Withdraw wrBTC from the vault.\n *\n * @param to The address of the recipient.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherWithdraw(address to, uint256 value) internal {\n if (value != 0) {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n uint256 balance = address(this).balance;\n if (value > balance) {\n _wrbtcToken.withdraw(value - balance);\n }\n Address.sendValue(to, value);\n\n emit VaultWithdraw(address(_wrbtcToken), to, value);\n }\n }\n\n /**\n * @notice Deposit tokens into the vault.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying the deposit.\n * @param value The amount of tokens to transfer.\n */\n function vaultDeposit(\n address token,\n address from,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransferFrom(from, address(this), value);\n\n emit VaultDeposit(token, from, value);\n }\n }\n\n /**\n * @notice Withdraw tokens from the vault.\n *\n * @param token The address of the token instance.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultWithdraw(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransfer(to, value);\n\n emit VaultWithdraw(token, to, value);\n }\n }\n\n /**\n * @notice Transfer tokens from an account into another one.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultTransfer(\n address token,\n address from,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n if (from == address(this)) {\n IERC20(token).safeTransfer(to, value);\n } else {\n IERC20(token).safeTransferFrom(from, to, value);\n }\n }\n }\n\n /**\n * @notice Approve an allowance of tokens to be spent by an account.\n *\n * @param token The address of the token instance.\n * @param to The address of the spender.\n * @param value The amount of tokens to allow.\n */\n function vaultApprove(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\n IERC20(token).safeApprove(to, 0);\n }\n IERC20(token).safeApprove(to, value);\n }\n}\n" + }, + "contracts/mockup/BlockMockUp.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title Used to get and set mock block number.\n */\ncontract BlockMockUp {\n uint256 public blockNum;\n\n /**\n * @notice To get the `blockNum`.\n * @return _blockNum The block number.\n */\n function getBlockNum() public view returns (uint256 _blockNum) {\n return blockNum;\n }\n\n /**\n * @notice To set the `blockNum`.\n * @param _blockNum The block number.\n */\n function setBlockNum(uint256 _blockNum) public {\n blockNum = _blockNum;\n }\n}\n" + }, + "contracts/mockup/FeeSharingCollectorMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/FeeSharingCollector/FeeSharingCollector.sol\";\n\ncontract FeeSharingCollectorMockup is FeeSharingCollector {\n struct TestData {\n address loanPoolToken;\n uint32 maxCheckpoints;\n address receiver;\n }\n\n TestData public testData;\n\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n testData = TestData(_token, _maxCheckpoints, _receiver);\n }\n\n function trueWithdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function addCheckPoint(address loanPoolToken, uint256 poolTokenAmount) public {\n uint96 amount96 =\n safe96(\n poolTokenAmount,\n \"FeeSharingCollectorProxy::withdrawFees: pool token amount exceeds 96 bits\"\n );\n _addCheckpoint(loanPoolToken, amount96);\n }\n\n function setTotalTokenCheckpoints(address _token, uint256 qty) public {\n totalTokenCheckpoints[_token] = qty;\n }\n\n function setUserProcessedCheckpoints(\n address _user,\n address _token,\n uint256 num\n ) public {\n processedCheckpoints[_user][_token] = num;\n }\n\n function getFullAccumulatedFees(\n address _user,\n address _token,\n uint32 _maxCheckpoints\n ) public view returns (uint256 amount, uint256 end) {\n (amount, end) = _getAccumulatedFees(_user, _token, 0, _maxCheckpoints);\n }\n\n function endOfRangeWithZeroMaxCheckpoint(address _token) public view returns (uint256) {\n return _getEndOfRange(0, _token, 0);\n }\n\n function getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) public view returns (uint256 _tokenAmount, uint256 _endToken) {\n return _getRBTCBalance(_token, _user, _maxCheckpoints);\n }\n\n function testWithdrawReentrancy(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n}\n" + }, + "contracts/mockup/GovernorAlphaMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/GovernorAlpha.sol\";\n\ncontract GovernorAlphaMockup is GovernorAlpha {\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 quorumVotes_,\n uint96 _minPercentageVotes\n ) public GovernorAlpha(timelock_, staking_, guardian_, quorumVotes_, _minPercentageVotes) {}\n\n function votingPeriod() public pure returns (uint256) {\n return 10;\n }\n\n function queueProposals(uint256[] calldata proposalIds) external {\n for (uint256 i = 0; i < proposalIds.length; i++) {\n queue(proposalIds[i]);\n }\n }\n}\n" + }, + "contracts/mockup/LiquidityMiningMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract LiquidityMiningMockup is LiquidityMining {\n function getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n public\n view\n returns (uint256)\n {\n return _getPassedBlocksWithBonusMultiplier(_from, _to);\n }\n\n function getPoolAccumulatedReward(address _poolToken) public view returns (uint256, uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n return _getPoolAccumulatedReward(pool);\n }\n}\n" + }, + "contracts/mockup/LiquidityPoolV1ConverterMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/IERC20.sol\";\n\ncontract LiquidityPoolV1ConverterMockup {\n IERC20[] public reserveTokens;\n IERC20 wrbtcToken;\n uint256 totalFeeMockupValue;\n address feesController;\n\n constructor(IERC20 _token0, IERC20 _token1) public {\n reserveTokens.push(_token0);\n reserveTokens.push(_token1);\n }\n\n function setFeesController(address _feesController) public {\n feesController = _feesController;\n }\n\n function setWrbtcToken(IERC20 _wrbtcToken) public {\n wrbtcToken = _wrbtcToken;\n }\n\n function setTotalFeeMockupValue(uint256 _totalFeeMockupValue) public {\n totalFeeMockupValue = _totalFeeMockupValue;\n }\n\n function withdrawFees(address _receiver) external returns (uint256) {\n require(msg.sender == feesController, \"unauthorized\");\n\n // transfer wrbtc\n wrbtcToken.transfer(_receiver, totalFeeMockupValue);\n return totalFeeMockupValue;\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/LoanClosingsWith.sol\";\n\ncontract LoanClosingsWithMockup is LoanClosingsWith {\n function worthTheTransfer(address, uint256) internal returns (bool) {\n return true;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithoutInvariantCheck.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanClosingsWithMockup.sol\";\n\ncontract LoanClosingsWithoutInvariantCheck is LoanClosingsWithMockup {\n /** Override the modifier of invariant check so that we can test the shared reentrancy guard */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n _;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicLMMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\n\ncontract LoanTokenLogicLMMockup is LoanTokenLogicLM {\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n returns (uint256 loanAmountPaid)\n {\n _callOptionalReturn(\n 0x2c34D66a5ca8686330e100372Eb3FDFB5aEECD0B, //Random EOA for testing\n abi.encodeWithSelector(IERC20(receiver).transfer.selector, receiver, burnAmount),\n \"error\"\n );\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicV2Mockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicV1Mockup is LoanTokenLogicStandard {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](27);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n // res[31] = this.totalSupply.selector;\n res[25] = this.balanceOf.selector;\n res[26] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n\ncontract LoanTokenLogicV2Mockup is LoanTokenLogicStandard {\n function testNewFunction() external pure returns (bool) {\n return true;\n }\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](29);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mockup\n res[28] = this.testNewFunction.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/mockup/lockedSOVFailedMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An interface for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete interface of the Locked SOV Contract.\n */\ncontract LockedSOVFailedMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The user balances.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n revert(\"For testing purposes\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/LockedSOVMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An mockup for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete mockup of the Locked SOV Contract.\n */\ncontract LockedSOVMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n event TokensStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // 10000 is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < 10000, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(10000);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n function _createVestingAndStake(address _sender) private {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n emit TokensStaked(_sender, address(0), amount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/MockAffiliates.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/Affiliates.sol\";\n\ncontract MockAffiliates is Affiliates {\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n }\n}\n" + }, + "contracts/mockup/MockFourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/Vesting/fouryear/FourYearVestingLogic.sol\";\n\ncontract MockFourYearVestingLogic is FourYearVestingLogic {\n /**\n * @notice gets duration left\n */\n function getDurationLeft() external view returns (uint256) {\n return durationLeft;\n }\n}\n" + }, + "contracts/mockup/MockLoanTokenLogic.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogic is LoanTokenLogic {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](31);\n\n // Loan Token Logic\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mock\n res[28] = this.setAffiliatesReferrer.selector;\n res[29] = this.setUserNotFirstTradeFlag.selector;\n res[30] = this.getMarginBorrowAmountAndRate.selector;\n\n return (res, stringToBytes32(\"MockLoanTokenLogic\"));\n }\n\n function setAffiliatesReferrer(address user, address referrer) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(user, referrer);\n }\n\n function setUserNotFirstTradeFlag(address user) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(user);\n }\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n\n /*function initialize(address target) external onlyOwner {\n\t\t_setTarget(this.setAffiliatesUserReferrer.selector, target);\n\t}*/\n}\n\ncontract ILoanTokenModulesMock is ILoanTokenModules {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user) external;\n}\n" + }, + "contracts/mockup/MockLoanTokenLogicLM.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogicLM is LoanTokenLogicLM {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n /** LoanTokenLogicLM function signature */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\"));\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\"));\n res[2] = bytes4(keccak256(\"burn(address,uint256)\"));\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\"));\n\n return (res, stringToBytes32(\"MockLoanTokenLogicLM\"));\n }\n}\n" + }, + "contracts/mockup/modules/IWeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract IWeightedStakingModuleMockup {\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) external;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) external;\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external;\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) external;\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/mockup/modules/StakingModuleBlockMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/StakingGovernanceModule.sol\";\nimport \"../../governance/Staking/modules/StakingStakeModule.sol\";\nimport \"../../governance/Staking/modules/StakingVestingModule.sol\";\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../BlockMockUp.sol\";\n\ncontract StakingModuleBlockMockup is\n IFunctionsList,\n StakingGovernanceModule,\n StakingStakeModule,\n StakingVestingModule,\n WeightedStakingModule\n{\n uint96 public priorWeightedStake;\n mapping(uint256 => uint96) public priorWeightedStakeAtBlock;\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n function balanceOf_MultipliedByTwo(address account) external view returns (uint256) {\n return this.balanceOf(account) * 2;\n }\n\n uint96 priorTotalVotingPower;\n\n function MOCK_priorTotalVotingPower(uint96 _priorTotalVotingPower) public {\n priorTotalVotingPower = _priorTotalVotingPower;\n }\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n return\n priorTotalVotingPower != 0\n ? priorTotalVotingPower\n : super.getPriorTotalVotingPower(blockNumber, time);\n }\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) public view returns (bool) {\n bytes32 codeHash = _getCodeHash(stakerAddress);\n return vestingCodeHashes[codeHash];\n }\n\n function getPriorWeightedStakeAtBlock(uint256 blockNum) public view returns (uint256) {\n return uint256(priorWeightedStakeAtBlock[blockNum]);\n }\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n // StakingGovernanceModule\n bytes4[] memory functionsList = new bytes4[](31);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n\n // StakingStakeModule\n functionsList[6] = this.stake.selector;\n functionsList[7] = this.stakeWithApproval.selector;\n functionsList[8] = this.extendStakingDuration.selector;\n functionsList[9] = this.stakesBySchedule.selector;\n functionsList[10] = this.stakeBySchedule.selector;\n functionsList[11] = this.balanceOf.selector;\n functionsList[12] = this.getCurrentStakedUntil.selector;\n functionsList[13] = this.getStakes.selector;\n functionsList[14] = this.timestampToLockDate.selector;\n\n //StakingVestingModule\n functionsList[15] = this.setVestingRegistry.selector;\n functionsList[16] = this.setVestingStakes.selector;\n functionsList[17] = this.getPriorUserStakeByDate.selector;\n functionsList[18] = this.getPriorVestingWeightedStake.selector;\n functionsList[19] = this.getPriorVestingStakeByDate.selector;\n functionsList[20] = this.addContractCodeHash.selector;\n functionsList[21] = this.removeContractCodeHash.selector;\n functionsList[22] = this.isVestingContract.selector;\n\n //BlockMockup\n functionsList[23] = this.setBlockMockUpAddr.selector;\n functionsList[24] = this.MOCK_priorWeightedStake.selector;\n functionsList[25] = this.MOCK_priorWeightedStakeAtBlock.selector;\n\n //WeightedStakingModule\n functionsList[26] = this.getPriorWeightedStake.selector;\n functionsList[27] = this.weightedStakeByDate.selector;\n functionsList[28] = this.computeWeightByDate.selector;\n functionsList[29] = this.priorWeightedStakeAtBlock.selector;\n functionsList[30] = this.getPriorWeightedStakeAtBlock.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/modules/StakingSharedModuleMock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/shared/StakingShared.sol\";\nimport \"../BlockMockUp.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\n\ncontract StakingModuleMock is IFunctionsList, StakingShared {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](1);\n functionList[0] = this.setBlockMockUpAddr.selector;\n }\n}\n" + }, + "contracts/mockup/modules/StakingWrapperMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\ncontract StakingWrapperMockup {\n uint256 constant TWO_WEEKS = 1209600;\n\n IStaking staking;\n IERC20 token;\n\n constructor(IStaking _staking, IERC20 _token) public {\n staking = _staking;\n token = _token;\n }\n\n function stake2times(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stake(amount, until, stakeFor, delegatee);\n }\n\n function stakeAndExtend(uint96 amount, uint256 until) external {\n require(token.transferFrom(msg.sender, address(this), amount));\n token.approve(address(staking), amount);\n\n staking.stake(amount, until, address(this), address(this));\n staking.extendStakingDuration(until, until + TWO_WEEKS);\n }\n\n function stakeAndStakeBySchedule(\n uint96 amount,\n uint256 until,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n}\n" + }, + "contracts/mockup/modules/WeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract WeightedStakingModuleMockup is WeightedStakingModule {\n uint96 priorWeightedStake;\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n mapping(uint256 => uint96) priorWeightedStakeAtBlock;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n functionsList[3] = this.MOCK_priorWeightedStake.selector;\n functionsList[4] = this.MOCK_priorWeightedStakeAtBlock.selector;\n functionsList[5] = this.calculatePriorWeightedStake.selector;\n functionsList[6] = this.setDelegateStake.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n//@todo can I change this proxy to EIP-1822 proxy standard, please. https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\ncontract PreviousLoanToken is AdvancedTokenStorage {\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../connectors/loantoken/interfaces/ProtocolSettingsLike.sol\";\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n// It is a LoanToken implementation!\ncontract PreviousLoanTokenSettingsLowerAdmin is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress\n\n // ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n // ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n //@todo check for restrictions in this contract\n modifier onlyAdmin() {\n require(msg.sender == address(this) || msg.sender == owner(), \"unauthorized\");\n _;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function init(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans // isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n // These params should be percentages represented like so: 5% = 5000000000000000000\n // rateMultiplier + baseRate can't exceed 100%\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; // 80 ether\n kinkLevel = _kinkLevel; // 90 ether\n maxScaleRate = _maxScaleRate; // 100 ether\n }\n\n function toggleFunctionPause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyAdmin {\n // keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /**\n * sets the transaction limit per token address\n * @param addresses the token addresses\n * @param limits the limit denominated in the currency of the token address\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyOwner\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n}\n" + }, + "contracts/mockup/PriceFeedsMoCMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../feeds/testnet/PriceFeedsMoC.sol\";\n\n// This contract is only for test purposes\n// https://github.com/money-on-chain/Amphiraos-Oracle/blob/master/contracts/medianizer/medianizer.sol\ncontract PriceFeedsMoCMockup is Medianizer {\n uint256 public value;\n bool public has;\n\n function peek() external view returns (bytes32, bool) {\n return (bytes32(value), has);\n }\n\n function setValue(uint256 _value) public {\n value = _value;\n }\n\n function setHas(bool _has) public {\n has = _has;\n }\n}\n" + }, + "contracts/mockup/ProtocolSettingsMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/ProtocolSettings.sol\";\n\ncontract ProtocolSettingsMockup is ProtocolSettings {\n function setLendingFeeTokensHeld(address token, uint256 amout) public {\n lendingFeeTokensHeld[token] = amout;\n }\n\n function setTradingFeeTokensHeld(address token, uint256 amout) public {\n tradingFeeTokensHeld[token] = amout;\n }\n\n function setBorrowingFeeTokensHeld(address token, uint256 amout) public {\n borrowingFeeTokensHeld[token] = amout;\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n\n _setTarget(this.setLendingFeeTokensHeld.selector, target);\n _setTarget(this.setTradingFeeTokensHeld.selector, target);\n _setTarget(this.setBorrowingFeeTokensHeld.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n\n _setTarget(this.getDefaultPathConversion.selector, target);\n }\n}\n" + }, + "contracts/mockup/proxy/ImplementationMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\n\ncontract ImplementationMockup is StorageMockup {\n function setValue(uint256 _value) public {\n value = _value;\n emit ValueChanged(_value);\n }\n\n function getValue() public view returns (uint256) {\n return value;\n }\n}\n" + }, + "contracts/mockup/proxy/ProxyMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract ProxyMockup is StorageMockup, UpgradableProxy {}\n" + }, + "contracts/mockup/proxy/StorageMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\ncontract StorageMockup {\n uint256 value;\n\n event ValueChanged(uint256 value);\n}\n" + }, + "contracts/mockup/RBTCWrapperProxyMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract RBTCWrapperProxyMockup {\n LiquidityMining public liquidityMining;\n\n constructor(LiquidityMining _liquidityMining) public {\n liquidityMining = _liquidityMining;\n }\n\n function claimReward(address _poolToken) public {\n liquidityMining.claimReward(_poolToken, msg.sender);\n }\n\n function claimRewardFromAllPools() public {\n liquidityMining.claimRewardFromAllPools(msg.sender);\n }\n\n function withdraw(address _poolToken, uint256 _amount) public {\n liquidityMining.withdraw(_poolToken, _amount, msg.sender);\n }\n}\n" + }, + "contracts/mockup/StakingRewardsMockUp.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/StakingRewards/StakingRewards.sol\";\nimport \"./BlockMockUp.sol\";\n\n/**\n * @title Staking Rewards Contract MockUp\n * @notice This is used for Testing\n * */\ncontract StakingRewardsMockUp is StakingRewards {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n using SafeMath for uint256;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n}\n" + }, + "contracts/mockup/TimelockHarness.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"../governance/Timelock.sol\";\n\ninterface Administered {\n function _acceptAdmin() external returns (uint256);\n}\n\ncontract TimelockHarness is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, delay_) {}\n\n function setDelayWithoutChecking(uint256 delay_) public {\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function harnessSetPendingAdmin(address pendingAdmin_) public {\n pendingAdmin = pendingAdmin_;\n }\n\n function harnessSetAdmin(address admin_) public {\n admin = admin_;\n }\n}\n\ncontract TimelockTest is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, 2 days) {\n delay = delay_;\n }\n\n function harnessSetAdmin(address admin_) public {\n require(msg.sender == admin);\n admin = admin_;\n }\n\n function harnessAcceptAdmin(Administered administered) public {\n administered._acceptAdmin();\n }\n}\n" + }, + "contracts/mockup/VestingLogicMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/Vesting/VestingLogic.sol\";\n\ncontract VestingLogicMockup is VestingLogic {\n /**\n * @dev we had a bug in a loop: \"i < endDate\" instead of \"i <= endDate\"\n */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n}\n" + }, + "contracts/mockup/VestingRegistryLogicMockUp.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\nimport \"../governance/Vesting/VestingRegistryLogic.sol\";\n\ncontract VestingRegistryLogicMockup is VestingRegistryLogic {\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return true;\n }\n\n function setTeamVesting(address _vesting, uint256 _vestingCreationType) external {\n vestingCreationAndTypes[_vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(VestingType.TeamVesting),\n vestingCreationType: uint128(_vestingCreationType)\n });\n }\n}\n" + }, + "contracts/modules/Affiliates.sol": { + "content": "/**\n * Copyright 2017-2020, Sovryn, All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Affiliates contract.\n * @notice Track referrals and reward referrers (affiliates) with tokens.\n * In-detail specifications are found at https://wiki.sovryn.app/en/community/Affiliates\n * @dev Module: Affiliates upgradable\n * Storage: from State, functions called from Protocol by delegatecall\n */\ncontract Affiliates is State, AffiliatesEvents, ModuleCommonFunctionalities {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Void constructor.\n */\n // solhint-disable-next-line no-empty-blocks\n constructor() public {}\n\n /**\n * @notice Avoid calls to this contract except for those explicitly declared.\n */\n function() external {\n revert(\"Affiliates - fallback not allowed\");\n }\n\n /**\n * @notice Set delegate callable functions by proxy contract.\n * @dev This contract is designed as a module, this way logic can be\n * expanded and upgraded w/o losing storage that is kept in the protocol (State.sol)\n * initialize() is used to register in the proxy external (module) functions\n * to be called via the proxy.\n * @param target The address of a new logic implementation.\n */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setAffiliatesReferrer.selector];\n _setTarget(this.setAffiliatesReferrer.selector, target);\n _setTarget(this.getUserNotFirstTradeFlag.selector, target);\n _setTarget(this.getReferralsList.selector, target);\n _setTarget(this.setUserNotFirstTradeFlag.selector, target);\n _setTarget(this.payTradingFeeToAffiliatesReferrer.selector, target);\n _setTarget(this.getAffiliatesReferrerBalances.selector, target);\n _setTarget(this.getAffiliatesReferrerTokenBalance.selector, target);\n _setTarget(this.getAffiliatesReferrerTokensList.selector, target);\n _setTarget(this.withdrawAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.withdrawAllAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.getMinReferralsToPayout.selector, target);\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n _setTarget(this.getAffiliateRewardsHeld.selector, target);\n _setTarget(this.getAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.getAffiliatesTokenRewardsValueInRbtc.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"Affiliates\");\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from loan pools.\n */\n modifier onlyCallableByLoanPools() {\n require(loanPoolToUnderlying[msg.sender] != address(0), \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from within protocol functions.\n */\n modifier onlyCallableInternal() {\n require(msg.sender == protocolAddress, \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Data structure comprised of 3 flags to compute the result of setting a referrer.\n */\n struct SetAffiliatesReferrerResult {\n bool success;\n bool alreadySet;\n bool userNotFirstTradeFlag;\n }\n\n /**\n * @notice Loan pool calls this function to tell affiliates\n * a user coming from a referrer is trading and should be registered if not yet.\n * Taking into account some user status flags may lead to the user and referrer\n * become added or not to the affiliates record.\n *\n * @param user The address of the user that is trading on loan pools.\n * @param referrer The address of the referrer the user is coming from.\n */\n function setAffiliatesReferrer(address user, address referrer)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n SetAffiliatesReferrerResult memory result;\n\n result.userNotFirstTradeFlag = getUserNotFirstTradeFlag(user);\n result.alreadySet = affiliatesUserReferrer[user] != address(0);\n result.success = !(result.userNotFirstTradeFlag || result.alreadySet || user == referrer);\n if (result.success) {\n affiliatesUserReferrer[user] = referrer;\n referralsList[referrer].add(user);\n emit SetAffiliatesReferrer(user, referrer);\n } else {\n emit SetAffiliatesReferrerFail(\n user,\n referrer,\n result.alreadySet,\n result.userNotFirstTradeFlag\n );\n }\n }\n\n /**\n * @notice Getter to query the referrals coming from a referrer.\n * @param referrer The address of a given referrer.\n * @return The referralsList mapping value by referrer.\n */\n function getReferralsList(address referrer) external view returns (address[] memory refList) {\n refList = referralsList[referrer].enumerate();\n return refList;\n }\n\n /**\n * @notice Getter to query the not-first-trade flag of a user.\n * @param user The address of a given user.\n * @return The userNotFirstTradeFlag mapping value by user.\n */\n function getUserNotFirstTradeFlag(address user) public view returns (bool) {\n return userNotFirstTradeFlag[user];\n }\n\n /**\n * @notice Setter to toggle on the not-first-trade flag of a user.\n * @param user The address of a given user.\n */\n function setUserNotFirstTradeFlag(address user)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n if (!userNotFirstTradeFlag[user]) {\n userNotFirstTradeFlag[user] = true;\n emit SetUserNotFirstTradeFlag(user);\n }\n }\n\n /**\n * @notice Internal getter to query the fee share for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function _getAffiliatesTradingFeePercentForSOV() internal view returns (uint256) {\n return affiliateFeePercent;\n }\n\n /**\n * @notice Internal to calculate the affiliates trading token fee amount.\n * Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * This _getReferrerTradingFeeForToken calculates the first one\n * by applying a custom percentage multiplier.\n * @param feeTokenAmount The trading token fee amount.\n * @return The affiliates share of the trading token fee amount.\n */\n function _getReferrerTradingFeeForToken(uint256 feeTokenAmount)\n internal\n view\n returns (uint256)\n {\n return feeTokenAmount.mul(getAffiliateTradingTokenFeePercent()).div(10**20);\n }\n\n /**\n * @notice Getter to query the fee share of trading token fee for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function getAffiliateTradingTokenFeePercent() public view returns (uint256) {\n return affiliateTradingTokenFeePercent;\n }\n\n /**\n * @notice Getter to query referral threshold for paying out to the referrer.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The minimum number of referrals set by Protocol.\n */\n function getMinReferralsToPayout() public view returns (uint256) {\n return minReferralsToPayout;\n }\n\n /**\n * @notice Get the sovToken reward of a trade.\n * @dev The reward is worth x% of the trading fee.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * @return The reward amount.\n * */\n function _getSovBonusAmount(address feeToken, uint256 feeAmount)\n internal\n view\n returns (uint256)\n {\n uint256 rewardAmount;\n address _priceFeeds = priceFeeds;\n\n /// @dev Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// dest token = SOV\n feeAmount.mul(_getAffiliatesTradingFeePercentForSOV()).div(1e20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n return rewardAmount;\n }\n\n /**\n * @notice Protocol calls this function to pay the affiliates rewards to a user (referrer).\n *\n * @dev Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * Both are paid in this function.\n *\n * @dev Actually they are not paid, but just holded by protocol until user claims them by\n * actively calling withdrawAffiliatesReferrerTokenFees() function,\n * and/or when unvesting lockedSOV.\n *\n * @dev To be precise, what this function does is updating the registers of the rewards\n * for the referrer including the assignment of the SOV tokens as rewards to the\n * referrer's vesting contract.\n *\n * @param referrer The address of the referrer.\n * @param trader The address of the trader.\n * @param token The address of the token in which the trading/borrowing fee was paid.\n * @param tradingFeeTokenBaseAmount Total trading fee amount, the base for calculating referrer's fees.\n *\n * @return referrerBonusSovAmount The amount of SOV tokens paid to the referrer (through a vesting contract, lockedSOV).\n * @return referrerBonusTokenAmount The amount of trading tokens paid directly to the referrer.\n */\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n )\n external\n onlyCallableInternal\n whenNotPaused\n returns (uint256 referrerBonusSovAmount, uint256 referrerBonusTokenAmount)\n {\n bool isHeld = referralsList[referrer].length() < getMinReferralsToPayout();\n bool bonusPaymentIsSuccess = true;\n uint256 paidReferrerBonusSovAmount;\n\n /// Process token fee rewards first.\n referrerBonusTokenAmount = _getReferrerTradingFeeForToken(tradingFeeTokenBaseAmount);\n if (!affiliatesReferrerTokensList[referrer].contains(token))\n affiliatesReferrerTokensList[referrer].add(token);\n affiliatesReferrerBalances[referrer][token] = affiliatesReferrerBalances[referrer][token]\n .add(referrerBonusTokenAmount);\n\n /// Then process SOV rewards.\n referrerBonusSovAmount = _getSovBonusAmount(token, tradingFeeTokenBaseAmount);\n uint256 rewardsHeldByProtocol = affiliateRewardsHeld[referrer];\n\n if (isHeld) {\n /// If referrals less than minimum, temp the rewards SOV to the storage\n affiliateRewardsHeld[referrer] = rewardsHeldByProtocol.add(referrerBonusSovAmount);\n } else {\n /// If referrals >= minimum, directly send all of the remain rewards to locked sov\n /// Call depositSOV() in LockedSov contract\n /// Set the affiliaterewardsheld = 0\n if (affiliateRewardsHeld[referrer] > 0) {\n affiliateRewardsHeld[referrer] = 0;\n }\n\n paidReferrerBonusSovAmount = referrerBonusSovAmount.add(rewardsHeldByProtocol);\n IERC20(sovTokenAddress).approve(lockedSOVAddress, paidReferrerBonusSovAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"depositSOV(address,uint256)\",\n referrer,\n paidReferrerBonusSovAmount\n )\n );\n\n if (!success) {\n bonusPaymentIsSuccess = false;\n }\n }\n\n if (bonusPaymentIsSuccess) {\n emit PayTradingFeeToAffiliate(\n referrer,\n trader, // trader\n token,\n isHeld,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n } else {\n emit PayTradingFeeToAffiliateFail(\n referrer,\n trader, // trader\n token,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n }\n\n return (referrerBonusSovAmount, referrerBonusTokenAmount);\n }\n\n /**\n * @notice Referrer calls this function to receive its reward in a given token.\n * It will send the other (non-SOV) reward tokens from trading protocol fees,\n * to the referrer’s wallet.\n * @dev Rewards are held by protocol in different tokens coming from trading fees.\n * Referrer has to claim them one by one for every token with accumulated balance.\n * @param token The address of the token to withdraw.\n * @param receiver The address of the withdrawal beneficiary.\n * @param amount The amount of tokens to claim. If greater than balance, just sends balance.\n */\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) public whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n uint256 referrerTokenBalance = affiliatesReferrerBalances[referrer][token];\n uint256 withdrawAmount = referrerTokenBalance > amount ? amount : referrerTokenBalance;\n\n require(withdrawAmount > 0, \"Affiliates: cannot withdraw zero amount\");\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n uint256 newReferrerTokenBalance = referrerTokenBalance.sub(withdrawAmount);\n\n if (newReferrerTokenBalance == 0) {\n _removeAffiliatesReferrerToken(referrer, token);\n } else {\n affiliatesReferrerBalances[referrer][token] = newReferrerTokenBalance;\n }\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawAffiliatesReferrerTokenFees(referrer, receiver, token, withdrawAmount);\n }\n\n /**\n * @notice Withdraw to msg.sender all token fees for a referrer.\n * @dev It's done by looping through its available tokens.\n * @param receiver The address of the withdrawal beneficiary.\n */\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n (address[] memory tokenAddresses, uint256[] memory tokenBalances) =\n getAffiliatesReferrerBalances(referrer);\n for (uint256 i; i < tokenAddresses.length; i++) {\n withdrawAffiliatesReferrerTokenFees(tokenAddresses[i], receiver, tokenBalances[i]);\n }\n }\n\n /**\n * @notice Internal function to delete a referrer's token balance.\n * @param referrer The address of the referrer.\n * @param token The address of the token specifying the balance to remove.\n */\n function _removeAffiliatesReferrerToken(address referrer, address token) internal {\n delete affiliatesReferrerBalances[referrer][token];\n affiliatesReferrerTokensList[referrer].remove(token);\n }\n\n /**\n * @notice Get all token balances of a referrer.\n * @param referrer The address of the referrer.\n * @return referrerTokensList The array of available tokens (keys).\n * @return referrerTokensBalances The array of token balances (values).\n */\n function getAffiliatesReferrerBalances(address referrer)\n public\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances)\n {\n referrerTokensList = getAffiliatesReferrerTokensList(referrer);\n referrerTokensBalances = new uint256[](referrerTokensList.length);\n for (uint256 i; i < referrerTokensList.length; i++) {\n referrerTokensBalances[i] = getAffiliatesReferrerTokenBalance(\n referrer,\n referrerTokensList[i]\n );\n }\n return (referrerTokensList, referrerTokensBalances);\n }\n\n /**\n * @dev Get all token rewards estimation value in rbtc.\n *\n * @param referrer Address of referrer.\n *\n * @return The value estimation in rbtc.\n */\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount)\n {\n address[] memory tokensList = getAffiliatesReferrerTokensList(referrer);\n address _priceFeeds = priceFeeds;\n\n for (uint256 i; i < tokensList.length; i++) {\n // Get the value of each token in rbtc\n\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n tokensList[i], // source token\n address(wrbtcToken), // dest token = SOV\n affiliatesReferrerBalances[referrer][tokensList[i]] // total token rewards\n )\n );\n\n assembly {\n if eq(success, 1) {\n rbtcTotalAmount := add(rbtcTotalAmount, mload(add(data, 32)))\n }\n }\n }\n }\n\n /**\n * @notice Get all available tokens at the affiliates program for a given referrer.\n * @param referrer The address of a given referrer.\n * @return tokensList The list of available tokens.\n */\n function getAffiliatesReferrerTokensList(address referrer)\n public\n view\n returns (address[] memory tokensList)\n {\n tokensList = affiliatesReferrerTokensList[referrer].enumerate();\n return tokensList;\n }\n\n /**\n * @notice Getter to query the affiliate balance for a given referrer and token.\n * @param referrer The address of the referrer.\n * @param token The address of the token to get balance for.\n * @return The affiliatesReferrerBalances mapping value by referrer and token keys.\n */\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n public\n view\n returns (uint256)\n {\n return affiliatesReferrerBalances[referrer][token];\n }\n\n /**\n * @notice Getter to query the address of referrer for a given user.\n * @param user The address of the user.\n * @return The address on affiliatesUserReferrer mapping value by user key.\n */\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user];\n }\n\n /**\n * @notice Getter to query the reward amount held for a given referrer.\n * @param referrer The address of the referrer.\n * @return The affiliateRewardsHeld mapping value by referrer key.\n */\n function getAffiliateRewardsHeld(address referrer) public view returns (uint256) {\n return affiliateRewardsHeld[referrer];\n }\n}\n" + }, + "contracts/modules/interfaces/ProtocolAffiliatesInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolAffiliatesInterface {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user_) external;\n\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\n\n function payTradingFeeToAffiliatesReferrer(\n address affiliate,\n address trader,\n address token,\n uint256 amount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n}\n" + }, + "contracts/modules/interfaces/ProtocolSwapExternalInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolSwapExternalInterface {\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n}\n" + }, + "contracts/modules/LoanClosingsLiquidation.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsLiquidation contract.\n * @notice Ways to close a loan: liquidation. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsLiquidation is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.liquidate.selector];\n _setTarget(this.liquidate.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsLiquidation\"\n );\n }\n\n /**\n * @notice Liquidate an unhealty loan.\n *\n * @dev Public wrapper for _liquidate internal function.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * loanId is the ID of the loan, which is created on loan opening.\n * It can be obtained either by parsing the Trade event or by reading\n * the open loans from the contract by calling getActiveLoans or getUserLoans.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n return _liquidate(loanId, receiver, closeAmount);\n }\n\n /**\n * @notice Internal function for liquidating an unhealthy loan.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function _liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin <= loanParamsLocal.maintenanceMargin, \"healthy position\");\n\n loanCloseAmount = closeAmount;\n\n //amounts to restore the desired margin (maintencance + 5%)\n (uint256 maxLiquidatable, uint256 maxSeizable, ) =\n _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n\n if (loanCloseAmount < maxLiquidatable) {\n //close maxLiquidatable if tiny position will remain\n uint256 remainingAmount = maxLiquidatable - loanCloseAmount;\n remainingAmount = _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingAmount <= TINY_AMOUNT) {\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable.mul(loanCloseAmount).div(maxLiquidatable);\n }\n } else if (loanCloseAmount > maxLiquidatable) {\n // adjust down the close amount to the max\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable;\n }\n\n require(loanCloseAmount != 0, \"nothing to liquidate\");\n\n // liquidator deposits the principal being closed\n _returnPrincipalWithDeposit(loanParamsLocal.loanToken, address(this), loanCloseAmount);\n\n // a portion of the principal is repaid to the lender out of interest refunded\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n loanLocal.borrower\n );\n\n if (loanCloseAmount > loanCloseAmountLessInterest) {\n // full interest refund goes to the borrower\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanCloseAmount - loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmountLessInterest != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n seizedToken = loanParamsLocal.collateralToken;\n\n if (seizedAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(seizedAmount);\n\n _withdrawAsset(seizedToken, receiver, seizedAmount);\n }\n\n _closeLoan(loanLocal, loanCloseAmount);\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n seizedAmount,\n collateralToLoanRate,\n 0,\n currentMargin,\n CloseTypes.Liquidation\n );\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsRollover.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsRollover contract.\n * @notice Ways to close a loan: rollover. Margin trade\n * positions are always closed with a swap.\n *\n * */\ncontract LoanClosingsRollover is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.rollover.selector];\n _setTarget(this.rollover.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsRollover\"\n );\n }\n\n /**\n * @notice Roll over a loan.\n *\n * @dev Public wrapper for _rollover internal function.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * The function rollover on the protocol contract extends the loan\n * duration by the maximum term (28 days for margin trades at the moment\n * of writing), pays the interest to the lender and refunds the caller\n * for the gas cost by sending 2 * the gas cost using the fast gas price\n * as base for the calculation.\n *\n * @param loanId The ID of the loan to roll over.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n * */\n function rollover(\n bytes32 loanId,\n bytes calldata // for future use /*loanDataBytes*/\n ) external nonReentrant globallyNonReentrant iTokenSupplyUnchanged(loanId) whenNotPaused {\n // restrict to EOAs to prevent griefing attacks, during interest rate recalculation\n require(msg.sender == tx.origin, \"EOAs call\");\n\n return\n _rollover(\n loanId,\n \"\" // loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for roll over a loan.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * @param loanId The ID of the loan to roll over.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n * */\n function _rollover(bytes32 loanId, bytes memory loanDataBytes) internal {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n require(block.timestamp > loanLocal.endTimestamp.sub(3600), \"healthy position\");\n require(loanPoolToUnderlying[loanLocal.lender] != address(0), \"invalid lender\");\n\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n // Handle back interest: calculates interest owned since the loan endtime passed but the loan remained open\n uint256 backInterestTime;\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestTime = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestTime.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(1 days);\n }\n\n //note: to avoid code duplication, it would be nicer to store loanParamsLocal.maxLoanTerm in a local variable\n //however, we've got stack too deep issues if we do so.\n if (loanParamsLocal.maxLoanTerm != 0) {\n // fixed-term loan, so need to query iToken for latest variable rate\n uint256 owedPerDay =\n loanLocal.principal.mul(ILoanPool(loanLocal.lender).borrowInterestRate()).div(\n 365 * 10**20\n );\n\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(\n loanInterestLocal.owedPerDay\n );\n\n loanInterestLocal.owedPerDay = owedPerDay;\n\n //if the loan has been open for longer than an additional period, add at least 1 additional day\n if (backInterestTime >= loanParamsLocal.maxLoanTerm) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n }\n //extend by the max loan term\n else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(loanParamsLocal.maxLoanTerm);\n }\n } else {\n // loanInterestLocal.owedPerDay doesn't change\n if (backInterestTime >= MONTH) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n } else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(MONTH);\n }\n }\n\n uint256 interestAmountRequired = loanLocal.endTimestamp.sub(block.timestamp);\n interestAmountRequired = interestAmountRequired.mul(loanInterestLocal.owedPerDay);\n interestAmountRequired = interestAmountRequired.div(1 days);\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n\n // add backInterestOwed\n interestAmountRequired = interestAmountRequired.add(backInterestOwed);\n\n // collect interest (needs to be converted from the collateral)\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n 0, //min swap 0 -> swap connector estimates the amount of source tokens to use\n interestAmountRequired, //required destination tokens\n true, // returnTokenIsCollateral\n loanDataBytes\n );\n\n //received more tokens than needed to pay the interest\n if (destTokenAmountReceived > interestAmountRequired) {\n // swap rest back to collateral, if the amount is big enough to cover gas cost\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n )\n ) {\n (destTokenAmountReceived, , ) = _swapBackExcess(\n loanLocal,\n loanParamsLocal,\n destTokenAmountReceived - interestAmountRequired, //amount to be swapped\n loanDataBytes\n );\n sourceTokenAmountUsed = sourceTokenAmountUsed.sub(destTokenAmountReceived);\n }\n //else give it to the protocol as a lending fee\n else {\n _payLendingFee(\n loanLocal.borrower,\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n );\n }\n }\n\n //subtract the interest from the collateral\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n if (backInterestOwed != 0) {\n // pay out backInterestOwed\n\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n uint256 rolloverReward =\n _getRolloverReward(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.principal\n );\n\n if (rolloverReward != 0) {\n // if the reward > collateral:\n if (rolloverReward > loanLocal.collateral) {\n // 1. pay back the remaining loan to the lender\n // 2. pay the remaining collateral to msg.sender\n // 3. close the position & emit close event\n _closeWithSwap(\n loanLocal.id,\n msg.sender,\n loanLocal.collateral,\n false,\n \"\" // loanDataBytes\n );\n } else {\n // pay out reward to caller\n loanLocal.collateral = loanLocal.collateral.sub(rolloverReward);\n\n _withdrawAsset(loanParamsLocal.collateralToken, msg.sender, rolloverReward);\n }\n }\n\n if (loanLocal.collateral > 0) {\n //close whole loan if tiny position will remain\n if (_getAmountInRbtc(loanParamsLocal.loanToken, loanLocal.principal) <= TINY_AMOUNT) {\n _closeWithSwap(\n loanLocal.id,\n loanLocal.borrower,\n loanLocal.collateral, // swap all collaterals\n false,\n \"\" /// loanDataBytes\n );\n } else {\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n require(\n currentMargin > 3 ether, // ensure there's more than 3% margin remaining\n \"unhealthy position\"\n );\n }\n }\n\n if (loanLocal.active) {\n emit Rollover(\n loanLocal.borrower, // user (borrower)\n loanLocal.lender, // lender\n loanLocal.id, // loanId\n loanLocal.principal, // principal\n loanLocal.collateral, // collateral\n loanLocal.endTimestamp, // endTimestamp\n msg.sender, // rewardReceiver\n rolloverReward // reward\n );\n }\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsShared.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/RewardHelper.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\n/**\n * @title LoanClosingsShared contract.\n * @notice This contract should only contains the internal function that is being used / utilized by\n * LoanClosingsLiquidation, LoanClosingsRollover & LoanClosingsWith contract\n *\n * */\ncontract LoanClosingsShared is\n LoanClosingsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n RewardHelper,\n ModuleCommonFunctionalities\n{\n uint256 internal constant MONTH = 365 days / 12;\n //0.00001 BTC, would be nicer in State.sol, but would require a redeploy of the complete protocol, so adding it here instead\n //because it's not shared state anyway and only used by this contract\n uint256 public constant paySwapExcessToBorrowerThreshold = 10000000000000;\n\n uint256 public constant TINY_AMOUNT = 25e13;\n\n enum CloseTypes { Deposit, Swap, Liquidation }\n\n /** modifier for invariant check */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n Loan storage loanLocal = loans[loanId];\n\n require(loanLocal.lender != address(0), \"Invalid loan token pool address\");\n\n uint256 previousITokenSupply = ILoanTokenModules(loanLocal.lender).totalSupply();\n\n _;\n\n /// Validate iToken total supply\n require(\n previousITokenSupply == ILoanTokenModules(loanLocal.lender).totalSupply(),\n \"loan token supply invariant check failure\"\n );\n }\n\n /**\n * @dev computes the interest which needs to be refunded to the borrower based on the amount he's closing and either\n * subtracts it from the amount which still needs to be paid back (in case outstanding amount > interest) or withdraws the\n * excess to the borrower (in case interest > outstanding).\n * @param loanLocal the loan\n * @param loanParamsLocal the loan params\n * @param loanCloseAmount the amount to be closed (base for the computation)\n * @param receiver the address of the receiver (usually the borrower)\n * */\n function _settleInterestToPrincipal(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 loanCloseAmount,\n address receiver\n ) internal returns (uint256) {\n uint256 loanCloseAmountLessInterest = loanCloseAmount;\n\n //compute the interest which neeeds to be refunded to the borrower (because full interest is paid on loan )\n uint256 interestRefundToBorrower =\n _settleInterest(loanParamsLocal, loanLocal, loanCloseAmountLessInterest);\n\n uint256 interestAppliedToPrincipal;\n //if the outstanding loan is bigger than the interest to be refunded, reduce the amount to be paid back / closed by the interest\n if (loanCloseAmountLessInterest >= interestRefundToBorrower) {\n // apply all of borrower interest refund torwards principal\n interestAppliedToPrincipal = interestRefundToBorrower;\n\n // principal needed is reduced by this amount\n loanCloseAmountLessInterest -= interestRefundToBorrower;\n\n // no interest refund remaining\n interestRefundToBorrower = 0;\n } else {\n //if the interest refund is bigger than the outstanding loan, the user needs to get back the interest\n // principal fully covered by excess interest\n interestAppliedToPrincipal = loanCloseAmountLessInterest;\n\n // amount refunded is reduced by this amount\n interestRefundToBorrower -= loanCloseAmountLessInterest;\n\n // principal fully covered by excess interest\n loanCloseAmountLessInterest = 0;\n\n if (interestRefundToBorrower != 0) {\n // refund overage\n _withdrawAsset(loanParamsLocal.loanToken, receiver, interestRefundToBorrower);\n }\n }\n\n //pay the interest to the lender\n //note: this is a waste of gas, because the loanCloseAmountLessInterest is withdrawn to the lender, too. It could be done at once.\n if (interestAppliedToPrincipal != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, interestAppliedToPrincipal);\n }\n\n return loanCloseAmountLessInterest;\n }\n\n // The receiver always gets back an ERC20 (even wrbtc)\n function _returnPrincipalWithDeposit(\n address loanToken,\n address receiver,\n uint256 principalNeeded\n ) internal {\n if (principalNeeded != 0) {\n if (msg.value == 0) {\n vaultTransfer(loanToken, msg.sender, receiver, principalNeeded);\n } else {\n require(loanToken == address(wrbtcToken), \"wrong asset sent\");\n require(msg.value >= principalNeeded, \"not enough ether\");\n wrbtcToken.deposit.value(principalNeeded)();\n if (receiver != address(this)) {\n vaultTransfer(loanToken, address(this), receiver, principalNeeded);\n }\n if (msg.value > principalNeeded) {\n // refund overage\n Address.sendValue(msg.sender, msg.value - principalNeeded);\n }\n }\n } else {\n require(msg.value == 0, \"wrong asset sent\");\n }\n }\n\n /**\n * @dev checks if the amount of the asset to be transfered is worth the transfer fee\n * @param asset the asset to be transfered\n * @param amount the amount to be transfered\n * @return True if the amount is bigger than the threshold\n * */\n function worthTheTransfer(address asset, uint256 amount) internal returns (bool) {\n uint256 amountInRbtc = _getAmountInRbtc(asset, amount);\n emit swapExcess(\n amountInRbtc > paySwapExcessToBorrowerThreshold,\n amount,\n amountInRbtc,\n paySwapExcessToBorrowerThreshold\n );\n\n return amountInRbtc > paySwapExcessToBorrowerThreshold;\n }\n\n /**\n * swaps collateral tokens for loan tokens\n * @param loanLocal the loan object\n * @param loanParamsLocal the loan parameters\n * @param swapAmount the amount to be swapped\n * @param principalNeeded the required destination token amount\n * @param returnTokenIsCollateral if true -> required destination token amount will be passed on, else not\n * note: quite dirty. should be refactored.\n * @param loanDataBytes additional loan data (not in use for token swaps)\n * */\n function _doCollateralSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n loanLocal.collateral, // maxSourceTokenAmount\n returnTokenIsCollateral\n ? principalNeeded // requiredDestTokenAmount\n : 0,\n false, // bypassFee\n loanDataBytes\n );\n require(destTokenAmountReceived >= principalNeeded, \"insufficient dest amount\");\n require(sourceTokenAmountUsed <= loanLocal.collateral, \"excessive source amount\");\n }\n\n /**\n * @notice Withdraw asset to receiver.\n *\n * @param assetToken The loan token.\n * @param receiver The address of the receiver.\n * @param assetAmount The loan token amount.\n * */\n function _withdrawAsset(\n address assetToken,\n address receiver,\n uint256 assetAmount\n ) internal {\n if (assetAmount != 0) {\n if (assetToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, assetAmount);\n } else {\n vaultWithdraw(assetToken, receiver, assetAmount);\n }\n }\n }\n\n /**\n * @notice Internal function to close a loan.\n *\n * @param loanLocal The loan object.\n * @param loanCloseAmount The amount to close: principal or lower.\n *\n * */\n function _closeLoan(Loan storage loanLocal, uint256 loanCloseAmount) internal {\n require(loanCloseAmount != 0, \"nothing to close\");\n\n if (loanCloseAmount == loanLocal.principal) {\n loanLocal.principal = 0;\n loanLocal.active = false;\n loanLocal.endTimestamp = block.timestamp;\n loanLocal.pendingTradesId = 0;\n activeLoansSet.removeBytes32(loanLocal.id);\n lenderLoanSets[loanLocal.lender].removeBytes32(loanLocal.id);\n borrowerLoanSets[loanLocal.borrower].removeBytes32(loanLocal.id);\n } else {\n loanLocal.principal = loanLocal.principal.sub(loanCloseAmount);\n }\n }\n\n function _settleInterest(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 closePrincipal\n ) internal returns (uint256) {\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 interestTime = block.timestamp;\n if (interestTime > loanLocal.endTimestamp) {\n interestTime = loanLocal.endTimestamp;\n }\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n interestTime\n );\n\n uint256 owedPerDayRefund;\n if (closePrincipal < loanLocal.principal) {\n owedPerDayRefund = loanInterestLocal.owedPerDay.mul(closePrincipal).div(\n loanLocal.principal\n );\n } else {\n owedPerDayRefund = loanInterestLocal.owedPerDay;\n }\n\n // update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.sub(owedPerDayRefund);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(owedPerDayRefund);\n\n // update borrower interest\n uint256 interestRefundToBorrower = loanLocal.endTimestamp.sub(interestTime);\n interestRefundToBorrower = interestRefundToBorrower.mul(owedPerDayRefund);\n interestRefundToBorrower = interestRefundToBorrower.div(1 days);\n\n if (closePrincipal < loanLocal.principal) {\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(\n interestRefundToBorrower\n );\n } else {\n loanInterestLocal.depositTotal = 0;\n }\n\n // update remaining lender interest values\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.sub(\n closePrincipal\n );\n\n uint256 owedTotal = lenderInterestLocal.owedTotal;\n lenderInterestLocal.owedTotal = owedTotal > interestRefundToBorrower\n ? owedTotal - interestRefundToBorrower\n : 0;\n\n return interestRefundToBorrower;\n }\n\n /**\n * @notice Check sender is borrower or delegatee and loan id exists.\n *\n * @param loanId byte32 of the loan id.\n * */\n function _checkAuthorized(bytes32 loanId) internal view {\n Loan storage loanLocal = loans[loanId];\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n }\n\n /**\n * @notice Internal function for closing a position by swapping the\n * collateral back to loan tokens, paying the lender and withdrawing\n * the remainder.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collatral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid\n * out in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(swapAmount != 0, \"swapAmount == 0\");\n\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't swap more than collateral.\n swapAmount = swapAmount > loanLocal.collateral ? loanLocal.collateral : swapAmount;\n\n //close whole loan if tiny position will remain\n if (loanLocal.collateral - swapAmount > 0) {\n if (\n _getAmountInRbtc(\n loanParamsLocal.collateralToken,\n loanLocal.collateral - swapAmount\n ) <= TINY_AMOUNT\n ) {\n swapAmount = loanLocal.collateral;\n }\n }\n\n uint256 loanCloseAmountLessInterest;\n if (swapAmount == loanLocal.collateral || returnTokenIsCollateral) {\n /// loanCloseAmountLessInterest will be passed as required amount amount of destination tokens.\n /// this means, the actual swapAmount passed to the swap contract does not matter at all.\n /// the source token amount will be computed depending on the required amount amount of destination tokens.\n loanCloseAmount = swapAmount == loanLocal.collateral\n ? loanLocal.principal\n : loanLocal.principal.mul(swapAmount).div(loanLocal.collateral);\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Computes the interest refund for the borrower and sends it to the lender to cover part of the principal.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n } else {\n /// loanCloseAmount is calculated after swap; for this case we want to swap the entire source amount\n /// and determine the loanCloseAmount and withdraw amount based on that.\n loanCloseAmountLessInterest = 0;\n }\n\n uint256 coveredPrincipal;\n uint256 usedCollateral;\n\n /// swapAmount repurposed for collateralToLoanSwapRate to avoid stack too deep error.\n (coveredPrincipal, usedCollateral, withdrawAmount, swapAmount) = _coverPrincipalWithSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount, /// The amount of source tokens to swap (only matters if !returnTokenIsCollateral or loanCloseAmountLessInterest = 0)\n loanCloseAmountLessInterest, /// This is the amount of destination tokens we want to receive (only matters if returnTokenIsCollateral)\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (loanCloseAmountLessInterest == 0) {\n /// Condition prior to swap: swapAmount != loanLocal.collateral && !returnTokenIsCollateral\n\n /// Amounts that is closed.\n loanCloseAmount = coveredPrincipal;\n if (coveredPrincipal != loanLocal.principal) {\n loanCloseAmount = loanCloseAmount.mul(usedCollateral).div(loanLocal.collateral);\n }\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Amount that is returned to the lender.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n\n /// Remaining amount withdrawn to the receiver.\n withdrawAmount = withdrawAmount.add(coveredPrincipal).sub(loanCloseAmountLessInterest);\n } else {\n /// Pay back the amount which was covered by the swap.\n loanCloseAmountLessInterest = coveredPrincipal;\n }\n\n require(loanCloseAmountLessInterest != 0, \"closeAmount is 0 after swap\");\n\n /// Reduce the collateral by the amount which was swapped for the closure.\n if (usedCollateral != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(usedCollateral);\n }\n\n /// Repays principal to lender.\n /// The lender always gets back an ERC20 (even wrbtc), so we call\n /// withdraw directly rather than use the _withdrawAsset helper function.\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, loanCloseAmountLessInterest);\n\n withdrawToken = returnTokenIsCollateral\n ? loanParamsLocal.collateralToken\n : loanParamsLocal.loanToken;\n\n if (withdrawAmount != 0) {\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n usedCollateral,\n swapAmount, /// collateralToLoanSwapRate\n CloseTypes.Swap\n );\n }\n\n /**\n * @notice Close a loan.\n *\n * @dev Wrapper for _closeLoan internal function.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan params.\n * @param loanCloseAmount The amount to close: principal or lower.\n * @param collateralCloseAmount The amount of collateral to close.\n * @param collateralToLoanSwapRate The price rate collateral/loan token.\n * @param closeType The type of loan close.\n * */\n function _finalizeClose(\n Loan storage loanLocal,\n LoanParams storage loanParamsLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanSwapRate,\n CloseTypes closeType\n ) internal {\n _closeLoan(loanLocal, loanCloseAmount);\n\n address _priceFeeds = priceFeeds;\n uint256 currentMargin;\n uint256 collateralToLoanRate;\n\n /// This is still called even with full loan close to return collateralToLoanRate\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).getCurrentMargin.selector,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n )\n );\n assembly {\n if eq(success, 1) {\n currentMargin := mload(add(data, 32))\n collateralToLoanRate := mload(add(data, 64))\n }\n }\n /// Note: We can safely skip the margin check if closing\n /// via closeWithDeposit or if closing the loan in full by any method.\n require(\n closeType == CloseTypes.Deposit ||\n loanLocal.principal == 0 || /// loan fully closed\n currentMargin > loanParamsLocal.maintenanceMargin,\n \"unhealthy position\"\n );\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n collateralCloseAmount,\n collateralToLoanRate,\n collateralToLoanSwapRate,\n currentMargin,\n closeType\n );\n }\n\n /**\n * swaps a share of a loan's collateral or the complete collateral in order to cover the principle.\n * @param loanLocal the loan\n * @param loanParamsLocal the loan parameters\n * @param swapAmount in case principalNeeded == 0 or !returnTokenIsCollateral, this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens needed for the swap is estimated by the connector.\n * @param principalNeeded the required amount of destination tokens in order to cover the principle (only used if returnTokenIsCollateral)\n * @param returnTokenIsCollateral tells if the user wants to withdraw his remaining collateral + profit in collateral tokens\n * @notice Swaps a share of a loan's collateral or the complete collateral\n * in order to cover the principle.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount In case principalNeeded == 0 or !returnTokenIsCollateral,\n * this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens\n * needed for the swap is estimated by the connector.\n * @param principalNeeded The required amount of destination tokens in order to\n * cover the principle (only used if returnTokenIsCollateral).\n * @param returnTokenIsCollateral Tells if the user wants to withdraw his\n * remaining collateral + profit in collateral tokens.\n *\n * @return coveredPrincipal The amount of principal that is covered.\n * @return usedCollateral The amount of collateral used.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _coverPrincipalWithSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 coveredPrincipal,\n uint256 usedCollateral,\n uint256 withdrawAmount,\n uint256 collateralToLoanSwapRate\n )\n {\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n (\n destTokenAmountReceived,\n sourceTokenAmountUsed,\n collateralToLoanSwapRate\n ) = _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount,\n principalNeeded,\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (returnTokenIsCollateral) {\n coveredPrincipal = principalNeeded;\n\n /// Better fill than expected.\n if (destTokenAmountReceived > coveredPrincipal) {\n /// Send excess to borrower if the amount is big enough to be\n /// worth the gas fees.\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - coveredPrincipal\n )\n ) {\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n destTokenAmountReceived - coveredPrincipal\n );\n }\n /// Else, give the excess to the lender (if it goes to the\n /// borrower, they're very confused. causes more trouble than it's worth)\n else {\n coveredPrincipal = destTokenAmountReceived;\n }\n }\n withdrawAmount = swapAmount > sourceTokenAmountUsed\n ? swapAmount - sourceTokenAmountUsed\n : 0;\n } else {\n require(sourceTokenAmountUsed == swapAmount, \"swap error\");\n\n if (swapAmount == loanLocal.collateral) {\n /// sourceTokenAmountUsed == swapAmount == loanLocal.collateral\n\n coveredPrincipal = principalNeeded;\n withdrawAmount = destTokenAmountReceived - principalNeeded;\n } else {\n /// sourceTokenAmountUsed == swapAmount < loanLocal.collateral\n\n if (destTokenAmountReceived >= loanLocal.principal) {\n /// Edge case where swap covers full principal.\n\n coveredPrincipal = loanLocal.principal;\n withdrawAmount = destTokenAmountReceived - loanLocal.principal;\n\n /// Excess collateral refunds to the borrower.\n _withdrawAsset(\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n loanLocal.collateral - sourceTokenAmountUsed\n );\n sourceTokenAmountUsed = loanLocal.collateral;\n } else {\n coveredPrincipal = destTokenAmountReceived;\n withdrawAmount = 0;\n }\n }\n }\n\n usedCollateral = sourceTokenAmountUsed > swapAmount ? sourceTokenAmountUsed : swapAmount;\n }\n\n function _emitClosingEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanRate,\n uint256 collateralToLoanSwapRate,\n uint256 currentMargin,\n CloseTypes closeType\n ) internal {\n if (closeType == CloseTypes.Deposit) {\n emit CloseWithDeposit(\n loanLocal.borrower, /// user (borrower)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n msg.sender, /// closer\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n loanCloseAmount, /// loanCloseAmount\n collateralCloseAmount, /// collateralCloseAmount\n collateralToLoanRate, /// collateralToLoanRate\n currentMargin /// currentMargin\n );\n } else if (closeType == CloseTypes.Swap) {\n /// exitPrice = 1 / collateralToLoanSwapRate\n if (collateralToLoanSwapRate != 0) {\n collateralToLoanSwapRate = SafeMath.div(10**36, collateralToLoanSwapRate);\n }\n\n /// currentLeverage = 100 / currentMargin\n if (currentMargin != 0) {\n currentMargin = SafeMath.div(10**38, currentMargin);\n }\n\n emit CloseWithSwap(\n loanLocal.borrower, /// user (trader)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n msg.sender, /// closer\n collateralCloseAmount, /// positionCloseSize\n loanCloseAmount, /// loanCloseAmount\n collateralToLoanSwapRate, /// exitPrice (1 / collateralToLoanSwapRate)\n currentMargin /// currentLeverage\n );\n } else if (closeType == CloseTypes.Liquidation) {\n emit Liquidate(\n loanLocal.borrower, // user (borrower)\n msg.sender, // liquidator\n loanLocal.id, // loanId\n loanLocal.lender, // lender\n loanParamsLocal.loanToken, // loanToken\n loanParamsLocal.collateralToken, // collateralToken\n loanCloseAmount, // loanCloseAmount\n collateralCloseAmount, // collateralCloseAmount\n collateralToLoanRate, // collateralToLoanRate\n currentMargin // currentMargin\n );\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal view returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n IPriceFeeds(priceFeeds).queryRate(asset, address(wrbtcToken));\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /**\n * @dev private function which check the loanLocal & loanParamsLocal does exist\n *\n * @param loanId bytes32 of loanId\n *\n * @return Loan storage\n * @return LoanParams storage\n */\n function _checkLoan(bytes32 loanId) internal view returns (Loan storage, LoanParams storage) {\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n return (loanLocal, loanParamsLocal);\n }\n}\n" + }, + "contracts/modules/LoanClosingsWith.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsWith contract.\n * @notice Close a loan w/deposit, close w/swap. There are 2 functions for ending a loan on the\n * protocol contract: closeWithSwap and closeWithDeposit. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsWith is LoanClosingsShared {\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n\n /**\n * @notice Closes a loan by doing a deposit.\n *\n * @dev Public wrapper for _closeWithDeposit internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens. (e.g. rBTC on a iSUSD contract).\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n public\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return _closeWithDeposit(loanId, receiver, depositAmount);\n }\n\n /**\n * @notice Close a position by swapping the collateral back to loan tokens\n * paying the lender and withdrawing the remainder.\n *\n * @dev Public wrapper for _closeWithSwap internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collateral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid out\n * in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes memory // for future use /*loanDataBytes*/\n )\n public\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return\n _closeWithSwap(\n loanId,\n receiver,\n swapAmount,\n returnTokenIsCollateral,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for closing a loan by doing a deposit.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens.\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(depositAmount != 0, \"depositAmount == 0\");\n\n //TODO should we skip this check if invoked from rollover ?\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't close more than the full principal.\n loanCloseAmount = depositAmount > loanLocal.principal\n ? loanLocal.principal\n : depositAmount;\n\n //revert if tiny position remains\n uint256 remainingAmount = loanLocal.principal - loanCloseAmount;\n if (remainingAmount > 0) {\n require(\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount) > TINY_AMOUNT,\n \"Tiny amount when closing with deposit\"\n );\n }\n\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(loanLocal, loanParamsLocal, loanCloseAmount, receiver);\n\n if (loanCloseAmountLessInterest != 0) {\n _returnPrincipalWithDeposit(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmount == loanLocal.principal) {\n withdrawAmount = loanLocal.collateral;\n } else {\n withdrawAmount = loanLocal.collateral.mul(loanCloseAmount).div(loanLocal.principal);\n }\n\n withdrawToken = loanParamsLocal.collateralToken;\n\n if (withdrawAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(withdrawAmount);\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n withdrawAmount, /// collateralCloseAmount\n 0, /// collateralToLoanSwapRate\n CloseTypes.Deposit\n );\n }\n\n /**\n * @notice Function to check whether the given loanId & deposit amount when closing with deposit will cause the tiny position\n *\n * @param loanId The id of the loan.\n * @param depositAmount Defines how much the deposit amount to close the position.\n *\n * @return isTinyPosition true is indicating tiny position, false otherwise.\n * @return tinyPositionAmount will return 0 for non tiny position, and will return the amount of tiny position if true\n */\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount)\n {\n (Loan memory loanLocal, LoanParams memory loanParamsLocal) = _checkLoan(loanId);\n\n if (depositAmount < loanLocal.principal) {\n uint256 remainingAmount = loanLocal.principal - depositAmount;\n uint256 remainingRBTCAmount =\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingRBTCAmount < TINY_AMOUNT) {\n isTinyPosition = true;\n tinyPositionAmount = remainingRBTCAmount;\n }\n }\n\n return (isTinyPosition, tinyPositionAmount);\n }\n}\n" + }, + "contracts/modules/LoanMaintenance.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Maintenance contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to query loan data and to modify its status\n * by withdrawing or depositing collateral.\n * */\ncontract LoanMaintenance is\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n LiquidationHelper,\n ModuleCommonFunctionalities\n{\n // Keep the old LoanReturnData for backward compatibility (especially for the watcher)\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n // The new struct which contained borrower & creation time of a loan\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set initial values of proxy targets.\n *\n * @param target The address of the logic contract instance.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.depositCollateral.selector];\n _setTarget(this.depositCollateral.selector, target);\n _setTarget(this.withdrawCollateral.selector, target);\n _setTarget(this.withdrawAccruedInterest.selector, target);\n _setTarget(this.extendLoanDuration.selector, target);\n _setTarget(this.reduceLoanDuration.selector, target);\n _setTarget(this.getLenderInterestData.selector, target);\n _setTarget(this.getLoanInterestData.selector, target);\n _setTarget(this.getUserLoans.selector, target);\n _setTarget(this.getUserLoansV2.selector, target);\n _setTarget(this.getLoan.selector, target);\n _setTarget(this.getLoanV2.selector, target);\n _setTarget(this.getActiveLoans.selector, target);\n _setTarget(this.getActiveLoansV2.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanMaintenance\");\n }\n\n /**\n * @notice Increase the margin of a position by depositing additional collateral.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount /// must match msg.value if ether is sent\n ) external payable nonReentrant whenNotPaused {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.value == 0 || loanParamsLocal.collateralToken == address(wrbtcToken),\n \"wrong asset sent\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(depositAmount);\n\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.collateralToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n\n (uint256 collateralToLoanRate, ) =\n IPriceFeeds(priceFeeds).queryRate(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n\n emit DepositCollateral(loanId, depositAmount, collateralToLoanRate);\n }\n\n /**\n * @notice Withdraw from the collateral. This reduces the margin of a position.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 actualWithdrawAmount) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral,\n loanParamsLocal.maintenanceMargin\n );\n\n if (withdrawAmount > maxDrawdown) {\n actualWithdrawAmount = maxDrawdown;\n } else {\n actualWithdrawAmount = withdrawAmount;\n }\n\n loanLocal.collateral = loanLocal.collateral.sub(actualWithdrawAmount);\n\n if (loanParamsLocal.collateralToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, actualWithdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.collateralToken, receiver, actualWithdrawAmount);\n }\n }\n\n /**\n * @notice Withdraw accrued loan interest.\n *\n * @dev Wrapper for _payInterest internal function.\n *\n * @param loanToken The loan token address.\n * */\n function withdrawAccruedInterest(address loanToken) external whenNotPaused {\n /// Pay outstanding interest to lender.\n _payInterest(\n msg.sender, /// Lender.\n loanToken\n );\n }\n\n /**\n * @notice Extend the loan duration by as much time as depositAmount can buy.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in loan tokens. Used to pay the interest for the new duration.\n * @param useCollateral Whether pay interests w/ the collateral. If true, depositAmount of loan tokens\n *\t\t\t\t\t\twill be purchased with the collateral.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n *\n * @return secondsExtended The amount of time in seconds the loan is extended.\n * */\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external payable nonReentrant whenNotPaused returns (uint256 secondsExtended) {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n !useCollateral ||\n msg.sender == loanLocal.borrower ||\n delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(\n msg.value == 0 || (!useCollateral && loanParamsLocal.loanToken == address(wrbtcToken)),\n \"wrong asset sent\"\n );\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n /// Handle back interest: calculates interest owned since the loan\n /// endtime passed but the loan remained open.\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestOwed = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestOwed.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(86400);\n\n require(depositAmount > backInterestOwed, \"deposit cannot cover back interest\");\n }\n\n /// Deposit interest.\n if (useCollateral) {\n /// Used the whole converted loanToken to extend the loan duration\n depositAmount = _doCollateralSwap(loanLocal, loanParamsLocal, depositAmount);\n } else {\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.loanToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n }\n\n if (backInterestOwed != 0) {\n depositAmount = depositAmount.sub(backInterestOwed);\n\n /// Pay out backInterestOwed\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n secondsExtended = depositAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(secondsExtended);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(depositAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .add(depositAmount);\n }\n\n /**\n * @notice Reduce the loan duration by withdrawing from the deposited interest.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in loan tokens.\n *\n * @return secondsReduced The amount of time in seconds the loan is reduced.\n * */\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 secondsReduced) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(loanLocal.endTimestamp > block.timestamp, \"loan term has ended\");\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 interestDepositRemaining =\n loanLocal.endTimestamp.sub(block.timestamp).mul(loanInterestLocal.owedPerDay).div(\n 86400\n );\n require(withdrawAmount < interestDepositRemaining, \"withdraw amount too high\");\n\n /// Withdraw interest.\n if (loanParamsLocal.loanToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, withdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.loanToken, receiver, withdrawAmount);\n }\n\n secondsReduced = withdrawAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n require(loanLocal.endTimestamp > secondsReduced, \"loan too short\");\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.sub(secondsReduced);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(withdrawAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .sub(withdrawAmount);\n }\n\n /**\n * @notice Get current lender interest data totals for all loans\n * with a specific oracle and interest token.\n *\n * @param lender The lender address.\n * @param loanToken The loan token address.\n *\n * @return interestPaid The total amount of interest that has been paid to a lender so far.\n * @return interestPaidDate The date of the last interest pay out, or 0 if no interest has been withdrawn yet.\n * @return interestOwedPerDay The amount of interest the lender is earning per day.\n * @return interestUnPaid The total amount of interest the lender is owned and not yet withdrawn.\n * @return interestFeePercent The fee retained by the protocol before interest is paid to the lender.\n * @return principalTotal The total amount of outstanding principal the lender has loaned.\n * */\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n )\n {\n LenderInterest memory lenderInterestLocal = lenderInterest[lender][loanToken];\n\n interestUnPaid = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(86400);\n if (interestUnPaid > lenderInterestLocal.owedTotal)\n interestUnPaid = lenderInterestLocal.owedTotal;\n\n return (\n lenderInterestLocal.paidTotal,\n lenderInterestLocal.paidTotal != 0 ? lenderInterestLocal.updatedTimestamp : 0,\n lenderInterestLocal.owedPerDay,\n lenderInterestLocal.updatedTimestamp != 0 ? interestUnPaid : 0,\n lendingFeePercent,\n lenderInterestLocal.principalTotal\n );\n }\n\n /**\n * @notice Get current interest data for a loan.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loanToken The loan token that interest is paid in.\n * @return interestOwedPerDay The amount of interest the borrower is paying per day.\n * @return interestDepositTotal The total amount of interest the borrower has deposited.\n * @return interestDepositRemaining The amount of deposited interest that is not yet owed to a lender.\n * */\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n )\n {\n loanToken = loanParams[loans[loanId].loanParamsId].loanToken;\n interestOwedPerDay = loanInterest[loanId].owedPerDay;\n interestDepositTotal = loanInterest[loanId].depositTotal;\n\n uint256 endTimestamp = loans[loanId].endTimestamp;\n uint256 interestTime = block.timestamp > endTimestamp ? endTimestamp : block.timestamp;\n interestDepositRemaining = endTimestamp > interestTime\n ? endTimestamp.sub(interestTime).mul(interestOwedPerDay).div(86400)\n : 0;\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData) {\n return\n _getLoan(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2) {\n return\n _getLoanV2(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get all active loans.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @dev New view function which will return the loan data.\n * @dev This function was created to support backward compatibility\n * @dev As in we the old getActiveLoans function is not expected to be changed by the wathcers.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loanData The data structure\n * @return extendedLoanData The data structure which contained (borrower & creation time)\n */\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Internal function to get one loan data structure.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ the loan information.\n * */\n function _getLoan(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnData memory loanData) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanData;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanData;\n }\n\n return\n LoanReturnData({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable\n });\n }\n\n /**\n * @notice Internal function to get one loan data structure v2.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data v2 structure w/ the loan information.\n * */\n function _getLoanV2(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnDataV2 memory loanDataV2) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanDataV2;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanDataV2;\n }\n\n return\n LoanReturnDataV2({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n borrower: loanLocal.borrower,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable,\n creationTimestamp: loanLocal.startTimestamp\n });\n }\n\n /**\n * @notice Internal function to collect interest from the collateral.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param depositAmount The amount of underlying tokens provided on the loan.\n * */\n function _doCollateralSwap(\n Loan storage loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 depositAmount\n ) internal returns (uint256 purchasedLoanToken) {\n /// Reverts in _loanSwap if amountNeeded can't be bought.\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanLocal.collateral, /// minSourceTokenAmount\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n depositAmount, /// requiredDestTokenAmount (partial spend of loanLocal.collateral to fill this amount)\n true, /// bypassFee\n \"\" /// loanDataBytes\n );\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n /// Ensure the loan is still healthy.\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n return destTokenAmountReceived;\n }\n}\n" + }, + "contracts/modules/LoanOpenings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\n/**\n * @title Loan Openings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to borrow and trade.\n * */\ncontract LoanOpenings is\n LoanOpeningsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n ModuleCommonFunctionalities\n{\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\n _setTarget(this.borrowOrTradeFromPool.selector, target);\n _setTarget(this.setDelegatedManager.selector, target);\n _setTarget(this.getEstimatedMarginExposure.selector, target);\n _setTarget(this.getRequiredCollateral.selector, target);\n _setTarget(this.getBorrowAmount.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanOpenings\");\n }\n\n /**\n * @notice Borrow or trade from pool.\n *\n * @dev Note: Only callable by loan pools (iTokens).\n * Wrapper to _borrowOrTrade internal function.\n *\n * @param loanParamsId The ID of the loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return newPrincipal The new loan size.\n * @return newCollateral The new collateral amount.\n * */\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n bytes calldata loanDataBytes\n )\n external\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 newPrincipal, uint256 newCollateral)\n {\n require(msg.value == 0 || loanDataBytes.length != 0, \"loanDataBytes required with ether\");\n\n /// Only callable by loan pools.\n require(loanPoolToUnderlying[msg.sender] != address(0), \"not authorized\");\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n /// Get required collateral.\n uint256 collateralAmountRequired =\n _getRequiredCollateral(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentValues.newPrincipal,\n initialMargin,\n isTorqueLoan\n );\n require(collateralAmountRequired != 0, \"collateral is 0\");\n\n return\n _borrowOrTrade(\n loanParamsLocal,\n loanId,\n isTorqueLoan,\n collateralAmountRequired,\n initialMargin,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @dev Wrapper for _setDelegatedManager internal function.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external whenNotPaused {\n require(loans[loanId].borrower == msg.sender, \"unauthorized\");\n\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\n }\n\n /**\n * @notice Get the estimated margin exposure.\n *\n * Margin is the money borrowed from a broker to purchase an investment\n * and is the difference between the total value of investment and the\n * loan amount. Margin trading refers to the practice of using borrowed\n * funds from a broker to trade a financial asset, which forms the\n * collateral for the loan from the broker.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param loanTokenSent The amount of loan tokens sent.\n * @param collateralTokenSent The amount of collateral tokens sent.\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\n * @param newPrincipal The updated amount of principal (current debt).\n *\n * @return The margin exposure.\n * */\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256) {\n uint256 maxLoanTerm = 2419200; // 28 days\n\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\n\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\n\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\n uint256 tradingFee = _getTradingFee(swapAmount);\n if (tradingFee != 0) {\n swapAmount = swapAmount.sub(tradingFee);\n }\n\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\n if (receivedAmount == 0) {\n return 0;\n } else {\n return collateralTokenSent.add(receivedAmount);\n }\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Calls internal _getRequiredCollateral and add fees.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralAmountRequired The required collateral.\n * */\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 collateralAmountRequired) {\n if (marginAmount != 0) {\n collateralAmountRequired = _getRequiredCollateral(\n loanToken,\n collateralToken,\n newPrincipal,\n marginAmount,\n isTorqueLoan\n );\n\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n // cannot be applied solely as it drives to some other tests failure\n /*\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (collateralAmountRequired != 0 && feePercent != 0) {\n\t\t\t\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t);\n\t\t\t}*/\n\n uint256 fee =\n isTorqueLoan\n ? _getBorrowingFee(collateralAmountRequired)\n : _getTradingFee(collateralAmountRequired);\n if (fee != 0) {\n collateralAmountRequired = collateralAmountRequired.add(fee);\n }\n }\n }\n\n /**\n * @notice Get the borrow amount of a trade loan.\n *\n * @dev Basically borrowAmount = collateral / marginAmount\n *\n * Collateral is something that helps secure a loan. When you borrow money,\n * you agree that your lender can take something and sell it to get their\n * money back if you fail to repay the loan. That's the collateral.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param collateralTokenAmount The amount of collateral.\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return borrowAmount The borrow amount.\n * */\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 borrowAmount) {\n if (marginAmount != 0) {\n if (isTorqueLoan) {\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\n }\n uint256 collateral = collateralTokenAmount;\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\n if (fee != 0) {\n collateral = collateral.sub(fee);\n }\n if (loanToken == collateralToken) {\n borrowAmount = collateral.mul(10**20).div(marginAmount);\n } else {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestPrecision != 0) {\n borrowAmount = collateral\n .mul(10**20)\n .mul(sourceToDestRate)\n .div(marginAmount)\n .div(sourceToDestPrecision);\n }\n }\n /*\n\t\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t\t// cannot be applied solely as it drives to some other tests failure\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (borrowAmount != 0 && feePercent != 0) {\n\t\t\t\tborrowAmount = borrowAmount\n\t\t\t\t\t.mul(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t)\n\t\t\t\t\t.divCeil(10**20);\n\t\t\t}*/\n }\n }\n\n /**\n * @notice Borrow or trade.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param collateralAmountRequired The required amount of collateral.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return The new loan size.\n * @return The new collateral amount.\n * */\n function _borrowOrTrade(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 collateralAmountRequired,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n require(\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\n \"collateral/loan match\"\n );\n require(initialMargin >= loanParamsLocal.minInitialMargin, \"initialMargin too low\");\n\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\n require(\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\n \"invalid interest\"\n );\n\n /// Initialize loan.\n Loan storage loanLocal =\n loans[\n _initializeLoan(\n loanParamsLocal,\n loanId,\n initialMargin,\n sentAddresses,\n sentValues.newPrincipal\n )\n ];\n\n // Get required interest.\n uint256 amount =\n _initializeInterest(\n loanParamsLocal,\n loanLocal,\n sentValues.interestRate, /// newRate\n sentValues.newPrincipal, /// newPrincipal,\n sentValues.interestInitialAmount /// torqueInterest\n );\n\n /// substract out interest from usable loanToken sent.\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\n\n if (isTorqueLoan) {\n require(sentValues.loanTokenSent == 0, \"surplus loan token\");\n\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\n // need to temp into local state to avoid\n address _collateralToken = loanParamsLocal.collateralToken;\n address _loanToken = loanParamsLocal.loanToken;\n if (borrowingFee != 0) {\n _payBorrowingFee(\n sentAddresses.borrower, /// borrower\n loanLocal.id,\n _collateralToken, /// fee token\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n borrowingFee\n );\n\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\n }\n } else {\n /// Update collateral after trade.\n uint256 receivedAmount;\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\n loanId,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentAddresses.borrower, /// borrower\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\n false, /// bypassFee\n loanDataBytes\n );\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\n\n /// Check the minEntryPrice with the rate\n require(\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\n \"entry price above the minimum\"\n );\n }\n\n /// Settle collateral.\n require(\n _isCollateralSatisfied(\n loanParamsLocal,\n loanLocal,\n initialMargin,\n sentValues.collateralTokenSent,\n collateralAmountRequired\n ),\n \"collateral insufficient\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\n\n if (isTorqueLoan) {\n /// reclaiming variable -> interestDuration\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\n } else {\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\n }\n\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\n\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\n }\n\n /**\n * @notice Finalize an open loan.\n *\n * @dev Finalize it by updating local parameters of the loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _finalizeOpen(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bool isTorqueLoan\n ) internal {\n /// @dev TODO: here the actual used rate and margin should go.\n (uint256 initialMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(initialMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n if (loanLocal.startTimestamp == block.timestamp) {\n uint256 loanToCollateralPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken\n );\n uint256 collateralToLoanPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\n loanLocal.startRate = isTorqueLoan\n ? collateralToLoanRate\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\n }\n\n _emitOpeningEvents(\n loanParamsLocal,\n loanLocal,\n sentAddresses,\n sentValues,\n collateralToLoanRate,\n initialMargin,\n isTorqueLoan\n );\n }\n\n /**\n * @notice Emit the opening events.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n * @param margin The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _emitOpeningEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n uint256 collateralToLoanRate,\n uint256 margin,\n bool isTorqueLoan\n ) internal {\n if (isTorqueLoan) {\n emit Borrow(\n sentAddresses.borrower, /// user (borrower)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n sentValues.newPrincipal, /// newPrincipal\n sentValues.collateralTokenSent, /// newCollateral\n sentValues.interestRate, /// interestRate\n sentValues.interestDuration, /// interestDuration\n collateralToLoanRate, /// collateralToLoanRate,\n margin /// currentMargin\n );\n } else {\n /// currentLeverage = 100 / currentMargin\n margin = SafeMath.div(10**38, margin);\n\n emit Trade(\n sentAddresses.borrower, /// user (trader)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n sentValues.collateralTokenSent, /// positionSize\n sentValues.newPrincipal, /// borrowedAmount\n sentValues.interestRate, /// interestRate,\n loanLocal.endTimestamp, /// settlementDate\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\n sentValues.entryLeverage, /// entryLeverage\n margin /// currentLeverage\n );\n }\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegator The address of previous manager.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function _setDelegatedManager(\n bytes32 loanId,\n address delegator,\n address delegated,\n bool toggle\n ) internal {\n delegatedManagers[loanId][delegated] = toggle;\n\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\n }\n\n /**\n * @notice Calculate whether the collateral is satisfied.\n *\n * @dev Basically check collateral + drawdown >= 98% of required.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param initialMargin The initial amount of margin.\n * @param newCollateral The amount of new collateral.\n * @param collateralAmountRequired The amount of required collateral.\n *\n * @return Whether the collateral is satisfied.\n * */\n function _isCollateralSatisfied(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 initialMargin,\n uint256 newCollateral,\n uint256 collateralAmountRequired\n ) internal view returns (bool) {\n /// Allow at most 2% under-collateralized.\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\n\n if (newCollateral < collateralAmountRequired) {\n /// Check that existing collateral is sufficient coverage.\n if (loanLocal.collateral != 0) {\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral,\n initialMargin\n );\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\n } else {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @notice Initialize a loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan.\n * @param initialMargin The amount of margin of the trade.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\n * @return The loanId.\n * */\n function _initializeLoan(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n uint256 newPrincipal\n ) internal returns (bytes32) {\n require(loanParamsLocal.active, \"loanParams disabled\");\n\n address lender = sentAddresses.lender;\n address borrower = sentAddresses.borrower;\n address manager = sentAddresses.manager;\n\n Loan memory loanLocal;\n\n if (loanId == 0) {\n borrowerNonce[borrower]++;\n loanId = keccak256(\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\n );\n require(loans[loanId].id == 0, \"loan exists\");\n\n loanLocal = Loan({\n id: loanId,\n loanParamsId: loanParamsLocal.id,\n pendingTradesId: 0,\n active: true,\n principal: newPrincipal,\n collateral: 0, /// calculated later\n startTimestamp: block.timestamp,\n endTimestamp: 0, /// calculated later\n startMargin: initialMargin,\n startRate: 0, /// queried later\n borrower: borrower,\n lender: lender\n });\n\n activeLoansSet.addBytes32(loanId);\n lenderLoanSets[lender].addBytes32(loanId);\n borrowerLoanSets[borrower].addBytes32(loanId);\n } else {\n loanLocal = loans[loanId];\n require(\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\n \"loan has ended\"\n );\n require(loanLocal.borrower == borrower, \"borrower mismatch\");\n require(loanLocal.lender == lender, \"lender mismatch\");\n require(loanLocal.loanParamsId == loanParamsLocal.id, \"loanParams mismatch\");\n\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\n }\n\n if (manager != address(0)) {\n _setDelegatedManager(loanId, borrower, manager, true);\n }\n\n loans[loanId] = loanLocal;\n\n return loanId;\n }\n\n /**\n * @notice Initialize a loan interest.\n *\n * @dev A Torque loan is an indefinite-term loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param newRate The new interest rate of the loan.\n * @param newPrincipal The new principal amount of the loan.\n * @param torqueInterest The interest rate of the Torque loan.\n *\n * @return interestAmountRequired The interest amount required.\n * */\n function _initializeInterest(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n uint256 newRate,\n uint256 newPrincipal,\n uint256 torqueInterest /// ignored for fixed-term loans\n ) internal returns (uint256 interestAmountRequired) {\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 previousDepositRemaining;\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\n previousDepositRemaining = loanLocal\n .endTimestamp\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\n .mul(loanInterestLocal.owedPerDay)\n .div(86400);\n }\n\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\n\n /// Update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n\n if (maxLoanTerm == 0) {\n /// Indefinite-term (Torque) loan.\n\n /// torqueInterest != 0 was confirmed earlier.\n loanLocal.endTimestamp = torqueInterest\n .add(previousDepositRemaining)\n .mul(86400)\n .div(loanInterestLocal.owedPerDay)\n .add(block.timestamp);\n\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxLoanTerm > 3600, \"loan too short\");\n\n interestAmountRequired = torqueInterest;\n } else {\n /// Fixed-term loan.\n\n if (loanLocal.endTimestamp == 0) {\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\n }\n\n interestAmountRequired = loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(owedPerDay)\n .div(86400);\n }\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n /// Update remaining lender interest values.\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Basically collateral = newPrincipal * marginAmount\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralTokenAmount The required collateral.\n * */\n function _getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) internal view returns (uint256 collateralTokenAmount) {\n if (loanToken == collateralToken) {\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\n } else {\n /// Using the price feed instead of the swap expected return\n /// because we need the rate in the inverse direction\n /// so the swap is probably farther off than the price feed.\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestRate != 0) {\n collateralTokenAmount = newPrincipal\n .mul(sourceToDestPrecision)\n .div(sourceToDestRate)\n .mul(marginAmount)\n .div(10**20);\n /*TODO: review\n\t\t\t\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\n }\n }\n // ./tests/loan-token/TradingTestToken.test.js\n if (isTorqueLoan && collateralTokenAmount != 0) {\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\n collateralTokenAmount\n );\n }\n }\n}\n" + }, + "contracts/modules/LoanSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to get and set loan parameters.\n * */\ncontract LoanSettings is State, LoanSettingsEvents, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"LoanSettings - fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setupLoanParams.selector];\n _setTarget(this.setupLoanParams.selector, target);\n _setTarget(this.disableLoanParams.selector, target);\n _setTarget(this.getLoanParams.selector, target);\n _setTarget(this.getLoanParamsList.selector, target);\n _setTarget(this.getTotalPrincipal.selector, target);\n _setTarget(this.minInitialMargin.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanSettings\");\n }\n\n /**\n * @notice Setup loan parameters, by looping every loan\n * and populating its parameters.\n *\n * @dev For each loan calls _setupLoanParams internal function.\n *\n * @param loanParamsList The array of loan parameters.\n *\n * @return loanParamsIdList The array of loan parameters IDs.\n * */\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n whenNotPaused\n returns (bytes32[] memory loanParamsIdList)\n {\n loanParamsIdList = new bytes32[](loanParamsList.length);\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsIdList[i] = _setupLoanParams(loanParamsList[i]);\n }\n }\n\n /**\n * @notice Deactivate LoanParams for future loans. Active loans\n * using it are unaffected.\n *\n * @param loanParamsIdList The array of loan parameters IDs to deactivate.\n * */\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external whenNotPaused {\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n require(msg.sender == loanParams[loanParamsIdList[i]].owner, \"unauthorized owner\");\n loanParams[loanParamsIdList[i]].active = false;\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n emit LoanParamsDisabled(\n loanParamsLocal.id,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdDisabled(loanParamsLocal.id, loanParamsLocal.owner);\n }\n }\n\n /**\n * @notice Get loan parameters for every matching IDs.\n *\n * @param loanParamsIdList The array of loan parameters IDs to match.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParams(bytes32[] memory loanParamsIdList)\n public\n view\n returns (LoanParams[] memory loanParamsList)\n {\n loanParamsList = new LoanParams[](loanParamsIdList.length);\n uint256 itemCount;\n\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n if (loanParamsLocal.id == 0) {\n continue;\n }\n loanParamsList[itemCount] = loanParamsLocal;\n itemCount++;\n }\n\n if (itemCount < loanParamsList.length) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get loan parameters for an owner and a given page\n * defined by an offset and a limit.\n *\n * @param owner The address of the loan owner.\n * @param start The page offset.\n * @param count The page limit.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList) {\n EnumerableBytes32Set.Bytes32Set storage set = userLoanParamSets[owner];\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loanParamsList;\n }\n\n loanParamsList = new bytes32[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n loanParamsList[itemCount] = set.get(i + start - 1);\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get the total principal of the loans by a lender.\n *\n * @param lender The address of the lender.\n * @param loanToken The address of the token instance.\n *\n * @return The total principal of the loans.\n * */\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256) {\n return lenderInterest[lender][loanToken].principalTotal;\n }\n\n /**\n * @notice Setup a loan parameters.\n *\n * @param loanParamsLocal The loan parameters.\n *\n * @return loanParamsId The loan parameters ID.\n * */\n function _setupLoanParams(LoanParams memory loanParamsLocal) internal returns (bytes32) {\n bytes32 loanParamsId =\n keccak256(\n abi.encodePacked(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm,\n block.timestamp\n )\n );\n require(loanParams[loanParamsId].id == 0, \"loanParams exists\");\n\n require(\n loanParamsLocal.loanToken != address(0) &&\n loanParamsLocal.collateralToken != address(0) &&\n loanParamsLocal.minInitialMargin > loanParamsLocal.maintenanceMargin &&\n (loanParamsLocal.maxLoanTerm == 0 || loanParamsLocal.maxLoanTerm > 3600), /// A defined maxLoanTerm has to be greater than one hour.\n \"invalid params\"\n );\n\n loanParamsLocal.id = loanParamsId;\n loanParamsLocal.active = true;\n loanParamsLocal.owner = msg.sender;\n\n loanParams[loanParamsId] = loanParamsLocal;\n userLoanParamSets[msg.sender].addBytes32(loanParamsId);\n\n emit LoanParamsSetup(\n loanParamsId,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdSetup(loanParamsId, loanParamsLocal.owner);\n\n return loanParamsId;\n }\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256) {\n return loanParams[loanParamsId].minInitialMargin;\n }\n}\n" + }, + "contracts/modules/ProtocolSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../mixins/ProtocolTokenUser.sol\";\nimport \"../modules/interfaces/ProtocolSwapExternalInterface.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../governance/IFeeSharingCollector.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title Protocol Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to customize protocol settings.\n * */\ncontract ProtocolSettings is\n State,\n ProtocolTokenUser,\n ProtocolSettingsEvents,\n ModuleCommonFunctionalities\n{\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyAdminOrOwner {\n address prevModuleContractAddress = logicTargets[this.setPriceFeedContract.selector];\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n _setTarget(this.setRebatePercent.selector, target);\n _setTarget(this.setSpecialRebates.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.togglePaused.selector, target);\n _setTarget(this.isProtocolPaused.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n _setTarget(this.setRolloverFlexFeePercent.selector, target);\n _setTarget(this.getDefaultPathConversion.selector, target);\n _setTarget(this.setDefaultPathConversion.selector, target);\n _setTarget(this.removeDefaultPathConversion.selector, target);\n _setTarget(this.setAdmin.selector, target);\n _setTarget(this.getAdmin.selector, target);\n _setTarget(this.setPauser.selector, target);\n _setTarget(this.getPauser.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"ProtocolSettings\");\n }\n\n /**\n * setting wrong address will break inter module functions calling\n * should be set once\n */\n function setSovrynProtocolAddress(address newProtocolAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address oldProtocolAddress = protocolAddress;\n protocolAddress = newProtocolAddress;\n\n emit SetProtocolAddress(msg.sender, oldProtocolAddress, newProtocolAddress);\n }\n\n function setSOVTokenAddress(address newSovTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newSovTokenAddress), \"newSovTokenAddress not a contract\");\n\n address oldTokenAddress = sovTokenAddress;\n sovTokenAddress = newSovTokenAddress;\n\n emit SetSOVTokenAddress(msg.sender, oldTokenAddress, newSovTokenAddress);\n }\n\n function setLockedSOVAddress(address newLockedSOVAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newLockedSOVAddress), \"newLockSOVAddress not a contract\");\n\n address oldLockedSOVAddress = lockedSOVAddress;\n lockedSOVAddress = newLockedSOVAddress;\n\n emit SetLockedSOVAddress(msg.sender, oldLockedSOVAddress, newLockedSOVAddress);\n }\n\n /**\n * @notice Set the basis point of trading rebate rewards (SOV), max value is 9999 (99.99% liquid, 0.01% vested).\n *\n * @param newBasisPoint Basis point value.\n */\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newBasisPoint <= 9999, \"value too high\");\n\n uint256 oldBasisPoint = tradingRebateRewardsBasisPoint;\n tradingRebateRewardsBasisPoint = newBasisPoint;\n\n emit SetTradingRebateRewardsBasisPoint(msg.sender, oldBasisPoint, newBasisPoint);\n }\n\n /**\n * @notice Update the minimum number of referrals to get affiliates rewards.\n *\n * @param newMinReferrals The new minimum number of referrals.\n * */\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n uint256 oldMinReferrals = minReferralsToPayout;\n minReferralsToPayout = newMinReferrals;\n\n emit SetMinReferralsToPayoutAffiliates(msg.sender, oldMinReferrals, newMinReferrals);\n }\n\n /**\n * @notice Set the address of the Price Feed instance.\n *\n * @param newContract The address of the Price Feed new instance.\n * */\n function setPriceFeedContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = priceFeeds;\n priceFeeds = newContract;\n\n emit SetPriceFeedContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set the address of the asset swapper instance.\n *\n * @param newContract The address of the asset swapper new instance.\n * */\n function setSwapsImplContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = swapsImpl;\n swapsImpl = newContract;\n\n emit SetSwapsImplContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set a list of loan pools and its tokens.\n *\n * @param pools The array of addresses of new loan pool instances.\n * @param assets The array of addresses of the corresponding underlying tokens.\n * */\n function setLoanPool(address[] calldata pools, address[] calldata assets)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(pools.length == assets.length, \"count mismatch\");\n\n for (uint256 i = 0; i < pools.length; i++) {\n require(pools[i] != assets[i], \"pool == asset\");\n require(pools[i] != address(0), \"pool == 0\");\n require(\n assets[i] != address(0) || loanPoolToUnderlying[pools[i]] != address(0),\n \"pool not exists\"\n );\n if (assets[i] == address(0)) {\n underlyingToLoanPool[loanPoolToUnderlying[pools[i]]] = address(0);\n loanPoolToUnderlying[pools[i]] = address(0);\n loanPoolsSet.removeAddress(pools[i]);\n } else {\n loanPoolToUnderlying[pools[i]] = assets[i];\n underlyingToLoanPool[assets[i]] = pools[i];\n loanPoolsSet.addAddress(pools[i]);\n }\n\n emit SetLoanPool(msg.sender, pools[i], assets[i]);\n }\n }\n\n /**\n * @notice Set a list of supported tokens by populating the\n * storage supportedTokens mapping.\n *\n * @param addrs The array of addresses of the tokens.\n * @param toggles The array of flags indicating whether\n * the corresponding token is supported or not.\n * */\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(addrs.length == toggles.length, \"count mismatch\");\n\n for (uint256 i = 0; i < addrs.length; i++) {\n supportedTokens[addrs[i]] = toggles[i];\n\n emit SetSupportedTokens(msg.sender, addrs[i], toggles[i]);\n }\n }\n\n /**\n * @notice Set the value of lendingFeePercent storage variable.\n *\n * @param newValue The new value for lendingFeePercent.\n * */\n function setLendingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = lendingFeePercent;\n lendingFeePercent = newValue;\n\n emit SetLendingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of tradingFeePercent storage variable.\n *\n * @param newValue The new value for tradingFeePercent.\n * */\n function setTradingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = tradingFeePercent;\n tradingFeePercent = newValue;\n\n emit SetTradingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of borrowingFeePercent storage variable.\n *\n * @param newValue The new value for borrowingFeePercent.\n * */\n function setBorrowingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = borrowingFeePercent;\n borrowingFeePercent = newValue;\n\n emit SetBorrowingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of swapExtrernalFeePercent storage variable\n *\n * @param newValue the new value for swapExternalFeePercent\n */\n function setSwapExternalFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = swapExtrernalFeePercent;\n swapExtrernalFeePercent = newValue;\n\n emit SetSwapExternalFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateFeePercent storage variable.\n *\n * @param newValue The new value for affiliateFeePercent.\n * */\n function setAffiliateFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateFeePercent;\n affiliateFeePercent = newValue;\n\n emit SetAffiliateFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateTradingTokenFeePercent storage variable.\n *\n * @param newValue The new value for affiliateTradingTokenFeePercent.\n * */\n function setAffiliateTradingTokenFeePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateTradingTokenFeePercent;\n affiliateTradingTokenFeePercent = newValue;\n\n emit SetAffiliateTradingTokenFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of liquidationIncentivePercent storage variable.\n *\n * @param newValue The new value for liquidationIncentivePercent.\n * */\n function setLiquidationIncentivePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = liquidationIncentivePercent;\n liquidationIncentivePercent = newValue;\n\n emit SetLiquidationIncentivePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of the maximum swap spread.\n *\n * @param newValue The new value for maxDisagreement.\n * */\n function setMaxDisagreement(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n maxDisagreement = newValue;\n }\n\n /**\n * @notice Set the value of the maximum source buffer.\n *\n * @dev To avoid rounding issues on the swap rate a small buffer is implemented.\n *\n * @param newValue The new value for the maximum source buffer.\n * */\n function setSourceBuffer(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n sourceBuffer = newValue;\n }\n\n /**\n * @notice Set the value of the swap size limit.\n *\n * @param newValue The new value for the maximum swap size.\n * */\n function setMaxSwapSize(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n uint256 oldValue = maxSwapSize;\n maxSwapSize = newValue;\n\n emit SetMaxSwapSize(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the address of the feesController instance.\n *\n * @dev The fee sharing proxy must be the feesController of the\n * protocol contract. This allows the fee sharing proxy\n * to withdraw the fees.\n *\n * @param newController The new address of the feesController.\n * */\n function setFeesController(address newController) external onlyAdminOrOwner whenNotPaused {\n address oldController = feesController;\n feesController = newController;\n\n emit SetFeesController(msg.sender, oldController, newController);\n }\n\n /**\n * @notice Set the pauser address of sovryn protocol.\n *\n * only pauser or owner can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Get pauser address.\n *\n *\n * @return pauser address.\n */\n function getPauser() external view returns (address) {\n return pauser;\n }\n\n /*\n * @notice Set the admin address of sovryn protocol.\n *\n * only owner can perform this action.\n *\n * @param newAdmin The new address of the admin.\n * */\n function setAdmin(address newAdmin) external onlyOwner {\n emit SetAdmin(msg.sender, admin, newAdmin);\n admin = newAdmin;\n }\n\n /**\n * @dev Get admin address.\n *\n *\n * @return admin address.\n */\n function getAdmin() external view returns (address) {\n return admin;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * from three sources: lending, trading and borrowing.\n * The fees (except SOV) will be converted to wRBTC.\n * For SOV, it will be deposited directly to feeSharingCollector from the protocol.\n *\n * @param tokens The array of address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n whenNotPaused\n returns (uint256 totalWRBTCWithdrawn)\n {\n require(msg.sender == feesController, \"unauthorized\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n uint256 lendingBalance = lendingFeeTokensHeld[tokens[i]];\n if (lendingBalance > 0) {\n lendingFeeTokensHeld[tokens[i]] = 0;\n lendingFeeTokensPaid[tokens[i]] = lendingFeeTokensPaid[tokens[i]].add(\n lendingBalance\n );\n }\n\n uint256 tradingBalance = tradingFeeTokensHeld[tokens[i]];\n if (tradingBalance > 0) {\n tradingFeeTokensHeld[tokens[i]] = 0;\n tradingFeeTokensPaid[tokens[i]] = tradingFeeTokensPaid[tokens[i]].add(\n tradingBalance\n );\n }\n\n uint256 borrowingBalance = borrowingFeeTokensHeld[tokens[i]];\n if (borrowingBalance > 0) {\n borrowingFeeTokensHeld[tokens[i]] = 0;\n borrowingFeeTokensPaid[tokens[i]] = borrowingFeeTokensPaid[tokens[i]].add(\n borrowingBalance\n );\n }\n\n uint256 tempAmount = lendingBalance.add(tradingBalance).add(borrowingBalance);\n\n if (tempAmount == 0) {\n continue;\n }\n\n uint256 amountConvertedToWRBTC;\n if (tokens[i] == address(sovTokenAddress)) {\n IERC20(tokens[i]).approve(feesController, tempAmount);\n IFeeSharingCollector(feesController).transferTokens(\n address(sovTokenAddress),\n uint96(tempAmount)\n );\n amountConvertedToWRBTC = 0;\n } else {\n if (tokens[i] == address(wrbtcToken)) {\n amountConvertedToWRBTC = tempAmount;\n\n IERC20(address(wrbtcToken)).safeTransfer(receiver, amountConvertedToWRBTC);\n } else {\n IERC20(tokens[i]).approve(protocolAddress, tempAmount);\n\n (amountConvertedToWRBTC, ) = ProtocolSwapExternalInterface(protocolAddress)\n .swapExternal(\n tokens[i], // source token address\n address(wrbtcToken), // dest token address\n feesController, // set feeSharingCollector as receiver\n protocolAddress, // protocol as the sender\n tempAmount, // source token amount\n 0, // reqDestToken\n 0, // minReturn\n \"\" // loan data bytes\n );\n\n /// Will revert if disagreement found.\n IPriceFeeds(priceFeeds).checkPriceDisagreement(\n tokens[i],\n address(wrbtcToken),\n tempAmount,\n amountConvertedToWRBTC,\n maxDisagreement\n );\n }\n\n totalWRBTCWithdrawn = totalWRBTCWithdrawn.add(amountConvertedToWRBTC);\n }\n\n emit WithdrawFees(\n msg.sender,\n tokens[i],\n receiver,\n lendingBalance,\n tradingBalance,\n borrowingBalance,\n amountConvertedToWRBTC\n );\n }\n\n return totalWRBTCWithdrawn;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from lending operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = lendingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n lendingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n lendingFeeTokensPaid[token] = lendingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawLendingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from trading operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = tradingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n tradingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n tradingFeeTokensPaid[token] = tradingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawTradingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from borrowing operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = borrowingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n borrowingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n borrowingFeeTokensPaid[token] = borrowingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawBorrowingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The owner calls this function to withdraw protocol tokens.\n *\n * @dev Wrapper for ProtocolTokenUser::_withdrawProtocolToken internal function.\n *\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of tokens to get.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n onlyAdminOrOwner\n whenNotPaused\n returns (address, bool)\n {\n return _withdrawProtocolToken(receiver, amount);\n }\n\n /**\n * @notice The owner calls this function to deposit protocol tokens.\n *\n * @param amount The tokens of fees to send.\n * */\n function depositProtocolToken(uint256 amount) external onlyAdminOrOwner whenNotPaused {\n /// @dev Update local balance\n protocolTokenHeld = protocolTokenHeld.add(amount);\n\n /// @dev Send the tokens\n IERC20(protocolTokenAddress).safeTransferFrom(msg.sender, address(this), amount);\n }\n\n /**\n * @notice Get a list of loan pools.\n *\n * @param start The offset.\n * @param count The limit.\n *\n * @return The array of loan pools.\n * */\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory)\n {\n return loanPoolsSet.enumerate(start, count);\n }\n\n /**\n * @notice Check whether a token is a pool token.\n *\n * @dev By querying its underlying token.\n *\n * @param loanPool The token address to check.\n * */\n function isLoanPool(address loanPool) external view returns (bool) {\n return loanPoolToUnderlying[loanPool] != address(0);\n }\n\n /**\n * @notice Set the contract registry address of the SovrynSwap network.\n *\n * @param registryAddress the address of the registry contract.\n * */\n function setSovrynSwapContractRegistryAddress(address registryAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(registryAddress), \"registryAddress not a contract\");\n\n address oldSovrynSwapContractRegistryAddress = sovrynSwapContractRegistryAddress;\n sovrynSwapContractRegistryAddress = registryAddress;\n\n emit SetSovrynSwapContractRegistryAddress(\n msg.sender,\n oldSovrynSwapContractRegistryAddress,\n sovrynSwapContractRegistryAddress\n );\n }\n\n /**\n * @notice Set the wrBTC contract address.\n *\n * @param wrbtcTokenAddress The address of the wrBTC contract.\n * */\n function setWrbtcToken(address wrbtcTokenAddress) external onlyAdminOrOwner whenNotPaused {\n require(Address.isContract(wrbtcTokenAddress), \"wrbtcTokenAddress not a contract\");\n\n address oldwrbtcToken = address(wrbtcToken);\n wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n emit SetWrbtcToken(msg.sender, oldwrbtcToken, wrbtcTokenAddress);\n }\n\n /**\n * @notice Set the protocol token contract address.\n *\n * @param _protocolTokenAddress The address of the protocol token contract.\n * */\n function setProtocolTokenAddress(address _protocolTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n\n address oldProtocolTokenAddress = protocolTokenAddress;\n protocolTokenAddress = _protocolTokenAddress;\n\n emit SetProtocolTokenAddress(msg.sender, oldProtocolTokenAddress, _protocolTokenAddress);\n }\n\n /**\n * @notice Set rollover base reward. It should be denominated in wrBTC.\n *\n * @param baseRewardValue The base reward.\n * */\n function setRolloverBaseReward(uint256 baseRewardValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(baseRewardValue > 0, \"Base reward is zero\");\n\n uint256 oldValue = rolloverBaseReward;\n rolloverBaseReward = baseRewardValue;\n\n emit SetRolloverBaseReward(msg.sender, oldValue, rolloverBaseReward);\n }\n\n /**\n * @notice Set the fee rebate percent.\n *\n * @param rebatePercent The fee rebate percent.\n * */\n function setRebatePercent(uint256 rebatePercent) external onlyAdminOrOwner whenNotPaused {\n require(rebatePercent <= 10**20, \"Fee rebate is too high\");\n\n uint256 oldRebatePercent = feeRebatePercent;\n feeRebatePercent = rebatePercent;\n\n emit SetRebatePercent(msg.sender, oldRebatePercent, rebatePercent);\n }\n\n /**\n * @notice Set the special fee rebate percent for specific pair\n *\n * @param specialRebatesPercent The new special fee rebate percent.\n * */\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external onlyAdminOrOwner whenNotPaused {\n // Set max special rebates to 1000%\n require(specialRebatesPercent <= 1000e18, \"Special fee rebate is too high\");\n\n uint256 oldSpecialRebatesPercent = specialRebates[sourceToken][destToken];\n specialRebates[sourceToken][destToken] = specialRebatesPercent;\n\n emit SetSpecialRebates(\n msg.sender,\n sourceToken,\n destToken,\n oldSpecialRebatesPercent,\n specialRebatesPercent\n );\n }\n\n /**\n * @notice Get a rebate percent of specific pairs.\n *\n * @param sourceTokenAddress The source of pairs.\n * @param destTokenAddress The dest of pairs.\n *\n * @return The percent rebates of the pairs.\n * */\n function getSpecialRebates(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 specialRebatesPercent)\n {\n return specialRebates[sourceTokenAddress][destTokenAddress];\n }\n\n function getProtocolAddress() external view returns (address) {\n return protocolAddress;\n }\n\n function getSovTokenAddress() external view returns (address) {\n return sovTokenAddress;\n }\n\n function getLockedSOVAddress() external view returns (address) {\n return lockedSOVAddress;\n }\n\n function getFeeRebatePercent() external view returns (uint256) {\n return feeRebatePercent;\n }\n\n function togglePaused(bool paused) external onlyPauserOrOwner {\n require(paused != pause, \"Can't toggle\");\n pause = paused;\n emit TogglePaused(msg.sender, !paused, paused);\n }\n\n function isProtocolPaused() external view returns (bool) {\n return pause;\n }\n\n function getSwapExternalFeePercent() external view returns (uint256) {\n return swapExtrernalFeePercent;\n }\n\n /**\n * @notice Get the basis point of trading rebate rewards.\n *\n * @return The basis point value.\n */\n function getTradingRebateRewardsBasisPoint() external view returns (uint256) {\n return tradingRebateRewardsBasisPoint;\n }\n\n /**\n * @dev Get how much SOV that is dedicated to pay the trading rebate rewards.\n * @notice If SOV balance is less than the fees held, it will return 0.\n *\n * @return total dedicated SOV.\n */\n function getDedicatedSOVRebate() public view returns (uint256) {\n uint256 sovProtocolBalance = IERC20(sovTokenAddress).balanceOf(address(this));\n uint256 sovFees =\n lendingFeeTokensHeld[sovTokenAddress].add(tradingFeeTokensHeld[sovTokenAddress]).add(\n borrowingFeeTokensHeld[sovTokenAddress]\n );\n\n return sovProtocolBalance >= sovFees ? sovProtocolBalance.sub(sovFees) : 0;\n }\n\n /**\n * @notice Set rolloverFlexFeePercent (max value is 1%)\n *\n * @param newRolloverFlexFeePercent uint256 value of new rollover flex fee percentage (0.1 ether = 0.1%)\n */\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newRolloverFlexFeePercent <= 1e18, \"value too high\");\n uint256 oldRolloverFlexFeePercent = rolloverFlexFeePercent;\n rolloverFlexFeePercent = newRolloverFlexFeePercent;\n\n emit SetRolloverFlexFeePercent(\n msg.sender,\n oldRolloverFlexFeePercent,\n newRolloverFlexFeePercent\n );\n }\n\n /**\n * @dev Get default path conversion for pairs.\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address.\n *\n * @return default path of the conversion.\n */\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory)\n {\n return defaultPathConversion[sourceTokenAddress][destTokenAddress];\n }\n\n /**\n * @dev Set default path conversion for pairs.\n *\n * @param defaultPath array of addresses for the default path.\n *\n */\n function setDefaultPathConversion(IERC20[] calldata defaultPath)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address sourceTokenAddress = address(defaultPath[0]);\n address destTokenAddress = address(defaultPath[defaultPath.length - 1]);\n\n uint256 defaultPathLength = defaultPath.length;\n require(defaultPathLength >= 3, \"ERR_PATH_LENGTH\");\n\n for (uint256 i = 0; i < defaultPathLength; i++) {\n require(Address.isContract(address(defaultPath[i])), \"ERR_PATH_NON_CONTRACT_ADDR\");\n }\n\n defaultPathConversion[sourceTokenAddress][destTokenAddress] = defaultPath;\n\n emit SetDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPath\n );\n }\n\n /**\n * @dev Remove the default path conversion for pairs\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address\n */\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(\n defaultPathConversion[sourceTokenAddress][destTokenAddress].length > 0,\n \"DEFAULT_PATH_EMPTY\"\n );\n\n IERC20[] memory defaultPathValue =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n delete defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n emit RemoveDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPathValue\n );\n }\n}\n" + }, + "contracts/modules/SwapsExternal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Swaps External contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to calculate and execute swaps.\n * */\ncontract SwapsExternal is VaultController, SwapsUser, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.swapExternal.selector];\n _setTarget(this.swapExternal.selector, target);\n _setTarget(this.getSwapExpectedReturn.selector, target);\n _setTarget(this.checkPriceDivergence.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"SwapsExternal\");\n }\n\n /**\n * @notice Perform a swap w/ tokens or rBTC as source currency.\n *\n * @dev External wrapper that calls SwapsUser::_swapsCall\n * after turning potential incoming rBTC into wrBTC tokens.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param receiver The address of the recipient account.\n * @param returnToSender The address of the sender account.\n * @param sourceTokenAmount The amount of source tokens.\n * @param requiredDestTokenAmount The amount of required destiny tokens.\n * @param minReturn Minimum amount (position size) in the collateral tokens.\n * @param swapData Additional swap data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes memory swapData\n )\n public\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(sourceTokenAmount != 0, \"sourceTokenAmount == 0\");\n checkPriceDivergence(sourceToken, destToken, sourceTokenAmount, minReturn);\n\n /// @dev Get payed value, be it rBTC or tokenized.\n if (msg.value != 0) {\n if (sourceToken == address(0)) {\n sourceToken = address(wrbtcToken);\n }\n require(sourceToken == address(wrbtcToken), \"sourceToken mismatch\");\n require(msg.value == sourceTokenAmount, \"sourceTokenAmount mismatch\");\n\n /// @dev Update wrBTC balance for this contract.\n wrbtcToken.deposit.value(sourceTokenAmount)();\n } else {\n if (address(this) != msg.sender) {\n IERC20(sourceToken).safeTransferFrom(msg.sender, address(this), sourceTokenAmount);\n }\n }\n\n /// @dev Perform the swap w/ tokens.\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n receiver,\n returnToSender,\n msg.sender /// user\n ],\n [\n sourceTokenAmount, /// minSourceTokenAmount\n sourceTokenAmount, /// maxSourceTokenAmount\n requiredDestTokenAmount\n ],\n 0, /// loanId (not tied to a specific loan)\n false, /// bypassFee\n swapData,\n true // the flag for swapExternal (so that it will use the swapExternalFeePercent)\n );\n\n emit ExternalSwap(\n msg.sender, /// user\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Get the swap expected return value.\n *\n * @dev External wrapper that calls SwapsUser::_swapsExpectedReturn\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n *\n * @return The expected return value.\n * */\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n }\n\n /**\n * @notice Check the slippage based on the swapExpectedReturn.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n * @param minReturn The amount (max slippage) that will be compared to the swapsExpectedReturn.\n *\n */\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view {\n uint256 destTokenAmount = _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n require(destTokenAmount >= minReturn, \"destTokenAmountReceived too low\");\n }\n}\n" + }, + "contracts/modules/SwapsImplSovrynSwapModule.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../swaps/connectors/SwapsImplSovrynSwapLib.sol\";\nimport \"../events/ModulesCommonEvents.sol\";\n\ncontract SwapsImplSovrynSwapModule is State, ModulesCommonEvents {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress =\n logicTargets[this.getSovrynSwapNetworkContract.selector];\n _setTarget(this.getSovrynSwapNetworkContract.selector, target);\n _setTarget(this.getContractHexName.selector, target);\n _setTarget(this.swapsImplExpectedRate.selector, target);\n _setTarget(this.swapsImplExpectedReturn.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"SwapsImplSovrynSwapModule\"\n );\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n return SwapsImplSovrynSwapLib.getContractHexName(source);\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n return SwapsImplSovrynSwapLib.getSovrynSwapNetworkContract(sovrynSwapRegistryAddress);\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return\n SwapsImplSovrynSwapLib.getExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn) {\n return\n SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n}\n" + }, + "contracts/multisig/MultiSigKeyHolders.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/Ownable.sol\";\n\n/**\n * @title Multi Signature Key Holders contract.\n *\n * This contract contains the implementation of functions to add and remove\n * key holders w/ rBTC and BTC addresses.\n * */\ncontract MultiSigKeyHolders is Ownable {\n /* Storage */\n\n uint256 public constant MAX_OWNER_COUNT = 50;\n\n string private constant ERROR_INVALID_ADDRESS = \"Invalid address\";\n string private constant ERROR_INVALID_REQUIRED = \"Invalid required\";\n\n /// Flag and index for Ethereum address.\n mapping(address => Data) private isEthereumAddressAdded;\n\n /// List of Ethereum addresses.\n address[] private ethereumAddresses;\n\n /// Required number of signatures for the Ethereum multisig.\n uint256 public ethereumRequired = 2;\n\n /// Flag and index for Bitcoin address.\n mapping(string => Data) private isBitcoinAddressAdded;\n\n /// List of Bitcoin addresses.\n string[] private bitcoinAddresses;\n\n /// Required number of signatures for the Bitcoin multisig.\n uint256 public bitcoinRequired = 2;\n\n /// Helps removing items from array.\n struct Data {\n bool added;\n uint248 index;\n }\n\n /* Events */\n\n event EthereumAddressAdded(address indexed account);\n event EthereumAddressRemoved(address indexed account);\n event EthereumRequirementChanged(uint256 required);\n event BitcoinAddressAdded(string account);\n event BitcoinAddressRemoved(string account);\n event BitcoinRequirementChanged(uint256 required);\n\n /* Modifiers */\n\n modifier validRequirement(uint256 ownerCount, uint256 _required) {\n require(\n ownerCount <= MAX_OWNER_COUNT &&\n _required <= ownerCount &&\n _required != 0 &&\n ownerCount != 0,\n ERROR_INVALID_REQUIRED\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function addEthereumAddress(address _address) public onlyOwner {\n _addEthereumAddress(_address);\n }\n\n /**\n * @notice Add rBTC addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function _addEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (!isEthereumAddressAdded[_address].added) {\n isEthereumAddressAdded[_address] = Data({\n added: true,\n index: uint248(ethereumAddresses.length)\n });\n ethereumAddresses.push(_address);\n }\n\n emit EthereumAddressAdded(_address);\n }\n\n /**\n * @notice Remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeEthereumAddress(address _address) public onlyOwner {\n _removeEthereumAddress(_address);\n }\n\n /**\n * @notice Remove rBTC addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (isEthereumAddressAdded[_address].added) {\n uint248 index = isEthereumAddressAdded[_address].index;\n if (index != ethereumAddresses.length - 1) {\n ethereumAddresses[index] = ethereumAddresses[ethereumAddresses.length - 1];\n isEthereumAddressAdded[ethereumAddresses[index]].index = index;\n }\n ethereumAddresses.length--;\n delete isEthereumAddressAdded[_address];\n }\n\n emit EthereumAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether rBTC address is a key holder.\n * @param _address The rBTC address to be checked.\n * */\n function isEthereumAddressOwner(address _address) public view returns (bool) {\n return isEthereumAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of rBTC key holders.\n * */\n function getEthereumAddresses() public view returns (address[] memory) {\n return ethereumAddresses;\n }\n\n /**\n * @notice Set flag ethereumRequired to true/false.\n * @param _required The new value of the ethereumRequired flag.\n * */\n function changeEthereumRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(ethereumAddresses.length, _required)\n {\n ethereumRequired = _required;\n emit EthereumRequirementChanged(_required);\n }\n\n /**\n * @notice Add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function addBitcoinAddress(string memory _address) public onlyOwner {\n _addBitcoinAddress(_address);\n }\n\n /**\n * @notice Add bitcoin addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function _addBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (!isBitcoinAddressAdded[_address].added) {\n isBitcoinAddressAdded[_address] = Data({\n added: true,\n index: uint248(bitcoinAddresses.length)\n });\n bitcoinAddresses.push(_address);\n }\n\n emit BitcoinAddressAdded(_address);\n }\n\n /**\n * @notice Remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeBitcoinAddress(string memory _address) public onlyOwner {\n _removeBitcoinAddress(_address);\n }\n\n /**\n * @notice Remove bitcoin addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (isBitcoinAddressAdded[_address].added) {\n uint248 index = isBitcoinAddressAdded[_address].index;\n if (index != bitcoinAddresses.length - 1) {\n bitcoinAddresses[index] = bitcoinAddresses[bitcoinAddresses.length - 1];\n isBitcoinAddressAdded[bitcoinAddresses[index]].index = index;\n }\n bitcoinAddresses.length--;\n delete isBitcoinAddressAdded[_address];\n }\n\n emit BitcoinAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether bitcoin address is a key holder.\n * @param _address The bitcoin address to be checked.\n * */\n function isBitcoinAddressOwner(string memory _address) public view returns (bool) {\n return isBitcoinAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of bitcoin key holders.\n * */\n function getBitcoinAddresses() public view returns (string[] memory) {\n return bitcoinAddresses;\n }\n\n /**\n * @notice Set flag bitcoinRequired to true/false.\n * @param _required The new value of the bitcoinRequired flag.\n * */\n function changeBitcoinRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(bitcoinAddresses.length, _required)\n {\n bitcoinRequired = _required;\n emit BitcoinRequirementChanged(_required);\n }\n\n /**\n * @notice Add rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress the rBTC addresses to be added.\n * @param _bitcoinAddress the bitcoin addresses to be added.\n * */\n function addEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _addEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _addBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n\n /**\n * @notice Remove rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress The rBTC addresses to be removed.\n * @param _bitcoinAddress The bitcoin addresses to be removed.\n * */\n function removeEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _removeEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _removeBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n}\n" + }, + "contracts/openzeppelin/Address.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256('')`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n codehash := extcodehash(account)\n }\n return (codehash != accountHash && codehash != 0x0);\n }\n\n /**\n * @dev Converts an `address` into `address payable`. Note that this is\n * simply a type cast: the actual underlying value is not changed.\n *\n * _Available since v2.4.0._\n */\n function toPayable(address account) internal pure returns (address payable) {\n return address(uint160(account));\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n *\n * _Available since v2.4.0._\n */\n function sendValue(address recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-call-value\n (bool success, ) = recipient.call.value(amount)(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n}\n" + }, + "contracts/openzeppelin/Context.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n // Empty internal constructor, to prevent people from mistakenly deploying\n // an instance of this contract, which should be used via inheritance.\n constructor() internal {}\n\n // solhint-disable-previous-line no-empty-blocks\n\n function _msgSender() internal view returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n" + }, + "contracts/openzeppelin/ERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./Context.sol\";\nimport \"./IERC20_.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20Mintable}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20_ {\n using SafeMath for uint256;\n\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20};\n *\n * Requirements:\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for `sender`'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n _allowances[sender][_msgSender()].sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n _approve(\n _msgSender(),\n spender,\n _allowances[_msgSender()][spender].sub(\n subtractedValue,\n \"ERC20: decreased allowance below zero\"\n )\n );\n return true;\n }\n\n /**\n * @dev Moves tokens `amount` from `sender` to `recipient`.\n *\n * This is internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _balances[sender] = _balances[sender].sub(\n amount,\n \"ERC20: transfer amount exceeds balance\"\n );\n _balances[recipient] = _balances[recipient].add(amount);\n emit Transfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n *\n * This is internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`.`amount` is then deducted\n * from the caller's allowance.\n *\n * See {_burn} and {_approve}.\n */\n function _burnFrom(address account, uint256 amount) internal {\n _burn(account, amount);\n _approve(\n account,\n _msgSender(),\n _allowances[account][_msgSender()].sub(amount, \"ERC20: burn amount exceeds allowance\")\n );\n }\n}\n" + }, + "contracts/openzeppelin/ERC20Detailed.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20_.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n */\ncontract ERC20Detailed is IERC20_ {\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n */\n constructor(\n string memory name,\n string memory symbol,\n uint8 decimals\n ) public {\n _name = name;\n _symbol = symbol;\n _decimals = decimals;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/openzeppelin/IERC20_.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20_ {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/openzeppelin/Initializable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n */\ncontract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(_initializing || !_initialized, \"Initializable: contract is already initialized\");\n\n bool isTopLevelCall = !_initializing;\n if (isTopLevelCall) {\n _initializing = true;\n _initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n _initializing = false;\n }\n }\n}\n" + }, + "contracts/openzeppelin/Ownable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() public view returns (bool) {\n return _msgSender() == _owner;\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public onlyOwner {\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n */\n function _transferOwnership(address newOwner) internal {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n}\n" + }, + "contracts/openzeppelin/PausableOz.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./Ownable.sol\";\n\ncontract PausableOz is Ownable {\n /**\n * @dev Emitted when the pause is triggered by the owner (`account`).\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by the owner (`account`).\n */\n event Unpaused(address account);\n\n bool internal _paused;\n\n constructor() internal {}\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n */\n modifier whenNotPaused() {\n require(!_paused, \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n */\n modifier whenPaused() {\n require(_paused, \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/openzeppelin/ReentrancyGuard.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title Helps contracts guard against reentrancy attacks.\n * @author Remco Bloemen , Eenae \n * @dev If you mark a function `nonReentrant`, you should also\n * mark it `external`.\n */\ncontract ReentrancyGuard {\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n" + }, + "contracts/openzeppelin/SafeERC20.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./SafeMath.sol\";\nimport \"./Address.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\n );\n }\n\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n // solhint-disable-next-line max-line-length\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance =\n token.allowance(address(this), spender).sub(\n value,\n \"SafeERC20: decreased allowance below zero\"\n );\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves.\n\n // A Solidity high level call has three parts:\n // 1. The target address is checked to verify it contains contract code\n // 2. The call itself is made, and success asserted\n // 3. The return value is decoded, which in turn checks the size of the returned data.\n // solhint-disable-next-line max-line-length\n require(address(token).isContract(), \"SafeERC20: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(data);\n require(success, \"SafeERC20: low-level call failed\");\n\n if (returndata.length > 0) {\n // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "contracts/openzeppelin/SafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n *\n * _Available since v2.4.0._\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\n return divCeil(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n\n if (a == 0) {\n return 0;\n }\n uint256 c = ((a - 1) / b) + 1;\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\n return _a < _b ? _a : _b;\n }\n}\n" + }, + "contracts/openzeppelin/SignedSafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title SignedSafeMath\n * @dev Signed math operations with safety checks that revert on error.\n */\nlibrary SignedSafeMath {\n int256 private constant _INT256_MIN = -2**255;\n\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n require(!(a == -1 && b == _INT256_MIN), \"SignedSafeMath: multiplication overflow\");\n\n int256 c = a * b;\n require(c / a == b, \"SignedSafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n require(b != 0, \"SignedSafeMath: division by zero\");\n require(!(b == -1 && a == _INT256_MIN), \"SignedSafeMath: division overflow\");\n\n int256 c = a / b;\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a - b;\n require((b >= 0 && c <= a) || (b < 0 && c > a), \"SignedSafeMath: subtraction overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a + b;\n require((b >= 0 && c >= a) || (b < 0 && c < a), \"SignedSafeMath: addition overflow\");\n\n return c;\n }\n}\n" + }, + "contracts/proxy/modules/interfaces/IFunctionsList.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\ninterface IFunctionsList {\n function getFunctionsList() external pure returns (bytes4[] memory functionSignatures);\n}\n" + }, + "contracts/proxy/modules/interfaces/IModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\n/**\n * ModulesProxyRegistry Interface\n */\n\ncontract IModulesProxyRegistry {\n event AddModule(address indexed moduleAddress);\n event ReplaceModule(address indexed oldAddress, address indexed newAddress);\n event RemoveModule(address indexed moduleAddress);\n event SetModuleFuncImplementation(\n bytes4 indexed _funcSig,\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use ReplaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external;\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl) external;\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external;\n\n /// @notice to disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external;\n\n /// @param _sig function signature to get impmementation address for\n /// @return function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address);\n\n /// @notice verifies if no functions from the module deployed already registered\n /// @param _impl module implementation address to verify\n /// @return true if module can be added\n function canAddModule(address _impl) external view returns (bool);\n\n /// @notice Multiple modules verification if no functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return True if all modules can be added, false otherwise\n function canNotAddModules(address[] calldata _implementations)\n external\n view\n returns (address[] memory modules);\n\n /// @notice used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n );\n}\n" + }, + "contracts/proxy/modules/ModulesProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"./ModulesProxyRegistry.sol\";\n\n/**\n * ModulesProxy serves as a storage processed by a set of logic contracts - modules\n * Modules functions are registered in the contract's slots generated per func sig\n * All the function calls except for own Proxy functions are delegated to\n * the registered functions\n * The ModulesProxy is designed as a universal solution for refactorig contracts\n * reaching a 24K size limit (EIP-170)\n *\n * Upgradability is implemented at a module level to provide consistency\n * It does not allow to replace separate functions - only the whole module\n * meaning that if a module being registered contains other modules function signatures\n * then these modulea should be replaced completely - all the functions should be removed\n * to avoid leftovers or accidental replacements and therefore functional inconsistency.\n *\n * A module is either a new non-overlapping with registered modules\n * or a complete replacement of another registered module\n * in which case all the old module functions are unregistered and then\n * the new module functions are registered\n * There is also a separate function to unregister a module which unregisters all the functions\n * There is no option to unregister a subset of module functions - one should use pausable functionality\n * to achieve this\n */\n\ncontract ModulesProxy is ModulesProxyRegistry {\n // Uncomment for using beforeFallback() hook\n /*\n bytes private constant BEFORE_FALLBACK_SIG = abi.encodeWithSignature(\"beforeFallback()\");\n bytes4 private constant BEFORE_FALLBACK_SIG_BYTES4 = bytes4(keccak256(abi.encodePacked(\"beforeFallback()\")));\n */\n\n /**\n * @notice Fallback function delegates calls to modules.\n * Returns whatever the implementation call returns.\n * Has a hook to execute before delegating calls\n * To activate register a module with beforeFallback() function\n */\n function() external payable {\n /*\n // Commented to safe gas by default\n // Uncomment for using beforeFallback() hook \n // Implement and register beforeFallback() function in a module\n address beforeFallback = _getFuncImplementation(BEFORE_FALLBACK_SIG_BYTES4);\n if (beforeFallback != address(0)) {\n (bool success, ) = beforeFallback.delegatecall(bytes(0x39b0111a)); // abi.encodeWithSignature(\"beforeFallback()\")\n require(success, \"ModulesProxy::fallback: beforeFallback() fail\"); //MP02\n }\n */\n\n address target = _getFuncImplementation(msg.sig);\n require(target != address(0), \"ModulesProxy:target module not registered\"); // MP03\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/modules/ModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"../../utils/Utils.sol\";\nimport \"../../utils/ProxyOwnable.sol\";\nimport \"../modules/interfaces/IFunctionsList.sol\";\nimport \"../modules/interfaces/IModulesProxyRegistry.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * ModulesProxyRegistry provides modules registration/removing/replacing functionality to ModulesProxy\n * Designed to be inherited\n */\n\ncontract ModulesProxyRegistry is IModulesProxyRegistry, ProxyOwnable {\n using Address for address;\n\n bytes32 internal constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n\n ///@notice Constructor is internal to make contract abstract\n constructor() internal {\n // abstract\n }\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use replaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external onlyProxyOwner {\n _addModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external onlyProxyOwner {\n _addModules(_implementations);\n }\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl)\n external\n onlyProxyOwner\n {\n _replaceModule(_oldModuleImpl, _newModuleImpl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external onlyProxyOwner {\n require(\n _implementationsFrom.length == _implementationsTo.length,\n \"ModulesProxyRegistry::replaceModules: arrays sizes must be equal\"\n ); //MR10\n\n // because the order of addresses is arbitrary, all modules are removed first to avoid collisions\n _removeModules(_implementationsFrom);\n _addModules(_implementationsTo);\n }\n\n /// @notice To disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external onlyProxyOwner {\n _removeModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external onlyProxyOwner {\n _removeModules(_implementations);\n }\n\n /// @param _sig Function signature to get impmementation address for\n /// @return Function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address) {\n return _getFuncImplementation(_sig);\n }\n\n /// @notice Verifies if no functions from the module already registered\n /// @param _impl Module implementation address to verify\n /// @return True if module can be added\n function canAddModule(address _impl) external view returns (bool) {\n return _canAddModule(_impl);\n }\n\n /// @notice Multiple modules verification if there are functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return addresses of registered modules\n function canNotAddModules(address[] memory _implementations)\n public\n view\n returns (address[] memory)\n {\n for (uint256 i = 0; i < _implementations.length; i++) {\n if (_canAddModule(_implementations[i])) {\n delete _implementations[i];\n }\n }\n return _implementations;\n }\n\n /// @notice Used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return Clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n )\n {\n require(\n _newModule.isContract(),\n \"ModulesProxyRegistry::checkClashingFuncSelectors: address is not a contract\"\n ); //MR06\n bytes4[] memory newModuleFunctions = IFunctionsList(_newModule).getFunctionsList();\n bytes4[] memory proxyRegistryFunctions = _getFunctionsList(); //registry functions list\n uint256 clashingProxyRegistryFuncsSize;\n uint256 clashingArraySize;\n uint256 clashingArrayIndex;\n uint256 clashingRegistryArrayIndex;\n\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0) && funcImpl != _newModule) {\n clashingArraySize++;\n } else if (_isFuncClashingWithProxyFunctions(newModuleFunctions[i]))\n clashingProxyRegistryFuncsSize++;\n }\n clashingModules = new address[](clashingArraySize);\n clashingModulesFuncSelectors = new bytes4[](clashingArraySize);\n clashingProxyRegistryFuncSelectors = new bytes4[](clashingProxyRegistryFuncsSize);\n\n if (clashingArraySize == 0 && clashingProxyRegistryFuncsSize == 0)\n //return empty arrays\n return (\n clashingModules,\n clashingModulesFuncSelectors,\n clashingProxyRegistryFuncSelectors\n );\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0)) {\n clashingModules[clashingArrayIndex] = funcImpl;\n clashingModulesFuncSelectors[clashingArrayIndex] = newModuleFunctions[i];\n clashingArrayIndex++;\n }\n for (uint256 j = 0; j < proxyRegistryFunctions.length; j++) {\n //ModulesProxyRegistry has a clashing function selector\n if (proxyRegistryFunctions[j] == newModuleFunctions[i]) {\n clashingProxyRegistryFuncSelectors[\n clashingRegistryArrayIndex\n ] = proxyRegistryFunctions[j];\n clashingRegistryArrayIndex++;\n }\n }\n }\n }\n\n /// Verifies the deployed contract address is a registered module contract\n /// @param _impl deployment address to verify\n /// @return true if _impl address is a registered module\n function isModuleRegistered(address _impl) external view returns (bool) {\n return _getFirstRegisteredModuleAddress(_impl) == _impl;\n }\n\n /****************** INTERNAL FUNCTIONS ******************/\n\n function _getFirstRegisteredModuleAddress(address _impl) internal view returns (address) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_getRegisteredModuleAddress: address is not a contract\"\n );\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n address _moduleImpl = _getFuncImplementation(functions[i]);\n if (_moduleImpl != address(0)) {\n return (_moduleImpl);\n }\n }\n return address(0);\n }\n\n function _getFuncImplementation(bytes4 _sig) internal view returns (address) {\n //TODO: add querying Registry for logic address and then delegate call to it OR use proxy memory slots like this:\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n address implementation;\n assembly {\n implementation := sload(key)\n }\n return implementation;\n }\n\n function _addModule(address _impl) internal {\n require(_impl.isContract(), \"ModulesProxyRegistry::_addModule: address is not a contract\"); //MR01\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n require(\n _getFuncImplementation(functions[i]) == address(0),\n \"ModulesProxyRegistry::_addModule: function already registered - use replaceModule function\"\n ); //MR02\n require(functions[i] != bytes4(0), \"does not allow empty function id\"); // MR03\n require(\n !_isFuncClashingWithProxyFunctions(functions[i]),\n \"ModulesProxyRegistry::_addModule: has a function with the same signature\"\n ); //MR09\n _setModuleFuncImplementation(functions[i], _impl);\n }\n emit AddModule(_impl);\n }\n\n function _addModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _addModule(_implementations[i]);\n }\n }\n\n function _removeModule(address _impl) internal onlyProxyOwner {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_removeModule: address is not a contract\"\n ); //MR07\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n _setModuleFuncImplementation(functions[i], address(0));\n\n emit RemoveModule(_impl);\n }\n\n function _removeModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _removeModule(_implementations[i]);\n }\n }\n\n function _replaceModule(address _oldModuleImpl, address _newModuleImpl) internal {\n if (_oldModuleImpl != _newModuleImpl) {\n require(\n _newModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _newModuleImpl is not a contract\"\n ); //MR03\n require(\n _oldModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _oldModuleImpl is not a contract\"\n ); //MR04\n _removeModule(_oldModuleImpl);\n _addModule(_newModuleImpl);\n\n emit ReplaceModule(_oldModuleImpl, _newModuleImpl);\n }\n }\n\n function _setModuleFuncImplementation(bytes4 _sig, address _impl) internal {\n emit SetModuleFuncImplementation(_sig, _getFuncImplementation(_sig), _impl);\n\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n assembly {\n sstore(key, _impl)\n }\n }\n\n function _isFuncClashingWithProxyFunctions(bytes4 _sig) internal pure returns (bool) {\n bytes4[] memory functionList = _getFunctionsList();\n for (uint256 i = 0; i < functionList.length; i++) {\n if (_sig == functionList[i])\n //ModulesProxyRegistry has function with the same id\n return true;\n }\n return false;\n }\n\n function _canAddModule(address _impl) internal view returns (bool) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_canAddModule: address is not a contract\"\n ); //MR06\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n if (_getFuncImplementation(functions[i]) != address(0)) return (false);\n return true;\n }\n\n function _getFunctionsList() internal pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](13);\n functionList[0] = this.getFuncImplementation.selector;\n functionList[1] = this.addModule.selector;\n functionList[2] = this.addModules.selector;\n functionList[3] = this.removeModule.selector;\n functionList[4] = this.removeModules.selector;\n functionList[5] = this.replaceModule.selector;\n functionList[6] = this.replaceModules.selector;\n functionList[7] = this.canAddModule.selector;\n functionList[8] = this.canNotAddModules.selector;\n functionList[9] = this.setProxyOwner.selector;\n functionList[10] = this.getProxyOwner.selector;\n functionList[11] = this.checkClashingFuncSelectors.selector;\n functionList[12] = this.isModuleRegistered.selector;\n return functionList;\n }\n}\n" + }, + "contracts/proxy/Proxy.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base Proxy contract.\n * @notice The proxy performs delegated calls to the contract implementation\n * it is pointing to. This way upgradable contracts are possible on blockchain.\n *\n * Delegating proxy contracts are widely used for both upgradeability and gas\n * savings. These proxies rely on a logic contract (also known as implementation\n * contract or master copy) that is called using delegatecall. This allows\n * proxies to keep a persistent state (storage and balance) while the code is\n * delegated to the logic contract.\n *\n * Proxy contract is meant to be inherited and its internal functions\n * _setImplementation and _setProxyOwner to be called when upgrades become\n * neccessary.\n *\n * The loan token (iToken) contract as well as the protocol contract act as\n * proxies, delegating all calls to underlying contracts. Therefore, if you\n * want to interact with them using web3, you need to use the ABIs from the\n * contracts containing the actual logic or the interface contract.\n * ABI for LoanToken contracts: LoanTokenLogicStandard\n * ABI for Protocol contract: ISovryn\n *\n * @dev UpgradableProxy is the contract that inherits Proxy and wraps these\n * functions.\n * */\ncontract Proxy {\n bytes32 private constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);\n event ImplementationChanged(\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /**\n * @notice Set sender as an owner.\n * */\n constructor() public {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @notice Throw error if called not by an owner.\n * */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Proxy:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the implementation.\n * @param _implementation Address of the implementation.\n * */\n function _setImplementation(address _implementation) internal {\n require(_implementation != address(0), \"Proxy::setImplementation: invalid address\");\n emit ImplementationChanged(getImplementation(), _implementation);\n\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n sstore(key, _implementation)\n }\n }\n\n /**\n * @notice Return address of the implementation.\n * @return Address of the implementation.\n * */\n function getImplementation() public view returns (address _implementation) {\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n _implementation := sload(key)\n }\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"Proxy::setProxyOwner: invalid address\");\n emit OwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Return address of the owner.\n * @return Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n address implementation = getImplementation();\n require(implementation != address(0), \"Proxy::(): implementation not found\");\n\n assembly {\n let pointer := mload(0x40)\n calldatacopy(pointer, 0, calldatasize)\n let result := delegatecall(gas, implementation, pointer, calldatasize, 0, 0)\n let size := returndatasize\n returndatacopy(pointer, 0, size)\n\n switch result\n case 0 {\n revert(pointer, size)\n }\n default {\n return(pointer, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/UpgradableProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Proxy.sol\";\n\n/**\n * @title Upgradable Proxy contract.\n * @notice A disadvantage of the immutable ledger is that nobody can change the\n * source code of a smart contract after it’s been deployed. In order to fix\n * bugs or introduce new features, smart contracts need to be upgradable somehow.\n *\n * Although it is not possible to upgrade the code of an already deployed smart\n * contract, it is possible to set-up a proxy contract architecture that will\n * allow to use new deployed contracts as if the main logic had been upgraded.\n *\n * A proxy architecture pattern is such that all message calls go through a\n * Proxy contract that will redirect them to the latest deployed contract logic.\n * To upgrade, a new version of the contract is deployed, and the Proxy is\n * updated to reference the new contract address.\n * */\ncontract UpgradableProxy is Proxy {\n /**\n * @notice Set address of the implementation.\n * @dev Wrapper for _setImplementation that exposes the function\n * as public for owner to be able to set a new version of the\n * contract as current pointing implementation.\n * @param _implementation Address of the implementation.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n _setImplementation(_implementation);\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n}\n" + }, + "contracts/reentrancy/Mutex.sol": { + "content": "pragma solidity ^0.5.17;\n\n/*\n * @title Global Mutex contract\n *\n * @notice A mutex contract that allows only one function to be called at a time out\n * of a large set of functions. *Anyone* in the network can freely use any instance\n * of this contract to add a universal mutex to any function in any contract.\n */\ncontract Mutex {\n /*\n * We use an uint to store the mutex state.\n */\n uint256 public value;\n\n /*\n * @notice Increment the mutex state and return the new value.\n *\n * @dev This is the function that will be called by anyone to change the mutex\n * state. It is purposely not protected by any access control\n */\n function incrementAndGetValue() external returns (uint256) {\n /*\n * increment value using unsafe math. This is safe because we are\n * pretty certain no one will ever increment the value 2^256 times\n * in a single transaction.\n */\n return ++value;\n }\n}\n" + }, + "contracts/reentrancy/SharedReentrancyGuard.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Mutex.sol\";\n\n/*\n * @title Abstract contract for shared reentrancy guards\n *\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\n * that there's no reentrancy between *any* functions marked with the modifier.\n *\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\n */\ncontract SharedReentrancyGuard {\n /*\n * This is the address of the mutex contract that will be used as the\n * reentrancy guard.\n *\n * The address is hardcoded to avoid changing the memory layout of\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\n * because the Mutex contract is always deployed to the same address, with the\n * same method used in the deployment of ERC1820Registry.\n */\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\n\n /*\n * This is the modifier that will be used to protect functions from\n * reentrancy. It will call the mutex contract to increment the mutex\n * state and then revert if the mutex state was changed by another\n * nested call.\n */\n modifier globallyNonReentrant() {\n uint256 previous = MUTEX.incrementAndGetValue();\n\n _;\n\n /*\n * If the mutex state was changed by a nested function call, then\n * the value of the state variable will be different from the previous value.\n */\n require(previous == MUTEX.value(), \"reentrancy violation\");\n }\n}\n" + }, + "contracts/rsk/RSKAddrValidator.sol": { + "content": "// SPDX-License-Identifier:MIT\npragma solidity ^0.5.17;\n\nlibrary RSKAddrValidator {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n * */\n function checkPKNotZero(address addr) internal pure returns (bool) {\n return (addr != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && addr != address(0));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key.\n * */\n function safeEquals(address addr1, address addr2) internal pure returns (bool) {\n return (addr1 == addr2 &&\n addr1 != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\n addr1 != address(0));\n }\n}\n" + }, + "contracts/swaps/connectors/interfaces/IContractRegistry.sol": { + "content": "pragma solidity 0.5.17;\n\ncontract IContractRegistry {\n function addressOf(bytes32 contractName) public view returns (address);\n}\n" + }, + "contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol": { + "content": "pragma solidity >=0.5.8 <=0.5.17;\n\nimport \"../../../interfaces/IERC20.sol\";\n\ncontract ISovrynSwapNetwork {\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256);\n\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\n\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory);\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwap.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../../core/State.sol\";\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\n\n/**\n * @dev WARNING: This contract is deprecated, all public functions are moved to the protocol modules.\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\ncontract SwapsImplSovrynSwap is State {\n using SafeERC20 for IERC20;\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n constructor() internal {\n // abstract\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destination tokens.\n * @param receiverAddress The address who will received the swap token results\n * @param returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * @param minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * @param maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address receiverAddress,\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n require(\n supportedTokens[sourceTokenAddress] && supportedTokens[destTokenAddress],\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = estimateSourceTokenAmount(\n sourceTokenAddress,\n destTokenAddress,\n requiredDestTokenAmount,\n maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n allowTransfer(sourceTokenAmountUsed, sourceTokenAddress, address(sovrynSwapNetwork));\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n uint256 sourceToDestPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n internalExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n maxSourceTokenAmount,\n sovrynSwapContractRegistryAddress\n );\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > sourceBuffer) buffer = sourceBuffer;\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistryAddress\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * @param sovrynSwapContractRegistry The sovryn swap contract reigstry address.\n * @param defaultPath The default path for specific pairs.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistry,\n IERC20[] memory defaultPath\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistry);\n\n IERC20[] memory path =\n defaultPath.length >= 3\n ? defaultPath\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\nimport \"../../interfaces/ISovryn.sol\";\n\n/**\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\nlibrary SwapsImplSovrynSwapLib {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n struct SwapParams {\n address sourceTokenAddress;\n address destTokenAddress;\n address receiverAddress;\n address returnToSenderAddress;\n uint256 minSourceTokenAmount;\n uint256 maxSourceTokenAmount;\n uint256 requiredDestTokenAmount;\n }\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param params SwapParams struct\n * sourceTokenAddress The address of the source tokens.\n * destTokenAddress The address of the destination tokens.\n * receiverAddress The address who will received the swap token results\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * requiredDestTokenAmount The required amount of destination tokens.\n * */\n function swap(SwapParams memory params)\n public\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(params.sourceTokenAddress != params.destTokenAddress, \"source == dest\");\n\n ISovryn iSovryn = ISovryn(address(this));\n require(\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\n iSovryn.supportedTokens(params.destTokenAddress),\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\n\n IERC20[] memory path =\n _getConversionPath(\n params.sourceTokenAddress,\n params.destTokenAddress,\n sovrynSwapNetwork\n );\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = params.minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (params.requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\n params.sourceTokenAddress,\n params.destTokenAddress,\n params.requiredDestTokenAmount,\n params.maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n params.requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = params.requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n _allowTransfer(\n sourceTokenAmountUsed,\n params.sourceTokenAddress,\n address(sovrynSwapNetwork)\n );\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n params.receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (params.returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(params.sourceTokenAddress).safeTransfer(\n params.returnToSenderAddress,\n params.maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function _allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function _estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n ISovryn iSovryn = ISovryn(address(this));\n uint256 sourceToDestPrecision =\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function getExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function getExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function _getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/testnet/SwapsImplLocal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../../core/State.sol\";\nimport \"../../../openzeppelin/SafeERC20.sol\";\nimport \"../../../feeds/IPriceFeeds.sol\";\nimport \"../../../testhelpers/TestToken.sol\";\n\n/**\n * @title Swaps Implementation Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate calculations.\n * */\ncontract SwapsImplLocal is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Swap two tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address, /*receiverAddress*/\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n\n (uint256 tradeRate, uint256 precision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n if (requiredDestTokenAmount == 0) {\n sourceTokenAmountUsed = minSourceTokenAmount;\n destTokenAmountReceived = minSourceTokenAmount.mul(tradeRate).div(precision);\n } else {\n destTokenAmountReceived = requiredDestTokenAmount;\n sourceTokenAmountUsed = requiredDestTokenAmount.mul(precision).div(tradeRate);\n require(sourceTokenAmountUsed <= minSourceTokenAmount, \"destAmount too great\");\n }\n\n TestToken(sourceTokenAddress).burn(address(this), sourceTokenAmountUsed);\n TestToken(destTokenAddress).mint(address(this), destTokenAmountReceived);\n\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Calculate the expected price rate of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n *\n * @return precision The expected price rate.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * @notice Calculate the expected return of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n * @param defaultPath defaultPath for swap.\n *\n * @return precision The expected return.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused,\n IERC20[] memory defaultPath\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n}\n" + }, + "contracts/swaps/SwapsUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../mixins/FeesHelper.sol\";\nimport \"./connectors/SwapsImplSovrynSwapLib.sol\";\n\n/**\n * @title Perform token swaps for loans and trades.\n * */\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\n /**\n * @notice Internal loan swap.\n *\n * @param loanId The ID of the loan.\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of destination tokens.\n * @param user The user address.\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * @param bypassFee To bypass or not the fee.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived\n * @return sourceTokenAmountUsed\n * @return sourceToDestSwapRate\n * */\n function _loanSwap(\n bytes32 loanId,\n address sourceToken,\n address destToken,\n address user,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount,\n bool bypassFee,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 sourceToDestSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n address(this), // receiver\n address(this), // returnToSender\n user\n ],\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\n loanId,\n bypassFee,\n loanDataBytes,\n false // swap external flag, set to false so that it will use the tradingFeePercent\n );\n\n /// Will revert if swap size too large.\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\n\n /// Will revert if disagreement found.\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived,\n maxDisagreement\n );\n\n emit LoanSwap(\n loanId,\n sourceToken,\n destToken,\n user,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Wrapper for _swapsCall_internal function.\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n * @param loanId The Id of the associated loan.\n * @param miscBool True/false to bypassFee.\n * @param loanDataBytes Additional loan data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall(\n address[5] memory addrs,\n uint256[3] memory vals,\n bytes32 loanId,\n bool miscBool, /// bypassFee\n bytes memory loanDataBytes,\n bool isSwapExternal\n ) internal returns (uint256, uint256) {\n /// addrs[0]: sourceToken\n /// addrs[1]: destToken\n /// addrs[2]: receiver\n /// addrs[3]: returnToSender\n /// addrs[4]: user\n /// vals[0]: minSourceTokenAmount\n /// vals[1]: maxSourceTokenAmount\n /// vals[2]: requiredDestTokenAmount\n\n require(vals[0] != 0 || vals[1] != 0, \"min or max source token amount needs to be set\");\n\n if (vals[1] == 0) {\n vals[1] = vals[0];\n }\n require(vals[0] <= vals[1], \"sourceAmount larger than max\");\n\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n\n uint256 tradingFee;\n if (!miscBool) {\n /// bypassFee\n if (vals[2] == 0) {\n /// condition: vals[0] will always be used as sourceAmount\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[0]);\n } else {\n tradingFee = _getTradingFee(vals[0]);\n }\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId,\n addrs[0], /// sourceToken (feeToken)\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n vals[0] = vals[0].sub(tradingFee);\n }\n } else {\n /// Condition: unknown sourceAmount will be used.\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[2]);\n } else {\n tradingFee = _getTradingFee(vals[2]);\n }\n\n if (tradingFee != 0) {\n vals[2] = vals[2].add(tradingFee);\n }\n }\n }\n\n require(loanDataBytes.length == 0, \"invalid state\");\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\n\n if (vals[2] == 0) {\n /// There's no minimum destTokenAmount, but all of vals[0]\n /// (minSourceTokenAmount) must be spent.\n require(sourceTokenAmountUsed == vals[0], \"swap too large to fill\");\n\n if (tradingFee != 0) {\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\n }\n } else {\n /// There's a minimum destTokenAmount required, but\n /// sourceTokenAmountUsed won't be greater\n /// than vals[1] (maxSourceTokenAmount)\n require(sourceTokenAmountUsed <= vals[1], \"swap fill too large\");\n require(destTokenAmountReceived >= vals[2], \"insufficient swap liquidity\");\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId, /// loanId,\n addrs[1], /// destToken (feeToken)\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\n }\n }\n\n return (destTokenAmountReceived, sourceTokenAmountUsed);\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Calls swapsImpl::internalSwap\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\n internal\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n SwapsImplSovrynSwapLib.SwapParams memory swapParams;\n\n swapParams.sourceTokenAddress = addrs[0];\n swapParams.destTokenAddress = addrs[1];\n swapParams.receiverAddress = addrs[2];\n swapParams.returnToSenderAddress = addrs[3];\n swapParams.minSourceTokenAmount = vals[0];\n swapParams.maxSourceTokenAmount = vals[1];\n swapParams.requiredDestTokenAmount = vals[2];\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = SwapsImplSovrynSwapLib.swap(swapParams);\n }\n\n /**\n * @notice Calculate expected amount of destination tokens.\n *\n * @dev Calls swapsImpl::internalExpectedReturn\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destination tokens.\n * @param sourceTokenAmount The amount of the source tokens.\n *\n * @param destTokenAmount The amount of destination tokens.\n * */\n function _swapsExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) internal view returns (uint256 destTokenAmount) {\n destTokenAmount = SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceToken,\n destToken,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Verify that the amount of tokens are under the swap limit.\n *\n * @dev Calls priceFeeds::amountInEth\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n * */\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\n uint256 _maxSwapSize = maxSwapSize;\n if (_maxSwapSize != 0) {\n uint256 amountInEth;\n if (tokenAddress == address(wrbtcToken)) {\n amountInEth = amount;\n } else {\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\n }\n require(amountInEth <= _maxSwapSize, \"swap too large\");\n }\n }\n}\n" + }, + "contracts/testhelpers/FlashLoanerTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n// \"SPDX-License-Identifier: Apache-2.0\"\n\nimport \"../interfaces/IERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./ITokenFlashLoanTest.sol\";\n\ncontract FlashLoanerTest is Ownable {\n function initiateFlashLoanTest(\n address loanToken,\n address iToken,\n uint256 flashLoanAmount\n ) internal returns (bytes memory success) {\n ITokenFlashLoanTest iTokenContract = ITokenFlashLoanTest(iToken);\n return\n iTokenContract.flashBorrow(\n flashLoanAmount,\n address(this),\n address(this),\n \"\",\n abi.encodeWithSignature(\n \"executeOperation(address,address,uint256)\",\n loanToken,\n iToken,\n flashLoanAmount\n )\n );\n }\n\n function repayFlashLoan(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) internal {\n IERC20(loanToken).transfer(iToken, loanAmount);\n }\n\n function executeOperation(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) external returns (bytes memory success) {\n emit BalanceOf(IERC20(loanToken).balanceOf(address(this)));\n emit ExecuteOperation(loanToken, iToken, loanAmount);\n repayFlashLoan(loanToken, iToken, loanAmount);\n return bytes(\"1\");\n }\n\n function doStuffWithFlashLoan(\n address token,\n address iToken,\n uint256 amount\n ) external onlyOwner {\n bytes memory result;\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n result = initiateFlashLoanTest(token, iToken, amount);\n\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n // after loan checks and what not.\n if (hashCompareWithLengthCheck(bytes(\"1\"), result)) {\n revert(\"failed executeOperation\");\n }\n }\n\n function hashCompareWithLengthCheck(bytes memory a, bytes memory b)\n internal\n pure\n returns (bool)\n {\n if (a.length != b.length) {\n return false;\n } else {\n return keccak256(a) == keccak256(b);\n }\n }\n\n event ExecuteOperation(address loanToken, address iToken, uint256 loanAmount);\n\n event BalanceOf(uint256 balance);\n}\n" + }, + "contracts/testhelpers/interfaces/IERC1820Registry.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the global ERC1820 Registry, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register\n * implementers for interfaces in this registry, as well as query support.\n *\n * Implementers may be shared by multiple accounts, and can also implement more\n * than a single interface for each account. Contracts can implement interfaces\n * for themselves, but externally-owned accounts (EOA) must delegate this to a\n * contract.\n *\n * {IERC165} interfaces can also be queried via the registry.\n *\n * For an in-depth explanation and source code analysis, see the EIP text.\n */\ninterface IERC1820Registry {\n /**\n * @dev Sets `newManager` as the manager for `account`. A manager of an\n * account is able to set interface implementers for it.\n *\n * By default, each account is its own manager. Passing a value of `0x0` in\n * `newManager` will reset the manager to this initial state.\n *\n * Emits a {ManagerChanged} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n */\n function setManager(address account, address newManager) external;\n\n /**\n * @dev Returns the manager for `account`.\n *\n * See {setManager}.\n */\n function getManager(address account) external view returns (address);\n\n /**\n * @dev Sets the `implementer` contract as `account`'s implementer for\n * `interfaceHash`.\n *\n * `account` being the zero address is an alias for the caller's address.\n * The zero address can also be used in `implementer` to remove an old one.\n *\n * See {interfaceHash} to learn how these are created.\n *\n * Emits an {InterfaceImplementerSet} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not\n * end in 28 zeroes).\n * - `implementer` must implement {IERC1820Implementer} and return true when\n * queried for support, unless `implementer` is the caller. See\n * {IERC1820Implementer-canImplementInterfaceForAddress}.\n */\n function setInterfaceImplementer(\n address account,\n bytes32 interfaceHash,\n address implementer\n ) external;\n\n /**\n * @dev Returns the implementer of `interfaceHash` for `account`. If no such\n * implementer is registered, returns the zero address.\n *\n * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28\n * zeroes), `account` will be queried for support of it.\n *\n * `account` being the zero address is an alias for the caller's address.\n */\n function getInterfaceImplementer(address account, bytes32 interfaceHash)\n external\n view\n returns (address);\n\n /**\n * @dev Returns the interface hash for an `interfaceName`, as defined in the\n * corresponding\n * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].\n */\n function interfaceHash(string calldata interfaceName) external pure returns (bytes32);\n\n /**\n * @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n * @param account Address of the contract for which to update the cache.\n * @param interfaceId ERC165 interface for which to update the cache.\n */\n function updateERC165Cache(address account, bytes4 interfaceId) external;\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not.\n * If the result is not cached a direct lookup on the contract address is performed.\n * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n * {updateERC165Cache} with the contract address.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165Interface(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n event InterfaceImplementerSet(\n address indexed account,\n bytes32 indexed interfaceHash,\n address indexed implementer\n );\n\n event ManagerChanged(address indexed account, address indexed newManager);\n}\n" + }, + "contracts/testhelpers/ITokenFlashLoanTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n// \"SPDX-License-Identifier: Apache-2.0\"\n\ninterface ITokenFlashLoanTest {\n function flashBorrow(\n uint256 borrowAmount,\n address borrower,\n address target,\n string calldata signature,\n bytes calldata data\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/testhelpers/LoanTokenLogicTest.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicTest is LoanTokenLogic {\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestNonReentrantValueSetter.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\ncontract TestNonReentrantValueSetter is SharedReentrancyGuard {\n uint256 public value;\n\n // This will fail if another globallyNonReentrant function has already been entered\n function setValue(uint256 newValue) public globallyNonReentrant {\n value = newValue;\n }\n\n // this will always fail if `other.setValue` is globallyNonReentrant\n function setOtherContractValueNonReentrant(address other, uint256 newValue)\n external\n globallyNonReentrant\n {\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n\n // this is intentionally not globallyNonReentrant and should work even if both contracts are non-reentrant\n function setThisAndOtherContractValue(address other, uint256 newValue) external {\n setValue(newValue);\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestValueSetterProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract TestValueSetterProxy is UpgradableProxy {\n // This is here for the memory layout\n uint256 public value;\n}\n" + }, + "contracts/testhelpers/staking/StakingTester.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../TestToken.sol\";\n\ncontract StakingTester {\n IStaking public staking;\n TestToken public token;\n\n constructor(address _staking, address _token) public {\n staking = IStaking(_staking);\n token = TestToken(_token);\n }\n\n function stakeAndWithdraw(uint96 _amount, uint256 _until) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _until, address(this), address(this));\n staking.withdraw(_amount, _until, address(this));\n }\n\n function stakeAndDelegate(\n uint96 _amount,\n address _delegatee,\n uint256 _lockDate\n ) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _lockDate, address(this), address(this));\n staking.delegate(_delegatee, _lockDate);\n }\n}\n" + }, + "contracts/testhelpers/TestCoverage.sol": { + "content": "/**\n * In order to test some functionalities like Pausable::pausable() modifier,\n * it is required to add a contract to invoke them and get a full coverage on tests.\n */\n\npragma solidity 0.5.17;\n\nimport \"../connectors/loantoken/Pausable.sol\";\nimport \"../governance/Staking/SafeMath96.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../connectors/loantoken/AdvancedToken.sol\";\nimport \"../connectors/loantoken/LoanTokenLogicStorage.sol\";\n\ncontract TestCoverage is\n Pausable,\n SafeMath96,\n VaultController,\n AdvancedToken,\n LoanTokenLogicStorage\n{\n /// @dev Pausable is currently an unused contract that still is operative\n /// because margin trade flashloan functionality has been commented out.\n /// In case it were restored, contract would become used again, so for a\n /// complete test coverage it is required to test it.\n\n function dummyPausableFunction() external pausable(msg.sig) {\n /// @dev do nothing, just to check if modifier is working\n }\n\n /// @dev This function should be located on Pausable contract in the case\n /// it has to be used again by flashloan restoration.\n function togglePause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047)\n )\n );\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /// @dev Testing internal functions of governance/Staking/SafeMath96.sol\n function testSafeMath96_safe32(uint256 n) public pure returns (uint32) {\n // Public wrapper for SafeMath96 internal function\n return safe32(n, \"overflow\");\n }\n\n function testSafeMath96_safe64(uint256 n) public pure returns (uint64) {\n // Public wrapper for SafeMath96 internal function\n return safe64(n, \"overflow\");\n }\n\n function testSafeMath96_safe96(uint256 n) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return safe96(n, \"overflow\");\n }\n\n function testSafeMath96_sub96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return sub96(a, b, \"underflow\");\n }\n\n function testSafeMath96_mul96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return mul96(a, b, \"overflow\");\n }\n\n function testSafeMath96_div96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return div96(a, b, \"division by 0\");\n }\n\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;\n EnumerableBytes32Set.Bytes32Set internal aSet;\n\n function testEnum_AddRemove(bytes32 a, bytes32 b) public returns (bool) {\n aSet.addBytes32(a);\n return aSet.removeBytes32(b);\n }\n\n function testEnum_AddAddress(address a, address b) public returns (bool) {\n aSet.addAddress(a);\n return aSet.containsAddress(b);\n }\n\n function testEnum_AddAddressesAndEnumerate(\n address a,\n address b,\n uint256 start,\n uint256 count\n ) public returns (bytes32[] memory) {\n aSet.addAddress(a);\n aSet.addAddress(b);\n return aSet.enumerate(start, count);\n }\n\n /// @dev Wrapper to test internal function never called along current codebase\n function testVaultController_vaultApprove(\n address token,\n address to,\n uint256 value\n ) public {\n vaultApprove(token, to, value);\n }\n\n /// @dev mint wrapper w/o previous checks\n function testMint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) public {\n _mint(_to, _tokenAmount, _assetAmount, _price);\n }\n\n /// @dev wrapper for a function unreachable to tests\n function testStringToBytes32(string memory source) public pure returns (bytes32 result) {\n return stringToBytes32(source);\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some ERC777 from the lending pool.\n * 2. Close the loan with closeWithDeposit function in the protocol.\n * 3. Burn all iERC777.\n *\n * The cross-reentrancy happened in step#3. It might happened through a hook function (tokensToSend) that is implemented in this contract to support the ERC777 transfer.\n * Inside the hook function, it will try to mint the iERC777.\n * The details about the hook functions can be found here: https://eips.ethereum.org/EIPS/eip-777#hooks\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithDeposit function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyERC777 {\n address public loanToken;\n address public WRBTC;\n address public SUSD; /// ERC777\n ProtocolLike public sovrynProtocol;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iUSDTBalance;\n }\n\n function() external payable {}\n\n constructor(\n address _loanToken,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanToken = _loanToken;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777TokensSender\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: WRBTC has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n });\n\n IERC20(WRBTC).approve(loanToken, initial.susdBalance);\n\n ILoanTokenModules(loanToken).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n WRBTC,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanToken).loanParamsIds(\n uint256(keccak256(abi.encodePacked(WRBTC, true)))\n );\n bytes32 loan_id =\n keccak256(abi.encodePacked(loanParamsLocalId, loanToken, _borrower, _borrowerNonce));\n\n // STEP 3 close the borrowed position with a deposit\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(address(sovrynProtocol), _SUSDBalance);\n sovrynProtocol.closeWithDeposit(\n loan_id,\n address(this),\n collateralTokenSent.mul(20).div(100) // make it 20% higher from initial borrow amount\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iSUSD\n uint256 _iSUSDBalance = ILoanTokenModules(loanToken).balanceOf(_borrower);\n ILoanTokenModules(loanToken).burn(_receiver, _iSUSDBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n // });\n }\n\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256,\n bytes calldata,\n bytes calldata\n ) external {\n if (operator == address(sovrynProtocol) && to == loanToken && from == address(this)) {\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(loanToken, _SUSDBalance);\n\n ILoanTokenModules(loanToken).mint(address(this), 1000000 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyRBTC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some WRBTC from the lending pool.\n * 2. Close the loan with closeWithSwap function in the protocol.\n * 3. Burn all iWRBTC.\n *\n * The refund happened in step #3, which will send back the RBTC back to this contract.\n * Then, this contract will try to do another iWRBTC minting to the loan token --> this is where the cross-reentrancy happened between the protocol & the loan token contract.\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithSwap function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyRBTC {\n address public loanTokenWRBTC;\n address public WRBTC;\n address public SUSD;\n ProtocolLike public sovrynProtocol;\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iWRBTCBalance;\n }\n\n function() external payable {\n if (msg.sender == address(sovrynProtocol)) {\n uint256 latestRBTCBalance = address(this).balance;\n IWrbtcERC20(WRBTC).deposit.value(14 ether)();\n uint256 _WRBTCBalance = IERC20(WRBTC).balanceOf(address(this));\n IERC20(WRBTC).approve(loanTokenWRBTC, _WRBTCBalance);\n\n ILoanTokenModules(loanTokenWRBTC).mint(address(this), 14 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n\n constructor(\n address _loanTokenWRBTC,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanTokenWRBTC = _loanTokenWRBTC;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: SUSD has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n });\n\n IERC20(SUSD).approve(loanTokenWRBTC, initial.susdBalance);\n\n ILoanTokenModules(loanTokenWRBTC).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n SUSD,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanTokenWRBTC).loanParamsIds(\n uint256(keccak256(abi.encodePacked(SUSD, true)))\n );\n bytes32 loan_id =\n keccak256(\n abi.encodePacked(loanParamsLocalId, loanTokenWRBTC, _borrower, _borrowerNonce)\n );\n\n // STEP 3 close the borrowed position with a swap (probably works just as well with deposit)\n sovrynProtocol.closeWithSwap(\n loan_id,\n msg.sender,\n collateralTokenSent.mul(200).div(100), // make it 20% higher from initial collateral sent to make sure whole position is closed\n true,\n \"\"\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iRBTC\n uint256 _iWRBTCBalance = ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower);\n ILoanTokenModules(loanTokenWRBTC).burn(_receiver, _iWRBTCBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n // });\n }\n}\n" + }, + "contracts/testhelpers/TestLibraries.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../rsk/RSKAddrValidator.sol\";\n\n// contract for testing libraries\ncontract TestLibraries {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n */\n function RSKAddrValidator_checkPKNotZero(address addr) public pure returns (bool) {\n return (RSKAddrValidator.checkPKNotZero(addr));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key\n */\n function RSKAddrValidator_safeEquals(address addr1, address addr2) public pure returns (bool) {\n return (RSKAddrValidator.safeEquals(addr1, addr2));\n }\n}\n" + }, + "contracts/testhelpers/TestSovrynSwap.sol": { + "content": "/**\n * Test file simulating the SovrynSwap network\n * */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"./TestToken.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestSovrynSwap {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n address public priceFeeds;\n\n constructor(address feed) public {\n priceFeeds = feed;\n }\n\n /**\n * simulating the contract registry. always returns the address of this contract\n * */\n function addressOf(bytes32 contractName) public view returns (address) {\n return address(this);\n }\n\n /**\n * calculates the return tokens when swapping _amount, makes sure the return is bigger than _minReturn,\n * mints and burns the test tokens accordingly.\n * */\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256) {\n //compute the return for the amount of tokens provided\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n uint256 actualReturn = _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n\n require(actualReturn >= _minReturn, \"insufficient source tokens provided\");\n\n TestToken(address(_path[0])).burn(address(msg.sender), _amount);\n TestToken(address(_path[1])).mint(address(_beneficiary), actualReturn);\n return actualReturn;\n }\n\n /**\n * queries the rate from the Price Feed contract and computes the expected return amount based on the\n * amout of source tokens to be swapped.\n * */\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n\n return _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * returns the conversion path -> always a direct path\n * */\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory)\n {\n IERC20[] memory path = new IERC20[](2);\n path[0] = _sourceToken;\n path[1] = _targetToken;\n return path;\n }\n}\n" + }, + "contracts/testhelpers/TestToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestToken {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balances[_who], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[_who] = balances[_who].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(_who, _value);\n emit Transfer(_who, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/testhelpers/TestTokenERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Context.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../interfaces/IERC777.sol\";\nimport \"../interfaces/IERC777Recipient.sol\";\nimport \"../interfaces/IERC777Sender.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\n\ncontract TestTokenERC777 is Context, IERC777, IERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n mapping(address => uint256) private _balances;\n\n uint256 private _totalSupply;\n\n // We inline the result of the following hashes because Solidity doesn't resolve them at compile time.\n // See https://github.com/ethereum/solidity/issues/4024.\n\n // keccak256(\"ERC777TokensSender\")\n bytes32 private constant TOKENS_SENDER_INTERFACE_HASH =\n 0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895;\n\n // keccak256(\"ERC777TokensRecipient\")\n bytes32 private constant TOKENS_RECIPIENT_INTERFACE_HASH =\n 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;\n\n // This isn't ever read from - it's only used to respond to the defaultOperators query.\n address[] private _defaultOperatorsArray;\n\n // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).\n mapping(address => bool) private _defaultOperators;\n\n // For each account, a mapping of its operators and revoked default operators.\n mapping(address => mapping(address => bool)) private _operators;\n mapping(address => mapping(address => bool)) private _revokedDefaultOperators;\n\n // ERC20-allowances\n mapping(address => mapping(address => uint256)) private _allowances;\n\n /**\n * @dev `defaultOperators` may be an empty array.\n */\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _initialSupply,\n uint8 _decimals,\n address[] memory defaultOperators\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n _defaultOperatorsArray = defaultOperators;\n for (uint256 i = 0; i < _defaultOperatorsArray.length; i++) {\n _defaultOperators[_defaultOperatorsArray[i]] = true;\n }\n\n _mint(msg.sender, msg.sender, _initialSupply, \"\", \"\");\n\n // register interfaces\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777Token\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n /**\n * @dev See {IERC777-granularity}.\n *\n * This implementation always returns `1`.\n */\n function granularity() public view returns (uint256) {\n return 1;\n }\n\n /**\n * @dev See {IERC777-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev Returns the amount of tokens owned by an account (`tokenHolder`).\n */\n function balanceOf(address tokenHolder) public view returns (uint256) {\n return _balances[tokenHolder];\n }\n\n /**\n * @dev See {IERC777-send}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes memory data\n ) public {\n _send(_msgSender(), _msgSender(), recipient, amount, data, \"\", true);\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient}\n * interface if it is a contract.\n *\n * Also emits a {Sent} event.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n\n address from = _msgSender();\n\n _callTokensToSend(from, from, recipient, amount, \"\", \"\");\n\n _move(from, from, recipient, amount, \"\", \"\");\n\n _callTokensReceived(from, from, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev See {IERC777-burn}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function burn(uint256 amount, bytes memory data) public {\n _burn(_msgSender(), _msgSender(), amount, data, \"\");\n }\n\n /**\n * @dev See {IERC777-isOperatorFor}.\n */\n function isOperatorFor(address operator, address tokenHolder) public view returns (bool) {\n return\n operator == tokenHolder ||\n (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||\n _operators[tokenHolder][operator];\n }\n\n /**\n * @dev See {IERC777-authorizeOperator}.\n */\n function authorizeOperator(address operator) public {\n require(_msgSender() != operator, \"ERC777: authorizing self as operator\");\n\n if (_defaultOperators[operator]) {\n delete _revokedDefaultOperators[_msgSender()][operator];\n } else {\n _operators[_msgSender()][operator] = true;\n }\n\n emit AuthorizedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-revokeOperator}.\n */\n function revokeOperator(address operator) public {\n require(operator != _msgSender(), \"ERC777: revoking self as operator\");\n\n if (_defaultOperators[operator]) {\n _revokedDefaultOperators[_msgSender()][operator] = true;\n } else {\n delete _operators[_msgSender()][operator];\n }\n\n emit RevokedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-defaultOperators}.\n */\n function defaultOperators() public view returns (address[] memory) {\n return _defaultOperatorsArray;\n }\n\n /**\n * @dev See {IERC777-operatorSend}.\n *\n * Emits {Sent} and {IERC20-Transfer} events.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), sender),\n \"ERC777: caller is not an operator for holder\"\n );\n _send(_msgSender(), sender, recipient, amount, data, operatorData, true);\n }\n\n /**\n * @dev See {IERC777-operatorBurn}.\n *\n * Emits {Burned} and {IERC20-Transfer} events.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), account),\n \"ERC777: caller is not an operator for holder\"\n );\n _burn(_msgSender(), account, amount, data, operatorData);\n }\n\n /**\n * @dev See {IERC20-allowance}.\n *\n * Note that operator and allowance concepts are orthogonal: operators may\n * not have allowance, and accounts with allowance may not be operators\n * themselves.\n */\n function allowance(address holder, address spender) public view returns (uint256) {\n return _allowances[holder][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Note that accounts cannot have allowance issued by their operators.\n */\n function approve(address spender, uint256 value) public returns (bool) {\n address holder = _msgSender();\n _approve(holder, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Note that operator and allowance concepts are orthogonal: operators cannot\n * call `transferFrom` (unless they have allowance), and accounts with\n * allowance cannot call `operatorSend` (unless they are operators).\n *\n * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.\n */\n function transferFrom(\n address holder,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n require(holder != address(0), \"ERC777: transfer from the zero address\");\n\n address spender = _msgSender();\n\n _callTokensToSend(spender, holder, recipient, amount, \"\", \"\");\n\n _move(spender, holder, recipient, amount, \"\", \"\");\n\n _approve(\n holder,\n spender,\n _allowances[holder][spender].sub(amount, \"ERC777: transfer amount exceeds allowance\")\n );\n\n _callTokensReceived(spender, holder, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `operator`, `data` and `operatorData`.\n *\n * See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits {Minted} and {IERC20-Transfer} events.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - if `account` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function _mint(\n address operator,\n address account,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n require(account != address(0), \"ERC777: mint to the zero address\");\n\n // Update state variables\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n\n _callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);\n\n emit Minted(operator, account, amount, userData, operatorData);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Send tokens\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _send(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n require(from != address(0), \"ERC777: send from the zero address\");\n require(to != address(0), \"ERC777: send to the zero address\");\n\n _callTokensToSend(operator, from, to, amount, userData, operatorData);\n\n _move(operator, from, to, amount, userData, operatorData);\n\n _callTokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData,\n requireReceptionAck\n );\n }\n\n /**\n * @dev Burn tokens\n * @param operator address operator requesting the operation\n * @param from address token holder address\n * @param amount uint256 amount of tokens to burn\n * @param data bytes extra information provided by the token holder\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _burn(\n address operator,\n address from,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) internal {\n require(from != address(0), \"ERC777: burn from the zero address\");\n\n _callTokensToSend(operator, from, address(0), amount, data, operatorData);\n\n // Update state variables\n _balances[from] = _balances[from].sub(amount, \"ERC777: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n\n emit Burned(operator, from, amount, data, operatorData);\n emit Transfer(from, address(0), amount);\n }\n\n function _move(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) private {\n _balances[from] = _balances[from].sub(amount, \"ERC777: transfer amount exceeds balance\");\n _balances[to] = _balances[to].add(amount);\n\n emit Sent(operator, from, to, amount, userData, operatorData);\n emit Transfer(from, to, amount);\n }\n\n function _approve(\n address holder,\n address spender,\n uint256 value\n ) internal {\n // TODO: restore this require statement if this function becomes internal, or is called at a new callsite. It is\n // currently unnecessary.\n //require(holder != address(0), \"ERC777: approve from the zero address\");\n require(spender != address(0), \"ERC777: approve to the zero address\");\n\n _allowances[holder][spender] = value;\n emit Approval(holder, spender, value);\n }\n\n /**\n * @dev Call from.tokensToSend() if the interface is registered\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _callTokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Sender(implementer).tokensToSend(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n }\n }\n\n /**\n * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but\n * tokensReceived() was not registered for the recipient\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _callTokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Recipient(implementer).tokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n } else if (requireReceptionAck) {\n require(\n !to.isContract(),\n \"ERC777: token recipient contract has no implementer for ERC777TokensRecipient\"\n );\n }\n }\n\n function mint(address _to, uint256 _value) public {\n // Update state variables\n _totalSupply = _totalSupply.add(_value);\n _balances[_to] = _balances[_to].add(_value);\n\n emit Minted(msg.sender, _to, _value, \"\", \"\");\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balanceOf(_who), \"balance too low\");\n\n _burn(msg.sender, _who, _value, \"\", \"\");\n }\n}\n" + }, + "contracts/testhelpers/TestTokenLimited.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestTokenLimited {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n require(_value <= 100000 ether, \"max mint amount exceeded\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(uint256 _value) public {\n require(_value <= balances[msg.sender], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(msg.sender, _value);\n emit Transfer(msg.sender, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/token/IApproveAndCall.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/ApprovalReceiver.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IApproveAndCall {\n /**\n * @notice Receives approval from SOV token.\n * @param _sender The sender of SOV.approveAndCall function.\n * @param _amount The amount was approved.\n * @param _token The address of token.\n * @param _data The data will be used for low level call.\n * */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/token/SOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/ERC20Detailed.sol\";\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./IApproveAndCall.sol\";\n\n/**\n * @title Sovryn Token: SOV is an ERC-20 token contract for Sovryn governance.\n *\n * @notice This contract accounts for all holders' balances.\n *\n * @dev This contract represents a token with dynamic supply.\n * The owner of the token contract can mint/burn tokens to/from any account\n * based upon previous governance voting and approval.\n * */\ncontract SOV is ERC20, ERC20Detailed, Ownable {\n string constant NAME = \"Sovryn Token\";\n string constant SYMBOL = \"SOV\";\n uint8 constant DECIMALS = 18;\n\n /**\n * @notice Constructor called on deployment, initiates the contract.\n * @dev On deployment, some amount of tokens will be minted for the owner.\n * @param _initialAmount The amount of tokens to be minted on contract creation.\n * */\n constructor(uint256 _initialAmount) public ERC20Detailed(NAME, SYMBOL, DECIMALS) {\n if (_initialAmount != 0) {\n _mint(msg.sender, _initialAmount);\n }\n }\n\n /**\n * @notice Creates new tokens and sends them to the recipient.\n * @dev Don't create more than 2^96/10 tokens before updating the governance first.\n * @param _account The recipient address to get the minted tokens.\n * @param _amount The amount of tokens to be minted.\n * */\n function mint(address _account, uint256 _amount) public onlyOwner {\n _mint(_account, _amount);\n }\n\n /**\n * @notice Approves and then calls the receiving contract.\n * Useful to encapsulate sending tokens to a contract in one call.\n * Solidity has no native way to send tokens to contracts.\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\n * @param _spender The contract address to spend the tokens.\n * @param _amount The amount of tokens to be sent.\n * @param _data Parameters for the contract call, such as endpoint signature.\n * */\n function approveAndCall(\n address _spender,\n uint256 _amount,\n bytes memory _data\n ) public {\n approve(_spender, _amount);\n IApproveAndCall(_spender).receiveApproval(msg.sender, _amount, address(this), _data);\n }\n}\n" + }, + "contracts/utils/AdminRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\n\ncontract AdminRole is Ownable {\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * or on our own overriding sovrynOwnable.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n}\n" + }, + "contracts/utils/PausableRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/PausableOz.sol\";\n\ncontract PausableRole is PausableOz {\n address public pauser;\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n\n /**\n * @dev Modifier to make a function callable only when the caller is pauser or owner\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"Pausable: unauthorized\"); // SS02\n _;\n }\n\n /**\n * @notice Set the pauser address.\n *\n * only pauser can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyPauserOrOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyPauserOrOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/utils/ProxyOwnable.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\n/**\n * Based on OpenZeppelin's Ownable contract:\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\n *\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract ProxyOwnable {\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Ownable:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"ProxyOwnable::setProxyOwner: invalid address\");\n emit ProxyOwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Set address of the owner (only owner can call this function)\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n\n /**\n * @notice Return address of the owner.\n * @return _owner Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n}\n" + }, + "contracts/utils/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\nlibrary Utils {\n function stringToBytes32(string memory source) internal pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + }, + "remappings": [] + } +} \ No newline at end of file diff --git a/deployment/deployments/rskSovrynTestnet/solcInputs/a007dc3b696b2fbb46f7704420ad9de4.json b/deployment/deployments/rskSovrynTestnet/solcInputs/a007dc3b696b2fbb46f7704420ad9de4.json new file mode 100644 index 000000000..9e7a830cb --- /dev/null +++ b/deployment/deployments/rskSovrynTestnet/solcInputs/a007dc3b696b2fbb46f7704420ad9de4.json @@ -0,0 +1,708 @@ +{ + "language": "Solidity", + "sources": { + "contracts/connectors/loantoken/AdvancedToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Advanced Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedToken implements standard ERC-20 approval, mint and burn token functionality.\n * Logic (AdvancedToken) is kept aside from storage (AdvancedTokenStorage).\n *\n * For example, LoanTokenLogicDai contract uses AdvancedToken::_mint() to mint\n * its Loan Dai iTokens.\n * */\ncontract AdvancedToken is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n /**\n * @notice Set an amount as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n *\n * @param _spender The account address that will be able to spend the tokens.\n * @param _value The amount of tokens allowed to spend.\n * */\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @notice The iToken minting process. Meant to issue Loan iTokens.\n * Lenders are able to open an iToken position, by minting them.\n * This function is called by LoanTokenLogicStandard::_mintToken\n * @param _to The recipient of the minted tTokens.\n * @param _tokenAmount The amount of iTokens to be minted.\n * @param _assetAmount The amount of lended tokens (asset to lend).\n * @param _price The price of the lended tokens.\n * @return The updated balance of the recipient.\n * */\n function _mint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n require(_to != address(0), \"15\");\n\n uint256 _balance = balances[_to].add(_tokenAmount);\n balances[_to] = _balance;\n\n totalSupply_ = totalSupply_.add(_tokenAmount);\n\n emit Mint(_to, _tokenAmount, _assetAmount, _price);\n emit Transfer(address(0), _to, _tokenAmount);\n\n return _balance;\n }\n\n /**\n * @notice The iToken burning process. Meant to destroy Loan iTokens.\n * Lenders are able to close an iToken position, by burning them.\n * This function is called by LoanTokenLogicStandard::_burnToken\n * @param _who The owner of the iTokens to burn.\n * @param _tokenAmount The amount of iTokens to burn.\n * @param _assetAmount The amount of lended tokens.\n * @param _price The price of the lended tokens.\n * @return The updated balance of the iTokens owner.\n * */\n function _burn(\n address _who,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n //bzx compare\n //TODO: Unit test\n uint256 _balance = balances[_who].sub(_tokenAmount, \"16\");\n\n // a rounding error may leave dust behind, so we clear this out\n if (_balance <= 10) {\n // We can't leave such small balance quantities.\n _tokenAmount = _tokenAmount.add(_balance);\n _balance = 0;\n }\n balances[_who] = _balance;\n\n totalSupply_ = totalSupply_.sub(_tokenAmount);\n\n emit Burn(_who, _tokenAmount, _assetAmount, _price);\n emit Transfer(_who, address(0), _tokenAmount);\n return _balance;\n }\n}\n" + }, + "contracts/connectors/loantoken/AdvancedTokenStorage.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./LoanTokenBase.sol\";\n\n/**\n * @title Advanced Token Storage contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedTokenStorage implements standard ERC-20 getters functionality:\n * totalSupply, balanceOf, allowance and some events.\n * iToken logic is divided into several contracts AdvancedToken,\n * AdvancedTokenStorage and LoanTokenBase.\n * */\ncontract AdvancedTokenStorage is LoanTokenBase {\n using SafeMath for uint256;\n\n /* Events */\n\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /* Storage */\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n /* Functions */\n\n /**\n * @notice Get the total supply of iTokens.\n * @return The total number of iTokens in existence as of now.\n * */\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n /**\n * @notice Get the amount of iTokens owned by an account.\n * @param _owner The account owner of the iTokens.\n * @return The number of iTokens an account owns.\n * */\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n /**\n * @notice Get the amount of iTokens allowed to be spent by a\n * given account on behalf of the owner.\n * @param _owner The account owner of the iTokens.\n * @param _spender The account allowed to send the iTokens.\n * @return The number of iTokens an account is allowing the spender\n * to send on its behalf.\n * */\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/connectors/loantoken/interfaces/FeedsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface FeedsLike {\n function queryRate(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 rate, uint256 precision);\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../lib/MarginTradeStructHelpers.sol\";\n\ninterface ProtocolLike {\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function priceFeeds() external view returns (address);\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function lendingFeePercent() external view returns (uint256);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function borrowerNonce(address) external view returns (uint256);\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata // for future use /*loanDataBytes*/\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolSettingsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../core/objects/LoanParamsStruct.sol\";\n\ninterface ProtocolSettingsLike {\n function setupLoanParams(LoanParamsStruct.LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n}\n" + }, + "contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol": { + "content": "pragma solidity 0.5.17;\n\nlibrary MarginTradeStructHelpers {\n struct SentAddresses {\n address lender;\n address borrower;\n address receiver;\n address manager;\n }\n\n struct SentAmounts {\n uint256 interestRate;\n uint256 newPrincipal;\n uint256 interestInitialAmount;\n uint256 loanTokenSent;\n uint256 collateralTokenSent;\n uint256 minEntryPrice;\n uint256 loanToCollateralSwapRate;\n uint256 interestDuration;\n uint256 entryLeverage;\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Loan Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * A loan token (iToken) is created as a proxy to an upgradable token contract.\n *\n * Examples of loan tokens on Sovryn are iRBTC, iDOC, iUSDT, iBPro,\n * iSOV (near future).\n *\n * Lenders receive iTokens that collect interest from the lending pool\n * which they can redeem by withdrawing them. The i in iToken stands for interest.\n *\n * Do not confuse iTokens with underlying tokens. iDOC is an iToken (loan token)\n * whilest DOC is the underlying token (currency).\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\n * */\ncontract LoanToken is AdvancedTokenStorage {\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n address public admin;\n\n /**\n * @notice Deploy loan token proxy.\n * Sets ERC20 parameters of the token.\n *\n * @param _newOwner The address of the new owner.\n * @param _newTarget The address of the new target contract instance.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice Public owner setter for target address.\n * @dev Calls internal setter.\n * @param _newTarget The address of the new target contract instance.\n * */\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n /**\n * @notice Internal setter for target address.\n * @param _newTarget The address of the new target contract instance.\n * */\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n /**\n * @notice Internal setter for sovrynContract address.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * */\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n /**\n * @notice Internal setter for wrBTC address.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n /**\n * @notice Public owner cloner for pointed loan token.\n * Sets ERC20 parameters of the token.\n *\n * @dev TODO: add check for double init.\n * idk but init usually can be called only once.\n *\n * @param _loanTokenAddress The address of the pointed loan token instance.\n * @param _name The ERC20 token name.\n * @param _symbol The ERC20 token symbol.\n * */\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; /// starting price of 1\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenBase.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SignedSafeMath.sol\";\nimport \"../../openzeppelin/ReentrancyGuard.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\nimport \"./Pausable.sol\";\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title Loan Token Base contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Specific loan related storage for iTokens.\n *\n * An loan token or iToken is a representation of a user funds in the pool and the\n * interest they've earned. The redemption value of iTokens continually increase\n * from the accretion of interest paid into the lending pool by borrowers. The user\n * can sell iTokens to exit its position. The user might potentially use them as\n * collateral wherever applicable.\n *\n * There are three main tokens in the bZx system, iTokens, pTokens, and BZRX tokens.\n * The bZx system of lending and borrowing depends on iTokens and pTokens, and when\n * users lend or borrow money on bZx, their crypto assets go into or come out of\n * global liquidity pools, which are pools of funds shared between many different\n * exchanges. When lenders supply funds into the global liquidity pools, they\n * automatically receive iTokens; When users borrow money to open margin trading\n * positions, they automatically receive pTokens. The system is also designed to\n * use the BZRX tokens, which are only used to pay fees on the network currently.\n * */\ncontract LoanTokenBase is ReentrancyGuard, SharedReentrancyGuard, Ownable, Pausable {\n uint256 internal constant WEI_PRECISION = 10**18;\n uint256 internal constant WEI_PERCENT_PRECISION = 10**20;\n\n int256 internal constant sWEI_PRECISION = 10**18;\n\n /// @notice Standard ERC-20 properties\n string public name;\n string public symbol;\n uint8 public decimals;\n\n /// @notice The address of the loan token (asset to lend) instance.\n address public loanTokenAddress;\n\n uint256 public baseRate;\n uint256 public rateMultiplier;\n uint256 public lowUtilBaseRate;\n uint256 public lowUtilRateMultiplier;\n\n uint256 public targetLevel;\n uint256 public kinkLevel;\n uint256 public maxScaleRate;\n\n uint256 internal _flTotalAssetSupply;\n uint256 public checkpointSupply;\n uint256 public initialPrice;\n\n /// uint88 for tight packing -> 8 + 88 + 160 = 256\n uint88 internal lastSettleTime_;\n\n /// Mapping of keccak256(collateralToken, isTorqueLoan) to loanParamsId.\n mapping(uint256 => bytes32) public loanParamsIds;\n\n /// Price of token at last user checkpoint.\n mapping(address => uint256) internal checkpointPrices_;\n\n // the maximum trading/borrowing/lending limit per token address\n mapping(address => uint256) public transactionLimit;\n // 0 -> no limit\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicBeacon.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../mixins/EnumerableBytes32Set.sol\";\nimport \"../../mixins/EnumerableBytes4Set.sol\";\nimport \"../../utils/PausableRole.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Loan Token Logic Beacon contract.\n *\n * @notice This contract stored the target logic implementation of LoanTokens which has the same logic implementation (LoanTokenLogicLM / LoanTokenLogicWrbtc)\n * Apart from storing the target logic implementation, this contract also has a pause functionality.\n * By implementing pause/unpause functionality in this beacon contract, we can pause the loan token that has the same Logic (LoanTokenLogicLM / LoanTokenLogicWrbtc) at one call.\n * Meanwhile the pause/unpause function in the LoanTokenLogicProxy is used to pause/unpause specific LoanToken\n */\n\ncontract LoanTokenLogicBeacon is PausableRole {\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; // enumerable map of bytes4 or addresses\n\n mapping(bytes4 => address) private logicTargets;\n\n struct LoanTokenLogicModuleUpdate {\n address implementation; // address implementaion of the module\n uint256 updateTimestamp; // time of update\n }\n\n mapping(bytes32 => LoanTokenLogicModuleUpdate[]) public moduleUpgradeLog; /** the module name as the key */\n\n mapping(bytes32 => uint256) public activeModuleIndex; /** To store the current active index log for module */\n\n mapping(bytes32 => EnumerableBytes4Set.Bytes4Set) private activeFuncSignatureList; /** Store the current active function signature */\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n * This is the overriden function from the pausable contract, so that we can use custom error message.\n */\n modifier whenNotPaused() {\n require(!_paused, \"LoanTokenLogicBeacon:paused mode\");\n _;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This function will store the updated protocol module to the storage (For rollback purposes)\n *\n * @param loanTokenModuleAddress The module target address\n */\n function registerLoanTokenModule(address loanTokenModuleAddress) external onlyOwner {\n bytes32 moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n\n // Store the upgrade to the log\n moduleUpgradeLog[moduleName].push(\n LoanTokenLogicModuleUpdate(loanTokenModuleAddress, block.timestamp)\n );\n activeModuleIndex[moduleName] = moduleUpgradeLog[moduleName].length - 1;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This registration will require target contract to have the exact function getListFunctionSignatures() which will return functionSignatureList and the moduleName in bytes32\n *\n * @param loanTokenModuleAddress the target logic of the loan token module\n *\n * @return the module name\n */\n function _registerLoanTokenModule(address loanTokenModuleAddress) private returns (bytes32) {\n require(\n Address.isContract(loanTokenModuleAddress),\n \"LoanTokenModuleAddress is not a contract\"\n );\n\n // Get the list of function signature on this loanTokenModulesAddress\n (bytes4[] memory functionSignatureList, bytes32 moduleName) =\n ILoanTokenLogicModules(loanTokenModuleAddress).getListFunctionSignatures();\n\n /// register / update the module function signature address implementation\n for (uint256 i; i < functionSignatureList.length; i++) {\n require(functionSignatureList[i] != bytes4(0x0), \"ERR_EMPTY_FUNC_SIGNATURE\");\n logicTargets[functionSignatureList[i]] = loanTokenModuleAddress;\n if (!activeFuncSignatureList[moduleName].contains(functionSignatureList[i]))\n activeFuncSignatureList[moduleName].addBytes4(functionSignatureList[i]);\n }\n\n /// delete the \"removed\" module function signature in the current implementation\n bytes4[] memory activeSignatureListEnum =\n activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n for (uint256 i; i < activeSignatureListEnum.length; i++) {\n bytes4 activeSigBytes = activeSignatureListEnum[i];\n if (logicTargets[activeSigBytes] != loanTokenModuleAddress) {\n logicTargets[activeSigBytes] = address(0);\n activeFuncSignatureList[moduleName].removeBytes4(activeSigBytes);\n }\n }\n\n return moduleName;\n }\n\n /**\n * @dev get all active function signature list based on the module name.\n *\n * @param moduleName in bytes32.\n *\n * @return the array of function signature.\n */\n function getActiveFuncSignatureList(bytes32 moduleName)\n public\n view\n returns (bytes4[] memory signatureList)\n {\n signatureList = activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n return signatureList;\n }\n\n /**\n * @dev Get total length of the module upgrade log.\n *\n * @param moduleName in bytes32.\n *\n * @return length of module upgrade log.\n */\n function getModuleUpgradeLogLength(bytes32 moduleName) external view returns (uint256) {\n return moduleUpgradeLog[moduleName].length;\n }\n\n /**\n * @notice This function will rollback particular module to the spesific index / version of deployment\n *\n * @param moduleName Name of module in bytes32 format\n * @param index index / version of previous deployment\n */\n function rollback(bytes32 moduleName, uint256 index) external onlyOwner {\n address loanTokenModuleAddress = moduleUpgradeLog[moduleName][index].implementation;\n moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n activeModuleIndex[moduleName] = index;\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(bytes4 sig) external view whenNotPaused returns (address) {\n return logicTargets[sig];\n }\n}\n\ninterface ILoanTokenLogicModules {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory, bytes32 moduleName);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicProxy.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./AdvancedTokenStorage.sol\";\nimport \"../../openzeppelin/Initializable.sol\";\n\n/**\n * @title Loan Token Logic Proxy contract.\n *\n * @notice This contract contains the proxy functionality and it will query the logic target from LoanTokenLogicBeacon\n * This contract will also has the pause/unpause functionality. The purpose of this pausability is so that we can pause/unpause from the loan token level.\n *\n */\ncontract LoanTokenLogicProxy is AdvancedTokenStorage {\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT\n */\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT (CONSTANT / IMMUTABLE)\n */\n\n bytes32 internal constant LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT =\n keccak256(\"LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT\");\n\n modifier onlyAdmin() {\n require(isOwner(), \"LoanTokenLogicProxy:unauthorized\");\n _;\n }\n\n /**\n * @notice Fallback function performs a logic implementation address query to LoanTokenLogicBeacon and then do delegate call to that query result address.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n // query the logic target implementation address from the LoanTokenLogicBeacon\n address target = ILoanTokenLogicBeacon(_beaconAddress()).getTarget(msg.sig);\n require(target != address(0), \"LoanTokenLogicProxy:target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @dev Returns the current Loan Token logic Beacon.\n * @return Address of the current LoanTokenLogicBeacon.\n */\n function _beaconAddress() internal view returns (address beaconAddress) {\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n assembly {\n beaconAddress := sload(slot)\n }\n }\n\n /**\n * @return The address of the current LoanTokenLogicBeacon.\n */\n function beaconAddress() external view returns (address) {\n return _beaconAddress();\n }\n\n /**\n * @dev Set/update the new beacon address.\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon.\n */\n function _setBeaconAddress(address _newBeaconAddress) private {\n require(\n Address.isContract(_newBeaconAddress),\n \"Cannot set beacon address to a non-contract address\"\n );\n\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n\n assembly {\n sstore(slot, _newBeaconAddress)\n }\n }\n\n /**\n * @dev External function to set the new LoanTokenLogicBeacon Address\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon\n */\n function setBeaconAddress(address _newBeaconAddress) external onlyAdmin {\n _setBeaconAddress(_newBeaconAddress);\n }\n}\n\ninterface ILoanTokenLogicBeacon {\n function getTarget(bytes4 functionSignature)\n external\n view\n returns (address logicTargetAddress);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicShared.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicStorage.sol\";\nimport \"./interfaces/ProtocolLike.sol\";\nimport \"./interfaces/FeedsLike.sol\";\nimport \"./interfaces/ProtocolSettingsLike.sol\";\nimport \"../../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../../farm/ILiquidityMining.sol\";\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../governance/Vesting/IVesting.sol\";\n\n/**\n * @dev This contract shares functions used by both LoanTokenLogicSplit and LoanTokenLogicStandard\n */\ncontract LoanTokenLogicShared is LoanTokenLogicStorage {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /**\n * @notice Update the user's checkpoint price and profit so far.\n * In this loan token contract, whenever some tokens are minted or burned,\n * the _updateCheckpoints() function is invoked to update the stats to\n * reflect the balance changes.\n *\n * @param _user The user address.\n * @param _oldBalance The user's previous balance.\n * @param _newBalance The user's updated balance.\n * @param _currentPrice The current loan token price.\n * */\n function _updateCheckpoints(\n address _user,\n uint256 _oldBalance,\n uint256 _newBalance,\n uint256 _currentPrice\n ) internal {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(_user, iToken_ProfitSoFar));\n\n int256 _currentProfit;\n if (_newBalance == 0) {\n _currentPrice = 0;\n } else if (_oldBalance != 0) {\n _currentProfit = _profitOf(slot, _oldBalance, _currentPrice, checkpointPrices_[_user]);\n }\n\n assembly {\n sstore(slot, _currentProfit)\n }\n\n checkpointPrices_[_user] = _currentPrice;\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice Transfer tokens, low level.\n * Checks allowance, updates sender and recipient balances\n * and updates checkpoints too.\n *\n * @param _from The tokens' owner.\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @param _allowanceAmount The amount of tokens allowed to transfer.\n *\n * @return Success true/false.\n * */\n function _internalTransferFrom(\n address _from,\n address _to,\n uint256 _value,\n uint256 _allowanceAmount\n ) internal returns (bool) {\n if (_allowanceAmount != uint256(-1)) {\n allowed[_from][msg.sender] = _allowanceAmount.sub(_value, \"14\");\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, _allowanceAmount, allowed[_from][msg.sender]);\n }\n\n require(_to != address(0), \"15\");\n\n uint256 _balancesFrom = balances[_from];\n uint256 _balancesFromNew = _balancesFrom.sub(_value, \"16\");\n balances[_from] = _balancesFromNew;\n\n uint256 _balancesTo = balances[_to];\n uint256 _balancesToNew = _balancesTo.add(_value);\n balances[_to] = _balancesToNew;\n\n /// @dev Handle checkpoint update.\n uint256 _currentPrice = tokenPrice();\n\n //checkpoints are not being used by the smart contract logic itself, but just for external use (query the profit)\n //only update the checkpoints of a user if he's not depositing to / withdrawing from the lending pool\n if (_from != liquidityMiningAddress && _to != liquidityMiningAddress) {\n _updateCheckpoints(_from, _balancesFrom, _balancesFromNew, _currentPrice);\n _updateCheckpoints(_to, _balancesTo, _balancesToNew, _currentPrice);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n /**\n * @notice Profit calculation based on checkpoints of price.\n * @param slot The user slot.\n * @param _balance The user balance.\n * @param _currentPrice The current price of the loan token.\n * @param _checkpointPrice The price of the loan token on checkpoint.\n * @return The profit of a user.\n * */\n function _profitOf(\n bytes32 slot,\n uint256 _balance,\n uint256 _currentPrice,\n uint256 _checkpointPrice\n ) internal view returns (int256 profitSoFar) {\n if (_checkpointPrice == 0) {\n return 0;\n }\n\n assembly {\n profitSoFar := sload(slot)\n }\n\n profitSoFar = int256(_currentPrice)\n .sub(int256(_checkpointPrice))\n .mul(int256(_balance))\n .div(sWEI_PRECISION)\n .add(profitSoFar);\n }\n\n /**\n * @notice Loan token price calculation considering unpaid interests.\n * @return The loan token price.\n * */\n function tokenPrice() public view returns (uint256 price) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _tokenPrice(_totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Get the total amount of loan tokens on debt.\n * Calls protocol getTotalPrincipal function.\n * In the context of borrowing, principal is the initial size of a loan.\n * It can also be the amount still owed on a loan. If you take out a\n * $50,000 mortgage, for example, the principal is $50,000. If you pay off\n * $30,000, the principal balance now consists of the remaining $20,000.\n *\n * @return The total amount of loan tokens on debt.\n * */\n function totalAssetBorrow() public view returns (uint256) {\n return\n ProtocolLike(sovrynContractAddress).getTotalPrincipal(address(this), loanTokenAddress);\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice .\n *\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param withdrawalAmount The amount of tokens to withdraw.\n *\n * @return msgValue The amount of rBTC sent minus the collateral on tokens.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = loanTokenAddress;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n _safeTransfer(_loanTokenAddress, sentAddresses.receiver, withdrawalAmount, \"\");\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n /**\n * This is a critical piece of code!\n * rBTC are supposed to be held by the contract itself, while other tokens are being transfered from the sender directly.\n * */\n if (collateralTokenSent != 0) {\n if (\n collateralTokenAddress == _wrbtcToken &&\n msgValue != 0 &&\n msgValue >= collateralTokenSent\n ) {\n IWrbtc(_wrbtcToken).deposit.value(collateralTokenSent)();\n _safeTransfer(\n collateralTokenAddress,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-a\"\n );\n msgValue -= collateralTokenSent;\n } else {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-b\"\n );\n }\n }\n\n if (loanTokenSent != 0) {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n\n /**\n * @notice Withdraw loan token interests from protocol.\n * This function only operates once per block.\n * It asks protocol to withdraw accrued interests for the loan token.\n *\n * @dev Internal sync required on every loan trade before starting.\n * */\n function _settleInterest() internal {\n uint88 ts = uint88(block.timestamp);\n if (lastSettleTime_ != ts) {\n ProtocolLike(sovrynContractAddress).withdrawAccruedInterest(loanTokenAddress);\n\n lastSettleTime_ = ts;\n }\n }\n\n /**\n * @notice Imitate a Solidity high-level call (i.e. a regular function\n * call to a contract), relaxing the requirement on the return value:\n * the return value is optional (but if data is returned, it must not be\n * false).\n *\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n * @param errorMsg The error message on failure.\n * */\n function _callOptionalReturn(\n address token,\n bytes memory data,\n string memory errorMsg\n ) internal {\n require(Address.isContract(token), \"call to a non-contract address\");\n (bool success, bytes memory returndata) = token.call(data);\n require(success, errorMsg);\n\n if (returndata.length != 0) {\n require(abi.decode(returndata, (bool)), errorMsg);\n }\n }\n\n /**\n * @notice Execute the ERC20 token's `transfer` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransfer(\n address token,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transfer.selector, to, amount),\n errorMsg\n );\n }\n\n /**\n * @notice Execute the ERC20 token's `transferFrom` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param from The source address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransferFrom(\n address token,\n address from,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transferFrom.selector, from, to, amount),\n errorMsg\n );\n }\n\n /** Internal view function */\n /**\n * @notice Compute the token price.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The token price.\n * */\n function _tokenPrice(uint256 assetSupply) internal view returns (uint256) {\n uint256 totalTokenSupply = totalSupply_;\n\n return\n totalTokenSupply != 0 ? assetSupply.mul(10**18).div(totalTokenSupply) : initialPrice;\n }\n\n /**\n * @notice Get two kind of interests: owed per day and yet to be paid.\n * @return interestOwedPerDay The interest per day.\n * @return interestUnPaid The interest not yet paid.\n * */\n function _getAllInterest()\n internal\n view\n returns (uint256 interestOwedPerDay, uint256 interestUnPaid)\n {\n /// interestPaid, interestPaidDate, interestOwedPerDay, interestUnPaid, interestFeePercent, principalTotal\n uint256 interestFeePercent;\n (, , interestOwedPerDay, interestUnPaid, interestFeePercent, ) = ProtocolLike(\n sovrynContractAddress\n )\n .getLenderInterestData(address(this), loanTokenAddress);\n\n interestUnPaid = interestUnPaid.mul(SafeMath.sub(10**20, interestFeePercent)).div(10**20);\n }\n\n /**\n * @notice Compute the total amount of loan tokens on supply.\n * @param interestUnPaid The interest not yet paid.\n * @return assetSupply The total amount of loan tokens on supply.\n * */\n function _totalAssetSupply(uint256 interestUnPaid)\n internal\n view\n returns (uint256 assetSupply)\n {\n if (totalSupply_ != 0) {\n uint256 assetsBalance = _flTotalAssetSupply; /// Temporary locked totalAssetSupply during a flash loan transaction.\n if (assetsBalance == 0) {\n assetsBalance = _underlyingBalance().add(totalAssetBorrow());\n }\n\n return assetsBalance.add(interestUnPaid);\n }\n }\n\n /**\n * @notice Get the loan contract balance.\n * @return The balance of the loan token for this contract.\n * */\n function _underlyingBalance() internal view returns (uint256) {\n return IERC20(loanTokenAddress).balanceOf(address(this));\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicSplit.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\n/**\n * @title Loan Token Logic Standard contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Logic around loan tokens (iTokens) required to operate borrowing,\n * and margin trading financial processes.\n *\n * The user provides funds to the lending pool using the mint function and\n * withdraws funds from the lending pool using the burn function. Mint and\n * burn refer to minting and burning loan tokens. Loan tokens represent a\n * share of the pool and gather interest over time.\n *\n * Interest rates are determined by supply and demand. When a lender deposits\n * funds, the interest rates go down. When a trader borrows funds, the\n * interest rates go up. Fulcrum uses a simple linear interest rate formula\n * of the form y = mx + b. The interest rate starts at 1% when loans aren't\n * being utilized and scales up to 40% when all the funds in the loan pool\n * are being borrowed.\n *\n * The borrow rate is determined at the time of the loan and represents the\n * net contribution of each borrower. Each borrower's interest contribution\n * is determined by the utilization rate of the pool and is netted against\n * all prior borrows. This means that the total amount of interest flowing\n * into the lending pool is not directly changed by lenders entering or\n * exiting the pool. The entrance or exit of lenders only impacts how the\n * interest payments are split up.\n *\n * For example, if there are 2 lenders with equal holdings each earning\n * 5% APR, but one of the lenders leave, then the remaining lender will earn\n * 10% APR since the interest payments don't have to be split between two\n * individuals.\n * */\ncontract LoanTokenLogicSplit is LoanTokenLogicShared {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /* Public functions */\n\n /**\n * @notice Mint loan token wrapper.\n * Adds a check before calling low level _mintToken function.\n * The function retrieves the tokens from the message sender, so make sure\n * to first approve the loan token contract to access your funds. This is\n * done by calling approve(address spender, uint amount) on the ERC20\n * token contract, where spender is the loan token contract address and\n * amount is the amount to be deposited.\n *\n * @param receiver The account getting the minted tokens.\n * @param depositAmount The amount of underlying tokens provided on the\n * loan. (Not the number of loan tokens to mint).\n *\n * @return The amount of loan tokens minted.\n * */\n function mint(address receiver, uint256 depositAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice Burn loan token wrapper.\n * Adds a pay-out transfer after calling low level _burnToken function.\n * In order to withdraw funds to the pool, call burn on the respective\n * loan token contract. This will burn your loan tokens and send you the\n * underlying token in exchange.\n *\n * @param receiver The account getting the minted tokens.\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 loanAmountPaid)\n {\n loanAmountPaid = _burnToken(burnAmount);\n\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (loanAmountPaid != 0) {\n _safeTransfer(loanTokenAddress, receiver, loanAmountPaid, \"5\");\n }\n }\n\n /**\n * @notice transfers the underlying asset from the msg.sender and mints tokens for the receiver\n * @param receiver the address of the iToken receiver\n * @param depositAmount the amount of underlying assets to be deposited\n * @return the amount of iTokens issued\n */\n function _mintToken(address receiver, uint256 depositAmount)\n internal\n returns (uint256 mintAmount)\n {\n uint256 currentPrice;\n\n //calculate amount to mint and transfer the underlying asset\n (mintAmount, currentPrice) = _prepareMinting(depositAmount);\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n receiver\n );\n uint256 oldBalance = balances[receiver].add(balanceOnLM);\n uint256 newBalance = oldBalance.add(mintAmount);\n\n //mint the tokens to the receiver\n _mint(receiver, mintAmount, depositAmount, currentPrice);\n\n //update the checkpoint of the receiver\n _updateCheckpoints(receiver, oldBalance, newBalance, currentPrice);\n }\n\n /**\n * calculates the amount of tokens to mint and transfers the underlying asset to this contract\n * @param depositAmount the amount of the underyling asset deposited\n * @return the amount to be minted\n */\n function _prepareMinting(uint256 depositAmount)\n internal\n returns (uint256 mintAmount, uint256 currentPrice)\n {\n require(depositAmount != 0, \"17\");\n\n _settleInterest();\n\n currentPrice = _tokenPrice(_totalAssetSupply(0));\n mintAmount = depositAmount.mul(10**18).div(currentPrice);\n\n if (msg.value == 0) {\n _safeTransferFrom(loanTokenAddress, msg.sender, address(this), depositAmount, \"18\");\n } else {\n IWrbtc(wrbtcTokenAddress).deposit.value(depositAmount)();\n }\n }\n\n /**\n * @notice A wrapper for AdvancedToken::_burn\n *\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function _burnToken(uint256 burnAmount) internal returns (uint256 loanAmountPaid) {\n require(burnAmount != 0, \"19\");\n\n if (burnAmount > balanceOf(msg.sender)) {\n require(burnAmount == uint256(-1), \"32\");\n burnAmount = balanceOf(msg.sender);\n }\n\n _settleInterest();\n\n uint256 currentPrice = _tokenPrice(_totalAssetSupply(0));\n\n uint256 loanAmountOwed = burnAmount.mul(currentPrice).div(10**18);\n uint256 loanAmountAvailableInContract = _underlyingBalance();\n\n loanAmountPaid = loanAmountOwed;\n require(loanAmountPaid <= loanAmountAvailableInContract, \"37\");\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n uint256 oldBalance = balances[msg.sender].add(balanceOnLM);\n uint256 newBalance = oldBalance.sub(burnAmount);\n\n _burn(msg.sender, burnAmount, loanAmountPaid, currentPrice);\n\n //this function does not only update the checkpoints but also the current profit of the user\n //all for external use only\n _updateCheckpoints(msg.sender, oldBalance, newBalance, currentPrice);\n }\n\n function _mintWithLM(address receiver, uint256 depositAmount)\n internal\n returns (uint256 minted)\n {\n //mint the tokens for the receiver\n minted = _mintToken(receiver, depositAmount);\n\n //transfer the tokens from the receiver to the LM address\n _internalTransferFrom(receiver, liquidityMiningAddress, minted, minted);\n\n //inform the LM mining contract\n ILiquidityMining(liquidityMiningAddress).onTokensDeposited(receiver, minted);\n }\n\n function _burnFromLM(uint256 burnAmount) internal returns (uint256) {\n uint256 balanceOnLM =\n ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n require(balanceOnLM.add(balanceOf(msg.sender)) >= burnAmount, \"not enough balance\");\n\n if (balanceOnLM > 0) {\n //withdraw pool tokens and LM rewards to the passed address\n if (balanceOnLM < burnAmount) {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n balanceOnLM,\n msg.sender\n );\n } else {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n burnAmount,\n msg.sender\n );\n }\n }\n //burn the tokens of the msg.sender\n return _burnToken(burnAmount);\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStandard.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\ncontract LoanTokenLogicStandard is LoanTokenLogicShared {\n /**\n * @notice Transfer tokens wrapper.\n * Sets token owner the msg.sender.\n * Sets maximun allowance uint256(-1) to ensure tokens are always transferred.\n *\n * If the recipient (_to) is a vesting contract address, transfer the token to the tokenOwner of the vesting contract itself.\n *\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @return Success true/false.\n * */\n function transfer(address _to, uint256 _value) external returns (bool) {\n /** need additional check address(0) here to support backward compatibility\n * in case we don't want to activate this check, just need to set the stakingContractAddress to 0 address\n */\n if (\n stakingContractAddress != address(0) &&\n IStaking(stakingContractAddress).isVestingContract(_to)\n ) {\n (bool success, bytes memory data) =\n _to.staticcall(abi.encodeWithSelector(IVesting(_to).tokenOwner.selector));\n\n if (success) _to = abi.decode(data, (address));\n }\n\n return _internalTransferFrom(msg.sender, _to, _value, uint256(-1));\n }\n\n /**\n * @notice Moves `_value` loan tokens from `_from` to `_to` using the\n * allowance mechanism. Calls internal _internalTransferFrom function.\n *\n * @return A boolean value indicating whether the operation succeeded.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool) {\n return\n _internalTransferFrom(\n _from,\n _to,\n _value,\n //allowed[_from][msg.sender]\n ProtocolLike(sovrynContractAddress).isLoanPool(msg.sender)\n ? uint256(-1)\n : allowed[_from][msg.sender]\n );\n }\n\n /**\n * @notice Borrow funds from the pool.\n * The underlying loan token may not be used as collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * (150% of the withdrawn amount worth in collateral tokens).\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param borrower The one paying for the collateral.\n * @param receiver The one receiving the withdrawn amount.\n *\n * @return New principal and new collateral added to loan.\n * */\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes memory /// loanDataBytes: arbitrary order data (for future use).\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n )\n {\n require(withdrawAmount != 0, \"6\");\n\n _checkPause();\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n\n require(\n (msg.value == 0 || msg.value == collateralTokenSent) &&\n (collateralTokenSent != 0 || loanId != 0) &&\n (collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0) &&\n (loanId == 0 || msg.sender == borrower),\n \"7\"\n );\n\n /// @dev We have an issue regarding contract size code is too big. 1 of the solution is need to keep the error message 32 bytes length\n // Temporarily, we combine this require to the above, so can save the contract size code\n // require(collateralTokenSent != 0 || loanId != 0, \"8\");\n // require(collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0, \"9\");\n\n /// @dev Ensure authorized use of existing loan.\n // require(loanId == 0 || msg.sender == borrower, \"401 use of existing loan\");\n\n /// @dev The condition is never met.\n /// Address zero is not allowed by previous require validation.\n /// This check is unneeded and was lowering the test coverage index.\n // if (collateralTokenAddress == address(0)) {\n // \tcollateralTokenAddress = wrbtcTokenAddress;\n // }\n\n require(collateralTokenAddress != loanTokenAddress, \"10\");\n\n _settleInterest();\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this); /// The lender.\n sentAddresses.borrower = borrower;\n sentAddresses.receiver = receiver;\n /// sentAddresses.manager = address(0); /// The manager.\n\n sentAmounts.newPrincipal = withdrawAmount;\n\n /// interestRate, interestInitialAmount, borrowAmount (newBorrowAmount).\n (\n sentAmounts.interestRate,\n sentAmounts.interestInitialAmount,\n sentAmounts.newPrincipal\n ) = _getInterestRateAndBorrowAmount(\n sentAmounts.newPrincipal,\n _totalAssetSupply(0), /// Interest is settled above.\n initialLoanDuration\n );\n\n /// sentAmounts.loanTokenSent = 0; /// loanTokenSent\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n return\n _borrowOrTrade(\n loanId,\n withdrawAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ]\n ),\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Borrow and immediately get into a position.\n *\n * Trading on margin is used to increase an investor's buying power.\n * Margin is the amount of money required to open a position, while\n * leverage is the multiple of exposure to account equity.\n *\n * Leverage allows you to trade positions LARGER than the amount\n * of money in your trading account. Leverage is expressed as a ratio.\n *\n * When trading on margin, investors first deposit some token that then\n * serves as collateral for the loan, and then pay ongoing interest\n * payments on the money they borrow.\n *\n * Margin trading = taking a loan and swapping it:\n * In order to open a margin trade position,\n * 1.- The user calls marginTrade on the loan token contract.\n * 2.- The loan token contract provides the loan and sends it for processing\n * to the protocol proxy contract.\n * 3.- The protocol proxy contract uses the module LoanOpening to create a\n * position and swaps the loan tokens to collateral tokens.\n * 4.- The Sovryn Swap network looks up the correct converter and swaps the\n * tokens.\n * If successful, the position is being held by the protocol proxy contract,\n * which is why positions need to be closed at the protocol proxy contract.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n * */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // value of loan token in collateral\n bytes memory loanDataBytes /// Arbitrary order data.\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n _checkPause();\n\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n require(collateralTokenAddress != loanTokenAddress, \"11\");\n\n /// @dev Ensure authorized use of existing loan.\n require(loanId == 0 || msg.sender == trader, \"401 use of existing loan\");\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n if (transactionLimit[loanTokenAddress] > 0)\n require(loanTokenSent <= transactionLimit[loanTokenAddress]);\n\n /// @dev Compute the worth of the total deposit in loan tokens.\n /// (loanTokenSent + convert(collateralTokenSent))\n /// No actual swap happening here.\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n require(totalDeposit != 0, \"12\");\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this);\n sentAddresses.borrower = trader;\n sentAddresses.receiver = trader;\n /// sentAddresses.manager = address(0); /// The manager.\n\n /// sentAmounts.interestRate = 0; /// interestRate (found later).\n sentAmounts.newPrincipal = totalDeposit;\n /// sentAmounts.interestInitialAmount = 0; /// interestInitialAmount (interest is calculated based on fixed-term loan).\n sentAmounts.loanTokenSent = loanTokenSent;\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n _settleInterest();\n\n (sentAmounts.newPrincipal, sentAmounts.interestRate) = _getMarginBorrowAmountAndRate( /// borrowAmount, interestRate\n leverageAmount,\n sentAmounts.newPrincipal /// depositAmount\n );\n\n require(\n _getAmountInRbtc(loanTokenAddress, sentAmounts.newPrincipal) > TINY_AMOUNT,\n \"principal too small\"\n );\n\n /// @dev Converting to initialMargin\n leverageAmount = SafeMath.div(10**38, leverageAmount);\n sentAmounts.minEntryPrice = minEntryPrice;\n return\n _borrowOrTrade(\n loanId,\n 0, /// withdrawAmount\n leverageAmount, //initial margin\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n );\n }\n\n /**\n * @notice Wrapper for marginTrade invoking setAffiliatesReferrer to track\n * referral trade by affiliates program.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param affiliateReferrer The address of the referrer from affiliates program.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n */\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, /// Value of loan token in collateral\n address affiliateReferrer, /// The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n if (affiliateReferrer != address(0))\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(\n trader,\n affiliateReferrer\n );\n return\n marginTrade(\n loanId,\n leverageAmount,\n loanTokenSent,\n collateralTokenSent,\n collateralTokenAddress,\n trader,\n minEntryPrice,\n loanDataBytes\n );\n }\n\n /* Public View functions */\n\n /**\n * @notice Wrapper for internal _profitOf low level function.\n * @param user The user address.\n * @return The profit of a user.\n * */\n function profitOf(address user) external view returns (int256) {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(user, iToken_ProfitSoFar));\n //TODO + LM balance\n return _profitOf(slot, balances[user], tokenPrice(), checkpointPrices_[user]);\n }\n\n /**\n * @notice Getter for the price checkpoint mapping.\n * @param _user The user account as the mapping index.\n * @return The price on the checkpoint for this user.\n * */\n function checkpointPrice(address _user) public view returns (uint256 price) {\n return checkpointPrices_[_user];\n }\n\n /**\n * @notice Get current liquidity.\n * A part of total funds supplied are borrowed. Liquidity = supply - borrow\n * @return The market liquidity.\n * */\n function marketLiquidity() public view returns (uint256) {\n uint256 totalSupply = _totalAssetSupply(0);\n uint256 totalBorrow = totalAssetBorrow();\n if (totalSupply > totalBorrow) {\n return totalSupply - totalBorrow;\n }\n }\n\n /**\n * @notice Wrapper for average borrow interest.\n * @return The average borrow interest.\n * */\n function avgBorrowInterestRate() public view returns (uint256) {\n return _avgBorrowInterestRate(totalAssetBorrow());\n }\n\n /**\n * @notice Get borrow interest rate.\n * The minimum rate the next base protocol borrower will receive\n * for variable-rate loans.\n * @return The borrow interest rate.\n * */\n function borrowInterestRate() public view returns (uint256) {\n return _nextBorrowInterestRate(0);\n }\n\n /**\n * @notice Public wrapper for internal call.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest rate.\n * */\n function nextBorrowInterestRate(uint256 borrowAmount) public view returns (uint256) {\n return _nextBorrowInterestRate(borrowAmount);\n }\n\n /**\n * @notice Get interest rate.\n *\n * @return Interest that lenders are currently receiving when supplying to\n * the pool.\n * */\n function supplyInterestRate() public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0));\n }\n\n /**\n * @notice Get interest rate w/ added supply.\n * @param supplyAmount The amount of tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of tokens to the pool.\n * */\n function nextSupplyInterestRate(uint256 supplyAmount) public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0).add(supplyAmount));\n }\n\n /**\n * @notice Get interest rate w/ added supply assets.\n * @param assetSupply The amount of loan tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of loan tokens to the pool.\n * */\n function totalSupplyInterestRate(uint256 assetSupply) public view returns (uint256) {\n uint256 assetBorrow = totalAssetBorrow();\n if (assetBorrow != 0) {\n return calculateSupplyInterestRate(assetBorrow, assetSupply);\n }\n }\n\n /**\n * @notice Get the total amount of loan tokens on supply.\n * @dev Wrapper for internal _totalAssetSupply function.\n * @return The total amount of loan tokens on supply.\n * */\n function totalAssetSupply() public view returns (uint256) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _totalAssetSupply(interestUnPaid);\n }\n\n /**\n * @notice Compute the maximum deposit amount under current market conditions.\n * @dev maxEscrowAmount = liquidity * (100 - interestForDuration) / 100\n * @param leverageAmount The chosen multiplier with 18 decimals.\n * */\n function getMaxEscrowAmount(uint256 leverageAmount)\n public\n view\n returns (uint256 maxEscrowAmount)\n {\n /**\n * @dev Mathematical imperfection: depending on liquidity we might be able\n * to borrow more if utilization is below the kink level.\n * */\n uint256 interestForDuration = maxScaleRate.mul(28).div(365);\n uint256 factor = uint256(10**20).sub(interestForDuration);\n uint256 maxLoanSize = marketLiquidity().mul(factor).div(10**20);\n maxEscrowAmount = maxLoanSize.mul(10**18).div(leverageAmount);\n }\n\n /**\n * @notice Get loan token balance.\n * @return The user's balance of underlying token.\n * */\n function assetBalanceOf(address _owner) public view returns (uint256) {\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0)) {\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n _owner\n );\n }\n return balanceOf(_owner).add(balanceOnLM).mul(tokenPrice()).div(10**18);\n }\n\n /**\n * @notice Get margin information on a trade.\n *\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The principal, the collateral and the interestRate.\n * */\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n public\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n )\n {\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n\n (principal, interestRate) = _getMarginBorrowAmountAndRate(leverageAmount, totalDeposit);\n if (principal > _underlyingBalance()) {\n return (0, 0, 0);\n }\n\n loanTokenSent = loanTokenSent.add(principal);\n\n collateral = ProtocolLike(sovrynContractAddress).getEstimatedMarginExposure(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent,\n collateralTokenSent,\n interestRate,\n principal\n );\n }\n\n /**\n * @notice Calculate the deposit required to a given borrow.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param borrowAmount The amount of borrow.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of deposit required.\n * */\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 depositAmount) {\n if (borrowAmount != 0) {\n (, , uint256 newBorrowAmount) =\n _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (newBorrowAmount <= _underlyingBalance()) {\n if (collateralTokenAddress == address(0))\n collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ];\n return\n ProtocolLike(sovrynContractAddress)\n .getRequiredCollateral(\n loanTokenAddress,\n collateralTokenAddress,\n newBorrowAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin\n true /// isTorqueLoan\n )\n .add(10); /// Some dust to compensate for rounding errors.\n }\n }\n }\n\n /**\n * @notice Calculate the borrow allowed for a given deposit.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param depositAmount The amount of deposit.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of borrow allowed.\n * */\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 borrowAmount) {\n if (depositAmount != 0) {\n if (collateralTokenAddress == address(0)) collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))];\n borrowAmount = ProtocolLike(sovrynContractAddress).getBorrowAmount(\n loanTokenAddress,\n collateralTokenAddress,\n depositAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin,\n true /// isTorqueLoan\n );\n\n (, , borrowAmount) = _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (borrowAmount > _underlyingBalance()) {\n borrowAmount = 0;\n }\n }\n }\n\n /**\n * @notice Check if entry price lies above a minimum\n *\n * @param loanTokenSent The amount of deposit.\n * @param collateralTokenAddress The token address of collateral.\n * @param minEntryPrice Value of loan token in collateral\n * */\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) public view {\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokensReceived =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent\n );\n uint256 collateralTokenPrice =\n (collateralTokensReceived.mul(WEI_PRECISION)).div(loanTokenSent);\n require(collateralTokenPrice >= minEntryPrice, \"entry price above the minimum\");\n }\n\n /**\n * @notice Compute the next supply interest adjustment.\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next supply interest adjustment.\n * */\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n public\n view\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply >= assetBorrow) {\n return\n _avgBorrowInterestRate(assetBorrow)\n .mul(_utilizationRate(assetBorrow, assetSupply))\n .mul(\n SafeMath.sub(10**20, ProtocolLike(sovrynContractAddress).lendingFeePercent())\n )\n .div(10**40);\n }\n }\n\n /* Internal functions */\n\n /**\n * @notice Compute what the deposit is worth in loan tokens using the swap rate\n * used for loan size computation.\n *\n * @param collateralTokenAddress The token address of the collateral.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param loanTokenSent The number of loan tokens provided by the user.\n *\n * @return The value of the deposit in loan tokens.\n * */\n function _totalDeposit(\n address collateralTokenAddress,\n uint256 collateralTokenSent,\n uint256 loanTokenSent\n ) internal view returns (uint256 totalDeposit) {\n totalDeposit = loanTokenSent;\n\n if (collateralTokenSent != 0) {\n /// @dev Get the oracle rate from collateral -> loan\n (uint256 collateralToLoanRate, uint256 collateralToLoanPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n collateralTokenAddress,\n loanTokenAddress\n );\n require(\n (collateralToLoanRate != 0) && (collateralToLoanPrecision != 0),\n \"invalid rate collateral token\"\n );\n\n /// @dev Compute the loan token amount with the oracle rate.\n uint256 loanTokenAmount =\n collateralTokenSent.mul(collateralToLoanRate).div(collateralToLoanPrecision);\n\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokenAmount =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenAmount\n );\n\n /// @dev Probably not the same due to the price difference.\n if (collateralTokenAmount != collateralTokenSent) {\n //scale the loan token amount accordingly, so we'll get the expected position size in the end\n loanTokenAmount = loanTokenAmount.mul(collateralTokenAmount).div(\n collateralTokenSent\n );\n }\n\n totalDeposit = loanTokenAmount.add(totalDeposit);\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n asset,\n wrbtcTokenAddress\n );\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /*\n * @notice Compute interest rate and other loan parameters.\n *\n * @param borrowAmount The amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n *\n * @return The interest rate, the interest calculated based on fixed-term\n * loan, and the new borrow amount.\n * */\n function _getInterestRateAndBorrowAmount(\n uint256 borrowAmount,\n uint256 assetSupply,\n uint256 initialLoanDuration /// Duration in seconds.\n )\n internal\n view\n returns (\n uint256 interestRate,\n uint256 interestInitialAmount,\n uint256 newBorrowAmount\n )\n {\n interestRate = _nextBorrowInterestRate2(borrowAmount, assetSupply);\n\n /// newBorrowAmount = borrowAmount * 10^18 / (10^18 - interestRate * 7884000 * 10^18 / 31536000 / 10^20)\n newBorrowAmount = borrowAmount.mul(10**18).div(\n SafeMath.sub(\n 10**18,\n interestRate.mul(initialLoanDuration).mul(10**18).div(31536000 * 10**20) /// 365 * 86400 * 10**20\n )\n );\n\n interestInitialAmount = newBorrowAmount.sub(borrowAmount);\n }\n\n /**\n * @notice Compute principal and collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialMargin The initial margin with 18 decimals\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return The new principal and the new collateral. Principal is the\n * complete borrowed amount (in loan tokens). Collateral is the complete\n * position size (loan + margin) (in collateral tokens).\n * */\n function _borrowOrTrade(\n bytes32 loanId,\n uint256 withdrawAmount,\n uint256 initialMargin,\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n _checkPause();\n require(\n sentAmounts.newPrincipal <= _underlyingBalance() && /// newPrincipal (borrowed amount + fees)\n sentAddresses.borrower != address(0), /// The borrower.\n \"24\"\n );\n\n if (sentAddresses.receiver == address(0)) {\n sentAddresses.receiver = sentAddresses.borrower; /// The receiver = the borrower.\n }\n\n /// @dev Handle transfers prior to adding newPrincipal to loanTokenSent\n uint256 msgValue =\n _verifyTransfers(collateralTokenAddress, sentAddresses, sentAmounts, withdrawAmount);\n\n /**\n * @dev Adding the loan token portion from the lender to loanTokenSent\n * (add the loan to the loan tokens sent from the user).\n * */\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.add(sentAmounts.newPrincipal); /// newPrincipal\n\n if (withdrawAmount != 0) {\n /// @dev withdrawAmount already sent to the borrower, so we aren't sending it to the protocol.\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.sub(withdrawAmount);\n }\n\n bool withdrawAmountExist = false; /// Default is false, but added just as to make sure.\n\n if (withdrawAmount != 0) {\n withdrawAmountExist = true;\n }\n\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, withdrawAmountExist)))\n ];\n\n (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent) = ProtocolLike(\n sovrynContractAddress\n )\n .borrowOrTradeFromPool\n .value(msgValue)(\n loanParamsId,\n loanId,\n withdrawAmountExist,\n initialMargin,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n ); /// newPrincipal, newCollateral\n require(sentAmounts.newPrincipal != 0, \"25\");\n\n /// @dev Setting not-first-trade flag to prevent binding to an affiliate existing users post factum.\n /// @dev REFACTOR: move to a general interface: ProtocolSettingsLike?\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(\n sentAddresses.borrower\n );\n\n return (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent); // newPrincipal, newCollateral\n }\n\n /* Internal View functions */\n\n /**\n * @notice Compute the average borrow interest rate.\n * @param assetBorrow The amount of loan tokens on debt.\n * @return The average borrow interest rate.\n * */\n function _avgBorrowInterestRate(uint256 assetBorrow) internal view returns (uint256) {\n if (assetBorrow != 0) {\n (uint256 interestOwedPerDay, ) = _getAllInterest();\n return interestOwedPerDay.mul(10**20).mul(365).div(assetBorrow);\n }\n }\n\n /**\n * @notice Compute the next borrow interest adjustment.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate(uint256 borrowAmount) internal view returns (uint256) {\n uint256 interestUnPaid;\n if (borrowAmount != 0) {\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n uint256 balance = _underlyingBalance().add(interestUnPaid);\n if (borrowAmount > balance) {\n borrowAmount = balance;\n }\n }\n\n return _nextBorrowInterestRate2(borrowAmount, _totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Compute the next borrow interest adjustment under target-kink\n * level analysis.\n *\n * The \"kink\" in the cDAI interest rate model reflects the utilization rate\n * at which the slope of the interest rate goes from \"gradual\" to \"steep\".\n * That is, below this utilization rate, the slope of the interest rate\n * curve is gradual. Above this utilization rate, it is steep.\n *\n * Because of this dynamic between the interest rate curves before and\n * after the \"kink\", the \"kink\" can be thought of as the target utilization\n * rate. Above that rate, it quickly becomes expensive to borrow (and\n * commensurately lucrative for suppliers).\n *\n * @param newBorrowAmount The new amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate2(uint256 newBorrowAmount, uint256 assetSupply)\n internal\n view\n returns (uint256 nextRate)\n {\n uint256 utilRate = _utilizationRate(totalAssetBorrow().add(newBorrowAmount), assetSupply);\n\n uint256 thisMinRate;\n uint256 thisRateAtKink;\n uint256 thisBaseRate = baseRate;\n uint256 thisRateMultiplier = rateMultiplier;\n uint256 thisTargetLevel = targetLevel;\n uint256 thisKinkLevel = kinkLevel;\n uint256 thisMaxScaleRate = maxScaleRate;\n\n if (utilRate < thisTargetLevel) {\n // target targetLevel utilization when utilization is under targetLevel\n utilRate = thisTargetLevel;\n }\n\n if (utilRate > thisKinkLevel) {\n /// @dev Scale rate proportionally up to 100%\n uint256 thisMaxRange = WEI_PERCENT_PRECISION - thisKinkLevel; /// Will not overflow.\n\n utilRate -= thisKinkLevel;\n if (utilRate > thisMaxRange) utilRate = thisMaxRange;\n\n // Modified the rate calculation as it is slightly exaggerated around kink level\n // thisRateAtKink = thisRateMultiplier.add(thisBaseRate).mul(thisKinkLevel).div(WEI_PERCENT_PRECISION);\n thisRateAtKink = thisKinkLevel.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n nextRate = utilRate\n .mul(SafeMath.sub(thisMaxScaleRate, thisRateAtKink))\n .div(thisMaxRange)\n .add(thisRateAtKink);\n } else {\n nextRate = utilRate.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n thisMinRate = thisBaseRate;\n thisRateAtKink = thisRateMultiplier.add(thisBaseRate);\n\n if (nextRate < thisMinRate) nextRate = thisMinRate;\n else if (nextRate > thisRateAtKink) nextRate = thisRateAtKink;\n }\n }\n\n /**\n * @notice Compute the loan size and interest rate.\n * @param leverageAmount The leverage with 18 decimals.\n * @param depositAmount The amount the user deposited in underlying loan tokens.\n * @return borrowAmount The amount of tokens to borrow.\n * @return interestRate The interest rate to pay on the position.\n * */\n function _getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n internal\n view\n returns (uint256 borrowAmount, uint256 interestRate)\n {\n uint256 loanSizeBeforeInterest = depositAmount.mul(leverageAmount).div(10**18);\n /**\n * @dev Mathematical imperfection. we calculate the interest rate based on\n * the loanSizeBeforeInterest, but the actual borrowed amount will be bigger.\n * */\n interestRate = _nextBorrowInterestRate2(loanSizeBeforeInterest, _totalAssetSupply(0));\n /// @dev Assumes that loan, collateral, and interest token are the same.\n borrowAmount = _adjustLoanSize(interestRate, 28 days, loanSizeBeforeInterest);\n }\n\n /**\n * @notice Make sure call is not paused.\n * @dev Used for internal verification if the called function is paused.\n * It throws an exception in case it's not.\n * */\n function _checkPause() internal view {\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n msg.sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n bool isPaused;\n assembly {\n isPaused := sload(slot)\n }\n require(!isPaused, \"unauthorized\");\n }\n\n /**\n * @notice Adjusts the loan size to make sure the expected exposure remains after prepaying the interest.\n * @dev loanSizeWithInterest = loanSizeBeforeInterest * 100 / (100 - interestForDuration)\n * @param interestRate The interest rate to pay on the position.\n * @param maxDuration The maximum duration of the position (until rollover).\n * @param loanSizeBeforeInterest The loan size before interest is added.\n * */\n function _adjustLoanSize(\n uint256 interestRate,\n uint256 maxDuration,\n uint256 loanSizeBeforeInterest\n ) internal pure returns (uint256 loanSizeWithInterest) {\n uint256 interestForDuration = interestRate.mul(maxDuration).div(365 days);\n uint256 divisor = uint256(10**20).sub(interestForDuration);\n loanSizeWithInterest = loanSizeBeforeInterest.mul(10**20).div(divisor);\n }\n\n /**\n * @notice Calculate the utilization rate.\n * @dev Utilization rate = assetBorrow / assetSupply\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The utilization rate.\n * */\n function _utilizationRate(uint256 assetBorrow, uint256 assetSupply)\n internal\n pure\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply != 0) {\n /// U = total_borrow / total_supply\n return assetBorrow.mul(10**20).div(assetSupply);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./AdvancedToken.sol\";\n\ncontract LoanTokenLogicStorage is AdvancedToken {\n /// DO NOT ADD VARIABLES HERE - SEE BELOW\n\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /// @dev Add new variables here on the bottom.\n address public earlyAccessToken; //not used anymore, but staying for upgradability\n address public pauser;\n /** The address of the liquidity mining contract */\n address public liquidityMiningAddress;\n\n /** The address of the staking contract */\n address public stakingContractAddress;\n\n /// @dev Used by flashBorrow function.\n uint256 public constant VERSION = 6;\n /// @dev Used by flashBorrow function.\n address internal constant arbitraryCaller = 0x000F400e6818158D541C3EBE45FE3AA0d47372FF;\n bytes32 internal constant iToken_ProfitSoFar =\n 0x37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb6; // keccak256(\"iToken_ProfitSoFar\")\n uint256 public constant TINY_AMOUNT = 25e13;\n\n function stringToBytes32(string memory source) public pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"unauthorized\"); // SS02\n _;\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogic is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenMintAndBurn also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenLogicStandard also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\")); /// LoanTokenLogicStandard\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\")); /// LoanTokenLogicLM\n res[2] = bytes4(keccak256(\"burn(address,uint256)\")); /// LoanTokenLogicStandard\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\")); /// LoanTokenLogicLM\n\n return (res, stringToBytes32(\"LoanTokenLogicLM\"));\n }\n\n /**\n * @notice deposit into the lending pool and optionally participate at the Liquidity Mining Program\n * @param receiver the receiver of the tokens\n * @param depositAmount The amount of underlying tokens provided on the loan.\n *\t\t\t\t\t\t(Not the number of loan tokens to mint).\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 minted) {\n if (useLM) return _mintWithLM(receiver, depositAmount);\n else return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice withdraws from the lending pool and optionally retrieves the pool tokens from the\n * Liquidity Mining Contract\n * @param receiver the receiver of the underlying tokens. note: potetial LM rewards are always sent to the msg.sender\n * @param burnAmount The amount of pool tokens to redeem.\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 redeemed) {\n if (useLM) redeemed = _burnFromLM(burnAmount);\n else redeemed = _burnToken(burnAmount);\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (redeemed != 0) {\n _safeTransfer(loanTokenAddress, receiver, redeemed, \"asset transfer failed\");\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtc.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogicWrbtc is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtc\"));\n }\n\n /**\n * @dev internal override functions\n * @dev Put all of internal override function dedicated to the loanTokenWrtbc module here\n * e.g: _verifyTransfers will override the implementation of _verifyTransfers in loanTokenLogicSplit\n */\n\n /**\n * @notice Handle transfers prior to adding newPrincipal to loanTokenSent.\n *\n * @param collateralTokenAddress The address of the collateral token.\n * @param sentAddresses The struct which contains addresses of\n * - lender\n * - borrower\n * - receiver\n * - manager\n *\n * @param sentAmounts The struct which contains uint256 of:\n * - interestRate\n * - newPrincipal\n * - interestInitialAmount\n * - loanTokenSent\n * - collateralTokenSent\n *\n * @param withdrawalAmount The amount to withdraw.\n *\n * @return msgValue The amount of value sent.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = _wrbtcToken;\n address receiver = sentAddresses.receiver;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n IWrbtcERC20(_wrbtcToken).withdraw(withdrawalAmount);\n Address.sendValue(receiver, withdrawalAmount);\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n\n if (collateralTokenSent != 0) {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28\"\n );\n }\n\n if (loanTokenSent != 0) {\n if (msgValue != 0 && msgValue >= loanTokenSent) {\n IWrbtc(_wrbtcToken).deposit.value(loanTokenSent)();\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, loanTokenSent, \"29\");\n msgValue -= loanTokenSent;\n } else {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtcLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicWrbtcLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token Mint and Burn.\n res[0] = this.mint.selector;\n res[1] = this.burn.selector;\n\n // Loan Token WRBTC\n res[2] = this.mintWithBTC.selector;\n res[3] = this.burnToBTC.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtcLM\"));\n }\n\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n if (useLM) return _mintWithLM(receiver, msg.value);\n else return _mintToken(receiver, msg.value);\n }\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 loanAmountPaid) {\n loanAmountPaid = useLM ? _burnFromLM(burnAmount) : _burnToken(burnAmount);\n\n if (loanAmountPaid != 0) {\n IWrbtcERC20(wrbtcTokenAddress).withdraw(loanAmountPaid);\n Address.sendValue(receiver, loanAmountPaid);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/shared/LoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../AdvancedToken.sol\";\nimport \"../../interfaces/ProtocolSettingsLike.sol\";\nimport \"../../LoanTokenLogicStorage.sol\";\n\ncontract LoanTokenSettingsLowerAdmin is LoanTokenLogicStorage {\n using SafeMath for uint256;\n\n /// @dev TODO: Check for restrictions in this contract.\n modifier onlyAdmin() {\n require(isOwner() || msg.sender == admin, \"unauthorized\");\n _;\n }\n\n /* Events */\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](15);\n res[0] = this.setAdmin.selector;\n res[1] = this.setPauser.selector;\n res[2] = this.setupLoanParams.selector;\n res[3] = this.disableLoanParams.selector;\n res[4] = this.setDemandCurve.selector;\n res[5] = this.toggleFunctionPause.selector;\n res[6] = this.setTransactionLimits.selector;\n res[7] = this.changeLoanTokenNameAndSymbol.selector;\n res[8] = this.pauser.selector;\n res[9] = this.setLiquidityMiningAddress.selector;\n res[10] = this.withdrawRBTCTo.selector;\n res[11] = this.getLiquidityMiningAddress.selector;\n res[12] = this.checkPause.selector;\n res[13] = this.setStakingContractAddress.selector;\n res[14] = this.getStakingContractAddress.selector;\n return (res, stringToBytes32(\"LoanTokenSettingsLowerAdmin\"));\n }\n\n /**\n * @notice Set admin account.\n * @param _admin The address of the account to grant admin permissions.\n * */\n function setAdmin(address _admin) public onlyOwner {\n admin = _admin;\n }\n\n /**\n * @notice Set pauser account.\n * @param _pauser The address of the account to grant pause permissions.\n * */\n function setPauser(address _pauser) public onlyOwner {\n pauser = _pauser;\n }\n\n /**\n * @notice Fallback function not allowed\n * */\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n /**\n * @notice Set loan token parameters.\n *\n * @param loanParamsList The array of loan parameters.\n * @param areTorqueLoans Whether the loan is a torque loan.\n * */\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans /// isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n /**\n * @notice Disable loan token parameters.\n *\n * @param collateralTokens The array of collateral tokens.\n * @param isTorqueLoans Whether the loan is a torque loan.\n * */\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n /**\n * @notice Set loan token parameters about the demand curve.\n *\n * @dev These params should be percentages represented\n * like so: 5% = 5000000000000000000 /// 18 digits precision.\n * rateMultiplier + baseRate can't exceed 100%\n *\n * To maintain a healthy credit score, it's important to keep your\n * credit utilization rate (CUR) low (_lowUtilBaseRate). In general\n * you don't want your CUR to exceed 30%, but increasingly financial\n * experts are recommending that you don't want to go above 10% if you\n * really want an excellent credit score.\n *\n * Interest rates tend to cluster around the kink level of a kinked\n * interest rate model. More info at https://arxiv.org/pdf/2006.13922.pdf\n * and https://compound.finance/governance/proposals/12\n *\n * @param _baseRate The interest rate.\n * @param _rateMultiplier The precision multiplier for base rate.\n * @param _lowUtilBaseRate The credit utilization rate (CUR) low value.\n * @param _lowUtilRateMultiplier The precision multiplier for low util base rate.\n * @param _targetLevel The target level.\n * @param _kinkLevel The level that interest rates cluster on kinked model.\n * @param _maxScaleRate The maximum rate of the scale.\n * */\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; /// 80 ether\n kinkLevel = _kinkLevel; /// 90 ether\n maxScaleRate = _maxScaleRate; /// 100 ether\n }\n\n /**\n * @notice Set the pause flag for a function to true or false.\n *\n * @dev Combining the hash of \"iToken_FunctionPause\" string and a function\n * selector gets a slot to write a flag for pause state.\n *\n * @param funcId The ID of a function, the selector.\n * @param isPaused true/false value of the flag.\n * */\n function toggleFunctionPause(\n string memory funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyPauserOrOwner {\n bool paused;\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n paused := sload(slot)\n }\n require(paused != isPaused, \"isPaused is already set to that value\");\n assembly {\n sstore(slot, isPaused)\n }\n emit ToggledFunctionPaused(funcId, !isPaused, isPaused);\n }\n\n /**\n * Set the transaction limit per token address.\n * @param addresses The token addresses.\n * @param limits The limit denominated in the currency of the token address.\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyAdmin\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n\n /**\n *\t@notice Update the loan token parameters.\n *\t@param _name The new name of the loan token.\n *\t@param _symbol The new symbol of the loan token.\n * */\n function changeLoanTokenNameAndSymbol(string memory _name, string memory _symbol)\n public\n onlyAdmin\n {\n name = _name;\n symbol = _symbol;\n }\n\n /**\n * @notice Withdraws RBTC from the contract by Multisig.\n * @param _receiverAddress The address where the rBTC has to be transferred.\n * @param _amount The amount of rBTC to be transferred.\n */\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external onlyOwner {\n require(_receiverAddress != address(0), \"receiver address invalid\");\n require(_amount > 0, \"non-zero withdraw amount expected\");\n require(_amount <= address(this).balance, \"withdraw amount cannot exceed balance\");\n _receiverAddress.transfer(_amount);\n emit WithdrawRBTCTo(_receiverAddress, _amount);\n }\n\n /**\n * @notice sets the liquidity mining contract address\n * @param LMAddress the address of the liquidity mining contract\n */\n function setLiquidityMiningAddress(address LMAddress) external onlyOwner {\n liquidityMiningAddress = LMAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for liquidityMiningAddress\n\n\t * @return liquidityMiningAddress\n\t */\n function getLiquidityMiningAddress() public view returns (address) {\n return liquidityMiningAddress;\n }\n\n /**\n * @notice sets the staking contract address\n * @param _stakingContractAddress the address of the staking contract\n */\n function setStakingContractAddress(address _stakingContractAddress) external onlyOwner {\n stakingContractAddress = _stakingContractAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for stakingContractAddress\n\n\t * @return stakingContractAddress\n\t */\n function getStakingContractAddress() public view returns (address) {\n return stakingContractAddress;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param funcId The function ID, the selector.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function checkPause(string memory funcId) public view returns (bool isPaused) {\n bytes4 sig = bytes4(keccak256(abi.encodePacked(funcId)));\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n isPaused := sload(slot)\n }\n return isPaused;\n }\n}\n" + }, + "contracts/connectors/loantoken/Pausable.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Pausable contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * The contract implements pausable functionality by reading on slots the\n * pause state of contract functions.\n * */\ncontract Pausable {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 internal constant Pausable_FunctionPause =\n 0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047;\n\n modifier pausable(bytes4 sig) {\n require(!_isPaused(sig), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param sig The function ID, the selector on bytes4.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function _isPaused(bytes4 sig) internal view returns (bool isPaused) {\n bytes32 slot = keccak256(abi.encodePacked(sig, Pausable_FunctionPause));\n assembly {\n isPaused := sload(slot)\n }\n }\n}\n" + }, + "contracts/core/Objects.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./objects/LoanStruct.sol\";\nimport \"./objects/LoanParamsStruct.sol\";\nimport \"./objects/OrderStruct.sol\";\nimport \"./objects/LenderInterestStruct.sol\";\nimport \"./objects/LoanInterestStruct.sol\";\n\n/**\n * @title Objects contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract inherints and aggregates several structures needed to handle\n * loans on the protocol.\n * */\ncontract Objects is\n LoanStruct,\n LoanParamsStruct,\n OrderStruct,\n LenderInterestStruct,\n LoanInterestStruct\n{\n\n}\n" + }, + "contracts/core/objects/LenderInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Lender Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Lender Interest.\n * */\ncontract LenderInterestStruct {\n struct LenderInterest {\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\n uint256 paidTotal; /// Total interest paid so far for asset.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Interest.\n * */\ncontract LoanInterestStruct {\n struct LoanInterest {\n uint256 owedPerDay; /// Interest owed per day for loan.\n uint256 depositTotal; /// Total escrowed interest for loan.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanParamsStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Parameters.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Parameters.\n * */\ncontract LoanParamsStruct {\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n}\n" + }, + "contracts/core/objects/LoanStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Object.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Object.\n * */\ncontract LoanStruct {\n struct Loan {\n bytes32 id; /// ID of the loan.\n bytes32 loanParamsId; /// The linked loan params ID.\n bytes32 pendingTradesId; /// The linked pending trades ID.\n bool active; /// If false, the loan has been fully closed.\n uint256 principal; /// Total borrowed amount outstanding.\n uint256 collateral; /// Total collateral escrowed for the loan.\n uint256 startTimestamp; /// Loan start time.\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\n uint256 startMargin; /// Initial margin when the loan opened.\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\n address borrower; /// Borrower of this loan.\n address lender; /// Lender of this loan.\n }\n}\n" + }, + "contracts/core/objects/OrderStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Order.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Order.\n * */\ncontract OrderStruct {\n struct Order {\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\n uint256 interestRate; /// Interest rate defined by the creator of this order.\n uint256 minLoanTerm; /// Minimum loan term allowed.\n uint256 maxLoanTerm; /// Maximum loan term allowed.\n uint256 createdTimestamp; /// Timestamp when this order was created.\n uint256 expirationTimestamp; /// Timestamp when this order expires.\n }\n}\n" + }, + "contracts/core/Protocol.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./State.sol\";\n\n/**\n * @title Sovryn Protocol contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the proxy functionality to deploy Protocol anchor\n * and logic apart, turning it upgradable.\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822\n * */\ncontract sovrynProtocol is State {\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = logicTargets[msg.sig];\n require(target != address(0), \"target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice External owner target initializer.\n * @param target The target addresses.\n * */\n function replaceContract(address target) external onlyOwner {\n (bool success, ) =\n target.delegatecall(abi.encodeWithSignature(\"initialize(address)\", target));\n require(success, \"setup failed\");\n }\n\n /**\n * @notice External owner setter for target addresses.\n * @param sigsArr The array of signatures.\n * @param targetsArr The array of addresses.\n * */\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr)\n external\n onlyOwner\n {\n require(sigsArr.length == targetsArr.length, \"count mismatch\");\n\n for (uint256 i = 0; i < sigsArr.length; i++) {\n _setTarget(bytes4(keccak256(abi.encodePacked(sigsArr[i]))), targetsArr[i]);\n }\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(string calldata sig) external view returns (address) {\n return logicTargets[bytes4(keccak256(abi.encodePacked(sig)))];\n }\n}\n" + }, + "contracts/core/State.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./Objects.sol\";\nimport \"../mixins/EnumerableAddressSet.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/ReentrancyGuard.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title State contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage values of the Protocol.\n * */\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\n using SafeMath for uint256;\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n\n /// Handles asset reference price lookups.\n address public priceFeeds;\n\n /// Handles asset swaps using dex liquidity.\n address public swapsImpl;\n\n /// Contract registry address of the Sovryn swap network.\n address public sovrynSwapContractRegistryAddress;\n\n /// Implementations of protocol functions.\n mapping(bytes4 => address) public logicTargets;\n\n /// Loans: loanId => Loan\n mapping(bytes32 => Loan) public loans;\n\n /// Loan parameters: loanParamsId => LoanParams\n mapping(bytes32 => LoanParams) public loanParams;\n\n /// lender => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\n\n /// borrower => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\n\n /// loanId => delegated => approved\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\n\n /**\n *** Interest ***\n **/\n\n /// lender => loanToken => LenderInterest object\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\n\n /// loanId => LoanInterest object\n mapping(bytes32 => LoanInterest) public loanInterest;\n\n /**\n *** Internals ***\n **/\n\n /// Implementations set.\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\n\n /// Active loans set.\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\n\n /// Lender loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\n\n /// Borrow loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\n\n /// User loan params set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\n\n /// Address controlling fee withdrawals.\n address public feesController;\n\n /// 10% fee /// Fee taken from lender interest payments.\n uint256 public lendingFeePercent = 10**19;\n\n /// Total interest fees received and not withdrawn per asset.\n mapping(address => uint256) public lendingFeeTokensHeld;\n\n /// Total interest fees withdraw per asset.\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\n mapping(address => uint256) public lendingFeeTokensPaid;\n\n /// 0.15% fee /// Fee paid for each trade.\n uint256 public tradingFeePercent = 15 * 10**16;\n\n /// Total trading fees received and not withdrawn per asset.\n mapping(address => uint256) public tradingFeeTokensHeld;\n\n /// Total trading fees withdraw per asset\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\n mapping(address => uint256) public tradingFeeTokensPaid;\n\n /// 0.09% fee /// Origination fee paid for each loan.\n uint256 public borrowingFeePercent = 9 * 10**16;\n\n /// Total borrowing fees received and not withdrawn per asset.\n mapping(address => uint256) public borrowingFeeTokensHeld;\n\n /// Total borrowing fees withdraw per asset.\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\n mapping(address => uint256) public borrowingFeeTokensPaid;\n\n /// Current protocol token deposit balance.\n uint256 public protocolTokenHeld;\n\n /// Lifetime total payout of protocol token.\n uint256 public protocolTokenPaid;\n\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\n uint256 public affiliateFeePercent = 5 * 10**18;\n\n /// 5% collateral discount /// Discount on collateral for liquidators.\n uint256 public liquidationIncentivePercent = 5 * 10**18;\n\n /// loanPool => underlying\n mapping(address => address) public loanPoolToUnderlying;\n\n /// underlying => loanPool\n mapping(address => address) public underlyingToLoanPool;\n\n /// Loan pools set.\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\n\n /// Supported tokens for swaps.\n mapping(address => bool) public supportedTokens;\n\n /// % disagreement between swap rate and reference rate.\n uint256 public maxDisagreement = 5 * 10**18;\n\n /// Used as buffer for swap source amount estimations.\n uint256 public sourceBuffer = 10000;\n\n /// Maximum support swap size in rBTC\n uint256 public maxSwapSize = 50 ether;\n\n /// Nonce per borrower. Used for loan id creation.\n mapping(address => uint256) public borrowerNonce;\n\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\n uint256 public rolloverBaseReward = 16800000000000;\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\n\n IWrbtcERC20 public wrbtcToken;\n address public protocolTokenAddress;\n\n /// 50% fee rebate\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\n uint256 public feeRebatePercent = 50 * 10**18;\n\n address public admin;\n\n /// For modules interaction.\n address public protocolAddress;\n\n /**\n *** Affiliates ***\n **/\n\n /// The flag is set on the user's first trade.\n mapping(address => bool) public userNotFirstTradeFlag;\n\n /// User => referrer (affiliate).\n mapping(address => address) public affiliatesUserReferrer;\n\n /// List of referral addresses affiliated to the referrer.\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\n\n /// @dev Referral threshold for paying out to the referrer.\n /// The referrer reward is being accumulated and locked until the threshold is passed.\n uint256 public minReferralsToPayout = 3;\n\n /// @dev Total affiliate SOV rewards that held in the protocol\n /// (Because the minimum referrals is less than the rule)\n mapping(address => uint256) public affiliateRewardsHeld;\n\n /// @dev For affiliates SOV Bonus proccess.\n address public sovTokenAddress;\n address public lockedSOVAddress;\n\n /// @dev 20% fee share of trading token fee.\n /// Fee share of trading token fee for affiliate program.\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\n\n /// @dev Addresses of tokens in which commissions were paid to referrers.\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\n\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\n\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\n bool public pause; //Flag to pause all protocol modules\n\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\n\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\n uint256 internal tradingRebateRewardsBasisPoint;\n\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\n /// Will be used in internal swap.\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\n\n address internal pauser;\n\n /**\n * @notice Add signature and target to storage.\n * @dev Protocol is a proxy and requires a way to add every\n * module function dynamically during deployment.\n * */\n function _setTarget(bytes4 sig, address target) internal {\n logicTargets[sig] = target;\n\n if (target != address(0)) {\n logicTargetsSet.addBytes32(bytes32(sig));\n } else {\n logicTargetsSet.removeBytes32(bytes32(sig));\n }\n }\n\n modifier onlyAdminOrOwner() {\n require(isOwner() || admin == (msg.sender), \"unauthorized\");\n _;\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || pauser == (msg.sender), \"unauthorized\");\n _;\n }\n}\n" + }, + "contracts/escrow/Escrow.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Ethereum Pool to accept SOV Token.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice You can use this contract for deposit of SOV tokens for some time and withdraw later.\n */\ncontract Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalDeposit;\n /// @notice The release timestamp for the tokens deposited.\n uint256 public releaseTime;\n /// @notice The amount of token we would be accepting as deposit at max.\n uint256 public depositLimit;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The multisig contract which handles the fund.\n address public multisig;\n\n /// @notice The user balances.\n mapping(address => uint256) userBalances;\n\n /// @notice The current contract status.\n /// @notice Deployed - Deployed the contract.\n /// @notice Deposit - Time to deposit in the contract by the users.\n /// @notice Holding - Deposit is closed and now the holding period starts.\n /// @notice Withdraw - Time to withdraw in the contract by the users.\n /// @notice Expired - The contract is now closed completely.\n enum Status { Deployed, Deposit, Holding, Withdraw, Expired }\n Status public status;\n\n /* Events */\n\n /// @notice Emitted when the contract deposit starts.\n event EscrowActivated();\n\n /// @notice Emitted when the contract is put in holding state. No new token deposit accepted by User.\n event EscrowInHoldingState();\n\n /// @notice Emitted when the contract is put in withdraw state. Users can now withdraw tokens.\n event EscrowInWithdrawState();\n\n /// @notice Emitted when the contract is expired after withdraws are made/total token transfer.\n event EscrowFundExpired();\n\n /// @notice Emitted when a new multisig is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newMultisig The address which is added as the new multisig.\n /// @dev Can only be initiated by the current multisig.\n event NewMultisig(address indexed _initiator, address indexed _newMultisig);\n\n /// @notice Emitted when the release timestamp is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseTimestamp The updated release timestamp for the withdraw.\n event TokenReleaseUpdated(address indexed _initiator, uint256 _releaseTimestamp);\n\n /// @notice Emitted when the deposit limit is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _depositLimit The updated deposit limit.\n event TokenDepositLimitUpdated(address indexed _initiator, uint256 _depositLimit);\n\n /// @notice Emitted when a new token deposit is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when we reach the token deposit limit.\n event DepositLimitReached();\n\n /// @notice Emitted when a token withdraw is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdrawByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyMultisig() {\n require(msg.sender == multisig, \"Only Multisig can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n modifier checkRelease() {\n require(\n releaseTime != 0 && releaseTime <= block.timestamp,\n \"The release time has not started yet.\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_multisig != address(0), \"Invalid Multisig Address.\");\n\n SOV = IERC20(_SOV);\n multisig = _multisig;\n\n emit NewMultisig(msg.sender, _multisig);\n\n releaseTime = _releaseTime;\n depositLimit = _depositLimit;\n\n status = Status.Deployed;\n }\n\n /**\n * @notice This function is called once after deployment for starting the deposit action.\n * @dev Without calling this function, the contract will not start accepting tokens.\n */\n function init() external onlyMultisig checkStatus(Status.Deployed) {\n status = Status.Deposit;\n\n emit EscrowActivated();\n }\n\n /**\n * @notice Update Multisig.\n * @param _newMultisig The new owner of the tokens & contract.\n */\n function updateMultisig(address _newMultisig) external onlyMultisig {\n require(_newMultisig != address(0), \"New Multisig address invalid.\");\n\n multisig = _newMultisig;\n\n emit NewMultisig(msg.sender, _newMultisig);\n }\n\n /**\n * @notice Update Release Timestamp.\n * @param _newReleaseTime The new release timestamp for token release.\n * @dev Zero is also a valid timestamp, if the release time is not scheduled yet.\n */\n function updateReleaseTimestamp(uint256 _newReleaseTime) external onlyMultisig {\n releaseTime = _newReleaseTime;\n\n emit TokenReleaseUpdated(msg.sender, _newReleaseTime);\n }\n\n /**\n * @notice Update Deposit Limit.\n * @param _newDepositLimit The new deposit limit.\n * @dev IMPORTANT: Should not decrease than already deposited.\n */\n function updateDepositLimit(uint256 _newDepositLimit) external onlyMultisig {\n require(\n _newDepositLimit >= totalDeposit,\n \"Deposit already higher than the limit trying to be set.\"\n );\n depositLimit = _newDepositLimit;\n\n emit TokenDepositLimitUpdated(msg.sender, _newDepositLimit);\n }\n\n /**\n * @notice Deposit tokens to this contract by User.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the user inorder for this function to work.\n * These tokens can be withdrawn/transferred during Holding State by the Multisig.\n */\n function depositTokens(uint256 _amount) external checkStatus(Status.Deposit) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n uint256 amount = _amount;\n\n if (totalDeposit.add(_amount) >= depositLimit) {\n amount = depositLimit.sub(totalDeposit);\n emit DepositLimitReached();\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n userBalances[msg.sender] = userBalances[msg.sender].add(amount);\n totalDeposit = totalDeposit.add(amount);\n\n emit TokenDeposit(msg.sender, amount);\n }\n\n /**\n * @notice Update contract state to Holding.\n * @dev Once called, the contract no longer accepts any more deposits.\n * The multisig can now withdraw tokens from the contract after the contract is in Holding State.\n */\n function changeStateToHolding() external onlyMultisig checkStatus(Status.Deposit) {\n status = Status.Holding;\n\n emit EscrowInHoldingState();\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred. Zero address if the withdraw is to be done in Multisig.\n * @dev Can only be called after the token state is changed to Holding.\n */\n function withdrawTokensByMultisig(address _receiverAddress)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n address receiverAddress = msg.sender;\n if (_receiverAddress != address(0)) {\n receiverAddress = _receiverAddress;\n }\n\n uint256 value = SOV.balanceOf(address(this));\n /// Sending the amount to multisig.\n bool txStatus = SOV.transfer(receiverAddress, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdrawByMultisig(msg.sender, value);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n * Once the token deposit is higher than the total deposits done, the contract state is changed to Withdraw.\n */\n function depositTokensByMultisig(uint256 _amount)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDepositByMultisig(msg.sender, _amount);\n\n if (SOV.balanceOf(address(this)) >= totalDeposit) {\n status = Status.Withdraw;\n emit EscrowInWithdrawState();\n }\n }\n\n /**\n * @notice Withdraws token from the contract by User.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokens() public checkRelease checkStatus(Status.Withdraw) {\n uint256 amount = userBalances[msg.sender];\n userBalances[msg.sender] = 0;\n bool txStatus = SOV.transfer(msg.sender, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdraw(msg.sender, amount);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token balance of a particular user.\n * @return _addr The user address whose balance has to be checked.\n */\n function getUserBalance(address _addr) external view returns (uint256 balance) {\n return userBalances[_addr];\n }\n}\n" + }, + "contracts/escrow/EscrowReward.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Escrow.sol\";\nimport \"../locked/ILockedSOV.sol\";\n\n/**\n * @title A reward distribution contract for Sovryn Ethereum Pool Escrow Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice Multisig can use this contract for depositing of Reward tokens based on the total token deposit.\n */\ncontract EscrowReward is Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total reward tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalRewardDeposit;\n\n /// @notice The Locked SOV contract.\n ILockedSOV public lockedSOV;\n\n /* Events */\n\n /// @notice Emitted when the Locked SOV Contract address is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _lockedSOV The address of the Locked SOV Contract.\n event LockedSOVUpdated(address indexed _initiator, address indexed _lockedSOV);\n\n /// @notice Emitted when a new reward token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event RewardDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a Reward token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event RewardTokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _lockedSOV The Locked SOV Contract address.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _lockedSOV,\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public Escrow(_SOV, _multisig, _releaseTime, _depositLimit) {\n if (_lockedSOV != address(0)) {\n lockedSOV = ILockedSOV(_lockedSOV);\n }\n }\n\n /**\n * @notice Set the Locked SOV Contract Address if not already done.\n * @param _lockedSOV The Locked SOV Contract address.\n */\n function updateLockedSOV(address _lockedSOV) external onlyMultisig {\n require(_lockedSOV != address(0), \"Invalid Reward Token Address.\");\n\n lockedSOV = ILockedSOV(_lockedSOV);\n\n emit LockedSOVUpdated(msg.sender, _lockedSOV);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n */\n function depositRewardByMultisig(uint256 _amount) external onlyMultisig {\n require(\n status != Status.Withdraw,\n \"Reward Token deposit is only allowed before User Withdraw starts.\"\n );\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n totalRewardDeposit = totalRewardDeposit.add(_amount);\n txStatus = SOV.approve(address(lockedSOV), totalRewardDeposit);\n require(txStatus, \"Token Approval was not successful.\");\n\n emit RewardDepositByMultisig(msg.sender, _amount);\n }\n\n /**\n * @notice Withdraws token and reward from the contract by User. Reward is gone to lockedSOV contract for future vesting.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokensAndReward() external checkRelease checkStatus(Status.Withdraw) {\n // Reward calculation have to be done initially as the User Balance is zeroed out .\n uint256 reward = userBalances[msg.sender].mul(totalRewardDeposit).div(totalDeposit);\n withdrawTokens();\n\n lockedSOV.depositSOV(msg.sender, reward);\n\n emit RewardTokenWithdraw(msg.sender, reward);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the reward a particular user can get.\n * @param _addr The address of the user whose reward is to be read.\n * @return reward The reward received by the user.\n */\n function getReward(address _addr) external view returns (uint256 reward) {\n if (userBalances[_addr].mul(totalRewardDeposit) == 0) {\n return 0;\n }\n return userBalances[_addr].mul(totalRewardDeposit).div(totalDeposit);\n }\n}\n" + }, + "contracts/events/AffiliatesEvents.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\ncontract AffiliatesEvents is ModulesCommonEvents {\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\n\n event SetAffiliatesReferrerFail(\n address indexed user,\n address indexed referrer,\n bool alreadySet,\n bool userNotFirstTrade\n );\n\n event SetUserNotFirstTradeFlag(address indexed user);\n\n event PayTradingFeeToAffiliate(\n address indexed referrer,\n address trader,\n address indexed token,\n bool indexed isHeld,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountPaid\n );\n\n event PayTradingFeeToAffiliateFail(\n address indexed referrer,\n address trader,\n address indexed token,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountTryingToPaid\n );\n\n event WithdrawAffiliatesReferrerTokenFees(\n address indexed referrer,\n address indexed receiver,\n address indexed tokenAddress,\n uint256 amount\n );\n}\n" + }, + "contracts/events/FeesEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Fees Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for fee payments.\n * */\ncontract FeesEvents {\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\n\n event PayTradingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event PayBorrowingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event EarnReward(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n\n event EarnRewardFail(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n}\n" + }, + "contracts/events/LoanClosingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Closing Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan closing operations.\n * */\ncontract LoanClosingsEvents is ModulesCommonEvents {\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\n event CloseWithDeposit(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address closer,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\n event CloseWithSwap(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n address closer,\n uint256 positionCloseSize,\n uint256 loanCloseAmount,\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\n uint256 currentLeverage\n );\n\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\n event Liquidate(\n address indexed user,\n address indexed liquidator,\n bytes32 indexed loanId,\n address lender,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n event Rollover(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n uint256 principal,\n uint256 collateral,\n uint256 endTimestamp,\n address rewardReceiver,\n uint256 reward\n );\n\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\n}\n" + }, + "contracts/events/LoanMaintenanceEvents.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Maintenance Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan maintenance operations.\n * */\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\n}\n" + }, + "contracts/events/LoanOpeningsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Openings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan openings operations.\n * */\ncontract LoanOpeningsEvents is ModulesCommonEvents {\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\n event Borrow(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 newCollateral,\n uint256 interestRate,\n uint256 interestDuration,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\n event Trade(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n uint256 positionSize,\n uint256 borrowedAmount,\n uint256 interestRate,\n uint256 settlementDate,\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\n uint256 entryLeverage,\n uint256 currentLeverage\n );\n\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\n event DelegatedManagerSet(\n bytes32 indexed loanId,\n address indexed delegator,\n address indexed delegated,\n bool isActive\n );\n}\n" + }, + "contracts/events/LoanSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan settings operations.\n * */\ncontract LoanSettingsEvents is ModulesCommonEvents {\n event LoanParamsSetup(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\n\n event LoanParamsDisabled(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\n}\n" + }, + "contracts/events/ModulesCommonEvents.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title The common events for all modules\n * @notice This contract contains the events which will be used by all modules\n **/\n\ncontract ModulesCommonEvents {\n event ProtocolModuleContractReplaced(\n address indexed prevModuleContractAddress,\n address indexed newModuleContractAddress,\n bytes32 indexed module\n );\n}\n" + }, + "contracts/events/ProtocolSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title The Protocol Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for protocol settings operations.\n * */\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\n\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\n\n event SetLoanPool(\n address indexed sender,\n address indexed loanPool,\n address indexed underlying\n );\n\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\n\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateTradingTokenFeePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetLiquidationIncentivePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetFeesController(\n address indexed sender,\n address indexed oldController,\n address indexed newController\n );\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWethToken,\n address indexed newWethToken\n );\n\n event SetSovrynSwapContractRegistryAddress(\n address indexed sender,\n address indexed oldSovrynSwapContractRegistryAddress,\n address indexed newSovrynSwapContractRegistryAddress\n );\n\n event SetProtocolTokenAddress(\n address indexed sender,\n address indexed oldProtocolToken,\n address indexed newProtocolToken\n );\n\n event WithdrawFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 lendingAmount,\n uint256 tradingAmount,\n uint256 borrowingAmount,\n uint256 wRBTCConverted\n );\n\n event WithdrawLendingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawTradingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawBorrowingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetRebatePercent(\n address indexed sender,\n uint256 oldRebatePercent,\n uint256 newRebatePercent\n );\n\n event SetSpecialRebates(\n address indexed sender,\n address indexed sourceToken,\n address indexed destToken,\n uint256 oldSpecialRebatesPercent,\n uint256 newSpecialRebatesPercent\n );\n\n event SetProtocolAddress(\n address indexed sender,\n address indexed oldProtocol,\n address indexed newProtocol\n );\n\n event SetMinReferralsToPayoutAffiliates(\n address indexed sender,\n uint256 oldMinReferrals,\n uint256 newMinReferrals\n );\n\n event SetSOVTokenAddress(\n address indexed sender,\n address indexed oldTokenAddress,\n address indexed newTokenAddress\n );\n\n event SetLockedSOVAddress(\n address indexed sender,\n address indexed oldAddress,\n address indexed newAddress\n );\n\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\n\n event SetTradingRebateRewardsBasisPoint(\n address indexed sender,\n uint256 oldBasisPoint,\n uint256 newBasisPoint\n );\n\n event SetRolloverFlexFeePercent(\n address indexed sender,\n uint256 oldRolloverFlexFeePercent,\n uint256 newRolloverFlexFeePercent\n );\n\n event SetDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event RemoveDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n}\n" + }, + "contracts/events/SwapsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Swaps Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for swap operations.\n * */\ncontract SwapsEvents is ModulesCommonEvents {\n event LoanSwap(\n bytes32 indexed loanId,\n address indexed sourceToken,\n address indexed destToken,\n address borrower,\n uint256 sourceAmount,\n uint256 destAmount\n );\n\n event ExternalSwap(\n address indexed user,\n address indexed sourceToken,\n address indexed destToken,\n uint256 sourceAmount,\n uint256 destAmount\n );\n}\n" + }, + "contracts/farm/ILiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\n\ninterface ILiquidityMining {\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external;\n\n function onTokensDeposited(address _user, uint256 _amount) external;\n\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/farm/LiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./LiquidityMiningStorage.sol\";\nimport \"./ILiquidityMining.sol\";\n\ncontract LiquidityMining is ILiquidityMining, LiquidityMiningStorage {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n /* Constants */\n\n uint256 public constant PRECISION = 1e12;\n // Bonus multiplier for early liquidity providers.\n // During bonus period each passed block will be calculated like N passed blocks, where N = BONUS_MULTIPLIER\n uint256 public constant BONUS_BLOCK_MULTIPLIER = 10;\n\n uint256 public constant SECONDS_PER_BLOCK = 30;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event PoolTokenAdded(address indexed user, address indexed poolToken, uint256 allocationPoint);\n event PoolTokenUpdated(\n address indexed user,\n address indexed poolToken,\n uint256 newAllocationPoint,\n uint256 oldAllocationPoint\n );\n event Deposit(address indexed user, address indexed poolToken, uint256 amount);\n event RewardClaimed(address indexed user, address indexed poolToken, uint256 amount);\n event Withdraw(address indexed user, address indexed poolToken, uint256 amount);\n event EmergencyWithdraw(\n address indexed user,\n address indexed poolToken,\n uint256 amount,\n uint256 accumulatedReward\n );\n\n /* Functions */\n\n /**\n * @notice Initialize mining.\n *\n * @param _SOV The SOV token.\n * @param _rewardTokensPerBlock The number of reward tokens per block.\n * @param _startDelayBlocks The number of blocks should be passed to start\n * mining.\n * @param _numberOfBonusBlocks The number of blocks when each block will\n * be calculated as N blocks (BONUS_BLOCK_MULTIPLIER).\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n * SOV rewards are not paid directly to liquidity providers. Instead they\n * are deposited into a lockedSOV vault contract.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n */\n function initialize(\n IERC20 _SOV,\n uint256 _rewardTokensPerBlock,\n uint256 _startDelayBlocks,\n uint256 _numberOfBonusBlocks,\n address _wrapper,\n ILockedSOV _lockedSOV,\n uint256 _unlockedImmediatelyPercent\n ) external onlyAuthorized {\n /// @dev Non-idempotent function. Must be called just once.\n require(address(SOV) == address(0), \"Already initialized\");\n require(address(_SOV) != address(0), \"Invalid token address\");\n require(_startDelayBlocks > 0, \"Invalid start block\");\n require(\n _unlockedImmediatelyPercent < 10000,\n \"Unlocked immediately percent has to be less than 10000.\"\n );\n\n SOV = _SOV;\n rewardTokensPerBlock = _rewardTokensPerBlock;\n startBlock = block.number + _startDelayBlocks;\n bonusEndBlock = startBlock + _numberOfBonusBlocks;\n wrapper = _wrapper;\n lockedSOV = _lockedSOV;\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets lockedSOV contract.\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n */\n function setLockedSOV(ILockedSOV _lockedSOV) external onlyAuthorized {\n require(address(_lockedSOV) != address(0), \"Invalid lockedSOV Address.\");\n lockedSOV = _lockedSOV;\n }\n\n /**\n * @notice Sets unlocked immediately percent.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setUnlockedImmediatelyPercent(uint256 _unlockedImmediatelyPercent)\n external\n onlyAuthorized\n {\n require(\n _unlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets unlocked immediately percent overwrite for specific pool token.\n * @param _poolToken the address of pool token\n * @param _poolTokenUnlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setPoolTokenUnlockedImmediatelyPercent(\n address _poolToken,\n uint256 _poolTokenUnlockedImmediatelyPercent\n ) external onlyAuthorized {\n require(\n _poolTokenUnlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n poolTokensUnlockedImmediatelyPercent[_poolToken] = _poolTokenUnlockedImmediatelyPercent;\n }\n\n /**\n * @notice sets wrapper proxy contract\n * @dev can be set to zero address to remove wrapper\n */\n function setWrapper(address _wrapper) external onlyAuthorized {\n wrapper = _wrapper;\n }\n\n /**\n * @notice stops mining by setting end block\n */\n function stopMining() external onlyAuthorized {\n require(endBlock == 0, \"Already stopped\");\n\n endBlock = block.number;\n }\n\n /**\n * @notice Transfers SOV tokens to given address.\n * Owner use this function to withdraw SOV from LM contract\n * into another account.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) external onlyAuthorized {\n require(_receiver != address(0), \"Receiver address invalid\");\n require(_amount != 0, \"Amount invalid\");\n\n /// @dev Do not transfer more SOV than available.\n uint256 SOVBal = SOV.balanceOf(address(this));\n if (_amount > SOVBal) {\n _amount = SOVBal;\n }\n\n /// @dev The actual transfer.\n require(SOV.transfer(_receiver, _amount), \"Transfer failed\");\n\n /// @dev Event log.\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Get the missed SOV balance of LM contract.\n *\n * @return The amount of SOV tokens according to totalUsersBalance\n * in excess of actual SOV balance of the LM contract.\n * */\n function getMissedBalance() external view returns (uint256) {\n uint256 balance = SOV.balanceOf(address(this));\n return balance >= totalUsersBalance ? 0 : totalUsersBalance.sub(balance);\n }\n\n /**\n * @notice adds a new lp to the pool. Can only be called by the owner or an admin\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _withUpdate the flag whether we need to update all pools\n */\n function add(\n address _poolToken,\n uint96 _allocationPoint,\n bool _withUpdate\n ) external onlyAuthorized {\n require(_allocationPoint > 0, \"Invalid allocation point\");\n require(_poolToken != address(0), \"Invalid token address\");\n require(poolIdList[_poolToken] == 0, \"Token already added\");\n\n if (_withUpdate) {\n updateAllPools();\n }\n\n uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;\n totalAllocationPoint = totalAllocationPoint.add(_allocationPoint);\n\n poolInfoList.push(\n PoolInfo({\n poolToken: IERC20(_poolToken),\n allocationPoint: _allocationPoint,\n lastRewardBlock: lastRewardBlock,\n accumulatedRewardPerShare: 0\n })\n );\n //indexing starts from 1 in order to check whether token was already added\n poolIdList[_poolToken] = poolInfoList.length;\n\n emit PoolTokenAdded(msg.sender, _poolToken, _allocationPoint);\n }\n\n /**\n * @notice updates the given pool's reward tokens allocation point\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function update(\n address _poolToken,\n uint96 _allocationPoint,\n bool _updateAllFlag\n ) external onlyAuthorized {\n if (_updateAllFlag) {\n updateAllPools();\n } else {\n updatePool(_poolToken);\n }\n _updateToken(_poolToken, _allocationPoint);\n }\n\n function _updateToken(address _poolToken, uint96 _allocationPoint) internal {\n uint256 poolId = _getPoolId(_poolToken);\n\n uint256 previousAllocationPoint = poolInfoList[poolId].allocationPoint;\n totalAllocationPoint = totalAllocationPoint.sub(previousAllocationPoint).add(\n _allocationPoint\n );\n poolInfoList[poolId].allocationPoint = _allocationPoint;\n\n emit PoolTokenUpdated(msg.sender, _poolToken, _allocationPoint, previousAllocationPoint);\n }\n\n /**\n * @notice updates the given pools' reward tokens allocation points\n * @param _poolTokens array of addresses of pool tokens\n * @param _allocationPoints array of allocation points (weight) for the given pools\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function updateTokens(\n address[] calldata _poolTokens,\n uint96[] calldata _allocationPoints,\n bool _updateAllFlag\n ) external onlyAuthorized {\n require(_poolTokens.length == _allocationPoints.length, \"Arrays mismatch\");\n\n if (_updateAllFlag) {\n updateAllPools();\n }\n uint256 length = _poolTokens.length;\n for (uint256 i = 0; i < length; i++) {\n if (!_updateAllFlag) {\n updatePool(_poolTokens[i]);\n }\n _updateToken(_poolTokens[i], _allocationPoints[i]);\n }\n }\n\n /**\n * @notice returns reward multiplier over the given _from to _to block\n * @param _from the first block for a calculation\n * @param _to the last block for a calculation\n */\n function _getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n internal\n view\n returns (uint256)\n {\n if (_from < startBlock) {\n _from = startBlock;\n }\n if (endBlock > 0 && _to > endBlock) {\n _to = endBlock;\n }\n if (_to <= bonusEndBlock) {\n return _to.sub(_from).mul(BONUS_BLOCK_MULTIPLIER);\n } else if (_from >= bonusEndBlock) {\n return _to.sub(_from);\n } else {\n return\n bonusEndBlock.sub(_from).mul(BONUS_BLOCK_MULTIPLIER).add(_to.sub(bonusEndBlock));\n }\n }\n\n function _getUserAccumulatedReward(uint256 _poolId, address _user)\n internal\n view\n returns (uint256)\n {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_user];\n\n uint256 accumulatedRewardPerShare = pool.accumulatedRewardPerShare;\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (block.number > pool.lastRewardBlock && poolTokenBalance != 0) {\n (, uint256 accumulatedRewardPerShare_) = _getPoolAccumulatedReward(pool);\n accumulatedRewardPerShare = accumulatedRewardPerShare.add(accumulatedRewardPerShare_);\n }\n\n return\n user.accumulatedReward.add(\n user.amount.mul(accumulatedRewardPerShare).div(PRECISION).sub(user.rewardDebt)\n );\n }\n\n /**\n * @notice returns accumulated reward\n * @param _poolToken the address of pool token\n * @param _user the user address\n */\n function getUserAccumulatedReward(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n uint256 poolId = _getPoolId(_poolToken);\n return _getUserAccumulatedReward(poolId, _user);\n }\n\n /**\n * @notice returns estimated reward\n * @param _poolToken the address of pool token\n * @param _amount the amount of tokens to be deposited\n * @param _duration the duration of liquidity providing in seconds\n */\n function getEstimatedReward(\n address _poolToken,\n uint256 _amount,\n uint256 _duration\n ) external view returns (uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n uint256 start = block.number;\n uint256 end = start.add(_duration.div(SECONDS_PER_BLOCK));\n (, uint256 accumulatedRewardPerShare) =\n _getPoolAccumulatedReward(pool, _amount, start, end);\n return _amount.mul(accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Updates reward variables for all pools.\n * @dev Be careful of gas spending!\n */\n function updateAllPools() public {\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n _updatePool(i);\n }\n }\n\n /**\n * @notice Updates reward variables of the given pool to be up-to-date\n * @param _poolToken the address of pool token\n */\n function updatePool(address _poolToken) public {\n uint256 poolId = _getPoolId(_poolToken);\n _updatePool(poolId);\n }\n\n function _updatePool(uint256 _poolId) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n\n //this pool has been updated recently\n if (block.number <= pool.lastRewardBlock) {\n return;\n }\n\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (poolTokenBalance == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n (uint256 accumulatedReward_, uint256 accumulatedRewardPerShare_) =\n _getPoolAccumulatedReward(pool);\n pool.accumulatedRewardPerShare = pool.accumulatedRewardPerShare.add(\n accumulatedRewardPerShare_\n );\n pool.lastRewardBlock = block.number;\n\n totalUsersBalance = totalUsersBalance.add(accumulatedReward_);\n }\n\n function _getPoolAccumulatedReward(PoolInfo storage _pool)\n internal\n view\n returns (uint256, uint256)\n {\n return _getPoolAccumulatedReward(_pool, 0, _pool.lastRewardBlock, block.number);\n }\n\n function _getPoolAccumulatedReward(\n PoolInfo storage _pool,\n uint256 _additionalAmount,\n uint256 _startBlock,\n uint256 _endBlock\n ) internal view returns (uint256, uint256) {\n uint256 passedBlocks = _getPassedBlocksWithBonusMultiplier(_startBlock, _endBlock);\n uint256 accumulatedReward =\n passedBlocks.mul(rewardTokensPerBlock).mul(_pool.allocationPoint).div(\n totalAllocationPoint\n );\n\n uint256 poolTokenBalance = _pool.poolToken.balanceOf(address(this));\n poolTokenBalance = poolTokenBalance.add(_additionalAmount);\n uint256 accumulatedRewardPerShare = accumulatedReward.mul(PRECISION).div(poolTokenBalance);\n return (accumulatedReward, accumulatedRewardPerShare);\n }\n\n /**\n * @notice deposits pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it or to msg.sender\n */\n function deposit(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n _deposit(_poolToken, _amount, _user, false);\n }\n\n /**\n * @notice if the lending pools directly mint/transfer tokens to this address, process it like a user deposit\n * @dev only callable by the pool which issues the tokens\n * @param _user the user address\n * @param _amount the minted amount\n */\n function onTokensDeposited(address _user, uint256 _amount) external {\n //the msg.sender is the pool token. if the msg.sender is not a valid pool token, _deposit will revert\n _deposit(msg.sender, _amount, _user, true);\n }\n\n /**\n * @notice internal function for depositing pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it\n * @param alreadyTransferred true if the pool tokens have already been transferred\n */\n function _deposit(\n address _poolToken,\n uint256 _amount,\n address _user,\n bool alreadyTransferred\n ) internal {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _user != address(0) ? _user : msg.sender;\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n\n _updatePool(poolId);\n //sends reward directly to the user\n _updateReward(pool, user);\n\n if (_amount > 0) {\n //receives pool tokens from msg.sender, it can be user or WrapperProxy contract\n if (!alreadyTransferred)\n pool.poolToken.safeTransferFrom(address(msg.sender), address(this), _amount);\n user.amount = user.amount.add(_amount);\n }\n _updateRewardDebt(pool, user);\n emit Deposit(userAddress, _poolToken, _amount);\n }\n\n /**\n * @notice transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimReward(address _poolToken, address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n _claimReward(poolId, userAddress, true);\n }\n\n function _claimReward(\n uint256 _poolId,\n address _userAddress,\n bool _isStakingTokens\n ) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_userAddress];\n\n _updatePool(_poolId);\n _updateReward(pool, user);\n _transferReward(address(pool.poolToken), user, _userAddress, _isStakingTokens, true);\n _updateRewardDebt(pool, user);\n }\n\n /**\n * @notice transfers reward tokens from all pools\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimRewardFromAllPools(address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n uint256 poolId = i;\n _claimReward(poolId, userAddress, false);\n }\n\n if (\n lockedSOV.getLockedBalance(userAddress) > 0 ||\n lockedSOV.getUnlockedBalance(userAddress) > 0\n ) {\n lockedSOV.withdrawAndStakeTokensFrom(userAddress);\n }\n }\n\n /**\n * @notice withdraws pool tokens and transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the user address will be used to process a withdrawal (can be passed only by wrapper contract)\n */\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n require(user.amount >= _amount, \"Not enough balance\");\n\n _updatePool(poolId);\n _updateReward(pool, user);\n _transferReward(_poolToken, user, userAddress, false, false);\n\n user.amount = user.amount.sub(_amount);\n\n //msg.sender is wrapper -> send to wrapper\n if (msg.sender == wrapper) {\n pool.poolToken.safeTransfer(address(msg.sender), _amount);\n }\n //msg.sender is user or pool token (lending pool) -> send to user\n else {\n pool.poolToken.safeTransfer(userAddress, _amount);\n }\n\n _updateRewardDebt(pool, user);\n emit Withdraw(userAddress, _poolToken, _amount);\n }\n\n function _getUserAddress(address _user) internal view returns (address) {\n address userAddress = msg.sender;\n if (_user != address(0)) {\n //only wrapper can pass _user parameter\n require(\n msg.sender == wrapper || poolIdList[msg.sender] != 0,\n \"only wrapper or pools may withdraw for a user\"\n );\n userAddress = _user;\n }\n return userAddress;\n }\n\n function _updateReward(PoolInfo storage pool, UserInfo storage user) internal {\n //update user accumulated reward\n if (user.amount > 0) {\n //add reward for the previous amount of deposited tokens\n uint256 accumulatedReward =\n user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION).sub(\n user.rewardDebt\n );\n user.accumulatedReward = user.accumulatedReward.add(accumulatedReward);\n }\n }\n\n function _updateRewardDebt(PoolInfo storage pool, UserInfo storage user) internal {\n //reward accumulated before amount update (should be subtracted during next reward calculation)\n user.rewardDebt = user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Send reward in SOV to the lockedSOV vault.\n * @param _user The user info, to get its reward share.\n * @param _userAddress The address of the user, to send SOV in its behalf.\n * @param _isStakingTokens The flag whether we need to stake tokens\n * @param _isCheckingBalance The flag whether we need to throw error or don't process reward if SOV balance isn't enough\n */\n function _transferReward(\n address _poolToken,\n UserInfo storage _user,\n address _userAddress,\n bool _isStakingTokens,\n bool _isCheckingBalance\n ) internal {\n uint256 userAccumulatedReward = _user.accumulatedReward;\n /// @dev get unlock immediate percent of the pool token.\n uint256 calculatedUnlockedImmediatelyPercent = calcUnlockedImmediatelyPercent(_poolToken);\n\n /// @dev Transfer if enough SOV balance on this LM contract.\n uint256 balance = SOV.balanceOf(address(this));\n if (balance >= userAccumulatedReward) {\n totalUsersBalance = totalUsersBalance.sub(userAccumulatedReward);\n _user.accumulatedReward = 0;\n\n /// @dev If calculatedUnlockedImmediatelyPercent is 100%, transfer the reward to the LP (user).\n /// else, deposit it into lockedSOV vault contract, but first\n /// SOV deposit must be approved to move the SOV tokens\n /// from this LM contract into the lockedSOV vault.\n if (calculatedUnlockedImmediatelyPercent == 10000) {\n SOV.transfer(_userAddress, userAccumulatedReward);\n } else {\n require(SOV.approve(address(lockedSOV), userAccumulatedReward), \"Approve failed\");\n lockedSOV.deposit(\n _userAddress,\n userAccumulatedReward,\n calculatedUnlockedImmediatelyPercent\n );\n\n if (_isStakingTokens) {\n lockedSOV.withdrawAndStakeTokensFrom(_userAddress);\n }\n }\n\n /// @dev Event log.\n emit RewardClaimed(_userAddress, _poolToken, userAccumulatedReward);\n } else {\n require(!_isCheckingBalance, \"Claiming reward failed\");\n }\n }\n\n /**\n * @notice withdraws pool tokens without transferring reward tokens\n * @param _poolToken the address of pool token\n * @dev EMERGENCY ONLY\n */\n function emergencyWithdraw(address _poolToken) external {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][msg.sender];\n\n _updatePool(poolId);\n _updateReward(pool, user);\n\n totalUsersBalance = totalUsersBalance.sub(user.accumulatedReward);\n uint256 userAmount = user.amount;\n uint256 userAccumulatedReward = user.accumulatedReward;\n user.amount = 0;\n user.rewardDebt = 0;\n user.accumulatedReward = 0;\n pool.poolToken.safeTransfer(address(msg.sender), userAmount);\n\n emit EmergencyWithdraw(msg.sender, _poolToken, userAmount, userAccumulatedReward);\n }\n\n /**\n * @notice returns pool id\n * @param _poolToken the address of pool token\n */\n function getPoolId(address _poolToken) external view returns (uint256) {\n return _getPoolId(_poolToken);\n }\n\n function _getPoolId(address _poolToken) internal view returns (uint256) {\n uint256 poolId = poolIdList[_poolToken];\n require(poolId > 0, \"Pool token not found\");\n return poolId - 1;\n }\n\n /**\n * @notice returns count of pool tokens\n */\n function getPoolLength() external view returns (uint256) {\n return poolInfoList.length;\n }\n\n /**\n * @notice returns list of pool token's info\n */\n function getPoolInfoList() external view returns (PoolInfo[] memory) {\n return poolInfoList;\n }\n\n /**\n * @notice returns pool info for the given token\n * @param _poolToken the address of pool token\n */\n function getPoolInfo(address _poolToken) external view returns (PoolInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return poolInfoList[poolId];\n }\n\n /**\n * @notice returns list of [amount, accumulatedReward] for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserBalanceList(address _user) external view returns (uint256[2][] memory) {\n uint256 length = poolInfoList.length;\n uint256[2][] memory userBalanceList = new uint256[2][](length);\n for (uint256 i = 0; i < length; i++) {\n userBalanceList[i][0] = userInfoMap[i][_user].amount;\n userBalanceList[i][1] = _getUserAccumulatedReward(i, _user);\n }\n return userBalanceList;\n }\n\n /**\n * @notice returns UserInfo for the given pool and user\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserInfo(address _poolToken, address _user) public view returns (UserInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return userInfoMap[poolId][_user];\n }\n\n /**\n * @notice returns list of UserInfo for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserInfoList(address _user) external view returns (UserInfo[] memory) {\n uint256 length = poolInfoList.length;\n UserInfo[] memory userInfoList = new UserInfo[](length);\n for (uint256 i = 0; i < length; i++) {\n userInfoList[i] = userInfoMap[i][_user];\n }\n return userInfoList;\n }\n\n /**\n * @notice returns accumulated reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardList(address _user) external view returns (uint256[] memory) {\n uint256 length = poolInfoList.length;\n uint256[] memory rewardList = new uint256[](length);\n for (uint256 i = 0; i < length; i++) {\n rewardList[i] = _getUserAccumulatedReward(i, _user);\n }\n return rewardList;\n }\n\n /**\n * @notice returns the pool token balance a user has on the contract\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n UserInfo memory ui = getUserInfo(_poolToken, _user);\n return ui.amount;\n }\n\n /**\n * @notice returns the accumulated liquid reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBePaidLiquid(address _user)\n external\n view\n returns (uint256)\n {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n calculatedUnlockedImmediatelyPercent.mul(_getUserAccumulatedReward(i, _user)).div(\n 10000\n )\n );\n }\n\n return result;\n }\n\n /**\n * @notice returns the accumulated vested reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBeVested(address _user) external view returns (uint256) {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n (10000 - calculatedUnlockedImmediatelyPercent)\n .mul(_getUserAccumulatedReward(i, _user))\n .div(10000)\n );\n }\n\n return result;\n }\n\n /**\n * @dev calculate the unlocked immediate percentage of specific pool token\n * use the poolTokensUnlockedImmediatelyPercent by default, if it is not set, then use the unlockedImmediatelyPercent\n */\n function calcUnlockedImmediatelyPercent(address _poolToken) public view returns (uint256) {\n uint256 poolTokenUnlockedImmediatelyPercent =\n poolTokensUnlockedImmediatelyPercent[_poolToken];\n return\n poolTokenUnlockedImmediatelyPercent > 0\n ? poolTokenUnlockedImmediatelyPercent\n : unlockedImmediatelyPercent;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningConfigToken.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/IERC20_.sol\";\n\n/**\n * @title Dummy token with 0 total supply.\n *\n * @dev We need this token for having a flexibility with LiquidityMining configuration\n */\ncontract LiquidityMiningConfigToken is IERC20_ {\n function totalSupply() external view returns (uint256) {\n return 0;\n }\n\n function balanceOf(address account) external view returns (uint256) {\n return 0;\n }\n\n function transfer(address recipient, uint256 amount) external returns (bool) {\n return false;\n }\n\n function allowance(address owner, address spender) external view returns (uint256) {\n return 0;\n }\n\n function approve(address spender, uint256 amount) external returns (bool) {\n return false;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool) {\n return false;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./LiquidityMiningStorage.sol\";\nimport \"../proxy/UpgradableProxy.sol\";\n\n/**\n * @dev LiquidityMining contract should be upgradable, use UpgradableProxy\n */\ncontract LiquidityMiningProxy is LiquidityMiningStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/farm/LiquidityMiningStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../utils/AdminRole.sol\";\n\ncontract LiquidityMiningStorage is AdminRole {\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many pool tokens the user has provided.\n uint256 rewardDebt; // Reward debt. See explanation below.\n uint256 accumulatedReward; //Reward that's ready to be transferred\n //\n // We do some fancy math here. Basically, any point in time, the amount of reward tokens\n // entitled to a user but is accumulated to be distributed is:\n //\n // accumulated reward = (user.amount * pool.accumulatedRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accumulatedRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the accumulated reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 poolToken; // Address of LP token contract.\n uint96 allocationPoint; // How many allocation points assigned to this pool. Amount of reward tokens to distribute per block.\n uint256 lastRewardBlock; // Last block number that reward tokens distribution occurs.\n uint256 accumulatedRewardPerShare; // Accumulated amount of reward tokens per share, times 1e12. See below.\n }\n\n // Rewards tokens created per block.\n uint256 public rewardTokensPerBlock;\n // The block number when reward token mining starts.\n uint256 public startBlock;\n // Block number when bonus reward token period ends.\n uint256 public bonusEndBlock;\n // Block number when reward token period ends.\n uint256 public endBlock;\n\n //Wrapper contract which will be a proxy between user and LM\n address public wrapper;\n\n // Info of each pool.\n PoolInfo[] public poolInfoList;\n // Mapping pool token address => pool id\n mapping(address => uint256) poolIdList;\n // Total allocation points. Must be the sum of all allocation points in all pools.\n uint256 public totalAllocationPoint;\n\n // Info of each user that stakes LP tokens.\n mapping(uint256 => mapping(address => UserInfo)) public userInfoMap;\n // Total balance this contract should have to handle withdrawal for all users\n uint256 public totalUsersBalance;\n\n /// @dev The SOV token\n IERC20 public SOV;\n\n /// @dev The locked vault contract to deposit LP's rewards into.\n ILockedSOV public lockedSOV;\n\n // The % which determines how much will be unlocked immediately.\n /// @dev 10000 is 100%\n uint256 public unlockedImmediatelyPercent;\n\n /// @dev overwrite the unlockedImmediatelyPercent for specific token.\n mapping(address => uint256) public poolTokensUnlockedImmediatelyPercent;\n}\n" + }, + "contracts/feeds/BProPriceFeed.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IMoCState.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The BPro Price Feed contract.\n *\n * This contract gets/sets the MoC (Money on Chain) address of its state\n * contract and queries its method bproUsdPrice to get bPro/USD valuation.\n * */\ncontract BProPriceFeed is IPriceFeedsExt, Ownable {\n address public mocStateAddress;\n\n event SetMoCStateAddress(address indexed mocStateAddress, address changerAddress);\n\n /**\n * @notice Initializes a new MoC state.\n *\n * @param _mocStateAddress MoC state address\n * */\n constructor(address _mocStateAddress) public {\n setMoCStateAddress(_mocStateAddress);\n }\n\n /**\n * @notice Get BPro USD price.\n *\n * @return the BPro USD Price [using mocPrecision]\n */\n function latestAnswer() external view returns (uint256) {\n IMoCState _mocState = IMoCState(mocStateAddress);\n return _mocState.bproUsdPrice();\n }\n\n /**\n * @notice Supposed to get the MoC update time, but instead\n * get the current timestamp.\n *\n * @return Always returns current block's timestamp.\n * */\n function latestTimestamp() external view returns (uint256) {\n return now; /// MoC state doesn't return update timestamp.\n }\n\n /**\n * @notice Set MoC state address.\n *\n * @param _mocStateAddress The MoC state address.\n * */\n function setMoCStateAddress(address _mocStateAddress) public onlyOwner {\n require(Address.isContract(_mocStateAddress), \"_mocStateAddress not a contract\");\n mocStateAddress = _mocStateAddress;\n emit SetMoCStateAddress(mocStateAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/IMoCState.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IMoCState {\n function getRbtcInBitPro(bytes32 bucket) external view returns (uint256);\n\n function globalMaxBPro() external view returns (uint256);\n\n function maxBPro(bytes32 bucket) external view returns (uint256);\n\n function absoluteMaxBPro() external view returns (uint256);\n\n function maxBProWithDiscount() external view returns (uint256);\n\n function bproTecPrice() external view returns (uint256);\n\n function bucketBProTecPrice(bytes32 bucket) external view returns (uint256);\n\n function bproDiscountPrice() external view returns (uint256);\n\n function bproUsdPrice() external view returns (uint256);\n\n function bproSpotDiscountRate() external view returns (uint256);\n\n function getBucketNBPro(bytes32 bucket) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IPriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface IPriceFeeds {\n function queryRate(address sourceToken, address destToken)\n external\n view\n returns (uint256 rate, uint256 precision);\n\n function queryPrecision(address sourceToken, address destToken)\n external\n view\n returns (uint256 precision);\n\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) external view returns (uint256 destAmount);\n\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) external view returns (uint256 sourceToDestSwapRate);\n\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\n\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (uint256);\n\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\n\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\n\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (bool);\n\n function getFastGasPrice(address payToken) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IRSKOracle {\n function updatePrice(uint256 price, uint256 timestamp) external;\n\n function getPricing() external view returns (uint256, uint256);\n\n function setOracleAddress(address addr) external;\n\n function clearOracleAddress() external;\n}\n" + }, + "contracts/feeds/IV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IV1PoolOracle {\n function read(uint256 price, uint256 timestamp)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function latestAnswer() external view returns (uint256);\n\n function liquidityPool() external view returns (address);\n\n function latestPrice(address _baseToken) external view returns (uint256 answer);\n}\n\ninterface ILiquidityPoolV1Converter {\n function reserveTokens(uint256 index) external view returns (address);\n}\n" + }, + "contracts/feeds/PriceFeedRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IRSKOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @notice The Price Feed RSK Oracle contract.\n *\n * This contract implements RSK Oracle query functionality,\n * getting the price and the last timestamp from an external oracle contract.\n * */\ncontract PriceFeedRSKOracle is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public rskOracleAddress;\n\n /* Events */\n\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new RSK Oracle.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _rskOracleAddress) public {\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256 _price) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (_price, ) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestTimestamp() external view returns (uint256 _timestamp) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (, _timestamp) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/PriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./PriceFeedsConstants.sol\";\n\ninterface IPriceFeedsExt {\n function latestAnswer() external view returns (uint256);\n}\n\n/**\n * @title The Price Feeds contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract queries the price feeds contracts where\n * oracles updates token prices computing relative token prices.\n * And besides it includes some calculations about loans such as\n * drawdown, margin and collateral.\n * */\ncontract PriceFeeds is Constants, Ownable {\n using SafeMath for uint256;\n\n /* Events */\n\n event GlobalPricingPaused(address indexed sender, bool indexed isPaused);\n\n /* Storage */\n\n /// Mapping of PriceFeedsExt instances.\n /// token => pricefeed\n mapping(address => IPriceFeedsExt) public pricesFeeds;\n\n /// Decimals of supported tokens.\n mapping(address => uint256) public decimals;\n\n /// Value on rBTC weis for the protocol token.\n uint256 public protocolTokenEthPrice = 0.0002 ether;\n\n /// Flag to pause pricings.\n bool public globalPricingPaused = false;\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires 3 parameters.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * @param _protocolTokenAddress The address of the protocol token.\n * @param _baseTokenAddress The address of the base token.\n * */\n constructor(\n address _wrbtcTokenAddress,\n address _protocolTokenAddress,\n address _baseTokenAddress\n ) public {\n /// Set decimals for this token.\n decimals[address(0)] = 18;\n decimals[_wrbtcTokenAddress] = 18;\n _setWrbtcToken(_wrbtcTokenAddress);\n _setProtocolTokenAddress(_protocolTokenAddress);\n _setBaseToken(_baseTokenAddress);\n }\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @dev Public wrapper for _queryRate internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function queryRate(address sourceToken, address destToken)\n public\n view\n returns (uint256 rate, uint256 precision)\n {\n return _queryRate(sourceToken, destToken);\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @dev Public wrapper for _getDecimalPrecision internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function queryPrecision(address sourceToken, address destToken) public view returns (uint256) {\n return sourceToken != destToken ? _getDecimalPrecision(sourceToken, destToken) : 10**18;\n }\n\n /**\n * @notice Price conversor: Calculate the price of an amount of source\n * tokens in destiny token units.\n *\n * @dev NOTE: This function returns 0 during a pause, rather than a revert.\n * Ensure calling contracts handle correctly.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of the source tokens.\n *\n * @return destAmount The amount of destiny tokens equivalent in price\n * to the amount of source tokens.\n * */\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) public view returns (uint256 destAmount) {\n if (globalPricingPaused) {\n return 0;\n }\n\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n destAmount = sourceAmount.mul(rate).div(precision);\n }\n\n /**\n * @notice Calculate the swap rate between two tokens.\n *\n * Regarding slippage, there is a hardcoded slippage limit of 5%, enforced\n * by this function for all borrowing, lending and margin trading\n * originated swaps performed in the Sovryn exchange.\n *\n * This means all operations in the Sovryn exchange are subject to losing\n * up to 5% from the internal swap performed.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of source tokens.\n * @param destAmount The amount of destiny tokens.\n * @param maxSlippage The maximum slippage limit.\n *\n * @return sourceToDestSwapRate The swap rate between tokens.\n * */\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) public view returns (uint256 sourceToDestSwapRate) {\n require(!globalPricingPaused, \"pricing is paused\");\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n sourceToDestSwapRate = destAmount.mul(precision).div(sourceAmount);\n\n if (rate > sourceToDestSwapRate) {\n uint256 spreadValue = rate - sourceToDestSwapRate;\n spreadValue = spreadValue.mul(10**20).div(sourceToDestSwapRate);\n require(spreadValue <= maxSlippage, \"price disagreement\");\n }\n }\n\n /**\n * @notice Calculate the rBTC amount equivalent to a given token amount.\n * Native coin on RSK is rBTC. This code comes from Ethereum applications,\n * so Eth refers to 10**18 weis of native coin, i.e.: 1 rBTC.\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n *\n * @return ethAmount The amount of rBTC equivalent.\n * */\n function amountInEth(address tokenAddress, uint256 amount)\n public\n view\n returns (uint256 ethAmount)\n {\n /// Token is wrBTC, amount in rBTC is the same.\n if (tokenAddress == address(wrbtcToken)) {\n ethAmount = amount;\n } else {\n (uint256 toEthRate, uint256 toEthPrecision) =\n queryRate(tokenAddress, address(wrbtcToken));\n ethAmount = amount.mul(toEthRate).div(toEthPrecision);\n }\n }\n\n /**\n * @notice Calculate the maximum drawdown of a loan.\n *\n * A drawdown is commonly defined as the decline from a high peak to a\n * pullback low of a specific investment or equity in an account.\n *\n * Drawdown magnitude refers to the amount of value that a user loses\n * during the drawdown period.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param margin The relation between the position size and the loan.\n * margin = (total position size - loan) / loan\n *\n * @return maxDrawdown The maximum drawdown.\n * */\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 margin\n ) public view returns (uint256 maxDrawdown) {\n uint256 loanToCollateralAmount;\n if (collateralToken == loanToken) {\n loanToCollateralAmount = loanAmount;\n } else {\n (uint256 rate, uint256 precision) = queryRate(loanToken, collateralToken);\n loanToCollateralAmount = loanAmount.mul(rate).div(precision);\n }\n\n uint256 combined =\n loanToCollateralAmount.add(loanToCollateralAmount.mul(margin).div(10**20));\n\n maxDrawdown = collateralAmount > combined ? collateralAmount - combined : 0;\n }\n\n /**\n * @notice Calculate the margin and the collateral on rBTC.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralInEthAmount The amount of collateral on rBTC.\n * */\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralInEthAmount) {\n (currentMargin, ) = getCurrentMargin(\n loanToken,\n collateralToken,\n loanAmount,\n collateralAmount\n );\n\n collateralInEthAmount = amountInEth(collateralToken, collateralAmount);\n }\n\n /**\n * @notice Calculate the margin of a loan.\n *\n * @dev current margin = (total position size - loan) / loan\n * The collateral amount passed as parameter equals the total position size.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralToLoanRate The price ratio between collateral and\n * loan tokens.\n * */\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralToLoanRate) {\n uint256 collateralToLoanAmount;\n if (collateralToken == loanToken) {\n collateralToLoanAmount = collateralAmount;\n collateralToLoanRate = 10**18;\n } else {\n uint256 collateralToLoanPrecision;\n (collateralToLoanRate, collateralToLoanPrecision) = queryRate(\n collateralToken,\n loanToken\n );\n\n collateralToLoanRate = collateralToLoanRate.mul(10**18).div(collateralToLoanPrecision);\n\n collateralToLoanAmount = collateralAmount.mul(collateralToLoanRate).div(10**18);\n }\n\n if (loanAmount != 0 && collateralToLoanAmount >= loanAmount) {\n return (\n collateralToLoanAmount.sub(loanAmount).mul(10**20).div(loanAmount),\n collateralToLoanRate\n );\n } else {\n return (0, collateralToLoanRate);\n }\n }\n\n /**\n * @notice Get assessment about liquidating a loan.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param maintenanceMargin The minimum margin before liquidation.\n *\n * @return True/false to liquidate the loan.\n * */\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) public view returns (bool) {\n (uint256 currentMargin, ) =\n getCurrentMargin(loanToken, collateralToken, loanAmount, collateralAmount);\n\n return currentMargin <= maintenanceMargin;\n }\n\n /*\n * Owner functions\n */\n\n /**\n * @notice Set new value for protocolTokenEthPrice\n *\n * @param newPrice The new value for protocolTokenEthPrice\n * */\n function setProtocolTokenEthPrice(uint256 newPrice) external onlyOwner {\n require(newPrice != 0, \"invalid price\");\n protocolTokenEthPrice = newPrice;\n }\n\n /**\n * @notice Populate pricesFeeds mapping w/ values from feeds[]\n *\n * @param tokens The array of tokens to loop and get addresses.\n * @param feeds The array of contract instances for every token.\n * */\n function setPriceFeed(address[] calldata tokens, IPriceFeedsExt[] calldata feeds)\n external\n onlyOwner\n {\n require(tokens.length == feeds.length, \"count mismatch\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n pricesFeeds[tokens[i]] = feeds[i];\n }\n }\n\n /**\n * @notice Populate decimals mapping w/ values from tokens[].decimals\n *\n * @param tokens The array of tokens to loop and get values from.\n * */\n function setDecimals(IERC20[] calldata tokens) external onlyOwner {\n for (uint256 i = 0; i < tokens.length; i++) {\n decimals[address(tokens[i])] = tokens[i].decimals();\n }\n }\n\n /**\n * @notice Set flag globalPricingPaused\n *\n * @param isPaused The new status of pause (true/false).\n * */\n function setGlobalPricingPaused(bool isPaused) external onlyOwner {\n if (globalPricingPaused != isPaused) {\n globalPricingPaused = isPaused;\n\n emit GlobalPricingPaused(msg.sender, isPaused);\n }\n }\n\n /*\n * Internal functions\n */\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n /// Different tokens, query prices and perform division.\n if (sourceToken != destToken) {\n uint256 sourceRate;\n if (sourceToken != address(baseToken) && sourceToken != protocolTokenAddress) {\n IPriceFeedsExt _sourceFeed = pricesFeeds[sourceToken];\n require(address(_sourceFeed) != address(0), \"unsupported src feed\");\n\n /// Query token price on priceFeedsExt instance.\n sourceRate = _sourceFeed.latestAnswer();\n require(sourceRate != 0 && (sourceRate >> 128) == 0, \"price error\");\n } else {\n sourceRate = sourceToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n uint256 destRate;\n if (destToken != address(baseToken) && destToken != protocolTokenAddress) {\n IPriceFeedsExt _destFeed = pricesFeeds[destToken];\n require(address(_destFeed) != address(0), \"unsupported dst feed\");\n\n /// Query token price on priceFeedsExt instance.\n destRate = _destFeed.latestAnswer();\n require(destRate != 0 && (destRate >> 128) == 0, \"price error\");\n } else {\n destRate = destToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n rate = sourceRate.mul(10**18).div(destRate);\n\n precision = _getDecimalPrecision(sourceToken, destToken);\n\n /// Same tokens, return 1 with decimals.\n } else {\n rate = 10**18;\n precision = 10**18;\n }\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function _getDecimalPrecision(address sourceToken, address destToken)\n internal\n view\n returns (uint256)\n {\n /// Same tokens, return 1 with decimals.\n if (sourceToken == destToken) {\n return 10**18;\n\n /// Different tokens, query ERC20 precisions and return 18 +- diff.\n } else {\n uint256 sourceTokenDecimals = decimals[sourceToken];\n if (sourceTokenDecimals == 0) sourceTokenDecimals = IERC20(sourceToken).decimals();\n\n uint256 destTokenDecimals = decimals[destToken];\n if (destTokenDecimals == 0) destTokenDecimals = IERC20(destToken).decimals();\n\n if (destTokenDecimals >= sourceTokenDecimals)\n return 10**(SafeMath.sub(18, destTokenDecimals - sourceTokenDecimals));\n else return 10**(SafeMath.add(18, sourceTokenDecimals - destTokenDecimals));\n }\n }\n}\n" + }, + "contracts/feeds/PriceFeedsConstants.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The Price Feeds Constants contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract keep the addresses of token instances for wrBTC, base token\n * and protocol token.\n * */\ncontract Constants {\n IWrbtcERC20 public wrbtcToken;\n IWrbtcERC20 public baseToken;\n address internal protocolTokenAddress;\n\n /**\n * @notice Set wrBTC token address.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * */\n function _setWrbtcToken(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"_wrbtcTokenAddress not a contract\");\n wrbtcToken = IWrbtcERC20(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Set protocol token address.\n *\n * @param _protocolTokenAddress The address of the protocol token.\n * */\n function _setProtocolTokenAddress(address _protocolTokenAddress) internal {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n protocolTokenAddress = _protocolTokenAddress;\n }\n\n /**\n * @notice Set base token address.\n *\n * @param _baseTokenAddress The address of the base token.\n * */\n function _setBaseToken(address _baseTokenAddress) internal {\n require(Address.isContract(_baseTokenAddress), \"_baseTokenAddress not a contract\");\n baseToken = IWrbtcERC20(_baseTokenAddress);\n }\n}\n" + }, + "contracts/feeds/PriceFeedV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IV1PoolOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./IPriceFeeds.sol\";\n\n/**\n * @notice The Price Feed V1 Pool Oracle contract.\n *\n * This contract implements V1 Pool Oracle query functionality,\n * getting the price from v1 pool oracle.\n * */\ncontract PriceFeedV1PoolOracle is IPriceFeedsExt, Ownable {\n using SafeMath for uint256;\n /* Storage */\n\n address public v1PoolOracleAddress;\n address public wRBTCAddress;\n address public docAddress;\n address public baseCurrency;\n\n /* Events */\n event SetV1PoolOracleAddress(address indexed v1PoolOracleAddress, address changerAddress);\n event SetWRBTCAddress(address indexed wRBTCAddress, address changerAddress);\n event SetDOCAddress(address indexed docAddress, address changerAddress);\n event SetBaseCurrency(address indexed baseCurrency, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new V1 Pool Oracle.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n * @param _wRBTCAddress The wrbtc token address.\n * @param _docAddress The doc token address.\n * */\n constructor(\n address _v1PoolOracleAddress,\n address _wRBTCAddress,\n address _docAddress,\n address _baseCurrency\n ) public {\n setRBTCAddress(_wRBTCAddress);\n setDOCAddress(_docAddress);\n setV1PoolOracleAddress(_v1PoolOracleAddress);\n setBaseCurrency(_baseCurrency);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256) {\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(v1PoolOracleAddress);\n\n uint256 _price = _v1PoolOracle.latestPrice(baseCurrency);\n\n // Need to convert to USD, since the V1 pool return value is based on BTC\n uint256 priceInUSD = _convertAnswerToUsd(_price);\n require(priceInUSD != 0, \"price error\");\n\n return priceInUSD;\n }\n\n function _convertAnswerToUsd(uint256 _valueInBTC) private view returns (uint256) {\n address _priceFeeds = msg.sender;\n\n uint256 precision = IPriceFeeds(_priceFeeds).queryPrecision(wRBTCAddress, docAddress);\n uint256 valueInUSD =\n IPriceFeeds(_priceFeeds).queryReturn(wRBTCAddress, docAddress, _valueInBTC);\n\n /// Need to multiply by query precision (doc's precision) and divide by 1*10^18 (Because the based price in v1 pool is using 18 decimals)\n return valueInUSD.mul(precision).div(1e18);\n }\n\n /**\n * @notice Set the V1 Pool Oracle address.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n */\n function setV1PoolOracleAddress(address _v1PoolOracleAddress) public onlyOwner {\n require(Address.isContract(_v1PoolOracleAddress), \"_v1PoolOracleAddress not a contract\");\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(_v1PoolOracleAddress);\n address liquidityPool = _v1PoolOracle.liquidityPool();\n require(\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(0) == wRBTCAddress ||\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(1) == wRBTCAddress,\n \"one of the two reserves needs to be wrbtc\"\n );\n v1PoolOracleAddress = _v1PoolOracleAddress;\n emit SetV1PoolOracleAddress(v1PoolOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the rBtc address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the rBtc\n *\n * @param _wRBTCAddress The rBTC address\n */\n function setRBTCAddress(address _wRBTCAddress) public onlyOwner {\n require(_wRBTCAddress != address(0), \"wRBTC address cannot be zero address\");\n wRBTCAddress = _wRBTCAddress;\n emit SetWRBTCAddress(wRBTCAddress, msg.sender);\n }\n\n /**\n * @notice Set the DoC address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the DoC\n *\n * @param _docAddress The DoC address\n */\n function setDOCAddress(address _docAddress) public onlyOwner {\n require(_docAddress != address(0), \"DOC address cannot be zero address\");\n docAddress = _docAddress;\n emit SetDOCAddress(_docAddress, msg.sender);\n }\n\n /**\n * @notice Set the base currency address. That's the reserve address which is not WRBTC\n *\n * @param _baseCurrency The base currency address\n */\n function setBaseCurrency(address _baseCurrency) public onlyOwner {\n require(_baseCurrency != address(0), \"Base currency address cannot be zero address\");\n baseCurrency = _baseCurrency;\n emit SetBaseCurrency(_baseCurrency, msg.sender);\n }\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsLocal.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\n\n/**\n * @title Price Feeds Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the logic of setting and getting rates between two tokens.\n * */\ncontract PriceFeedsLocal is PriceFeeds {\n mapping(address => mapping(address => uint256)) public rates;\n\n /// uint256 public slippageMultiplier = 100 ether;\n\n /**\n * @notice Deploy local price feed contract.\n *\n * @param _wrbtcTokenAddress The address of the wrBTC instance.\n * @param _protocolTokenAddress The address of the protocol token instance.\n * */\n constructor(address _wrbtcTokenAddress, address _protocolTokenAddress)\n public\n PriceFeeds(_wrbtcTokenAddress, _protocolTokenAddress, _wrbtcTokenAddress)\n {}\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n if (sourceToken == destToken) {\n rate = 10**18;\n precision = 10**18;\n } else {\n if (sourceToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = protocolTokenEthPrice;\n } else if (destToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = SafeMath.div(10**36, protocolTokenEthPrice);\n } else {\n if (rates[sourceToken][destToken] != 0) {\n rate = rates[sourceToken][destToken];\n } else {\n uint256 sourceToEther =\n rates[sourceToken][address(wrbtcToken)] != 0\n ? rates[sourceToken][address(wrbtcToken)]\n : 10**18;\n uint256 etherToDest =\n rates[address(wrbtcToken)][destToken] != 0\n ? rates[address(wrbtcToken)][destToken]\n : 10**18;\n\n rate = sourceToEther.mul(etherToDest).div(10**18);\n }\n }\n precision = _getDecimalPrecision(sourceToken, destToken);\n }\n }\n\n /**\n * @notice Owner set price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param rate The price ratio source/dest.\n * */\n function setRates(\n address sourceToken,\n address destToken,\n uint256 rate\n ) public onlyOwner {\n if (sourceToken != destToken) {\n rates[sourceToken][destToken] = rate;\n rates[destToken][sourceToken] = SafeMath.div(10**36, rate);\n }\n }\n\n /*function setSlippageMultiplier(\n uint256 _slippageMultiplier)\n public\n onlyOwner\n {\n require (slippageMultiplier != _slippageMultiplier && _slippageMultiplier <= 100 ether);\n slippageMultiplier = _slippageMultiplier;\n }*/\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsMoC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\nimport \"../IRSKOracle.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\ninterface Medianizer {\n function peek() external view returns (bytes32, bool);\n}\n\n/**\n * @title Price Feed of MoC (Money on Chain) contract.\n *\n * This contract contains the logic to set MoC oracles\n * and query last price update.\n * */\ncontract PriceFeedsMoC is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public mocOracleAddress;\n address public rskOracleAddress;\n\n /* Events */\n\n event SetMoCOracleAddress(address indexed mocOracleAddress, address changerAddress);\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new MoC Oracle.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _mocOracleAddress, address _rskOracleAddress) public {\n setMoCOracleAddress(_mocOracleAddress);\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestAnswer() external view returns (uint256) {\n (bytes32 value, bool hasValue) = Medianizer(mocOracleAddress).peek();\n if (hasValue) {\n return uint256(value);\n } else {\n (uint256 price, ) = IRSKOracle(rskOracleAddress).getPricing();\n return price;\n }\n }\n\n /**\n * @notice Set the MoC Oracle address.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n */\n function setMoCOracleAddress(address _mocOracleAddress) public onlyOwner {\n require(Address.isContract(_mocOracleAddress), \"_mocOracleAddress not a contract\");\n mocOracleAddress = _mocOracleAddress;\n emit SetMoCOracleAddress(mocOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/USDTPriceFeed.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./PriceFeeds.sol\";\n\n/**\n * @notice The Price Feed USDT contract.\n *\n * This contract implements USDT query functionality,\n * getting the price and the last timestamp from a\n * trivial formula, always returning 1 and now.\n * */\ncontract USDTPriceFeed is IPriceFeedsExt {\n uint256 private constant USDT_RATE = 1 ether;\n\n /**\n * @notice Get the USDT price.\n *\n * @return Always returns the trivial rate of 1.\n * */\n function latestAnswer() external view returns (uint256) {\n return USDT_RATE;\n }\n\n /**\n * @notice Get the las time the price was updated.\n * @return Always trivial current block's timestamp.\n */\n function latestTimestamp() external view returns (uint256) {\n return now;\n }\n}\n" + }, + "contracts/governance/ApprovalReceiver.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./ErrorDecoder.sol\";\nimport \"../token/IApproveAndCall.sol\";\n\n/**\n * @title Base contract for receiving approval from SOV token.\n */\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\n modifier onlyThisContract() {\n // Accepts calls only from receiveApproval function.\n require(msg.sender == address(this), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external {\n // Accepts calls only from SOV token.\n require(msg.sender == _getToken(), \"unauthorized\");\n require(msg.sender == _token, \"unauthorized\");\n\n // Only allowed methods.\n bool isAllowed = false;\n bytes4[] memory selectors = _getSelectors();\n bytes4 sig = _getSig(_data);\n for (uint256 i = 0; i < selectors.length; i++) {\n if (sig == selectors[i]) {\n isAllowed = true;\n break;\n }\n }\n require(isAllowed, \"method is not allowed\");\n\n // Check sender and amount.\n address sender;\n uint256 amount;\n (, sender, amount) = abi.decode(\n abi.encodePacked(bytes28(0), _data),\n (bytes32, address, uint256)\n );\n require(sender == _sender, \"sender mismatch\");\n require(amount == _amount, \"amount mismatch\");\n\n _call(_data);\n }\n\n /**\n * @notice Returns token address, only this address can be a sender for receiveApproval.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, 0x. When overriden, the token address making the call.\n */\n function _getToken() internal view returns (address) {\n return address(0);\n }\n\n /**\n * @notice Returns list of function selectors allowed to be invoked.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, empty array. When overriden, allowed selectors.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n return new bytes4[](0);\n }\n\n /**\n * @notice Makes call and reverts w/ enhanced error message.\n * @param _data Error message as bytes.\n */\n function _call(bytes memory _data) internal {\n (bool success, bytes memory returnData) = address(this).call(_data);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"receiveApproval: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"receiveApproval: \", string(returnData)));\n }\n }\n }\n\n /**\n * @notice Extracts the called function selector, a hash of the signature.\n * @dev The first four bytes of the call data for a function call specifies\n * the function to be called. It is the first (left, high-order in big-endian)\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\n * Example:\n * msg.data:\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\n * 000450000000000000000000000000000000000000000000000000000000000000001\n * selector (or method ID): 0xcdcd77c0\n * signature: baz(uint32,bool)\n * @param _data The msg.data from the low level call.\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\n */\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\n assembly {\n sig := mload(add(_data, 32))\n }\n }\n}\n" + }, + "contracts/governance/ErrorDecoder.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base contract to properly handle returned data on failed calls\n * @dev On EVM if the return data length of a call is less than 68,\n * then the transaction fails silently without a revert message!\n *\n * As described in the Solidity documentation\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\n * the revert reason is an ABI-encoded string consisting of:\n * 0x08c379a0 // Function selector (method id) for \"Error(string)\" signature\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\n *\n * Another example, debug data from test:\n * 0x08c379a0\n * 0000000000000000000000000000000000000000000000000000000000000020\n * 0000000000000000000000000000000000000000000000000000000000000034\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n *\n * Parsed into:\n * Data offset: 20\n * Length: 34\n * Error message:\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n */\ncontract ErrorDecoder {\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\n\n /**\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\n * @param str1 First string, usually a hardcoded context written by dev.\n * @param str2 Second string, usually the error message from the reverted call.\n * @return The concatenated error string\n */\n function _addErrorMessage(string memory str1, string memory str2)\n internal\n pure\n returns (string memory)\n {\n bytes memory bytesStr1 = bytes(str1);\n bytes memory bytesStr2 = bytes(str2);\n string memory str12 =\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\n bytes memory bytesStr12 = bytes(str12);\n uint256 j = 0;\n for (uint256 i = 0; i < bytesStr1.length; i++) {\n bytesStr12[j++] = bytesStr1[i];\n }\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\n bytesStr12[j++] = bytesStr2[i];\n }\n return string(bytesStr12);\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../Staking/SafeMath96.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../interfaces/IConverterAMM.sol\";\n\n/**\n * @title The FeeSharingCollector contract.\n * @notice This contract withdraws fees to be paid to SOV Stakers from the protocol.\n * Stakers call withdraw() to get their share of the fees.\n *\n * @notice Staking is not only granting voting rights, but also access to fee\n * sharing according to the own voting power in relation to the total. Whenever\n * somebody decides to collect the fees from the protocol, they get transferred\n * to a proxy contract which invests the funds in the lending pool and keeps\n * the pool tokens.\n *\n * The fee sharing proxy will be set as feesController of the protocol contract.\n * This allows the fee sharing proxy to withdraw the fees. The fee sharing\n * proxy holds the pool tokens and keeps track of which user owns how many\n * tokens. In order to know how many tokens a user owns, the fee sharing proxy\n * needs to know the user’s weighted stake in relation to the total weighted\n * stake (aka total voting power).\n *\n * Because both values are subject to change, they may be different on each fee\n * withdrawal. To be able to calculate a user’s share of tokens when he wants\n * to withdraw, we need checkpoints.\n *\n * This contract is intended to be set as the protocol fee collector.\n * Anybody can invoke the withdrawFees function which uses\n * protocol.withdrawFees to obtain available fees from operations on a\n * certain token. These fees are deposited in the corresponding loanPool.\n * Also, the staking contract sends slashed tokens to this contract.\n * When a user calls the withdraw function, the contract transfers the fee sharing\n * rewards in proportion to the user’s weighted stake since the last withdrawal.\n *\n * The protocol initially collects fees in all tokens.\n * Then the FeeSharingCollector wihtdraws fees from the protocol.\n * When the fees are withdrawn all the tokens except SOV will be converted to wRBTC\n * and then transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n * */\ncontract FeeSharingCollector is\n SafeMath96,\n IFeeSharingCollector,\n Ownable,\n FeeSharingCollectorStorage\n{\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n address constant ZERO_ADDRESS = address(0);\n address public constant RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT =\n address(uint160(uint256(keccak256(\"RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\"))));\n\n /* Events */\n\n /// @notice Deprecated event after the unification between wrbtc & rbtc\n // event FeeWithdrawn(address indexed sender, address indexed token, uint256 amount);\n event FeeWithdrawnInRBTC(address indexed sender, uint256 amount);\n\n /// @notice An event emitted when tokens transferred.\n event TokensTransferred(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when checkpoint added.\n event CheckpointAdded(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeWithdrawn(\n address indexed sender,\n address indexed receiver,\n address indexed token,\n uint256 amount\n );\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeProcessedNoWithdraw(\n address indexed sender,\n address indexed token,\n uint256 prevProcessedCheckpoints,\n uint256 newProcessedCheckpoints\n );\n\n /**\n * @notice An event emitted when fee from AMM get withdrawn.\n *\n * @param sender sender who initiate the withdrawn amm fees.\n * @param converter the converter address.\n * @param amount total amount of fee (Already converted to WRBTC).\n */\n event FeeAMMWithdrawn(address indexed sender, address indexed converter, uint256 amount);\n\n /// @notice An event emitted when converter address has been registered to be whitelisted.\n event WhitelistedConverter(address indexed sender, address converter);\n\n /// @notice An event emitted when converter address has been removed from whitelist.\n event UnwhitelistedConverter(address indexed sender, address converter);\n\n event RBTCWithdrawn(address indexed sender, address indexed receiver, uint256 amount);\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWrbtcToken,\n address indexed newWrbtcToken\n );\n\n event SetLoanTokenWrbtc(\n address indexed sender,\n address indexed oldLoanTokenWrbtc,\n address indexed newLoanTokenWrbtc\n );\n\n /* Modifier */\n modifier oneTimeExecution(bytes4 _funcSig) {\n require(\n !isFunctionExecuted[_funcSig],\n \"FeeSharingCollector: function can only be called once\"\n );\n _;\n isFunctionExecuted[_funcSig] = true;\n }\n\n /* Functions */\n\n /// @dev fallback function to support rbtc transfer when unwrap the wrbtc.\n function() external payable {}\n\n /**\n * @dev initialize function for fee sharing collector proxy\n * @param wrbtcToken wrbtc token address\n * @param loanWrbtcToken address of loan token wrbtc (IWrbtc)\n */\n function initialize(address wrbtcToken, address loanWrbtcToken)\n external\n onlyOwner\n oneTimeExecution(this.initialize.selector)\n {\n require(\n wrbtcTokenAddress == address(0) && loanTokenWrbtcAddress == address(0),\n \"wrbtcToken or loanWrbtcToken has been initialized\"\n );\n setWrbtcToken(wrbtcToken);\n setLoanTokenWrbtc(loanWrbtcToken);\n }\n\n /**\n * @notice Set the wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newWrbtcTokenAddress The new address of the wrbtc token.\n * */\n function setWrbtcToken(address newWrbtcTokenAddress) public onlyOwner {\n require(Address.isContract(newWrbtcTokenAddress), \"newWrbtcTokenAddress not a contract\");\n emit SetWrbtcToken(msg.sender, wrbtcTokenAddress, newWrbtcTokenAddress);\n wrbtcTokenAddress = newWrbtcTokenAddress;\n }\n\n /**\n * @notice Set the loan wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newLoanTokenWrbtcAddress The new address of the loan wrbtc token.\n * */\n function setLoanTokenWrbtc(address newLoanTokenWrbtcAddress) public onlyOwner {\n require(\n Address.isContract(newLoanTokenWrbtcAddress),\n \"newLoanTokenWrbtcAddress not a contract\"\n );\n emit SetLoanTokenWrbtc(msg.sender, loanTokenWrbtcAddress, newLoanTokenWrbtcAddress);\n loanTokenWrbtcAddress = newLoanTokenWrbtcAddress;\n }\n\n /**\n * @notice Withdraw fees for the given token:\n * lendingFee + tradingFee + borrowingFee\n * the fees (except SOV) will be converted in wRBTC form, and then will be transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n *\n * @param _tokens array address of the token\n * */\n function withdrawFees(address[] calldata _tokens) external {\n for (uint256 i = 0; i < _tokens.length; i++) {\n require(\n Address.isContract(_tokens[i]),\n \"FeeSharingCollector::withdrawFees: token is not a contract\"\n );\n }\n\n uint256 wrbtcAmountWithdrawn = protocol.withdrawFees(_tokens, address(this));\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap the wrbtc to rbtc, and hold the rbtc.\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFees: wrbtc token amount exceeds 96 bits\"\n );\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, amount96);\n }\n\n // note deprecated event since we unify the wrbtc & rbtc\n // emit FeeWithdrawn(msg.sender, RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, poolTokenAmount);\n\n // note new emitted event\n emit FeeWithdrawnInRBTC(msg.sender, wrbtcAmountWithdrawn);\n }\n\n /**\n * @notice Withdraw amm fees for the given converter addresses:\n * protocolFee from the conversion\n * the fees will be converted in wRBTC form, and then will be transferred to wRBTC loan pool\n *\n * @param _converters array addresses of the converters\n * */\n function withdrawFeesAMM(address[] memory _converters) public {\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n // Validate\n _validateWhitelistedConverter(_converters);\n\n uint96 totalPoolTokenAmount;\n for (uint256 i = 0; i < _converters.length; i++) {\n uint256 wrbtcAmountWithdrawn =\n IConverterAMM(_converters[i]).withdrawFees(address(this));\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap wrbtc to rbtc, and hold the rbtc\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFeesAMM: wrbtc token amount exceeds 96 bits\"\n );\n\n totalPoolTokenAmount = add96(\n totalPoolTokenAmount,\n amount96,\n \"FeeSharingCollector::withdrawFeesAMM: total wrbtc token amount exceeds 96 bits\"\n );\n\n emit FeeAMMWithdrawn(msg.sender, _converters[i], wrbtcAmountWithdrawn);\n }\n }\n\n if (totalPoolTokenAmount > 0) {\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, totalPoolTokenAmount);\n }\n }\n\n /**\n * @notice Transfer tokens to this contract.\n * @dev We just update amount of tokens here and write checkpoint in a separate methods\n * in order to prevent adding checkpoints too often.\n * @param _token Address of the token.\n * @param _amount Amount to be transferred.\n * */\n function transferTokens(address _token, uint96 _amount) public {\n require(_token != ZERO_ADDRESS, \"FeeSharingCollector::transferTokens: invalid address\");\n require(_amount > 0, \"FeeSharingCollector::transferTokens: invalid amount\");\n\n /// @notice Transfer tokens from msg.sender\n bool success = IERC20(_token).transferFrom(address(msg.sender), address(this), _amount);\n require(success, \"Staking::transferTokens: token transfer failed\");\n\n // if _token is wrbtc, need to unwrap it to rbtc\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n if (_token == address(wrbtcToken)) {\n wrbtcToken.withdraw(_amount);\n _token = RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT;\n }\n\n _addCheckpoint(_token, _amount);\n\n emit TokensTransferred(msg.sender, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC / native tokens to this contract.\n * @dev We just write checkpoint here (based on the rbtc value that is sent) in a separate methods\n * in order to prevent adding checkpoints too often.\n * */\n function transferRBTC() external payable {\n uint96 _amount = uint96(msg.value);\n require(_amount > 0, \"FeeSharingCollector::transferRBTC: invalid value\");\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, _amount);\n\n emit TokensTransferred(msg.sender, ZERO_ADDRESS, _amount);\n }\n\n /**\n * @notice Add checkpoint with accumulated amount by function invocation.\n * @param _token Address of the token.\n * */\n function _addCheckpoint(address _token, uint96 _amount) internal {\n if (block.timestamp - lastFeeWithdrawalTime[_token] >= FEE_WITHDRAWAL_INTERVAL) {\n lastFeeWithdrawalTime[_token] = block.timestamp;\n uint96 amount =\n add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: amount exceeds 96 bits\"\n );\n\n /// @notice Reset unprocessed amount of tokens to zero.\n unprocessedAmount[_token] = 0;\n\n /// @notice Write a regular checkpoint.\n _writeTokenCheckpoint(_token, amount);\n } else {\n unprocessedAmount[_token] = add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: unprocessedAmount exceeds 96 bits\"\n );\n }\n }\n\n function _withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n /// @dev Prevents block gas limit hit when processing checkpoints\n require(\n _maxCheckpoints > 0,\n \"FeeSharingCollector::withdraw: _maxCheckpoints should be positive\"\n );\n\n address user = msg.sender;\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n uint256 processedUserCheckpoints = processedCheckpoints[user][_token];\n (uint256 amount, uint256 end) =\n _getAccumulatedFees(user, _token, processedUserCheckpoints, _maxCheckpoints);\n if (amount == 0) {\n if (end > processedUserCheckpoints) {\n emit UserFeeProcessedNoWithdraw(msg.sender, _token, processedUserCheckpoints, end);\n processedCheckpoints[user][_token] = end;\n return (0, end);\n } else {\n // getting here most likely means smth wrong with the state\n revert(\"FeeSharingCollector::withdrawFees: no tokens for withdrawal\");\n }\n }\n\n processedCheckpoints[user][_token] = end;\n if (loanTokenWrbtcAddress == _token) {\n // We will change, so that feeSharingCollector will directly burn then loanToken (IWRBTC) to rbtc and send to the user --- by call burnToBTC function\n ILoanTokenWRBTC(_token).burnToBTC(_receiver, amount, false);\n } else {\n // Previously it directly send the loanToken to the user\n require(\n IERC20(_token).transfer(_receiver, amount),\n \"FeeSharingCollector::withdraw: withdrawal failed\"\n );\n }\n\n emit UserFeeWithdrawn(msg.sender, _receiver, _token, amount);\n\n return (amount, end);\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power. Therefore, staking more\n * SOV and/or staking for longer will increase your share of the fees\n * generated, meaning you will earn more from staking.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed. Must be positive value.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public nonReentrant {\n _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n /// @notice Validates if the checkpoint is payable for the user\n function validFromCheckpointsParam(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n address _user\n ) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n // _fromCheckpoint is checkpoint number, not array index, so should be > 1\n require(tokenData.fromCheckpoint > 1, \"_fromCheckpoint param must be > 1\");\n uint256 fromCheckpointIndex = tokenData.fromCheckpoint - 1;\n require(\n tokenData.fromCheckpoint > processedCheckpoints[_user][tokenData.tokenAddress],\n \"_fromCheckpoint param must be > userProcessedCheckpoints\"\n );\n require(\n tokenData.fromCheckpoint <= totalTokenCheckpoints[tokenData.tokenAddress],\n \"_fromCheckpoint should be <= totalTokenCheckpoints\"\n );\n\n Checkpoint memory prevCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex - 1];\n\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n prevCheckpoint.blockNumber - 1,\n prevCheckpoint.timestamp\n );\n require(\n weightedStake == 0,\n \"User weighted stake should be zero at previous checkpoint\"\n );\n\n Checkpoint memory fromCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex];\n weightedStake = staking.getPriorWeightedStake(\n _user,\n fromCheckpoint.blockNumber - 1,\n fromCheckpoint.timestamp\n );\n\n require(weightedStake > 0, \"User weighted stake should be > 0 at _fromCheckpoint\");\n }\n }\n\n function validRBTCBasedTokens(address[] memory _tokens) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n address _token = _tokens[i];\n if (\n _token != RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT &&\n _token != wrbtcTokenAddress &&\n _token != loanTokenWrbtcAddress\n ) {\n revert(\"only rbtc-based tokens are allowed\");\n }\n }\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender/receiver.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @dev WARNING! This function skips all the checkpoints before '_fromCheckpoint' irreversibly, use with care\n *\n * @param _tokens Array of TokenWithSkippedCheckpointsWithdraw struct, which contains the token address, and fromCheckpoiint\n * fromCheckpoints Skips all the checkpoints before '_fromCheckpoint'\n * should be calculated offchain with getNextPositiveUserCheckpoint function\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n *\n * @return total processed checkpoints\n * */\n function _withdrawStartingFromCheckpoints(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validFromCheckpointsParam(_tokens, msg.sender);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n if (_maxCheckpoints == 0) break;\n uint256 endToken;\n uint256 totalAmount;\n\n uint256 previousProcessedUserCheckpoints =\n processedCheckpoints[msg.sender][tokenData.tokenAddress];\n uint256 startingCheckpoint =\n tokenData.fromCheckpoint > previousProcessedUserCheckpoints\n ? tokenData.fromCheckpoint\n : previousProcessedUserCheckpoints;\n\n if (\n tokenData.tokenAddress == wrbtcTokenAddress ||\n tokenData.tokenAddress == loanTokenWrbtcAddress ||\n tokenData.tokenAddress == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\n ) {\n (totalAmount, endToken) = _withdrawRbtcTokenStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n } else {\n (, endToken) = _withdrawStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n }\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint).add(1);\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n if (rbtcAmountToSend > 0) {\n // send all rbtc withdrawal\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Function to wrap:\n * 1. regular withdrawal for both rbtc & non-rbtc token\n * 2. skipped checkpoints withdrawal for both rbtc & non-rbtc token\n *\n * @param _nonRbtcTokensRegularWithdraw array of non-rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _rbtcTokensRegularWithdraw array of rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _tokensWithSkippedCheckpoints array of rbtc & non-rbtc TokenWithSkippedCheckpointsWithdraw struct, which has skipped checkpoints that will be withdrawn\n *\n */\n function claimAllCollectedFees(\n address[] calldata _nonRbtcTokensRegularWithdraw,\n address[] calldata _rbtcTokensRegularWithdraw,\n TokenWithSkippedCheckpointsWithdraw[] calldata _tokensWithSkippedCheckpoints,\n uint32 _maxCheckpoints,\n address _receiver\n ) external nonReentrant {\n uint256 totalProcessedCheckpoints;\n\n /** Process normal multiple withdrawal for RBTC based tokens */\n if (_rbtcTokensRegularWithdraw.length > 0) {\n totalProcessedCheckpoints = _withdrawRbtcTokens(\n _rbtcTokensRegularWithdraw,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process normal non-rbtc token withdrawal */\n for (uint256 i = 0; i < _nonRbtcTokensRegularWithdraw.length; i++) {\n if (_maxCheckpoints == 0) break;\n uint256 endTokenCheckpoint;\n\n address _nonRbtcTokenAddress = _nonRbtcTokensRegularWithdraw[i];\n\n /** starting checkpoint is the previous processedCheckpoints for token */\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_nonRbtcTokenAddress];\n\n (, endTokenCheckpoint) = _withdraw(_nonRbtcTokenAddress, _maxCheckpoints, _receiver);\n\n uint256 _previousUsedCheckpoint = endTokenCheckpoint.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n _previousUsedCheckpoint.add(1);\n }\n\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process token with skipped checkpoints withdrawal */\n if (_tokensWithSkippedCheckpoints.length > 0) {\n totalProcessedCheckpoints = _withdrawStartingFromCheckpoints(\n _tokensWithSkippedCheckpoints,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n }\n\n function _withdrawStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10 meaning we should set 9 user's processed checkpoints\n // after _withdraw() the user's processedCheckpoints should be 10\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n (totalAmount, endTokenCheckpoint) = _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function _withdrawRbtcToken(address _token, uint32 _maxCheckpoints)\n internal\n returns (uint256 totalAmount, uint256 endTokenCheckpoint)\n {\n address user = msg.sender;\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n (totalAmount, endTokenCheckpoint) = _getRBTCBalance(_token, user, _maxCheckpoints);\n\n if (totalAmount > 0) {\n processedCheckpoints[user][_token] = endTokenCheckpoint;\n if (_token == address(wrbtcToken)) {\n // unwrap the wrbtc\n wrbtcToken.withdraw(totalAmount);\n } else if (_token == loanTokenWrbtcAddress) {\n // pull out the iWRBTC to rbtc to this feeSharingCollector contract\n /** @dev will use the burned result from IWRBTC to RBTC as return total amount */\n totalAmount = ILoanTokenWRBTC(loanTokenWrbtcAddress).burnToBTC(\n address(this),\n totalAmount,\n false\n );\n }\n }\n }\n\n /**\n * @dev withdraw all of the RBTC balance based on particular checkpoints\n *\n * This function will withdraw RBTC balance which is passed as _token param, so it could be either of these:\n * - rbtc balance or\n * - wrbtc balance which will be unwrapped to rbtc or\n * - iwrbtc balance which will be unwrapped to rbtc or\n *\n *\n * @param _tokens array of either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _maxCheckpoints Maximum number of checkpoints to be processed to workaround block gas limit\n * @param _receiver An optional tokens receiver (msg.sender used if 0)\n */\n function _withdrawRbtcTokens(\n address[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validRBTCBasedTokens(_tokens);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n if (_maxCheckpoints == 0) break;\n address _token = _tokens[i];\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_token];\n\n (uint256 totalAmount, uint256 endToken) =\n _withdrawRbtcToken(_tokens[i], _maxCheckpoints);\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n // we only need to add used checkpoint by 1 only if starting checkpoint > 0\n _previousUsedCheckpoint.add(1);\n }\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n // send all rbtc\n if (rbtcAmountToSend > 0) {\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Withdraw either specific RBTC related token balance or all RBTC related tokens balances.\n * RBTC related here means, it could be either rbtc, wrbtc, or iwrbtc, depends on the _token param.\n */\n function _withdrawRbtcTokenStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) private returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10\n // after _withdraw() user's processedCheckpoints should be 10 =>\n // set processed checkpoints = 9, next maping index = 9 (10th checkpoint)\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n return _withdrawRbtcToken(_token, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n external\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n return _getNextPositiveUserCheckpoint(_user, _token, _startFrom, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function _getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n internal\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n if (staking.isVestingContract(_user)) {\n return (0, false, false);\n }\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n\n if (processedUserCheckpoints >= totalCheckpoints || totalCheckpoints == 0) {\n return (totalCheckpoints, false, false);\n }\n\n uint256 startFrom =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n\n uint256 end = startFrom.add(_maxCheckpoints);\n if (end >= totalCheckpoints) {\n end = totalCheckpoints;\n }\n\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startFrom; i < end; i++) {\n Checkpoint storage tokenCheckpoint = tokenCheckpoints[_token][i];\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n tokenCheckpoint.blockNumber - 1,\n tokenCheckpoint.timestamp\n );\n if (weightedStake > 0) {\n // i is the index and we need to return checkpoint num which is i + 1\n return (i + 1, i > processedUserCheckpoints, true);\n }\n }\n return (end, end > processedUserCheckpoints, false);\n }\n\n /**\n * @notice Get the accumulated loan pool fee of the message sender.\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @return The accumulated fee for the message sender.\n * */\n function getAccumulatedFees(address _user, address _token) public view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: 0\n });\n return amount;\n }\n\n /**\n * @notice Get the accumulated fee rewards for the message sender for a checkpoints range\n *\n * @dev This function is required to keep consistent with caching of weighted voting power when claiming fees\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The accumulated fees rewards for the _user in the given checkpoints interval: [_startFrom, _startFrom + maxCheckpoints].\n * */\n function getAccumulatedFeesForCheckpointsRange(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees(_user, _token, _startFrom, _maxCheckpoints);\n return amount;\n }\n\n /**\n * @dev Get all user fees reward per maxCheckpoint starting from latest processed checkpoint\n *\n * @dev e.g: Total user checkpoint for the particualar token = 300,\n * when we call this function with 50 maxCheckpoint, it will return 6 fee values in array form.\n * if there is no more fees, it will return empty array.\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The next checkpoint num which is the starting point to fetch all of the fees, array of calculated fees.\n * */\n function getAllUserFeesPerMaxCheckpoints(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256[] memory fees) {\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 totalTokensCheckpointsIndex = totalCheckpoints > 0 ? totalCheckpoints - 1 : 0;\n\n if (totalTokensCheckpointsIndex < _startFrom) return fees;\n\n uint256 arrSize = totalTokensCheckpointsIndex.sub(_startFrom).div(_maxCheckpoints) + 1;\n\n fees = new uint256[](arrSize);\n\n for (uint256 i = 0; i < fees.length; i++) {\n (uint256 fee, ) =\n _getAccumulatedFees(\n _user,\n _token,\n _startFrom + i * _maxCheckpoints,\n _maxCheckpoints\n );\n fees[i] = fee;\n }\n\n return fees;\n }\n\n /**\n * @notice Gets accumulated fees for a user starting from a given checkpoint\n *\n * @param _user Address of the user's account.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Max checkpoints to process at once to fit into block gas limit\n * @param _startFrom Checkpoint num to start calculations from\n *\n * @return feesAmount - accumulated fees amount\n * @return endCheckpoint - last checkpoint of fees calculation\n * */\n function _getAccumulatedFees(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 feesAmount, uint256 endCheckpoint) {\n if (staking.isVestingContract(_user)) {\n return (0, 0);\n }\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n uint256 startOfRange =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n endCheckpoint = _maxCheckpoints > 0\n ? _getEndOfRange(startOfRange, _token, _maxCheckpoints)\n : totalTokenCheckpoints[_token];\n\n if (startOfRange >= totalTokenCheckpoints[_token]) {\n return (0, endCheckpoint);\n }\n\n uint256 cachedLockDate = 0;\n uint96 cachedWeightedStake = 0;\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startOfRange; i < endCheckpoint; i++) {\n Checkpoint memory checkpoint = tokenCheckpoints[_token][i];\n uint256 lockDate = staking.timestampToLockDate(checkpoint.timestamp);\n uint96 weightedStake;\n if (lockDate == cachedLockDate) {\n weightedStake = cachedWeightedStake;\n } else {\n /// @dev We need to use \"checkpoint.blockNumber - 1\" here to calculate weighted stake\n /// For the same block like we did for total voting power in _writeTokenCheckpoint\n weightedStake = staking.getPriorWeightedStake(\n _user,\n checkpoint.blockNumber - 1,\n checkpoint.timestamp\n );\n cachedWeightedStake = weightedStake;\n cachedLockDate = lockDate;\n }\n uint256 share =\n uint256(checkpoint.numTokens).mul(weightedStake).div(\n uint256(checkpoint.totalWeightedStake)\n );\n feesAmount = feesAmount.add(share);\n }\n return (feesAmount, endCheckpoint);\n }\n\n /**\n * @notice Withdrawal should only be possible for blocks which were already\n * mined. If the fees are withdrawn in the same block as the user withdrawal\n * they are not considered by the withdrawing logic (to avoid inconsistencies).\n *\n * @param _start Start of the range.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of a pool token.\n * @param _maxCheckpoints Checkpoint index incremental.\n * */\n function _getEndOfRange(\n uint256 _start,\n address _token,\n uint32 _maxCheckpoints\n ) internal view returns (uint256) {\n uint256 nextCheckpointIndex = totalTokenCheckpoints[_token];\n if (nextCheckpointIndex == 0) {\n return 0;\n }\n uint256 end;\n\n if (_maxCheckpoints == 0) {\n /// @dev All checkpoints will be processed (only for getter outside of a transaction).\n end = nextCheckpointIndex;\n } else {\n end = safe32(\n _start + _maxCheckpoints,\n \"FeeSharingCollector::withdraw: checkpoint index exceeds 32 bits\"\n );\n if (end > nextCheckpointIndex) {\n end = nextCheckpointIndex;\n }\n }\n\n /// @dev Withdrawal should only be possible for blocks which were already mined.\n uint32 lastBlockNumber = tokenCheckpoints[_token][end - 1].blockNumber;\n if (block.number == lastBlockNumber) {\n end--;\n }\n return end;\n }\n\n /**\n * @notice Write a regular checkpoint w/ the foolowing data:\n * block number, block timestamp, total weighted stake and num of tokens.\n * @param _token The pool token address.\n * @param _numTokens The amount of pool tokens.\n * */\n function _writeTokenCheckpoint(address _token, uint96 _numTokens) internal {\n uint32 blockNumber =\n safe32(\n block.number,\n \"FeeSharingCollector::_writeCheckpoint: block number exceeds 32 bits\"\n );\n uint32 blockTimestamp =\n safe32(\n block.timestamp,\n \"FeeSharingCollector::_writeCheckpoint: block timestamp exceeds 32 bits\"\n );\n uint256 nextCheckpointsIndex = totalTokenCheckpoints[_token];\n\n uint96 totalWeightedStake = _getVoluntaryWeightedStake(blockNumber - 1, block.timestamp);\n require(totalWeightedStake > 0, \"Invalid totalWeightedStake\");\n if (\n nextCheckpointsIndex > 0 &&\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].blockNumber == blockNumber\n ) {\n tokenCheckpoints[_token][nextCheckpointsIndex - 1]\n .totalWeightedStake = totalWeightedStake;\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].numTokens = _numTokens;\n } else {\n tokenCheckpoints[_token][nextCheckpointsIndex] = Checkpoint(\n blockNumber,\n blockTimestamp,\n totalWeightedStake,\n _numTokens\n );\n totalTokenCheckpoints[_token] = nextCheckpointsIndex + 1;\n }\n emit CheckpointAdded(msg.sender, _token, _numTokens);\n }\n\n /**\n * Queries the total weighted stake and the weighted stake of vesting contracts and returns the difference\n * @param blockNumber the blocknumber\n * @param timestamp the timestamp\n */\n function _getVoluntaryWeightedStake(uint32 blockNumber, uint256 timestamp)\n internal\n view\n returns (uint96 totalWeightedStake)\n {\n uint96 vestingWeightedStake = staking.getPriorVestingWeightedStake(blockNumber, timestamp);\n totalWeightedStake = staking.getPriorTotalVotingPower(blockNumber, timestamp);\n totalWeightedStake = sub96(\n totalWeightedStake,\n vestingWeightedStake,\n \"FeeSharingCollector::_getTotalVoluntaryWeightedStake: vested stake exceeds total stake\"\n );\n }\n\n /**\n * @dev Whitelisting converter address.\n *\n * @param converterAddress converter address to be whitelisted.\n */\n function addWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n require(Address.isContract(converterAddress), \"Non contract address given\");\n whitelistedConverterList.add(converterAddress);\n emit WhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @dev Removing converter address from whitelist.\n *\n * @param converterAddress converter address to be removed from whitelist.\n */\n function removeWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n whitelistedConverterList.remove(converterAddress);\n emit UnwhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @notice Getter to query all of the whitelisted converter.\n * @return All of the whitelisted converter list.\n */\n function getWhitelistedConverterList() external view returns (address[] memory converterList) {\n converterList = whitelistedConverterList.enumerate();\n }\n\n /**\n * @dev validate array of given address whether is whitelisted or not.\n * @dev if one of them is not whitelisted, then revert.\n *\n * @param converterAddresses array of converter addresses.\n */\n function _validateWhitelistedConverter(address[] memory converterAddresses) private view {\n for (uint256 i = 0; i < converterAddresses.length; i++) {\n require(whitelistedConverterList.contains(converterAddresses[i]), \"Invalid Converter\");\n }\n }\n\n function withdrawWRBTC(address receiver, uint256 wrbtcAmount) external onlyOwner {\n IERC20 wrbtcToken = IERC20(wrbtcTokenAddress);\n\n uint256 balance = wrbtcToken.balanceOf(address(this));\n require(wrbtcAmount <= balance, \"Insufficient balance\");\n\n wrbtcToken.safeTransfer(receiver, wrbtcAmount);\n }\n\n /**\n * @dev This function is dedicated to recover the wrong fee allocation for the 4 year vesting contracts.\n * This function can only be called once\n * The affected tokens to be withdrawn\n * 1. RBTC\n * 2. ZUSD\n * 3. SOV\n * The amount for all of the tokens above is hardcoded\n * The withdrawn tokens will be sent to the owner.\n */\n function recoverIncorrectAllocatedFees()\n external\n oneTimeExecution(this.recoverIncorrectAllocatedFees.selector)\n onlyOwner\n {\n uint256 rbtcAmount = 878778886164898400;\n uint256 zusdAmount = 16658600400155126000000;\n uint256 sovAmount = 6275898259771202000000;\n\n address zusdToken = 0xdB107FA69E33f05180a4C2cE9c2E7CB481645C2d;\n address sovToken = 0xEFc78fc7d48b64958315949279Ba181c2114ABBd;\n\n // Withdraw rbtc\n (bool success, ) = owner().call.value(rbtcAmount)(\"\");\n require(\n success,\n \"FeeSharingCollector::recoverIncorrectAllocatedFees: Withdrawal rbtc failed\"\n );\n\n // Withdraw ZUSD\n IERC20(zusdToken).safeTransfer(owner(), zusdAmount);\n\n // Withdraw SOV\n IERC20(sovToken).safeTransfer(owner(), sovAmount);\n }\n\n /**\n * @dev view function that calculate the total RBTC that includes:\n * - RBTC\n * - WRBTC\n * - iWRBTC * iWRBTC.tokenPrice()\n * @param _user address of the user.\n * @return rbtc balance of the given user's address.\n */\n function getAccumulatedRBTCFeeBalances(address _user) external view returns (uint256) {\n (uint256 _rbtcAmount, uint256 _wrbtcAmount, uint256 _iWrbtcAmount, , , ) =\n _getRBTCBalances(_user, 0);\n uint256 iWRBTCAmountInRBTC =\n _iWrbtcAmount.mul(ILoanTokenWRBTC(loanTokenWrbtcAddress).tokenPrice()).div(1e18);\n return _rbtcAmount.add(_wrbtcAmount).add(iWRBTCAmountInRBTC);\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _rbtcAmount rbtc amount\n * @return _wrbtcAmount wrbtc amount\n * @return _iWrbtcAmount iWrbtc (wrbtc lending pool token) amount * token price\n * @return _endRBTC end time of accumulated fee calculation for rbtc\n * @return _endWRBTC end time of accumulated fee calculation for wrbtc\n * @return _endIWRBTC end time of accumulated fee calculation for iwrbtc\n */\n function _getRBTCBalances(address _user, uint32 _maxCheckpoints)\n private\n view\n returns (\n uint256 _rbtcAmount,\n uint256 _wrbtcAmount,\n uint256 _iWrbtcAmount,\n uint256 _endRBTC,\n uint256 _endWRBTC,\n uint256 _endIWRBTC\n )\n {\n (_rbtcAmount, _endRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n\n (_wrbtcAmount, _endWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: wrbtcTokenAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n (_iWrbtcAmount, _endIWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: loanTokenWrbtcAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _token either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _tokenAmount token (rbtc, or wrbtc, or iwrbtc) amount\n * @return _endToken end time of accumulated fee calculation for token (rbtc, or wrbtc, or iwrbtc )\n */\n function _getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 _tokenAmount, uint256 _endToken) {\n if (\n _token == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT ||\n _token == wrbtcTokenAddress ||\n _token == loanTokenWrbtcAddress\n ) {\n (_tokenAmount, _endToken) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n } else {\n revert(\"FeeSharingCollector::_getRBTCBalance: only rbtc-based tokens are allowed\");\n }\n }\n\n // @todo update dependency `numTokenCheckpoints` -> `totalTokenCheckpoints` and deprecate numTokenCheckpoints function\n /**\n * @dev This getter function `numTokenCheckpoints` is added for backwards compatibility\n * broken when renamed `numTokenCheckpoints` storage variable to `totalTokenCheckpoints`.\n *\n * @param _token token address to get checkpoints for\n *\n * @return Total token checkpoints\n */\n function numTokenCheckpoints(address _token) external view returns (uint256) {\n return totalTokenCheckpoints[_token];\n }\n}\n\n/* Interfaces */\ninterface ILoanToken {\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n}\n\ninterface ILoanTokenWRBTC {\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function tokenPrice() external view returns (uint256 price);\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title FeeSharingCollectorProxy contract.\n * @dev FeeSharingCollectorProxy contract should be upgradable, use UpgradableProxy.\n * FeeSharingCollectorStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract FeeSharingCollectorProxy is FeeSharingCollectorStorage, UpgradableProxy {\n /**\n * @notice Construct a new feeSharingCollectorProxy contract.\n * @param _protocol The address of the sovryn protocol.\n * @param _staking The address of the staking\n */\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorStorage.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../mixins/EnumerableAddressSet.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\n\n/**\n * @title FeeSharingCollectorStorage contact\n * @notice Just the storage part of FeeSharingCollector contract, and FeeSharingCollectorProxy. No functions,\n * only constant, variables and required structures (mappings)\n * */\ncontract FeeSharingCollectorStorage is Ownable {\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet;\n uint256 constant FEE_WITHDRAWAL_INTERVAL = 172800;\n\n IProtocol public protocol;\n IStaking public staking;\n\n /// @notice Checkpoints by index per pool token address\n mapping(address => mapping(uint256 => Checkpoint)) public tokenCheckpoints;\n\n /// @notice The number of checkpoints for each token address.\n mapping(address => uint256) public totalTokenCheckpoints;\n\n /// @notice\n /// user => token => processed checkpoints\n mapping(address => mapping(address => uint256)) public processedCheckpoints;\n\n /// @notice Last time fees were withdrawn per pool token address:\n /// token => time\n mapping(address => uint256) public lastFeeWithdrawalTime;\n\n /// @notice Amount of tokens that were transferred, but not saved in checkpoints.\n /// token => amount\n mapping(address => uint96) public unprocessedAmount;\n\n struct Checkpoint {\n uint32 blockNumber;\n uint32 timestamp;\n uint96 totalWeightedStake;\n uint96 numTokens;\n }\n\n struct TokenWithSkippedCheckpointsWithdraw {\n address tokenAddress;\n uint256 fromCheckpoint;\n }\n\n /**\n * @dev Add extra modifier (Reentrancy) below.\n * Because we cannot add any additional storage slot before this storage contract after initial deployment\n */\n\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Additional storage for converter whitelist mechanism.\n * @dev Initialization here does not works. We need to create a separate setter & getter.\n * @dev Just set the visibility to internal should be fine.\n */\n EnumerableAddressSet.AddressSet internal whitelistedConverterList;\n\n mapping(bytes4 => bool) public isFunctionExecuted;\n\n /**\n * @dev Wrbtc token address\n */\n address public wrbtcTokenAddress;\n\n /**\n * @dev iWrbtc loan token address\n */\n address public loanTokenWrbtcAddress;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n\n/* Interfaces */\n\ninterface IProtocol {\n /**\n *\n * @param tokens The array address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function underlyingToLoanPool(address token) external view returns (address);\n\n function wrbtcToken() external view returns (IWrbtcERC20);\n\n function getSovTokenAddress() external view returns (address);\n}\n" + }, + "contracts/governance/GovernorAlpha.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./Staking/SafeMath96.sol\";\nimport \"./Timelock.sol\";\nimport \"./Staking/interfaces/IStaking.sol\";\nimport \"../rsk/RSKAddrValidator.sol\";\n\n/**\n * @title Governance Contract.\n * @notice This is an adapted clone of compound’s governance model. In general,\n * the process is the same: Token holders can make (executable) proposals if\n * they possess enough voting power, vote on proposals during a predefined\n * voting period and in the end evaluate the outcome. If successful, the\n * proposal will be scheduled on the timelock contract. Only after sufficient\n * time passed, it can be executed. A minimum voting power is required for\n * making a proposal as well as a minimum quorum.\n *\n * Voting power in the Bitocracy:\n * Stakers will receive voting power in the Bitocracy in return for their\n * staking commitment. This voting power is weighted by how much SOV is staked\n * and for how long the staking period is - staking more SOV over longer staking\n * periods results in higher voting power. With this voting power, users can\n * vote for or against any SIP in bitocracy.sovryn.app.\n * */\ncontract GovernorAlpha is SafeMath96 {\n /* Storage */\n\n /// @notice The name of this contract.\n string public constant NAME = \"Sovryn Governor Alpha\";\n\n /// @notice The maximum number of actions that can be included in a proposal.\n function proposalMaxOperations() public pure returns (uint256) {\n return 10;\n } // 10 actions\n\n /// @notice The delay before voting on a proposal may take place, once proposed.\n function votingDelay() public pure returns (uint256) {\n return 1;\n } // 1 block\n\n /// @notice The duration of voting on a proposal, in blocks.\n function votingPeriod() public pure returns (uint256) {\n return 2880;\n } // ~1 day in blocks (assuming 30s blocks)\n\n /// @notice The address of the Sovryn Protocol Timelock.\n ITimelock public timelock;\n\n /// @notice The address of the Sovryn staking contract.\n IStaking public staking;\n\n /// @notice The address of the Governor Guardian.\n address public guardian;\n\n /// @notice The total number of proposals.\n uint256 public proposalCount;\n\n /// @notice Percentage of current total voting power require to vote.\n uint96 public quorumPercentageVotes;\n\n // @notice Majority percentage.\n uint96 public majorityPercentageVotes;\n\n struct Proposal {\n /// @notice Unique id for looking up a proposal.\n uint256 id;\n /// @notice The block at which voting begins: holders must delegate their votes prior to this block.\n uint32 startBlock;\n /// @notice The block at which voting ends: votes must be cast prior to this block.\n uint32 endBlock;\n /// @notice Current number of votes in favor of this proposal.\n uint96 forVotes;\n /// @notice Current number of votes in opposition to this proposal.\n uint96 againstVotes;\n ///@notice the quorum required for this proposal.\n uint96 quorum;\n ///@notice the majority percentage required for this proposal.\n uint96 majorityPercentage;\n /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds.\n uint64 eta;\n /// @notice the start time is required for the staking contract.\n uint64 startTime;\n /// @notice Flag marking whether the proposal has been canceled.\n bool canceled;\n /// @notice Flag marking whether the proposal has been executed.\n bool executed;\n /// @notice Creator of the proposal.\n address proposer;\n /// @notice the ordered list of target addresses for calls to be made.\n address[] targets;\n /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made.\n uint256[] values;\n /// @notice The ordered list of function signatures to be called.\n string[] signatures;\n /// @notice The ordered list of calldata to be passed to each call.\n bytes[] calldatas;\n /// @notice Receipts of ballots for the entire set of voters.\n mapping(address => Receipt) receipts;\n }\n\n /// @notice Ballot receipt record for a voter\n struct Receipt {\n /// @notice Whether or not a vote has been cast.\n bool hasVoted;\n /// @notice Whether or not the voter supports the proposal.\n bool support;\n /// @notice The number of votes the voter had, which were cast.\n uint96 votes;\n }\n\n /// @notice Possible states that a proposal may be in.\n enum ProposalState {\n Pending,\n Active,\n Canceled,\n Defeated,\n Succeeded,\n Queued,\n Expired,\n Executed\n }\n\n /// @notice The official record of all proposals ever proposed.\n mapping(uint256 => Proposal) public proposals;\n\n /// @notice The latest proposal for each proposer.\n mapping(address => uint256) public latestProposalIds;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the ballot struct used by the contract.\n bytes32 public constant BALLOT_TYPEHASH = keccak256(\"Ballot(uint256 proposalId,bool support)\");\n\n /* Events */\n\n /// @notice An event emitted when a new proposal is created.\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint256 startBlock,\n uint256 endBlock,\n string description\n );\n\n /// @notice An event emitted when a vote has been cast on a proposal.\n event VoteCast(address voter, uint256 proposalId, bool support, uint256 votes);\n\n /// @notice An event emitted when a proposal has been canceled.\n event ProposalCanceled(uint256 id);\n\n /// @notice An event emitted when a proposal has been queued in the Timelock.\n event ProposalQueued(uint256 id, uint256 eta);\n\n /// @notice An event emitted when a proposal has been executed in the Timelock.\n event ProposalExecuted(uint256 id);\n\n /* Functions */\n\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 _quorumPercentageVotes,\n uint96 _majorityPercentageVotes\n ) public {\n timelock = ITimelock(timelock_);\n staking = IStaking(staking_);\n guardian = guardian_;\n quorumPercentageVotes = _quorumPercentageVotes;\n majorityPercentageVotes = _majorityPercentageVotes;\n }\n\n /// @notice The number of votes required in order for a voter to become a proposer.\n function proposalThreshold() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(\n block.number - 1,\n \"GovernorAlpha::proposalThreshold: block number overflow\"\n ),\n block.timestamp\n );\n // 1% of current total voting power.\n return totalVotingPower / 100;\n }\n\n /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.\n function quorumVotes() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(block.number - 1, \"GovernorAlpha::quorumVotes: block number overflow\"),\n block.timestamp\n );\n // 4% of current total voting power.\n return\n mul96(\n quorumPercentageVotes,\n totalVotingPower,\n \"GovernorAlpha::quorumVotes:multiplication overflow\"\n ) / 100;\n }\n\n /**\n * @notice Create a new proposal.\n * @param targets Array of contract addresses to perform proposal execution.\n * @param values Array of rBTC amounts to send on proposal execution.\n * @param signatures Array of function signatures to call on proposal execution.\n * @param calldatas Array of payloads for the calls on proposal execution.\n * @param description Text describing the purpose of the proposal.\n * */\n function propose(\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // note: passing this block's timestamp, but the number of the previous block.\n // todo: think if it would be better to pass block.timestamp - 30 (average block time)\n // (probably not because proposal starts in 1 block from now).\n uint96 threshold = proposalThreshold();\n require(\n staking.getPriorVotes(msg.sender, sub256(block.number, 1), block.timestamp) >\n threshold,\n \"GovernorAlpha::propose: proposer votes below proposal threshold\"\n );\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"GovernorAlpha::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"GovernorAlpha::propose: must provide actions\");\n require(\n targets.length <= proposalMaxOperations(),\n \"GovernorAlpha::propose: too many actions\"\n );\n\n uint256 latestProposalId = latestProposalIds[msg.sender];\n if (latestProposalId != 0) {\n ProposalState proposersLatestProposalState = state(latestProposalId);\n require(\n proposersLatestProposalState != ProposalState.Active,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already active proposal\"\n );\n require(\n proposersLatestProposalState != ProposalState.Pending,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal\"\n );\n }\n\n uint256 startBlock = add256(block.number, votingDelay());\n uint256 endBlock = add256(startBlock, votingPeriod());\n\n proposalCount++;\n\n /// @dev quorum: proposalThreshold is 1% of total votes, we can save gas using this pre calculated value.\n /// @dev startTime: Required by the staking contract. not used by the governance contract itself.\n Proposal memory newProposal =\n Proposal({\n id: proposalCount,\n startBlock: safe32(\n startBlock,\n \"GovernorAlpha::propose: start block number overflow\"\n ),\n endBlock: safe32(endBlock, \"GovernorAlpha::propose: end block number overflow\"),\n forVotes: 0,\n againstVotes: 0,\n quorum: mul96(\n quorumPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on quorum computation\"\n ),\n majorityPercentage: mul96(\n majorityPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on majorityPercentage computation\"\n ),\n eta: 0,\n startTime: safe64(block.timestamp, \"GovernorAlpha::propose: startTime overflow\"),\n canceled: false,\n executed: false,\n proposer: msg.sender,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas\n });\n\n proposals[newProposal.id] = newProposal;\n latestProposalIds[newProposal.proposer] = newProposal.id;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n values,\n signatures,\n calldatas,\n startBlock,\n endBlock,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Enqueue a proposal and everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function queue(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Succeeded,\n \"GovernorAlpha::queue: proposal can only be queued if it is succeeded\"\n );\n Proposal storage proposal = proposals[proposalId];\n uint256 eta = add256(block.timestamp, timelock.delay());\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n proposal.eta = safe64(eta, \"GovernorAlpha::queue: ETA overflow\");\n emit ProposalQueued(proposalId, eta);\n }\n\n /**\n * @notice Tries to enqueue a proposal, verifying it has not been previously queued.\n * @param target Contract addresses to perform proposal execution.\n * @param value rBTC amount to send on proposal execution.\n * @param signature Function signature to call on proposal execution.\n * @param data Payload for the call on proposal execution.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function _queueOrRevert(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !timelock.queuedTransactions(\n keccak256(abi.encode(target, value, signature, data, eta))\n ),\n \"GovernorAlpha::_queueOrRevert: proposal action already queued at eta\"\n );\n timelock.queueTransaction(target, value, signature, data, eta);\n }\n\n /**\n * @notice Execute a proposal by looping and performing everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function execute(uint256 proposalId) public payable {\n require(\n state(proposalId) == ProposalState.Queued,\n \"GovernorAlpha::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.executeTransaction.value(proposal.values[i])(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal by looping and cancelling everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function cancel(uint256 proposalId) public {\n ProposalState state = state(proposalId);\n require(\n state != ProposalState.Executed,\n \"GovernorAlpha::cancel: cannot cancel executed proposal\"\n );\n\n Proposal storage proposal = proposals[proposalId];\n /// @notice Cancel only if sent by the guardian.\n require(msg.sender == guardian, \"GovernorAlpha::cancel: sender isn't a guardian\");\n\n proposal.canceled = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalCanceled(proposalId);\n }\n\n /**\n * @notice Get a proposal list of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return Arrays of the 4 call parameters: targets, values, signatures, calldatas.\n * */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.values, p.signatures, p.calldatas);\n }\n\n /**\n * @notice Get a proposal receipt.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param voter A governance stakeholder with voting power.\n * @return The voter receipt of the proposal.\n * */\n function getReceipt(uint256 proposalId, address voter) public view returns (Receipt memory) {\n return proposals[proposalId].receipts[voter];\n }\n\n /**\n * @notice Casts a vote by sender.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function castVote(uint256 proposalId, bool support) public {\n return _castVote(msg.sender, proposalId, support);\n }\n\n /**\n * @notice Voting with EIP-712 Signatures.\n *\n * Voting power can be delegated to any address, and then can be used to\n * vote on proposals. A key benefit to users of by-signature functionality\n * is that they can create a signed vote transaction for free, and have a\n * trusted third-party spend rBTC(or ETH) on gas fees and write it to the\n * blockchain for them.\n *\n * The third party in this scenario, submitting the SOV-holder’s signed\n * transaction holds a voting power that is for only a single proposal.\n * The signatory still holds the power to vote on their own behalf in\n * the proposal if the third party has not yet published the signed\n * transaction that was given to them.\n *\n * @dev The signature needs to be broken up into 3 parameters, known as\n * v, r and s:\n * const r = '0x' + sig.substring(2).substring(0, 64);\n * const s = '0x' + sig.substring(2).substring(64, 128);\n * const v = '0x' + sig.substring(2).substring(128, 130);\n *\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * @param v The recovery byte of the signature.\n * @param r Half of the ECDSA signature pair.\n * @param s Half of the ECDSA signature pair.\n * */\n function castVoteBySig(\n uint256 proposalId,\n bool support,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public {\n /**\n * @dev The DOMAIN_SEPARATOR is a hash that uniquely identifies a\n * smart contract. It is built from a string denoting it as an\n * EIP712 Domain, the name of the token contract, the version,\n * the chainId in case it changes, and the address that the\n * contract is deployed at.\n * */\n bytes32 domainSeparator =\n keccak256(\n abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this))\n );\n\n /// @dev GovernorAlpha uses BALLOT_TYPEHASH, while Staking uses DELEGATION_TYPEHASH\n bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support));\n\n bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n address signatory = ecrecover(digest, v, r, s);\n\n /// @dev Verify address is not null and PK is not null either.\n require(\n RSKAddrValidator.checkPKNotZero(signatory),\n \"GovernorAlpha::castVoteBySig: invalid signature\"\n );\n return _castVote(signatory, proposalId, support);\n }\n\n /**\n * @notice Cast a vote, adding it to the total counting.\n * @param voter A governance stakeholder with voting power that is casting the vote.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function _castVote(\n address voter,\n uint256 proposalId,\n bool support\n ) internal {\n require(\n state(proposalId) == ProposalState.Active,\n \"GovernorAlpha::_castVote: voting is closed\"\n );\n Proposal storage proposal = proposals[proposalId];\n Receipt storage receipt = proposal.receipts[voter];\n require(receipt.hasVoted == false, \"GovernorAlpha::_castVote: voter already voted\");\n uint96 votes = staking.getPriorVotes(voter, proposal.startBlock, proposal.startTime);\n\n if (support) {\n proposal.forVotes = add96(\n proposal.forVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n } else {\n proposal.againstVotes = add96(\n proposal.againstVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n }\n\n receipt.hasVoted = true;\n receipt.support = support;\n receipt.votes = votes;\n\n emit VoteCast(voter, proposalId, support, votes);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __acceptAdmin() public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__acceptAdmin: sender must be gov guardian\"\n );\n timelock.acceptAdmin();\n }\n\n /// @notice Sets guardian address to zero.\n function __abdicate() public {\n require(msg.sender == guardian, \"GovernorAlpha::__abdicate: sender must be gov guardian\");\n guardian = address(0);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.queueTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.executeTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /**\n * @notice Get a proposal state.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return The state of the proposal: Canceled, Pending, Active, Defeated,\n * Succeeded, Executed, Expired.\n * */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"GovernorAlpha::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n\n if (proposal.canceled) {\n return ProposalState.Canceled;\n }\n\n if (block.number <= proposal.startBlock) {\n return ProposalState.Pending;\n }\n\n if (block.number <= proposal.endBlock) {\n return ProposalState.Active;\n }\n\n uint96 totalVotes =\n add96(\n proposal.forVotes,\n proposal.againstVotes,\n \"GovernorAlpha:: state: forVotes + againstVotes > uint96\"\n );\n uint96 totalVotesMajorityPercentage =\n div96(totalVotes, 100, \"GovernorAlpha:: state: division error\");\n totalVotesMajorityPercentage = mul96(\n totalVotesMajorityPercentage,\n majorityPercentageVotes,\n \"GovernorAlpha:: state: totalVotes * majorityPercentage > uint96\"\n );\n if (proposal.forVotes <= totalVotesMajorityPercentage || totalVotes < proposal.quorum) {\n return ProposalState.Defeated;\n }\n\n if (proposal.eta == 0) {\n return ProposalState.Succeeded;\n }\n\n if (proposal.executed) {\n return ProposalState.Executed;\n }\n\n if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) {\n return ProposalState.Expired;\n }\n\n return ProposalState.Queued;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function add256(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"addition overflow\");\n return c;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function sub256(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b <= a, \"subtraction underflow\");\n return a - b;\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n}\n\n/* Interfaces */\n\ninterface TimelockInterface {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\ninterface StakingInterface {\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n}\n" + }, + "contracts/governance/GovernorVault.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title Governance Vault.\n * @notice This contract stores tokens and rBTC only transfereble by owner,\n * i.e. Sovryn governance.\n * */\ncontract GovernorVault is Ownable {\n /* Events */\n\n event Deposited(address indexed sender, uint256 amount);\n event TokensTransferred(address indexed receiver, address indexed token, uint256 amount);\n event RbtcTransferred(address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer tokens.\n * @param _receiver The receiver of tokens.\n * @param _token The address of token contract.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _receiver,\n address _token,\n uint256 _amount\n ) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n require(_token != address(0), \"Invalid token address\");\n\n require(IERC20(_token).transfer(_receiver, _amount), \"Transfer failed\");\n emit TokensTransferred(_receiver, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC.\n * @param _receiver The receiver of RBTC.\n * @param _amount The amount to be transferred.\n * */\n function transferRbtc(address payable _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n\n address(_receiver).transfer(_amount);\n emit RbtcTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {\n if (msg.value > 0) {\n emit Deposited(msg.sender, msg.value);\n }\n }\n}\n" + }, + "contracts/governance/IFeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * */\ninterface IFeeSharingCollector {\n function withdrawFees(address[] calldata _token) external;\n\n function transferTokens(address _token, uint96 _amount) external;\n\n function withdraw(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external;\n}\n" + }, + "contracts/governance/Staking/interfaces/IStaking.sol": { + "content": "pragma solidity ^0.5.17;\n\npragma experimental ABIEncoderV2;\n\n/**\n * @title Interface for Staking modules governance/Staking/modules\n */\n\ninterface IStaking {\n /*************************** StakingAdminModule ***************************/\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external;\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external;\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external;\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external;\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) external;\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external;\n\n /**\n * @notice Allows the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external;\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external;\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external;\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\n\n /*************************** StakingGovernanceModule ***************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\n * be internal instead of a public function.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external;\n\n /*************************** StakingStakeModule ***************************/\n\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance);\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes);\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\n\n /*************************** StakingStorageModule ***************************/\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n /// @return uint256(MAX_VOTING_WEIGHT);\n function getStorageMaxVotingWeight() external pure returns (uint256);\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n /// @return uint256(WEIGHT_FACTOR);\n function getStorageWeightFactor() external pure returns (uint256);\n\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\n function getStorageDefaultWeightScaling() external pure returns (uint256);\n\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\n\n /// @notice The EIP-712 typehash for the contract's domain.\n /// @return uint256(DOMAIN_TYPEHASH);\n function getStorageDomainTypehash() external pure returns (uint256);\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n /// @return uint256(DELEGATION_TYPEHASH);\n function getStorageDelegationTypehash() external pure returns (uint256);\n\n /// @return name;\n function getStorageName() external view returns (string memory);\n\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n function kickoffTS() external view returns (uint256);\n\n /// @notice The token to be staked\n function SOVToken() external view returns (address);\n\n /// @notice Stakers delegated voting power\n /// @param staker - the delegating address\n /// @param until - delegated voting\n /// @return _delegate - voting power delegated to address\n function delegates(address staker, uint256 until) external view returns (address _delegate);\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately\n /// see function unlockAllTokens() for details\n function allUnlocked() external view returns (bool);\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\n function newStakingContract() external view returns (address);\n\n /// CHECKPOINTS\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\n function totalStakingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n function numTotalStakingCheckpoints(uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n function delegateStakingCheckpoints(\n address delagatee,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n function userStakingCheckpoints(\n address user,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number\n function numUserStakingCheckpoints(address user, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n function nonces(address user) external view returns (uint256 nonce);\n\n /// SLASHING ///\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n function feeSharing() external view returns (address);\n\n /// @notice used for weight scaling when unstaking with slashing.\n /// @return uint96 DEFAULT_WEIGHT_SCALING\n function weightScaling() external view returns (uint96);\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n function admins(address isAdmin) external view returns (bool);\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n function vestingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\n\n ///@notice vesting registry contract PROXY address\n function vestingRegistryLogic() external view returns (address);\n\n /// @dev user => flag whether user has pauser role.\n function pausers(address isPauser) external view returns (bool);\n\n /// @dev Staking contract is paused\n function paused() external view returns (bool);\n\n /// @dev Staking contract is frozen\n function frozen() external view returns (bool);\n\n /*************************** StakingVestingModule ***************************/\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool);\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external;\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external;\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes);\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n /*************************** StakingWithdrawModule ***************************/\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * */\n function governanceWithdrawVesting(address vesting, address receiver) external;\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96);\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external;\n\n /*************************** WeightedStakingModule ***************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The date/timestamp of the unstaking time.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * TODO: WeightedStaking::weightedStakeByDate should probably better\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Returns public constant MAX_DURATION\n * preserved for backwards compatibility\n * Use getStorageMaxDurationToStakeTokens()\n * @return uint96 MAX_DURATION for staking\n **/\n function MAX_DURATION() external view returns (uint256);\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() external view returns (address);\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() external view returns (bool);\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) external;\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external;\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() external view returns (uint256);\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param maxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\n}\n" + }, + "contracts/governance/Staking/modules/shared/CheckpointsShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\n\n/**\n * @title Checkpoints contract.\n * @notice Increases and decreases storage values for users, delegatees and\n * total daily stake.\n * */\ncontract CheckpointsShared is StakingStorageShared, SafeMath96 {\n /// @notice An event emitted when an account changes its delegate.\n event DelegateChanged(\n address indexed delegator,\n uint256 lockedUntil,\n address indexed fromDelegate,\n address indexed toDelegate\n );\n\n /// @notice An event emitted when a delegate account's stake balance changes.\n event DelegateStakeChanged(\n address indexed delegate,\n uint256 lockedUntil,\n uint256 previousBalance,\n uint256 newBalance\n );\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n event ContractCodeHashAdded(bytes32 hash);\n\n event ContractCodeHashRemoved(bytes32 hash);\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n event TeamVestingCancelled(address indexed caller, address receiver);\n\n event TeamVestingPartiallyCancelled(\n address indexed caller,\n address receiver,\n uint256 lastProcessedDate\n );\n\n constructor() internal {\n // abstract\n }\n\n /**\n * @notice Increases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = add96(vested, value, \"CP01\"); // vested overflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Decreases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = sub96(vested, value, \"CP02\"); // vested underflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Writes on storage the user vested amount.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newVest The new vest balance.\n * */\n function _writeVestingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newVest\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP03\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n vestingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n vestingCheckpoints[lockedTS][nCheckpoints - 1].stake = newVest;\n } else {\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newVest);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP04\"); // staked overflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP05\"); // staked underflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the user stake.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeUserCheckpoint(\n address account,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP06\"); // block number > 32 bits\n\n if (\n nCheckpoints > 0 &&\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n userStakingCheckpoints[account][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numUserStakingCheckpoints[account][lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP07\"); // block number > 32 bits\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = 0;\n // @dev We need to check delegate checkpoint value here,\n //\t\tbecause we had an issue in `stake` function:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n // @dev It can be greater than 0, but inconsistent after 3 transactions\n if (staked > value) {\n newStake = sub96(staked, value, \"CP08\"); // staked underflow\n }\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the delegate stake.\n * @param delegatee The delegate address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeDelegateCheckpoint(\n address delegatee,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP09\"); // block numb > 32 bits\n uint96 oldStake = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n\n if (\n nCheckpoints > 0 &&\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].fromBlock ==\n blockNumber\n ) {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numDelegateStakingCheckpoints[delegatee][lockedTS] = nCheckpoints + 1;\n }\n emit DelegateStakeChanged(delegatee, lockedTS, oldStake, newStake);\n }\n\n /**\n * @notice Increases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP10\"); // staked overflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP11\"); // staked underflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the total stake.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeStakingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP12\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n totalStakingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newStake);\n numTotalStakingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Get the current balance of an account locked until a certain date.\n * @param account The user address.\n * @param lockDate The lock date.\n * @return The stake amount.\n * */\n function _currentBalance(address account, uint256 lockDate) internal view returns (uint96) {\n uint32 _numUnserStakingCheckpoints = numUserStakingCheckpoints[account][lockDate] - 1;\n return userStakingCheckpoints[account][lockDate][_numUnserStakingCheckpoints].stake;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\nimport \"../../../../openzeppelin/SafeMath.sol\";\nimport \"../../../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking modules shared functionality\n */\ncontract StakingShared is StakingStorageShared, SafeMath96 {\n using SafeMath for uint256;\n\n uint256 internal constant FOUR_WEEKS = 4 weeks;\n\n /**\n * @dev Throws if paused.\n */\n modifier whenNotPaused() {\n require(!paused, \"paused\"); // SS03\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\"); // SS01\n _;\n }\n\n /**\n\t * @dev Throws if called by any account other than the owner or admin or pauser.\n\t \n\tmodifier onlyAuthorizedOrPauser() {\n\t\trequire(isOwner() || admins[msg.sender] || pausers[msg.sender], \"unauthorized\"); // WS02\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if called by any account other than the owner or pauser.\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || pausers[msg.sender], \"unauthorized\"); // SS02\n _;\n }\n\n /**\n * @dev Throws if called by any account other than pauser.\n * @notice Uncomment when needed\n */\n /*\n\tmodifier onlyPauser() {\n\t\trequire(pausers[msg.sender], \"Not pauser\");\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if frozen.\n */\n modifier whenNotFrozen() {\n require(!frozen, \"paused\"); // SS04\n _;\n }\n\n constructor() internal {\n // abstract\n }\n\n function _notSameBlockAsStakingCheckpoint(uint256 lockDate, address stakeFor) internal view {\n uint32 nCheckpoints = numUserStakingCheckpoints[stakeFor][lockDate];\n bool notSameBlock =\n userStakingCheckpoints[stakeFor][lockDate][nCheckpoints - 1].fromBlock != block.number;\n require(notSameBlock, \"cannot be mined in the same block as last stake\"); // S20\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = kickoffTS;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / TWO_WEEKS;\n lockDate = periodFromKickoff * TWO_WEEKS + start;\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS14\n\n date = _adjustDateForOrigin(date);\n uint32 nCheckpoints = numUserStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (userStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return userStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (userStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = userStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return userStakingCheckpoints[account][date][lower].stake;\n }\n\n /**\n * @dev origin vesting contracts have different dates\n * we need to add 2 weeks to get end of period (by default, it's start)\n * @param date The staking date to compute the power for.\n * @return unlocking date.\n */\n function _adjustDateForOrigin(uint256 date) internal view returns (uint256) {\n uint256 adjustedDate = _timestampToLockDate(date);\n //origin vesting contracts have different dates\n //we need to add 2 weeks to get end of period (by default, it's start)\n if (adjustedDate != date) {\n date = adjustedDate + TWO_WEEKS;\n }\n return date;\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function _computeWeightByDate(uint256 date, uint256 startDate)\n internal\n pure\n returns (uint96 weight)\n {\n require(date >= startDate, \"date < startDate\"); // WS18\n uint256 remainingTime = (date - startDate);\n require(MAX_DURATION >= remainingTime, \"remaining time > max duration\"); // WS19\n /// @dev x = max days - remaining days\n uint96 x = uint96(MAX_DURATION - remainingTime) / (1 days);\n /// @dev w = (m^2 - x^2)/m^2 +1 (multiplied by the weight factor)\n weight = add96(\n WEIGHT_FACTOR,\n mul96(\n MAX_VOTING_WEIGHT * WEIGHT_FACTOR,\n sub96(\n MAX_DURATION_POW_2,\n x * x,\n \"weight underflow\" // WS20\n ),\n \"weight mul overflow\" // WS21\n ) / MAX_DURATION_POW_2,\n \"overflow on weight\" // WS22\n );\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function _isVestingContract(address stakerAddress) internal view returns (bool) {\n bool isVesting;\n bytes32 codeHash;\n\n assembly {\n codeHash := extcodehash(stakerAddress)\n }\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingStorageShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../../openzeppelin/Ownable.sol\";\nimport \"../../../../interfaces/IERC20.sol\";\nimport \"../../../IFeeSharingCollector.sol\";\nimport \"../../../Vesting/IVestingRegistry.sol\";\n\n/**\n * @title StakingStorageShared contract is inherited by Staking modules.\n * @notice Just the storage part of stacking contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingProxy and Checkpoints contracts.\n *\n * What is SOV staking?\n * The purpose of the SOV token is to provide a pseudonymous,\n * censorship-resistant mechanism for governing the parameters of the Sovryn\n * protocol, while aligning the incentives of protocol governors with the\n * long-term success of the protocol. Any SOV token holder can choose to\n * stake (lock up) their tokens for a fixed period of time in return for\n * voting rights in the Bitocracy. Stakers are further incentivised through\n * fee and slashing rewards.\n * */\ncontract StakingStorageShared is Ownable {\n /// @notice 2 weeks in seconds.\n uint256 constant TWO_WEEKS = 1209600;\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n uint96 public constant MAX_VOTING_WEIGHT = 9;\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n uint96 public constant WEIGHT_FACTOR = 10;\n\n /// @notice The maximum duration to stake tokens for.\n uint256 public constant MAX_DURATION = 1092 days;\n\n /// @notice The maximum duration ^2\n uint96 constant MAX_DURATION_POW_2 = 1092 * 1092;\n\n /// @notice Default weight scaling.\n uint96 constant DEFAULT_WEIGHT_SCALING = 3;\n\n /// @notice Range for weight scaling.\n uint96 constant MIN_WEIGHT_SCALING = 1;\n uint96 constant MAX_WEIGHT_SCALING = 9;\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n uint256 public kickoffTS;\n\n string name = \"SOVStaking\";\n\n /// @notice The token to be staked.\n IERC20 public SOVToken;\n\n /// @notice A record of each accounts delegate.\n mapping(address => mapping(uint256 => address)) public delegates;\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately.\n bool public allUnlocked = false;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n bytes32 public constant DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 lockDate,uint256 nonce,uint256 expiry)\");\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure.\n address public newStakingContract;\n\n /*************************** Checkpoints *******************************/\n\n /// @notice A checkpoint for marking the stakes from a given block\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public totalStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numTotalStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public delegateStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numDelegateStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public userStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numUserStakingCheckpoints;\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n mapping(address => uint256) public nonces;\n\n /*************************** Slashing *******************************/\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n IFeeSharingCollector public feeSharing;\n\n /// @notice used for weight scaling when unstaking with slashing.\n uint96 public weightScaling = DEFAULT_WEIGHT_SCALING;\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n mapping(address => bool) public vestingWhitelist;\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n mapping(address => bool) public admins;\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n mapping(bytes32 => bool) public vestingCodeHashes;\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public vestingCheckpoints;\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numVestingCheckpoints;\n\n ///@notice vesting registry contract\n IVestingRegistry public vestingRegistryLogic;\n\n /// @dev user => flag whether user has pauser role.\n mapping(address => bool) public pausers;\n\n /// @dev Staking contract is paused\n bool public paused;\n\n /// @dev Staking contract is frozen\n bool public frozen;\n\n /// @dev max iterations that can be supported in 1 tx for the withdrawal\n uint256 internal maxVestingWithdrawIterations;\n\n constructor() internal {\n //abstract\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingAdminModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Admin Module.\n * @notice Implements administrative functionality pause, freeze and setting addresses and parameters\n * related to staking\n * */\ncontract StakingAdminModule is IFunctionsList, StakingShared {\n using Address for address payable;\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(_admin != address(0), \"cannot add the zero address as an admin\");\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(admins[_admin], \"address is not an admin\");\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external onlyOwner whenNotFrozen {\n require(_pauser != address(0), \"cannot add the zero address as a pauser\");\n pausers[_pauser] = true;\n emit PauserAddedOrRemoved(_pauser, true);\n }\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external onlyOwner whenNotFrozen {\n require(pausers[_pauser], \"address is not a pauser\");\n delete pausers[_pauser];\n emit PauserAddedOrRemoved(_pauser, false);\n }\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) public onlyPauserOrOwner whenNotFrozen {\n paused = _pause;\n emit StakingPaused(_pause);\n }\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external onlyPauserOrOwner {\n require(_freeze != frozen, \"Cannot freeze/unfreeze to the same state\"); // WS25\n if (_freeze) pauseUnpause(true);\n frozen = _freeze;\n emit StakingFrozen(_freeze);\n }\n\n /**\n * @notice Allow the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external onlyOwner whenNotFrozen {\n require(_feeSharing != address(0), \"FeeSharing address shouldn't be 0\"); // S17\n feeSharing = IFeeSharingCollector(_feeSharing);\n }\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external onlyOwner whenNotFrozen {\n require(\n MIN_WEIGHT_SCALING <= _weightScaling && _weightScaling <= MAX_WEIGHT_SCALING,\n \"scaling doesn't belong to range [1, 9]\" // S18\n );\n weightScaling = _weightScaling;\n }\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external onlyOwner whenNotFrozen {\n require(_newStakingContract != address(0), \"can't reset the new staking contract to 0\"); // S16\n newStakingContract = _newStakingContract;\n }\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external whenNotFrozen {\n require(newStakingContract != address(0), \"there is no new staking contract set\"); // S19\n revert(\"not implemented\");\n /// @dev implementation:\n /// @dev Iterate over all possible lock dates from now until now + MAX_DURATION.\n /// @dev Read the stake & delegate of the msg.sender\n /// @dev If stake > 0, stake it at the new contract until the lock date with the current delegate.\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](13);\n functionsList[0] = this.addAdmin.selector;\n functionsList[1] = this.removeAdmin.selector;\n functionsList[2] = this.addPauser.selector;\n functionsList[3] = this.removePauser.selector;\n functionsList[4] = this.pauseUnpause.selector;\n functionsList[5] = this.freezeUnfreeze.selector;\n functionsList[6] = this.setFeeSharing.selector;\n functionsList[7] = this.setWeightScaling.selector;\n functionsList[8] = this.setNewStakingContract.selector;\n functionsList[9] = this.owner.selector;\n functionsList[10] = this.isOwner.selector;\n functionsList[11] = this.transferOwnership.selector;\n functionsList[12] = this.migrateToNewStakingContract.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingGovernanceModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/IVesting.sol\";\n\n/**\n * @title Staking Governance Module contract\n * @notice Implements voting power and delegation functionality\n * */\ncontract StakingGovernanceModule is IFunctionsList, StakingShared, CheckpointsShared {\n using Address for address payable;\n\n /************* TOTAL VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n /// @dev Start the computation with the exact or previous unlocking date (voting weight remians the same until the next break point).\n uint256 start = _timestampToLockDate(time);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n totalVotingPower = add96(\n totalVotingPower,\n _totalPowerByDate(i, start, blockNumber),\n \"arrays mismatch\"\n ); // WS06\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorTotalStakesForDate(date, blockNumber);\n /// @dev weight is multiplied by some factor to allow decimals.\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS07\n }\n\n /****************************** DELEGATED VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96) {\n return getPriorVotes(account, block.number - 1, block.timestamp);\n }\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96 votes) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n votes = add96(\n votes,\n _totalPowerByDateForDelegatee(account, i, start, blockNumber),\n \"overflow - total VP\"\n ); // WS09\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDateForDelegatee(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS10\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n date = _adjustDateForOrigin(date);\n return _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined yet\"); // WS11\n\n uint32 nCheckpoints = numDelegateStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (delegateStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return delegateStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (delegateStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = delegateStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return delegateStakingCheckpoints[account][date][lower].stake;\n }\n\n /**************** SHARED FUNCTIONS *********************/\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for. Adjusted to the next valid lock date, as necessary\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n public\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorTotalStakesForDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function _getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS08\n\n uint32 nCheckpoints = numTotalStakingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (totalStakingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return totalStakingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n // Next check implicit zero balance\n if (totalStakingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Checkpoint memory cp = totalStakingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return totalStakingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Set new delegatee. Move from user's current delegate to a new\n * delegatee the stake balance.\n * @param delegator The user address to move stake balance from its current delegatee.\n * @param delegatee The new delegatee. The address to move stake balance to.\n * @param lockedTS The lock date.\n * @dev Reverts if delegator balance or delegatee is not valid, unless the sender is a vesting contract.\n * */\n function _delegate(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n address currentDelegate = delegates[delegator][lockedTS];\n uint96 delegatorBalance = _currentBalance(delegator, lockedTS);\n\n // vesting contracts will in multiple cases try to delegate a zero balance\n // or to the existing delegatee\n if (_isVestingContract(msg.sender)) {\n if (delegatorBalance == 0 || currentDelegate == delegatee) {\n return;\n }\n } else {\n require(delegatorBalance > 0, \"no stake to delegate\");\n require(currentDelegate != delegatee, \"cannot delegate to the existing delegatee\");\n }\n\n delegates[delegator][lockedTS] = delegatee;\n\n emit DelegateChanged(delegator, lockedTS, currentDelegate, delegatee);\n\n _moveDelegates(currentDelegate, delegatee, delegatorBalance, lockedTS);\n }\n\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n function _delegateNext(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n if (_isVestingContract(msg.sender)) {\n uint256 nextLock = lockedTS.add(TWO_WEEKS);\n address currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n\n // @dev workaround for the issue with a delegation of the latest stake\n uint256 endDate = IVesting(msg.sender).endDate();\n nextLock = lockedTS.add(FOUR_WEEKS);\n if (nextLock == endDate) {\n currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n }\n }\n }\n\n /**\n * @notice Move an amount of delegate stake from a source address to a\n * destination address.\n * @param srcRep The address to get the staked amount from.\n * @param dstRep The address to send the staked amount to.\n * @param amount The staked amount to move.\n * @param lockedTS The lock date.\n * */\n function _moveDelegates(\n address srcRep,\n address dstRep,\n uint96 amount,\n uint256 lockedTS\n ) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) _decreaseDelegateStake(srcRep, lockedTS, amount);\n\n if (dstRep != address(0)) _increaseDelegateStake(dstRep, lockedTS, amount);\n }\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function _getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external whenNotPaused {\n require(delegatee != address(0), \"cannot delegate to the zero address\");\n _notSameBlockAsStakingCheckpoint(lockDate, msg.sender);\n\n _delegate(msg.sender, delegatee, lockDate);\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n _delegateNext(msg.sender, delegatee, lockDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](6);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStakeModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking contract staking functionality module\n * @notice Implements staking functionality\n **/\ncontract StakingStakeModule is IFunctionsList, StakingShared, CheckpointsShared, ApprovalReceiver {\n using SafeMath for uint256;\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stake(msg.sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external onlyThisContract whenNotPaused whenNotFrozen {\n _stake(sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * */\n function _stake(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted\n ) internal {\n _stakeOptionalTokenTransfer(\n sender,\n amount,\n until,\n stakeFor,\n delegatee,\n timeAdjusted,\n true // transfer SOV\n );\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * @param transferToken Should transfer SOV - false for multiple iterations like in stakeBySchedule\n * */\n function _stakeOptionalTokenTransfer(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted,\n bool transferToken\n ) internal {\n require(amount > 0, \"amount needs to be bigger than 0\"); // S01\n\n if (!timeAdjusted) {\n until = _timestampToLockDate(until);\n }\n require(\n until > block.timestamp,\n \"Staking::_timestampToLockDate: staking period too short\"\n ); // S02\n\n /// @dev Stake for the sender if not specified otherwise.\n if (stakeFor == address(0)) {\n stakeFor = sender;\n }\n // must wait a block before staking again for that same deadline\n _notSameBlockAsStakingCheckpoint(until, stakeFor);\n\n /// @dev Delegate for stakeFor if not specified otherwise.\n if (delegatee == address(0)) {\n delegatee = stakeFor;\n }\n\n /// @dev Do not stake longer than the max duration.\n if (!timeAdjusted) {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n }\n\n uint96 previousBalance = _currentBalance(stakeFor, until);\n\n /// @dev Increase stake.\n _increaseStake(sender, amount, stakeFor, until, transferToken);\n\n // @dev Previous version wasn't working properly for the following case:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n address previousDelegatee = delegates[stakeFor][until];\n\n if (previousDelegatee != delegatee) {\n // @dev only the user that stakes for himself is allowed to delegate VP to another address\n // which works with vesting stakes and prevents vulnerability of delegating VP to an arbitrary address from\n // any address\n\n if (delegatee != stakeFor) {\n require(\n stakeFor == sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n } else if (sender != stakeFor && previousDelegatee != address(0)) {\n require(stakeFor == sender, \"Only sender is allowed to change delegatee\");\n }\n\n /// @dev Update delegatee.\n delegates[stakeFor][until] = delegatee;\n\n /// @dev Decrease stake on previous balance for previous delegatee.\n _decreaseDelegateStake(previousDelegatee, until, previousBalance);\n\n /// @dev Add previousBalance to amount.\n amount = add96(previousBalance, amount, \"add amounts failed\");\n }\n\n /// @dev Increase stake.\n _increaseDelegateStake(delegatee, until, amount);\n emit DelegateChanged(stakeFor, until, previousDelegatee, delegatee);\n }\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until)\n external\n whenNotPaused\n whenNotFrozen\n {\n previousLock = _timestampToLockDate(previousLock);\n until = _timestampToLockDate(until);\n\n _notSameBlockAsStakingCheckpoint(previousLock, msg.sender);\n\n /// @dev Do not exceed the max duration, no overflow possible.\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n\n require(previousLock < until, \"must increase staking duration\"); // S04\n\n /// @dev Update checkpoints.\n /// @dev TODO James: Can reading stake at block.number -1 cause trouble with multiple tx in a block?\n uint96 amount = _getPriorUserStakeByDate(msg.sender, previousLock, block.number - 1);\n require(amount > 0, \"no stakes till the prev lock date\"); // S05\n _decreaseUserStake(msg.sender, previousLock, amount);\n _increaseUserStake(msg.sender, until, amount);\n\n if (_isVestingContract(msg.sender)) {\n _decreaseVestingStake(previousLock, amount);\n _increaseVestingStake(until, amount);\n }\n\n _decreaseDailyStake(previousLock, amount);\n _increaseDailyStake(until, amount);\n\n /// @dev Delegate might change: if there is already a delegate set for the until date, it will remain the delegate for this position\n address delegateFrom = delegates[msg.sender][previousLock];\n delegates[msg.sender][previousLock] = address(0); //the previousLock delegates nullifying before reading that form `until` guards in case delegateTo == until\n address delegateTo = delegates[msg.sender][until];\n if (delegateTo == address(0)) {\n delegateTo = delegateFrom;\n delegates[msg.sender][until] = delegateFrom;\n }\n _decreaseDelegateStake(delegateFrom, previousLock, amount);\n _increaseDelegateStake(delegateTo, until, amount);\n\n emit ExtendedStakingDuration(msg.sender, previousLock, until, amount);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param until The date until which the tokens will be staked.\n * @param transferToken if false - token transfer should be handled separately\n * */\n function _increaseStake(\n address sender,\n uint96 amount,\n address stakeFor,\n uint256 until,\n bool transferToken\n ) internal {\n /// @dev Retrieve the SOV tokens.\n if (transferToken)\n require(\n SOVToken.transferFrom(sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // IS10\n\n /// @dev Increase staked balance.\n uint96 balance = _currentBalance(stakeFor, until);\n balance = add96(balance, amount, \"increaseStake: overflow\"); // IS20\n\n /// @dev Update checkpoints.\n _increaseDailyStake(until, amount);\n _increaseUserStake(stakeFor, until, amount);\n\n if (_isVestingContract(stakeFor)) _increaseVestingStake(until, amount);\n\n emit TokensStaked(stakeFor, amount, until, balance);\n }\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function _stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) internal {\n require(amount > 0, \"Invalid amount\");\n require(duration <= MAX_DURATION, \"Invalid duration\");\n require(intervalLength > 0, \"Invalid interval length\");\n require(intervalLength % TWO_WEEKS == 0, \"Invalid interval length\");\n if (delegatee != stakeFor && delegatee != address(0)) {\n require(\n stakeFor == msg.sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n }\n /**\n * @dev Stake them until lock dates according to the vesting schedule.\n * Note: because staking is only possible in periods of 2 weeks,\n * the total duration might end up a bit shorter than specified\n * depending on the date of staking.\n * */\n uint256 start = _timestampToLockDate(block.timestamp + cliff);\n uint256 end = _timestampToLockDate(block.timestamp + duration);\n require(start <= end, \"Invalid schedule\");\n uint256 numIntervals;\n if (start < end) {\n numIntervals = (end - start) / intervalLength + 1;\n } else {\n numIntervals = 1;\n }\n uint256 stakedPerInterval = amount / numIntervals;\n\n /// @dev transferring total SOV amount before staking\n require(\n SOVToken.transferFrom(msg.sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // SS10\n /// @dev stakedPerInterval might lose some dust on rounding. Add it to the first staking date.\n if (numIntervals >= 1) {\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(amount - stakedPerInterval * (numIntervals - 1)),\n start,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n /// @dev Stake the rest in 4 week intervals.\n for (uint256 i = start + intervalLength; i <= end; i += intervalLength) {\n /// @dev Stakes for itself, delegates to the owner.\n _notSameBlockAsStakingCheckpoint(i, stakeFor); // must wait a block before staking again for that same deadline\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(stakedPerInterval),\n i,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n }\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance) {\n for (uint256 i = kickoffTS; i <= block.timestamp + MAX_DURATION; i += TWO_WEEKS) {\n balance = add96(balance, _currentBalance(account, i), \"Staking::balanceOf: overflow\"); // S12\n }\n }\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96) {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n return nCheckpoints > 0 ? totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake : 0;\n }\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes)\n {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n\n /// @dev Calculate stakes.\n uint256 count = 0;\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n if (_currentBalance(account, i) > 0) {\n count++;\n }\n }\n dates = new uint256[](count);\n stakes = new uint96[](count);\n\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n uint256 j = 0;\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n uint96 balance = _currentBalance(account, i);\n if (balance > 0) {\n dates[j] = i;\n stakes[j] = balance;\n j++;\n }\n }\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOVToken);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeWithApproval.selector;\n return selectors;\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256) {\n return _timestampToLockDate(timestamp);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](10);\n functionsList[0] = this.stake.selector;\n functionsList[1] = this.stakeWithApproval.selector;\n functionsList[2] = this.extendStakingDuration.selector;\n functionsList[3] = this.stakesBySchedule.selector;\n functionsList[4] = this.stakeBySchedule.selector;\n functionsList[5] = this.balanceOf.selector;\n functionsList[6] = this.getCurrentStakedUntil.selector;\n functionsList[7] = this.getStakes.selector;\n functionsList[8] = this.timestampToLockDate.selector;\n functionsList[9] = this.receiveApproval.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStorageModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/StakingStorageShared.sol\";\n\n/**\n * @title Staking Storage Module\n * @notice Provides getters for public storage variables\n **/\ncontract StakingStorageModule is IFunctionsList, StakingStorageShared {\n function getStorageDefaultWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256) {\n return MAX_DURATION;\n }\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n function getStorageMaxVotingWeight() external pure returns (uint256) {\n return uint256(MAX_VOTING_WEIGHT);\n }\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n function getStorageWeightFactor() external pure returns (uint256) {\n return uint256(WEIGHT_FACTOR);\n }\n\n /// @notice Default weight scaling.\n function getStorageDefaulWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling)\n {\n return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING));\n }\n\n /// @notice The EIP-712 typehash for the contract's domain.\n function getStorageDomainTypehash() external pure returns (uint256) {\n return uint256(DOMAIN_TYPEHASH);\n }\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n function getStorageDelegationTypehash() external pure returns (uint256) {\n return uint256(DELEGATION_TYPEHASH);\n }\n\n function getStorageName() external view returns (string memory) {\n return name;\n }\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() public view returns (uint256) {\n return maxVestingWithdrawIterations;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](32);\n functionsList[0] = this.getStorageMaxDurationToStakeTokens.selector;\n functionsList[1] = this.getStorageMaxVotingWeight.selector;\n functionsList[2] = this.getStorageWeightFactor.selector;\n functionsList[3] = this.getStorageDefaulWeightScaling.selector;\n functionsList[4] = this.getStorageRangeForWeightScaling.selector;\n functionsList[5] = this.getStorageDomainTypehash.selector;\n functionsList[6] = this.getStorageDelegationTypehash.selector;\n functionsList[7] = this.getStorageName.selector;\n functionsList[8] = this.kickoffTS.selector;\n functionsList[9] = this.SOVToken.selector;\n functionsList[10] = this.delegates.selector;\n functionsList[11] = this.allUnlocked.selector;\n functionsList[12] = this.newStakingContract.selector;\n functionsList[13] = this.totalStakingCheckpoints.selector;\n functionsList[14] = this.numTotalStakingCheckpoints.selector;\n functionsList[15] = this.delegateStakingCheckpoints.selector;\n functionsList[16] = this.numDelegateStakingCheckpoints.selector;\n functionsList[17] = this.userStakingCheckpoints.selector;\n functionsList[18] = this.numUserStakingCheckpoints.selector;\n functionsList[19] = this.nonces.selector;\n functionsList[20] = this.feeSharing.selector;\n functionsList[21] = this.weightScaling.selector;\n functionsList[22] = this.vestingWhitelist.selector;\n functionsList[23] = this.admins.selector;\n functionsList[24] = this.vestingCodeHashes.selector;\n functionsList[25] = this.vestingCheckpoints.selector;\n functionsList[26] = this.numVestingCheckpoints.selector;\n functionsList[27] = this.vestingRegistryLogic.selector;\n functionsList[28] = this.pausers.selector;\n functionsList[29] = this.paused.selector;\n functionsList[30] = this.frozen.selector;\n functionsList[31] = this.getMaxVestingWithdrawIterations.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingVestingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Vesting Module contract\n * @notice Implements interaction with Vesting functionality: vesting registry, vesting staking\n * */\ncontract StakingVestingModule is IFunctionsList, StakingShared {\n event ContractCodeHashAdded(bytes32 hash);\n event ContractCodeHashRemoved(bytes32 hash);\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external onlyOwner whenNotFrozen {\n vestingRegistryLogic = IVestingRegistry(_vestingRegistryProxy);\n }\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(lockedDates.length == values.length, \"arrays mismatch\"); // WS05\n\n uint256 length = lockedDates.length;\n for (uint256 i = 0; i < length; i++) {\n _setVestingStake(lockedDates[i], values[i]);\n }\n }\n\n /**\n * @notice Sets the users' vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to be set.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function _setVestingStake(uint256 lockedTS, uint96 value) internal {\n require(\n lockedTS > kickoffTS,\n \"Invalid lock dates: must greater than contract creation timestamp\"\n );\n\n // locked date must be multiples of 14 days / TWO_WEEKS\n require(\n (lockedTS - kickoffTS) % TWO_WEEKS == 0,\n \"Invalid lock dates: not multiples of 14 days\"\n );\n\n // locked date must not exceed the MAX_DURATION\n if (lockedTS > block.timestamp) {\n require(\n lockedTS - block.timestamp <= MAX_DURATION,\n \"Invalid lock dates: exceed max duration\"\n );\n }\n\n // the value must not exceed the total staked at the given locked date\n uint32 nStakeCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 totalStaked = totalStakingCheckpoints[lockedTS][nStakeCheckpoints - 1].stake;\n require(\n value <= totalStaked,\n \"Invalid stake amount: greater than the total staked for given date\"\n );\n\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint32 blockNumber;\n\n Checkpoint memory recentCP = vestingCheckpoints[lockedTS][nCheckpoints - 1];\n if (nCheckpoints == 0) blockNumber = uint32(block.number) - 1;\n else blockNumber = recentCP.fromBlock + 1;\n\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, value);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n\n emit VestingStakeSet(lockedTS, value);\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n uint96 priorStake = _getPriorUserStakeByDate(account, date, blockNumber);\n // @dev we need to modify function in order to workaround issue with Vesting.withdrawTokens:\n //\t\treturn 1 instead of 0 if message sender is a contract.\n if (priorStake == 0 && _isVestingContract(msg.sender)) {\n priorStake = 1;\n }\n return priorStake;\n }\n\n /*************************** Weighted Vesting Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes)\n {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedVestingStakeByDate(i, start, blockNumber);\n if (weightedStake > 0) {\n votes = add96(votes, weightedStake, \"overflow on total weight\"); // WS15\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n power = _weightedVestingStakeByDate(date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorVestingStakeByDate(date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul oveflow\") / WEIGHT_FACTOR; // WS16\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorVestingStakeByDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS17\n\n uint32 nCheckpoints = numVestingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (vestingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return vestingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (vestingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = vestingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return vestingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n require(vestingCodeHashes[codeHash], \"not a registered vesting code hash\");\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool) {\n bool isVesting;\n bytes32 codeHash = _getCodeHash(stakerAddress);\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](9);\n functionsList[0] = this.setVestingRegistry.selector;\n functionsList[1] = this.setVestingStakes.selector;\n functionsList[2] = this.getPriorUserStakeByDate.selector;\n functionsList[3] = this.getPriorVestingWeightedStake.selector;\n functionsList[4] = this.getPriorVestingStakeByDate.selector;\n functionsList[5] = this.addContractCodeHash.selector;\n functionsList[6] = this.removeContractCodeHash.selector;\n functionsList[7] = this.isVestingContract.selector;\n functionsList[8] = this.weightedVestingStakeByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingWithdrawModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/ITeamVesting.sol\";\nimport \"../../Vesting/IVesting.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking withdrawal functionality module\n **/\ncontract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShared {\n using SafeMath for uint256;\n\n event MaxVestingWithdrawIterationsUpdated(uint256 oldMaxIterations, uint256 newMaxIterations);\n\n /// @dev Struct for direct withdraw function -- to avoid stack too deep issue\n struct VestingConfig {\n address vestingAddress;\n uint256 startDate;\n uint256 endDate;\n uint256 cliff;\n uint256 duration;\n address tokenOwner;\n }\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev If until is not a valid lock date, the next lock date after until is used.\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n // adjust until here to avoid adjusting multiple times, and to make sure an adjusted date is passed to\n // _notSameBlockAsStakingCheckpoint\n until = _adjustDateForOrigin(until);\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, false);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe need to check block.timestamp here\n _withdrawNext(until, receiver, false);\n }\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external onlyAuthorized whenNotFrozen {\n /// require the caller only for team vesting contract.\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n _cancelTeamVesting(vesting, receiver, startFrom);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param _vesting The vesting address.\n * @param _receiver The receiving address.\n * @param _startFrom The start value for the iterations.\n * or just unlocked tokens (false).\n * */\n function _cancelTeamVesting(\n address _vesting,\n address _receiver,\n uint256 _startFrom\n ) private {\n require(_receiver != address(0), \"receiver address invalid\");\n\n ITeamVesting teamVesting = ITeamVesting(_vesting);\n\n VestingConfig memory vestingConfig =\n VestingConfig(\n _vesting,\n teamVesting.startDate(),\n teamVesting.endDate(),\n teamVesting.cliff(),\n teamVesting.duration(),\n teamVesting.tokenOwner()\n );\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them, as long as the itrations less than maxVestingWithdrawIterations.\n uint256 end = vestingConfig.endDate;\n\n uint256 defaultStart = vestingConfig.startDate + vestingConfig.cliff;\n\n _startFrom = _startFrom >= defaultStart ? _startFrom : defaultStart;\n\n /// @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 totalIterationValue =\n (_startFrom + (TWO_WEEKS * (maxVestingWithdrawIterations - 1)));\n uint256 adjustedEnd = end < totalIterationValue ? end : totalIterationValue;\n\n /// @dev Withdraw for each unlocked position.\n for (uint256 i = _startFrom; i <= adjustedEnd; i += TWO_WEEKS) {\n /// @dev Read amount to withdraw.\n uint96 tempStake = _getPriorUserStakeByDate(_vesting, i, block.number - 1);\n\n if (tempStake > 0) {\n /// @dev do governance direct withdraw for team vesting\n _withdrawFromTeamVesting(tempStake, i, _receiver, vestingConfig);\n }\n }\n\n if (adjustedEnd < end) {\n emit TeamVestingPartiallyCancelled(msg.sender, _receiver, adjustedEnd);\n } else {\n emit TeamVestingCancelled(msg.sender, _receiver);\n }\n }\n\n /**\n * @notice Send user' staked tokens to a receiver taking into account punishments.\n * Sovryn encourages long-term commitment and thinking. When/if you unstake before\n * the end of the staking period, a percentage of the original staking amount will\n * be slashed. This amount is also added to the reward pool and is distributed\n * between all other stakers.\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * Needs to be adjusted to the next valid lock date before calling this function.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdraw(\n uint96 amount,\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n // @dev it's very unlikely some one will have 1/10**18 SOV staked in Vesting contract\n //\t\tthis check is a part of workaround for Vesting.withdrawTokens issue\n if (amount == 1 && _isVestingContract(msg.sender)) {\n return;\n }\n _validateWithdrawParams(msg.sender, amount, until);\n\n /// @dev Determine the receiver.\n if (receiver == address(0)) receiver = msg.sender;\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(msg.sender, until, amount);\n if (_isVestingContract(msg.sender)) _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[msg.sender][until], until, amount);\n\n /// @dev Early unstaking should be punished.\n if (block.timestamp < until && !allUnlocked && !isGovernance) {\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n amount -= punishedAmount;\n\n /// @dev punishedAmount can be 0 if block.timestamp are very close to 'until'\n if (punishedAmount > 0) {\n require(address(feeSharing) != address(0), \"FeeSharing address wasn't set\"); // S08\n /// @dev Move punished amount to fee sharing.\n /// @dev Approve transfer here and let feeSharing do transfer and write checkpoint.\n SOVToken.approve(address(feeSharing), punishedAmount);\n feeSharing.transferTokens(address(SOVToken), punishedAmount);\n }\n }\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(msg.sender, amount, until, receiver, isGovernance);\n }\n\n /**\n * @notice Send user' staked tokens to a receiver.\n * This function is dedicated only for direct withdrawal from staking contract.\n * Currently only being used by cancelTeamVesting()\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender.\n * @param vestingConfig The vesting config.\n * @dev VestingConfig struct intended to avoid stack too deep issue, and it contains this properties:\n address vestingAddress; // vesting contract address\n uint256 startDate; //start date of vesting\n uint256 endDate; // end date of vesting\n uint256 cliff; // after this time period the tokens begin to unlock\n uint256 duration; // after this period all the tokens will be unlocked\n address tokenOwner; // owner of the vested tokens\n * */\n function _withdrawFromTeamVesting(\n uint96 amount,\n uint256 until,\n address receiver,\n VestingConfig memory vestingConfig\n ) internal {\n address vesting = vestingConfig.vestingAddress;\n\n until = _timestampToLockDate(until);\n _validateWithdrawParams(vesting, amount, until);\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(vesting, until, amount);\n\n _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[vesting][until], until, amount);\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(vesting, amount, until, receiver, true);\n }\n\n // @dev withdraws tokens for lock date 2 weeks later than given lock date\n function _withdrawNext(\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n if (_isVestingContract(msg.sender)) {\n // nextLock needs to be adjusted to the next valid lock date to make sure we don't accidentally\n // withdraw stakes that are in the future and would get slashed (if until is not\n // a valid lock date). but until is already handled in the withdraw function\n uint256 nextLock = until.add(TWO_WEEKS);\n if (isGovernance || block.timestamp >= nextLock) {\n uint96 stakes = _getPriorUserStakeByDate(msg.sender, nextLock, block.number - 1);\n if (stakes > 0) {\n _withdraw(stakes, nextLock, receiver, isGovernance);\n }\n }\n }\n }\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked. Adjusted to the next valid lock date, if necessary.\n * @return Amount to withraw and penalty amount\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96)\n {\n until = _adjustDateForOrigin(until);\n _validateWithdrawParams(msg.sender, amount, until);\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n return (amount - punishedAmount, punishedAmount);\n }\n\n /**\n * @notice Get punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _getPunishedAmount(uint96 amount, uint256 until) internal view returns (uint96) {\n uint256 date = _timestampToLockDate(block.timestamp);\n uint96 weight = _computeWeightByDate(until, date); /// @dev (10 - 1) * WEIGHT_FACTOR\n weight = weight * weightScaling;\n return (amount * weight) / WEIGHT_FACTOR / 100;\n }\n\n /**\n * @notice Validate withdraw parameters.\n * @param account Address to be validated.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _validateWithdrawParams(\n address account,\n uint96 amount,\n uint256 until\n ) internal view {\n require(amount > 0, \"Amount of tokens to withdraw must be > 0\"); // S10\n uint96 balance = _getPriorUserStakeByDate(account, until, block.number - 1);\n require(amount <= balance, \"Staking::withdraw: not enough balance\"); // S11\n }\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external onlyOwner whenNotFrozen {\n allUnlocked = true;\n emit TokensUnlocked(SOVToken.balanceOf(address(this)));\n }\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param newMaxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 newMaxIterations)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(newMaxIterations > 0, \"Invalid max iterations\");\n emit MaxVestingWithdrawIterationsUpdated(maxVestingWithdrawIterations, newMaxIterations);\n maxVestingWithdrawIterations = newMaxIterations;\n }\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * @dev This function is dedicated only to support backward compatibility for sovryn ecosystem that has been implementing this staking contract.\n * @dev Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/4bbfe5bd0311ca71e4ef0e3af810d3791d8e4061/contracts/governance/Staking/modules/StakingWithdrawModule.sol#L78\n * */\n function governanceWithdrawVesting(address vesting, address receiver)\n public\n onlyAuthorized\n whenNotFrozen\n {\n vestingWhitelist[vesting] = true;\n ITeamVesting(vesting).governanceWithdrawTokens(receiver);\n vestingWhitelist[vesting] = false;\n\n emit VestingTokensWithdrawn(vesting, receiver);\n }\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n require(vestingWhitelist[msg.sender], \"unauthorized\"); // S07\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, true);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe don't need to check block.timestamp here\n _withdrawNext(until, receiver, true);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.withdraw.selector;\n functionsList[1] = this.cancelTeamVesting.selector;\n functionsList[2] = this.getWithdrawAmounts.selector;\n functionsList[3] = this.unlockAllTokens.selector;\n functionsList[4] = this.setMaxVestingWithdrawIterations.selector;\n functionsList[5] = this.governanceWithdraw.selector;\n functionsList[6] = this.governanceWithdrawVesting.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/WeightedStakingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Weighted Staking module contract.\n * @notice Implements getters for weighted staking functionality\n * */\ncontract WeightedStakingModule is IFunctionsList, StakingShared, CheckpointsShared {\n /*************************** User Weighted Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The start date/timestamp from which to calculate the weighted stake.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake) {\n return _getPriorWeightedStake(account, blockNumber, date);\n }\n\n function _getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) internal view returns (uint96 priorWeightedStake) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedStakeByDate(account, i, start, blockNumber);\n if (weightedStake > 0) {\n priorWeightedStake = add96(\n priorWeightedStake,\n weightedStake,\n \"overflow on total weight calc\"\n ); // WS12\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n return _weightedStakeByDate(account, date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function _weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorUserStakeByDate(account, date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS13\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight)\n {\n return _computeWeightByDate(date, startDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](3);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/SafeMath96.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n/**\n * @title SafeMath96 contract.\n * @notice Improved Solidity's arithmetic operations with added overflow checks.\n * @dev SafeMath96 uses uint96, unsigned integers of 96 bits length, so every\n * integer from 0 to 2^96-1 can be operated.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * SafeMath restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this contract instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n * */\ncontract SafeMath96 {\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function safe64(uint256 n, string memory errorMessage) internal pure returns (uint64) {\n require(n < 2**64, errorMessage);\n return uint64(n);\n }\n\n function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) {\n require(n < 2**96, errorMessage);\n return uint96(n);\n }\n\n /**\n * @notice Adds two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `+` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe addition a+b.\n * */\n function add96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n uint96 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n /**\n * @notice Substracts two unsigned integers, reverting on underflow.\n * @dev Counterpart to Solidity's `-` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on underflow.\n * @return The safe substraction a-b.\n * */\n function sub96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n require(b <= a, errorMessage);\n return a - b;\n }\n\n /**\n * @notice Multiplies two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `*` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe product a*b.\n * */\n function mul96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n if (a == 0) {\n return 0;\n }\n\n uint96 c = a * b;\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @notice Divides two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `/` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe division a/b.\n * */\n function div96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint96 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n}\n" + }, + "contracts/governance/Staking/StakingProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./modules/shared/StakingStorageShared.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Staking Proxy contract.\n * @dev Staking contract should be upgradable, use UpgradableProxy.\n * StakingStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingProxy is StakingStorageShared, UpgradableProxy {\n /**\n * @notice Construct a new staking contract.\n * @param SOV The address of the SOV token address.\n */\n constructor(address SOV) public {\n SOVToken = IERC20(SOV);\n kickoffTS = block.timestamp;\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewards.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Staking Rewards Contract.\n * @notice This is a trial incentive program.\n * In this, the SOV emitted and becoming liquid from the Adoption Fund could be utilized\n * to offset the higher APY's offered for Liquidity Mining events.\n * Vesting contract stakes are excluded from these rewards.\n * Only wallets which have staked previously liquid SOV are eligible for these rewards.\n * Tokenholders who stake their SOV receive staking rewards, a pro-rata share\n * of the revenue that the platform generates from various transaction fees\n * plus revenues from stakers who have a portion of their SOV slashed for\n * early unstaking.\n * */\ncontract StakingRewards is StakingRewardsStorage {\n using SafeMath for uint256;\n\n /// @notice Emitted when SOV is withdrawn\n /// @param receiver The address which recieves the SOV\n /// @param amount The amount withdrawn from the Smart Contract\n event RewardWithdrawn(address indexed receiver, uint256 amount);\n\n /**\n * @notice Replacement of constructor by initialize function for Upgradable Contracts\n * This function will be called only once by the owner.\n * @param _SOV SOV token address\n * @param _staking StakingProxy address should be passed\n * */\n function initialize(address _SOV, IStaking _staking) external onlyOwner {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n SOV = IERC20(_SOV);\n staking = _staking;\n startTime = staking.timestampToLockDate(block.timestamp);\n setMaxDuration(15 * TWO_WEEKS);\n deploymentBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Stops the current rewards program.\n * @dev All stakes existing on the contract at the point in time of\n * cancellation continue accruing rewards until the end of the staking\n * period being rewarded\n * */\n function stop() external onlyOwner {\n require(stopBlock == 0, \"Already stopped\");\n stopBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Collect rewards\n * @dev User calls this function to collect SOV staking rewards as per the SIP-0024 program.\n * The weighted stake is calculated using getPriorWeightedStake. Block number sent to the functon\n * must be a finalised block, hence we deduct 1 from the current block. User is only allowed to withdraw\n * after intervals of 14 days.\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * The issue is that we can only run for a max duration and if someone stakes for the\n * first time after the max duration is over, the reward will always return 0. Thus, we need to restart\n * from the duration that elapsed without generating rewards.\n * */\n function collectReward(uint256 restartTime) external {\n (uint256 withdrawalTime, uint256 amount) = getStakerCurrentReward(true, restartTime);\n require(withdrawalTime > 0 && amount > 0, \"no valid reward\");\n withdrawals[msg.sender] = withdrawalTime;\n _payReward(msg.sender, amount);\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred.\n */\n function withdrawTokensByOwner(address _receiverAddress) external onlyOwner {\n uint256 value = SOV.balanceOf(address(this));\n _transferSOV(_receiverAddress, value);\n }\n\n /**\n * @notice Changes average block time - based on blockchain\n * @dev If average block time significantly changes, we can update it here and use for block number calculation\n */\n function setAverageBlockTime(uint256 _averageBlockTime) external onlyOwner {\n averageBlockTime = _averageBlockTime;\n }\n\n /**\n * @notice This function computes the last staking checkpoint and calculates the corresponding\n * block number using the average block time which is then added to the mapping `checkpointBlockDetails`.\n */\n function setBlock() external {\n uint256 lastCheckpointTime = staking.timestampToLockDate(block.timestamp);\n _setBlock(lastCheckpointTime);\n }\n\n /**\n * @notice This function computes the block number using the average block time for a given historical\n * checkpoint which is added to the mapping `checkpointBlockDetails`.\n * @param _time Exact staking checkpoint time\n */\n function setHistoricalBlock(uint256 _time) external {\n _setBlock(_time);\n }\n\n /**\n * @notice Sets the max duration\n * @dev Rewards can be collected for a maximum duration at a time. This\n * is to avoid Block Gas Limit failures. Setting it zero would mean that it will loop\n * through the entire duration since the start of rewards program.\n * It should ideally be set to a value, for which the rewards can be easily processed.\n * @param _duration Max duration for which rewards can be collected at a go (in seconds)\n * */\n function setMaxDuration(uint256 _duration) public onlyOwner {\n maxDuration = _duration;\n }\n\n /**\n * @notice Internal function to calculate weighted stake\n * @dev If the rewards program is stopped, the user will still continue to\n * earn till the end of staking period based on the stop block.\n * @param _staker Staker address\n * @param _block Last finalised block\n * @param _date The date to compute prior weighted stakes\n * @return The weighted stake\n * */\n function _computeRewardForDate(\n address _staker,\n uint256 _block,\n uint256 _date\n ) internal view returns (uint256 weightedStake) {\n weightedStake = staking.getPriorWeightedStake(_staker, _block, _date);\n if (stopBlock > 0 && stopBlock < _block) {\n uint256 previousWeightedStake =\n staking.getPriorWeightedStake(_staker, stopBlock, _date);\n if (previousWeightedStake < weightedStake) {\n weightedStake = previousWeightedStake;\n }\n }\n }\n\n /**\n * @notice Internal function to pay rewards\n * @dev Base rate is annual, but we pay interest for 14 days,\n * which is 1/26 of one staking year (1092 days)\n * @param _staker User address\n * @param amount the reward amount\n * */\n function _payReward(address _staker, uint256 amount) internal {\n require(SOV.balanceOf(address(this)) >= amount, \"not enough funds to reward user\");\n claimedBalances[_staker] = claimedBalances[_staker].add(amount);\n _transferSOV(_staker, amount);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit RewardWithdrawn(_receiver, _amount);\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Internal function to calculate and set block\n * */\n function _setBlock(uint256 _checkpointTime) internal {\n uint256 currentTS = block.timestamp;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n require(checkpointBlockDetails[_checkpointTime] == 0, \"block number already set\");\n uint256 checkpointBlock =\n lastFinalisedBlock.sub(((currentTS.sub(_checkpointTime)).div(averageBlockTime)));\n checkpointBlockDetails[_checkpointTime] = checkpointBlock;\n }\n\n /**\n * @notice Get staker's current accumulated reward\n * @dev The collectReward() function internally calls this function to calculate reward amount\n * @param considerMaxDuration True: Runs for the maximum duration - used in tx not to run out of gas\n * False - to query total rewards\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * @return The timestamp of last withdrawal\n * @return The accumulated reward\n */\n function getStakerCurrentReward(bool considerMaxDuration, uint256 restartTime)\n public\n view\n returns (uint256 lastWithdrawalInterval, uint256 amount)\n {\n uint256 weightedStake;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n uint256 currentTS = block.timestamp;\n uint256 duration;\n address staker = msg.sender;\n uint256 lastWithdrawal = withdrawals[staker];\n\n uint256 lastStakingInterval = staking.timestampToLockDate(currentTS);\n lastWithdrawalInterval = lastWithdrawal > 0 ? lastWithdrawal : startTime;\n if (lastStakingInterval <= lastWithdrawalInterval) return (0, 0);\n /* Normally the restart time is 0. If this function returns a valid lastWithdrawalInterval\n\t\tand zero amount - that means there were no valid rewards for that period. So the new period must start\n\t\tfrom the end of the last interval or till the time no rewards are accumulated i.e. restartTime */\n if (restartTime >= lastWithdrawalInterval) {\n uint256 latestRestartTime = staking.timestampToLockDate(restartTime);\n lastWithdrawalInterval = latestRestartTime;\n }\n\n if (considerMaxDuration) {\n uint256 addedMaxDuration = lastWithdrawalInterval.add(maxDuration);\n duration = addedMaxDuration < currentTS\n ? staking.timestampToLockDate(addedMaxDuration)\n : lastStakingInterval;\n } else {\n duration = lastStakingInterval;\n }\n for (uint256 i = lastWithdrawalInterval; i < duration; i += TWO_WEEKS) {\n uint256 referenceBlock = checkpointBlockDetails[i];\n if (referenceBlock == 0) {\n referenceBlock = lastFinalisedBlock.sub(\n ((currentTS.sub(i)).div(averageBlockTime))\n );\n }\n if (referenceBlock < deploymentBlock) referenceBlock = deploymentBlock;\n weightedStake = weightedStake.add(_computeRewardForDate(staker, referenceBlock, i));\n }\n lastWithdrawalInterval = duration;\n amount = weightedStake.mul(BASE_RATE).div(DIVISOR);\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title StakingRewards Proxy contract.\n * @dev StakingRewards contract should be upgradable. Used UpgradableProxy.\n * StakingRewardsStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy with\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingRewardsProxy is StakingRewardsStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking Rewards Storage Contract.\n * @notice Just the storage part of staking rewards contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingRewardsProxy.\n *\n * What is SOV staking rewards - SIP-0024?\n * The purpose of the SOV staking rewards - SIP-0024 is to reward,\n * \"marginal stakers\" (ie, stakers by choice, not currently vesting) with liquid SOV\n * at the beginning of each new staking interval.\n * */\ncontract StakingRewardsStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n ///@notice the staking proxy contract address\n IStaking public staking;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 1209600;\n\n /// @notice Annual Base Rate - it is the maximum interest rate(APY)\n uint256 public constant BASE_RATE = 2975;\n\n /// @notice DIVISOR is set as 2600000 = 26 (num periods per year) * 10 (max voting weight) * 10000 (2975 -> 0.2975)\n uint256 public constant DIVISOR = 2600000;\n\n /// @notice Maximum duration to collect rewards at one go\n uint256 public maxDuration;\n\n /// @notice Represents the time when the contract is deployed\n uint256 public startTime;\n\n /// @notice Represents the block when the Staking Rewards pogram is stopped\n uint256 public stopBlock;\n\n /// @notice User Address -> Last Withdrawn Timestamp\n mapping(address => uint256) public withdrawals;\n\n /// @notice User Address -> Claimed Balance\n mapping(address => uint256) public claimedBalances;\n\n /// @notice Represents the block when the StakingRwards Program is started\n uint256 public deploymentBlock;\n\n /// Moved the variables from Initializable contract to resolve issue caused by incorrect Inheritance Order\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /// @notice BlockTime -> BlockNumber for a Staking Checkpoint\n mapping(uint256 => uint256) public checkpointBlockDetails;\n\n /// @notice Average Block Time - making it flexible\n uint256 public averageBlockTime;\n}\n" + }, + "contracts/governance/Timelock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./ErrorDecoder.sol\";\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\n/**\n * @title Sovryn Protocol Timelock contract, based on Compound system.\n *\n * @notice This contract lets Sovryn governance system set up its\n * own Time Lock instance to execute transactions proposed through the\n * GovernorAlpha contract instance.\n *\n * The Timelock contract allows its admin (Sovryn governance on\n * GovernorAlpha contract) to add arbitrary function calls to a\n * queue. This contract can only execute a function call if the\n * function call has been in the queue for at least 3 hours.\n *\n * Anytime the Timelock contract makes a function call, it must be the\n * case that the function call was first made public by having been publicly\n * added to the queue at least 3 hours prior.\n *\n * The intention is to provide GovernorAlpha contract the functionality to\n * queue proposal actions. This would mean that any changes made by Sovryn\n * governance of any contract would necessarily come with at least an\n * advanced warning. This makes the Sovryn system follow a “time-delayed,\n * opt-out” upgrade pattern (rather than an “instant, forced” upgrade pattern).\n *\n * Time-delaying admin actions gives users a chance to exit system if its\n * admins become malicious or compromised (or make a change that the users\n * do not like). Downside is that honest admins would be unable\n * to lock down functionality to protect users if a critical bug was found.\n *\n * Delayed transactions reduce the amount of trust required by users of Sovryn\n * and the overall risk for contracts building on top of it, as GovernorAlpha.\n * */\ncontract Timelock is ErrorDecoder, ITimelock {\n using SafeMath for uint256;\n\n uint256 public constant GRACE_PERIOD = 14 days;\n uint256 public constant MINIMUM_DELAY = 3 hours;\n uint256 public constant MAXIMUM_DELAY = 30 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /**\n * @notice Function called on instance deployment of the contract.\n * @param admin_ Governance contract address.\n * @param delay_ Time to wait for queued transactions to be executed.\n * */\n constructor(address admin_, uint256 delay_) public {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {}\n\n /**\n * @notice Set a new delay when executing the contract calls.\n * @param delay_ The amount of time to wait until execution.\n * */\n function setDelay(uint256 delay_) public {\n require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n require(delay_ >= MINIMUM_DELAY, \"Timelock::setDelay: Delay must exceed minimum delay.\");\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n /**\n * @notice Accept a new admin for the timelock.\n * */\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n /**\n * @notice Set a new pending admin for the timelock.\n * @param pendingAdmin_ The new pending admin address.\n * */\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n /**\n * @notice Queue a new transaction from the governance contract.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function queueTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public returns (bytes32) {\n require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n /**\n * @notice Cancel a transaction.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function cancelTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public {\n require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n /**\n * @notice Executes a previously queued transaction from the governance.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function executeTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public payable returns (bytes memory) {\n require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call.value(value)(callData);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"Timelock::executeTransaction: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"Timelock::executeTransaction: \", string(returnData)));\n }\n }\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n /**\n * @notice A function used to get the current Block Timestamp.\n * @dev Timestamp of the current block in seconds since the epoch.\n * It is a Unix time stamp. So, it has the complete information about\n * the date, hours, minutes, and seconds (in UTC) when the block was\n * created.\n * */\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" + }, + "contracts/governance/Vesting/DevelopmentFund.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Development Fund.\n * @author Franklin Richards\n * @notice You can use this contract for timed token release from Dev Fund.\n */\ncontract DevelopmentFund {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The current contract status.\n enum Status { Deployed, Active, Expired }\n Status public status;\n\n /// @notice The owner of the locked tokens (usually Governance).\n address public lockedTokenOwner;\n /// @notice The owner of the unlocked tokens (usually MultiSig).\n address public unlockedTokenOwner;\n /// @notice The emergency transfer wallet/contract.\n address public safeVault;\n /// @notice The new locked token owner waiting to be approved.\n address public newLockedTokenOwner;\n\n /// @notice The last token release timestamp or the time of contract creation.\n uint256 public lastReleaseTime;\n\n /// @notice The release duration array in seconds.\n uint256[] public releaseDuration;\n /// @notice The release token amount.\n uint256[] public releaseTokenAmount;\n\n /* Events */\n\n /// @notice Emitted when the contract is activated.\n event DevelopmentFundActivated();\n\n /// @notice Emitted when the contract is expired due to total token transfer.\n event DevelopmentFundExpired();\n\n /// @notice Emitted when a new locked owner is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current locked owner.\n event NewLockedOwnerAdded(address indexed _initiator, address indexed _newLockedOwner);\n\n /// @notice Emitted when a new locked owner is approved to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _oldLockedOwner The address of the previous locked owner.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current unlocked owner.\n event NewLockedOwnerApproved(\n address indexed _initiator,\n address indexed _oldLockedOwner,\n address indexed _newLockedOwner\n );\n\n /// @notice Emitted when a new unlocked owner is updated in the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newUnlockedOwner The address which is updated as the new unlocked owner.\n /// @dev Can only be initiated by the current locked owner.\n event UnlockedOwnerUpdated(address indexed _initiator, address indexed _newUnlockedOwner);\n\n /// @notice Emitted when a new token deposit is done.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new release schedule is created.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseCount The number of releases planned in the schedule.\n event TokenReleaseChanged(address indexed _initiator, uint256 _releaseCount);\n\n /// @notice Emitted when a unlocked owner transfers all the tokens to a safe vault.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token withdrawn.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done in an emergency situation only to a predetermined wallet by locked token owner.\n event LockedTokenTransferByUnlockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /// @notice Emitted when a unlocked owner withdraws the released tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token withdrawn.\n /// @param _releaseCount The total number of releases done based on duration.\n event UnlockedTokenWithdrawalByUnlockedOwner(\n address indexed _initiator,\n uint256 _amount,\n uint256 _releaseCount\n );\n\n /// @notice Emitted when a locked owner transfers all the tokens to a receiver.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token transfer.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done only by locked token owner.\n event LockedTokenTransferByLockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /* Modifiers */\n\n modifier onlyLockedTokenOwner() {\n require(msg.sender == lockedTokenOwner, \"Only Locked Token Owner can call this.\");\n _;\n }\n\n modifier onlyUnlockedTokenOwner() {\n require(msg.sender == unlockedTokenOwner, \"Only Unlocked Token Owner can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _lockedTokenOwner The owner of the locked tokens & contract.\n * @param _safeVault The emergency wallet/contract to transfer token.\n * @param _unlockedTokenOwner The owner of the unlocked tokens.\n * @param _lastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev Initial release schedule should be verified, error will result in either redeployment or calling changeTokenReleaseSchedule() after init() along with token transfer.\n */\n constructor(\n address _SOV,\n address _lockedTokenOwner,\n address _safeVault,\n address _unlockedTokenOwner,\n uint256 _lastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_lockedTokenOwner != address(0), \"Locked token & contract owner address invalid.\");\n require(_safeVault != address(0), \"Safe Vault address invalid.\");\n require(_unlockedTokenOwner != address(0), \"Unlocked token address invalid.\");\n\n SOV = IERC20(_SOV);\n lockedTokenOwner = _lockedTokenOwner;\n safeVault = _safeVault;\n unlockedTokenOwner = _unlockedTokenOwner;\n\n lastReleaseTime = _lastReleaseTime;\n /// If last release time passed is zero, then current time stamp will be used as the last release time.\n if (_lastReleaseTime == 0) {\n lastReleaseTime = block.timestamp;\n }\n\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n }\n\n /**\n * @notice This function is called once after deployment for token transfer based on schedule.\n * @dev Without calling this function, the contract will not work.\n */\n function init() public checkStatus(Status.Deployed) {\n uint256[] memory _releaseTokenAmount = releaseTokenAmount;\n require(_releaseTokenAmount.length != 0, \"Release Schedule not set.\");\n\n /// Getting the current release schedule total token amount.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _releaseTotalTokenAmount);\n require(txStatus, \"Not enough token sent to change release schedule.\");\n\n status = Status.Active;\n\n emit DevelopmentFundActivated();\n }\n\n /**\n * @notice Update Locked Token Owner.\n * @param _newLockedTokenOwner The owner of the locked tokens & contract.\n */\n function updateLockedTokenOwner(address _newLockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newLockedTokenOwner != address(0), \"New locked token owner address invalid.\");\n\n newLockedTokenOwner = _newLockedTokenOwner;\n\n emit NewLockedOwnerAdded(msg.sender, _newLockedTokenOwner);\n }\n\n /**\n * @notice Approve Locked Token Owner.\n * @dev This approval is an added security to avoid development fund takeover by a compromised locked token owner.\n */\n function approveLockedTokenOwner() public onlyUnlockedTokenOwner checkStatus(Status.Active) {\n require(newLockedTokenOwner != address(0), \"No new locked owner added.\");\n\n emit NewLockedOwnerApproved(msg.sender, lockedTokenOwner, newLockedTokenOwner);\n\n lockedTokenOwner = newLockedTokenOwner;\n\n newLockedTokenOwner = address(0);\n }\n\n /**\n * @notice Update Unlocked Token Owner.\n * @param _newUnlockedTokenOwner The new unlocked token owner.\n */\n function updateUnlockedTokenOwner(address _newUnlockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newUnlockedTokenOwner != address(0), \"New unlocked token owner address invalid.\");\n\n unlockedTokenOwner = _newUnlockedTokenOwner;\n\n emit UnlockedOwnerUpdated(msg.sender, _newUnlockedTokenOwner);\n }\n\n /**\n * @notice Deposit tokens to this contract.\n * @param _amount the amount of tokens deposited.\n * @dev These tokens can be withdrawn/transferred any time by the lockedTokenOwner.\n */\n function depositTokens(uint256 _amount) public checkStatus(Status.Active) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDeposit(msg.sender, _amount);\n }\n\n /**\n * @notice Change the Token release schedule. It creates a completely new schedule, and does not append on the previous one.\n * @param _newLastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev _releaseDuration and _releaseTokenAmount should be specified in reverse order of release.\n */\n function changeTokenReleaseSchedule(\n uint256 _newLastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public onlyLockedTokenOwner checkStatus(Status.Active) {\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// If the last release time has to be changed, then you can pass a new one here.\n /// Or else, the duration of release will be calculated based on this timestamp.\n /// Even a future timestamp can be mentioned here.\n if (_newLastReleaseTime != 0) {\n lastReleaseTime = _newLastReleaseTime;\n }\n\n /// Checking if the contract have enough token balance for the release.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n /// Getting the current token balance of the contract.\n uint256 remainingTokens = SOV.balanceOf(address(this));\n\n /// If the token balance is not sufficient, then we transfer the change to contract.\n if (remainingTokens < _releaseTotalTokenAmount) {\n bool txStatus =\n SOV.transferFrom(\n msg.sender,\n address(this),\n _releaseTotalTokenAmount.sub(remainingTokens)\n );\n require(txStatus, \"Not enough token sent to change release schedule.\");\n } else if (remainingTokens > _releaseTotalTokenAmount) {\n /// If there are more tokens than required, send the extra tokens back.\n bool txStatus =\n SOV.transfer(msg.sender, remainingTokens.sub(_releaseTotalTokenAmount));\n require(txStatus, \"Token not received by the Locked Owner.\");\n }\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n\n emit TokenReleaseChanged(msg.sender, _releaseDuration.length);\n }\n\n /**\n * @notice Transfers all of the remaining tokens in an emergency situation.\n * @dev This could be called when governance or development fund might be compromised.\n */\n function transferTokensByUnlockedTokenOwner()\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(safeVault, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByUnlockedOwner(msg.sender, safeVault, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /**\n * @notice Withdraws all unlocked/released token.\n * @param _amount The amount to be withdrawn.\n */\n function withdrawTokensByUnlockedTokenOwner(uint256 _amount)\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_amount > 0, \"Zero can't be withdrawn.\");\n\n uint256 count; /// To know how many elements to be removed from the release schedule.\n uint256 amount = _amount; /// To know the total amount to be transferred.\n uint256 newLastReleaseTimeMemory = lastReleaseTime; /// Better to use memory than storage.\n uint256 releaseLength = releaseDuration.length.sub(1); /// Also checks if there are any elements in the release schedule.\n\n /// Getting the amount of tokens, the number of releases and calculating the total duration.\n while (\n amount > 0 &&\n newLastReleaseTimeMemory.add(releaseDuration[releaseLength]) < block.timestamp\n ) {\n if (amount >= releaseTokenAmount[releaseLength]) {\n amount = amount.sub(releaseTokenAmount[releaseLength]);\n newLastReleaseTimeMemory = newLastReleaseTimeMemory.add(\n releaseDuration[releaseLength]\n );\n count++;\n } else {\n /// This will be the last case, if correct amount is passed.\n releaseTokenAmount[releaseLength] = releaseTokenAmount[releaseLength].sub(amount);\n amount = 0;\n }\n releaseLength--;\n }\n\n /// Checking to see if atleast a single schedule was reached or not.\n require(count > 0 || amount == 0, \"No release schedule reached.\");\n\n /// If locked token owner tries to send a higher amount that schedule\n uint256 value = _amount.sub(amount);\n\n /// Now clearing up the release schedule.\n releaseDuration.length -= count;\n releaseTokenAmount.length -= count;\n\n /// Updating the last release time.\n lastReleaseTime = newLastReleaseTimeMemory;\n\n /// Sending the amount to unlocked token owner.\n bool txStatus = SOV.transfer(msg.sender, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit UnlockedTokenWithdrawalByUnlockedOwner(msg.sender, value, count);\n }\n\n /**\n * @notice Transfers all of the remaining tokens by the owner maybe for an upgrade.\n * @dev This could be called when the current development fund has to be upgraded.\n * @param _receiver The address which receives this token transfer.\n */\n function transferTokensByLockedTokenOwner(address _receiver)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(_receiver, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByLockedOwner(msg.sender, _receiver, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token release duration.\n * @return _currentReleaseDuration The current release duration.\n */\n function getReleaseDuration() public view returns (uint256[] memory _releaseTokenDuration) {\n return releaseDuration;\n }\n\n /**\n * @notice Function to read the current token release amount.\n * @return _currentReleaseTokenAmount The current release token amount.\n */\n function getReleaseTokenAmount()\n public\n view\n returns (uint256[] memory _currentReleaseTokenAmount)\n {\n return releaseTokenAmount;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../IFeeSharingCollector.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../proxy/UpgradableProxy.sol\";\nimport \"../../../openzeppelin/Address.sol\";\n\n/**\n * @title Four Year Vesting Contract.\n *\n * @notice A four year vesting contract.\n *\n * @dev Vesting contract is upgradable,\n * Make sure the vesting owner is multisig otherwise it will be\n * catastrophic.\n * */\ncontract FourYearVesting is FourYearVestingStorage, UpgradableProxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharingCollector Fee sharing proxy address.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n address _feeSharingCollector,\n uint256 _extendDurationFor\n ) public {\n require(Address.isContract(_logic), \"_logic not a contract\");\n require(_SOV != address(0), \"SOV address invalid\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(Address.isContract(_stakingAddress), \"_stakingAddress not a contract\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(Address.isContract(_feeSharingCollector), \"_feeSharingCollector not a contract\");\n require((_extendDurationFor % FOUR_WEEKS) == 0, \"invalid duration\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n tokenOwner = _tokenOwner;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n maxInterval = 18 * FOUR_WEEKS;\n extendDurationFor = _extendDurationFor;\n }\n\n /**\n * @notice Set address of the implementation - vesting owner.\n * @dev Overriding setImplementation function of UpgradableProxy. The logic can only be\n * modified when both token owner and veting owner approve. Since\n * setImplementation can only be called by vesting owner, we also need to check\n * if the new logic is already approved by the token owner.\n * @param _implementation Address of the implementation. Must match with what is set by token owner.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n require(Address.isContract(_implementation), \"_implementation not a contract\");\n require(newImplementation == _implementation, \"address mismatch\");\n _setImplementation(_implementation);\n newImplementation = address(0);\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"./FourYearVesting.sol\";\nimport \"./IFourYearVestingFactory.sol\";\n\n/**\n * @title Four Year Vesting Factory: Contract to deploy four year vesting contracts.\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract FourYearVestingFactory is IFourYearVestingFactory, Ownable {\n /// @dev Added an event to keep track of the vesting contract created for a token owner\n event FourYearVestingCreated(address indexed tokenOwner, address indexed vestingAddress);\n\n /**\n * @notice Deploys four year vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwnerMultisig The address of an owner of vesting contract.\n * @dev _vestingOwnerMultisig should ALWAYS be multisig.\n * @param _fourYearVestingLogic The implementation contract.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * @return The four year vesting contract address.\n * */\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external onlyOwner returns (address) {\n address fourYearVesting =\n address(\n new FourYearVesting(\n _fourYearVestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _feeSharing,\n _extendDurationFor\n )\n );\n Ownable(fourYearVesting).transferOwnership(_vestingOwnerMultisig);\n emit FourYearVestingCreated(_tokenOwner, fourYearVesting);\n return fourYearVesting;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./IFourYearVesting.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Four Year Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by FourYearVestingFactory contract.\n * */\ncontract FourYearVestingLogic is IFourYearVesting, FourYearVestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n\n /* Events */\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n event TokenOwnerChanged(address indexed newOwner, address indexed oldOwner);\n\n /* Modifiers */\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Sets the max interval.\n * @param _interval Max interval for which tokens scheduled shall be staked.\n * */\n function setMaxInterval(uint256 _interval) external onlyOwner {\n require(_interval.mod(FOUR_WEEKS) == 0, \"invalid interval\");\n maxInterval = _interval;\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount)\n {\n (lastSchedule, remainingAmount) = _stakeTokens(msg.sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokensWithApproval(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) external onlyThisContract returns (uint256 lastSchedule, uint256 remainingAmount) {\n (lastSchedule, remainingAmount) = _stakeTokens(_sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) external onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n uint256 stakingEndDate = endDate;\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate.add(cliff); i <= stakingEndDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) external onlyTokenOwner {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external onlyTokenOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Change token owner - only vesting owner is allowed to change.\n * @dev Modifies token owner. This must be followed by approval\n * from token owner.\n * @param _newTokenOwner Address of new token owner.\n * */\n function changeTokenOwner(address _newTokenOwner) public onlyOwner {\n require(_newTokenOwner != address(0), \"invalid new token owner address\");\n require(_newTokenOwner != tokenOwner, \"same owner not allowed\");\n newTokenOwner = _newTokenOwner;\n }\n\n /**\n * @notice Approve token owner change - only token Owner.\n * @dev Token owner can only be modified\n * when both vesting owner and token owner have approved. This\n * function ascertains the approval of token owner.\n * */\n function approveOwnershipTransfer() public onlyTokenOwner {\n require(newTokenOwner != address(0), \"invalid address\");\n tokenOwner = newTokenOwner;\n newTokenOwner = address(0);\n emit TokenOwnerChanged(tokenOwner, msg.sender);\n }\n\n /**\n * @notice Set address of the implementation - only Token Owner.\n * @dev This function sets the new implementation address.\n * It must also be approved by the Vesting owner.\n * @param _newImplementation Address of the new implementation.\n * */\n function setImpl(address _newImplementation) public onlyTokenOwner {\n require(_newImplementation != address(0), \"invalid new implementation address\");\n newImplementation = _newImplementation;\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() external onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Extends stakes(unlocked till timeDuration) for four year vesting contracts.\n * @dev Tokens are vested for 4 years. Since the max staking\n * period is 3 years and the tokens are unlocked only after the first year(timeDuration) is\n * passed, hence, we usually extend the duration of staking for all unlocked tokens for the first\n * year by 3 years. In some cases, the timeDuration can differ.\n * */\n function extendStaking() external {\n uint256 timeDuration = startDate.add(extendDurationFor);\n uint256[] memory dates;\n uint96[] memory stakes;\n (dates, stakes) = staking.getStakes(address(this));\n\n for (uint256 i = 0; i < dates.length; i++) {\n if ((dates[i] < block.timestamp) && (dates[i] <= timeDuration) && (stakes[i] > 0)) {\n staking.extendStakingDuration(dates[i], dates[i].add(156 weeks));\n endDate = dates[i].add(156 weeks);\n } else {\n break;\n }\n }\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function _stakeTokens(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) internal returns (uint256 lastSchedule, uint256 remainingAmount) {\n // Creating a new staking schedule for the same vesting contract is disallowed unlike normal vesting\n require(\n (startDate == 0) ||\n (startDate > 0 && remainingStakeAmount > 0 && _restartStakeSchedule > 0),\n \"create new vesting address\"\n );\n uint256 restartDate;\n uint256 relativeAmount;\n // Calling the _stakeTokens function first time for the vesting contract\n // Runs for maxInterval only (consider maxInterval = 18 * 4 = 72 weeks)\n if (startDate == 0 && _restartStakeSchedule == 0) {\n startDate = staking.timestampToLockDate(block.timestamp); // Set only once\n durationLeft = duration; // We do not touch duration and cliff as they are used throughout\n cliffAdded = cliff; // Hence, durationLeft and cliffAdded is created\n }\n // Calling the _stakeTokens second/third time - we start from the end of previous interval\n // and the remaining amount(amount left after tokens are staked in the previous interval)\n if (_restartStakeSchedule > 0) {\n require(\n _restartStakeSchedule == lastStakingSchedule && _amount == remainingStakeAmount,\n \"invalid params\"\n );\n restartDate = _restartStakeSchedule;\n } else {\n restartDate = startDate;\n }\n // Runs only once when the _stakeTokens is called for the first time\n if (endDate == 0) {\n endDate = staking.timestampToLockDate(block.timestamp.add(duration));\n }\n uint256 addedMaxInterval = restartDate.add(maxInterval); // run for maxInterval\n if (addedMaxInterval < endDate) {\n // Runs for max interval\n lastStakingSchedule = addedMaxInterval;\n relativeAmount = (_amount.mul(maxInterval)).div(durationLeft); // (_amount * 18) / 39\n durationLeft = durationLeft.sub(maxInterval); // durationLeft - 18 periods(72 weeks)\n remainingStakeAmount = _amount.sub(relativeAmount); // Amount left to be staked in subsequent intervals\n } else {\n // Normal run\n lastStakingSchedule = endDate; // if staking intervals left < 18 periods(72 weeks)\n remainingStakeAmount = 0;\n durationLeft = 0;\n relativeAmount = _amount; // Stake all amount left\n }\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), relativeAmount);\n require(success, \"transfer failed\");\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), relativeAmount);\n\n staking.stakesBySchedule(\n relativeAmount,\n cliffAdded,\n duration.sub(durationLeft),\n FOUR_WEEKS,\n address(this),\n tokenOwner\n );\n if (durationLeft == 0) {\n // All tokens staked\n cliffAdded = 0;\n } else {\n cliffAdded = cliffAdded.add(maxInterval); // Add cliff to the end of previous maxInterval\n }\n\n emit TokensStaked(_sender, relativeAmount);\n return (lastStakingSchedule, remainingStakeAmount);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n /// @dev For four year vesting, withdrawal of stakes for the first year is not allowed. These\n /// stakes are extended for three years. In some cases the withdrawal may be allowed at a different\n /// time and hence we use extendDurationFor.\n for (uint256 i = startDate.add(extendDurationFor); i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number.sub(1));\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../Staking/interfaces/IStaking.sol\";\nimport \"../../IFeeSharingCollector.sol\";\n\n/**\n * @title Four Year Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for four year vesting.\n * It is parent of FourYearVestingLogic and FourYearVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract FourYearVestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n // Used lower case for cliff and duration to maintain consistency with normal vesting\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public constant cliff = 4 weeks;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public constant duration = 156 weeks;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n /// @notice Maximum interval to stake tokens at one go\n uint256 public maxInterval;\n\n /// @notice End of previous staking schedule.\n uint256 public lastStakingSchedule;\n\n /// @notice Amount of shares left to be staked.\n uint256 public remainingStakeAmount;\n\n /// @notice Durations left.\n uint256 public durationLeft;\n\n /// @notice Cliffs added.\n uint256 public cliffAdded;\n\n /// @notice Address of new token owner.\n address public newTokenOwner;\n\n /// @notice Address of new implementation.\n address public newImplementation;\n\n /// @notice Duration(from start) till the time unlocked tokens are extended(for 3 years)\n uint256 public extendDurationFor;\n\n /// @dev Please add new state variables below this line. Mark them internal and\n /// add a getter function while upgrading the contracts.\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IFourYearVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IFourYearVesting {\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount);\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingFactory contract to override empty\n * implemention of deployFourYearVesting function\n * and use an instance of FourYearVestingFactory.\n */\ninterface IFourYearVestingFactory {\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/GenericTokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\n\n/**\n * @title Token sender contract.\n *\n * @notice This contract includes functions to transfer tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract GenericTokenSender is AdminRole {\n /* Events */\n\n event TokensTransferred(address indexed token, address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer given amounts of tokens to the given addresses.\n * @param _token The address of the token.\n * @param _receivers The addresses of the receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferTokensUsingList(\n address _token,\n address[] calldata _receivers,\n uint256[] calldata _amounts\n ) external onlyAuthorized {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferTokens(_token, _receivers[i], _amounts[i]);\n }\n }\n\n /**\n * @notice Transfer tokens to given address.\n * @param _token The address of the token.\n * @param _receiver The address of the token receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) external onlyAuthorized {\n _transferTokens(_token, _receiver, _amount);\n }\n\n function _transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) internal {\n require(_token != address(0), \"token address invalid\");\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n require(IERC20(_token).transfer(_receiver, _amount), \"transfer failed\");\n emit TokensTransferred(_token, _receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/ITeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for TeamVesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by Staking contract to call governanceWithdrawTokens\n * function having the vesting contract instance address.\n */\ninterface ITeamVesting {\n function startDate() external view returns (uint256);\n\n function cliff() external view returns (uint256);\n\n function endDate() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function tokenOwner() external view returns (address);\n\n function governanceWithdrawTokens(address receiver) external;\n}\n" + }, + "contracts/governance/Vesting/IVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IVesting {\n function duration() external returns (uint256);\n\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 amount) external;\n\n function tokenOwner() external view returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingFactory contract to override empty\n * implemention of deployVesting and deployTeamVesting functions\n * and on VestingRegistry contract to use an instance of VestingFactory.\n */\ninterface IVestingFactory {\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for upgradable Vesting Registry contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IVestingRegistry {\n function getVesting(address _tokenOwner) external view returns (address);\n\n function getTeamVesting(address _tokenOwner) external view returns (address);\n\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n function isVestingAddress(address _vestingAddress) external view returns (bool);\n\n function isTeamVesting(address _vestingAddress) external view returns (bool);\n}\n" + }, + "contracts/governance/Vesting/OrigingVestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./VestingRegistry.sol\";\n\n/**\n * @title Temp contract for checking address, creating and staking tokens.\n * @notice It casts an instance of vestingRegistry and by using createVesting\n * function it creates a vesting, gets it and stakes some tokens w/ this vesting.\n * */\ncontract OrigingVestingCreator is Ownable {\n VestingRegistry public vestingRegistry;\n\n mapping(address => bool) processedList;\n\n constructor(address _vestingRegistry) public {\n vestingRegistry = VestingRegistry(_vestingRegistry);\n }\n\n /**\n * @notice Create a vesting, get it and stake some tokens w/ this vesting.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount of tokens to be vested.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyOwner {\n require(_tokenOwner != address(0), \"Invalid address\");\n require(!processedList[_tokenOwner], \"Already processed\");\n\n processedList[_tokenOwner] = true;\n\n vestingRegistry.createVesting(_tokenOwner, _amount, _cliff, _duration);\n address vesting = vestingRegistry.getVesting(_tokenOwner);\n vestingRegistry.stakeTokens(vesting, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/OriginInvestorsClaim.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./VestingRegistry.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\n\n/**\n * @title Origin investors claim vested cSOV tokens.\n * @notice // TODO: fund this contract with a total amount of SOV needed to distribute.\n * */\ncontract OriginInvestorsClaim is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// VestingRegistry public constant vestingRegistry = VestingRegistry(0x80B036ae59B3e38B573837c01BB1DB95515b7E6B);\n\n uint256 public totalAmount;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant SOV_VESTING_CLIFF = 6 weeks;\n\n uint256 public kickoffTS;\n uint256 public vestingTerm;\n uint256 public investorsQty;\n bool public investorsListInitialized;\n VestingRegistry public vestingRegistry;\n IStaking public staking;\n IERC20 public SOVToken;\n\n /// @dev user => flag : Whether user has admin role.\n mapping(address => bool) public admins;\n\n /// @dev investor => Amount : Origin investors entitled to claim SOV.\n mapping(address => uint256) public investorsAmountsList;\n\n /* Events */\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n event InvestorsAmountsListAppended(uint256 qty, uint256 amount);\n event ClaimVested(address indexed investor, uint256 amount);\n event ClaimTransferred(address indexed investor, uint256 amount);\n event InvestorsAmountsListInitialized(uint256 qty, uint256 totalAmount);\n\n /* Modifiers */\n\n /// @dev Throws if called by any account other than the owner or admin.\n modifier onlyAuthorized() {\n require(\n isOwner() || admins[msg.sender],\n \"OriginInvestorsClaim::onlyAuthorized: should be authorized\"\n );\n _;\n }\n\n /// @dev Throws if called by any account not whitelisted.\n modifier onlyWhitelisted() {\n require(\n investorsAmountsList[msg.sender] != 0,\n \"OriginInvestorsClaim::onlyWhitelisted: not whitelisted or already claimed\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an initialized investors list.\n modifier notInitialized() {\n require(\n !investorsListInitialized,\n \"OriginInvestorsClaim::notInitialized: the investors list should not be set as initialized\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an uninitialized investors list.\n modifier initialized() {\n require(\n investorsListInitialized,\n \"OriginInvestorsClaim::initialized: the investors list has not been set yet\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires one parameter:\n * @param vestingRegistryAddress The vestingRegistry contract instance address.\n * */\n constructor(address vestingRegistryAddress) public {\n vestingRegistry = VestingRegistry(vestingRegistryAddress);\n staking = IStaking(vestingRegistry.staking());\n kickoffTS = staking.kickoffTS();\n SOVToken = IERC20(staking.SOVToken());\n vestingTerm = kickoffTS + SOV_VESTING_CLIFF;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice In case we have unclaimed tokens or in emergency case\n * this function transfers all SOV tokens to a given address.\n * @param toAddress The recipient address of all this contract tokens.\n * */\n function authorizedBalanceWithdraw(address toAddress) public onlyAuthorized {\n require(\n SOVToken.transfer(toAddress, SOVToken.balanceOf(address(this))),\n \"OriginInvestorsClaim::authorizedTransferBalance: transfer failed\"\n );\n }\n\n /**\n * @notice Should be called after the investors list setup completed.\n * This function checks whether the SOV token balance of the contract is\n * enough and sets status list to initialized.\n * */\n function setInvestorsAmountsListInitialized() public onlyAuthorized notInitialized {\n require(\n SOVToken.balanceOf(address(this)) >= totalAmount,\n \"OriginInvestorsClaim::setInvestorsAmountsList: the contract is not enough financed\"\n );\n\n investorsListInitialized = true;\n\n emit InvestorsAmountsListInitialized(investorsQty, totalAmount);\n }\n\n /**\n * @notice The contract should be approved or transferred necessary\n * amount of SOV prior to calling the function.\n * @param investors The list of investors addresses to add to the list.\n * Duplicates will be skipped.\n * @param claimAmounts The list of amounts for investors investors[i]\n * will receive claimAmounts[i] of SOV.\n * */\n function appendInvestorsAmountsList(\n address[] calldata investors,\n uint256[] calldata claimAmounts\n ) external onlyAuthorized notInitialized {\n uint256 subQty;\n uint256 sumAmount;\n require(\n investors.length == claimAmounts.length,\n \"OriginInvestorsClaim::appendInvestorsAmountsList: investors.length != claimAmounts.length\"\n );\n\n for (uint256 i = 0; i < investors.length; i++) {\n if (investorsAmountsList[investors[i]] == 0) {\n investorsAmountsList[investors[i]] = claimAmounts[i];\n sumAmount = sumAmount.add(claimAmounts[i]);\n } else {\n subQty = subQty.add(1);\n }\n }\n\n investorsQty = investorsQty.add(investors.length.sub(subQty));\n totalAmount = totalAmount.add(sumAmount);\n emit InvestorsAmountsListAppended(investors.length.sub(subQty), sumAmount);\n }\n\n /**\n * @notice Claim tokens from this contract.\n * If vestingTerm is not yet achieved a vesting is created.\n * Otherwise tokens are tranferred.\n * */\n function claim() external onlyWhitelisted initialized {\n if (now < vestingTerm) {\n createVesting();\n } else {\n transfer();\n }\n }\n\n /**\n * @notice Transfer tokens from this contract to a vestingRegistry contract.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to vesting contract.\n * */\n function createVesting() internal {\n uint256 cliff = vestingTerm.sub(now);\n uint256 duration = cliff;\n uint256 amount = investorsAmountsList[msg.sender];\n address vestingContractAddress;\n\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n vestingContractAddress == address(0),\n \"OriginInvestorsClaim::withdraw: the claimer has an active vesting contract\"\n );\n\n delete investorsAmountsList[msg.sender];\n\n vestingRegistry.createVesting(msg.sender, amount, cliff, duration);\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n SOVToken.transfer(address(vestingRegistry), amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n vestingRegistry.stakeTokens(vestingContractAddress, amount);\n\n emit ClaimVested(msg.sender, amount);\n }\n\n /**\n * @notice Transfer tokens from this contract to the sender.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to its account.\n * */\n function transfer() internal {\n uint256 amount = investorsAmountsList[msg.sender];\n\n delete investorsAmountsList[msg.sender];\n\n /**\n * @dev Withdraw only for those claiming after the cliff, i.e. without vesting contracts.\n * Those with vestingContracts should withdraw using Vesting.withdrawTokens\n * from Vesting (VestingLogic) contract.\n * */\n require(\n SOVToken.transfer(msg.sender, amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n\n emit ClaimTransferred(msg.sender, amount);\n }\n}\n" + }, + "contracts/governance/Vesting/TeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n//import \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../proxy/Proxy.sol\";\n\n/**\n * @title Team Vesting Contract.\n *\n * @notice A regular vesting contract, but the owner (governance) is able to\n * withdraw earlier without a slashing.\n *\n * @dev Vesting contracts shouldn't be upgradable,\n * use Proxy instead of UpgradableProxy.\n * */\ncontract TeamVesting is VestingStorage, Proxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollector\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_duration >= _cliff, \"duration must be bigger than or equal to the cliff\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n require(_duration <= staking.MAX_DURATION(), \"duration may not exceed the max duration\");\n tokenOwner = _tokenOwner;\n cliff = _cliff;\n duration = _duration;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n }\n}\n" + }, + "contracts/governance/Vesting/TokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title SOV Token sender contract.\n *\n * @notice This contract includes functions to transfer SOV tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract TokenSender is Ownable {\n /* Storage */\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @dev user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n constructor(address _SOV) public {\n require(_SOV != address(0), \"SOV address invalid\");\n\n SOV = _SOV;\n }\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Transfer given amounts of SOV to the given addresses.\n * @param _receivers The addresses of the SOV receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferSOVusingList(address[] memory _receivers, uint256[] memory _amounts)\n public\n onlyAuthorized\n {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferSOV(_receivers[i], _amounts[i]);\n }\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyAuthorized {\n _transferSOV(_receiver, _amount);\n }\n\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/Vesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./TeamVesting.sol\";\n\n/**\n * @title Vesting Contract.\n * @notice Team tokens and investor tokens are vested. Therefore, a smart\n * contract needs to be developed to enforce the vesting schedule.\n *\n * @dev TODO add tests for governanceWithdrawTokens.\n * */\ncontract Vesting is TeamVesting {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollectorProxy\n )\n public\n TeamVesting(\n _logic,\n _SOV,\n _stakingAddress,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharingCollectorProxy\n )\n {}\n\n /**\n * @dev We need to add this implementation to prevent proxy call VestingLogic.governanceWithdrawTokens\n * @param receiver The receiver of the token withdrawal.\n * */\n function governanceWithdrawTokens(address receiver) public {\n revert(\"operation not supported\");\n }\n}\n" + }, + "contracts/governance/Vesting/VestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"./VestingRegistryLogic.sol\";\nimport \"./VestingLogic.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingCreator is AdminRole {\n using SafeMath for uint256;\n\n ///@notice Boolean to check both vesting creation and staking is completed for a record\n bool vestingCreated;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 2 weeks;\n\n ///@notice the SOV token contract\n IERC20 public SOV;\n\n ///@notice the vesting registry contract\n VestingRegistryLogic public vestingRegistryLogic;\n\n ///@notice Holds Vesting Data\n struct VestingData {\n uint256 amount;\n uint256 cliff;\n uint256 duration;\n bool governanceControl; ///@dev true - tokens can be withdrawn by governance\n address tokenOwner;\n uint256 vestingCreationType;\n }\n\n ///@notice list of vesting to be processed\n VestingData[] public vestingDataList;\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event TokensStaked(address indexed vesting, address indexed tokenOwner, uint256 amount);\n event VestingDataRemoved(address indexed caller, address indexed tokenOwner);\n event DataCleared(address indexed caller);\n\n constructor(address _SOV, address _vestingRegistryProxy) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_vestingRegistryProxy != address(0), \"Vesting registry address invalid\");\n\n SOV = IERC20(_SOV);\n vestingRegistryLogic = VestingRegistryLogic(_vestingRegistryProxy);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings to be processed to the list\n */\n function addVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _amounts,\n uint256[] calldata _cliffs,\n uint256[] calldata _durations,\n bool[] calldata _governanceControls,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n require(\n _tokenOwners.length == _amounts.length &&\n _tokenOwners.length == _cliffs.length &&\n _tokenOwners.length == _durations.length &&\n _tokenOwners.length == _governanceControls.length,\n \"arrays mismatch\"\n );\n\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(\n _durations[i] >= _cliffs[i],\n \"duration must be bigger than or equal to the cliff\"\n );\n require(_amounts[i] > 0, \"vesting amount cannot be 0\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_cliffs[i].mod(TWO_WEEKS) == 0, \"cliffs should have intervals of two weeks\");\n require(\n _durations[i].mod(TWO_WEEKS) == 0,\n \"durations should have intervals of two weeks\"\n );\n VestingData memory vestingData =\n VestingData({\n amount: _amounts[i],\n cliff: _cliffs[i],\n duration: _durations[i],\n governanceControl: _governanceControls[i],\n tokenOwner: _tokenOwners[i],\n vestingCreationType: _vestingCreationTypes[i]\n });\n vestingDataList.push(vestingData);\n }\n }\n\n /**\n * @notice Creates vesting contract and stakes tokens\n * @dev Vesting and Staking are merged for calls that fits the gas limit\n */\n function processNextVesting() external {\n processVestingCreation();\n processStaking();\n }\n\n /**\n * @notice Creates vesting contract without staking any tokens\n * @dev Separating the Vesting and Staking to tackle Block Gas Limit\n */\n function processVestingCreation() public {\n require(!vestingCreated, \"staking not done for the previous vesting\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n _createAndGetVesting(vestingData);\n vestingCreated = true;\n }\n }\n\n /**\n * @notice Staking vested tokens\n * @dev it can be the case when vesting creation and tokens staking can't be done in one transaction because of block gas limit\n */\n function processStaking() public {\n require(vestingCreated, \"cannot stake without vesting creation\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n address vestingAddress =\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n require(SOV.approve(address(vesting), vestingData.amount), \"Approve failed\");\n vesting.stakeTokens(vestingData.amount);\n emit TokensStaked(vestingAddress, vestingData.tokenOwner, vestingData.amount);\n address tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n vestingCreated = false;\n }\n\n /**\n * @notice removes next vesting data from the list\n * @dev we process inverted list\n * @dev we should be able to remove incorrect vesting data that can't be processed\n */\n function removeNextVesting() external onlyAuthorized {\n address tokenOwnerDetails;\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n\n /**\n * @notice removes all data about unprocessed vestings to be processed\n */\n function clearVestingDataList() public onlyAuthorized {\n delete vestingDataList;\n emit DataCleared(msg.sender);\n }\n\n /**\n * @notice returns address after vesting creation\n */\n function getVestingAddress() external view returns (address) {\n return\n _getVesting(\n vestingDataList[vestingDataList.length - 1].tokenOwner,\n vestingDataList[vestingDataList.length - 1].cliff,\n vestingDataList[vestingDataList.length - 1].duration,\n vestingDataList[vestingDataList.length - 1].governanceControl,\n vestingDataList[vestingDataList.length - 1].vestingCreationType\n );\n }\n\n /**\n * @notice returns period i.e. ((duration - cliff) / 4 WEEKS)\n * @dev will be used for deciding if vesting and staking needs to be processed\n * in a single transaction or separate transactions\n */\n function getVestingPeriod() external view returns (uint256) {\n uint256 duration = vestingDataList[vestingDataList.length - 1].duration;\n uint256 cliff = vestingDataList[vestingDataList.length - 1].cliff;\n uint256 fourWeeks = TWO_WEEKS.mul(2);\n uint256 period = duration.sub(cliff).div(fourWeeks);\n return period;\n }\n\n /**\n * @notice returns count of vestings to be processed\n */\n function getUnprocessedCount() external view returns (uint256) {\n return vestingDataList.length;\n }\n\n /**\n * @notice returns total amount of vestings to be processed\n */\n function getUnprocessedAmount() public view returns (uint256) {\n uint256 amount = 0;\n uint256 length = vestingDataList.length;\n for (uint256 i = 0; i < length; i++) {\n amount = amount.add(vestingDataList[i].amount);\n }\n return amount;\n }\n\n /**\n * @notice checks if contract balance is enough to process all vestings\n */\n function isEnoughBalance() public view returns (bool) {\n return SOV.balanceOf(address(this)) >= getUnprocessedAmount();\n }\n\n /**\n * @notice returns missed balance to process all vestings\n */\n function getMissingBalance() external view returns (uint256) {\n if (isEnoughBalance()) {\n return 0;\n }\n return getUnprocessedAmount() - SOV.balanceOf(address(this));\n }\n\n /**\n * @notice creates TeamVesting or Vesting contract\n * @dev new contract won't be created if account already has contract of the same type\n */\n function _createAndGetVesting(VestingData memory vestingData)\n internal\n returns (address vesting)\n {\n if (vestingData.governanceControl) {\n vestingRegistryLogic.createTeamVesting(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n } else {\n vestingRegistryLogic.createVestingAddr(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n }\n return\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n }\n\n /**\n * @notice returns an address of TeamVesting or Vesting contract (depends on a governance control)\n */\n function _getVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n bool _governanceControl,\n uint256 _vestingCreationType\n ) internal view returns (address vestingAddress) {\n if (_governanceControl) {\n vestingAddress = vestingRegistryLogic.getTeamVesting(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n } else {\n vestingAddress = vestingRegistryLogic.getVestingAddr(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n }\n }\n}\n" + }, + "contracts/governance/Vesting/VestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./Vesting.sol\";\nimport \"./TeamVesting.sol\";\nimport \"./IVestingFactory.sol\";\n\n/**\n * @title Vesting Factory: Contract to deploy vesting contracts\n * of two types: vesting (TokenHolder) and team vesting (Multisig).\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract VestingFactory is IVestingFactory, Ownable {\n address public vestingLogic;\n\n constructor(address _vestingLogic) public {\n require(_vestingLogic != address(0), \"invalid vesting logic address\");\n vestingLogic = _vestingLogic;\n }\n\n /**\n * @notice Deploys Vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner /// @dev owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new Vesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n\n /**\n * @notice Deploys Team Vesting contract.\n * @param _SOV The address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner //owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new TeamVesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\n\n/**\n * @title Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by a VestingFactory contract.\n * */\ncontract VestingLogic is IVesting, VestingStorage, ApprovalReceiver {\n /* Events */\n\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(uint256 _amount) public {\n _stakeTokens(msg.sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokensWithApproval(address _sender, uint256 _amount) public onlyThisContract {\n _stakeTokens(_sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * */\n function _stakeTokens(address _sender, uint256 _amount) internal {\n /// @dev Maybe better to allow staking unil the cliff was reached.\n if (startDate == 0) {\n startDate = staking.timestampToLockDate(block.timestamp);\n }\n endDate = staking.timestampToLockDate(block.timestamp + duration);\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), _amount);\n require(success);\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), _amount);\n\n staking.stakeBySchedule(_amount, cliff, duration, FOUR_WEEKS, address(this), tokenOwner);\n\n emit TokensStaked(_sender, _amount);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws all tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * @dev Can be called only by owner.\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdrawTokens(address receiver) public {\n require(msg.sender == address(staking), \"unauthorized\");\n\n _withdrawTokens(receiver, true);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) public onlyOwners {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number - 1);\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n if (isGovernance) {\n staking.governanceWithdraw(stake, i, receiver);\n } else {\n staking.withdraw(stake, i, receiver);\n }\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) public onlyOwners {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() public onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Registry contract.\n *\n * @notice On January 25, 2020, Sovryn launched the Genesis Reservation system.\n * Sovryn community members who controlled a special NFT were granted access to\n * stake BTC or rBTC for cSOV tokens at a rate of 2500 satoshis per cSOV. Per\n * SIP-0003, up to 2,000,000 cSOV were made available in the Genesis event,\n * which will be redeemable on a 1:1 basis for cSOV, subject to approval by\n * existing SOV holders.\n *\n * On 15 Feb 2021 Sovryn is taking another step in its journey to decentralized\n * financial sovereignty with the vote on SIP 0005. This proposal will enable\n * participants of the Genesis Reservation system to redeem their reserved cSOV\n * tokens for SOV. They will also have the choice to redeem cSOV for rBTC if\n * they decide to exit the system.\n *\n * This contract deals with the vesting and redemption of cSOV tokens.\n * */\ncontract VestingRegistry is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The cSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract.\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVReImburse(address from, uint256 CSOVamount, uint256 reImburseAmount);\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing collector proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n //---ACL------------------------------------------------------------------\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * TODO: This ACL logic should be available on OpenZeppeling Ownable.sol\n * or on our own overriding sovrynOwnable. This same logic is repeated\n * on OriginInvestorsClaim.sol, TokenSender.sol and VestingRegistry2.sol\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice cSOV payout to sender with rBTC currency.\n * 1.- Check holder cSOV balance by adding up every cSOV token balance.\n * 2.- ReImburse rBTC if funds available.\n * 3.- And store holder address in processedList.\n */\n function reImburse() public isNotProcessed isNotBlacklisted {\n uint256 CSOVAmountWei = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n CSOVAmountWei = CSOVAmountWei.add(balance);\n }\n\n require(CSOVAmountWei > lockedAmount[msg.sender], \"holder has no CSOV\");\n CSOVAmountWei -= lockedAmount[msg.sender];\n processedList[msg.sender] = true;\n\n /**\n * @dev Found and fixed the SIP-0007 bug on VestingRegistry::reImburse formula.\n * More details at Documenting Code issues at point 11 in\n * https://docs.google.com/document/d/10idTD1K6JvoBmtPKGuJ2Ub_mMh6qTLLlTP693GQKMyU/\n * Previous buggy code: uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**10);\n * */\n uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**8);\n require(address(this).balance >= reImburseAmount, \"Not enough funds to reimburse\");\n msg.sender.transfer(reImburseAmount);\n\n emit CSOVReImburse(msg.sender, CSOVAmountWei, reImburseAmount);\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Exchange cSOV to SOV with 1:1 rate\n */\n function exchangeAllCSOV() public isNotProcessed isNotBlacklisted {\n processedList[msg.sender] = true;\n\n uint256 amount = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n amount += balance;\n }\n\n require(amount > lockedAmount[msg.sender], \"amount invalid\");\n amount -= lockedAmount[msg.sender];\n\n _createVestingForCSOV(amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param _vesting The address of Vesting contract.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n /// @dev TODO: Owner of OwnerVesting contracts - the same address as tokenOwner.\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry2.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title VestingRegistry 2 contract.\n * @notice One time contract needed to distribute tokens to origin sales investors.\n * */\ncontract VestingRegistry2 is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The CSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry3.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingRegistry3 is Ownable {\n using SafeMath for uint256;\n\n IVestingFactory public vestingFactory;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n //@notice fee sharing proxy\n address public feeSharingCollector;\n //@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n //TODO add to the documentation: address can have only one vesting of each type\n //user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n //user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n constructor(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"./VestingRegistryStorage.sol\";\n\ncontract VestingRegistryLogic is VestingRegistryStorage {\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event VestingCreationAndTypesSet(\n address indexed vesting,\n VestingCreationAndTypeDetails vestingCreationAndType\n );\n\n /**\n * @notice Replace constructor with initialize function for Upgradable Contracts\n * This function will be called only once by the owner\n * */\n function initialize(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner,\n address _lockedSOV,\n address[] calldata _vestingRegistries\n ) external onlyOwner initializer {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n require(_lockedSOV != address(0), \"LockedSOV address invalid\");\n\n _setVestingFactory(_vestingFactory);\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n lockedSOV = LockedSOV(_lockedSOV);\n for (uint256 i = 0; i < _vestingRegistries.length; i++) {\n require(_vestingRegistries[i] != address(0), \"Vesting registry address invalid\");\n vestingRegistries.push(IVestingRegistry(_vestingRegistries[i]));\n }\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) external onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Internal function that sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings that were deployed in previous vesting registries\n * @dev migration of data from previous vesting registy contracts\n */\n function addDeployedVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingCreationTypes[i] > 0, \"vesting creation type must be greater than 0\");\n _addDeployedVestings(_tokenOwners[i], _vestingCreationTypes[i]);\n }\n }\n\n /**\n * @notice adds four year vestings to vesting registry logic\n * @param _tokenOwners array of token owners\n * @param _vestingAddresses array of vesting addresses\n */\n function addFourYearVestings(\n address[] calldata _tokenOwners,\n address[] calldata _vestingAddresses\n ) external onlyAuthorized {\n require(_tokenOwners.length == _vestingAddresses.length, \"arrays mismatch\");\n uint256 vestingCreationType = 4;\n uint256 cliff = 4 weeks;\n uint256 duration = 156 weeks;\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(!isVesting[_vestingAddresses[i]], \"vesting exists\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingAddresses[i] != address(0), \"vesting cannot be 0 address\");\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwners[i],\n uint256(VestingType.Vesting),\n cliff,\n duration,\n vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n vestingCreationType,\n _vestingAddresses[i]\n );\n vestingsOf[_tokenOwners[i]].push(uid);\n isVesting[_vestingAddresses[i]] = true;\n }\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @dev Calls a public createVestingAddr function with vestingCreationType. This is to accomodate the existing logic for LockedSOV\n * @dev vestingCreationType 0 = LockedSOV\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAuthorized {\n createVestingAddr(_tokenOwner, _amount, _cliff, _duration, 3);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createVestingAddr(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.Vesting),\n _vestingCreationType\n );\n\n emit VestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) external onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.TeamVesting),\n _vestingCreationType\n );\n\n emit TeamVestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) external onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n * @dev Calls a public getVestingAddr function with cliff and duration. This is to accomodate the existing logic for LockedSOV\n * @dev We need to use LockedSOV.changeRegistryCliffAndDuration function very judiciously\n * @dev vestingCreationType 0 - LockedSOV\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return getVestingAddr(_tokenOwner, lockedSOV.cliff(), lockedSOV.duration(), 3);\n }\n\n /**\n * @notice public function that returns vesting contract address for the given token owner, cliff, duration\n * @dev Important: Please use this instead of getVesting function\n */\n function getVestingAddr(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner, cliff, duration\n */\n function getTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @dev check if the specific vesting address is team vesting or not\n * @dev read the vestingType from vestingCreationAndTypes storage\n *\n * @param _vestingAddress address of vesting contract\n *\n * @return true for teamVesting, false for normal vesting\n */\n function isTeamVesting(address _vestingAddress) external view returns (bool) {\n return (vestingCreationAndTypes[_vestingAddress].isSet &&\n vestingCreationAndTypes[_vestingAddress].vestingType ==\n uint32(VestingType.TeamVesting));\n }\n\n /**\n * @dev setter function to register existing vesting contract to vestingCreationAndTypes storage\n * @dev need to set the function visilibty to public to support VestingCreationAndTypeDetails struct as parameter\n *\n * @param _vestingAddresses array of vesting address\n * @param _vestingCreationAndTypes array for VestingCreationAndTypeDetails struct\n */\n function registerVestingToVestingCreationAndTypes(\n address[] memory _vestingAddresses,\n VestingCreationAndTypeDetails[] memory _vestingCreationAndTypes\n ) public onlyAuthorized {\n require(_vestingAddresses.length == _vestingCreationAndTypes.length, \"Unmatched length\");\n for (uint256 i = 0; i < _vestingCreationAndTypes.length; i++) {\n VestingCreationAndTypeDetails memory _vestingCreationAndType =\n _vestingCreationAndTypes[i];\n address _vestingAddress = _vestingAddresses[i];\n\n vestingCreationAndTypes[_vestingAddress] = _vestingCreationAndType;\n\n emit VestingCreationAndTypesSet(\n _vestingAddress,\n vestingCreationAndTypes[_vestingAddress]\n );\n }\n }\n\n /**\n * @notice Internal function to deploy Vesting/Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _type the type of vesting\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _type,\n uint256 _vestingCreationType\n ) internal returns (address) {\n address vesting;\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, _type, _cliff, _duration, _vestingCreationType)\n )\n );\n if (vestings[uid].vestingAddress == address(0)) {\n if (_type == 1) {\n vesting = vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n } else {\n vesting = vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n }\n vestings[uid] = Vesting(_type, _vestingCreationType, vesting);\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vesting] = true;\n\n vestingCreationAndTypes[vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(_type),\n vestingCreationType: uint128(_vestingCreationType)\n });\n\n emit VestingCreationAndTypesSet(vesting, vestingCreationAndTypes[vesting]);\n }\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice stores the addresses of Vesting contracts from all three previous versions of Vesting Registry\n */\n function _addDeployedVestings(address _tokenOwner, uint256 _vestingCreationType) internal {\n uint256 uid;\n uint256 i = _vestingCreationType - 1;\n\n address vestingAddress = vestingRegistries[i].getVesting(_tokenOwner);\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.Vesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n _vestingCreationType,\n vestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vestingAddress] = true;\n }\n\n address teamVestingAddress = vestingRegistries[i].getTeamVesting(_tokenOwner);\n if (teamVestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(teamVestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.TeamVesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.TeamVesting),\n _vestingCreationType,\n teamVestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[teamVestingAddress] = true;\n }\n }\n\n /**\n * @notice returns all vesting details for the given token owner\n */\n function getVestingsOf(address _tokenOwner) external view returns (Vesting[] memory) {\n uint256[] memory vestingIds = vestingsOf[_tokenOwner];\n uint256 length = vestingIds.length;\n Vesting[] memory _vestings = new Vesting[](vestingIds.length);\n for (uint256 i = 0; i < length; i++) {\n _vestings[i] = vestings[vestingIds[i]];\n }\n return _vestings;\n }\n\n /**\n * @notice returns cliff and duration for Vesting & TeamVesting contracts\n */\n function getVestingDetails(address _vestingAddress)\n external\n view\n returns (uint256 cliff, uint256 duration)\n {\n VestingLogic vesting = VestingLogic(_vestingAddress);\n return (vesting.cliff(), vesting.duration());\n }\n\n /**\n * @notice returns if the address is a vesting address\n */\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return isVesting[_vestingAddress];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./VestingRegistryStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Vesting Registry Proxy contract.\n * @dev Vesting Registry contract should be upgradable, use UpgradableProxy.\n * VestingRegistryStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract VestingRegistryProxy is VestingRegistryStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Initializable.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"../../locked/LockedSOV.sol\";\nimport \"./IVestingRegistry.sol\";\n\n/**\n * @title Vesting Registry Storage Contract.\n *\n * @notice This contract is just the storage required for vesting registry.\n * It is parent of VestingRegistryProxy and VestingRegistryLogic.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\n\ncontract VestingRegistryStorage is Initializable, AdminRole {\n ///@notice the vesting factory contract\n IVestingFactory public vestingFactory;\n\n ///@notice the Locked SOV contract\n ILockedSOV public lockedSOV;\n\n ///@notice the list of vesting registries\n IVestingRegistry[] public vestingRegistries;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n\n ///@notice fee sharing proxy\n address public feeSharingCollector;\n\n ///@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n ///@notice Vesting details\n struct Vesting {\n uint256 vestingType;\n uint256 vestingCreationType;\n address vestingAddress;\n }\n\n ///@notice A record of vesting details for a unique id\n ///@dev vestings[uid] returns vesting data\n mapping(uint256 => Vesting) public vestings;\n\n ///@notice A record of all unique ids for a particular token owner\n ///@dev vestingsOf[tokenOwner] returns array of unique ids\n mapping(address => uint256[]) public vestingsOf;\n\n ///@notice A record of all vesting addresses\n ///@dev isVesting[address] returns if the address is a vesting address\n mapping(address => bool) public isVesting;\n\n /// @notice Store vesting creation type & vesting type information\n /// @dev it is packed into 1 single storage slot for cheaper gas usage\n struct VestingCreationAndTypeDetails {\n bool isSet;\n uint32 vestingType;\n uint128 vestingCreationType;\n }\n\n ///@notice A record of all vesting addresses with the detail\n ///@dev vestingDetail[vestingAddress] returns Vesting struct data\n ///@dev can be used to easily check the vesting type / creation type based on the vesting address itself\n mapping(address => VestingCreationAndTypeDetails) public vestingCreationAndTypes;\n}\n" + }, + "contracts/governance/Vesting/VestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\n\n/**\n * @title Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for vesting.\n * It is parent of VestingLogic and TeamVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract VestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public cliff;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 constant FOUR_WEEKS = 4 weeks;\n}\n" + }, + "contracts/interfaces/IChai.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IERC20.sol\";\n\ninterface IPot {\n function dsr() external view returns (uint256);\n\n function chi() external view returns (uint256);\n\n function rho() external view returns (uint256);\n}\n\ncontract IChai is IERC20 {\n function move(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function join(address dst, uint256 wad) external;\n\n function draw(address src, uint256 wad) external;\n\n function exit(address src, uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IConverterAMM.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IConverterAMM {\n function withdrawFees(address receiver) external returns (uint256);\n}\n" + }, + "contracts/interfaces/IERC20.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ncontract IERC20 {\n string public name;\n uint8 public decimals;\n string public symbol;\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address _who) external view returns (uint256);\n\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/interfaces/IERC777.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777Token standard as defined in the EIP.\n *\n * This contract uses the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let\n * token holders and recipients react to token movements by using setting implementers\n * for the associated interfaces in said registry. See {IERC1820Registry} and\n * {ERC1820Implementer}.\n */\ninterface IERC777 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the smallest part of the token that is not divisible. This\n * means all token operations (creation, movement and destruction) must have\n * amounts that are a multiple of this number.\n *\n * For most token contracts, this value will equal 1.\n */\n function granularity() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by an account (`owner`).\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * If send or receive hooks are registered for the caller and `recipient`,\n * the corresponding functions will be called with `data` and empty\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes calldata data\n ) external;\n\n /**\n * @dev Destroys `amount` tokens from the caller's account, reducing the\n * total supply.\n *\n * If a send hook is registered for the caller, the corresponding function\n * will be called with `data` and empty `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n */\n function burn(uint256 amount, bytes calldata data) external;\n\n /**\n * @dev Returns true if an account is an operator of `tokenHolder`.\n * Operators can send and burn tokens on behalf of their owners. All\n * accounts are their own operator.\n *\n * See {operatorSend} and {operatorBurn}.\n */\n function isOperatorFor(address operator, address tokenHolder) external view returns (bool);\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor}.\n *\n * Emits an {AuthorizedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function authorizeOperator(address operator) external;\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor} and {defaultOperators}.\n *\n * Emits a {RevokedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function revokeOperator(address operator) external;\n\n /**\n * @dev Returns the list of default operators. These accounts are operators\n * for all token holders, even if {authorizeOperator} was never called on\n * them.\n *\n * This list is immutable, but individual holders may revoke these via\n * {revokeOperator}, in which case {isOperatorFor} will return false.\n */\n function defaultOperators() external view returns (address[] memory);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must\n * be an operator of `sender`.\n *\n * If send or receive hooks are registered for `sender` and `recipient`,\n * the corresponding functions will be called with `data` and\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - `sender` cannot be the zero address.\n * - `sender` must have at least `amount` tokens.\n * - the caller must be an operator for `sender`.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n /**\n * @dev Destoys `amount` tokens from `account`, reducing the total supply.\n * The caller must be an operator of `account`.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `data` and `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n * - the caller must be an operator for `account`.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n event Sent(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Minted(\n address indexed operator,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Burned(\n address indexed operator,\n address indexed from,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event AuthorizedOperator(address indexed operator, address indexed tokenHolder);\n\n event RevokedOperator(address indexed operator, address indexed tokenHolder);\n}\n" + }, + "contracts/interfaces/IERC777Recipient.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.\n *\n * Accounts can be notified of {IERC777} tokens being sent to them by having a\n * contract implement this interface (contract holders can be their own\n * implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Recipient {\n /**\n * @dev Called by an {IERC777} token contract whenever tokens are being\n * moved or created into a registered account (`to`). The type of operation\n * is conveyed by `from` being the zero address or not.\n *\n * This call occurs _after_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the post-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/IERC777Sender.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensSender standard as defined in the EIP.\n *\n * {IERC777} Token holders can be notified of operations performed on their\n * tokens by having a contract implement this interface (contract holders can be\n * their own implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Sender {\n /**\n * @dev Called by an {IERC777} token contract whenever a registered holder's\n * (`from`) tokens are about to be moved or destroyed. The type of operation\n * is conveyed by `to` being the zero address or not.\n *\n * This call occurs _before_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the pre-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/ILoanPool.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface ILoanPool {\n function tokenPrice() external view returns (uint256 price);\n\n function borrowInterestRate() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/ILoanTokenModules.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\ninterface ILoanTokenModules {\n /** EVENT */\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /// topic: 0x9bbd2de400810774339120e2f8a2b517ed748595e944529bba8ebabf314d0591\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n\n /** INTERFACE */\n\n /** START LOAN TOKEN SETTINGS LOWER ADMIN */\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n\n function setAdmin(address _admin) external;\n\n function setPauser(address _pauser) external;\n\n function setupLoanParams(LoanParams[] calldata loanParamsList, bool areTorqueLoans) external;\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external;\n\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) external;\n\n function toggleFunctionPause(\n string calldata funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) external;\n\n function setTransactionLimits(address[] calldata addresses, uint256[] calldata limits)\n external;\n\n function changeLoanTokenNameAndSymbol(string calldata _name, string calldata _symbol) external;\n\n /** END LOAN TOKEN SETTINGS LOWER ADMIN */\n\n /** START LOAN TOKEN LOGIC STANDARD */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n address affiliateReferrer, // The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes // Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function borrowInterestRate() external view returns (uint256);\n\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n\n function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid);\n\n function checkPause(string calldata funcId) external view returns (bool isPaused);\n\n function nextBorrowInterestRate(uint256 borrowAmount) external view returns (uint256);\n\n function totalAssetBorrow() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes calldata /// loanDataBytes: arbitrary order data (for future use).\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n );\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function setLiquidityMiningAddress(address LMAddress) external;\n\n function getLiquidityMiningAddress() external view returns (address);\n\n function setStakingContractAddress(address _stakingContractAddress) external;\n\n function getStakingContractAddress() external view returns (address);\n\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n external\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n );\n\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 depositAmount);\n\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 borrowAmount);\n\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) external view;\n\n function getMaxEscrowAmount(uint256 leverageAmount)\n external\n view\n returns (uint256 maxEscrowAmount);\n\n function checkpointPrice(address _user) external view returns (uint256 price);\n\n function assetBalanceOf(address _owner) external view returns (uint256);\n\n function profitOf(address user) external view returns (int256);\n\n function tokenPrice() external view returns (uint256 price);\n\n function avgBorrowInterestRate() external view returns (uint256);\n\n function supplyInterestRate() external view returns (uint256);\n\n function nextSupplyInterestRate(uint256 supplyAmount) external view returns (uint256);\n\n function totalSupplyInterestRate(uint256 assetSupply) external view returns (uint256);\n\n function loanTokenAddress() external view returns (address);\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n external\n view\n returns (uint256, uint256);\n\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external;\n\n /** START LOAN TOKEN BASE */\n function initialPrice() external view returns (uint256);\n\n /** START LOAN TOKEN LOGIC LM */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external returns (uint256 minted);\n\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 redeemed);\n\n /** START LOAN TOKEN LOGIC WRBTC */\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n returns (uint256 mintAmount);\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n /** START LOAN TOKEN LOGIC STORAGE */\n function pauser() external view returns (address);\n\n function liquidityMiningAddress() external view returns (address);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n /** START ADVANCED TOKEN */\n function approve(address _spender, uint256 _value) external returns (bool);\n\n /** START ADVANCED TOKEN STORAGE */\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function balanceOf(address _owner) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function loanParamsIds(uint256) external view returns (bytes32);\n}\n" + }, + "contracts/interfaces/ISovryn.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\npragma experimental ABIEncoderV2;\n//TODO: stored in ./interfaces only while brownie isn't removed\n//TODO: move to contracts/interfaces after with brownie is removed\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\ncontract ISovryn is\n State,\n ProtocolSettingsEvents,\n LoanSettingsEvents,\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n LoanClosingsEvents,\n SwapsEvents,\n AffiliatesEvents,\n FeesEvents\n{\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n ////// Protocol //////\n\n function replaceContract(address target) external;\n\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\n\n function getTarget(string calldata sig) external view returns (address);\n\n ////// Protocol Settings //////\n\n function setSovrynProtocolAddress(address newProtocolAddress) external;\n\n function setSOVTokenAddress(address newSovTokenAddress) external;\n\n function setLockedSOVAddress(address newSOVLockedAddress) external;\n\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\n\n function setPriceFeedContract(address newContract) external;\n\n function setSwapsImplContract(address newContract) external;\n\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\n\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\n\n function setLendingFeePercent(uint256 newValue) external;\n\n function setTradingFeePercent(uint256 newValue) external;\n\n function setBorrowingFeePercent(uint256 newValue) external;\n\n function setSwapExternalFeePercent(uint256 newValue) external;\n\n function setAffiliateFeePercent(uint256 newValue) external;\n\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\n\n function setLiquidationIncentivePercent(uint256 newAmount) external;\n\n function setMaxDisagreement(uint256 newAmount) external;\n\n function setSourceBuffer(uint256 newAmount) external;\n\n function setMaxSwapSize(uint256 newAmount) external;\n\n function setFeesController(address newController) external;\n\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n returns (address, bool);\n\n function depositProtocolToken(uint256 amount) external;\n\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function setWrbtcToken(address wrbtcTokenAddress) external;\n\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\n\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\n\n function setRolloverBaseReward(uint256 transactionCost) external;\n\n function setRebatePercent(uint256 rebatePercent) external;\n\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external;\n\n function getSpecialRebates(address sourceToken, address destToken)\n external\n view\n returns (uint256 specialRebatesPercent);\n\n function togglePaused(bool paused) external;\n\n function isProtocolPaused() external view returns (bool);\n\n ////// Loan Settings //////\n\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function getLoanParams(bytes32[] calldata loanParamsIdList)\n external\n view\n returns (LoanParams[] memory loanParamsList);\n\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n\n ////// Loan Openings //////\n\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256);\n\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external;\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n ////// Loan Closings //////\n\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n );\n\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata loanDataBytes\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n ////// Loan Maintenance //////\n\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount // must match msg.value if ether is sent\n ) external payable;\n\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 actualWithdrawAmount);\n\n function extendLoanByInterest(\n bytes32 loanId,\n address payer,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata loanDataBytes\n ) external payable returns (uint256 secondsExtended);\n\n function reduceLoanByInterest(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 secondsReduced);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n );\n\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; // collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\n\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\n\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external;\n\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external;\n\n ////// Protocol Migration //////\n\n function setLegacyOracles(address[] calldata refs, address[] calldata oracles) external;\n\n function getLegacyOracle(address ref) external view returns (address);\n\n ////// Swaps External //////\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view;\n\n ////// Affiliates Module //////\n\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\n\n function setUserNotFirstTradeFlag(address user) external view returns (bool);\n\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\n\n function getReferralsList(address referrer) external view returns (address[] memory refList);\n\n function getAffiliatesReferrerBalances(address referrer)\n external\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\n\n function getAffiliatesReferrerTokensList(address referrer)\n external\n view\n returns (address[] memory tokensList);\n\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n external\n view\n returns (uint256);\n\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (uint256 withdrawAmount);\n\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\n\n function getProtocolAddress() external view returns (address);\n\n function getSovTokenAddress() external view returns (address);\n\n function getLockedSOVAddress() external view returns (address);\n\n function getFeeRebatePercent() external view returns (uint256);\n\n function getMinReferralsToPayout() external view returns (uint256);\n\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\n\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\n\n function getAffiliateTradingTokenFeePercent()\n external\n view\n returns (uint256 affiliateTradingTokenFeePercent);\n\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount);\n\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\n\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\n\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\n\n function getDedicatedSOVRebate() external view returns (uint256);\n\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\n\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory);\n\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\n\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external;\n\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\n\n function setAdmin(address newAdmin) external;\n\n function getAdmin() external view returns (address);\n\n function setPauser(address newPauser) external;\n\n function getPauser() external view returns (address);\n}\n" + }, + "contracts/interfaces/IWrbtc.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface IWrbtc {\n function deposit() external payable;\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IWrbtcERC20.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IWrbtc.sol\";\nimport \"./IERC20.sol\";\n\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\n" + }, + "contracts/locked/ILockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title The Locked SOV Interface.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This interface is an incomplete yet useful for future migration of LockedSOV Contract.\n * @dev Only use it if you know what you are doing.\n */\ninterface ILockedSOV {\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external;\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external;\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external;\n\n function cliff() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function getLockedBalance(address _addr) external view returns (uint256 _balance);\n\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance);\n}\n" + }, + "contracts/locked/LockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../governance/Vesting/VestingRegistry.sol\";\nimport \"../governance/Vesting/VestingLogic.sol\";\nimport \"./ILockedSOV.sol\";\n\n/**\n * @title The Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This contract is used to receive reward from other contracts, Create Vesting and Stake Tokens.\n */\ncontract LockedSOV is ILockedSOV {\n using SafeMath for uint256;\n\n uint256 public constant MAX_BASIS_POINT = 10000;\n uint256 public constant MAX_DURATION = 37;\n\n /* Storage */\n\n /// @notice True if the migration to a new Locked SOV Contract has started.\n bool public migration;\n\n /// @notice The cliff is the time period after which the tokens begin to unlock.\n uint256 public cliff;\n /// @notice The duration is the time period after all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n /// @notice The Vesting registry contract.\n VestingRegistry public vestingRegistry;\n /// @notice The New (Future) Locked SOV.\n ILockedSOV public newLockedSOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) private lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) private unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) private isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /// @notice Emitted when Vesting Registry, Duration and/or Cliff is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vestingRegistry The Vesting Registry Contract.\n /// @param _cliff The time period after which the tokens begin to unlock.\n /// @param _duration The time period after all tokens will have been unlocked.\n event RegistryCliffAndDurationUpdated(\n address indexed _initiator,\n address indexed _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n );\n\n /// @notice Emitted when a new deposit is made.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user to whose un/locked balance a new deposit was made.\n /// @param _sovAmount The amount of SOV to be added to the un/locked balance.\n /// @param _basisPoint The % (in Basis Point) which determines how much will be unlocked immediately.\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n /// @notice Emitted when a user withdraws the fund.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _sovAmount The amount of SOV withdrawn from the unlocked balance.\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n /// @notice Emitted when a user creates a vesting for himself.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _vesting The Vesting Contract.\n event VestingCreated(\n address indexed _initiator,\n address indexed _userAddress,\n address indexed _vesting\n );\n\n /// @notice Emitted when a user stakes tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vesting The Vesting Contract.\n /// @param _amount The amount of locked tokens staked by the user.\n event TokenStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /// @notice Emitted when an admin initiates a migration to new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedSOV The address of the new Locked SOV Contract.\n event MigrationStarted(address indexed _initiator, address indexed _newLockedSOV);\n\n /// @notice Emitted when a user initiates the transfer to a new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of locked tokens to transfer from this contract to the new one.\n event UserTransfered(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n modifier migrationAllowed {\n require(migration, \"Migration has not yet started.\");\n _;\n }\n\n /* Constructor */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV Token Address.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @param _admins The list of Admins to be added.\n */\n constructor(\n address _SOV,\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration,\n address[] memory _admins\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_vestingRegistry != address(0), \"Vesting registry address is invalid.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n SOV = IERC20(_SOV);\n vestingRegistry = VestingRegistry(_vestingRegistry);\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /* Public or External Functions */\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n * @dev Only callable by an Admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address.\");\n require(!isAdmin[_newAdmin], \"Address is already admin.\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n * @dev Only callable by an Admin.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin.\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice The function to update the Vesting Registry, Duration and Cliff.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @dev IMPORTANT 1: You have to change Vesting Registry if you want to change Duration and/or Cliff.\n * IMPORTANT 2: `_cliff` and `_duration` is multiplied by 4 weeks in this function.\n */\n function changeRegistryCliffAndDuration(\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAdmin {\n require(\n address(vestingRegistry) != _vestingRegistry,\n \"Vesting Registry has to be different for changing duration and cliff.\"\n );\n /// If duration is also zero, then it is similar to Unlocked SOV.\n require(_duration != 0, \"Duration cannot be zero.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n vestingRegistry = VestingRegistry(_vestingRegistry);\n\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n emit RegistryCliffAndDurationUpdated(msg.sender, _vestingRegistry, _cliff, _duration);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // MAX_BASIS_POINT is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < MAX_BASIS_POINT, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(MAX_BASIS_POINT);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice A function to withdraw the unlocked balance.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdraw(address _receiverAddress) public {\n _withdraw(msg.sender, _receiverAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n /**\n * @notice Creates vesting if not already created and Stakes tokens for a user.\n * @dev Only use this function if the `duration` is small.\n */\n function createVestingAndStake() public {\n _createVestingAndStake(msg.sender);\n }\n\n function _createVestingAndStake(address _sender) private {\n address vestingAddr = _getVesting(_sender);\n\n if (vestingAddr == address(0)) {\n vestingAddr = _createVesting(_sender);\n }\n\n _stakeTokens(_sender, vestingAddr);\n }\n\n /**\n * @notice Creates vesting contract (if it hasn't been created yet) for the calling user.\n * @return _vestingAddress The New Vesting Contract Created.\n */\n function createVesting() public returns (address _vestingAddress) {\n _vestingAddress = _createVesting(msg.sender);\n }\n\n /**\n * @notice Stakes tokens for a user who already have a vesting created.\n * @dev The user should already have a vesting created, else this function will throw error.\n */\n function stakeTokens() public {\n VestingLogic vesting = VestingLogic(_getVesting(msg.sender));\n\n require(\n cliff == vesting.cliff() && duration == vesting.duration(),\n \"Wrong Vesting Schedule.\"\n );\n\n _stakeTokens(msg.sender, address(vesting));\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdrawAndStakeTokens(address _receiverAddress) external {\n _withdraw(msg.sender, _receiverAddress);\n _createVestingAndStake(msg.sender);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n /**\n * @notice Function to start the process of migration to new contract.\n * @param _newLockedSOV The new locked sov contract address.\n */\n function startMigration(address _newLockedSOV) external onlyAdmin {\n require(_newLockedSOV != address(0), \"New Locked SOV Address is Invalid.\");\n newLockedSOV = ILockedSOV(_newLockedSOV);\n SOV.approve(_newLockedSOV, SOV.balanceOf(address(this)));\n migration = true;\n\n emit MigrationStarted(msg.sender, _newLockedSOV);\n }\n\n /**\n * @notice Function to transfer the locked balance from this contract to new LockedSOV Contract.\n * @dev Address is not specified to discourage selling lockedSOV to other address.\n */\n function transfer() external migrationAllowed {\n uint256 amount = lockedBalances[msg.sender];\n lockedBalances[msg.sender] = 0;\n\n newLockedSOV.depositSOV(msg.sender, amount);\n\n emit UserTransfered(msg.sender, amount);\n }\n\n /* Internal Functions */\n\n /**\n * @notice Creates a Vesting Contract for a user.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n * @dev Does not do anything if Vesting Contract was already created.\n */\n function _createVesting(address _tokenOwner) internal returns (address _vestingAddress) {\n /// Here zero is given in place of amount, as amount is not really used in `vestingRegistry.createVesting()`.\n vestingRegistry.createVesting(_tokenOwner, 0, cliff, duration);\n _vestingAddress = _getVesting(_tokenOwner);\n emit VestingCreated(msg.sender, _tokenOwner, _vestingAddress);\n }\n\n /**\n * @notice Returns the Vesting Contract Address.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n */\n function _getVesting(address _tokenOwner) internal view returns (address _vestingAddress) {\n return vestingRegistry.getVesting(_tokenOwner);\n }\n\n /**\n * @notice Stakes the tokens in a particular vesting contract.\n * @param _vesting The Vesting Contract Address.\n */\n function _stakeTokens(address _sender, address _vesting) internal {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n require(SOV.approve(_vesting, amount), \"Approve failed.\");\n VestingLogic(_vesting).stakeTokens(amount);\n\n emit TokenStaked(_sender, _vesting, amount);\n }\n\n /* Getter or Read Functions */\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) external view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n\n /**\n * @notice The function to check is an address is admin or not.\n * @param _addr The address of the user to check the admin status.\n * @return _status True if admin, False otherwise.\n */\n function adminStatus(address _addr) external view returns (bool _status) {\n return isAdmin[_addr];\n }\n}\n" + }, + "contracts/mixins/EnumerableAddressSet.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Based on Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * As of v2.5.0, only `address` sets are supported.\n *\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\n *\n * _Available since v2.5.0._\n */\nlibrary EnumerableAddressSet {\n struct AddressSet {\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(address => uint256) index;\n address[] values;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n * Returns false if the value was already in the set.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n * Returns false if the value was not present in the set.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n // If the element we're deleting is the last one, we can just remove it without doing a swap\n if (lastIndex != toDeleteIndex) {\n address lastValue = set.values[lastIndex];\n\n // Move the last value to the index where the deleted value is\n set.values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n // Delete the index entry for the deleted value\n delete set.index[value];\n\n // Delete the old entry for the moved value\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns an array with all values in the set. O(N).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\n address[] memory output = new address[](set.values.length);\n for (uint256 i; i < set.values.length; i++) {\n output[i] = set.values[i];\n }\n return output;\n }\n\n /**\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n \n * @param start start index of chunk\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\n */\n function enumerateChunk(\n AddressSet storage set,\n uint256 start,\n uint256 count\n ) internal view returns (address[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = (set.values.length < end || count == 0) ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new address[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @dev Returns the number of elements on the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /** @dev Returns the element stored at position `index` in the set. O(1).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes32Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\n * */\nlibrary EnumerableBytes32Set {\n struct Bytes32Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes32 => uint256) index;\n bytes32[] values;\n }\n\n /**\n * @notice Add an address value to a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to add.\n *\n * @return False if the value was already in the set.\n */\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return addBytes32(set, value);\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove an address value from a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to remove.\n *\n * @return False if the address was not present in the set.\n */\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return removeBytes32(set, value);\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function containsAddress(Bytes32Set storage set, address addrvalue)\n internal\n view\n returns (bool)\n {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes32Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes32[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes32[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes4Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`.\n * */\nlibrary EnumerableBytes4Set {\n struct Bytes4Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes4 => uint256) index;\n bytes4[] values;\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes4 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes4Set storage set, bytes4 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes4Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes4[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes4[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes4Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes4Set storage set, uint256 index) internal view returns (bytes4) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/FeesHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ISovryn.sol\";\nimport \"../core/objects/LoanParamsStruct.sol\";\n\n/**\n * @title The Fees Helper contract.\n *\n * This contract calculates and pays lending/borrow fees and rewards.\n * */\ncontract FeesHelper is State, FeesEvents {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Calculate trading fee.\n * @param feeTokenAmount The amount of tokens to trade.\n * @return The fee of the trade.\n * */\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\n }\n\n /**\n * @notice Calculate swap external fee.\n * @param feeTokenAmount The amount of token to swap.\n * @return The fee of the swap.\n */\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\n }\n\n /*\n\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - tradingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);\n\t}*/\n\n /**\n * @notice Calculate the loan origination fee.\n * @param feeTokenAmount The amount of tokens to borrow.\n * @return The fee of the loan.\n * */\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\n /*\n\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - borrowingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);*/\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\n *\n * @param referrer The affiliate referrer address to send the reward to.\n * @param trader The account that performs this trade.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n *\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\n * */\n function _payTradingFeeToAffiliate(\n address referrer,\n address trader,\n address feeToken,\n uint256 tradingFee\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\n address(this)\n )\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n * */\n function _payTradingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 tradingFee\n ) internal {\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\n if (tradingFee != 0) {\n if (affiliatesUserReferrer[user] != address(0)) {\n _payTradingFeeToAffiliate(\n affiliatesUserReferrer[user],\n user,\n feeToken,\n protocolTradingFee\n );\n protocolTradingFee = (\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\n )\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\n }\n\n /// Increase the storage variable keeping track of the accumulated fees.\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\n protocolTradingFee\n );\n\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\n }\n }\n\n /**\n * @notice Settle the borrowing fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the borrowig fee is paid.\n * @param borrowingFee The height of the fee.\n * */\n function _payBorrowingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 borrowingFee\n ) internal {\n if (borrowingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\n\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\n }\n }\n\n /**\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\n * @param user The address to send the reward to.\n * @param feeToken The address of the token in which the lending fee is paid.\n * @param lendingFee The height of the fee.\n * */\n function _payLendingFee(\n address user,\n address feeToken,\n uint256 lendingFee\n ) internal {\n if (lendingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\n\n emit PayLendingFee(user, feeToken, lendingFee);\n\n //// NOTE: Lenders do not receive a fee reward ////\n }\n }\n\n /// Settle and pay borrowers based on the fees generated by their interest payments.\n function _settleFeeRewardForInterestExpense(\n LoanInterest storage loanInterestLocal,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n address user,\n uint256 interestTime\n ) internal {\n /// This represents the fee generated by a borrower's interest payment.\n uint256 interestExpenseFee =\n interestTime\n .sub(loanInterestLocal.updatedTimestamp)\n .mul(loanInterestLocal.owedPerDay)\n .mul(lendingFeePercent)\n .div(1 days * 10**20);\n\n loanInterestLocal.updatedTimestamp = interestTime;\n\n if (interestExpenseFee != 0) {\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\n }\n }\n\n /**\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associeated loan - used for logging only.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * */\n function _payFeeReward(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 feeAmount\n ) internal {\n uint256 rewardAmount;\n uint256 _feeRebatePercent = feeRebatePercent;\n address _priceFeeds = priceFeeds;\n\n if (specialRebates[feeToken][feeTokenPair] > 0) {\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\n }\n\n /// Note: this should be refactored.\n /// Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\n feeAmount.mul(_feeRebatePercent).div(10**20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n // Check the dedicated SOV that is used to pay trading rebate rewards\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"deposit(address,uint256,uint256)\",\n user,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n )\n );\n\n if (success) {\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\n\n emit EarnReward(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n } else {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n }\n}\n" + }, + "contracts/mixins/InterestUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"./FeesHelper.sol\";\n\n/**\n * @title The Interest User contract.\n *\n * This contract pays loan interests.\n * */\ncontract InterestUser is VaultController, FeesHelper {\n using SafeERC20 for IERC20;\n\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n /**\n * @notice Internal function to pay interest of a loan.\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * */\n function _payInterest(address lender, address interestToken) internal {\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\n\n uint256 interestOwedNow = 0;\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\n interestOwedNow = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(1 days);\n\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n\n if (interestOwedNow > lenderInterestLocal.owedTotal)\n interestOwedNow = lenderInterestLocal.owedTotal;\n\n if (interestOwedNow != 0) {\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\n\n _payInterestTransfer(lender, interestToken, interestOwedNow);\n }\n } else {\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n }\n }\n\n /**\n * @notice Internal function to transfer tokens for the interest of a loan.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * @param interestOwedNow The amount of interest to pay.\n * */\n function _payInterestTransfer(\n address lender,\n address interestToken,\n uint256 interestOwedNow\n ) internal {\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\n /// TODO: refactor: data incapsulation violation and DRY design principles\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\n\n _payLendingFee(lender, interestToken, lendingFee);\n\n /// Transfers the interest to the lender, less the interest fee.\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\n\n /// Event Log\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\n }\n}\n" + }, + "contracts/mixins/LiquidationHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\n/**\n * @title The Liquidation Helper contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract computes the liquidation amount.\n * */\ncontract LiquidationHelper is State {\n /**\n * @notice Compute how much needs to be liquidated in order to restore the\n * desired margin (maintenance + 5%).\n *\n * @param principal The total borrowed amount (in loan tokens).\n * @param collateral The collateral (in collateral tokens).\n * @param currentMargin The current margin.\n * @param maintenanceMargin The maintenance (minimum) margin.\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n *\n * @return maxLiquidatable The collateral you can get liquidating.\n * @return maxSeizable The loan you available for liquidation.\n * @return incentivePercent The discount on collateral.\n * */\n function _getLiquidationAmounts(\n uint256 principal,\n uint256 collateral,\n uint256 currentMargin,\n uint256 maintenanceMargin,\n uint256 collateralToLoanRate\n )\n internal\n view\n returns (\n uint256 maxLiquidatable,\n uint256 maxSeizable,\n uint256 incentivePercent\n )\n {\n incentivePercent = liquidationIncentivePercent;\n if (currentMargin > maintenanceMargin || collateralToLoanRate == 0) {\n return (maxLiquidatable, maxSeizable, incentivePercent);\n } else if (currentMargin <= incentivePercent) {\n return (principal, collateral, currentMargin);\n }\n\n /// 5 percentage points above maintenance.\n uint256 desiredMargin = maintenanceMargin.add(5 ether);\n\n /// maxLiquidatable = ((1 + desiredMargin)*principal - collateralToLoanRate*collateral) / (desiredMargin - 0.05)\n maxLiquidatable = desiredMargin.add(10**20).mul(principal).div(10**20);\n maxLiquidatable = maxLiquidatable.sub(collateral.mul(collateralToLoanRate).div(10**18));\n maxLiquidatable = maxLiquidatable.mul(10**20).div(desiredMargin.sub(incentivePercent));\n if (maxLiquidatable > principal) {\n maxLiquidatable = principal;\n }\n\n /// maxSeizable = maxLiquidatable * (1 + incentivePercent) / collateralToLoanRate\n maxSeizable = maxLiquidatable.mul(incentivePercent.add(10**20));\n maxSeizable = maxSeizable.div(collateralToLoanRate).div(100);\n if (maxSeizable > collateral) {\n maxSeizable = collateral;\n }\n\n return (maxLiquidatable, maxSeizable, incentivePercent);\n }\n}\n" + }, + "contracts/mixins/ModuleCommonFunctionalities.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\ncontract ModuleCommonFunctionalities is State {\n modifier whenNotPaused() {\n require(!pause, \"Paused\");\n _;\n }\n}\n" + }, + "contracts/mixins/ProtocolTokenUser.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\n\n/**\n * @title The Protocol Token User contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to withdraw protocol tokens.\n * */\ncontract ProtocolTokenUser is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Internal function to withdraw an amount of protocol tokens from this contract.\n *\n * @param receiver The address of the recipient.\n * @param amount The amount of tokens to withdraw.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function _withdrawProtocolToken(address receiver, uint256 amount)\n internal\n returns (address, bool)\n {\n uint256 withdrawAmount = amount;\n\n uint256 tokenBalance = protocolTokenHeld;\n if (withdrawAmount > tokenBalance) {\n withdrawAmount = tokenBalance;\n }\n if (withdrawAmount == 0) {\n return (protocolTokenAddress, false);\n }\n\n protocolTokenHeld = tokenBalance.sub(withdrawAmount);\n\n IERC20(protocolTokenAddress).safeTransfer(receiver, withdrawAmount);\n\n return (protocolTokenAddress, true);\n }\n}\n" + }, + "contracts/mixins/RewardHelper.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title The Reward Helper contract.\n * @notice This contract calculates the reward for rollover transactions.\n *\n * A rollover is a renewal of a deposit. Instead of liquidating a deposit\n * on maturity, you can roll it over into a new deposit. The outstanding\n * principal of the old deposit is rolled over with or without the interest\n * outstanding on it.\n * */\ncontract RewardHelper is State {\n using SafeMath for uint256;\n\n /**\n * @notice Calculate the reward of a rollover transaction.\n *\n * @param collateralToken The address of the collateral token.\n * @param loanToken The address of the loan token.\n * @param positionSize The amount of value of the position.\n *\n * @return The base fee + the flex fee.\n */\n function _getRolloverReward(\n address collateralToken,\n address loanToken,\n uint256 positionSize\n ) internal view returns (uint256 reward) {\n uint256 positionSizeInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(loanToken, collateralToken, positionSize);\n uint256 rolloverBaseRewardInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(\n address(wrbtcToken),\n collateralToken,\n rolloverBaseReward\n );\n\n return\n rolloverBaseRewardInCollateralToken\n .mul(2) /// baseFee\n .add(positionSizeInCollateralToken.mul(rolloverFlexFeePercent).div(10**20)); /// flexFee = 0.1% of position size\n }\n}\n" + }, + "contracts/mixins/VaultController.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\n\n/**\n * @title The Vault Controller contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to deposit and withdraw wrBTC and\n * other tokens from the vault.\n * */\ncontract VaultController is State {\n using SafeERC20 for IERC20;\n\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\n\n /**\n * @notice Deposit wrBTC into the vault.\n *\n * @param from The address of the account paying the deposit.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherDeposit(address from, uint256 value) internal {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n _wrbtcToken.deposit.value(value)();\n\n emit VaultDeposit(address(_wrbtcToken), from, value);\n }\n\n /**\n * @notice Withdraw wrBTC from the vault.\n *\n * @param to The address of the recipient.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherWithdraw(address to, uint256 value) internal {\n if (value != 0) {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n uint256 balance = address(this).balance;\n if (value > balance) {\n _wrbtcToken.withdraw(value - balance);\n }\n Address.sendValue(to, value);\n\n emit VaultWithdraw(address(_wrbtcToken), to, value);\n }\n }\n\n /**\n * @notice Deposit tokens into the vault.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying the deposit.\n * @param value The amount of tokens to transfer.\n */\n function vaultDeposit(\n address token,\n address from,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransferFrom(from, address(this), value);\n\n emit VaultDeposit(token, from, value);\n }\n }\n\n /**\n * @notice Withdraw tokens from the vault.\n *\n * @param token The address of the token instance.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultWithdraw(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransfer(to, value);\n\n emit VaultWithdraw(token, to, value);\n }\n }\n\n /**\n * @notice Transfer tokens from an account into another one.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultTransfer(\n address token,\n address from,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n if (from == address(this)) {\n IERC20(token).safeTransfer(to, value);\n } else {\n IERC20(token).safeTransferFrom(from, to, value);\n }\n }\n }\n\n /**\n * @notice Approve an allowance of tokens to be spent by an account.\n *\n * @param token The address of the token instance.\n * @param to The address of the spender.\n * @param value The amount of tokens to allow.\n */\n function vaultApprove(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\n IERC20(token).safeApprove(to, 0);\n }\n IERC20(token).safeApprove(to, value);\n }\n}\n" + }, + "contracts/mockup/BlockMockUp.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title Used to get and set mock block number.\n */\ncontract BlockMockUp {\n uint256 public blockNum;\n\n /**\n * @notice To get the `blockNum`.\n * @return _blockNum The block number.\n */\n function getBlockNum() public view returns (uint256 _blockNum) {\n return blockNum;\n }\n\n /**\n * @notice To set the `blockNum`.\n * @param _blockNum The block number.\n */\n function setBlockNum(uint256 _blockNum) public {\n blockNum = _blockNum;\n }\n}\n" + }, + "contracts/mockup/FeeSharingCollectorMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/FeeSharingCollector/FeeSharingCollector.sol\";\n\ncontract FeeSharingCollectorMockup is FeeSharingCollector {\n struct TestData {\n address loanPoolToken;\n uint32 maxCheckpoints;\n address receiver;\n }\n\n TestData public testData;\n\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n testData = TestData(_token, _maxCheckpoints, _receiver);\n }\n\n function trueWithdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function addCheckPoint(address loanPoolToken, uint256 poolTokenAmount) public {\n uint96 amount96 =\n safe96(\n poolTokenAmount,\n \"FeeSharingCollectorProxy::withdrawFees: pool token amount exceeds 96 bits\"\n );\n _addCheckpoint(loanPoolToken, amount96);\n }\n\n function setTotalTokenCheckpoints(address _token, uint256 qty) public {\n totalTokenCheckpoints[_token] = qty;\n }\n\n function setUserProcessedCheckpoints(\n address _user,\n address _token,\n uint256 num\n ) public {\n processedCheckpoints[_user][_token] = num;\n }\n\n function getFullAccumulatedFees(\n address _user,\n address _token,\n uint32 _maxCheckpoints\n ) public view returns (uint256 amount, uint256 end) {\n (amount, end) = _getAccumulatedFees(_user, _token, 0, _maxCheckpoints);\n }\n\n function endOfRangeWithZeroMaxCheckpoint(address _token) public view returns (uint256) {\n return _getEndOfRange(0, _token, 0);\n }\n\n function getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) public view returns (uint256 _tokenAmount, uint256 _endToken) {\n return _getRBTCBalance(_token, _user, _maxCheckpoints);\n }\n\n function testWithdrawReentrancy(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n}\n" + }, + "contracts/mockup/GovernorAlphaMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/GovernorAlpha.sol\";\n\ncontract GovernorAlphaMockup is GovernorAlpha {\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 quorumVotes_,\n uint96 _minPercentageVotes\n ) public GovernorAlpha(timelock_, staking_, guardian_, quorumVotes_, _minPercentageVotes) {}\n\n function votingPeriod() public pure returns (uint256) {\n return 10;\n }\n\n function queueProposals(uint256[] calldata proposalIds) external {\n for (uint256 i = 0; i < proposalIds.length; i++) {\n queue(proposalIds[i]);\n }\n }\n}\n" + }, + "contracts/mockup/LiquidityMiningMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract LiquidityMiningMockup is LiquidityMining {\n function getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n public\n view\n returns (uint256)\n {\n return _getPassedBlocksWithBonusMultiplier(_from, _to);\n }\n\n function getPoolAccumulatedReward(address _poolToken) public view returns (uint256, uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n return _getPoolAccumulatedReward(pool);\n }\n}\n" + }, + "contracts/mockup/LiquidityPoolV1ConverterMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/IERC20.sol\";\n\ncontract LiquidityPoolV1ConverterMockup {\n IERC20[] public reserveTokens;\n IERC20 wrbtcToken;\n uint256 totalFeeMockupValue;\n address feesController;\n\n constructor(IERC20 _token0, IERC20 _token1) public {\n reserveTokens.push(_token0);\n reserveTokens.push(_token1);\n }\n\n function setFeesController(address _feesController) public {\n feesController = _feesController;\n }\n\n function setWrbtcToken(IERC20 _wrbtcToken) public {\n wrbtcToken = _wrbtcToken;\n }\n\n function setTotalFeeMockupValue(uint256 _totalFeeMockupValue) public {\n totalFeeMockupValue = _totalFeeMockupValue;\n }\n\n function withdrawFees(address _receiver) external returns (uint256) {\n require(msg.sender == feesController, \"unauthorized\");\n\n // transfer wrbtc\n wrbtcToken.transfer(_receiver, totalFeeMockupValue);\n return totalFeeMockupValue;\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/LoanClosingsWith.sol\";\n\ncontract LoanClosingsWithMockup is LoanClosingsWith {\n function worthTheTransfer(address, uint256) internal returns (bool) {\n return true;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithoutInvariantCheck.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanClosingsWithMockup.sol\";\n\ncontract LoanClosingsWithoutInvariantCheck is LoanClosingsWithMockup {\n /** Override the modifier of invariant check so that we can test the shared reentrancy guard */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n _;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicLMMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\n\ncontract LoanTokenLogicLMMockup is LoanTokenLogicLM {\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n returns (uint256 loanAmountPaid)\n {\n _callOptionalReturn(\n 0x2c34D66a5ca8686330e100372Eb3FDFB5aEECD0B, //Random EOA for testing\n abi.encodeWithSelector(IERC20(receiver).transfer.selector, receiver, burnAmount),\n \"error\"\n );\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicV2Mockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicV1Mockup is LoanTokenLogicStandard {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](27);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n // res[31] = this.totalSupply.selector;\n res[25] = this.balanceOf.selector;\n res[26] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n\ncontract LoanTokenLogicV2Mockup is LoanTokenLogicStandard {\n function testNewFunction() external pure returns (bool) {\n return true;\n }\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](29);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mockup\n res[28] = this.testNewFunction.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/mockup/lockedSOVFailedMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An interface for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete interface of the Locked SOV Contract.\n */\ncontract LockedSOVFailedMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The user balances.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n revert(\"For testing purposes\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/LockedSOVMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An mockup for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete mockup of the Locked SOV Contract.\n */\ncontract LockedSOVMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n event TokensStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // 10000 is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < 10000, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(10000);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n function _createVestingAndStake(address _sender) private {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n emit TokensStaked(_sender, address(0), amount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/MockAffiliates.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/Affiliates.sol\";\n\ncontract MockAffiliates is Affiliates {\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n }\n}\n" + }, + "contracts/mockup/MockFourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/Vesting/fouryear/FourYearVestingLogic.sol\";\n\ncontract MockFourYearVestingLogic is FourYearVestingLogic {\n /**\n * @notice gets duration left\n */\n function getDurationLeft() external view returns (uint256) {\n return durationLeft;\n }\n}\n" + }, + "contracts/mockup/MockLoanTokenLogic.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogic is LoanTokenLogic {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](31);\n\n // Loan Token Logic\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mock\n res[28] = this.setAffiliatesReferrer.selector;\n res[29] = this.setUserNotFirstTradeFlag.selector;\n res[30] = this.getMarginBorrowAmountAndRate.selector;\n\n return (res, stringToBytes32(\"MockLoanTokenLogic\"));\n }\n\n function setAffiliatesReferrer(address user, address referrer) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(user, referrer);\n }\n\n function setUserNotFirstTradeFlag(address user) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(user);\n }\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n\n /*function initialize(address target) external onlyOwner {\n\t\t_setTarget(this.setAffiliatesUserReferrer.selector, target);\n\t}*/\n}\n\ncontract ILoanTokenModulesMock is ILoanTokenModules {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user) external;\n}\n" + }, + "contracts/mockup/MockLoanTokenLogicLM.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogicLM is LoanTokenLogicLM {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n /** LoanTokenLogicLM function signature */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\"));\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\"));\n res[2] = bytes4(keccak256(\"burn(address,uint256)\"));\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\"));\n\n return (res, stringToBytes32(\"MockLoanTokenLogicLM\"));\n }\n}\n" + }, + "contracts/mockup/modules/IWeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract IWeightedStakingModuleMockup {\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) external;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) external;\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external;\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) external;\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/mockup/modules/StakingModuleBlockMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/StakingGovernanceModule.sol\";\nimport \"../../governance/Staking/modules/StakingStakeModule.sol\";\nimport \"../../governance/Staking/modules/StakingVestingModule.sol\";\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../BlockMockUp.sol\";\n\ncontract StakingModuleBlockMockup is\n IFunctionsList,\n StakingGovernanceModule,\n StakingStakeModule,\n StakingVestingModule,\n WeightedStakingModule\n{\n uint96 public priorWeightedStake;\n mapping(uint256 => uint96) public priorWeightedStakeAtBlock;\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n function balanceOf_MultipliedByTwo(address account) external view returns (uint256) {\n return this.balanceOf(account) * 2;\n }\n\n uint96 priorTotalVotingPower;\n\n function MOCK_priorTotalVotingPower(uint96 _priorTotalVotingPower) public {\n priorTotalVotingPower = _priorTotalVotingPower;\n }\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n return\n priorTotalVotingPower != 0\n ? priorTotalVotingPower\n : super.getPriorTotalVotingPower(blockNumber, time);\n }\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) public view returns (bool) {\n bytes32 codeHash = _getCodeHash(stakerAddress);\n return vestingCodeHashes[codeHash];\n }\n\n function getPriorWeightedStakeAtBlock(uint256 blockNum) public view returns (uint256) {\n return uint256(priorWeightedStakeAtBlock[blockNum]);\n }\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n // StakingGovernanceModule\n bytes4[] memory functionsList = new bytes4[](31);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n\n // StakingStakeModule\n functionsList[6] = this.stake.selector;\n functionsList[7] = this.stakeWithApproval.selector;\n functionsList[8] = this.extendStakingDuration.selector;\n functionsList[9] = this.stakesBySchedule.selector;\n functionsList[10] = this.stakeBySchedule.selector;\n functionsList[11] = this.balanceOf.selector;\n functionsList[12] = this.getCurrentStakedUntil.selector;\n functionsList[13] = this.getStakes.selector;\n functionsList[14] = this.timestampToLockDate.selector;\n\n //StakingVestingModule\n functionsList[15] = this.setVestingRegistry.selector;\n functionsList[16] = this.setVestingStakes.selector;\n functionsList[17] = this.getPriorUserStakeByDate.selector;\n functionsList[18] = this.getPriorVestingWeightedStake.selector;\n functionsList[19] = this.getPriorVestingStakeByDate.selector;\n functionsList[20] = this.addContractCodeHash.selector;\n functionsList[21] = this.removeContractCodeHash.selector;\n functionsList[22] = this.isVestingContract.selector;\n\n //BlockMockup\n functionsList[23] = this.setBlockMockUpAddr.selector;\n functionsList[24] = this.MOCK_priorWeightedStake.selector;\n functionsList[25] = this.MOCK_priorWeightedStakeAtBlock.selector;\n\n //WeightedStakingModule\n functionsList[26] = this.getPriorWeightedStake.selector;\n functionsList[27] = this.weightedStakeByDate.selector;\n functionsList[28] = this.computeWeightByDate.selector;\n functionsList[29] = this.priorWeightedStakeAtBlock.selector;\n functionsList[30] = this.getPriorWeightedStakeAtBlock.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/modules/StakingSharedModuleMock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/shared/StakingShared.sol\";\nimport \"../BlockMockUp.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\n\ncontract StakingModuleMock is IFunctionsList, StakingShared {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](1);\n functionList[0] = this.setBlockMockUpAddr.selector;\n }\n}\n" + }, + "contracts/mockup/modules/StakingWrapperMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\ncontract StakingWrapperMockup {\n uint256 constant TWO_WEEKS = 1209600;\n\n IStaking staking;\n IERC20 token;\n\n constructor(IStaking _staking, IERC20 _token) public {\n staking = _staking;\n token = _token;\n }\n\n function stake2times(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stake(amount, until, stakeFor, delegatee);\n }\n\n function stakeAndExtend(uint96 amount, uint256 until) external {\n require(token.transferFrom(msg.sender, address(this), amount));\n token.approve(address(staking), amount);\n\n staking.stake(amount, until, address(this), address(this));\n staking.extendStakingDuration(until, until + TWO_WEEKS);\n }\n\n function stakeAndStakeBySchedule(\n uint96 amount,\n uint256 until,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n}\n" + }, + "contracts/mockup/modules/WeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract WeightedStakingModuleMockup is WeightedStakingModule {\n uint96 priorWeightedStake;\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n mapping(uint256 => uint96) priorWeightedStakeAtBlock;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n functionsList[3] = this.MOCK_priorWeightedStake.selector;\n functionsList[4] = this.MOCK_priorWeightedStakeAtBlock.selector;\n functionsList[5] = this.calculatePriorWeightedStake.selector;\n functionsList[6] = this.setDelegateStake.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n//@todo can I change this proxy to EIP-1822 proxy standard, please. https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\ncontract PreviousLoanToken is AdvancedTokenStorage {\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../connectors/loantoken/interfaces/ProtocolSettingsLike.sol\";\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n// It is a LoanToken implementation!\ncontract PreviousLoanTokenSettingsLowerAdmin is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress\n\n // ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n // ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n //@todo check for restrictions in this contract\n modifier onlyAdmin() {\n require(msg.sender == address(this) || msg.sender == owner(), \"unauthorized\");\n _;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function init(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans // isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n // These params should be percentages represented like so: 5% = 5000000000000000000\n // rateMultiplier + baseRate can't exceed 100%\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; // 80 ether\n kinkLevel = _kinkLevel; // 90 ether\n maxScaleRate = _maxScaleRate; // 100 ether\n }\n\n function toggleFunctionPause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyAdmin {\n // keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /**\n * sets the transaction limit per token address\n * @param addresses the token addresses\n * @param limits the limit denominated in the currency of the token address\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyOwner\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n}\n" + }, + "contracts/mockup/PriceFeedsMoCMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../feeds/testnet/PriceFeedsMoC.sol\";\n\n// This contract is only for test purposes\n// https://github.com/money-on-chain/Amphiraos-Oracle/blob/master/contracts/medianizer/medianizer.sol\ncontract PriceFeedsMoCMockup is Medianizer {\n uint256 public value;\n bool public has;\n\n function peek() external view returns (bytes32, bool) {\n return (bytes32(value), has);\n }\n\n function setValue(uint256 _value) public {\n value = _value;\n }\n\n function setHas(bool _has) public {\n has = _has;\n }\n}\n" + }, + "contracts/mockup/ProtocolSettingsMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/ProtocolSettings.sol\";\n\ncontract ProtocolSettingsMockup is ProtocolSettings {\n function setLendingFeeTokensHeld(address token, uint256 amout) public {\n lendingFeeTokensHeld[token] = amout;\n }\n\n function setTradingFeeTokensHeld(address token, uint256 amout) public {\n tradingFeeTokensHeld[token] = amout;\n }\n\n function setBorrowingFeeTokensHeld(address token, uint256 amout) public {\n borrowingFeeTokensHeld[token] = amout;\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n\n _setTarget(this.setLendingFeeTokensHeld.selector, target);\n _setTarget(this.setTradingFeeTokensHeld.selector, target);\n _setTarget(this.setBorrowingFeeTokensHeld.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n }\n}\n" + }, + "contracts/mockup/proxy/ImplementationMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\n\ncontract ImplementationMockup is StorageMockup {\n function setValue(uint256 _value) public {\n value = _value;\n emit ValueChanged(_value);\n }\n\n function getValue() public view returns (uint256) {\n return value;\n }\n}\n" + }, + "contracts/mockup/proxy/ProxyMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract ProxyMockup is StorageMockup, UpgradableProxy {}\n" + }, + "contracts/mockup/proxy/StorageMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\ncontract StorageMockup {\n uint256 value;\n\n event ValueChanged(uint256 value);\n}\n" + }, + "contracts/mockup/RBTCWrapperProxyMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract RBTCWrapperProxyMockup {\n LiquidityMining public liquidityMining;\n\n constructor(LiquidityMining _liquidityMining) public {\n liquidityMining = _liquidityMining;\n }\n\n function claimReward(address _poolToken) public {\n liquidityMining.claimReward(_poolToken, msg.sender);\n }\n\n function claimRewardFromAllPools() public {\n liquidityMining.claimRewardFromAllPools(msg.sender);\n }\n\n function withdraw(address _poolToken, uint256 _amount) public {\n liquidityMining.withdraw(_poolToken, _amount, msg.sender);\n }\n}\n" + }, + "contracts/mockup/StakingRewardsMockUp.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/StakingRewards/StakingRewards.sol\";\nimport \"./BlockMockUp.sol\";\n\n/**\n * @title Staking Rewards Contract MockUp\n * @notice This is used for Testing\n * */\ncontract StakingRewardsMockUp is StakingRewards {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n using SafeMath for uint256;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n}\n" + }, + "contracts/mockup/TimelockHarness.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"../governance/Timelock.sol\";\n\ninterface Administered {\n function _acceptAdmin() external returns (uint256);\n}\n\ncontract TimelockHarness is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, delay_) {}\n\n function setDelayWithoutChecking(uint256 delay_) public {\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function harnessSetPendingAdmin(address pendingAdmin_) public {\n pendingAdmin = pendingAdmin_;\n }\n\n function harnessSetAdmin(address admin_) public {\n admin = admin_;\n }\n}\n\ncontract TimelockTest is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, 2 days) {\n delay = delay_;\n }\n\n function harnessSetAdmin(address admin_) public {\n require(msg.sender == admin);\n admin = admin_;\n }\n\n function harnessAcceptAdmin(Administered administered) public {\n administered._acceptAdmin();\n }\n}\n" + }, + "contracts/mockup/VestingLogicMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/Vesting/VestingLogic.sol\";\n\ncontract VestingLogicMockup is VestingLogic {\n /**\n * @dev we had a bug in a loop: \"i < endDate\" instead of \"i <= endDate\"\n */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n}\n" + }, + "contracts/mockup/VestingRegistryLogicMockUp.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\nimport \"../governance/Vesting/VestingRegistryLogic.sol\";\n\ncontract VestingRegistryLogicMockup is VestingRegistryLogic {\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return true;\n }\n\n function setTeamVesting(address _vesting, uint256 _vestingCreationType) external {\n vestingCreationAndTypes[_vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(VestingType.TeamVesting),\n vestingCreationType: uint128(_vestingCreationType)\n });\n }\n}\n" + }, + "contracts/modules/Affiliates.sol": { + "content": "/**\n * Copyright 2017-2020, Sovryn, All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Affiliates contract.\n * @notice Track referrals and reward referrers (affiliates) with tokens.\n * In-detail specifications are found at https://wiki.sovryn.app/en/community/Affiliates\n * @dev Module: Affiliates upgradable\n * Storage: from State, functions called from Protocol by delegatecall\n */\ncontract Affiliates is State, AffiliatesEvents, ModuleCommonFunctionalities {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Void constructor.\n */\n // solhint-disable-next-line no-empty-blocks\n constructor() public {}\n\n /**\n * @notice Avoid calls to this contract except for those explicitly declared.\n */\n function() external {\n revert(\"Affiliates - fallback not allowed\");\n }\n\n /**\n * @notice Set delegate callable functions by proxy contract.\n * @dev This contract is designed as a module, this way logic can be\n * expanded and upgraded w/o losing storage that is kept in the protocol (State.sol)\n * initialize() is used to register in the proxy external (module) functions\n * to be called via the proxy.\n * @param target The address of a new logic implementation.\n */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setAffiliatesReferrer.selector];\n _setTarget(this.setAffiliatesReferrer.selector, target);\n _setTarget(this.getUserNotFirstTradeFlag.selector, target);\n _setTarget(this.getReferralsList.selector, target);\n _setTarget(this.setUserNotFirstTradeFlag.selector, target);\n _setTarget(this.payTradingFeeToAffiliatesReferrer.selector, target);\n _setTarget(this.getAffiliatesReferrerBalances.selector, target);\n _setTarget(this.getAffiliatesReferrerTokenBalance.selector, target);\n _setTarget(this.getAffiliatesReferrerTokensList.selector, target);\n _setTarget(this.withdrawAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.withdrawAllAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.getMinReferralsToPayout.selector, target);\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n _setTarget(this.getAffiliateRewardsHeld.selector, target);\n _setTarget(this.getAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.getAffiliatesTokenRewardsValueInRbtc.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"Affiliates\");\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from loan pools.\n */\n modifier onlyCallableByLoanPools() {\n require(loanPoolToUnderlying[msg.sender] != address(0), \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from within protocol functions.\n */\n modifier onlyCallableInternal() {\n require(msg.sender == protocolAddress, \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Data structure comprised of 3 flags to compute the result of setting a referrer.\n */\n struct SetAffiliatesReferrerResult {\n bool success;\n bool alreadySet;\n bool userNotFirstTradeFlag;\n }\n\n /**\n * @notice Loan pool calls this function to tell affiliates\n * a user coming from a referrer is trading and should be registered if not yet.\n * Taking into account some user status flags may lead to the user and referrer\n * become added or not to the affiliates record.\n *\n * @param user The address of the user that is trading on loan pools.\n * @param referrer The address of the referrer the user is coming from.\n */\n function setAffiliatesReferrer(address user, address referrer)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n SetAffiliatesReferrerResult memory result;\n\n result.userNotFirstTradeFlag = getUserNotFirstTradeFlag(user);\n result.alreadySet = affiliatesUserReferrer[user] != address(0);\n result.success = !(result.userNotFirstTradeFlag || result.alreadySet || user == referrer);\n if (result.success) {\n affiliatesUserReferrer[user] = referrer;\n referralsList[referrer].add(user);\n emit SetAffiliatesReferrer(user, referrer);\n } else {\n emit SetAffiliatesReferrerFail(\n user,\n referrer,\n result.alreadySet,\n result.userNotFirstTradeFlag\n );\n }\n }\n\n /**\n * @notice Getter to query the referrals coming from a referrer.\n * @param referrer The address of a given referrer.\n * @return The referralsList mapping value by referrer.\n */\n function getReferralsList(address referrer) external view returns (address[] memory refList) {\n refList = referralsList[referrer].enumerate();\n return refList;\n }\n\n /**\n * @notice Getter to query the not-first-trade flag of a user.\n * @param user The address of a given user.\n * @return The userNotFirstTradeFlag mapping value by user.\n */\n function getUserNotFirstTradeFlag(address user) public view returns (bool) {\n return userNotFirstTradeFlag[user];\n }\n\n /**\n * @notice Setter to toggle on the not-first-trade flag of a user.\n * @param user The address of a given user.\n */\n function setUserNotFirstTradeFlag(address user)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n if (!userNotFirstTradeFlag[user]) {\n userNotFirstTradeFlag[user] = true;\n emit SetUserNotFirstTradeFlag(user);\n }\n }\n\n /**\n * @notice Internal getter to query the fee share for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function _getAffiliatesTradingFeePercentForSOV() internal view returns (uint256) {\n return affiliateFeePercent;\n }\n\n /**\n * @notice Internal to calculate the affiliates trading token fee amount.\n * Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * This _getReferrerTradingFeeForToken calculates the first one\n * by applying a custom percentage multiplier.\n * @param feeTokenAmount The trading token fee amount.\n * @return The affiliates share of the trading token fee amount.\n */\n function _getReferrerTradingFeeForToken(uint256 feeTokenAmount)\n internal\n view\n returns (uint256)\n {\n return feeTokenAmount.mul(getAffiliateTradingTokenFeePercent()).div(10**20);\n }\n\n /**\n * @notice Getter to query the fee share of trading token fee for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function getAffiliateTradingTokenFeePercent() public view returns (uint256) {\n return affiliateTradingTokenFeePercent;\n }\n\n /**\n * @notice Getter to query referral threshold for paying out to the referrer.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The minimum number of referrals set by Protocol.\n */\n function getMinReferralsToPayout() public view returns (uint256) {\n return minReferralsToPayout;\n }\n\n /**\n * @notice Get the sovToken reward of a trade.\n * @dev The reward is worth x% of the trading fee.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * @return The reward amount.\n * */\n function _getSovBonusAmount(address feeToken, uint256 feeAmount)\n internal\n view\n returns (uint256)\n {\n uint256 rewardAmount;\n address _priceFeeds = priceFeeds;\n\n /// @dev Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// dest token = SOV\n feeAmount.mul(_getAffiliatesTradingFeePercentForSOV()).div(1e20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n return rewardAmount;\n }\n\n /**\n * @notice Protocol calls this function to pay the affiliates rewards to a user (referrer).\n *\n * @dev Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * Both are paid in this function.\n *\n * @dev Actually they are not paid, but just holded by protocol until user claims them by\n * actively calling withdrawAffiliatesReferrerTokenFees() function,\n * and/or when unvesting lockedSOV.\n *\n * @dev To be precise, what this function does is updating the registers of the rewards\n * for the referrer including the assignment of the SOV tokens as rewards to the\n * referrer's vesting contract.\n *\n * @param referrer The address of the referrer.\n * @param trader The address of the trader.\n * @param token The address of the token in which the trading/borrowing fee was paid.\n * @param tradingFeeTokenBaseAmount Total trading fee amount, the base for calculating referrer's fees.\n *\n * @return referrerBonusSovAmount The amount of SOV tokens paid to the referrer (through a vesting contract, lockedSOV).\n * @return referrerBonusTokenAmount The amount of trading tokens paid directly to the referrer.\n */\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n )\n external\n onlyCallableInternal\n whenNotPaused\n returns (uint256 referrerBonusSovAmount, uint256 referrerBonusTokenAmount)\n {\n bool isHeld = referralsList[referrer].length() < getMinReferralsToPayout();\n bool bonusPaymentIsSuccess = true;\n uint256 paidReferrerBonusSovAmount;\n\n /// Process token fee rewards first.\n referrerBonusTokenAmount = _getReferrerTradingFeeForToken(tradingFeeTokenBaseAmount);\n if (!affiliatesReferrerTokensList[referrer].contains(token))\n affiliatesReferrerTokensList[referrer].add(token);\n affiliatesReferrerBalances[referrer][token] = affiliatesReferrerBalances[referrer][token]\n .add(referrerBonusTokenAmount);\n\n /// Then process SOV rewards.\n referrerBonusSovAmount = _getSovBonusAmount(token, tradingFeeTokenBaseAmount);\n uint256 rewardsHeldByProtocol = affiliateRewardsHeld[referrer];\n\n if (isHeld) {\n /// If referrals less than minimum, temp the rewards SOV to the storage\n affiliateRewardsHeld[referrer] = rewardsHeldByProtocol.add(referrerBonusSovAmount);\n } else {\n /// If referrals >= minimum, directly send all of the remain rewards to locked sov\n /// Call depositSOV() in LockedSov contract\n /// Set the affiliaterewardsheld = 0\n if (affiliateRewardsHeld[referrer] > 0) {\n affiliateRewardsHeld[referrer] = 0;\n }\n\n paidReferrerBonusSovAmount = referrerBonusSovAmount.add(rewardsHeldByProtocol);\n IERC20(sovTokenAddress).approve(lockedSOVAddress, paidReferrerBonusSovAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"depositSOV(address,uint256)\",\n referrer,\n paidReferrerBonusSovAmount\n )\n );\n\n if (!success) {\n bonusPaymentIsSuccess = false;\n }\n }\n\n if (bonusPaymentIsSuccess) {\n emit PayTradingFeeToAffiliate(\n referrer,\n trader, // trader\n token,\n isHeld,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n } else {\n emit PayTradingFeeToAffiliateFail(\n referrer,\n trader, // trader\n token,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n }\n\n return (referrerBonusSovAmount, referrerBonusTokenAmount);\n }\n\n /**\n * @notice Referrer calls this function to receive its reward in a given token.\n * It will send the other (non-SOV) reward tokens from trading protocol fees,\n * to the referrer’s wallet.\n * @dev Rewards are held by protocol in different tokens coming from trading fees.\n * Referrer has to claim them one by one for every token with accumulated balance.\n * @param token The address of the token to withdraw.\n * @param receiver The address of the withdrawal beneficiary.\n * @param amount The amount of tokens to claim. If greater than balance, just sends balance.\n */\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) public whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n uint256 referrerTokenBalance = affiliatesReferrerBalances[referrer][token];\n uint256 withdrawAmount = referrerTokenBalance > amount ? amount : referrerTokenBalance;\n\n require(withdrawAmount > 0, \"Affiliates: cannot withdraw zero amount\");\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n uint256 newReferrerTokenBalance = referrerTokenBalance.sub(withdrawAmount);\n\n if (newReferrerTokenBalance == 0) {\n _removeAffiliatesReferrerToken(referrer, token);\n } else {\n affiliatesReferrerBalances[referrer][token] = newReferrerTokenBalance;\n }\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawAffiliatesReferrerTokenFees(referrer, receiver, token, withdrawAmount);\n }\n\n /**\n * @notice Withdraw to msg.sender all token fees for a referrer.\n * @dev It's done by looping through its available tokens.\n * @param receiver The address of the withdrawal beneficiary.\n */\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n (address[] memory tokenAddresses, uint256[] memory tokenBalances) =\n getAffiliatesReferrerBalances(referrer);\n for (uint256 i; i < tokenAddresses.length; i++) {\n withdrawAffiliatesReferrerTokenFees(tokenAddresses[i], receiver, tokenBalances[i]);\n }\n }\n\n /**\n * @notice Internal function to delete a referrer's token balance.\n * @param referrer The address of the referrer.\n * @param token The address of the token specifying the balance to remove.\n */\n function _removeAffiliatesReferrerToken(address referrer, address token) internal {\n delete affiliatesReferrerBalances[referrer][token];\n affiliatesReferrerTokensList[referrer].remove(token);\n }\n\n /**\n * @notice Get all token balances of a referrer.\n * @param referrer The address of the referrer.\n * @return referrerTokensList The array of available tokens (keys).\n * @return referrerTokensBalances The array of token balances (values).\n */\n function getAffiliatesReferrerBalances(address referrer)\n public\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances)\n {\n referrerTokensList = getAffiliatesReferrerTokensList(referrer);\n referrerTokensBalances = new uint256[](referrerTokensList.length);\n for (uint256 i; i < referrerTokensList.length; i++) {\n referrerTokensBalances[i] = getAffiliatesReferrerTokenBalance(\n referrer,\n referrerTokensList[i]\n );\n }\n return (referrerTokensList, referrerTokensBalances);\n }\n\n /**\n * @dev Get all token rewards estimation value in rbtc.\n *\n * @param referrer Address of referrer.\n *\n * @return The value estimation in rbtc.\n */\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount)\n {\n address[] memory tokensList = getAffiliatesReferrerTokensList(referrer);\n address _priceFeeds = priceFeeds;\n\n for (uint256 i; i < tokensList.length; i++) {\n // Get the value of each token in rbtc\n\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n tokensList[i], // source token\n address(wrbtcToken), // dest token = SOV\n affiliatesReferrerBalances[referrer][tokensList[i]] // total token rewards\n )\n );\n\n assembly {\n if eq(success, 1) {\n rbtcTotalAmount := add(rbtcTotalAmount, mload(add(data, 32)))\n }\n }\n }\n }\n\n /**\n * @notice Get all available tokens at the affiliates program for a given referrer.\n * @param referrer The address of a given referrer.\n * @return tokensList The list of available tokens.\n */\n function getAffiliatesReferrerTokensList(address referrer)\n public\n view\n returns (address[] memory tokensList)\n {\n tokensList = affiliatesReferrerTokensList[referrer].enumerate();\n return tokensList;\n }\n\n /**\n * @notice Getter to query the affiliate balance for a given referrer and token.\n * @param referrer The address of the referrer.\n * @param token The address of the token to get balance for.\n * @return The affiliatesReferrerBalances mapping value by referrer and token keys.\n */\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n public\n view\n returns (uint256)\n {\n return affiliatesReferrerBalances[referrer][token];\n }\n\n /**\n * @notice Getter to query the address of referrer for a given user.\n * @param user The address of the user.\n * @return The address on affiliatesUserReferrer mapping value by user key.\n */\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user];\n }\n\n /**\n * @notice Getter to query the reward amount held for a given referrer.\n * @param referrer The address of the referrer.\n * @return The affiliateRewardsHeld mapping value by referrer key.\n */\n function getAffiliateRewardsHeld(address referrer) public view returns (uint256) {\n return affiliateRewardsHeld[referrer];\n }\n}\n" + }, + "contracts/modules/interfaces/ProtocolAffiliatesInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolAffiliatesInterface {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user_) external;\n\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\n\n function payTradingFeeToAffiliatesReferrer(\n address affiliate,\n address trader,\n address token,\n uint256 amount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n}\n" + }, + "contracts/modules/interfaces/ProtocolSwapExternalInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolSwapExternalInterface {\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n}\n" + }, + "contracts/modules/LoanClosingsLiquidation.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsLiquidation contract.\n * @notice Ways to close a loan: liquidation. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsLiquidation is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.liquidate.selector];\n _setTarget(this.liquidate.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsLiquidation\"\n );\n }\n\n /**\n * @notice Liquidate an unhealty loan.\n *\n * @dev Public wrapper for _liquidate internal function.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * loanId is the ID of the loan, which is created on loan opening.\n * It can be obtained either by parsing the Trade event or by reading\n * the open loans from the contract by calling getActiveLoans or getUserLoans.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n return _liquidate(loanId, receiver, closeAmount);\n }\n\n /**\n * @notice Internal function for liquidating an unhealthy loan.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function _liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin <= loanParamsLocal.maintenanceMargin, \"healthy position\");\n\n loanCloseAmount = closeAmount;\n\n //amounts to restore the desired margin (maintencance + 5%)\n (uint256 maxLiquidatable, uint256 maxSeizable, ) =\n _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n\n if (loanCloseAmount < maxLiquidatable) {\n //close maxLiquidatable if tiny position will remain\n uint256 remainingAmount = maxLiquidatable - loanCloseAmount;\n remainingAmount = _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingAmount <= TINY_AMOUNT) {\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable.mul(loanCloseAmount).div(maxLiquidatable);\n }\n } else if (loanCloseAmount > maxLiquidatable) {\n // adjust down the close amount to the max\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable;\n }\n\n require(loanCloseAmount != 0, \"nothing to liquidate\");\n\n // liquidator deposits the principal being closed\n _returnPrincipalWithDeposit(loanParamsLocal.loanToken, address(this), loanCloseAmount);\n\n // a portion of the principal is repaid to the lender out of interest refunded\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n loanLocal.borrower\n );\n\n if (loanCloseAmount > loanCloseAmountLessInterest) {\n // full interest refund goes to the borrower\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanCloseAmount - loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmountLessInterest != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n seizedToken = loanParamsLocal.collateralToken;\n\n if (seizedAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(seizedAmount);\n\n _withdrawAsset(seizedToken, receiver, seizedAmount);\n }\n\n _closeLoan(loanLocal, loanCloseAmount);\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n seizedAmount,\n collateralToLoanRate,\n 0,\n currentMargin,\n CloseTypes.Liquidation\n );\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsRollover.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsRollover contract.\n * @notice Ways to close a loan: rollover. Margin trade\n * positions are always closed with a swap.\n *\n * */\ncontract LoanClosingsRollover is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.rollover.selector];\n _setTarget(this.rollover.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsRollover\"\n );\n }\n\n /**\n * @notice Roll over a loan.\n *\n * @dev Public wrapper for _rollover internal function.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * The function rollover on the protocol contract extends the loan\n * duration by the maximum term (28 days for margin trades at the moment\n * of writing), pays the interest to the lender and refunds the caller\n * for the gas cost by sending 2 * the gas cost using the fast gas price\n * as base for the calculation.\n *\n * @param loanId The ID of the loan to roll over.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n * */\n function rollover(\n bytes32 loanId,\n bytes calldata // for future use /*loanDataBytes*/\n ) external nonReentrant globallyNonReentrant iTokenSupplyUnchanged(loanId) whenNotPaused {\n // restrict to EOAs to prevent griefing attacks, during interest rate recalculation\n require(msg.sender == tx.origin, \"EOAs call\");\n\n return\n _rollover(\n loanId,\n \"\" // loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for roll over a loan.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * @param loanId The ID of the loan to roll over.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n * */\n function _rollover(bytes32 loanId, bytes memory loanDataBytes) internal {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n require(block.timestamp > loanLocal.endTimestamp.sub(3600), \"healthy position\");\n require(loanPoolToUnderlying[loanLocal.lender] != address(0), \"invalid lender\");\n\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n // Handle back interest: calculates interest owned since the loan endtime passed but the loan remained open\n uint256 backInterestTime;\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestTime = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestTime.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(1 days);\n }\n\n //note: to avoid code duplication, it would be nicer to store loanParamsLocal.maxLoanTerm in a local variable\n //however, we've got stack too deep issues if we do so.\n if (loanParamsLocal.maxLoanTerm != 0) {\n // fixed-term loan, so need to query iToken for latest variable rate\n uint256 owedPerDay =\n loanLocal.principal.mul(ILoanPool(loanLocal.lender).borrowInterestRate()).div(\n 365 * 10**20\n );\n\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(\n loanInterestLocal.owedPerDay\n );\n\n loanInterestLocal.owedPerDay = owedPerDay;\n\n //if the loan has been open for longer than an additional period, add at least 1 additional day\n if (backInterestTime >= loanParamsLocal.maxLoanTerm) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n }\n //extend by the max loan term\n else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(loanParamsLocal.maxLoanTerm);\n }\n } else {\n // loanInterestLocal.owedPerDay doesn't change\n if (backInterestTime >= MONTH) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n } else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(MONTH);\n }\n }\n\n uint256 interestAmountRequired = loanLocal.endTimestamp.sub(block.timestamp);\n interestAmountRequired = interestAmountRequired.mul(loanInterestLocal.owedPerDay);\n interestAmountRequired = interestAmountRequired.div(1 days);\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n\n // add backInterestOwed\n interestAmountRequired = interestAmountRequired.add(backInterestOwed);\n\n // collect interest (needs to be converted from the collateral)\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n 0, //min swap 0 -> swap connector estimates the amount of source tokens to use\n interestAmountRequired, //required destination tokens\n true, // returnTokenIsCollateral\n loanDataBytes\n );\n\n //received more tokens than needed to pay the interest\n if (destTokenAmountReceived > interestAmountRequired) {\n // swap rest back to collateral, if the amount is big enough to cover gas cost\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n )\n ) {\n (destTokenAmountReceived, , ) = _swapBackExcess(\n loanLocal,\n loanParamsLocal,\n destTokenAmountReceived - interestAmountRequired, //amount to be swapped\n loanDataBytes\n );\n sourceTokenAmountUsed = sourceTokenAmountUsed.sub(destTokenAmountReceived);\n }\n //else give it to the protocol as a lending fee\n else {\n _payLendingFee(\n loanLocal.borrower,\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n );\n }\n }\n\n //subtract the interest from the collateral\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n if (backInterestOwed != 0) {\n // pay out backInterestOwed\n\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n uint256 rolloverReward =\n _getRolloverReward(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.principal\n );\n\n if (rolloverReward != 0) {\n // if the reward > collateral:\n if (rolloverReward > loanLocal.collateral) {\n // 1. pay back the remaining loan to the lender\n // 2. pay the remaining collateral to msg.sender\n // 3. close the position & emit close event\n _closeWithSwap(\n loanLocal.id,\n msg.sender,\n loanLocal.collateral,\n false,\n \"\" // loanDataBytes\n );\n } else {\n // pay out reward to caller\n loanLocal.collateral = loanLocal.collateral.sub(rolloverReward);\n\n _withdrawAsset(loanParamsLocal.collateralToken, msg.sender, rolloverReward);\n }\n }\n\n if (loanLocal.collateral > 0) {\n //close whole loan if tiny position will remain\n if (_getAmountInRbtc(loanParamsLocal.loanToken, loanLocal.principal) <= TINY_AMOUNT) {\n _closeWithSwap(\n loanLocal.id,\n loanLocal.borrower,\n loanLocal.collateral, // swap all collaterals\n false,\n \"\" /// loanDataBytes\n );\n } else {\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n require(\n currentMargin > 3 ether, // ensure there's more than 3% margin remaining\n \"unhealthy position\"\n );\n }\n }\n\n if (loanLocal.active) {\n emit Rollover(\n loanLocal.borrower, // user (borrower)\n loanLocal.lender, // lender\n loanLocal.id, // loanId\n loanLocal.principal, // principal\n loanLocal.collateral, // collateral\n loanLocal.endTimestamp, // endTimestamp\n msg.sender, // rewardReceiver\n rolloverReward // reward\n );\n }\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsShared.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/RewardHelper.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\n/**\n * @title LoanClosingsShared contract.\n * @notice This contract should only contains the internal function that is being used / utilized by\n * LoanClosingsLiquidation, LoanClosingsRollover & LoanClosingsWith contract\n *\n * */\ncontract LoanClosingsShared is\n LoanClosingsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n RewardHelper,\n ModuleCommonFunctionalities\n{\n uint256 internal constant MONTH = 365 days / 12;\n //0.00001 BTC, would be nicer in State.sol, but would require a redeploy of the complete protocol, so adding it here instead\n //because it's not shared state anyway and only used by this contract\n uint256 public constant paySwapExcessToBorrowerThreshold = 10000000000000;\n\n uint256 public constant TINY_AMOUNT = 25e13;\n\n enum CloseTypes { Deposit, Swap, Liquidation }\n\n /** modifier for invariant check */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n Loan storage loanLocal = loans[loanId];\n\n require(loanLocal.lender != address(0), \"Invalid loan token pool address\");\n\n uint256 previousITokenSupply = ILoanTokenModules(loanLocal.lender).totalSupply();\n\n _;\n\n /// Validate iToken total supply\n require(\n previousITokenSupply == ILoanTokenModules(loanLocal.lender).totalSupply(),\n \"loan token supply invariant check failure\"\n );\n }\n\n /**\n * @dev computes the interest which needs to be refunded to the borrower based on the amount he's closing and either\n * subtracts it from the amount which still needs to be paid back (in case outstanding amount > interest) or withdraws the\n * excess to the borrower (in case interest > outstanding).\n * @param loanLocal the loan\n * @param loanParamsLocal the loan params\n * @param loanCloseAmount the amount to be closed (base for the computation)\n * @param receiver the address of the receiver (usually the borrower)\n * */\n function _settleInterestToPrincipal(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 loanCloseAmount,\n address receiver\n ) internal returns (uint256) {\n uint256 loanCloseAmountLessInterest = loanCloseAmount;\n\n //compute the interest which neeeds to be refunded to the borrower (because full interest is paid on loan )\n uint256 interestRefundToBorrower =\n _settleInterest(loanParamsLocal, loanLocal, loanCloseAmountLessInterest);\n\n uint256 interestAppliedToPrincipal;\n //if the outstanding loan is bigger than the interest to be refunded, reduce the amount to be paid back / closed by the interest\n if (loanCloseAmountLessInterest >= interestRefundToBorrower) {\n // apply all of borrower interest refund torwards principal\n interestAppliedToPrincipal = interestRefundToBorrower;\n\n // principal needed is reduced by this amount\n loanCloseAmountLessInterest -= interestRefundToBorrower;\n\n // no interest refund remaining\n interestRefundToBorrower = 0;\n } else {\n //if the interest refund is bigger than the outstanding loan, the user needs to get back the interest\n // principal fully covered by excess interest\n interestAppliedToPrincipal = loanCloseAmountLessInterest;\n\n // amount refunded is reduced by this amount\n interestRefundToBorrower -= loanCloseAmountLessInterest;\n\n // principal fully covered by excess interest\n loanCloseAmountLessInterest = 0;\n\n if (interestRefundToBorrower != 0) {\n // refund overage\n _withdrawAsset(loanParamsLocal.loanToken, receiver, interestRefundToBorrower);\n }\n }\n\n //pay the interest to the lender\n //note: this is a waste of gas, because the loanCloseAmountLessInterest is withdrawn to the lender, too. It could be done at once.\n if (interestAppliedToPrincipal != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, interestAppliedToPrincipal);\n }\n\n return loanCloseAmountLessInterest;\n }\n\n // The receiver always gets back an ERC20 (even wrbtc)\n function _returnPrincipalWithDeposit(\n address loanToken,\n address receiver,\n uint256 principalNeeded\n ) internal {\n if (principalNeeded != 0) {\n if (msg.value == 0) {\n vaultTransfer(loanToken, msg.sender, receiver, principalNeeded);\n } else {\n require(loanToken == address(wrbtcToken), \"wrong asset sent\");\n require(msg.value >= principalNeeded, \"not enough ether\");\n wrbtcToken.deposit.value(principalNeeded)();\n if (receiver != address(this)) {\n vaultTransfer(loanToken, address(this), receiver, principalNeeded);\n }\n if (msg.value > principalNeeded) {\n // refund overage\n Address.sendValue(msg.sender, msg.value - principalNeeded);\n }\n }\n } else {\n require(msg.value == 0, \"wrong asset sent\");\n }\n }\n\n /**\n * @dev checks if the amount of the asset to be transfered is worth the transfer fee\n * @param asset the asset to be transfered\n * @param amount the amount to be transfered\n * @return True if the amount is bigger than the threshold\n * */\n function worthTheTransfer(address asset, uint256 amount) internal returns (bool) {\n uint256 amountInRbtc = _getAmountInRbtc(asset, amount);\n emit swapExcess(\n amountInRbtc > paySwapExcessToBorrowerThreshold,\n amount,\n amountInRbtc,\n paySwapExcessToBorrowerThreshold\n );\n\n return amountInRbtc > paySwapExcessToBorrowerThreshold;\n }\n\n /**\n * swaps collateral tokens for loan tokens\n * @param loanLocal the loan object\n * @param loanParamsLocal the loan parameters\n * @param swapAmount the amount to be swapped\n * @param principalNeeded the required destination token amount\n * @param returnTokenIsCollateral if true -> required destination token amount will be passed on, else not\n * note: quite dirty. should be refactored.\n * @param loanDataBytes additional loan data (not in use for token swaps)\n * */\n function _doCollateralSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n loanLocal.collateral, // maxSourceTokenAmount\n returnTokenIsCollateral\n ? principalNeeded // requiredDestTokenAmount\n : 0,\n false, // bypassFee\n loanDataBytes\n );\n require(destTokenAmountReceived >= principalNeeded, \"insufficient dest amount\");\n require(sourceTokenAmountUsed <= loanLocal.collateral, \"excessive source amount\");\n }\n\n /**\n * @notice Withdraw asset to receiver.\n *\n * @param assetToken The loan token.\n * @param receiver The address of the receiver.\n * @param assetAmount The loan token amount.\n * */\n function _withdrawAsset(\n address assetToken,\n address receiver,\n uint256 assetAmount\n ) internal {\n if (assetAmount != 0) {\n if (assetToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, assetAmount);\n } else {\n vaultWithdraw(assetToken, receiver, assetAmount);\n }\n }\n }\n\n /**\n * @notice Internal function to close a loan.\n *\n * @param loanLocal The loan object.\n * @param loanCloseAmount The amount to close: principal or lower.\n *\n * */\n function _closeLoan(Loan storage loanLocal, uint256 loanCloseAmount) internal {\n require(loanCloseAmount != 0, \"nothing to close\");\n\n if (loanCloseAmount == loanLocal.principal) {\n loanLocal.principal = 0;\n loanLocal.active = false;\n loanLocal.endTimestamp = block.timestamp;\n loanLocal.pendingTradesId = 0;\n activeLoansSet.removeBytes32(loanLocal.id);\n lenderLoanSets[loanLocal.lender].removeBytes32(loanLocal.id);\n borrowerLoanSets[loanLocal.borrower].removeBytes32(loanLocal.id);\n } else {\n loanLocal.principal = loanLocal.principal.sub(loanCloseAmount);\n }\n }\n\n function _settleInterest(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 closePrincipal\n ) internal returns (uint256) {\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 interestTime = block.timestamp;\n if (interestTime > loanLocal.endTimestamp) {\n interestTime = loanLocal.endTimestamp;\n }\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n interestTime\n );\n\n uint256 owedPerDayRefund;\n if (closePrincipal < loanLocal.principal) {\n owedPerDayRefund = loanInterestLocal.owedPerDay.mul(closePrincipal).div(\n loanLocal.principal\n );\n } else {\n owedPerDayRefund = loanInterestLocal.owedPerDay;\n }\n\n // update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.sub(owedPerDayRefund);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(owedPerDayRefund);\n\n // update borrower interest\n uint256 interestRefundToBorrower = loanLocal.endTimestamp.sub(interestTime);\n interestRefundToBorrower = interestRefundToBorrower.mul(owedPerDayRefund);\n interestRefundToBorrower = interestRefundToBorrower.div(1 days);\n\n if (closePrincipal < loanLocal.principal) {\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(\n interestRefundToBorrower\n );\n } else {\n loanInterestLocal.depositTotal = 0;\n }\n\n // update remaining lender interest values\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.sub(\n closePrincipal\n );\n\n uint256 owedTotal = lenderInterestLocal.owedTotal;\n lenderInterestLocal.owedTotal = owedTotal > interestRefundToBorrower\n ? owedTotal - interestRefundToBorrower\n : 0;\n\n return interestRefundToBorrower;\n }\n\n /**\n * @notice Check sender is borrower or delegatee and loan id exists.\n *\n * @param loanId byte32 of the loan id.\n * */\n function _checkAuthorized(bytes32 loanId) internal view {\n Loan storage loanLocal = loans[loanId];\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n }\n\n /**\n * @notice Internal function for closing a position by swapping the\n * collateral back to loan tokens, paying the lender and withdrawing\n * the remainder.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collatral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid\n * out in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(swapAmount != 0, \"swapAmount == 0\");\n\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't swap more than collateral.\n swapAmount = swapAmount > loanLocal.collateral ? loanLocal.collateral : swapAmount;\n\n //close whole loan if tiny position will remain\n if (loanLocal.collateral - swapAmount > 0) {\n if (\n _getAmountInRbtc(\n loanParamsLocal.collateralToken,\n loanLocal.collateral - swapAmount\n ) <= TINY_AMOUNT\n ) {\n swapAmount = loanLocal.collateral;\n }\n }\n\n uint256 loanCloseAmountLessInterest;\n if (swapAmount == loanLocal.collateral || returnTokenIsCollateral) {\n /// loanCloseAmountLessInterest will be passed as required amount amount of destination tokens.\n /// this means, the actual swapAmount passed to the swap contract does not matter at all.\n /// the source token amount will be computed depending on the required amount amount of destination tokens.\n loanCloseAmount = swapAmount == loanLocal.collateral\n ? loanLocal.principal\n : loanLocal.principal.mul(swapAmount).div(loanLocal.collateral);\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Computes the interest refund for the borrower and sends it to the lender to cover part of the principal.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n } else {\n /// loanCloseAmount is calculated after swap; for this case we want to swap the entire source amount\n /// and determine the loanCloseAmount and withdraw amount based on that.\n loanCloseAmountLessInterest = 0;\n }\n\n uint256 coveredPrincipal;\n uint256 usedCollateral;\n\n /// swapAmount repurposed for collateralToLoanSwapRate to avoid stack too deep error.\n (coveredPrincipal, usedCollateral, withdrawAmount, swapAmount) = _coverPrincipalWithSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount, /// The amount of source tokens to swap (only matters if !returnTokenIsCollateral or loanCloseAmountLessInterest = 0)\n loanCloseAmountLessInterest, /// This is the amount of destination tokens we want to receive (only matters if returnTokenIsCollateral)\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (loanCloseAmountLessInterest == 0) {\n /// Condition prior to swap: swapAmount != loanLocal.collateral && !returnTokenIsCollateral\n\n /// Amounts that is closed.\n loanCloseAmount = coveredPrincipal;\n if (coveredPrincipal != loanLocal.principal) {\n loanCloseAmount = loanCloseAmount.mul(usedCollateral).div(loanLocal.collateral);\n }\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Amount that is returned to the lender.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n\n /// Remaining amount withdrawn to the receiver.\n withdrawAmount = withdrawAmount.add(coveredPrincipal).sub(loanCloseAmountLessInterest);\n } else {\n /// Pay back the amount which was covered by the swap.\n loanCloseAmountLessInterest = coveredPrincipal;\n }\n\n require(loanCloseAmountLessInterest != 0, \"closeAmount is 0 after swap\");\n\n /// Reduce the collateral by the amount which was swapped for the closure.\n if (usedCollateral != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(usedCollateral);\n }\n\n /// Repays principal to lender.\n /// The lender always gets back an ERC20 (even wrbtc), so we call\n /// withdraw directly rather than use the _withdrawAsset helper function.\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, loanCloseAmountLessInterest);\n\n withdrawToken = returnTokenIsCollateral\n ? loanParamsLocal.collateralToken\n : loanParamsLocal.loanToken;\n\n if (withdrawAmount != 0) {\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n usedCollateral,\n swapAmount, /// collateralToLoanSwapRate\n CloseTypes.Swap\n );\n }\n\n /**\n * @notice Close a loan.\n *\n * @dev Wrapper for _closeLoan internal function.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan params.\n * @param loanCloseAmount The amount to close: principal or lower.\n * @param collateralCloseAmount The amount of collateral to close.\n * @param collateralToLoanSwapRate The price rate collateral/loan token.\n * @param closeType The type of loan close.\n * */\n function _finalizeClose(\n Loan storage loanLocal,\n LoanParams storage loanParamsLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanSwapRate,\n CloseTypes closeType\n ) internal {\n _closeLoan(loanLocal, loanCloseAmount);\n\n address _priceFeeds = priceFeeds;\n uint256 currentMargin;\n uint256 collateralToLoanRate;\n\n /// This is still called even with full loan close to return collateralToLoanRate\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).getCurrentMargin.selector,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n )\n );\n assembly {\n if eq(success, 1) {\n currentMargin := mload(add(data, 32))\n collateralToLoanRate := mload(add(data, 64))\n }\n }\n /// Note: We can safely skip the margin check if closing\n /// via closeWithDeposit or if closing the loan in full by any method.\n require(\n closeType == CloseTypes.Deposit ||\n loanLocal.principal == 0 || /// loan fully closed\n currentMargin > loanParamsLocal.maintenanceMargin,\n \"unhealthy position\"\n );\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n collateralCloseAmount,\n collateralToLoanRate,\n collateralToLoanSwapRate,\n currentMargin,\n closeType\n );\n }\n\n /**\n * swaps a share of a loan's collateral or the complete collateral in order to cover the principle.\n * @param loanLocal the loan\n * @param loanParamsLocal the loan parameters\n * @param swapAmount in case principalNeeded == 0 or !returnTokenIsCollateral, this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens needed for the swap is estimated by the connector.\n * @param principalNeeded the required amount of destination tokens in order to cover the principle (only used if returnTokenIsCollateral)\n * @param returnTokenIsCollateral tells if the user wants to withdraw his remaining collateral + profit in collateral tokens\n * @notice Swaps a share of a loan's collateral or the complete collateral\n * in order to cover the principle.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount In case principalNeeded == 0 or !returnTokenIsCollateral,\n * this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens\n * needed for the swap is estimated by the connector.\n * @param principalNeeded The required amount of destination tokens in order to\n * cover the principle (only used if returnTokenIsCollateral).\n * @param returnTokenIsCollateral Tells if the user wants to withdraw his\n * remaining collateral + profit in collateral tokens.\n *\n * @return coveredPrincipal The amount of principal that is covered.\n * @return usedCollateral The amount of collateral used.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _coverPrincipalWithSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 coveredPrincipal,\n uint256 usedCollateral,\n uint256 withdrawAmount,\n uint256 collateralToLoanSwapRate\n )\n {\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n (\n destTokenAmountReceived,\n sourceTokenAmountUsed,\n collateralToLoanSwapRate\n ) = _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount,\n principalNeeded,\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (returnTokenIsCollateral) {\n coveredPrincipal = principalNeeded;\n\n /// Better fill than expected.\n if (destTokenAmountReceived > coveredPrincipal) {\n /// Send excess to borrower if the amount is big enough to be\n /// worth the gas fees.\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - coveredPrincipal\n )\n ) {\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n destTokenAmountReceived - coveredPrincipal\n );\n }\n /// Else, give the excess to the lender (if it goes to the\n /// borrower, they're very confused. causes more trouble than it's worth)\n else {\n coveredPrincipal = destTokenAmountReceived;\n }\n }\n withdrawAmount = swapAmount > sourceTokenAmountUsed\n ? swapAmount - sourceTokenAmountUsed\n : 0;\n } else {\n require(sourceTokenAmountUsed == swapAmount, \"swap error\");\n\n if (swapAmount == loanLocal.collateral) {\n /// sourceTokenAmountUsed == swapAmount == loanLocal.collateral\n\n coveredPrincipal = principalNeeded;\n withdrawAmount = destTokenAmountReceived - principalNeeded;\n } else {\n /// sourceTokenAmountUsed == swapAmount < loanLocal.collateral\n\n if (destTokenAmountReceived >= loanLocal.principal) {\n /// Edge case where swap covers full principal.\n\n coveredPrincipal = loanLocal.principal;\n withdrawAmount = destTokenAmountReceived - loanLocal.principal;\n\n /// Excess collateral refunds to the borrower.\n _withdrawAsset(\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n loanLocal.collateral - sourceTokenAmountUsed\n );\n sourceTokenAmountUsed = loanLocal.collateral;\n } else {\n coveredPrincipal = destTokenAmountReceived;\n withdrawAmount = 0;\n }\n }\n }\n\n usedCollateral = sourceTokenAmountUsed > swapAmount ? sourceTokenAmountUsed : swapAmount;\n }\n\n function _emitClosingEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanRate,\n uint256 collateralToLoanSwapRate,\n uint256 currentMargin,\n CloseTypes closeType\n ) internal {\n if (closeType == CloseTypes.Deposit) {\n emit CloseWithDeposit(\n loanLocal.borrower, /// user (borrower)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n msg.sender, /// closer\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n loanCloseAmount, /// loanCloseAmount\n collateralCloseAmount, /// collateralCloseAmount\n collateralToLoanRate, /// collateralToLoanRate\n currentMargin /// currentMargin\n );\n } else if (closeType == CloseTypes.Swap) {\n /// exitPrice = 1 / collateralToLoanSwapRate\n if (collateralToLoanSwapRate != 0) {\n collateralToLoanSwapRate = SafeMath.div(10**36, collateralToLoanSwapRate);\n }\n\n /// currentLeverage = 100 / currentMargin\n if (currentMargin != 0) {\n currentMargin = SafeMath.div(10**38, currentMargin);\n }\n\n emit CloseWithSwap(\n loanLocal.borrower, /// user (trader)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n msg.sender, /// closer\n collateralCloseAmount, /// positionCloseSize\n loanCloseAmount, /// loanCloseAmount\n collateralToLoanSwapRate, /// exitPrice (1 / collateralToLoanSwapRate)\n currentMargin /// currentLeverage\n );\n } else if (closeType == CloseTypes.Liquidation) {\n emit Liquidate(\n loanLocal.borrower, // user (borrower)\n msg.sender, // liquidator\n loanLocal.id, // loanId\n loanLocal.lender, // lender\n loanParamsLocal.loanToken, // loanToken\n loanParamsLocal.collateralToken, // collateralToken\n loanCloseAmount, // loanCloseAmount\n collateralCloseAmount, // collateralCloseAmount\n collateralToLoanRate, // collateralToLoanRate\n currentMargin // currentMargin\n );\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal view returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n IPriceFeeds(priceFeeds).queryRate(asset, address(wrbtcToken));\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /**\n * @dev private function which check the loanLocal & loanParamsLocal does exist\n *\n * @param loanId bytes32 of loanId\n *\n * @return Loan storage\n * @return LoanParams storage\n */\n function _checkLoan(bytes32 loanId) internal view returns (Loan storage, LoanParams storage) {\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n return (loanLocal, loanParamsLocal);\n }\n}\n" + }, + "contracts/modules/LoanClosingsWith.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsWith contract.\n * @notice Close a loan w/deposit, close w/swap. There are 2 functions for ending a loan on the\n * protocol contract: closeWithSwap and closeWithDeposit. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsWith is LoanClosingsShared {\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n\n /**\n * @notice Closes a loan by doing a deposit.\n *\n * @dev Public wrapper for _closeWithDeposit internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens. (e.g. rBTC on a iSUSD contract).\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n public\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return _closeWithDeposit(loanId, receiver, depositAmount);\n }\n\n /**\n * @notice Close a position by swapping the collateral back to loan tokens\n * paying the lender and withdrawing the remainder.\n *\n * @dev Public wrapper for _closeWithSwap internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collateral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid out\n * in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes memory // for future use /*loanDataBytes*/\n )\n public\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return\n _closeWithSwap(\n loanId,\n receiver,\n swapAmount,\n returnTokenIsCollateral,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for closing a loan by doing a deposit.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens.\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(depositAmount != 0, \"depositAmount == 0\");\n\n //TODO should we skip this check if invoked from rollover ?\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't close more than the full principal.\n loanCloseAmount = depositAmount > loanLocal.principal\n ? loanLocal.principal\n : depositAmount;\n\n //revert if tiny position remains\n uint256 remainingAmount = loanLocal.principal - loanCloseAmount;\n if (remainingAmount > 0) {\n require(\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount) > TINY_AMOUNT,\n \"Tiny amount when closing with deposit\"\n );\n }\n\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(loanLocal, loanParamsLocal, loanCloseAmount, receiver);\n\n if (loanCloseAmountLessInterest != 0) {\n _returnPrincipalWithDeposit(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmount == loanLocal.principal) {\n withdrawAmount = loanLocal.collateral;\n } else {\n withdrawAmount = loanLocal.collateral.mul(loanCloseAmount).div(loanLocal.principal);\n }\n\n withdrawToken = loanParamsLocal.collateralToken;\n\n if (withdrawAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(withdrawAmount);\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n withdrawAmount, /// collateralCloseAmount\n 0, /// collateralToLoanSwapRate\n CloseTypes.Deposit\n );\n }\n\n /**\n * @notice Function to check whether the given loanId & deposit amount when closing with deposit will cause the tiny position\n *\n * @param loanId The id of the loan.\n * @param depositAmount Defines how much the deposit amount to close the position.\n *\n * @return isTinyPosition true is indicating tiny position, false otherwise.\n * @return tinyPositionAmount will return 0 for non tiny position, and will return the amount of tiny position if true\n */\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount)\n {\n (Loan memory loanLocal, LoanParams memory loanParamsLocal) = _checkLoan(loanId);\n\n if (depositAmount < loanLocal.principal) {\n uint256 remainingAmount = loanLocal.principal - depositAmount;\n uint256 remainingRBTCAmount =\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingRBTCAmount < TINY_AMOUNT) {\n isTinyPosition = true;\n tinyPositionAmount = remainingRBTCAmount;\n }\n }\n\n return (isTinyPosition, tinyPositionAmount);\n }\n}\n" + }, + "contracts/modules/LoanMaintenance.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Maintenance contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to query loan data and to modify its status\n * by withdrawing or depositing collateral.\n * */\ncontract LoanMaintenance is\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n LiquidationHelper,\n ModuleCommonFunctionalities\n{\n // Keep the old LoanReturnData for backward compatibility (especially for the watcher)\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n // The new struct which contained borrower & creation time of a loan\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set initial values of proxy targets.\n *\n * @param target The address of the logic contract instance.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.depositCollateral.selector];\n _setTarget(this.depositCollateral.selector, target);\n _setTarget(this.withdrawCollateral.selector, target);\n _setTarget(this.withdrawAccruedInterest.selector, target);\n _setTarget(this.extendLoanDuration.selector, target);\n _setTarget(this.reduceLoanDuration.selector, target);\n _setTarget(this.getLenderInterestData.selector, target);\n _setTarget(this.getLoanInterestData.selector, target);\n _setTarget(this.getUserLoans.selector, target);\n _setTarget(this.getUserLoansV2.selector, target);\n _setTarget(this.getLoan.selector, target);\n _setTarget(this.getLoanV2.selector, target);\n _setTarget(this.getActiveLoans.selector, target);\n _setTarget(this.getActiveLoansV2.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanMaintenance\");\n }\n\n /**\n * @notice Increase the margin of a position by depositing additional collateral.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount /// must match msg.value if ether is sent\n ) external payable nonReentrant whenNotPaused {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.value == 0 || loanParamsLocal.collateralToken == address(wrbtcToken),\n \"wrong asset sent\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(depositAmount);\n\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.collateralToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n\n (uint256 collateralToLoanRate, ) =\n IPriceFeeds(priceFeeds).queryRate(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n\n emit DepositCollateral(loanId, depositAmount, collateralToLoanRate);\n }\n\n /**\n * @notice Withdraw from the collateral. This reduces the margin of a position.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 actualWithdrawAmount) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral,\n loanParamsLocal.maintenanceMargin\n );\n\n if (withdrawAmount > maxDrawdown) {\n actualWithdrawAmount = maxDrawdown;\n } else {\n actualWithdrawAmount = withdrawAmount;\n }\n\n loanLocal.collateral = loanLocal.collateral.sub(actualWithdrawAmount);\n\n if (loanParamsLocal.collateralToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, actualWithdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.collateralToken, receiver, actualWithdrawAmount);\n }\n }\n\n /**\n * @notice Withdraw accrued loan interest.\n *\n * @dev Wrapper for _payInterest internal function.\n *\n * @param loanToken The loan token address.\n * */\n function withdrawAccruedInterest(address loanToken) external whenNotPaused {\n /// Pay outstanding interest to lender.\n _payInterest(\n msg.sender, /// Lender.\n loanToken\n );\n }\n\n /**\n * @notice Extend the loan duration by as much time as depositAmount can buy.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in loan tokens. Used to pay the interest for the new duration.\n * @param useCollateral Whether pay interests w/ the collateral. If true, depositAmount of loan tokens\n *\t\t\t\t\t\twill be purchased with the collateral.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n *\n * @return secondsExtended The amount of time in seconds the loan is extended.\n * */\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external payable nonReentrant whenNotPaused returns (uint256 secondsExtended) {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n !useCollateral ||\n msg.sender == loanLocal.borrower ||\n delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(\n msg.value == 0 || (!useCollateral && loanParamsLocal.loanToken == address(wrbtcToken)),\n \"wrong asset sent\"\n );\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n /// Handle back interest: calculates interest owned since the loan\n /// endtime passed but the loan remained open.\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestOwed = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestOwed.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(86400);\n\n require(depositAmount > backInterestOwed, \"deposit cannot cover back interest\");\n }\n\n /// Deposit interest.\n if (useCollateral) {\n /// Used the whole converted loanToken to extend the loan duration\n depositAmount = _doCollateralSwap(loanLocal, loanParamsLocal, depositAmount);\n } else {\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.loanToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n }\n\n if (backInterestOwed != 0) {\n depositAmount = depositAmount.sub(backInterestOwed);\n\n /// Pay out backInterestOwed\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n secondsExtended = depositAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(secondsExtended);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(depositAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .add(depositAmount);\n }\n\n /**\n * @notice Reduce the loan duration by withdrawing from the deposited interest.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in loan tokens.\n *\n * @return secondsReduced The amount of time in seconds the loan is reduced.\n * */\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 secondsReduced) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(loanLocal.endTimestamp > block.timestamp, \"loan term has ended\");\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 interestDepositRemaining =\n loanLocal.endTimestamp.sub(block.timestamp).mul(loanInterestLocal.owedPerDay).div(\n 86400\n );\n require(withdrawAmount < interestDepositRemaining, \"withdraw amount too high\");\n\n /// Withdraw interest.\n if (loanParamsLocal.loanToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, withdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.loanToken, receiver, withdrawAmount);\n }\n\n secondsReduced = withdrawAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n require(loanLocal.endTimestamp > secondsReduced, \"loan too short\");\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.sub(secondsReduced);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(withdrawAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .sub(withdrawAmount);\n }\n\n /**\n * @notice Get current lender interest data totals for all loans\n * with a specific oracle and interest token.\n *\n * @param lender The lender address.\n * @param loanToken The loan token address.\n *\n * @return interestPaid The total amount of interest that has been paid to a lender so far.\n * @return interestPaidDate The date of the last interest pay out, or 0 if no interest has been withdrawn yet.\n * @return interestOwedPerDay The amount of interest the lender is earning per day.\n * @return interestUnPaid The total amount of interest the lender is owned and not yet withdrawn.\n * @return interestFeePercent The fee retained by the protocol before interest is paid to the lender.\n * @return principalTotal The total amount of outstanding principal the lender has loaned.\n * */\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n )\n {\n LenderInterest memory lenderInterestLocal = lenderInterest[lender][loanToken];\n\n interestUnPaid = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(86400);\n if (interestUnPaid > lenderInterestLocal.owedTotal)\n interestUnPaid = lenderInterestLocal.owedTotal;\n\n return (\n lenderInterestLocal.paidTotal,\n lenderInterestLocal.paidTotal != 0 ? lenderInterestLocal.updatedTimestamp : 0,\n lenderInterestLocal.owedPerDay,\n lenderInterestLocal.updatedTimestamp != 0 ? interestUnPaid : 0,\n lendingFeePercent,\n lenderInterestLocal.principalTotal\n );\n }\n\n /**\n * @notice Get current interest data for a loan.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loanToken The loan token that interest is paid in.\n * @return interestOwedPerDay The amount of interest the borrower is paying per day.\n * @return interestDepositTotal The total amount of interest the borrower has deposited.\n * @return interestDepositRemaining The amount of deposited interest that is not yet owed to a lender.\n * */\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n )\n {\n loanToken = loanParams[loans[loanId].loanParamsId].loanToken;\n interestOwedPerDay = loanInterest[loanId].owedPerDay;\n interestDepositTotal = loanInterest[loanId].depositTotal;\n\n uint256 endTimestamp = loans[loanId].endTimestamp;\n uint256 interestTime = block.timestamp > endTimestamp ? endTimestamp : block.timestamp;\n interestDepositRemaining = endTimestamp > interestTime\n ? endTimestamp.sub(interestTime).mul(interestOwedPerDay).div(86400)\n : 0;\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData) {\n return\n _getLoan(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2) {\n return\n _getLoanV2(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get all active loans.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @dev New view function which will return the loan data.\n * @dev This function was created to support backward compatibility\n * @dev As in we the old getActiveLoans function is not expected to be changed by the wathcers.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loanData The data structure\n * @return extendedLoanData The data structure which contained (borrower & creation time)\n */\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Internal function to get one loan data structure.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ the loan information.\n * */\n function _getLoan(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnData memory loanData) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanData;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanData;\n }\n\n return\n LoanReturnData({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable\n });\n }\n\n /**\n * @notice Internal function to get one loan data structure v2.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data v2 structure w/ the loan information.\n * */\n function _getLoanV2(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnDataV2 memory loanDataV2) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanDataV2;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanDataV2;\n }\n\n return\n LoanReturnDataV2({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n borrower: loanLocal.borrower,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable,\n creationTimestamp: loanLocal.startTimestamp\n });\n }\n\n /**\n * @notice Internal function to collect interest from the collateral.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param depositAmount The amount of underlying tokens provided on the loan.\n * */\n function _doCollateralSwap(\n Loan storage loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 depositAmount\n ) internal returns (uint256 purchasedLoanToken) {\n /// Reverts in _loanSwap if amountNeeded can't be bought.\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanLocal.collateral, /// minSourceTokenAmount\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n depositAmount, /// requiredDestTokenAmount (partial spend of loanLocal.collateral to fill this amount)\n true, /// bypassFee\n \"\" /// loanDataBytes\n );\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n /// Ensure the loan is still healthy.\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n return destTokenAmountReceived;\n }\n}\n" + }, + "contracts/modules/LoanOpenings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\n/**\n * @title Loan Openings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to borrow and trade.\n * */\ncontract LoanOpenings is\n LoanOpeningsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n ModuleCommonFunctionalities\n{\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\n _setTarget(this.borrowOrTradeFromPool.selector, target);\n _setTarget(this.setDelegatedManager.selector, target);\n _setTarget(this.getEstimatedMarginExposure.selector, target);\n _setTarget(this.getRequiredCollateral.selector, target);\n _setTarget(this.getBorrowAmount.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanOpenings\");\n }\n\n /**\n * @notice Borrow or trade from pool.\n *\n * @dev Note: Only callable by loan pools (iTokens).\n * Wrapper to _borrowOrTrade internal function.\n *\n * @param loanParamsId The ID of the loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return newPrincipal The new loan size.\n * @return newCollateral The new collateral amount.\n * */\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n bytes calldata loanDataBytes\n )\n external\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 newPrincipal, uint256 newCollateral)\n {\n require(msg.value == 0 || loanDataBytes.length != 0, \"loanDataBytes required with ether\");\n\n /// Only callable by loan pools.\n require(loanPoolToUnderlying[msg.sender] != address(0), \"not authorized\");\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n /// Get required collateral.\n uint256 collateralAmountRequired =\n _getRequiredCollateral(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentValues.newPrincipal,\n initialMargin,\n isTorqueLoan\n );\n require(collateralAmountRequired != 0, \"collateral is 0\");\n\n return\n _borrowOrTrade(\n loanParamsLocal,\n loanId,\n isTorqueLoan,\n collateralAmountRequired,\n initialMargin,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @dev Wrapper for _setDelegatedManager internal function.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external whenNotPaused {\n require(loans[loanId].borrower == msg.sender, \"unauthorized\");\n\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\n }\n\n /**\n * @notice Get the estimated margin exposure.\n *\n * Margin is the money borrowed from a broker to purchase an investment\n * and is the difference between the total value of investment and the\n * loan amount. Margin trading refers to the practice of using borrowed\n * funds from a broker to trade a financial asset, which forms the\n * collateral for the loan from the broker.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param loanTokenSent The amount of loan tokens sent.\n * @param collateralTokenSent The amount of collateral tokens sent.\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\n * @param newPrincipal The updated amount of principal (current debt).\n *\n * @return The margin exposure.\n * */\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256) {\n uint256 maxLoanTerm = 2419200; // 28 days\n\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\n\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\n\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\n uint256 tradingFee = _getTradingFee(swapAmount);\n if (tradingFee != 0) {\n swapAmount = swapAmount.sub(tradingFee);\n }\n\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\n if (receivedAmount == 0) {\n return 0;\n } else {\n return collateralTokenSent.add(receivedAmount);\n }\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Calls internal _getRequiredCollateral and add fees.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralAmountRequired The required collateral.\n * */\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 collateralAmountRequired) {\n if (marginAmount != 0) {\n collateralAmountRequired = _getRequiredCollateral(\n loanToken,\n collateralToken,\n newPrincipal,\n marginAmount,\n isTorqueLoan\n );\n\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n // cannot be applied solely as it drives to some other tests failure\n /*\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (collateralAmountRequired != 0 && feePercent != 0) {\n\t\t\t\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t);\n\t\t\t}*/\n\n uint256 fee =\n isTorqueLoan\n ? _getBorrowingFee(collateralAmountRequired)\n : _getTradingFee(collateralAmountRequired);\n if (fee != 0) {\n collateralAmountRequired = collateralAmountRequired.add(fee);\n }\n }\n }\n\n /**\n * @notice Get the borrow amount of a trade loan.\n *\n * @dev Basically borrowAmount = collateral / marginAmount\n *\n * Collateral is something that helps secure a loan. When you borrow money,\n * you agree that your lender can take something and sell it to get their\n * money back if you fail to repay the loan. That's the collateral.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param collateralTokenAmount The amount of collateral.\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return borrowAmount The borrow amount.\n * */\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 borrowAmount) {\n if (marginAmount != 0) {\n if (isTorqueLoan) {\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\n }\n uint256 collateral = collateralTokenAmount;\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\n if (fee != 0) {\n collateral = collateral.sub(fee);\n }\n if (loanToken == collateralToken) {\n borrowAmount = collateral.mul(10**20).div(marginAmount);\n } else {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestPrecision != 0) {\n borrowAmount = collateral\n .mul(10**20)\n .mul(sourceToDestRate)\n .div(marginAmount)\n .div(sourceToDestPrecision);\n }\n }\n /*\n\t\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t\t// cannot be applied solely as it drives to some other tests failure\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (borrowAmount != 0 && feePercent != 0) {\n\t\t\t\tborrowAmount = borrowAmount\n\t\t\t\t\t.mul(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t)\n\t\t\t\t\t.divCeil(10**20);\n\t\t\t}*/\n }\n }\n\n /**\n * @notice Borrow or trade.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param collateralAmountRequired The required amount of collateral.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return The new loan size.\n * @return The new collateral amount.\n * */\n function _borrowOrTrade(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 collateralAmountRequired,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n require(\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\n \"collateral/loan match\"\n );\n require(initialMargin >= loanParamsLocal.minInitialMargin, \"initialMargin too low\");\n\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\n require(\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\n \"invalid interest\"\n );\n\n // @note this fix is for borrowing only\n uint256 sentNewPrincipal = isTorqueLoan ? sentValues.newPrincipal : 0;\n\n /// Initialize loan.\n Loan storage loanLocal =\n loans[\n _initializeLoan(\n loanParamsLocal,\n loanId,\n initialMargin,\n sentAddresses,\n sentValues.newPrincipal\n )\n ];\n\n // Get required interest.\n uint256 amount =\n _initializeInterest(\n loanParamsLocal,\n loanLocal,\n sentValues.interestRate, /// newRate\n sentValues.newPrincipal, /// newPrincipal,\n sentValues.interestInitialAmount /// torqueInterest\n );\n\n /// substract out interest from usable loanToken sent.\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\n\n if (isTorqueLoan) {\n require(sentValues.loanTokenSent == 0, \"surplus loan token\");\n\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\n // need to temp into local state to avoid\n address _collateralToken = loanParamsLocal.collateralToken;\n address _loanToken = loanParamsLocal.loanToken;\n if (borrowingFee != 0) {\n _payBorrowingFee(\n sentAddresses.borrower, /// borrower\n loanLocal.id,\n _collateralToken, /// fee token\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n borrowingFee\n );\n\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\n }\n } else {\n /// Update collateral after trade.\n sentValues = _updateCollateralAfterTrade(\n loanId,\n loanParamsLocal,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /// Settle collateral.\n require(\n _isCollateralSatisfied(\n loanParamsLocal,\n loanLocal,\n initialMargin,\n sentValues.collateralTokenSent,\n collateralAmountRequired,\n sentNewPrincipal\n ),\n \"collateral insufficient\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\n\n if (isTorqueLoan) {\n /// reclaiming variable -> interestDuration\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\n } else {\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\n }\n\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\n\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\n }\n\n function _updateCollateralAfterTrade(\n bytes32 loanId,\n LoanParams memory loanParamsLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (MarginTradeStructHelpers.SentAmounts memory) {\n uint256 receivedAmount;\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\n loanId,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentAddresses.borrower, /// borrower\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\n false, /// bypassFee\n loanDataBytes\n );\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\n\n /// Check the minEntryPrice with the rate\n require(\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\n \"entry price above the minimum\"\n );\n\n return sentValues;\n }\n\n /**\n * @notice Finalize an open loan.\n *\n * @dev Finalize it by updating local parameters of the loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _finalizeOpen(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bool isTorqueLoan\n ) internal {\n /// @dev TODO: here the actual used rate and margin should go.\n (uint256 initialMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(initialMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n if (loanLocal.startTimestamp == block.timestamp) {\n uint256 loanToCollateralPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken\n );\n uint256 collateralToLoanPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\n loanLocal.startRate = isTorqueLoan\n ? collateralToLoanRate\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\n }\n\n _emitOpeningEvents(\n loanParamsLocal,\n loanLocal,\n sentAddresses,\n sentValues,\n collateralToLoanRate,\n initialMargin,\n isTorqueLoan\n );\n }\n\n /**\n * @notice Emit the opening events.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n * @param margin The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _emitOpeningEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n uint256 collateralToLoanRate,\n uint256 margin,\n bool isTorqueLoan\n ) internal {\n if (isTorqueLoan) {\n emit Borrow(\n sentAddresses.borrower, /// user (borrower)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n sentValues.newPrincipal, /// newPrincipal\n sentValues.collateralTokenSent, /// newCollateral\n sentValues.interestRate, /// interestRate\n sentValues.interestDuration, /// interestDuration\n collateralToLoanRate, /// collateralToLoanRate,\n margin /// currentMargin\n );\n } else {\n /// currentLeverage = 100 / currentMargin\n margin = SafeMath.div(10**38, margin);\n\n emit Trade(\n sentAddresses.borrower, /// user (trader)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n sentValues.collateralTokenSent, /// positionSize\n sentValues.newPrincipal, /// borrowedAmount\n sentValues.interestRate, /// interestRate,\n loanLocal.endTimestamp, /// settlementDate\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\n sentValues.entryLeverage, /// entryLeverage\n margin /// currentLeverage\n );\n }\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegator The address of previous manager.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function _setDelegatedManager(\n bytes32 loanId,\n address delegator,\n address delegated,\n bool toggle\n ) internal {\n delegatedManagers[loanId][delegated] = toggle;\n\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\n }\n\n /**\n * @notice Calculate whether the collateral is satisfied.\n *\n * @dev Basically check collateral + drawdown >= 98% of required.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param initialMargin The initial amount of margin.\n * @param newCollateral The amount of new collateral.\n * @param collateralAmountRequired The amount of required collateral.\n * @param newPrincipal The amount to borrow.\n *\n * @return Whether the collateral is satisfied.\n * */\n function _isCollateralSatisfied(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 initialMargin,\n uint256 newCollateral,\n uint256 collateralAmountRequired,\n uint256 newPrincipal\n ) internal view returns (bool) {\n /// Allow at most 2% under-collateralized.\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\n\n if (newCollateral < collateralAmountRequired) {\n /// Check that existing collateral is sufficient coverage.\n if (loanLocal.collateral != 0) {\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal.sub(newPrincipal), // sub(newPrincipal) to exclude the new borrowed amount from the total principal to calculate maxDrawdown for existing loan\n loanLocal.collateral,\n initialMargin\n );\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\n } else {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @notice Initialize a loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan.\n * @param initialMargin The amount of margin of the trade.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\n * @return The loanId.\n * */\n function _initializeLoan(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n uint256 newPrincipal\n ) internal returns (bytes32) {\n require(loanParamsLocal.active, \"loanParams disabled\");\n\n address lender = sentAddresses.lender;\n address borrower = sentAddresses.borrower;\n address manager = sentAddresses.manager;\n\n Loan memory loanLocal;\n\n if (loanId == 0) {\n borrowerNonce[borrower]++;\n loanId = keccak256(\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\n );\n require(loans[loanId].id == 0, \"loan exists\");\n\n loanLocal = Loan({\n id: loanId,\n loanParamsId: loanParamsLocal.id,\n pendingTradesId: 0,\n active: true,\n principal: newPrincipal,\n collateral: 0, /// calculated later\n startTimestamp: block.timestamp,\n endTimestamp: 0, /// calculated later\n startMargin: initialMargin,\n startRate: 0, /// queried later\n borrower: borrower,\n lender: lender\n });\n\n activeLoansSet.addBytes32(loanId);\n lenderLoanSets[lender].addBytes32(loanId);\n borrowerLoanSets[borrower].addBytes32(loanId);\n } else {\n loanLocal = loans[loanId];\n require(\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\n \"loan has ended\"\n );\n require(loanLocal.borrower == borrower, \"borrower mismatch\");\n require(loanLocal.lender == lender, \"lender mismatch\");\n require(loanLocal.loanParamsId == loanParamsLocal.id, \"loanParams mismatch\");\n\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\n }\n\n if (manager != address(0)) {\n _setDelegatedManager(loanId, borrower, manager, true);\n }\n\n loans[loanId] = loanLocal;\n\n return loanId;\n }\n\n /**\n * @notice Initialize a loan interest.\n *\n * @dev A Torque loan is an indefinite-term loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param newRate The new interest rate of the loan.\n * @param newPrincipal The new principal amount of the loan.\n * @param torqueInterest The interest rate of the Torque loan.\n *\n * @return interestAmountRequired The interest amount required.\n * */\n function _initializeInterest(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n uint256 newRate,\n uint256 newPrincipal,\n uint256 torqueInterest /// ignored for fixed-term loans\n ) internal returns (uint256 interestAmountRequired) {\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 previousDepositRemaining;\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\n previousDepositRemaining = loanLocal\n .endTimestamp\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\n .mul(loanInterestLocal.owedPerDay)\n .div(86400);\n }\n\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\n\n /// Update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n\n if (maxLoanTerm == 0) {\n /// Indefinite-term (Torque) loan.\n\n /// torqueInterest != 0 was confirmed earlier.\n loanLocal.endTimestamp = torqueInterest\n .add(previousDepositRemaining)\n .mul(86400)\n .div(loanInterestLocal.owedPerDay)\n .add(block.timestamp);\n\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxLoanTerm > 3600, \"loan too short\");\n\n interestAmountRequired = torqueInterest;\n } else {\n /// Fixed-term loan.\n\n if (loanLocal.endTimestamp == 0) {\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\n }\n\n interestAmountRequired = loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(owedPerDay)\n .div(86400);\n }\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n /// Update remaining lender interest values.\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Basically collateral = newPrincipal * marginAmount\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralTokenAmount The required collateral.\n * */\n function _getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) internal view returns (uint256 collateralTokenAmount) {\n if (loanToken == collateralToken) {\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\n } else {\n /// Using the price feed instead of the swap expected return\n /// because we need the rate in the inverse direction\n /// so the swap is probably farther off than the price feed.\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestRate != 0) {\n collateralTokenAmount = newPrincipal\n .mul(sourceToDestPrecision)\n .div(sourceToDestRate)\n .mul(marginAmount)\n .div(10**20);\n /*TODO: review\n\t\t\t\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\n }\n }\n // ./tests/loan-token/TradingTestToken.test.js\n if (isTorqueLoan && collateralTokenAmount != 0) {\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\n collateralTokenAmount\n );\n }\n }\n}\n" + }, + "contracts/modules/LoanSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to get and set loan parameters.\n * */\ncontract LoanSettings is State, LoanSettingsEvents, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"LoanSettings - fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setupLoanParams.selector];\n _setTarget(this.setupLoanParams.selector, target);\n _setTarget(this.disableLoanParams.selector, target);\n _setTarget(this.getLoanParams.selector, target);\n _setTarget(this.getLoanParamsList.selector, target);\n _setTarget(this.getTotalPrincipal.selector, target);\n _setTarget(this.minInitialMargin.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanSettings\");\n }\n\n /**\n * @notice Setup loan parameters, by looping every loan\n * and populating its parameters.\n *\n * @dev For each loan calls _setupLoanParams internal function.\n *\n * @param loanParamsList The array of loan parameters.\n *\n * @return loanParamsIdList The array of loan parameters IDs.\n * */\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n whenNotPaused\n returns (bytes32[] memory loanParamsIdList)\n {\n loanParamsIdList = new bytes32[](loanParamsList.length);\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsIdList[i] = _setupLoanParams(loanParamsList[i]);\n }\n }\n\n /**\n * @notice Deactivate LoanParams for future loans. Active loans\n * using it are unaffected.\n *\n * @param loanParamsIdList The array of loan parameters IDs to deactivate.\n * */\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external whenNotPaused {\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n require(msg.sender == loanParams[loanParamsIdList[i]].owner, \"unauthorized owner\");\n loanParams[loanParamsIdList[i]].active = false;\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n emit LoanParamsDisabled(\n loanParamsLocal.id,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdDisabled(loanParamsLocal.id, loanParamsLocal.owner);\n }\n }\n\n /**\n * @notice Get loan parameters for every matching IDs.\n *\n * @param loanParamsIdList The array of loan parameters IDs to match.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParams(bytes32[] memory loanParamsIdList)\n public\n view\n returns (LoanParams[] memory loanParamsList)\n {\n loanParamsList = new LoanParams[](loanParamsIdList.length);\n uint256 itemCount;\n\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n if (loanParamsLocal.id == 0) {\n continue;\n }\n loanParamsList[itemCount] = loanParamsLocal;\n itemCount++;\n }\n\n if (itemCount < loanParamsList.length) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get loan parameters for an owner and a given page\n * defined by an offset and a limit.\n *\n * @param owner The address of the loan owner.\n * @param start The page offset.\n * @param count The page limit.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList) {\n EnumerableBytes32Set.Bytes32Set storage set = userLoanParamSets[owner];\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loanParamsList;\n }\n\n loanParamsList = new bytes32[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n loanParamsList[itemCount] = set.get(i + start - 1);\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get the total principal of the loans by a lender.\n *\n * @param lender The address of the lender.\n * @param loanToken The address of the token instance.\n *\n * @return The total principal of the loans.\n * */\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256) {\n return lenderInterest[lender][loanToken].principalTotal;\n }\n\n /**\n * @notice Setup a loan parameters.\n *\n * @param loanParamsLocal The loan parameters.\n *\n * @return loanParamsId The loan parameters ID.\n * */\n function _setupLoanParams(LoanParams memory loanParamsLocal) internal returns (bytes32) {\n bytes32 loanParamsId =\n keccak256(\n abi.encodePacked(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm,\n block.timestamp\n )\n );\n require(loanParams[loanParamsId].id == 0, \"loanParams exists\");\n\n require(\n loanParamsLocal.loanToken != address(0) &&\n loanParamsLocal.collateralToken != address(0) &&\n loanParamsLocal.minInitialMargin > loanParamsLocal.maintenanceMargin &&\n (loanParamsLocal.maxLoanTerm == 0 || loanParamsLocal.maxLoanTerm > 3600), /// A defined maxLoanTerm has to be greater than one hour.\n \"invalid params\"\n );\n\n loanParamsLocal.id = loanParamsId;\n loanParamsLocal.active = true;\n loanParamsLocal.owner = msg.sender;\n\n loanParams[loanParamsId] = loanParamsLocal;\n userLoanParamSets[msg.sender].addBytes32(loanParamsId);\n\n emit LoanParamsSetup(\n loanParamsId,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdSetup(loanParamsId, loanParamsLocal.owner);\n\n return loanParamsId;\n }\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256) {\n return loanParams[loanParamsId].minInitialMargin;\n }\n}\n" + }, + "contracts/modules/ProtocolSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../mixins/ProtocolTokenUser.sol\";\nimport \"../modules/interfaces/ProtocolSwapExternalInterface.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../swaps/ISwapsImpl.sol\";\nimport \"../governance/IFeeSharingCollector.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title Protocol Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to customize protocol settings.\n * */\ncontract ProtocolSettings is\n State,\n ProtocolTokenUser,\n ProtocolSettingsEvents,\n ModuleCommonFunctionalities\n{\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyAdminOrOwner {\n address prevModuleContractAddress = logicTargets[this.setPriceFeedContract.selector];\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n _setTarget(this.setRebatePercent.selector, target);\n _setTarget(this.setSpecialRebates.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.togglePaused.selector, target);\n _setTarget(this.isProtocolPaused.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n _setTarget(this.setRolloverFlexFeePercent.selector, target);\n _setTarget(this.getDefaultPathConversion.selector, target);\n _setTarget(this.setDefaultPathConversion.selector, target);\n _setTarget(this.removeDefaultPathConversion.selector, target);\n _setTarget(this.setAdmin.selector, target);\n _setTarget(this.getAdmin.selector, target);\n _setTarget(this.setPauser.selector, target);\n _setTarget(this.getPauser.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"ProtocolSettings\");\n }\n\n /**\n * setting wrong address will break inter module functions calling\n * should be set once\n */\n function setSovrynProtocolAddress(address newProtocolAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address oldProtocolAddress = protocolAddress;\n protocolAddress = newProtocolAddress;\n\n emit SetProtocolAddress(msg.sender, oldProtocolAddress, newProtocolAddress);\n }\n\n function setSOVTokenAddress(address newSovTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newSovTokenAddress), \"newSovTokenAddress not a contract\");\n\n address oldTokenAddress = sovTokenAddress;\n sovTokenAddress = newSovTokenAddress;\n\n emit SetSOVTokenAddress(msg.sender, oldTokenAddress, newSovTokenAddress);\n }\n\n function setLockedSOVAddress(address newLockedSOVAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newLockedSOVAddress), \"newLockSOVAddress not a contract\");\n\n address oldLockedSOVAddress = lockedSOVAddress;\n lockedSOVAddress = newLockedSOVAddress;\n\n emit SetLockedSOVAddress(msg.sender, oldLockedSOVAddress, newLockedSOVAddress);\n }\n\n /**\n * @notice Set the basis point of trading rebate rewards (SOV), max value is 9999 (99.99% liquid, 0.01% vested).\n *\n * @param newBasisPoint Basis point value.\n */\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newBasisPoint <= 9999, \"value too high\");\n\n uint256 oldBasisPoint = tradingRebateRewardsBasisPoint;\n tradingRebateRewardsBasisPoint = newBasisPoint;\n\n emit SetTradingRebateRewardsBasisPoint(msg.sender, oldBasisPoint, newBasisPoint);\n }\n\n /**\n * @notice Update the minimum number of referrals to get affiliates rewards.\n *\n * @param newMinReferrals The new minimum number of referrals.\n * */\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n uint256 oldMinReferrals = minReferralsToPayout;\n minReferralsToPayout = newMinReferrals;\n\n emit SetMinReferralsToPayoutAffiliates(msg.sender, oldMinReferrals, newMinReferrals);\n }\n\n /**\n * @notice Set the address of the Price Feed instance.\n *\n * @param newContract The address of the Price Feed new instance.\n * */\n function setPriceFeedContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = priceFeeds;\n priceFeeds = newContract;\n\n emit SetPriceFeedContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set the address of the asset swapper instance.\n *\n * @param newContract The address of the asset swapper new instance.\n * */\n function setSwapsImplContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = swapsImpl;\n swapsImpl = newContract;\n\n emit SetSwapsImplContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set a list of loan pools and its tokens.\n *\n * @param pools The array of addresses of new loan pool instances.\n * @param assets The array of addresses of the corresponding underlying tokens.\n * */\n function setLoanPool(address[] calldata pools, address[] calldata assets)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(pools.length == assets.length, \"count mismatch\");\n\n for (uint256 i = 0; i < pools.length; i++) {\n require(pools[i] != assets[i], \"pool == asset\");\n require(pools[i] != address(0), \"pool == 0\");\n require(\n assets[i] != address(0) || loanPoolToUnderlying[pools[i]] != address(0),\n \"pool not exists\"\n );\n if (assets[i] == address(0)) {\n underlyingToLoanPool[loanPoolToUnderlying[pools[i]]] = address(0);\n loanPoolToUnderlying[pools[i]] = address(0);\n loanPoolsSet.removeAddress(pools[i]);\n } else {\n loanPoolToUnderlying[pools[i]] = assets[i];\n underlyingToLoanPool[assets[i]] = pools[i];\n loanPoolsSet.addAddress(pools[i]);\n }\n\n emit SetLoanPool(msg.sender, pools[i], assets[i]);\n }\n }\n\n /**\n * @notice Set a list of supported tokens by populating the\n * storage supportedTokens mapping.\n *\n * @param addrs The array of addresses of the tokens.\n * @param toggles The array of flags indicating whether\n * the corresponding token is supported or not.\n * */\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(addrs.length == toggles.length, \"count mismatch\");\n\n for (uint256 i = 0; i < addrs.length; i++) {\n supportedTokens[addrs[i]] = toggles[i];\n\n emit SetSupportedTokens(msg.sender, addrs[i], toggles[i]);\n }\n }\n\n /**\n * @notice Set the value of lendingFeePercent storage variable.\n *\n * @param newValue The new value for lendingFeePercent.\n * */\n function setLendingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = lendingFeePercent;\n lendingFeePercent = newValue;\n\n emit SetLendingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of tradingFeePercent storage variable.\n *\n * @param newValue The new value for tradingFeePercent.\n * */\n function setTradingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = tradingFeePercent;\n tradingFeePercent = newValue;\n\n emit SetTradingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of borrowingFeePercent storage variable.\n *\n * @param newValue The new value for borrowingFeePercent.\n * */\n function setBorrowingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = borrowingFeePercent;\n borrowingFeePercent = newValue;\n\n emit SetBorrowingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of swapExtrernalFeePercent storage variable\n *\n * @param newValue the new value for swapExternalFeePercent\n */\n function setSwapExternalFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = swapExtrernalFeePercent;\n swapExtrernalFeePercent = newValue;\n\n emit SetSwapExternalFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateFeePercent storage variable.\n *\n * @param newValue The new value for affiliateFeePercent.\n * */\n function setAffiliateFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateFeePercent;\n affiliateFeePercent = newValue;\n\n emit SetAffiliateFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateTradingTokenFeePercent storage variable.\n *\n * @param newValue The new value for affiliateTradingTokenFeePercent.\n * */\n function setAffiliateTradingTokenFeePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateTradingTokenFeePercent;\n affiliateTradingTokenFeePercent = newValue;\n\n emit SetAffiliateTradingTokenFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of liquidationIncentivePercent storage variable.\n *\n * @param newValue The new value for liquidationIncentivePercent.\n * */\n function setLiquidationIncentivePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = liquidationIncentivePercent;\n liquidationIncentivePercent = newValue;\n\n emit SetLiquidationIncentivePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of the maximum swap spread.\n *\n * @param newValue The new value for maxDisagreement.\n * */\n function setMaxDisagreement(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n maxDisagreement = newValue;\n }\n\n /**\n * @notice Set the value of the maximum source buffer.\n *\n * @dev To avoid rounding issues on the swap rate a small buffer is implemented.\n *\n * @param newValue The new value for the maximum source buffer.\n * */\n function setSourceBuffer(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n sourceBuffer = newValue;\n }\n\n /**\n * @notice Set the value of the swap size limit.\n *\n * @param newValue The new value for the maximum swap size.\n * */\n function setMaxSwapSize(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n uint256 oldValue = maxSwapSize;\n maxSwapSize = newValue;\n\n emit SetMaxSwapSize(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the address of the feesController instance.\n *\n * @dev The fee sharing proxy must be the feesController of the\n * protocol contract. This allows the fee sharing proxy\n * to withdraw the fees.\n *\n * @param newController The new address of the feesController.\n * */\n function setFeesController(address newController) external onlyAdminOrOwner whenNotPaused {\n address oldController = feesController;\n feesController = newController;\n\n emit SetFeesController(msg.sender, oldController, newController);\n }\n\n /**\n * @notice Set the pauser address of sovryn protocol.\n *\n * only pauser or owner can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Get pauser address.\n *\n *\n * @return pauser address.\n */\n function getPauser() external view returns (address) {\n return pauser;\n }\n\n /*\n * @notice Set the admin address of sovryn protocol.\n *\n * only owner can perform this action.\n *\n * @param newAdmin The new address of the admin.\n * */\n function setAdmin(address newAdmin) external onlyOwner {\n emit SetAdmin(msg.sender, admin, newAdmin);\n admin = newAdmin;\n }\n\n /**\n * @dev Get admin address.\n *\n *\n * @return admin address.\n */\n function getAdmin() external view returns (address) {\n return admin;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * from three sources: lending, trading and borrowing.\n * The fees (except SOV) will be converted to wRBTC.\n * For SOV, it will be deposited directly to feeSharingCollector from the protocol.\n *\n * @param tokens The array of address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n whenNotPaused\n returns (uint256 totalWRBTCWithdrawn)\n {\n require(msg.sender == feesController, \"unauthorized\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n uint256 lendingBalance = lendingFeeTokensHeld[tokens[i]];\n if (lendingBalance > 0) {\n lendingFeeTokensHeld[tokens[i]] = 0;\n lendingFeeTokensPaid[tokens[i]] = lendingFeeTokensPaid[tokens[i]].add(\n lendingBalance\n );\n }\n\n uint256 tradingBalance = tradingFeeTokensHeld[tokens[i]];\n if (tradingBalance > 0) {\n tradingFeeTokensHeld[tokens[i]] = 0;\n tradingFeeTokensPaid[tokens[i]] = tradingFeeTokensPaid[tokens[i]].add(\n tradingBalance\n );\n }\n\n uint256 borrowingBalance = borrowingFeeTokensHeld[tokens[i]];\n if (borrowingBalance > 0) {\n borrowingFeeTokensHeld[tokens[i]] = 0;\n borrowingFeeTokensPaid[tokens[i]] = borrowingFeeTokensPaid[tokens[i]].add(\n borrowingBalance\n );\n }\n\n uint256 tempAmount = lendingBalance.add(tradingBalance).add(borrowingBalance);\n\n if (tempAmount == 0) {\n continue;\n }\n\n uint256 amountConvertedToWRBTC;\n if (tokens[i] == address(sovTokenAddress)) {\n IERC20(tokens[i]).approve(feesController, tempAmount);\n IFeeSharingCollector(feesController).transferTokens(\n address(sovTokenAddress),\n uint96(tempAmount)\n );\n amountConvertedToWRBTC = 0;\n } else {\n if (tokens[i] == address(wrbtcToken)) {\n amountConvertedToWRBTC = tempAmount;\n\n IERC20(address(wrbtcToken)).safeTransfer(receiver, amountConvertedToWRBTC);\n } else {\n IERC20(tokens[i]).approve(protocolAddress, tempAmount);\n\n (amountConvertedToWRBTC, ) = ProtocolSwapExternalInterface(protocolAddress)\n .swapExternal(\n tokens[i], // source token address\n address(wrbtcToken), // dest token address\n feesController, // set feeSharingCollector as receiver\n protocolAddress, // protocol as the sender\n tempAmount, // source token amount\n 0, // reqDestToken\n 0, // minReturn\n \"\" // loan data bytes\n );\n\n /// Will revert if disagreement found.\n IPriceFeeds(priceFeeds).checkPriceDisagreement(\n tokens[i],\n address(wrbtcToken),\n tempAmount,\n amountConvertedToWRBTC,\n maxDisagreement\n );\n }\n\n totalWRBTCWithdrawn = totalWRBTCWithdrawn.add(amountConvertedToWRBTC);\n }\n\n emit WithdrawFees(\n msg.sender,\n tokens[i],\n receiver,\n lendingBalance,\n tradingBalance,\n borrowingBalance,\n amountConvertedToWRBTC\n );\n }\n\n return totalWRBTCWithdrawn;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from lending operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = lendingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n lendingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n lendingFeeTokensPaid[token] = lendingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawLendingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from trading operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = tradingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n tradingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n tradingFeeTokensPaid[token] = tradingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawTradingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from borrowing operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = borrowingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n borrowingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n borrowingFeeTokensPaid[token] = borrowingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawBorrowingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The owner calls this function to withdraw protocol tokens.\n *\n * @dev Wrapper for ProtocolTokenUser::_withdrawProtocolToken internal function.\n *\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of tokens to get.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n onlyAdminOrOwner\n whenNotPaused\n returns (address, bool)\n {\n return _withdrawProtocolToken(receiver, amount);\n }\n\n /**\n * @notice The owner calls this function to deposit protocol tokens.\n *\n * @param amount The tokens of fees to send.\n * */\n function depositProtocolToken(uint256 amount) external onlyAdminOrOwner whenNotPaused {\n /// @dev Update local balance\n protocolTokenHeld = protocolTokenHeld.add(amount);\n\n /// @dev Send the tokens\n IERC20(protocolTokenAddress).safeTransferFrom(msg.sender, address(this), amount);\n }\n\n /**\n * @notice Get a list of loan pools.\n *\n * @param start The offset.\n * @param count The limit.\n *\n * @return The array of loan pools.\n * */\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory)\n {\n return loanPoolsSet.enumerate(start, count);\n }\n\n /**\n * @notice Check whether a token is a pool token.\n *\n * @dev By querying its underlying token.\n *\n * @param loanPool The token address to check.\n * */\n function isLoanPool(address loanPool) external view returns (bool) {\n return loanPoolToUnderlying[loanPool] != address(0);\n }\n\n /**\n * @notice Set the contract registry address of the SovrynSwap network.\n *\n * @param registryAddress the address of the registry contract.\n * */\n function setSovrynSwapContractRegistryAddress(address registryAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(registryAddress), \"registryAddress not a contract\");\n\n address oldSovrynSwapContractRegistryAddress = sovrynSwapContractRegistryAddress;\n sovrynSwapContractRegistryAddress = registryAddress;\n\n emit SetSovrynSwapContractRegistryAddress(\n msg.sender,\n oldSovrynSwapContractRegistryAddress,\n sovrynSwapContractRegistryAddress\n );\n }\n\n /**\n * @notice Set the wrBTC contract address.\n *\n * @param wrbtcTokenAddress The address of the wrBTC contract.\n * */\n function setWrbtcToken(address wrbtcTokenAddress) external onlyAdminOrOwner whenNotPaused {\n require(Address.isContract(wrbtcTokenAddress), \"wrbtcTokenAddress not a contract\");\n\n address oldwrbtcToken = address(wrbtcToken);\n wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n emit SetWrbtcToken(msg.sender, oldwrbtcToken, wrbtcTokenAddress);\n }\n\n /**\n * @notice Set the protocol token contract address.\n *\n * @param _protocolTokenAddress The address of the protocol token contract.\n * */\n function setProtocolTokenAddress(address _protocolTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n\n address oldProtocolTokenAddress = protocolTokenAddress;\n protocolTokenAddress = _protocolTokenAddress;\n\n emit SetProtocolTokenAddress(msg.sender, oldProtocolTokenAddress, _protocolTokenAddress);\n }\n\n /**\n * @notice Set rollover base reward. It should be denominated in wrBTC.\n *\n * @param baseRewardValue The base reward.\n * */\n function setRolloverBaseReward(uint256 baseRewardValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(baseRewardValue > 0, \"Base reward is zero\");\n\n uint256 oldValue = rolloverBaseReward;\n rolloverBaseReward = baseRewardValue;\n\n emit SetRolloverBaseReward(msg.sender, oldValue, rolloverBaseReward);\n }\n\n /**\n * @notice Set the fee rebate percent.\n *\n * @param rebatePercent The fee rebate percent.\n * */\n function setRebatePercent(uint256 rebatePercent) external onlyAdminOrOwner whenNotPaused {\n require(rebatePercent <= 10**20, \"Fee rebate is too high\");\n\n uint256 oldRebatePercent = feeRebatePercent;\n feeRebatePercent = rebatePercent;\n\n emit SetRebatePercent(msg.sender, oldRebatePercent, rebatePercent);\n }\n\n /**\n * @notice Set the special fee rebate percent for specific pair\n *\n * @param specialRebatesPercent The new special fee rebate percent.\n * */\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external onlyAdminOrOwner whenNotPaused {\n // Set max special rebates to 1000%\n require(specialRebatesPercent <= 1000e18, \"Special fee rebate is too high\");\n\n uint256 oldSpecialRebatesPercent = specialRebates[sourceToken][destToken];\n specialRebates[sourceToken][destToken] = specialRebatesPercent;\n\n emit SetSpecialRebates(\n msg.sender,\n sourceToken,\n destToken,\n oldSpecialRebatesPercent,\n specialRebatesPercent\n );\n }\n\n /**\n * @notice Get a rebate percent of specific pairs.\n *\n * @param sourceTokenAddress The source of pairs.\n * @param destTokenAddress The dest of pairs.\n *\n * @return The percent rebates of the pairs.\n * */\n function getSpecialRebates(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 specialRebatesPercent)\n {\n return specialRebates[sourceTokenAddress][destTokenAddress];\n }\n\n function getProtocolAddress() external view returns (address) {\n return protocolAddress;\n }\n\n function getSovTokenAddress() external view returns (address) {\n return sovTokenAddress;\n }\n\n function getLockedSOVAddress() external view returns (address) {\n return lockedSOVAddress;\n }\n\n function getFeeRebatePercent() external view returns (uint256) {\n return feeRebatePercent;\n }\n\n function togglePaused(bool paused) external onlyPauserOrOwner {\n require(paused != pause, \"Can't toggle\");\n pause = paused;\n emit TogglePaused(msg.sender, !paused, paused);\n }\n\n function isProtocolPaused() external view returns (bool) {\n return pause;\n }\n\n function getSwapExternalFeePercent() external view returns (uint256) {\n return swapExtrernalFeePercent;\n }\n\n /**\n * @notice Get the basis point of trading rebate rewards.\n *\n * @return The basis point value.\n */\n function getTradingRebateRewardsBasisPoint() external view returns (uint256) {\n return tradingRebateRewardsBasisPoint;\n }\n\n /**\n * @dev Get how much SOV that is dedicated to pay the trading rebate rewards.\n * @notice If SOV balance is less than the fees held, it will return 0.\n *\n * @return total dedicated SOV.\n */\n function getDedicatedSOVRebate() public view returns (uint256) {\n uint256 sovProtocolBalance = IERC20(sovTokenAddress).balanceOf(address(this));\n uint256 sovFees =\n lendingFeeTokensHeld[sovTokenAddress].add(tradingFeeTokensHeld[sovTokenAddress]).add(\n borrowingFeeTokensHeld[sovTokenAddress]\n );\n\n return sovProtocolBalance >= sovFees ? sovProtocolBalance.sub(sovFees) : 0;\n }\n\n /**\n * @notice Set rolloverFlexFeePercent (max value is 1%)\n *\n * @param newRolloverFlexFeePercent uint256 value of new rollover flex fee percentage (0.1 ether = 0.1%)\n */\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newRolloverFlexFeePercent <= 1e18, \"value too high\");\n uint256 oldRolloverFlexFeePercent = rolloverFlexFeePercent;\n rolloverFlexFeePercent = newRolloverFlexFeePercent;\n\n emit SetRolloverFlexFeePercent(\n msg.sender,\n oldRolloverFlexFeePercent,\n newRolloverFlexFeePercent\n );\n }\n\n /**\n * @dev Get default path conversion for pairs.\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address.\n *\n * @return default path of the conversion.\n */\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory)\n {\n return defaultPathConversion[sourceTokenAddress][destTokenAddress];\n }\n\n /**\n * @dev Set default path conversion for pairs.\n *\n * @param defaultPath array of addresses for the default path.\n *\n */\n function setDefaultPathConversion(IERC20[] calldata defaultPath)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address sourceTokenAddress = address(defaultPath[0]);\n address destTokenAddress = address(defaultPath[defaultPath.length - 1]);\n\n uint256 defaultPathLength = defaultPath.length;\n require(defaultPathLength >= 3, \"ERR_PATH_LENGTH\");\n\n for (uint256 i = 0; i < defaultPathLength; i++) {\n require(Address.isContract(address(defaultPath[i])), \"ERR_PATH_NON_CONTRACT_ADDR\");\n }\n\n defaultPathConversion[sourceTokenAddress][destTokenAddress] = defaultPath;\n\n emit SetDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPath\n );\n }\n\n /**\n * @dev Remove the default path conversion for pairs\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address\n */\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(\n defaultPathConversion[sourceTokenAddress][destTokenAddress].length > 0,\n \"DEFAULT_PATH_EMPTY\"\n );\n\n IERC20[] memory defaultPathValue =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n delete defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n emit RemoveDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPathValue\n );\n }\n}\n" + }, + "contracts/modules/SwapsExternal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../swaps/ISwapsImpl.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Swaps External contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to calculate and execute swaps.\n * */\ncontract SwapsExternal is VaultController, SwapsUser, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.swapExternal.selector];\n _setTarget(this.swapExternal.selector, target);\n _setTarget(this.getSwapExpectedReturn.selector, target);\n _setTarget(this.checkPriceDivergence.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"SwapsExternal\");\n }\n\n /**\n * @notice Perform a swap w/ tokens or rBTC as source currency.\n *\n * @dev External wrapper that calls SwapsUser::_swapsCall\n * after turning potential incoming rBTC into wrBTC tokens.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param receiver The address of the recipient account.\n * @param returnToSender The address of the sender account.\n * @param sourceTokenAmount The amount of source tokens.\n * @param requiredDestTokenAmount The amount of required destiny tokens.\n * @param minReturn Minimum amount (position size) in the collateral tokens.\n * @param swapData Additional swap data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes memory swapData\n )\n public\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(sourceTokenAmount != 0, \"sourceTokenAmount == 0\");\n checkPriceDivergence(sourceToken, destToken, sourceTokenAmount, minReturn);\n\n /// @dev Get payed value, be it rBTC or tokenized.\n if (msg.value != 0) {\n if (sourceToken == address(0)) {\n sourceToken = address(wrbtcToken);\n }\n require(sourceToken == address(wrbtcToken), \"sourceToken mismatch\");\n require(msg.value == sourceTokenAmount, \"sourceTokenAmount mismatch\");\n\n /// @dev Update wrBTC balance for this contract.\n wrbtcToken.deposit.value(sourceTokenAmount)();\n } else {\n if (address(this) != msg.sender) {\n IERC20(sourceToken).safeTransferFrom(msg.sender, address(this), sourceTokenAmount);\n }\n }\n\n /// @dev Perform the swap w/ tokens.\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n receiver,\n returnToSender,\n msg.sender /// user\n ],\n [\n sourceTokenAmount, /// minSourceTokenAmount\n sourceTokenAmount, /// maxSourceTokenAmount\n requiredDestTokenAmount\n ],\n 0, /// loanId (not tied to a specific loan)\n false, /// bypassFee\n swapData,\n true // the flag for swapExternal (so that it will use the swapExternalFeePercent)\n );\n\n emit ExternalSwap(\n msg.sender, /// user\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Get the swap expected return value.\n *\n * @dev External wrapper that calls SwapsUser::_swapsExpectedReturn\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n *\n * @return The expected return value.\n * */\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n }\n\n /**\n * @notice Check the slippage based on the swapExpectedReturn.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n * @param minReturn The amount (max slippage) that will be compared to the swapsExpectedReturn.\n *\n */\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view {\n uint256 destTokenAmount = _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n require(destTokenAmount >= minReturn, \"destTokenAmountReceived too low\");\n }\n}\n" + }, + "contracts/multisig/MultiSigKeyHolders.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/Ownable.sol\";\n\n/**\n * @title Multi Signature Key Holders contract.\n *\n * This contract contains the implementation of functions to add and remove\n * key holders w/ rBTC and BTC addresses.\n * */\ncontract MultiSigKeyHolders is Ownable {\n /* Storage */\n\n uint256 public constant MAX_OWNER_COUNT = 50;\n\n string private constant ERROR_INVALID_ADDRESS = \"Invalid address\";\n string private constant ERROR_INVALID_REQUIRED = \"Invalid required\";\n\n /// Flag and index for Ethereum address.\n mapping(address => Data) private isEthereumAddressAdded;\n\n /// List of Ethereum addresses.\n address[] private ethereumAddresses;\n\n /// Required number of signatures for the Ethereum multisig.\n uint256 public ethereumRequired = 2;\n\n /// Flag and index for Bitcoin address.\n mapping(string => Data) private isBitcoinAddressAdded;\n\n /// List of Bitcoin addresses.\n string[] private bitcoinAddresses;\n\n /// Required number of signatures for the Bitcoin multisig.\n uint256 public bitcoinRequired = 2;\n\n /// Helps removing items from array.\n struct Data {\n bool added;\n uint248 index;\n }\n\n /* Events */\n\n event EthereumAddressAdded(address indexed account);\n event EthereumAddressRemoved(address indexed account);\n event EthereumRequirementChanged(uint256 required);\n event BitcoinAddressAdded(string account);\n event BitcoinAddressRemoved(string account);\n event BitcoinRequirementChanged(uint256 required);\n\n /* Modifiers */\n\n modifier validRequirement(uint256 ownerCount, uint256 _required) {\n require(\n ownerCount <= MAX_OWNER_COUNT &&\n _required <= ownerCount &&\n _required != 0 &&\n ownerCount != 0,\n ERROR_INVALID_REQUIRED\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function addEthereumAddress(address _address) public onlyOwner {\n _addEthereumAddress(_address);\n }\n\n /**\n * @notice Add rBTC addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function _addEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (!isEthereumAddressAdded[_address].added) {\n isEthereumAddressAdded[_address] = Data({\n added: true,\n index: uint248(ethereumAddresses.length)\n });\n ethereumAddresses.push(_address);\n }\n\n emit EthereumAddressAdded(_address);\n }\n\n /**\n * @notice Remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeEthereumAddress(address _address) public onlyOwner {\n _removeEthereumAddress(_address);\n }\n\n /**\n * @notice Remove rBTC addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (isEthereumAddressAdded[_address].added) {\n uint248 index = isEthereumAddressAdded[_address].index;\n if (index != ethereumAddresses.length - 1) {\n ethereumAddresses[index] = ethereumAddresses[ethereumAddresses.length - 1];\n isEthereumAddressAdded[ethereumAddresses[index]].index = index;\n }\n ethereumAddresses.length--;\n delete isEthereumAddressAdded[_address];\n }\n\n emit EthereumAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether rBTC address is a key holder.\n * @param _address The rBTC address to be checked.\n * */\n function isEthereumAddressOwner(address _address) public view returns (bool) {\n return isEthereumAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of rBTC key holders.\n * */\n function getEthereumAddresses() public view returns (address[] memory) {\n return ethereumAddresses;\n }\n\n /**\n * @notice Set flag ethereumRequired to true/false.\n * @param _required The new value of the ethereumRequired flag.\n * */\n function changeEthereumRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(ethereumAddresses.length, _required)\n {\n ethereumRequired = _required;\n emit EthereumRequirementChanged(_required);\n }\n\n /**\n * @notice Add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function addBitcoinAddress(string memory _address) public onlyOwner {\n _addBitcoinAddress(_address);\n }\n\n /**\n * @notice Add bitcoin addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function _addBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (!isBitcoinAddressAdded[_address].added) {\n isBitcoinAddressAdded[_address] = Data({\n added: true,\n index: uint248(bitcoinAddresses.length)\n });\n bitcoinAddresses.push(_address);\n }\n\n emit BitcoinAddressAdded(_address);\n }\n\n /**\n * @notice Remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeBitcoinAddress(string memory _address) public onlyOwner {\n _removeBitcoinAddress(_address);\n }\n\n /**\n * @notice Remove bitcoin addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (isBitcoinAddressAdded[_address].added) {\n uint248 index = isBitcoinAddressAdded[_address].index;\n if (index != bitcoinAddresses.length - 1) {\n bitcoinAddresses[index] = bitcoinAddresses[bitcoinAddresses.length - 1];\n isBitcoinAddressAdded[bitcoinAddresses[index]].index = index;\n }\n bitcoinAddresses.length--;\n delete isBitcoinAddressAdded[_address];\n }\n\n emit BitcoinAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether bitcoin address is a key holder.\n * @param _address The bitcoin address to be checked.\n * */\n function isBitcoinAddressOwner(string memory _address) public view returns (bool) {\n return isBitcoinAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of bitcoin key holders.\n * */\n function getBitcoinAddresses() public view returns (string[] memory) {\n return bitcoinAddresses;\n }\n\n /**\n * @notice Set flag bitcoinRequired to true/false.\n * @param _required The new value of the bitcoinRequired flag.\n * */\n function changeBitcoinRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(bitcoinAddresses.length, _required)\n {\n bitcoinRequired = _required;\n emit BitcoinRequirementChanged(_required);\n }\n\n /**\n * @notice Add rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress the rBTC addresses to be added.\n * @param _bitcoinAddress the bitcoin addresses to be added.\n * */\n function addEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _addEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _addBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n\n /**\n * @notice Remove rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress The rBTC addresses to be removed.\n * @param _bitcoinAddress The bitcoin addresses to be removed.\n * */\n function removeEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _removeEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _removeBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n}\n" + }, + "contracts/openzeppelin/Address.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256('')`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n codehash := extcodehash(account)\n }\n return (codehash != accountHash && codehash != 0x0);\n }\n\n /**\n * @dev Converts an `address` into `address payable`. Note that this is\n * simply a type cast: the actual underlying value is not changed.\n *\n * _Available since v2.4.0._\n */\n function toPayable(address account) internal pure returns (address payable) {\n return address(uint160(account));\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n *\n * _Available since v2.4.0._\n */\n function sendValue(address recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-call-value\n (bool success, ) = recipient.call.value(amount)(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n}\n" + }, + "contracts/openzeppelin/Context.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n // Empty internal constructor, to prevent people from mistakenly deploying\n // an instance of this contract, which should be used via inheritance.\n constructor() internal {}\n\n // solhint-disable-previous-line no-empty-blocks\n\n function _msgSender() internal view returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n" + }, + "contracts/openzeppelin/ERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./Context.sol\";\nimport \"./IERC20_.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20Mintable}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20_ {\n using SafeMath for uint256;\n\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20};\n *\n * Requirements:\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for `sender`'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n _allowances[sender][_msgSender()].sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n _approve(\n _msgSender(),\n spender,\n _allowances[_msgSender()][spender].sub(\n subtractedValue,\n \"ERC20: decreased allowance below zero\"\n )\n );\n return true;\n }\n\n /**\n * @dev Moves tokens `amount` from `sender` to `recipient`.\n *\n * This is internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _balances[sender] = _balances[sender].sub(\n amount,\n \"ERC20: transfer amount exceeds balance\"\n );\n _balances[recipient] = _balances[recipient].add(amount);\n emit Transfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n *\n * This is internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`.`amount` is then deducted\n * from the caller's allowance.\n *\n * See {_burn} and {_approve}.\n */\n function _burnFrom(address account, uint256 amount) internal {\n _burn(account, amount);\n _approve(\n account,\n _msgSender(),\n _allowances[account][_msgSender()].sub(amount, \"ERC20: burn amount exceeds allowance\")\n );\n }\n}\n" + }, + "contracts/openzeppelin/ERC20Detailed.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20_.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n */\ncontract ERC20Detailed is IERC20_ {\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n */\n constructor(\n string memory name,\n string memory symbol,\n uint8 decimals\n ) public {\n _name = name;\n _symbol = symbol;\n _decimals = decimals;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/openzeppelin/IERC20_.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20_ {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/openzeppelin/Initializable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n */\ncontract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(_initializing || !_initialized, \"Initializable: contract is already initialized\");\n\n bool isTopLevelCall = !_initializing;\n if (isTopLevelCall) {\n _initializing = true;\n _initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n _initializing = false;\n }\n }\n}\n" + }, + "contracts/openzeppelin/Ownable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() public view returns (bool) {\n return _msgSender() == _owner;\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public onlyOwner {\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n */\n function _transferOwnership(address newOwner) internal {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n}\n" + }, + "contracts/openzeppelin/PausableOz.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./Ownable.sol\";\n\ncontract PausableOz is Ownable {\n /**\n * @dev Emitted when the pause is triggered by the owner (`account`).\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by the owner (`account`).\n */\n event Unpaused(address account);\n\n bool internal _paused;\n\n constructor() internal {}\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n */\n modifier whenNotPaused() {\n require(!_paused, \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n */\n modifier whenPaused() {\n require(_paused, \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/openzeppelin/ReentrancyGuard.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title Helps contracts guard against reentrancy attacks.\n * @author Remco Bloemen , Eenae \n * @dev If you mark a function `nonReentrant`, you should also\n * mark it `external`.\n */\ncontract ReentrancyGuard {\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n" + }, + "contracts/openzeppelin/SafeERC20.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./SafeMath.sol\";\nimport \"./Address.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\n );\n }\n\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n // solhint-disable-next-line max-line-length\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance =\n token.allowance(address(this), spender).sub(\n value,\n \"SafeERC20: decreased allowance below zero\"\n );\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves.\n\n // A Solidity high level call has three parts:\n // 1. The target address is checked to verify it contains contract code\n // 2. The call itself is made, and success asserted\n // 3. The return value is decoded, which in turn checks the size of the returned data.\n // solhint-disable-next-line max-line-length\n require(address(token).isContract(), \"SafeERC20: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(data);\n require(success, \"SafeERC20: low-level call failed\");\n\n if (returndata.length > 0) {\n // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "contracts/openzeppelin/SafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n *\n * _Available since v2.4.0._\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\n return divCeil(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n\n if (a == 0) {\n return 0;\n }\n uint256 c = ((a - 1) / b) + 1;\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\n return _a < _b ? _a : _b;\n }\n}\n" + }, + "contracts/openzeppelin/SignedSafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title SignedSafeMath\n * @dev Signed math operations with safety checks that revert on error.\n */\nlibrary SignedSafeMath {\n int256 private constant _INT256_MIN = -2**255;\n\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n require(!(a == -1 && b == _INT256_MIN), \"SignedSafeMath: multiplication overflow\");\n\n int256 c = a * b;\n require(c / a == b, \"SignedSafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n require(b != 0, \"SignedSafeMath: division by zero\");\n require(!(b == -1 && a == _INT256_MIN), \"SignedSafeMath: division overflow\");\n\n int256 c = a / b;\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a - b;\n require((b >= 0 && c <= a) || (b < 0 && c > a), \"SignedSafeMath: subtraction overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a + b;\n require((b >= 0 && c >= a) || (b < 0 && c < a), \"SignedSafeMath: addition overflow\");\n\n return c;\n }\n}\n" + }, + "contracts/proxy/modules/interfaces/IFunctionsList.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\ninterface IFunctionsList {\n function getFunctionsList() external pure returns (bytes4[] memory functionSignatures);\n}\n" + }, + "contracts/proxy/modules/interfaces/IModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\n/**\n * ModulesProxyRegistry Interface\n */\n\ncontract IModulesProxyRegistry {\n event AddModule(address indexed moduleAddress);\n event ReplaceModule(address indexed oldAddress, address indexed newAddress);\n event RemoveModule(address indexed moduleAddress);\n event SetModuleFuncImplementation(\n bytes4 indexed _funcSig,\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use ReplaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external;\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl) external;\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external;\n\n /// @notice to disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external;\n\n /// @param _sig function signature to get impmementation address for\n /// @return function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address);\n\n /// @notice verifies if no functions from the module deployed already registered\n /// @param _impl module implementation address to verify\n /// @return true if module can be added\n function canAddModule(address _impl) external view returns (bool);\n\n /// @notice Multiple modules verification if no functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return True if all modules can be added, false otherwise\n function canNotAddModules(address[] calldata _implementations)\n external\n view\n returns (address[] memory modules);\n\n /// @notice used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n );\n}\n" + }, + "contracts/proxy/modules/ModulesProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"./ModulesProxyRegistry.sol\";\n\n/**\n * ModulesProxy serves as a storage processed by a set of logic contracts - modules\n * Modules functions are registered in the contract's slots generated per func sig\n * All the function calls except for own Proxy functions are delegated to\n * the registered functions\n * The ModulesProxy is designed as a universal solution for refactorig contracts\n * reaching a 24K size limit (EIP-170)\n *\n * Upgradability is implemented at a module level to provide consistency\n * It does not allow to replace separate functions - only the whole module\n * meaning that if a module being registered contains other modules function signatures\n * then these modulea should be replaced completely - all the functions should be removed\n * to avoid leftovers or accidental replacements and therefore functional inconsistency.\n *\n * A module is either a new non-overlapping with registered modules\n * or a complete replacement of another registered module\n * in which case all the old module functions are unregistered and then\n * the new module functions are registered\n * There is also a separate function to unregister a module which unregisters all the functions\n * There is no option to unregister a subset of module functions - one should use pausable functionality\n * to achieve this\n */\n\ncontract ModulesProxy is ModulesProxyRegistry {\n // Uncomment for using beforeFallback() hook\n /*\n bytes private constant BEFORE_FALLBACK_SIG = abi.encodeWithSignature(\"beforeFallback()\");\n bytes4 private constant BEFORE_FALLBACK_SIG_BYTES4 = bytes4(keccak256(abi.encodePacked(\"beforeFallback()\")));\n */\n\n /**\n * @notice Fallback function delegates calls to modules.\n * Returns whatever the implementation call returns.\n * Has a hook to execute before delegating calls\n * To activate register a module with beforeFallback() function\n */\n function() external payable {\n /*\n // Commented to safe gas by default\n // Uncomment for using beforeFallback() hook \n // Implement and register beforeFallback() function in a module\n address beforeFallback = _getFuncImplementation(BEFORE_FALLBACK_SIG_BYTES4);\n if (beforeFallback != address(0)) {\n (bool success, ) = beforeFallback.delegatecall(bytes(0x39b0111a)); // abi.encodeWithSignature(\"beforeFallback()\")\n require(success, \"ModulesProxy::fallback: beforeFallback() fail\"); //MP02\n }\n */\n\n address target = _getFuncImplementation(msg.sig);\n require(target != address(0), \"ModulesProxy:target module not registered\"); // MP03\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/modules/ModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"../../utils/Utils.sol\";\nimport \"../../utils/ProxyOwnable.sol\";\nimport \"../modules/interfaces/IFunctionsList.sol\";\nimport \"../modules/interfaces/IModulesProxyRegistry.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * ModulesProxyRegistry provides modules registration/removing/replacing functionality to ModulesProxy\n * Designed to be inherited\n */\n\ncontract ModulesProxyRegistry is IModulesProxyRegistry, ProxyOwnable {\n using Address for address;\n\n bytes32 internal constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n\n ///@notice Constructor is internal to make contract abstract\n constructor() internal {\n // abstract\n }\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use replaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external onlyProxyOwner {\n _addModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external onlyProxyOwner {\n _addModules(_implementations);\n }\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl)\n external\n onlyProxyOwner\n {\n _replaceModule(_oldModuleImpl, _newModuleImpl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external onlyProxyOwner {\n require(\n _implementationsFrom.length == _implementationsTo.length,\n \"ModulesProxyRegistry::replaceModules: arrays sizes must be equal\"\n ); //MR10\n\n // because the order of addresses is arbitrary, all modules are removed first to avoid collisions\n _removeModules(_implementationsFrom);\n _addModules(_implementationsTo);\n }\n\n /// @notice To disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external onlyProxyOwner {\n _removeModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external onlyProxyOwner {\n _removeModules(_implementations);\n }\n\n /// @param _sig Function signature to get impmementation address for\n /// @return Function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address) {\n return _getFuncImplementation(_sig);\n }\n\n /// @notice Verifies if no functions from the module already registered\n /// @param _impl Module implementation address to verify\n /// @return True if module can be added\n function canAddModule(address _impl) external view returns (bool) {\n return _canAddModule(_impl);\n }\n\n /// @notice Multiple modules verification if there are functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return addresses of registered modules\n function canNotAddModules(address[] memory _implementations)\n public\n view\n returns (address[] memory)\n {\n for (uint256 i = 0; i < _implementations.length; i++) {\n if (_canAddModule(_implementations[i])) {\n delete _implementations[i];\n }\n }\n return _implementations;\n }\n\n /// @notice Used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return Clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n )\n {\n require(\n _newModule.isContract(),\n \"ModulesProxyRegistry::checkClashingFuncSelectors: address is not a contract\"\n ); //MR06\n bytes4[] memory newModuleFunctions = IFunctionsList(_newModule).getFunctionsList();\n bytes4[] memory proxyRegistryFunctions = _getFunctionsList(); //registry functions list\n uint256 clashingProxyRegistryFuncsSize;\n uint256 clashingArraySize;\n uint256 clashingArrayIndex;\n uint256 clashingRegistryArrayIndex;\n\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0) && funcImpl != _newModule) {\n clashingArraySize++;\n } else if (_isFuncClashingWithProxyFunctions(newModuleFunctions[i]))\n clashingProxyRegistryFuncsSize++;\n }\n clashingModules = new address[](clashingArraySize);\n clashingModulesFuncSelectors = new bytes4[](clashingArraySize);\n clashingProxyRegistryFuncSelectors = new bytes4[](clashingProxyRegistryFuncsSize);\n\n if (clashingArraySize == 0 && clashingProxyRegistryFuncsSize == 0)\n //return empty arrays\n return (\n clashingModules,\n clashingModulesFuncSelectors,\n clashingProxyRegistryFuncSelectors\n );\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0)) {\n clashingModules[clashingArrayIndex] = funcImpl;\n clashingModulesFuncSelectors[clashingArrayIndex] = newModuleFunctions[i];\n clashingArrayIndex++;\n }\n for (uint256 j = 0; j < proxyRegistryFunctions.length; j++) {\n //ModulesProxyRegistry has a clashing function selector\n if (proxyRegistryFunctions[j] == newModuleFunctions[i]) {\n clashingProxyRegistryFuncSelectors[\n clashingRegistryArrayIndex\n ] = proxyRegistryFunctions[j];\n clashingRegistryArrayIndex++;\n }\n }\n }\n }\n\n /// Verifies the deployed contract address is a registered module contract\n /// @param _impl deployment address to verify\n /// @return true if _impl address is a registered module\n function isModuleRegistered(address _impl) external view returns (bool) {\n return _getFirstRegisteredModuleAddress(_impl) == _impl;\n }\n\n /****************** INTERNAL FUNCTIONS ******************/\n\n function _getFirstRegisteredModuleAddress(address _impl) internal view returns (address) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_getRegisteredModuleAddress: address is not a contract\"\n );\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n address _moduleImpl = _getFuncImplementation(functions[i]);\n if (_moduleImpl != address(0)) {\n return (_moduleImpl);\n }\n }\n return address(0);\n }\n\n function _getFuncImplementation(bytes4 _sig) internal view returns (address) {\n //TODO: add querying Registry for logic address and then delegate call to it OR use proxy memory slots like this:\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n address implementation;\n assembly {\n implementation := sload(key)\n }\n return implementation;\n }\n\n function _addModule(address _impl) internal {\n require(_impl.isContract(), \"ModulesProxyRegistry::_addModule: address is not a contract\"); //MR01\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n require(\n _getFuncImplementation(functions[i]) == address(0),\n \"ModulesProxyRegistry::_addModule: function already registered - use replaceModule function\"\n ); //MR02\n require(functions[i] != bytes4(0), \"does not allow empty function id\"); // MR03\n require(\n !_isFuncClashingWithProxyFunctions(functions[i]),\n \"ModulesProxyRegistry::_addModule: has a function with the same signature\"\n ); //MR09\n _setModuleFuncImplementation(functions[i], _impl);\n }\n emit AddModule(_impl);\n }\n\n function _addModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _addModule(_implementations[i]);\n }\n }\n\n function _removeModule(address _impl) internal onlyProxyOwner {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_removeModule: address is not a contract\"\n ); //MR07\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n _setModuleFuncImplementation(functions[i], address(0));\n\n emit RemoveModule(_impl);\n }\n\n function _removeModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _removeModule(_implementations[i]);\n }\n }\n\n function _replaceModule(address _oldModuleImpl, address _newModuleImpl) internal {\n if (_oldModuleImpl != _newModuleImpl) {\n require(\n _newModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _newModuleImpl is not a contract\"\n ); //MR03\n require(\n _oldModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _oldModuleImpl is not a contract\"\n ); //MR04\n _removeModule(_oldModuleImpl);\n _addModule(_newModuleImpl);\n\n emit ReplaceModule(_oldModuleImpl, _newModuleImpl);\n }\n }\n\n function _setModuleFuncImplementation(bytes4 _sig, address _impl) internal {\n emit SetModuleFuncImplementation(_sig, _getFuncImplementation(_sig), _impl);\n\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n assembly {\n sstore(key, _impl)\n }\n }\n\n function _isFuncClashingWithProxyFunctions(bytes4 _sig) internal pure returns (bool) {\n bytes4[] memory functionList = _getFunctionsList();\n for (uint256 i = 0; i < functionList.length; i++) {\n if (_sig == functionList[i])\n //ModulesProxyRegistry has function with the same id\n return true;\n }\n return false;\n }\n\n function _canAddModule(address _impl) internal view returns (bool) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_canAddModule: address is not a contract\"\n ); //MR06\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n if (_getFuncImplementation(functions[i]) != address(0)) return (false);\n return true;\n }\n\n function _getFunctionsList() internal pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](13);\n functionList[0] = this.getFuncImplementation.selector;\n functionList[1] = this.addModule.selector;\n functionList[2] = this.addModules.selector;\n functionList[3] = this.removeModule.selector;\n functionList[4] = this.removeModules.selector;\n functionList[5] = this.replaceModule.selector;\n functionList[6] = this.replaceModules.selector;\n functionList[7] = this.canAddModule.selector;\n functionList[8] = this.canNotAddModules.selector;\n functionList[9] = this.setProxyOwner.selector;\n functionList[10] = this.getProxyOwner.selector;\n functionList[11] = this.checkClashingFuncSelectors.selector;\n functionList[12] = this.isModuleRegistered.selector;\n return functionList;\n }\n}\n" + }, + "contracts/proxy/Proxy.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base Proxy contract.\n * @notice The proxy performs delegated calls to the contract implementation\n * it is pointing to. This way upgradable contracts are possible on blockchain.\n *\n * Delegating proxy contracts are widely used for both upgradeability and gas\n * savings. These proxies rely on a logic contract (also known as implementation\n * contract or master copy) that is called using delegatecall. This allows\n * proxies to keep a persistent state (storage and balance) while the code is\n * delegated to the logic contract.\n *\n * Proxy contract is meant to be inherited and its internal functions\n * _setImplementation and _setProxyOwner to be called when upgrades become\n * neccessary.\n *\n * The loan token (iToken) contract as well as the protocol contract act as\n * proxies, delegating all calls to underlying contracts. Therefore, if you\n * want to interact with them using web3, you need to use the ABIs from the\n * contracts containing the actual logic or the interface contract.\n * ABI for LoanToken contracts: LoanTokenLogicStandard\n * ABI for Protocol contract: ISovryn\n *\n * @dev UpgradableProxy is the contract that inherits Proxy and wraps these\n * functions.\n * */\ncontract Proxy {\n bytes32 private constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);\n event ImplementationChanged(\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /**\n * @notice Set sender as an owner.\n * */\n constructor() public {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @notice Throw error if called not by an owner.\n * */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Proxy:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the implementation.\n * @param _implementation Address of the implementation.\n * */\n function _setImplementation(address _implementation) internal {\n require(_implementation != address(0), \"Proxy::setImplementation: invalid address\");\n emit ImplementationChanged(getImplementation(), _implementation);\n\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n sstore(key, _implementation)\n }\n }\n\n /**\n * @notice Return address of the implementation.\n * @return Address of the implementation.\n * */\n function getImplementation() public view returns (address _implementation) {\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n _implementation := sload(key)\n }\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"Proxy::setProxyOwner: invalid address\");\n emit OwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Return address of the owner.\n * @return Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n address implementation = getImplementation();\n require(implementation != address(0), \"Proxy::(): implementation not found\");\n\n assembly {\n let pointer := mload(0x40)\n calldatacopy(pointer, 0, calldatasize)\n let result := delegatecall(gas, implementation, pointer, calldatasize, 0, 0)\n let size := returndatasize\n returndatacopy(pointer, 0, size)\n\n switch result\n case 0 {\n revert(pointer, size)\n }\n default {\n return(pointer, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/UpgradableProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Proxy.sol\";\n\n/**\n * @title Upgradable Proxy contract.\n * @notice A disadvantage of the immutable ledger is that nobody can change the\n * source code of a smart contract after it’s been deployed. In order to fix\n * bugs or introduce new features, smart contracts need to be upgradable somehow.\n *\n * Although it is not possible to upgrade the code of an already deployed smart\n * contract, it is possible to set-up a proxy contract architecture that will\n * allow to use new deployed contracts as if the main logic had been upgraded.\n *\n * A proxy architecture pattern is such that all message calls go through a\n * Proxy contract that will redirect them to the latest deployed contract logic.\n * To upgrade, a new version of the contract is deployed, and the Proxy is\n * updated to reference the new contract address.\n * */\ncontract UpgradableProxy is Proxy {\n /**\n * @notice Set address of the implementation.\n * @dev Wrapper for _setImplementation that exposes the function\n * as public for owner to be able to set a new version of the\n * contract as current pointing implementation.\n * @param _implementation Address of the implementation.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n _setImplementation(_implementation);\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n}\n" + }, + "contracts/reentrancy/Mutex.sol": { + "content": "pragma solidity ^0.5.17;\n\n/*\n * @title Global Mutex contract\n *\n * @notice A mutex contract that allows only one function to be called at a time out\n * of a large set of functions. *Anyone* in the network can freely use any instance\n * of this contract to add a universal mutex to any function in any contract.\n */\ncontract Mutex {\n /*\n * We use an uint to store the mutex state.\n */\n uint256 public value;\n\n /*\n * @notice Increment the mutex state and return the new value.\n *\n * @dev This is the function that will be called by anyone to change the mutex\n * state. It is purposely not protected by any access control\n */\n function incrementAndGetValue() external returns (uint256) {\n /*\n * increment value using unsafe math. This is safe because we are\n * pretty certain no one will ever increment the value 2^256 times\n * in a single transaction.\n */\n return ++value;\n }\n}\n" + }, + "contracts/reentrancy/SharedReentrancyGuard.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Mutex.sol\";\n\n/*\n * @title Abstract contract for shared reentrancy guards\n *\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\n * that there's no reentrancy between *any* functions marked with the modifier.\n *\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\n */\ncontract SharedReentrancyGuard {\n /*\n * This is the address of the mutex contract that will be used as the\n * reentrancy guard.\n *\n * The address is hardcoded to avoid changing the memory layout of\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\n * because the Mutex contract is always deployed to the same address, with the\n * same method used in the deployment of ERC1820Registry.\n */\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\n\n /*\n * This is the modifier that will be used to protect functions from\n * reentrancy. It will call the mutex contract to increment the mutex\n * state and then revert if the mutex state was changed by another\n * nested call.\n */\n modifier globallyNonReentrant() {\n uint256 previous = MUTEX.incrementAndGetValue();\n\n _;\n\n /*\n * If the mutex state was changed by a nested function call, then\n * the value of the state variable will be different from the previous value.\n */\n require(previous == MUTEX.value(), \"reentrancy violation\");\n }\n}\n" + }, + "contracts/rsk/RSKAddrValidator.sol": { + "content": "// SPDX-License-Identifier:MIT\npragma solidity ^0.5.17;\n\nlibrary RSKAddrValidator {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n * */\n function checkPKNotZero(address addr) internal pure returns (bool) {\n return (addr != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && addr != address(0));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key.\n * */\n function safeEquals(address addr1, address addr2) internal pure returns (bool) {\n return (addr1 == addr2 &&\n addr1 != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\n addr1 != address(0));\n }\n}\n" + }, + "contracts/swaps/connectors/interfaces/IContractRegistry.sol": { + "content": "pragma solidity 0.5.17;\n\ncontract IContractRegistry {\n function addressOf(bytes32 contractName) public view returns (address);\n}\n" + }, + "contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol": { + "content": "pragma solidity >=0.5.8 <=0.5.17;\n\nimport \"../../../interfaces/IERC20.sol\";\n\ncontract ISovrynSwapNetwork {\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256);\n\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\n\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory);\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwap.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../../core/State.sol\";\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"../ISwapsImpl.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\n\n/**\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\ncontract SwapsImplSovrynSwap is State, ISwapsImpl {\n using SafeERC20 for IERC20;\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destination tokens.\n * @param receiverAddress The address who will received the swap token results\n * @param returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * @param minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * @param maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address receiverAddress,\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n require(\n supportedTokens[sourceTokenAddress] && supportedTokens[destTokenAddress],\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = estimateSourceTokenAmount(\n sourceTokenAddress,\n destTokenAddress,\n requiredDestTokenAmount,\n maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n allowTransfer(sourceTokenAmountUsed, sourceTokenAddress, address(sovrynSwapNetwork));\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n uint256 sourceToDestPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n internalExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n maxSourceTokenAmount,\n sovrynSwapContractRegistryAddress\n );\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > sourceBuffer) buffer = sourceBuffer;\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistryAddress\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * @param sovrynSwapContractRegistry The sovryn swap contract reigstry address.\n * @param defaultPath The default path for specific pairs.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistry,\n IERC20[] memory defaultPath\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistry);\n\n IERC20[] memory path =\n defaultPath.length >= 3\n ? defaultPath\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/testnet/SwapsImplLocal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../../core/State.sol\";\nimport \"../../../openzeppelin/SafeERC20.sol\";\nimport \"../../ISwapsImpl.sol\";\nimport \"../../../feeds/IPriceFeeds.sol\";\nimport \"../../../testhelpers/TestToken.sol\";\n\n/**\n * @title Swaps Implementation Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate calculations.\n * */\ncontract SwapsImplLocal is State, ISwapsImpl {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Swap two tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address, /*receiverAddress*/\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n\n (uint256 tradeRate, uint256 precision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n if (requiredDestTokenAmount == 0) {\n sourceTokenAmountUsed = minSourceTokenAmount;\n destTokenAmountReceived = minSourceTokenAmount.mul(tradeRate).div(precision);\n } else {\n destTokenAmountReceived = requiredDestTokenAmount;\n sourceTokenAmountUsed = requiredDestTokenAmount.mul(precision).div(tradeRate);\n require(sourceTokenAmountUsed <= minSourceTokenAmount, \"destAmount too great\");\n }\n\n TestToken(sourceTokenAddress).burn(address(this), sourceTokenAmountUsed);\n TestToken(destTokenAddress).mint(address(this), destTokenAmountReceived);\n\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Calculate the expected price rate of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n *\n * @return precision The expected price rate.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * @notice Calculate the expected return of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n * @param defaultPath defaultPath for swap.\n *\n * @return precision The expected return.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused,\n IERC20[] memory defaultPath\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n}\n" + }, + "contracts/swaps/ISwapsImpl.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../interfaces/IERC20.sol\";\n\ninterface ISwapsImpl {\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address receiverAddress,\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) external payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address optionalContractAddress\n ) external view returns (uint256);\n\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistryAddress,\n IERC20[] calldata defaultPath\n ) external view returns (uint256 expectedReturn);\n}\n" + }, + "contracts/swaps/SwapsUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../mixins/FeesHelper.sol\";\nimport \"./ISwapsImpl.sol\";\n\n/**\n * @title Perform token swaps for loans and trades.\n * */\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\n /**\n * @notice Internal loan swap.\n *\n * @param loanId The ID of the loan.\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of destiny tokens.\n * @param user The user address.\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * @param bypassFee To bypass or not the fee.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived\n * @return sourceTokenAmountUsed\n * @return sourceToDestSwapRate\n * */\n function _loanSwap(\n bytes32 loanId,\n address sourceToken,\n address destToken,\n address user,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount,\n bool bypassFee,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 sourceToDestSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n address(this), // receiver\n address(this), // returnToSender\n user\n ],\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\n loanId,\n bypassFee,\n loanDataBytes,\n false // swap external flag, set to false so that it will use the tradingFeePercent\n );\n\n /// Will revert if swap size too large.\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\n\n /// Will revert if disagreement found.\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived,\n maxDisagreement\n );\n\n emit LoanSwap(\n loanId,\n sourceToken,\n destToken,\n user,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Calculate amount of source and destiny tokens.\n *\n * @dev Wrapper for _swapsCall_internal function.\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n * @param loanId The Id of the associated loan.\n * @param miscBool True/false to bypassFee.\n * @param loanDataBytes Additional loan data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall(\n address[5] memory addrs,\n uint256[3] memory vals,\n bytes32 loanId,\n bool miscBool, /// bypassFee\n bytes memory loanDataBytes,\n bool isSwapExternal\n ) internal returns (uint256, uint256) {\n /// addrs[0]: sourceToken\n /// addrs[1]: destToken\n /// addrs[2]: receiver\n /// addrs[3]: returnToSender\n /// addrs[4]: user\n /// vals[0]: minSourceTokenAmount\n /// vals[1]: maxSourceTokenAmount\n /// vals[2]: requiredDestTokenAmount\n\n require(vals[0] != 0 || vals[1] != 0, \"min or max source token amount needs to be set\");\n\n if (vals[1] == 0) {\n vals[1] = vals[0];\n }\n require(vals[0] <= vals[1], \"sourceAmount larger than max\");\n\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n\n uint256 tradingFee;\n if (!miscBool) {\n /// bypassFee\n if (vals[2] == 0) {\n /// condition: vals[0] will always be used as sourceAmount\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[0]);\n } else {\n tradingFee = _getTradingFee(vals[0]);\n }\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId,\n addrs[0], /// sourceToken (feeToken)\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n vals[0] = vals[0].sub(tradingFee);\n }\n } else {\n /// Condition: unknown sourceAmount will be used.\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[2]);\n } else {\n tradingFee = _getTradingFee(vals[2]);\n }\n\n if (tradingFee != 0) {\n vals[2] = vals[2].add(tradingFee);\n }\n }\n }\n\n require(loanDataBytes.length == 0, \"invalid state\");\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\n\n if (vals[2] == 0) {\n /// There's no minimum destTokenAmount, but all of vals[0]\n /// (minSourceTokenAmount) must be spent.\n require(sourceTokenAmountUsed == vals[0], \"swap too large to fill\");\n\n if (tradingFee != 0) {\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\n }\n } else {\n /// There's a minimum destTokenAmount required, but\n /// sourceTokenAmountUsed won't be greater\n /// than vals[1] (maxSourceTokenAmount)\n require(sourceTokenAmountUsed <= vals[1], \"swap fill too large\");\n require(destTokenAmountReceived >= vals[2], \"insufficient swap liquidity\");\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId, /// loanId,\n addrs[1], /// destToken (feeToken)\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\n }\n }\n\n return (destTokenAmountReceived, sourceTokenAmountUsed);\n }\n\n /**\n * @notice Calculate amount of source and destiny tokens.\n *\n * @dev Calls swapsImpl::internalSwap\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\n internal\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n bytes memory data =\n abi.encodeWithSelector(\n ISwapsImpl(swapsImpl).internalSwap.selector,\n addrs[0], /// sourceToken\n addrs[1], /// destToken\n addrs[2], /// receiverAddress\n addrs[3], /// returnToSenderAddress\n vals[0], /// minSourceTokenAmount\n vals[1], /// maxSourceTokenAmount\n vals[2] /// requiredDestTokenAmount\n );\n\n bool success;\n (success, data) = swapsImpl.delegatecall(data);\n require(success, \"swap failed\");\n\n assembly {\n destTokenAmountReceived := mload(add(data, 32))\n sourceTokenAmountUsed := mload(add(data, 64))\n }\n }\n\n /**\n * @notice Calculate expected amount of destiny tokens.\n *\n * @dev Calls swapsImpl::internalExpectedReturn\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceTokenAmount The amount of the source tokens.\n *\n * @param destTokenAmount The amount of destiny tokens.\n * */\n function _swapsExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) internal view returns (uint256 destTokenAmount) {\n destTokenAmount = ISwapsImpl(swapsImpl).internalExpectedReturn(\n sourceToken,\n destToken,\n sourceTokenAmount,\n sovrynSwapContractRegistryAddress,\n defaultPathConversion[sourceToken][destToken]\n );\n }\n\n /**\n * @notice Verify that the amount of tokens are under the swap limit.\n *\n * @dev Calls priceFeeds::amountInEth\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n * */\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\n uint256 _maxSwapSize = maxSwapSize;\n if (_maxSwapSize != 0) {\n uint256 amountInEth;\n if (tokenAddress == address(wrbtcToken)) {\n amountInEth = amount;\n } else {\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\n }\n require(amountInEth <= _maxSwapSize, \"swap too large\");\n }\n }\n}\n" + }, + "contracts/testhelpers/FlashLoanerTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n// \"SPDX-License-Identifier: Apache-2.0\"\n\nimport \"../interfaces/IERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./ITokenFlashLoanTest.sol\";\n\ncontract FlashLoanerTest is Ownable {\n function initiateFlashLoanTest(\n address loanToken,\n address iToken,\n uint256 flashLoanAmount\n ) internal returns (bytes memory success) {\n ITokenFlashLoanTest iTokenContract = ITokenFlashLoanTest(iToken);\n return\n iTokenContract.flashBorrow(\n flashLoanAmount,\n address(this),\n address(this),\n \"\",\n abi.encodeWithSignature(\n \"executeOperation(address,address,uint256)\",\n loanToken,\n iToken,\n flashLoanAmount\n )\n );\n }\n\n function repayFlashLoan(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) internal {\n IERC20(loanToken).transfer(iToken, loanAmount);\n }\n\n function executeOperation(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) external returns (bytes memory success) {\n emit BalanceOf(IERC20(loanToken).balanceOf(address(this)));\n emit ExecuteOperation(loanToken, iToken, loanAmount);\n repayFlashLoan(loanToken, iToken, loanAmount);\n return bytes(\"1\");\n }\n\n function doStuffWithFlashLoan(\n address token,\n address iToken,\n uint256 amount\n ) external onlyOwner {\n bytes memory result;\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n result = initiateFlashLoanTest(token, iToken, amount);\n\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n // after loan checks and what not.\n if (hashCompareWithLengthCheck(bytes(\"1\"), result)) {\n revert(\"failed executeOperation\");\n }\n }\n\n function hashCompareWithLengthCheck(bytes memory a, bytes memory b)\n internal\n pure\n returns (bool)\n {\n if (a.length != b.length) {\n return false;\n } else {\n return keccak256(a) == keccak256(b);\n }\n }\n\n event ExecuteOperation(address loanToken, address iToken, uint256 loanAmount);\n\n event BalanceOf(uint256 balance);\n}\n" + }, + "contracts/testhelpers/interfaces/IERC1820Registry.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the global ERC1820 Registry, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register\n * implementers for interfaces in this registry, as well as query support.\n *\n * Implementers may be shared by multiple accounts, and can also implement more\n * than a single interface for each account. Contracts can implement interfaces\n * for themselves, but externally-owned accounts (EOA) must delegate this to a\n * contract.\n *\n * {IERC165} interfaces can also be queried via the registry.\n *\n * For an in-depth explanation and source code analysis, see the EIP text.\n */\ninterface IERC1820Registry {\n /**\n * @dev Sets `newManager` as the manager for `account`. A manager of an\n * account is able to set interface implementers for it.\n *\n * By default, each account is its own manager. Passing a value of `0x0` in\n * `newManager` will reset the manager to this initial state.\n *\n * Emits a {ManagerChanged} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n */\n function setManager(address account, address newManager) external;\n\n /**\n * @dev Returns the manager for `account`.\n *\n * See {setManager}.\n */\n function getManager(address account) external view returns (address);\n\n /**\n * @dev Sets the `implementer` contract as `account`'s implementer for\n * `interfaceHash`.\n *\n * `account` being the zero address is an alias for the caller's address.\n * The zero address can also be used in `implementer` to remove an old one.\n *\n * See {interfaceHash} to learn how these are created.\n *\n * Emits an {InterfaceImplementerSet} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not\n * end in 28 zeroes).\n * - `implementer` must implement {IERC1820Implementer} and return true when\n * queried for support, unless `implementer` is the caller. See\n * {IERC1820Implementer-canImplementInterfaceForAddress}.\n */\n function setInterfaceImplementer(\n address account,\n bytes32 interfaceHash,\n address implementer\n ) external;\n\n /**\n * @dev Returns the implementer of `interfaceHash` for `account`. If no such\n * implementer is registered, returns the zero address.\n *\n * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28\n * zeroes), `account` will be queried for support of it.\n *\n * `account` being the zero address is an alias for the caller's address.\n */\n function getInterfaceImplementer(address account, bytes32 interfaceHash)\n external\n view\n returns (address);\n\n /**\n * @dev Returns the interface hash for an `interfaceName`, as defined in the\n * corresponding\n * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].\n */\n function interfaceHash(string calldata interfaceName) external pure returns (bytes32);\n\n /**\n * @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n * @param account Address of the contract for which to update the cache.\n * @param interfaceId ERC165 interface for which to update the cache.\n */\n function updateERC165Cache(address account, bytes4 interfaceId) external;\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not.\n * If the result is not cached a direct lookup on the contract address is performed.\n * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n * {updateERC165Cache} with the contract address.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165Interface(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n event InterfaceImplementerSet(\n address indexed account,\n bytes32 indexed interfaceHash,\n address indexed implementer\n );\n\n event ManagerChanged(address indexed account, address indexed newManager);\n}\n" + }, + "contracts/testhelpers/ITokenFlashLoanTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n// \"SPDX-License-Identifier: Apache-2.0\"\n\ninterface ITokenFlashLoanTest {\n function flashBorrow(\n uint256 borrowAmount,\n address borrower,\n address target,\n string calldata signature,\n bytes calldata data\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/testhelpers/LoanTokenLogicTest.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicTest is LoanTokenLogic {\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestNonReentrantValueSetter.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\ncontract TestNonReentrantValueSetter is SharedReentrancyGuard {\n uint256 public value;\n\n // This will fail if another globallyNonReentrant function has already been entered\n function setValue(uint256 newValue) public globallyNonReentrant {\n value = newValue;\n }\n\n // this will always fail if `other.setValue` is globallyNonReentrant\n function setOtherContractValueNonReentrant(address other, uint256 newValue)\n external\n globallyNonReentrant\n {\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n\n // this is intentionally not globallyNonReentrant and should work even if both contracts are non-reentrant\n function setThisAndOtherContractValue(address other, uint256 newValue) external {\n setValue(newValue);\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestValueSetterProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract TestValueSetterProxy is UpgradableProxy {\n // This is here for the memory layout\n uint256 public value;\n}\n" + }, + "contracts/testhelpers/staking/StakingTester.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../TestToken.sol\";\n\ncontract StakingTester {\n IStaking public staking;\n TestToken public token;\n\n constructor(address _staking, address _token) public {\n staking = IStaking(_staking);\n token = TestToken(_token);\n }\n\n function stakeAndWithdraw(uint96 _amount, uint256 _until) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _until, address(this), address(this));\n staking.withdraw(_amount, _until, address(this));\n }\n\n function stakeAndDelegate(\n uint96 _amount,\n address _delegatee,\n uint256 _lockDate\n ) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _lockDate, address(this), address(this));\n staking.delegate(_delegatee, _lockDate);\n }\n}\n" + }, + "contracts/testhelpers/TestCoverage.sol": { + "content": "/**\n * In order to test some functionalities like Pausable::pausable() modifier,\n * it is required to add a contract to invoke them and get a full coverage on tests.\n */\n\npragma solidity 0.5.17;\n\nimport \"../connectors/loantoken/Pausable.sol\";\nimport \"../governance/Staking/SafeMath96.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../connectors/loantoken/AdvancedToken.sol\";\nimport \"../connectors/loantoken/LoanTokenLogicStorage.sol\";\n\ncontract TestCoverage is\n Pausable,\n SafeMath96,\n VaultController,\n AdvancedToken,\n LoanTokenLogicStorage\n{\n /// @dev Pausable is currently an unused contract that still is operative\n /// because margin trade flashloan functionality has been commented out.\n /// In case it were restored, contract would become used again, so for a\n /// complete test coverage it is required to test it.\n\n function dummyPausableFunction() external pausable(msg.sig) {\n /// @dev do nothing, just to check if modifier is working\n }\n\n /// @dev This function should be located on Pausable contract in the case\n /// it has to be used again by flashloan restoration.\n function togglePause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047)\n )\n );\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /// @dev Testing internal functions of governance/Staking/SafeMath96.sol\n function testSafeMath96_safe32(uint256 n) public pure returns (uint32) {\n // Public wrapper for SafeMath96 internal function\n return safe32(n, \"overflow\");\n }\n\n function testSafeMath96_safe64(uint256 n) public pure returns (uint64) {\n // Public wrapper for SafeMath96 internal function\n return safe64(n, \"overflow\");\n }\n\n function testSafeMath96_safe96(uint256 n) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return safe96(n, \"overflow\");\n }\n\n function testSafeMath96_sub96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return sub96(a, b, \"underflow\");\n }\n\n function testSafeMath96_mul96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return mul96(a, b, \"overflow\");\n }\n\n function testSafeMath96_div96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return div96(a, b, \"division by 0\");\n }\n\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;\n EnumerableBytes32Set.Bytes32Set internal aSet;\n\n function testEnum_AddRemove(bytes32 a, bytes32 b) public returns (bool) {\n aSet.addBytes32(a);\n return aSet.removeBytes32(b);\n }\n\n function testEnum_AddAddress(address a, address b) public returns (bool) {\n aSet.addAddress(a);\n return aSet.containsAddress(b);\n }\n\n function testEnum_AddAddressesAndEnumerate(\n address a,\n address b,\n uint256 start,\n uint256 count\n ) public returns (bytes32[] memory) {\n aSet.addAddress(a);\n aSet.addAddress(b);\n return aSet.enumerate(start, count);\n }\n\n /// @dev Wrapper to test internal function never called along current codebase\n function testVaultController_vaultApprove(\n address token,\n address to,\n uint256 value\n ) public {\n vaultApprove(token, to, value);\n }\n\n /// @dev mint wrapper w/o previous checks\n function testMint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) public {\n _mint(_to, _tokenAmount, _assetAmount, _price);\n }\n\n /// @dev wrapper for a function unreachable to tests\n function testStringToBytes32(string memory source) public pure returns (bytes32 result) {\n return stringToBytes32(source);\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some ERC777 from the lending pool.\n * 2. Close the loan with closeWithDeposit function in the protocol.\n * 3. Burn all iERC777.\n *\n * The cross-reentrancy happened in step#3. It might happened through a hook function (tokensToSend) that is implemented in this contract to support the ERC777 transfer.\n * Inside the hook function, it will try to mint the iERC777.\n * The details about the hook functions can be found here: https://eips.ethereum.org/EIPS/eip-777#hooks\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithDeposit function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyERC777 {\n address public loanToken;\n address public WRBTC;\n address public SUSD; /// ERC777\n ProtocolLike public sovrynProtocol;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iUSDTBalance;\n }\n\n function() external payable {}\n\n constructor(\n address _loanToken,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanToken = _loanToken;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777TokensSender\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: WRBTC has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n });\n\n IERC20(WRBTC).approve(loanToken, initial.susdBalance);\n\n ILoanTokenModules(loanToken).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n WRBTC,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanToken).loanParamsIds(\n uint256(keccak256(abi.encodePacked(WRBTC, true)))\n );\n bytes32 loan_id =\n keccak256(abi.encodePacked(loanParamsLocalId, loanToken, _borrower, _borrowerNonce));\n\n // STEP 3 close the borrowed position with a deposit\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(address(sovrynProtocol), _SUSDBalance);\n sovrynProtocol.closeWithDeposit(\n loan_id,\n address(this),\n collateralTokenSent.mul(20).div(100) // make it 20% higher from initial borrow amount\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iSUSD\n uint256 _iSUSDBalance = ILoanTokenModules(loanToken).balanceOf(_borrower);\n ILoanTokenModules(loanToken).burn(_receiver, _iSUSDBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n // });\n }\n\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256,\n bytes calldata,\n bytes calldata\n ) external {\n if (operator == address(sovrynProtocol) && to == loanToken && from == address(this)) {\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(loanToken, _SUSDBalance);\n\n ILoanTokenModules(loanToken).mint(address(this), 1000000 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyRBTC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some WRBTC from the lending pool.\n * 2. Close the loan with closeWithSwap function in the protocol.\n * 3. Burn all iWRBTC.\n *\n * The refund happened in step #3, which will send back the RBTC back to this contract.\n * Then, this contract will try to do another iWRBTC minting to the loan token --> this is where the cross-reentrancy happened between the protocol & the loan token contract.\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithSwap function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyRBTC {\n address public loanTokenWRBTC;\n address public WRBTC;\n address public SUSD;\n ProtocolLike public sovrynProtocol;\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iWRBTCBalance;\n }\n\n function() external payable {\n if (msg.sender == address(sovrynProtocol)) {\n uint256 latestRBTCBalance = address(this).balance;\n IWrbtcERC20(WRBTC).deposit.value(14 ether)();\n uint256 _WRBTCBalance = IERC20(WRBTC).balanceOf(address(this));\n IERC20(WRBTC).approve(loanTokenWRBTC, _WRBTCBalance);\n\n ILoanTokenModules(loanTokenWRBTC).mint(address(this), 14 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n\n constructor(\n address _loanTokenWRBTC,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanTokenWRBTC = _loanTokenWRBTC;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: SUSD has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n });\n\n IERC20(SUSD).approve(loanTokenWRBTC, initial.susdBalance);\n\n ILoanTokenModules(loanTokenWRBTC).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n SUSD,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanTokenWRBTC).loanParamsIds(\n uint256(keccak256(abi.encodePacked(SUSD, true)))\n );\n bytes32 loan_id =\n keccak256(\n abi.encodePacked(loanParamsLocalId, loanTokenWRBTC, _borrower, _borrowerNonce)\n );\n\n // STEP 3 close the borrowed position with a swap (probably works just as well with deposit)\n sovrynProtocol.closeWithSwap(\n loan_id,\n msg.sender,\n collateralTokenSent.mul(200).div(100), // make it 20% higher from initial collateral sent to make sure whole position is closed\n true,\n \"\"\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iRBTC\n uint256 _iWRBTCBalance = ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower);\n ILoanTokenModules(loanTokenWRBTC).burn(_receiver, _iWRBTCBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n // });\n }\n}\n" + }, + "contracts/testhelpers/TestLibraries.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../rsk/RSKAddrValidator.sol\";\n\n// contract for testing libraries\ncontract TestLibraries {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n */\n function RSKAddrValidator_checkPKNotZero(address addr) public pure returns (bool) {\n return (RSKAddrValidator.checkPKNotZero(addr));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key\n */\n function RSKAddrValidator_safeEquals(address addr1, address addr2) public pure returns (bool) {\n return (RSKAddrValidator.safeEquals(addr1, addr2));\n }\n}\n" + }, + "contracts/testhelpers/TestSovrynSwap.sol": { + "content": "/**\n * Test file simulating the SovrynSwap network\n * */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"./TestToken.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestSovrynSwap {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n address public priceFeeds;\n\n constructor(address feed) public {\n priceFeeds = feed;\n }\n\n /**\n * simulating the contract registry. always returns the address of this contract\n * */\n function addressOf(bytes32 contractName) public view returns (address) {\n return address(this);\n }\n\n /**\n * calculates the return tokens when swapping _amount, makes sure the return is bigger than _minReturn,\n * mints and burns the test tokens accordingly.\n * */\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256) {\n //compute the return for the amount of tokens provided\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n uint256 actualReturn = _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n\n require(actualReturn >= _minReturn, \"insufficient source tokens provided\");\n\n TestToken(address(_path[0])).burn(address(msg.sender), _amount);\n TestToken(address(_path[1])).mint(address(_beneficiary), actualReturn);\n return actualReturn;\n }\n\n /**\n * queries the rate from the Price Feed contract and computes the expected return amount based on the\n * amout of source tokens to be swapped.\n * */\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n\n return _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * returns the conversion path -> always a direct path\n * */\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory)\n {\n IERC20[] memory path = new IERC20[](2);\n path[0] = _sourceToken;\n path[1] = _targetToken;\n return path;\n }\n}\n" + }, + "contracts/testhelpers/TestToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestToken {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balances[_who], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[_who] = balances[_who].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(_who, _value);\n emit Transfer(_who, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/testhelpers/TestTokenERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Context.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../interfaces/IERC777.sol\";\nimport \"../interfaces/IERC777Recipient.sol\";\nimport \"../interfaces/IERC777Sender.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\n\ncontract TestTokenERC777 is Context, IERC777, IERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n mapping(address => uint256) private _balances;\n\n uint256 private _totalSupply;\n\n // We inline the result of the following hashes because Solidity doesn't resolve them at compile time.\n // See https://github.com/ethereum/solidity/issues/4024.\n\n // keccak256(\"ERC777TokensSender\")\n bytes32 private constant TOKENS_SENDER_INTERFACE_HASH =\n 0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895;\n\n // keccak256(\"ERC777TokensRecipient\")\n bytes32 private constant TOKENS_RECIPIENT_INTERFACE_HASH =\n 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;\n\n // This isn't ever read from - it's only used to respond to the defaultOperators query.\n address[] private _defaultOperatorsArray;\n\n // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).\n mapping(address => bool) private _defaultOperators;\n\n // For each account, a mapping of its operators and revoked default operators.\n mapping(address => mapping(address => bool)) private _operators;\n mapping(address => mapping(address => bool)) private _revokedDefaultOperators;\n\n // ERC20-allowances\n mapping(address => mapping(address => uint256)) private _allowances;\n\n /**\n * @dev `defaultOperators` may be an empty array.\n */\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _initialSupply,\n uint8 _decimals,\n address[] memory defaultOperators\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n _defaultOperatorsArray = defaultOperators;\n for (uint256 i = 0; i < _defaultOperatorsArray.length; i++) {\n _defaultOperators[_defaultOperatorsArray[i]] = true;\n }\n\n _mint(msg.sender, msg.sender, _initialSupply, \"\", \"\");\n\n // register interfaces\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777Token\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n /**\n * @dev See {IERC777-granularity}.\n *\n * This implementation always returns `1`.\n */\n function granularity() public view returns (uint256) {\n return 1;\n }\n\n /**\n * @dev See {IERC777-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev Returns the amount of tokens owned by an account (`tokenHolder`).\n */\n function balanceOf(address tokenHolder) public view returns (uint256) {\n return _balances[tokenHolder];\n }\n\n /**\n * @dev See {IERC777-send}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes memory data\n ) public {\n _send(_msgSender(), _msgSender(), recipient, amount, data, \"\", true);\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient}\n * interface if it is a contract.\n *\n * Also emits a {Sent} event.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n\n address from = _msgSender();\n\n _callTokensToSend(from, from, recipient, amount, \"\", \"\");\n\n _move(from, from, recipient, amount, \"\", \"\");\n\n _callTokensReceived(from, from, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev See {IERC777-burn}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function burn(uint256 amount, bytes memory data) public {\n _burn(_msgSender(), _msgSender(), amount, data, \"\");\n }\n\n /**\n * @dev See {IERC777-isOperatorFor}.\n */\n function isOperatorFor(address operator, address tokenHolder) public view returns (bool) {\n return\n operator == tokenHolder ||\n (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||\n _operators[tokenHolder][operator];\n }\n\n /**\n * @dev See {IERC777-authorizeOperator}.\n */\n function authorizeOperator(address operator) public {\n require(_msgSender() != operator, \"ERC777: authorizing self as operator\");\n\n if (_defaultOperators[operator]) {\n delete _revokedDefaultOperators[_msgSender()][operator];\n } else {\n _operators[_msgSender()][operator] = true;\n }\n\n emit AuthorizedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-revokeOperator}.\n */\n function revokeOperator(address operator) public {\n require(operator != _msgSender(), \"ERC777: revoking self as operator\");\n\n if (_defaultOperators[operator]) {\n _revokedDefaultOperators[_msgSender()][operator] = true;\n } else {\n delete _operators[_msgSender()][operator];\n }\n\n emit RevokedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-defaultOperators}.\n */\n function defaultOperators() public view returns (address[] memory) {\n return _defaultOperatorsArray;\n }\n\n /**\n * @dev See {IERC777-operatorSend}.\n *\n * Emits {Sent} and {IERC20-Transfer} events.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), sender),\n \"ERC777: caller is not an operator for holder\"\n );\n _send(_msgSender(), sender, recipient, amount, data, operatorData, true);\n }\n\n /**\n * @dev See {IERC777-operatorBurn}.\n *\n * Emits {Burned} and {IERC20-Transfer} events.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), account),\n \"ERC777: caller is not an operator for holder\"\n );\n _burn(_msgSender(), account, amount, data, operatorData);\n }\n\n /**\n * @dev See {IERC20-allowance}.\n *\n * Note that operator and allowance concepts are orthogonal: operators may\n * not have allowance, and accounts with allowance may not be operators\n * themselves.\n */\n function allowance(address holder, address spender) public view returns (uint256) {\n return _allowances[holder][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Note that accounts cannot have allowance issued by their operators.\n */\n function approve(address spender, uint256 value) public returns (bool) {\n address holder = _msgSender();\n _approve(holder, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Note that operator and allowance concepts are orthogonal: operators cannot\n * call `transferFrom` (unless they have allowance), and accounts with\n * allowance cannot call `operatorSend` (unless they are operators).\n *\n * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.\n */\n function transferFrom(\n address holder,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n require(holder != address(0), \"ERC777: transfer from the zero address\");\n\n address spender = _msgSender();\n\n _callTokensToSend(spender, holder, recipient, amount, \"\", \"\");\n\n _move(spender, holder, recipient, amount, \"\", \"\");\n\n _approve(\n holder,\n spender,\n _allowances[holder][spender].sub(amount, \"ERC777: transfer amount exceeds allowance\")\n );\n\n _callTokensReceived(spender, holder, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `operator`, `data` and `operatorData`.\n *\n * See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits {Minted} and {IERC20-Transfer} events.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - if `account` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function _mint(\n address operator,\n address account,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n require(account != address(0), \"ERC777: mint to the zero address\");\n\n // Update state variables\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n\n _callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);\n\n emit Minted(operator, account, amount, userData, operatorData);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Send tokens\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _send(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n require(from != address(0), \"ERC777: send from the zero address\");\n require(to != address(0), \"ERC777: send to the zero address\");\n\n _callTokensToSend(operator, from, to, amount, userData, operatorData);\n\n _move(operator, from, to, amount, userData, operatorData);\n\n _callTokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData,\n requireReceptionAck\n );\n }\n\n /**\n * @dev Burn tokens\n * @param operator address operator requesting the operation\n * @param from address token holder address\n * @param amount uint256 amount of tokens to burn\n * @param data bytes extra information provided by the token holder\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _burn(\n address operator,\n address from,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) internal {\n require(from != address(0), \"ERC777: burn from the zero address\");\n\n _callTokensToSend(operator, from, address(0), amount, data, operatorData);\n\n // Update state variables\n _balances[from] = _balances[from].sub(amount, \"ERC777: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n\n emit Burned(operator, from, amount, data, operatorData);\n emit Transfer(from, address(0), amount);\n }\n\n function _move(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) private {\n _balances[from] = _balances[from].sub(amount, \"ERC777: transfer amount exceeds balance\");\n _balances[to] = _balances[to].add(amount);\n\n emit Sent(operator, from, to, amount, userData, operatorData);\n emit Transfer(from, to, amount);\n }\n\n function _approve(\n address holder,\n address spender,\n uint256 value\n ) internal {\n // TODO: restore this require statement if this function becomes internal, or is called at a new callsite. It is\n // currently unnecessary.\n //require(holder != address(0), \"ERC777: approve from the zero address\");\n require(spender != address(0), \"ERC777: approve to the zero address\");\n\n _allowances[holder][spender] = value;\n emit Approval(holder, spender, value);\n }\n\n /**\n * @dev Call from.tokensToSend() if the interface is registered\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _callTokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Sender(implementer).tokensToSend(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n }\n }\n\n /**\n * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but\n * tokensReceived() was not registered for the recipient\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _callTokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Recipient(implementer).tokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n } else if (requireReceptionAck) {\n require(\n !to.isContract(),\n \"ERC777: token recipient contract has no implementer for ERC777TokensRecipient\"\n );\n }\n }\n\n function mint(address _to, uint256 _value) public {\n // Update state variables\n _totalSupply = _totalSupply.add(_value);\n _balances[_to] = _balances[_to].add(_value);\n\n emit Minted(msg.sender, _to, _value, \"\", \"\");\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balanceOf(_who), \"balance too low\");\n\n _burn(msg.sender, _who, _value, \"\", \"\");\n }\n}\n" + }, + "contracts/testhelpers/TestTokenLimited.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestTokenLimited {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n require(_value <= 100000 ether, \"max mint amount exceeded\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(uint256 _value) public {\n require(_value <= balances[msg.sender], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(msg.sender, _value);\n emit Transfer(msg.sender, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/token/IApproveAndCall.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/ApprovalReceiver.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IApproveAndCall {\n /**\n * @notice Receives approval from SOV token.\n * @param _sender The sender of SOV.approveAndCall function.\n * @param _amount The amount was approved.\n * @param _token The address of token.\n * @param _data The data will be used for low level call.\n * */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/token/SOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/ERC20Detailed.sol\";\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./IApproveAndCall.sol\";\n\n/**\n * @title Sovryn Token: SOV is an ERC-20 token contract for Sovryn governance.\n *\n * @notice This contract accounts for all holders' balances.\n *\n * @dev This contract represents a token with dynamic supply.\n * The owner of the token contract can mint/burn tokens to/from any account\n * based upon previous governance voting and approval.\n * */\ncontract SOV is ERC20, ERC20Detailed, Ownable {\n string constant NAME = \"Sovryn Token\";\n string constant SYMBOL = \"SOV\";\n uint8 constant DECIMALS = 18;\n\n /**\n * @notice Constructor called on deployment, initiates the contract.\n * @dev On deployment, some amount of tokens will be minted for the owner.\n * @param _initialAmount The amount of tokens to be minted on contract creation.\n * */\n constructor(uint256 _initialAmount) public ERC20Detailed(NAME, SYMBOL, DECIMALS) {\n if (_initialAmount != 0) {\n _mint(msg.sender, _initialAmount);\n }\n }\n\n /**\n * @notice Creates new tokens and sends them to the recipient.\n * @dev Don't create more than 2^96/10 tokens before updating the governance first.\n * @param _account The recipient address to get the minted tokens.\n * @param _amount The amount of tokens to be minted.\n * */\n function mint(address _account, uint256 _amount) public onlyOwner {\n _mint(_account, _amount);\n }\n\n /**\n * @notice Approves and then calls the receiving contract.\n * Useful to encapsulate sending tokens to a contract in one call.\n * Solidity has no native way to send tokens to contracts.\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\n * @param _spender The contract address to spend the tokens.\n * @param _amount The amount of tokens to be sent.\n * @param _data Parameters for the contract call, such as endpoint signature.\n * */\n function approveAndCall(\n address _spender,\n uint256 _amount,\n bytes memory _data\n ) public {\n approve(_spender, _amount);\n IApproveAndCall(_spender).receiveApproval(msg.sender, _amount, address(this), _data);\n }\n}\n" + }, + "contracts/utils/AdminRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\n\ncontract AdminRole is Ownable {\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * or on our own overriding sovrynOwnable.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n}\n" + }, + "contracts/utils/PausableRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/PausableOz.sol\";\n\ncontract PausableRole is PausableOz {\n address public pauser;\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n\n /**\n * @dev Modifier to make a function callable only when the caller is pauser or owner\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"Pausable: unauthorized\"); // SS02\n _;\n }\n\n /**\n * @notice Set the pauser address.\n *\n * only pauser can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyPauserOrOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyPauserOrOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/utils/ProxyOwnable.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\n/**\n * Based on OpenZeppelin's Ownable contract:\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\n *\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract ProxyOwnable {\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Ownable:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"ProxyOwnable::setProxyOwner: invalid address\");\n emit ProxyOwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Set address of the owner (only owner can call this function)\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n\n /**\n * @notice Return address of the owner.\n * @return _owner Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n}\n" + }, + "contracts/utils/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\nlibrary Utils {\n function stringToBytes32(string memory source) internal pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + }, + "remappings": [ + "ds-test/=foundry/lib/forge-std/lib/ds-test/src/", + "forge-std/=foundry/lib/forge-std/src/" + ] + } +} \ No newline at end of file diff --git a/deployment/deployments/rskSovrynTestnet/solcInputs/aca886878e9e0827277d5a4711a5589b.json b/deployment/deployments/rskSovrynTestnet/solcInputs/aca886878e9e0827277d5a4711a5589b.json new file mode 100644 index 000000000..131856511 --- /dev/null +++ b/deployment/deployments/rskSovrynTestnet/solcInputs/aca886878e9e0827277d5a4711a5589b.json @@ -0,0 +1,708 @@ +{ + "language": "Solidity", + "sources": { + "contracts/connectors/loantoken/AdvancedToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Advanced Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedToken implements standard ERC-20 approval, mint and burn token functionality.\n * Logic (AdvancedToken) is kept aside from storage (AdvancedTokenStorage).\n *\n * For example, LoanTokenLogicDai contract uses AdvancedToken::_mint() to mint\n * its Loan Dai iTokens.\n * */\ncontract AdvancedToken is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n /**\n * @notice Set an amount as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n *\n * @param _spender The account address that will be able to spend the tokens.\n * @param _value The amount of tokens allowed to spend.\n * */\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n /**\n * @notice The iToken minting process. Meant to issue Loan iTokens.\n * Lenders are able to open an iToken position, by minting them.\n * This function is called by LoanTokenLogicStandard::_mintToken\n * @param _to The recipient of the minted tTokens.\n * @param _tokenAmount The amount of iTokens to be minted.\n * @param _assetAmount The amount of lended tokens (asset to lend).\n * @param _price The price of the lended tokens.\n * @return The updated balance of the recipient.\n * */\n function _mint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n require(_to != address(0), \"15\");\n\n uint256 _balance = balances[_to].add(_tokenAmount);\n balances[_to] = _balance;\n\n totalSupply_ = totalSupply_.add(_tokenAmount);\n\n emit Mint(_to, _tokenAmount, _assetAmount, _price);\n emit Transfer(address(0), _to, _tokenAmount);\n\n return _balance;\n }\n\n /**\n * @notice The iToken burning process. Meant to destroy Loan iTokens.\n * Lenders are able to close an iToken position, by burning them.\n * This function is called by LoanTokenLogicStandard::_burnToken\n * @param _who The owner of the iTokens to burn.\n * @param _tokenAmount The amount of iTokens to burn.\n * @param _assetAmount The amount of lended tokens.\n * @param _price The price of the lended tokens.\n * @return The updated balance of the iTokens owner.\n * */\n function _burn(\n address _who,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) internal returns (uint256) {\n //bzx compare\n //TODO: Unit test\n uint256 _balance = balances[_who].sub(_tokenAmount, \"16\");\n\n // a rounding error may leave dust behind, so we clear this out\n if (_balance <= 10) {\n // We can't leave such small balance quantities.\n _tokenAmount = _tokenAmount.add(_balance);\n _balance = 0;\n }\n balances[_who] = _balance;\n\n totalSupply_ = totalSupply_.sub(_tokenAmount);\n\n emit Burn(_who, _tokenAmount, _assetAmount, _price);\n emit Transfer(_who, address(0), _tokenAmount);\n return _balance;\n }\n}\n" + }, + "contracts/connectors/loantoken/AdvancedTokenStorage.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./LoanTokenBase.sol\";\n\n/**\n * @title Advanced Token Storage contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * AdvancedTokenStorage implements standard ERC-20 getters functionality:\n * totalSupply, balanceOf, allowance and some events.\n * iToken logic is divided into several contracts AdvancedToken,\n * AdvancedTokenStorage and LoanTokenBase.\n * */\ncontract AdvancedTokenStorage is LoanTokenBase {\n using SafeMath for uint256;\n\n /* Events */\n\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /* Storage */\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n /* Functions */\n\n /**\n * @notice Get the total supply of iTokens.\n * @return The total number of iTokens in existence as of now.\n * */\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n /**\n * @notice Get the amount of iTokens owned by an account.\n * @param _owner The account owner of the iTokens.\n * @return The number of iTokens an account owns.\n * */\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n /**\n * @notice Get the amount of iTokens allowed to be spent by a\n * given account on behalf of the owner.\n * @param _owner The account owner of the iTokens.\n * @param _spender The account allowed to send the iTokens.\n * @return The number of iTokens an account is allowing the spender\n * to send on its behalf.\n * */\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/connectors/loantoken/interfaces/FeedsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface FeedsLike {\n function queryRate(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 rate, uint256 precision);\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../lib/MarginTradeStructHelpers.sol\";\n\ninterface ProtocolLike {\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function priceFeeds() external view returns (address);\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function lendingFeePercent() external view returns (uint256);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function borrowerNonce(address) external view returns (uint256);\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata // for future use /*loanDataBytes*/\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n}\n" + }, + "contracts/connectors/loantoken/interfaces/ProtocolSettingsLike.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../core/objects/LoanParamsStruct.sol\";\n\ninterface ProtocolSettingsLike {\n function setupLoanParams(LoanParamsStruct.LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n}\n" + }, + "contracts/connectors/loantoken/lib/MarginTradeStructHelpers.sol": { + "content": "pragma solidity 0.5.17;\n\nlibrary MarginTradeStructHelpers {\n struct SentAddresses {\n address lender;\n address borrower;\n address receiver;\n address manager;\n }\n\n struct SentAmounts {\n uint256 interestRate;\n uint256 newPrincipal;\n uint256 interestInitialAmount;\n uint256 loanTokenSent;\n uint256 collateralTokenSent;\n uint256 minEntryPrice;\n uint256 loanToCollateralSwapRate;\n uint256 interestDuration;\n uint256 entryLeverage;\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./AdvancedTokenStorage.sol\";\n\n/**\n * @title Loan Token contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * A loan token (iToken) is created as a proxy to an upgradable token contract.\n *\n * Examples of loan tokens on Sovryn are iRBTC, iDOC, iUSDT, iBPro,\n * iSOV (near future).\n *\n * Lenders receive iTokens that collect interest from the lending pool\n * which they can redeem by withdrawing them. The i in iToken stands for interest.\n *\n * Do not confuse iTokens with underlying tokens. iDOC is an iToken (loan token)\n * whilest DOC is the underlying token (currency).\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\n * */\ncontract LoanToken is AdvancedTokenStorage {\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n address public admin;\n\n /**\n * @notice Deploy loan token proxy.\n * Sets ERC20 parameters of the token.\n *\n * @param _newOwner The address of the new owner.\n * @param _newTarget The address of the new target contract instance.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice Public owner setter for target address.\n * @dev Calls internal setter.\n * @param _newTarget The address of the new target contract instance.\n * */\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n /**\n * @notice Internal setter for target address.\n * @param _newTarget The address of the new target contract instance.\n * */\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n /**\n * @notice Internal setter for sovrynContract address.\n * @param _sovrynContractAddress The address of the new sovrynContract instance.\n * */\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n /**\n * @notice Internal setter for wrBTC address.\n * @param _wrbtcTokenAddress The address of the new wrBTC instance.\n * */\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n /**\n * @notice Public owner cloner for pointed loan token.\n * Sets ERC20 parameters of the token.\n *\n * @dev TODO: add check for double init.\n * idk but init usually can be called only once.\n *\n * @param _loanTokenAddress The address of the pointed loan token instance.\n * @param _name The ERC20 token name.\n * @param _symbol The ERC20 token symbol.\n * */\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; /// starting price of 1\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenBase.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SignedSafeMath.sol\";\nimport \"../../openzeppelin/ReentrancyGuard.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\nimport \"./Pausable.sol\";\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title Loan Token Base contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Specific loan related storage for iTokens.\n *\n * An loan token or iToken is a representation of a user funds in the pool and the\n * interest they've earned. The redemption value of iTokens continually increase\n * from the accretion of interest paid into the lending pool by borrowers. The user\n * can sell iTokens to exit its position. The user might potentially use them as\n * collateral wherever applicable.\n *\n * There are three main tokens in the bZx system, iTokens, pTokens, and BZRX tokens.\n * The bZx system of lending and borrowing depends on iTokens and pTokens, and when\n * users lend or borrow money on bZx, their crypto assets go into or come out of\n * global liquidity pools, which are pools of funds shared between many different\n * exchanges. When lenders supply funds into the global liquidity pools, they\n * automatically receive iTokens; When users borrow money to open margin trading\n * positions, they automatically receive pTokens. The system is also designed to\n * use the BZRX tokens, which are only used to pay fees on the network currently.\n * */\ncontract LoanTokenBase is ReentrancyGuard, SharedReentrancyGuard, Ownable, Pausable {\n uint256 internal constant WEI_PRECISION = 10**18;\n uint256 internal constant WEI_PERCENT_PRECISION = 10**20;\n\n int256 internal constant sWEI_PRECISION = 10**18;\n\n /// @notice Standard ERC-20 properties\n string public name;\n string public symbol;\n uint8 public decimals;\n\n /// @notice The address of the loan token (asset to lend) instance.\n address public loanTokenAddress;\n\n uint256 public baseRate;\n uint256 public rateMultiplier;\n uint256 public lowUtilBaseRate;\n uint256 public lowUtilRateMultiplier;\n\n uint256 public targetLevel;\n uint256 public kinkLevel;\n uint256 public maxScaleRate;\n\n uint256 internal _flTotalAssetSupply;\n uint256 public checkpointSupply;\n uint256 public initialPrice;\n\n /// uint88 for tight packing -> 8 + 88 + 160 = 256\n uint88 internal lastSettleTime_;\n\n /// Mapping of keccak256(collateralToken, isTorqueLoan) to loanParamsId.\n mapping(uint256 => bytes32) public loanParamsIds;\n\n /// Price of token at last user checkpoint.\n mapping(address => uint256) internal checkpointPrices_;\n\n // the maximum trading/borrowing/lending limit per token address\n mapping(address => uint256) public transactionLimit;\n // 0 -> no limit\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicBeacon.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../mixins/EnumerableBytes32Set.sol\";\nimport \"../../mixins/EnumerableBytes4Set.sol\";\nimport \"../../utils/PausableRole.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Loan Token Logic Beacon contract.\n *\n * @notice This contract stored the target logic implementation of LoanTokens which has the same logic implementation (LoanTokenLogicLM / LoanTokenLogicWrbtc)\n * Apart from storing the target logic implementation, this contract also has a pause functionality.\n * By implementing pause/unpause functionality in this beacon contract, we can pause the loan token that has the same Logic (LoanTokenLogicLM / LoanTokenLogicWrbtc) at one call.\n * Meanwhile the pause/unpause function in the LoanTokenLogicProxy is used to pause/unpause specific LoanToken\n */\n\ncontract LoanTokenLogicBeacon is PausableRole {\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set; // enumerable map of bytes4 or addresses\n\n mapping(bytes4 => address) private logicTargets;\n\n struct LoanTokenLogicModuleUpdate {\n address implementation; // address implementaion of the module\n uint256 updateTimestamp; // time of update\n }\n\n mapping(bytes32 => LoanTokenLogicModuleUpdate[]) public moduleUpgradeLog; /** the module name as the key */\n\n mapping(bytes32 => uint256) public activeModuleIndex; /** To store the current active index log for module */\n\n mapping(bytes32 => EnumerableBytes4Set.Bytes4Set) private activeFuncSignatureList; /** Store the current active function signature */\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n * This is the overriden function from the pausable contract, so that we can use custom error message.\n */\n modifier whenNotPaused() {\n require(!_paused, \"LoanTokenLogicBeacon:paused mode\");\n _;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This function will store the updated protocol module to the storage (For rollback purposes)\n *\n * @param loanTokenModuleAddress The module target address\n */\n function registerLoanTokenModule(address loanTokenModuleAddress) external onlyOwner {\n bytes32 moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n\n // Store the upgrade to the log\n moduleUpgradeLog[moduleName].push(\n LoanTokenLogicModuleUpdate(loanTokenModuleAddress, block.timestamp)\n );\n activeModuleIndex[moduleName] = moduleUpgradeLog[moduleName].length - 1;\n }\n\n /**\n * @notice Register the loanTokenModule (LoanTokenSettingsLowerAdmin, LoanTokenLogicLM / LoanTokenLogicWrbtc, etc)\n *\n * @dev This registration will require target contract to have the exact function getListFunctionSignatures() which will return functionSignatureList and the moduleName in bytes32\n *\n * @param loanTokenModuleAddress the target logic of the loan token module\n *\n * @return the module name\n */\n function _registerLoanTokenModule(address loanTokenModuleAddress) private returns (bytes32) {\n require(\n Address.isContract(loanTokenModuleAddress),\n \"LoanTokenModuleAddress is not a contract\"\n );\n\n // Get the list of function signature on this loanTokenModulesAddress\n (bytes4[] memory functionSignatureList, bytes32 moduleName) =\n ILoanTokenLogicModules(loanTokenModuleAddress).getListFunctionSignatures();\n\n /// register / update the module function signature address implementation\n for (uint256 i; i < functionSignatureList.length; i++) {\n require(functionSignatureList[i] != bytes4(0x0), \"ERR_EMPTY_FUNC_SIGNATURE\");\n logicTargets[functionSignatureList[i]] = loanTokenModuleAddress;\n if (!activeFuncSignatureList[moduleName].contains(functionSignatureList[i]))\n activeFuncSignatureList[moduleName].addBytes4(functionSignatureList[i]);\n }\n\n /// delete the \"removed\" module function signature in the current implementation\n bytes4[] memory activeSignatureListEnum =\n activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n for (uint256 i; i < activeSignatureListEnum.length; i++) {\n bytes4 activeSigBytes = activeSignatureListEnum[i];\n if (logicTargets[activeSigBytes] != loanTokenModuleAddress) {\n logicTargets[activeSigBytes] = address(0);\n activeFuncSignatureList[moduleName].removeBytes4(activeSigBytes);\n }\n }\n\n return moduleName;\n }\n\n /**\n * @dev get all active function signature list based on the module name.\n *\n * @param moduleName in bytes32.\n *\n * @return the array of function signature.\n */\n function getActiveFuncSignatureList(bytes32 moduleName)\n public\n view\n returns (bytes4[] memory signatureList)\n {\n signatureList = activeFuncSignatureList[moduleName].enumerate(\n 0,\n activeFuncSignatureList[moduleName].length()\n );\n return signatureList;\n }\n\n /**\n * @dev Get total length of the module upgrade log.\n *\n * @param moduleName in bytes32.\n *\n * @return length of module upgrade log.\n */\n function getModuleUpgradeLogLength(bytes32 moduleName) external view returns (uint256) {\n return moduleUpgradeLog[moduleName].length;\n }\n\n /**\n * @notice This function will rollback particular module to the spesific index / version of deployment\n *\n * @param moduleName Name of module in bytes32 format\n * @param index index / version of previous deployment\n */\n function rollback(bytes32 moduleName, uint256 index) external onlyOwner {\n address loanTokenModuleAddress = moduleUpgradeLog[moduleName][index].implementation;\n moduleName = _registerLoanTokenModule(loanTokenModuleAddress);\n activeModuleIndex[moduleName] = index;\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(bytes4 sig) external view whenNotPaused returns (address) {\n return logicTargets[sig];\n }\n}\n\ninterface ILoanTokenLogicModules {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory, bytes32 moduleName);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicProxy.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./AdvancedTokenStorage.sol\";\nimport \"../../openzeppelin/Initializable.sol\";\n\n/**\n * @title Loan Token Logic Proxy contract.\n *\n * @notice This contract contains the proxy functionality and it will query the logic target from LoanTokenLogicBeacon\n * This contract will also has the pause/unpause functionality. The purpose of this pausability is so that we can pause/unpause from the loan token level.\n *\n */\ncontract LoanTokenLogicProxy is AdvancedTokenStorage {\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT\n */\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /**\n * @notice PLEASE DO NOT ADD ANY VARIABLES HERE UNLESS FOR SPESIFIC SLOT (CONSTANT / IMMUTABLE)\n */\n\n bytes32 internal constant LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT =\n keccak256(\"LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT\");\n\n modifier onlyAdmin() {\n require(isOwner(), \"LoanTokenLogicProxy:unauthorized\");\n _;\n }\n\n /**\n * @notice Fallback function performs a logic implementation address query to LoanTokenLogicBeacon and then do delegate call to that query result address.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n // query the logic target implementation address from the LoanTokenLogicBeacon\n address target = ILoanTokenLogicBeacon(_beaconAddress()).getTarget(msg.sig);\n require(target != address(0), \"LoanTokenLogicProxy:target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @dev Returns the current Loan Token logic Beacon.\n * @return Address of the current LoanTokenLogicBeacon.\n */\n function _beaconAddress() internal view returns (address beaconAddress) {\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n assembly {\n beaconAddress := sload(slot)\n }\n }\n\n /**\n * @return The address of the current LoanTokenLogicBeacon.\n */\n function beaconAddress() external view returns (address) {\n return _beaconAddress();\n }\n\n /**\n * @dev Set/update the new beacon address.\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon.\n */\n function _setBeaconAddress(address _newBeaconAddress) private {\n require(\n Address.isContract(_newBeaconAddress),\n \"Cannot set beacon address to a non-contract address\"\n );\n\n bytes32 slot = LOAN_TOKEN_LOGIC_BEACON_ADDRESS_SLOT;\n\n assembly {\n sstore(slot, _newBeaconAddress)\n }\n }\n\n /**\n * @dev External function to set the new LoanTokenLogicBeacon Address\n * @param _newBeaconAddress Address of the new LoanTokenLogicBeacon\n */\n function setBeaconAddress(address _newBeaconAddress) external onlyAdmin {\n _setBeaconAddress(_newBeaconAddress);\n }\n\n /**\n * @dev External function to return the LoanTokenLogicProxy of loan token (target of LoanToken contract).\n * Ideally this getter should be added in the LoanToken contract\n * but since LoanToken contract can't be changed, adding the getter in this contract will do\n * because it will use the context of LoanToken contract.\n *\n * @return target address of LoanToken contract\n */\n function getTarget() external view returns (address) {\n return target_;\n }\n}\n\ninterface ILoanTokenLogicBeacon {\n function getTarget(bytes4 functionSignature)\n external\n view\n returns (address logicTargetAddress);\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicShared.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicStorage.sol\";\nimport \"./interfaces/ProtocolLike.sol\";\nimport \"./interfaces/FeedsLike.sol\";\nimport \"./interfaces/ProtocolSettingsLike.sol\";\nimport \"../../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../../farm/ILiquidityMining.sol\";\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../governance/Vesting/IVesting.sol\";\n\n/**\n * @dev This contract shares functions used by both LoanTokenLogicSplit and LoanTokenLogicStandard\n */\ncontract LoanTokenLogicShared is LoanTokenLogicStorage {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /**\n * @notice Update the user's checkpoint price and profit so far.\n * In this loan token contract, whenever some tokens are minted or burned,\n * the _updateCheckpoints() function is invoked to update the stats to\n * reflect the balance changes.\n *\n * @param _user The user address.\n * @param _oldBalance The user's previous balance.\n * @param _newBalance The user's updated balance.\n * @param _currentPrice The current loan token price.\n * */\n function _updateCheckpoints(\n address _user,\n uint256 _oldBalance,\n uint256 _newBalance,\n uint256 _currentPrice\n ) internal {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(_user, iToken_ProfitSoFar));\n\n int256 _currentProfit;\n if (_newBalance == 0) {\n _currentPrice = 0;\n } else if (_oldBalance != 0) {\n _currentProfit = _profitOf(slot, _oldBalance, _currentPrice, checkpointPrices_[_user]);\n }\n\n assembly {\n sstore(slot, _currentProfit)\n }\n\n checkpointPrices_[_user] = _currentPrice;\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice Transfer tokens, low level.\n * Checks allowance, updates sender and recipient balances\n * and updates checkpoints too.\n *\n * @param _from The tokens' owner.\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @param _allowanceAmount The amount of tokens allowed to transfer.\n *\n * @return Success true/false.\n * */\n function _internalTransferFrom(\n address _from,\n address _to,\n uint256 _value,\n uint256 _allowanceAmount\n ) internal returns (bool) {\n if (_allowanceAmount != uint256(-1)) {\n allowed[_from][msg.sender] = _allowanceAmount.sub(_value, \"14\");\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, _allowanceAmount, allowed[_from][msg.sender]);\n }\n\n require(_to != address(0), \"15\");\n\n uint256 _balancesFrom = balances[_from];\n uint256 _balancesFromNew = _balancesFrom.sub(_value, \"16\");\n balances[_from] = _balancesFromNew;\n\n uint256 _balancesTo = balances[_to];\n uint256 _balancesToNew = _balancesTo.add(_value);\n balances[_to] = _balancesToNew;\n\n /// @dev Handle checkpoint update.\n uint256 _currentPrice = tokenPrice();\n\n //checkpoints are not being used by the smart contract logic itself, but just for external use (query the profit)\n //only update the checkpoints of a user if he's not depositing to / withdrawing from the lending pool\n if (_from != liquidityMiningAddress && _to != liquidityMiningAddress) {\n _updateCheckpoints(_from, _balancesFrom, _balancesFromNew, _currentPrice);\n _updateCheckpoints(_to, _balancesTo, _balancesToNew, _currentPrice);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n /**\n * @notice Profit calculation based on checkpoints of price.\n * @param slot The user slot.\n * @param _balance The user balance.\n * @param _currentPrice The current price of the loan token.\n * @param _checkpointPrice The price of the loan token on checkpoint.\n * @return The profit of a user.\n * */\n function _profitOf(\n bytes32 slot,\n uint256 _balance,\n uint256 _currentPrice,\n uint256 _checkpointPrice\n ) internal view returns (int256 profitSoFar) {\n if (_checkpointPrice == 0) {\n return 0;\n }\n\n assembly {\n profitSoFar := sload(slot)\n }\n\n profitSoFar = int256(_currentPrice)\n .sub(int256(_checkpointPrice))\n .mul(int256(_balance))\n .div(sWEI_PRECISION)\n .add(profitSoFar);\n }\n\n /**\n * @notice Loan token price calculation considering unpaid interests.\n * @return The loan token price.\n * */\n function tokenPrice() public view returns (uint256 price) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _tokenPrice(_totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Get the total amount of loan tokens on debt.\n * Calls protocol getTotalPrincipal function.\n * In the context of borrowing, principal is the initial size of a loan.\n * It can also be the amount still owed on a loan. If you take out a\n * $50,000 mortgage, for example, the principal is $50,000. If you pay off\n * $30,000, the principal balance now consists of the remaining $20,000.\n *\n * @return The total amount of loan tokens on debt.\n * */\n function totalAssetBorrow() public view returns (uint256) {\n return\n ProtocolLike(sovrynContractAddress).getTotalPrincipal(address(this), loanTokenAddress);\n }\n\n /** INTERNAL FUNCTION */\n\n /**\n * @notice .\n *\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param withdrawalAmount The amount of tokens to withdraw.\n *\n * @return msgValue The amount of rBTC sent minus the collateral on tokens.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = loanTokenAddress;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n _safeTransfer(_loanTokenAddress, sentAddresses.receiver, withdrawalAmount, \"\");\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n /**\n * This is a critical piece of code!\n * rBTC are supposed to be held by the contract itself, while other tokens are being transfered from the sender directly.\n * */\n if (collateralTokenSent != 0) {\n if (\n collateralTokenAddress == _wrbtcToken &&\n msgValue != 0 &&\n msgValue >= collateralTokenSent\n ) {\n IWrbtc(_wrbtcToken).deposit.value(collateralTokenSent)();\n _safeTransfer(\n collateralTokenAddress,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-a\"\n );\n msgValue -= collateralTokenSent;\n } else {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28-b\"\n );\n }\n }\n\n if (loanTokenSent != 0) {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n\n /**\n * @notice Withdraw loan token interests from protocol.\n * This function only operates once per block.\n * It asks protocol to withdraw accrued interests for the loan token.\n *\n * @dev Internal sync required on every loan trade before starting.\n * */\n function _settleInterest() internal {\n uint88 ts = uint88(block.timestamp);\n if (lastSettleTime_ != ts) {\n ProtocolLike(sovrynContractAddress).withdrawAccruedInterest(loanTokenAddress);\n\n lastSettleTime_ = ts;\n }\n }\n\n /**\n * @notice Imitate a Solidity high-level call (i.e. a regular function\n * call to a contract), relaxing the requirement on the return value:\n * the return value is optional (but if data is returned, it must not be\n * false).\n *\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n * @param errorMsg The error message on failure.\n * */\n function _callOptionalReturn(\n address token,\n bytes memory data,\n string memory errorMsg\n ) internal {\n require(Address.isContract(token), \"call to a non-contract address\");\n (bool success, bytes memory returndata) = token.call(data);\n require(success, errorMsg);\n\n if (returndata.length != 0) {\n require(abi.decode(returndata, (bool)), errorMsg);\n }\n }\n\n /**\n * @notice Execute the ERC20 token's `transfer` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransfer(\n address token,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transfer.selector, to, amount),\n errorMsg\n );\n }\n\n /**\n * @notice Execute the ERC20 token's `transferFrom` function and reverts\n * upon failure the main purpose of this function is to prevent a non\n * standard ERC20 token from failing silently.\n *\n * @dev Wrappers around ERC20 operations that throw on failure (when the\n * token contract returns false). Tokens that return no value (and instead\n * revert or throw on failure) are also supported, non-reverting calls are\n * assumed to be successful.\n *\n * @param token The ERC20 token address.\n * @param from The source address.\n * @param to The target address.\n * @param amount The transfer amount.\n * @param errorMsg The error message on failure.\n */\n function _safeTransferFrom(\n address token,\n address from,\n address to,\n uint256 amount,\n string memory errorMsg\n ) internal {\n _callOptionalReturn(\n token,\n abi.encodeWithSelector(IERC20(token).transferFrom.selector, from, to, amount),\n errorMsg\n );\n }\n\n /** Internal view function */\n /**\n * @notice Compute the token price.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The token price.\n * */\n function _tokenPrice(uint256 assetSupply) internal view returns (uint256) {\n uint256 totalTokenSupply = totalSupply_;\n\n return\n totalTokenSupply != 0 ? assetSupply.mul(10**18).div(totalTokenSupply) : initialPrice;\n }\n\n /**\n * @notice Get two kind of interests: owed per day and yet to be paid.\n * @return interestOwedPerDay The interest per day.\n * @return interestUnPaid The interest not yet paid.\n * */\n function _getAllInterest()\n internal\n view\n returns (uint256 interestOwedPerDay, uint256 interestUnPaid)\n {\n /// interestPaid, interestPaidDate, interestOwedPerDay, interestUnPaid, interestFeePercent, principalTotal\n uint256 interestFeePercent;\n (, , interestOwedPerDay, interestUnPaid, interestFeePercent, ) = ProtocolLike(\n sovrynContractAddress\n )\n .getLenderInterestData(address(this), loanTokenAddress);\n\n interestUnPaid = interestUnPaid.mul(SafeMath.sub(10**20, interestFeePercent)).div(10**20);\n }\n\n /**\n * @notice Compute the total amount of loan tokens on supply.\n * @param interestUnPaid The interest not yet paid.\n * @return assetSupply The total amount of loan tokens on supply.\n * */\n function _totalAssetSupply(uint256 interestUnPaid)\n internal\n view\n returns (uint256 assetSupply)\n {\n if (totalSupply_ != 0) {\n uint256 assetsBalance = _flTotalAssetSupply; /// Temporary locked totalAssetSupply during a flash loan transaction.\n if (assetsBalance == 0) {\n assetsBalance = _underlyingBalance().add(totalAssetBorrow());\n }\n\n return assetsBalance.add(interestUnPaid);\n }\n }\n\n /**\n * @notice Get the loan contract balance.\n * @return The balance of the loan token for this contract.\n * */\n function _underlyingBalance() internal view returns (uint256) {\n return IERC20(loanTokenAddress).balanceOf(address(this));\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicSplit.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\n/**\n * @title Loan Token Logic Standard contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * Logic around loan tokens (iTokens) required to operate borrowing,\n * and margin trading financial processes.\n *\n * The user provides funds to the lending pool using the mint function and\n * withdraws funds from the lending pool using the burn function. Mint and\n * burn refer to minting and burning loan tokens. Loan tokens represent a\n * share of the pool and gather interest over time.\n *\n * Interest rates are determined by supply and demand. When a lender deposits\n * funds, the interest rates go down. When a trader borrows funds, the\n * interest rates go up. Fulcrum uses a simple linear interest rate formula\n * of the form y = mx + b. The interest rate starts at 1% when loans aren't\n * being utilized and scales up to 40% when all the funds in the loan pool\n * are being borrowed.\n *\n * The borrow rate is determined at the time of the loan and represents the\n * net contribution of each borrower. Each borrower's interest contribution\n * is determined by the utilization rate of the pool and is netted against\n * all prior borrows. This means that the total amount of interest flowing\n * into the lending pool is not directly changed by lenders entering or\n * exiting the pool. The entrance or exit of lenders only impacts how the\n * interest payments are split up.\n *\n * For example, if there are 2 lenders with equal holdings each earning\n * 5% APR, but one of the lenders leave, then the remaining lender will earn\n * 10% APR since the interest payments don't have to be split between two\n * individuals.\n * */\ncontract LoanTokenLogicSplit is LoanTokenLogicShared {\n using SafeMath for uint256;\n using SignedSafeMath for int256;\n\n /// DON'T ADD VARIABLES HERE, PLEASE\n\n /* Public functions */\n\n /**\n * @notice Mint loan token wrapper.\n * Adds a check before calling low level _mintToken function.\n * The function retrieves the tokens from the message sender, so make sure\n * to first approve the loan token contract to access your funds. This is\n * done by calling approve(address spender, uint amount) on the ERC20\n * token contract, where spender is the loan token contract address and\n * amount is the amount to be deposited.\n *\n * @param receiver The account getting the minted tokens.\n * @param depositAmount The amount of underlying tokens provided on the\n * loan. (Not the number of loan tokens to mint).\n *\n * @return The amount of loan tokens minted.\n * */\n function mint(address receiver, uint256 depositAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice Burn loan token wrapper.\n * Adds a pay-out transfer after calling low level _burnToken function.\n * In order to withdraw funds to the pool, call burn on the respective\n * loan token contract. This will burn your loan tokens and send you the\n * underlying token in exchange.\n *\n * @param receiver The account getting the minted tokens.\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n globallyNonReentrant\n returns (uint256 loanAmountPaid)\n {\n loanAmountPaid = _burnToken(burnAmount);\n\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (loanAmountPaid != 0) {\n _safeTransfer(loanTokenAddress, receiver, loanAmountPaid, \"5\");\n }\n }\n\n /**\n * @notice transfers the underlying asset from the msg.sender and mints tokens for the receiver\n * @param receiver the address of the iToken receiver\n * @param depositAmount the amount of underlying assets to be deposited\n * @return the amount of iTokens issued\n */\n function _mintToken(address receiver, uint256 depositAmount)\n internal\n returns (uint256 mintAmount)\n {\n uint256 currentPrice;\n\n //calculate amount to mint and transfer the underlying asset\n (mintAmount, currentPrice) = _prepareMinting(depositAmount);\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n receiver\n );\n uint256 oldBalance = balances[receiver].add(balanceOnLM);\n uint256 newBalance = oldBalance.add(mintAmount);\n\n //mint the tokens to the receiver\n _mint(receiver, mintAmount, depositAmount, currentPrice);\n\n //update the checkpoint of the receiver\n _updateCheckpoints(receiver, oldBalance, newBalance, currentPrice);\n }\n\n /**\n * calculates the amount of tokens to mint and transfers the underlying asset to this contract\n * @param depositAmount the amount of the underyling asset deposited\n * @return the amount to be minted\n */\n function _prepareMinting(uint256 depositAmount)\n internal\n returns (uint256 mintAmount, uint256 currentPrice)\n {\n require(depositAmount != 0, \"17\");\n\n _settleInterest();\n\n currentPrice = _tokenPrice(_totalAssetSupply(0));\n mintAmount = depositAmount.mul(10**18).div(currentPrice);\n\n if (msg.value == 0) {\n _safeTransferFrom(loanTokenAddress, msg.sender, address(this), depositAmount, \"18\");\n } else {\n IWrbtc(wrbtcTokenAddress).deposit.value(depositAmount)();\n }\n }\n\n /**\n * @notice A wrapper for AdvancedToken::_burn\n *\n * @param burnAmount The amount of loan tokens to redeem.\n *\n * @return The amount of underlying tokens payed to lender.\n * */\n function _burnToken(uint256 burnAmount) internal returns (uint256 loanAmountPaid) {\n require(burnAmount != 0, \"19\");\n\n if (burnAmount > balanceOf(msg.sender)) {\n require(burnAmount == uint256(-1), \"32\");\n burnAmount = balanceOf(msg.sender);\n }\n\n _settleInterest();\n\n uint256 currentPrice = _tokenPrice(_totalAssetSupply(0));\n\n uint256 loanAmountOwed = burnAmount.mul(currentPrice).div(10**18);\n uint256 loanAmountAvailableInContract = _underlyingBalance();\n\n loanAmountPaid = loanAmountOwed;\n require(loanAmountPaid <= loanAmountAvailableInContract, \"37\");\n\n //compute balances needed for checkpoint update, considering that the user might have a pool token balance\n //on the liquidity mining contract\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0))\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n uint256 oldBalance = balances[msg.sender].add(balanceOnLM);\n uint256 newBalance = oldBalance.sub(burnAmount);\n\n _burn(msg.sender, burnAmount, loanAmountPaid, currentPrice);\n\n //this function does not only update the checkpoints but also the current profit of the user\n //all for external use only\n _updateCheckpoints(msg.sender, oldBalance, newBalance, currentPrice);\n }\n\n function _mintWithLM(address receiver, uint256 depositAmount)\n internal\n returns (uint256 minted)\n {\n //mint the tokens for the receiver\n minted = _mintToken(receiver, depositAmount);\n\n //transfer the tokens from the receiver to the LM address\n _internalTransferFrom(receiver, liquidityMiningAddress, minted, minted);\n\n //inform the LM mining contract\n ILiquidityMining(liquidityMiningAddress).onTokensDeposited(receiver, minted);\n }\n\n function _burnFromLM(uint256 burnAmount) internal returns (uint256) {\n uint256 balanceOnLM =\n ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n msg.sender\n );\n require(balanceOnLM.add(balanceOf(msg.sender)) >= burnAmount, \"not enough balance\");\n\n if (balanceOnLM > 0) {\n //withdraw pool tokens and LM rewards to the passed address\n if (balanceOnLM < burnAmount) {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n balanceOnLM,\n msg.sender\n );\n } else {\n ILiquidityMining(liquidityMiningAddress).withdraw(\n address(this),\n burnAmount,\n msg.sender\n );\n }\n }\n //burn the tokens of the msg.sender\n return _burnToken(burnAmount);\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStandard.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanTokenLogicShared.sol\";\n\ncontract LoanTokenLogicStandard is LoanTokenLogicShared {\n /**\n * @notice Transfer tokens wrapper.\n * Sets token owner the msg.sender.\n * Sets maximun allowance uint256(-1) to ensure tokens are always transferred.\n *\n * If the recipient (_to) is a vesting contract address, transfer the token to the tokenOwner of the vesting contract itself.\n *\n * @param _to The recipient of the tokens.\n * @param _value The amount of tokens sent.\n * @return Success true/false.\n * */\n function transfer(address _to, uint256 _value) external returns (bool) {\n /** need additional check address(0) here to support backward compatibility\n * in case we don't want to activate this check, just need to set the stakingContractAddress to 0 address\n */\n if (\n stakingContractAddress != address(0) &&\n IStaking(stakingContractAddress).isVestingContract(_to)\n ) {\n (bool success, bytes memory data) =\n _to.staticcall(abi.encodeWithSelector(IVesting(_to).tokenOwner.selector));\n\n if (success) _to = abi.decode(data, (address));\n }\n\n return _internalTransferFrom(msg.sender, _to, _value, uint256(-1));\n }\n\n /**\n * @notice Moves `_value` loan tokens from `_from` to `_to` using the\n * allowance mechanism. Calls internal _internalTransferFrom function.\n *\n * @return A boolean value indicating whether the operation succeeded.\n */\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool) {\n return\n _internalTransferFrom(\n _from,\n _to,\n _value,\n //allowed[_from][msg.sender]\n ProtocolLike(sovrynContractAddress).isLoanPool(msg.sender)\n ? uint256(-1)\n : allowed[_from][msg.sender]\n );\n }\n\n /**\n * @notice Borrow funds from the pool.\n * The underlying loan token may not be used as collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * (150% of the withdrawn amount worth in collateral tokens).\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param borrower The one paying for the collateral.\n * @param receiver The one receiving the withdrawn amount.\n *\n * @return New principal and new collateral added to loan.\n * */\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes memory /// loanDataBytes: arbitrary order data (for future use).\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n )\n {\n require(withdrawAmount != 0, \"6\");\n\n _checkPause();\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n\n require(\n (msg.value == 0 || msg.value == collateralTokenSent) &&\n (collateralTokenSent != 0 || loanId != 0) &&\n (collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0) &&\n (loanId == 0 || msg.sender == borrower),\n \"7\"\n );\n\n /// @dev We have an issue regarding contract size code is too big. 1 of the solution is need to keep the error message 32 bytes length\n // Temporarily, we combine this require to the above, so can save the contract size code\n // require(collateralTokenSent != 0 || loanId != 0, \"8\");\n // require(collateralTokenAddress != address(0) || msg.value != 0 || loanId != 0, \"9\");\n\n /// @dev Ensure authorized use of existing loan.\n // require(loanId == 0 || msg.sender == borrower, \"401 use of existing loan\");\n\n /// @dev The condition is never met.\n /// Address zero is not allowed by previous require validation.\n /// This check is unneeded and was lowering the test coverage index.\n // if (collateralTokenAddress == address(0)) {\n // \tcollateralTokenAddress = wrbtcTokenAddress;\n // }\n\n require(collateralTokenAddress != loanTokenAddress, \"10\");\n\n _settleInterest();\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this); /// The lender.\n sentAddresses.borrower = borrower;\n sentAddresses.receiver = receiver;\n /// sentAddresses.manager = address(0); /// The manager.\n\n sentAmounts.newPrincipal = withdrawAmount;\n\n /// interestRate, interestInitialAmount, borrowAmount (newBorrowAmount).\n (\n sentAmounts.interestRate,\n sentAmounts.interestInitialAmount,\n sentAmounts.newPrincipal\n ) = _getInterestRateAndBorrowAmount(\n sentAmounts.newPrincipal,\n _totalAssetSupply(0), /// Interest is settled above.\n initialLoanDuration\n );\n\n /// sentAmounts.loanTokenSent = 0; /// loanTokenSent\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n return\n _borrowOrTrade(\n loanId,\n withdrawAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ]\n ),\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Borrow and immediately get into a position.\n *\n * Trading on margin is used to increase an investor's buying power.\n * Margin is the amount of money required to open a position, while\n * leverage is the multiple of exposure to account equity.\n *\n * Leverage allows you to trade positions LARGER than the amount\n * of money in your trading account. Leverage is expressed as a ratio.\n *\n * When trading on margin, investors first deposit some token that then\n * serves as collateral for the loan, and then pay ongoing interest\n * payments on the money they borrow.\n *\n * Margin trading = taking a loan and swapping it:\n * In order to open a margin trade position,\n * 1.- The user calls marginTrade on the loan token contract.\n * 2.- The loan token contract provides the loan and sends it for processing\n * to the protocol proxy contract.\n * 3.- The protocol proxy contract uses the module LoanOpening to create a\n * position and swaps the loan tokens to collateral tokens.\n * 4.- The Sovryn Swap network looks up the correct converter and swaps the\n * tokens.\n * If successful, the position is being held by the protocol proxy contract,\n * which is why positions need to be closed at the protocol proxy contract.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n * */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // value of loan token in collateral\n bytes memory loanDataBytes /// Arbitrary order data.\n )\n public\n payable\n nonReentrant /// Note: needs to be removed to allow flashloan use cases.\n globallyNonReentrant\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n _checkPause();\n\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n require(collateralTokenAddress != loanTokenAddress, \"11\");\n\n /// @dev Ensure authorized use of existing loan.\n require(loanId == 0 || msg.sender == trader, \"401 use of existing loan\");\n\n /// Temporary: limit transaction size.\n if (transactionLimit[collateralTokenAddress] > 0)\n require(collateralTokenSent <= transactionLimit[collateralTokenAddress]);\n if (transactionLimit[loanTokenAddress] > 0)\n require(loanTokenSent <= transactionLimit[loanTokenAddress]);\n\n /// @dev Compute the worth of the total deposit in loan tokens.\n /// (loanTokenSent + convert(collateralTokenSent))\n /// No actual swap happening here.\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n require(totalDeposit != 0, \"12\");\n\n MarginTradeStructHelpers.SentAddresses memory sentAddresses;\n MarginTradeStructHelpers.SentAmounts memory sentAmounts;\n\n sentAddresses.lender = address(this);\n sentAddresses.borrower = trader;\n sentAddresses.receiver = trader;\n /// sentAddresses.manager = address(0); /// The manager.\n\n /// sentAmounts.interestRate = 0; /// interestRate (found later).\n sentAmounts.newPrincipal = totalDeposit;\n /// sentAmounts.interestInitialAmount = 0; /// interestInitialAmount (interest is calculated based on fixed-term loan).\n sentAmounts.loanTokenSent = loanTokenSent;\n sentAmounts.collateralTokenSent = collateralTokenSent;\n\n _settleInterest();\n\n (sentAmounts.newPrincipal, sentAmounts.interestRate) = _getMarginBorrowAmountAndRate( /// borrowAmount, interestRate\n leverageAmount,\n sentAmounts.newPrincipal /// depositAmount\n );\n\n require(\n _getAmountInRbtc(loanTokenAddress, sentAmounts.newPrincipal) > TINY_AMOUNT,\n \"principal too small\"\n );\n\n /// @dev Converting to initialMargin\n leverageAmount = SafeMath.div(10**38, leverageAmount);\n sentAmounts.minEntryPrice = minEntryPrice;\n return\n _borrowOrTrade(\n loanId,\n 0, /// withdrawAmount\n leverageAmount, //initial margin\n collateralTokenAddress,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n );\n }\n\n /**\n * @notice Wrapper for marginTrade invoking setAffiliatesReferrer to track\n * referral trade by affiliates program.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n * @param trader The account that performs this trade.\n * @param minEntryPrice Value of loan token in collateral.\n * @param affiliateReferrer The address of the referrer from affiliates program.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return New principal and new collateral added to trade.\n */\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, /// Value of loan token in collateral\n address affiliateReferrer, /// The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n )\n {\n if (affiliateReferrer != address(0))\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(\n trader,\n affiliateReferrer\n );\n return\n marginTrade(\n loanId,\n leverageAmount,\n loanTokenSent,\n collateralTokenSent,\n collateralTokenAddress,\n trader,\n minEntryPrice,\n loanDataBytes\n );\n }\n\n /* Public View functions */\n\n /**\n * @notice Wrapper for internal _profitOf low level function.\n * @param user The user address.\n * @return The profit of a user.\n * */\n function profitOf(address user) external view returns (int256) {\n /// @dev keccak256(\"iToken_ProfitSoFar\")\n bytes32 slot = keccak256(abi.encodePacked(user, iToken_ProfitSoFar));\n //TODO + LM balance\n return _profitOf(slot, balances[user], tokenPrice(), checkpointPrices_[user]);\n }\n\n /**\n * @notice Getter for the price checkpoint mapping.\n * @param _user The user account as the mapping index.\n * @return The price on the checkpoint for this user.\n * */\n function checkpointPrice(address _user) public view returns (uint256 price) {\n return checkpointPrices_[_user];\n }\n\n /**\n * @notice Get current liquidity.\n * A part of total funds supplied are borrowed. Liquidity = supply - borrow\n * @return The market liquidity.\n * */\n function marketLiquidity() public view returns (uint256) {\n uint256 totalSupply = _totalAssetSupply(0);\n uint256 totalBorrow = totalAssetBorrow();\n if (totalSupply > totalBorrow) {\n return totalSupply - totalBorrow;\n }\n }\n\n /**\n * @notice Wrapper for average borrow interest.\n * @return The average borrow interest.\n * */\n function avgBorrowInterestRate() public view returns (uint256) {\n return _avgBorrowInterestRate(totalAssetBorrow());\n }\n\n /**\n * @notice Get borrow interest rate.\n * The minimum rate the next base protocol borrower will receive\n * for variable-rate loans.\n * @return The borrow interest rate.\n * */\n function borrowInterestRate() public view returns (uint256) {\n return _nextBorrowInterestRate(0);\n }\n\n /**\n * @notice Public wrapper for internal call.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest rate.\n * */\n function nextBorrowInterestRate(uint256 borrowAmount) public view returns (uint256) {\n return _nextBorrowInterestRate(borrowAmount);\n }\n\n /**\n * @notice Get interest rate.\n *\n * @return Interest that lenders are currently receiving when supplying to\n * the pool.\n * */\n function supplyInterestRate() public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0));\n }\n\n /**\n * @notice Get interest rate w/ added supply.\n * @param supplyAmount The amount of tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of tokens to the pool.\n * */\n function nextSupplyInterestRate(uint256 supplyAmount) public view returns (uint256) {\n return totalSupplyInterestRate(_totalAssetSupply(0).add(supplyAmount));\n }\n\n /**\n * @notice Get interest rate w/ added supply assets.\n * @param assetSupply The amount of loan tokens supplied.\n * @return Interest that lenders are currently receiving when supplying\n * a given amount of loan tokens to the pool.\n * */\n function totalSupplyInterestRate(uint256 assetSupply) public view returns (uint256) {\n uint256 assetBorrow = totalAssetBorrow();\n if (assetBorrow != 0) {\n return calculateSupplyInterestRate(assetBorrow, assetSupply);\n }\n }\n\n /**\n * @notice Get the total amount of loan tokens on supply.\n * @dev Wrapper for internal _totalAssetSupply function.\n * @return The total amount of loan tokens on supply.\n * */\n function totalAssetSupply() public view returns (uint256) {\n uint256 interestUnPaid;\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n return _totalAssetSupply(interestUnPaid);\n }\n\n /**\n * @notice Compute the maximum deposit amount under current market conditions.\n * @dev maxEscrowAmount = liquidity * (100 - interestForDuration) / 100\n * @param leverageAmount The chosen multiplier with 18 decimals.\n * */\n function getMaxEscrowAmount(uint256 leverageAmount)\n public\n view\n returns (uint256 maxEscrowAmount)\n {\n /**\n * @dev Mathematical imperfection: depending on liquidity we might be able\n * to borrow more if utilization is below the kink level.\n * */\n uint256 interestForDuration = maxScaleRate.mul(28).div(365);\n uint256 factor = uint256(10**20).sub(interestForDuration);\n uint256 maxLoanSize = marketLiquidity().mul(factor).div(10**20);\n maxEscrowAmount = maxLoanSize.mul(10**18).div(leverageAmount);\n }\n\n /**\n * @notice Get loan token balance.\n * @return The user's balance of underlying token.\n * */\n function assetBalanceOf(address _owner) public view returns (uint256) {\n uint256 balanceOnLM = 0;\n if (liquidityMiningAddress != address(0)) {\n balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(\n address(this),\n _owner\n );\n }\n return balanceOf(_owner).add(balanceOnLM).mul(tokenPrice()).div(10**18);\n }\n\n /**\n * @notice Get margin information on a trade.\n *\n * @param leverageAmount The multiple of exposure: 2x ... 5x. The leverage with 18 decimals.\n * @param loanTokenSent The number of loan tokens provided by the user.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The principal, the collateral and the interestRate.\n * */\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n public\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n )\n {\n if (collateralTokenAddress == address(0)) {\n collateralTokenAddress = wrbtcTokenAddress;\n }\n\n uint256 totalDeposit =\n _totalDeposit(collateralTokenAddress, collateralTokenSent, loanTokenSent);\n\n (principal, interestRate) = _getMarginBorrowAmountAndRate(leverageAmount, totalDeposit);\n if (principal > _underlyingBalance()) {\n return (0, 0, 0);\n }\n\n loanTokenSent = loanTokenSent.add(principal);\n\n collateral = ProtocolLike(sovrynContractAddress).getEstimatedMarginExposure(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent,\n collateralTokenSent,\n interestRate,\n principal\n );\n }\n\n /**\n * @notice Calculate the deposit required to a given borrow.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param borrowAmount The amount of borrow.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of deposit required.\n * */\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 depositAmount) {\n if (borrowAmount != 0) {\n (, , uint256 newBorrowAmount) =\n _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (newBorrowAmount <= _underlyingBalance()) {\n if (collateralTokenAddress == address(0))\n collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))\n ];\n return\n ProtocolLike(sovrynContractAddress)\n .getRequiredCollateral(\n loanTokenAddress,\n collateralTokenAddress,\n newBorrowAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin\n true /// isTorqueLoan\n )\n .add(10); /// Some dust to compensate for rounding errors.\n }\n }\n }\n\n /**\n * @notice Calculate the borrow allowed for a given deposit.\n *\n * The function for doing over-collateralized borrows against loan tokens\n * expects a minimum amount of collateral be sent to satisfy collateral\n * requirements of the loan, for borrow amount, interest rate, and\n * initial loan duration. To determine appropriate values to pass to this\n * function for a given loan, `getDepositAmountForBorrow` and\n * 'getBorrowAmountForDeposit` are required.\n *\n * @param depositAmount The amount of deposit.\n * @param initialLoanDuration The duration of the loan.\n * @param collateralTokenAddress The token address of collateral.\n *\n * @return The amount of borrow allowed.\n * */\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) public view returns (uint256 borrowAmount) {\n if (depositAmount != 0) {\n if (collateralTokenAddress == address(0)) collateralTokenAddress = wrbtcTokenAddress;\n bytes32 loanParamsId =\n loanParamsIds[uint256(keccak256(abi.encodePacked(collateralTokenAddress, true)))];\n borrowAmount = ProtocolLike(sovrynContractAddress).getBorrowAmount(\n loanTokenAddress,\n collateralTokenAddress,\n depositAmount,\n ProtocolSettingsLike(sovrynContractAddress).minInitialMargin(loanParamsId), /// initialMargin,\n true /// isTorqueLoan\n );\n\n (, , borrowAmount) = _getInterestRateAndBorrowAmount(\n borrowAmount,\n totalAssetSupply(),\n initialLoanDuration\n );\n\n if (borrowAmount > _underlyingBalance()) {\n borrowAmount = 0;\n }\n }\n }\n\n /**\n * @notice Check if entry price lies above a minimum\n *\n * @param loanTokenSent The amount of deposit.\n * @param collateralTokenAddress The token address of collateral.\n * @param minEntryPrice Value of loan token in collateral\n * */\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) public view {\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokensReceived =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenSent\n );\n uint256 collateralTokenPrice =\n (collateralTokensReceived.mul(WEI_PRECISION)).div(loanTokenSent);\n require(collateralTokenPrice >= minEntryPrice, \"entry price above the minimum\");\n }\n\n /**\n * @notice Compute the next supply interest adjustment.\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next supply interest adjustment.\n * */\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n public\n view\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply >= assetBorrow) {\n return\n _avgBorrowInterestRate(assetBorrow)\n .mul(_utilizationRate(assetBorrow, assetSupply))\n .mul(\n SafeMath.sub(10**20, ProtocolLike(sovrynContractAddress).lendingFeePercent())\n )\n .div(10**40);\n }\n }\n\n /* Internal functions */\n\n /**\n * @notice Compute what the deposit is worth in loan tokens using the swap rate\n * used for loan size computation.\n *\n * @param collateralTokenAddress The token address of the collateral.\n * @param collateralTokenSent The amount of collateral tokens provided by the user.\n * @param loanTokenSent The number of loan tokens provided by the user.\n *\n * @return The value of the deposit in loan tokens.\n * */\n function _totalDeposit(\n address collateralTokenAddress,\n uint256 collateralTokenSent,\n uint256 loanTokenSent\n ) internal view returns (uint256 totalDeposit) {\n totalDeposit = loanTokenSent;\n\n if (collateralTokenSent != 0) {\n /// @dev Get the oracle rate from collateral -> loan\n (uint256 collateralToLoanRate, uint256 collateralToLoanPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n collateralTokenAddress,\n loanTokenAddress\n );\n require(\n (collateralToLoanRate != 0) && (collateralToLoanPrecision != 0),\n \"invalid rate collateral token\"\n );\n\n /// @dev Compute the loan token amount with the oracle rate.\n uint256 loanTokenAmount =\n collateralTokenSent.mul(collateralToLoanRate).div(collateralToLoanPrecision);\n\n /// @dev See how many collateralTokens we would get if exchanging this amount of loan tokens to collateral tokens.\n uint256 collateralTokenAmount =\n ProtocolLike(sovrynContractAddress).getSwapExpectedReturn(\n loanTokenAddress,\n collateralTokenAddress,\n loanTokenAmount\n );\n\n /// @dev Probably not the same due to the price difference.\n if (collateralTokenAmount != collateralTokenSent) {\n //scale the loan token amount accordingly, so we'll get the expected position size in the end\n loanTokenAmount = loanTokenAmount.mul(collateralTokenAmount).div(\n collateralTokenSent\n );\n }\n\n totalDeposit = loanTokenAmount.add(totalDeposit);\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n FeedsLike(ProtocolLike(sovrynContractAddress).priceFeeds()).queryRate(\n asset,\n wrbtcTokenAddress\n );\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /*\n * @notice Compute interest rate and other loan parameters.\n *\n * @param borrowAmount The amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @param initialLoanDuration The duration of the loan in seconds.\n * If the loan is not paid back until then, it'll need to be rolled over.\n *\n * @return The interest rate, the interest calculated based on fixed-term\n * loan, and the new borrow amount.\n * */\n function _getInterestRateAndBorrowAmount(\n uint256 borrowAmount,\n uint256 assetSupply,\n uint256 initialLoanDuration /// Duration in seconds.\n )\n internal\n view\n returns (\n uint256 interestRate,\n uint256 interestInitialAmount,\n uint256 newBorrowAmount\n )\n {\n interestRate = _nextBorrowInterestRate2(borrowAmount, assetSupply);\n\n /// newBorrowAmount = borrowAmount * 10^18 / (10^18 - interestRate * 7884000 * 10^18 / 31536000 / 10^20)\n newBorrowAmount = borrowAmount.mul(10**18).div(\n SafeMath.sub(\n 10**18,\n interestRate.mul(initialLoanDuration).mul(10**18).div(31536000 * 10**20) /// 365 * 86400 * 10**20\n )\n );\n\n interestInitialAmount = newBorrowAmount.sub(borrowAmount);\n }\n\n /**\n * @notice Compute principal and collateral.\n *\n * @param loanId The ID of the loan, 0 for a new loan.\n * @param withdrawAmount The amount to be withdrawn (actually borrowed).\n * @param initialMargin The initial margin with 18 decimals\n * @param collateralTokenAddress The address of the token to be used as\n * collateral. Cannot be the loan token address.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager.\n * @param sentAmounts The amounts to send to each address.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return The new principal and the new collateral. Principal is the\n * complete borrowed amount (in loan tokens). Collateral is the complete\n * position size (loan + margin) (in collateral tokens).\n * */\n function _borrowOrTrade(\n bytes32 loanId,\n uint256 withdrawAmount,\n uint256 initialMargin,\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n _checkPause();\n require(\n sentAmounts.newPrincipal <= _underlyingBalance() && /// newPrincipal (borrowed amount + fees)\n sentAddresses.borrower != address(0), /// The borrower.\n \"24\"\n );\n\n if (sentAddresses.receiver == address(0)) {\n sentAddresses.receiver = sentAddresses.borrower; /// The receiver = the borrower.\n }\n\n /// @dev Handle transfers prior to adding newPrincipal to loanTokenSent\n uint256 msgValue =\n _verifyTransfers(collateralTokenAddress, sentAddresses, sentAmounts, withdrawAmount);\n\n /**\n * @dev Adding the loan token portion from the lender to loanTokenSent\n * (add the loan to the loan tokens sent from the user).\n * */\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.add(sentAmounts.newPrincipal); /// newPrincipal\n\n if (withdrawAmount != 0) {\n /// @dev withdrawAmount already sent to the borrower, so we aren't sending it to the protocol.\n sentAmounts.loanTokenSent = sentAmounts.loanTokenSent.sub(withdrawAmount);\n }\n\n bool withdrawAmountExist = false; /// Default is false, but added just as to make sure.\n\n if (withdrawAmount != 0) {\n withdrawAmountExist = true;\n }\n\n bytes32 loanParamsId =\n loanParamsIds[\n uint256(keccak256(abi.encodePacked(collateralTokenAddress, withdrawAmountExist)))\n ];\n\n (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent) = ProtocolLike(\n sovrynContractAddress\n )\n .borrowOrTradeFromPool\n .value(msgValue)(\n loanParamsId,\n loanId,\n withdrawAmountExist,\n initialMargin,\n sentAddresses,\n sentAmounts,\n loanDataBytes\n ); /// newPrincipal, newCollateral\n require(sentAmounts.newPrincipal != 0, \"25\");\n\n /// @dev Setting not-first-trade flag to prevent binding to an affiliate existing users post factum.\n /// @dev REFACTOR: move to a general interface: ProtocolSettingsLike?\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(\n sentAddresses.borrower\n );\n\n return (sentAmounts.newPrincipal, sentAmounts.collateralTokenSent); // newPrincipal, newCollateral\n }\n\n /* Internal View functions */\n\n /**\n * @notice Compute the average borrow interest rate.\n * @param assetBorrow The amount of loan tokens on debt.\n * @return The average borrow interest rate.\n * */\n function _avgBorrowInterestRate(uint256 assetBorrow) internal view returns (uint256) {\n if (assetBorrow != 0) {\n (uint256 interestOwedPerDay, ) = _getAllInterest();\n return interestOwedPerDay.mul(10**20).mul(365).div(assetBorrow);\n }\n }\n\n /**\n * @notice Compute the next borrow interest adjustment.\n * @param borrowAmount The amount of tokens to borrow.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate(uint256 borrowAmount) internal view returns (uint256) {\n uint256 interestUnPaid;\n if (borrowAmount != 0) {\n if (lastSettleTime_ != uint88(block.timestamp)) {\n (, interestUnPaid) = _getAllInterest();\n }\n\n uint256 balance = _underlyingBalance().add(interestUnPaid);\n if (borrowAmount > balance) {\n borrowAmount = balance;\n }\n }\n\n return _nextBorrowInterestRate2(borrowAmount, _totalAssetSupply(interestUnPaid));\n }\n\n /**\n * @notice Compute the next borrow interest adjustment under target-kink\n * level analysis.\n *\n * The \"kink\" in the cDAI interest rate model reflects the utilization rate\n * at which the slope of the interest rate goes from \"gradual\" to \"steep\".\n * That is, below this utilization rate, the slope of the interest rate\n * curve is gradual. Above this utilization rate, it is steep.\n *\n * Because of this dynamic between the interest rate curves before and\n * after the \"kink\", the \"kink\" can be thought of as the target utilization\n * rate. Above that rate, it quickly becomes expensive to borrow (and\n * commensurately lucrative for suppliers).\n *\n * @param newBorrowAmount The new amount of tokens to borrow.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The next borrow interest adjustment.\n * */\n function _nextBorrowInterestRate2(uint256 newBorrowAmount, uint256 assetSupply)\n internal\n view\n returns (uint256 nextRate)\n {\n uint256 utilRate = _utilizationRate(totalAssetBorrow().add(newBorrowAmount), assetSupply);\n\n uint256 thisMinRate;\n uint256 thisRateAtKink;\n uint256 thisBaseRate = baseRate;\n uint256 thisRateMultiplier = rateMultiplier;\n uint256 thisTargetLevel = targetLevel;\n uint256 thisKinkLevel = kinkLevel;\n uint256 thisMaxScaleRate = maxScaleRate;\n\n if (utilRate < thisTargetLevel) {\n // target targetLevel utilization when utilization is under targetLevel\n utilRate = thisTargetLevel;\n }\n\n if (utilRate > thisKinkLevel) {\n /// @dev Scale rate proportionally up to 100%\n uint256 thisMaxRange = WEI_PERCENT_PRECISION - thisKinkLevel; /// Will not overflow.\n\n utilRate -= thisKinkLevel;\n if (utilRate > thisMaxRange) utilRate = thisMaxRange;\n\n // Modified the rate calculation as it is slightly exaggerated around kink level\n // thisRateAtKink = thisRateMultiplier.add(thisBaseRate).mul(thisKinkLevel).div(WEI_PERCENT_PRECISION);\n thisRateAtKink = thisKinkLevel.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n nextRate = utilRate\n .mul(SafeMath.sub(thisMaxScaleRate, thisRateAtKink))\n .div(thisMaxRange)\n .add(thisRateAtKink);\n } else {\n nextRate = utilRate.mul(thisRateMultiplier).div(WEI_PERCENT_PRECISION).add(\n thisBaseRate\n );\n\n thisMinRate = thisBaseRate;\n thisRateAtKink = thisRateMultiplier.add(thisBaseRate);\n\n if (nextRate < thisMinRate) nextRate = thisMinRate;\n else if (nextRate > thisRateAtKink) nextRate = thisRateAtKink;\n }\n }\n\n /**\n * @notice Compute the loan size and interest rate.\n * @param leverageAmount The leverage with 18 decimals.\n * @param depositAmount The amount the user deposited in underlying loan tokens.\n * @return borrowAmount The amount of tokens to borrow.\n * @return interestRate The interest rate to pay on the position.\n * */\n function _getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n internal\n view\n returns (uint256 borrowAmount, uint256 interestRate)\n {\n uint256 loanSizeBeforeInterest = depositAmount.mul(leverageAmount).div(10**18);\n /**\n * @dev Mathematical imperfection. we calculate the interest rate based on\n * the loanSizeBeforeInterest, but the actual borrowed amount will be bigger.\n * */\n interestRate = _nextBorrowInterestRate2(loanSizeBeforeInterest, _totalAssetSupply(0));\n /// @dev Assumes that loan, collateral, and interest token are the same.\n borrowAmount = _adjustLoanSize(interestRate, 28 days, loanSizeBeforeInterest);\n }\n\n /**\n * @notice Make sure call is not paused.\n * @dev Used for internal verification if the called function is paused.\n * It throws an exception in case it's not.\n * */\n function _checkPause() internal view {\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n msg.sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n bool isPaused;\n assembly {\n isPaused := sload(slot)\n }\n require(!isPaused, \"unauthorized\");\n }\n\n /**\n * @notice Adjusts the loan size to make sure the expected exposure remains after prepaying the interest.\n * @dev loanSizeWithInterest = loanSizeBeforeInterest * 100 / (100 - interestForDuration)\n * @param interestRate The interest rate to pay on the position.\n * @param maxDuration The maximum duration of the position (until rollover).\n * @param loanSizeBeforeInterest The loan size before interest is added.\n * */\n function _adjustLoanSize(\n uint256 interestRate,\n uint256 maxDuration,\n uint256 loanSizeBeforeInterest\n ) internal pure returns (uint256 loanSizeWithInterest) {\n uint256 interestForDuration = interestRate.mul(maxDuration).div(365 days);\n uint256 divisor = uint256(10**20).sub(interestForDuration);\n loanSizeWithInterest = loanSizeBeforeInterest.mul(10**20).div(divisor);\n }\n\n /**\n * @notice Calculate the utilization rate.\n * @dev Utilization rate = assetBorrow / assetSupply\n * @param assetBorrow The amount of loan tokens on debt.\n * @param assetSupply The amount of loan tokens supplied.\n * @return The utilization rate.\n * */\n function _utilizationRate(uint256 assetBorrow, uint256 assetSupply)\n internal\n pure\n returns (uint256)\n {\n if (assetBorrow != 0 && assetSupply != 0) {\n /// U = total_borrow / total_supply\n return assetBorrow.mul(10**20).div(assetSupply);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/LoanTokenLogicStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./AdvancedToken.sol\";\n\ncontract LoanTokenLogicStorage is AdvancedToken {\n /// DO NOT ADD VARIABLES HERE - SEE BELOW\n\n /// @dev It is important to maintain the variables order so the delegate\n /// calls can access sovrynContractAddress\n\n /// ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address public target_;\n address public admin;\n /// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n /// @dev Add new variables here on the bottom.\n address public earlyAccessToken; //not used anymore, but staying for upgradability\n address public pauser;\n /** The address of the liquidity mining contract */\n address public liquidityMiningAddress;\n\n /** The address of the staking contract */\n address public stakingContractAddress;\n\n /// @dev Used by flashBorrow function.\n uint256 public constant VERSION = 6;\n /// @dev Used by flashBorrow function.\n address internal constant arbitraryCaller = 0x000F400e6818158D541C3EBE45FE3AA0d47372FF;\n bytes32 internal constant iToken_ProfitSoFar =\n 0x37aa2b7d583612f016e4a4de4292cb015139b3d7762663d06a53964912ea2fb6; // keccak256(\"iToken_ProfitSoFar\")\n uint256 public constant TINY_AMOUNT = 25e13;\n\n function stringToBytes32(string memory source) public pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"unauthorized\"); // SS02\n _;\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogic is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenMintAndBurn also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token LM & OVERLOADING function\n /**\n * @notice BE CAREFUL,\n * LoanTokenLogicStandard also has mint & burn function (overloading).\n * You need to compute the function signature manually --> bytes4(keccak256(\"mint(address,uint256,bool)\"))\n */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\")); /// LoanTokenLogicStandard\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\")); /// LoanTokenLogicLM\n res[2] = bytes4(keccak256(\"burn(address,uint256)\")); /// LoanTokenLogicStandard\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\")); /// LoanTokenLogicLM\n\n return (res, stringToBytes32(\"LoanTokenLogicLM\"));\n }\n\n /**\n * @notice deposit into the lending pool and optionally participate at the Liquidity Mining Program\n * @param receiver the receiver of the tokens\n * @param depositAmount The amount of underlying tokens provided on the loan.\n *\t\t\t\t\t\t(Not the number of loan tokens to mint).\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 minted) {\n if (useLM) return _mintWithLM(receiver, depositAmount);\n else return _mintToken(receiver, depositAmount);\n }\n\n /**\n * @notice withdraws from the lending pool and optionally retrieves the pool tokens from the\n * Liquidity Mining Contract\n * @param receiver the receiver of the underlying tokens. note: potetial LM rewards are always sent to the msg.sender\n * @param burnAmount The amount of pool tokens to redeem.\n * @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract\n */\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 redeemed) {\n if (useLM) redeemed = _burnFromLM(burnAmount);\n else redeemed = _burnToken(burnAmount);\n //this needs to be here and not in _burnTokens because of the WRBTC implementation\n if (redeemed != 0) {\n _safeTransfer(loanTokenAddress, receiver, redeemed, \"asset transfer failed\");\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtc.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicStandard.sol\";\n\ncontract LoanTokenLogicWrbtc is LoanTokenLogicStandard {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](28);\n\n // Loan Token Logic Standard, Trade & Borrow\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtc\"));\n }\n\n /**\n * @dev internal override functions\n * @dev Put all of internal override function dedicated to the loanTokenWrtbc module here\n * e.g: _verifyTransfers will override the implementation of _verifyTransfers in loanTokenLogicSplit\n */\n\n /**\n * @notice Handle transfers prior to adding newPrincipal to loanTokenSent.\n *\n * @param collateralTokenAddress The address of the collateral token.\n * @param sentAddresses The struct which contains addresses of\n * - lender\n * - borrower\n * - receiver\n * - manager\n *\n * @param sentAmounts The struct which contains uint256 of:\n * - interestRate\n * - newPrincipal\n * - interestInitialAmount\n * - loanTokenSent\n * - collateralTokenSent\n *\n * @param withdrawalAmount The amount to withdraw.\n *\n * @return msgValue The amount of value sent.\n * */\n function _verifyTransfers(\n address collateralTokenAddress,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentAmounts,\n uint256 withdrawalAmount\n ) internal returns (uint256 msgValue) {\n address _wrbtcToken = wrbtcTokenAddress;\n address _loanTokenAddress = _wrbtcToken;\n address receiver = sentAddresses.receiver;\n uint256 newPrincipal = sentAmounts.newPrincipal;\n uint256 loanTokenSent = sentAmounts.loanTokenSent;\n uint256 collateralTokenSent = sentAmounts.collateralTokenSent;\n\n require(_loanTokenAddress != collateralTokenAddress, \"26\");\n\n msgValue = msg.value;\n\n if (withdrawalAmount != 0) {\n /// withdrawOnOpen == true\n IWrbtcERC20(_wrbtcToken).withdraw(withdrawalAmount);\n Address.sendValue(receiver, withdrawalAmount);\n if (newPrincipal > withdrawalAmount) {\n _safeTransfer(\n _loanTokenAddress,\n sovrynContractAddress,\n newPrincipal - withdrawalAmount,\n \"\"\n );\n }\n } else {\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, newPrincipal, \"27\");\n }\n\n if (collateralTokenSent != 0) {\n _safeTransferFrom(\n collateralTokenAddress,\n msg.sender,\n sovrynContractAddress,\n collateralTokenSent,\n \"28\"\n );\n }\n\n if (loanTokenSent != 0) {\n if (msgValue != 0 && msgValue >= loanTokenSent) {\n IWrbtc(_wrbtcToken).deposit.value(loanTokenSent)();\n _safeTransfer(_loanTokenAddress, sovrynContractAddress, loanTokenSent, \"29\");\n msgValue -= loanTokenSent;\n } else {\n _safeTransferFrom(\n _loanTokenAddress,\n msg.sender,\n sovrynContractAddress,\n loanTokenSent,\n \"29\"\n );\n }\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/beaconLogicWRBTC/LoanTokenLogicWrbtcLM.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../LoanTokenLogicSplit.sol\";\n\ncontract LoanTokenLogicWrbtcLM is LoanTokenLogicSplit {\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n // Loan Token Mint and Burn.\n res[0] = this.mint.selector;\n res[1] = this.burn.selector;\n\n // Loan Token WRBTC\n res[2] = this.mintWithBTC.selector;\n res[3] = this.burnToBTC.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogicWrbtcLM\"));\n }\n\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n nonReentrant\n globallyNonReentrant\n returns (uint256 mintAmount)\n {\n if (useLM) return _mintWithLM(receiver, msg.value);\n else return _mintToken(receiver, msg.value);\n }\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external nonReentrant globallyNonReentrant returns (uint256 loanAmountPaid) {\n loanAmountPaid = useLM ? _burnFromLM(burnAmount) : _burnToken(burnAmount);\n\n if (loanAmountPaid != 0) {\n IWrbtcERC20(wrbtcTokenAddress).withdraw(loanAmountPaid);\n Address.sendValue(receiver, loanAmountPaid);\n }\n }\n}\n" + }, + "contracts/connectors/loantoken/modules/shared/LoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../AdvancedToken.sol\";\nimport \"../../interfaces/ProtocolSettingsLike.sol\";\nimport \"../../LoanTokenLogicStorage.sol\";\n\ncontract LoanTokenSettingsLowerAdmin is LoanTokenLogicStorage {\n using SafeMath for uint256;\n\n /// @dev TODO: Check for restrictions in this contract.\n modifier onlyAdmin() {\n require(isOwner() || msg.sender == admin, \"unauthorized\");\n _;\n }\n\n /* Events */\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice This function is MANDATORY, which will be called by LoanTokenLogicBeacon and be registered.\n * Every new public function, the signature needs to be included in this function.\n *\n * @dev This function will return the list of function signature in this contract that are available for public call\n * Then this function will be called by LoanTokenLogicBeacon, and the function signatures will be registred in LoanTokenLogicBeacon.\n * @dev To save the gas we can just directly return the list of function signature from this pure function.\n * The other workaround (fancy way) is we can create a storage for the list of the function signature, and then we can store each function signature to that storage from the constructor.\n * Then, in this function we just need to return that storage variable.\n *\n * @return The list of function signatures (bytes4[])\n */\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](15);\n res[0] = this.setAdmin.selector;\n res[1] = this.setPauser.selector;\n res[2] = this.setupLoanParams.selector;\n res[3] = this.disableLoanParams.selector;\n res[4] = this.setDemandCurve.selector;\n res[5] = this.toggleFunctionPause.selector;\n res[6] = this.setTransactionLimits.selector;\n res[7] = this.changeLoanTokenNameAndSymbol.selector;\n res[8] = this.pauser.selector;\n res[9] = this.setLiquidityMiningAddress.selector;\n res[10] = this.withdrawRBTCTo.selector;\n res[11] = this.getLiquidityMiningAddress.selector;\n res[12] = this.checkPause.selector;\n res[13] = this.setStakingContractAddress.selector;\n res[14] = this.getStakingContractAddress.selector;\n return (res, stringToBytes32(\"LoanTokenSettingsLowerAdmin\"));\n }\n\n /**\n * @notice Set admin account.\n * @param _admin The address of the account to grant admin permissions.\n * */\n function setAdmin(address _admin) public onlyOwner {\n admin = _admin;\n }\n\n /**\n * @notice Set pauser account.\n * @param _pauser The address of the account to grant pause permissions.\n * */\n function setPauser(address _pauser) public onlyOwner {\n pauser = _pauser;\n }\n\n /**\n * @notice Fallback function not allowed\n * */\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n /**\n * @notice Set loan token parameters.\n *\n * @param loanParamsList The array of loan parameters.\n * @param areTorqueLoans Whether the loan is a torque loan.\n * */\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans /// isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n /**\n * @notice Disable loan token parameters.\n *\n * @param collateralTokens The array of collateral tokens.\n * @param isTorqueLoans Whether the loan is a torque loan.\n * */\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n /**\n * @notice Set loan token parameters about the demand curve.\n *\n * @dev These params should be percentages represented\n * like so: 5% = 5000000000000000000 /// 18 digits precision.\n * rateMultiplier + baseRate can't exceed 100%\n *\n * To maintain a healthy credit score, it's important to keep your\n * credit utilization rate (CUR) low (_lowUtilBaseRate). In general\n * you don't want your CUR to exceed 30%, but increasingly financial\n * experts are recommending that you don't want to go above 10% if you\n * really want an excellent credit score.\n *\n * Interest rates tend to cluster around the kink level of a kinked\n * interest rate model. More info at https://arxiv.org/pdf/2006.13922.pdf\n * and https://compound.finance/governance/proposals/12\n *\n * @param _baseRate The interest rate.\n * @param _rateMultiplier The precision multiplier for base rate.\n * @param _lowUtilBaseRate The credit utilization rate (CUR) low value.\n * @param _lowUtilRateMultiplier The precision multiplier for low util base rate.\n * @param _targetLevel The target level.\n * @param _kinkLevel The level that interest rates cluster on kinked model.\n * @param _maxScaleRate The maximum rate of the scale.\n * */\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; /// 80 ether\n kinkLevel = _kinkLevel; /// 90 ether\n maxScaleRate = _maxScaleRate; /// 100 ether\n }\n\n /**\n * @notice Set the pause flag for a function to true or false.\n *\n * @dev Combining the hash of \"iToken_FunctionPause\" string and a function\n * selector gets a slot to write a flag for pause state.\n *\n * @param funcId The ID of a function, the selector.\n * @param isPaused true/false value of the flag.\n * */\n function toggleFunctionPause(\n string memory funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyPauserOrOwner {\n bool paused;\n /// keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n paused := sload(slot)\n }\n require(paused != isPaused, \"isPaused is already set to that value\");\n assembly {\n sstore(slot, isPaused)\n }\n emit ToggledFunctionPaused(funcId, !isPaused, isPaused);\n }\n\n /**\n * Set the transaction limit per token address.\n * @param addresses The token addresses.\n * @param limits The limit denominated in the currency of the token address.\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyAdmin\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n\n /**\n *\t@notice Update the loan token parameters.\n *\t@param _name The new name of the loan token.\n *\t@param _symbol The new symbol of the loan token.\n * */\n function changeLoanTokenNameAndSymbol(string memory _name, string memory _symbol)\n public\n onlyAdmin\n {\n name = _name;\n symbol = _symbol;\n }\n\n /**\n * @notice Withdraws RBTC from the contract by Multisig.\n * @param _receiverAddress The address where the rBTC has to be transferred.\n * @param _amount The amount of rBTC to be transferred.\n */\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external onlyOwner {\n require(_receiverAddress != address(0), \"receiver address invalid\");\n require(_amount > 0, \"non-zero withdraw amount expected\");\n require(_amount <= address(this).balance, \"withdraw amount cannot exceed balance\");\n _receiverAddress.transfer(_amount);\n emit WithdrawRBTCTo(_receiverAddress, _amount);\n }\n\n /**\n * @notice sets the liquidity mining contract address\n * @param LMAddress the address of the liquidity mining contract\n */\n function setLiquidityMiningAddress(address LMAddress) external onlyOwner {\n liquidityMiningAddress = LMAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for liquidityMiningAddress\n\n\t * @return liquidityMiningAddress\n\t */\n function getLiquidityMiningAddress() public view returns (address) {\n return liquidityMiningAddress;\n }\n\n /**\n * @notice sets the staking contract address\n * @param _stakingContractAddress the address of the staking contract\n */\n function setStakingContractAddress(address _stakingContractAddress) external onlyOwner {\n stakingContractAddress = _stakingContractAddress;\n }\n\n /**\n\t * @notice We need separate getter for newly added storage variable\n\t * @notice Getter for stakingContractAddress\n\n\t * @return stakingContractAddress\n\t */\n function getStakingContractAddress() public view returns (address) {\n return stakingContractAddress;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param funcId The function ID, the selector.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function checkPause(string memory funcId) public view returns (bool isPaused) {\n bytes4 sig = bytes4(keccak256(abi.encodePacked(funcId)));\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n sig,\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n isPaused := sload(slot)\n }\n return isPaused;\n }\n}\n" + }, + "contracts/connectors/loantoken/Pausable.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Pausable contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * The contract implements pausable functionality by reading on slots the\n * pause state of contract functions.\n * */\ncontract Pausable {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 internal constant Pausable_FunctionPause =\n 0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047;\n\n modifier pausable(bytes4 sig) {\n require(!_isPaused(sig), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Check whether a function is paused.\n *\n * @dev Used to read externally from the smart contract to see if a\n * function is paused.\n *\n * @param sig The function ID, the selector on bytes4.\n *\n * @return isPaused Whether the function is paused: true or false.\n * */\n function _isPaused(bytes4 sig) internal view returns (bool isPaused) {\n bytes32 slot = keccak256(abi.encodePacked(sig, Pausable_FunctionPause));\n assembly {\n isPaused := sload(slot)\n }\n }\n}\n" + }, + "contracts/core/Objects.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./objects/LoanStruct.sol\";\nimport \"./objects/LoanParamsStruct.sol\";\nimport \"./objects/OrderStruct.sol\";\nimport \"./objects/LenderInterestStruct.sol\";\nimport \"./objects/LoanInterestStruct.sol\";\n\n/**\n * @title Objects contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract inherints and aggregates several structures needed to handle\n * loans on the protocol.\n * */\ncontract Objects is\n LoanStruct,\n LoanParamsStruct,\n OrderStruct,\n LenderInterestStruct,\n LoanInterestStruct\n{\n\n}\n" + }, + "contracts/core/objects/LenderInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Lender Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Lender Interest.\n * */\ncontract LenderInterestStruct {\n struct LenderInterest {\n uint256 principalTotal; /// Total borrowed amount outstanding of asset.\n uint256 owedPerDay; /// Interest owed per day for all loans of asset.\n uint256 owedTotal; /// Total interest owed for all loans of asset (assuming they go to full term).\n uint256 paidTotal; /// Total interest paid so far for asset.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanInterestStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Interest.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Interest.\n * */\ncontract LoanInterestStruct {\n struct LoanInterest {\n uint256 owedPerDay; /// Interest owed per day for loan.\n uint256 depositTotal; /// Total escrowed interest for loan.\n uint256 updatedTimestamp; /// Last update.\n }\n}\n" + }, + "contracts/core/objects/LoanParamsStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Parameters.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Parameters.\n * */\ncontract LoanParamsStruct {\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n}\n" + }, + "contracts/core/objects/LoanStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Object.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Object.\n * */\ncontract LoanStruct {\n struct Loan {\n bytes32 id; /// ID of the loan.\n bytes32 loanParamsId; /// The linked loan params ID.\n bytes32 pendingTradesId; /// The linked pending trades ID.\n bool active; /// If false, the loan has been fully closed.\n uint256 principal; /// Total borrowed amount outstanding.\n uint256 collateral; /// Total collateral escrowed for the loan.\n uint256 startTimestamp; /// Loan start time.\n uint256 endTimestamp; /// For active loans, this is the expected loan end time, for in-active loans, is the actual (past) end time.\n uint256 startMargin; /// Initial margin when the loan opened.\n uint256 startRate; /// Reference rate when the loan opened for converting collateralToken to loanToken.\n address borrower; /// Borrower of this loan.\n address lender; /// Lender of this loan.\n }\n}\n" + }, + "contracts/core/objects/OrderStruct.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Loan Order.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage structure of the Loan Order.\n * */\ncontract OrderStruct {\n struct Order {\n uint256 lockedAmount; /// Escrowed amount waiting for a counterparty.\n uint256 interestRate; /// Interest rate defined by the creator of this order.\n uint256 minLoanTerm; /// Minimum loan term allowed.\n uint256 maxLoanTerm; /// Maximum loan term allowed.\n uint256 createdTimestamp; /// Timestamp when this order was created.\n uint256 expirationTimestamp; /// Timestamp when this order expires.\n }\n}\n" + }, + "contracts/core/Protocol.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./State.sol\";\n\n/**\n * @title Sovryn Protocol contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the proxy functionality to deploy Protocol anchor\n * and logic apart, turning it upgradable.\n *\n * @dev TODO: can I change this proxy to EIP-1822 proxy standard, please.\n * https://eips.ethereum.org/EIPS/eip-1822\n * */\ncontract sovrynProtocol is State {\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = logicTargets[msg.sig];\n require(target != address(0), \"target not active\");\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n /**\n * @notice External owner target initializer.\n * @param target The target addresses.\n * */\n function replaceContract(address target) external onlyOwner {\n (bool success, ) =\n target.delegatecall(abi.encodeWithSignature(\"initialize(address)\", target));\n require(success, \"setup failed\");\n }\n\n /**\n * @notice External owner setter for target addresses.\n * @param sigsArr The array of signatures.\n * @param targetsArr The array of addresses.\n * */\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr)\n external\n onlyOwner\n {\n require(sigsArr.length == targetsArr.length, \"count mismatch\");\n\n for (uint256 i = 0; i < sigsArr.length; i++) {\n _setTarget(bytes4(keccak256(abi.encodePacked(sigsArr[i]))), targetsArr[i]);\n }\n }\n\n /**\n * @notice External getter for target addresses.\n * @param sig The signature.\n * @return The address for a given signature.\n * */\n function getTarget(string calldata sig) external view returns (address) {\n return logicTargets[bytes4(keccak256(abi.encodePacked(sig)))];\n }\n}\n" + }, + "contracts/core/State.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./Objects.sol\";\nimport \"../mixins/EnumerableAddressSet.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/ReentrancyGuard.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../reentrancy/SharedReentrancyGuard.sol\";\n\n/**\n * @title State contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the storage values of the Protocol.\n * */\ncontract State is Objects, ReentrancyGuard, SharedReentrancyGuard, Ownable {\n using SafeMath for uint256;\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet; // enumerable map of addresses\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set; // enumerable map of bytes32 or addresses\n\n /// Handles asset reference price lookups.\n address public priceFeeds;\n\n /// Handles asset swaps using dex liquidity.\n address public swapsImpl;\n\n /// Contract registry address of the Sovryn swap network.\n address public sovrynSwapContractRegistryAddress;\n\n /// Implementations of protocol functions.\n mapping(bytes4 => address) public logicTargets;\n\n /// Loans: loanId => Loan\n mapping(bytes32 => Loan) public loans;\n\n /// Loan parameters: loanParamsId => LoanParams\n mapping(bytes32 => LoanParams) public loanParams;\n\n /// lender => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public lenderOrders;\n\n /// borrower => orderParamsId => Order\n mapping(address => mapping(bytes32 => Order)) public borrowerOrders;\n\n /// loanId => delegated => approved\n mapping(bytes32 => mapping(address => bool)) public delegatedManagers;\n\n /**\n *** Interest ***\n **/\n\n /// lender => loanToken => LenderInterest object\n mapping(address => mapping(address => LenderInterest)) public lenderInterest;\n\n /// loanId => LoanInterest object\n mapping(bytes32 => LoanInterest) public loanInterest;\n\n /**\n *** Internals ***\n **/\n\n /// Implementations set.\n EnumerableBytes32Set.Bytes32Set internal logicTargetsSet;\n\n /// Active loans set.\n EnumerableBytes32Set.Bytes32Set internal activeLoansSet;\n\n /// Lender loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal lenderLoanSets;\n\n /// Borrow loans set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal borrowerLoanSets;\n\n /// User loan params set.\n mapping(address => EnumerableBytes32Set.Bytes32Set) internal userLoanParamSets;\n\n /// Address controlling fee withdrawals.\n address public feesController;\n\n /// 10% fee /// Fee taken from lender interest payments.\n uint256 public lendingFeePercent = 10**19;\n\n /// Total interest fees received and not withdrawn per asset.\n mapping(address => uint256) public lendingFeeTokensHeld;\n\n /// Total interest fees withdraw per asset.\n /// lifetime fees = lendingFeeTokensHeld + lendingFeeTokensPaid\n mapping(address => uint256) public lendingFeeTokensPaid;\n\n /// 0.15% fee /// Fee paid for each trade.\n uint256 public tradingFeePercent = 15 * 10**16;\n\n /// Total trading fees received and not withdrawn per asset.\n mapping(address => uint256) public tradingFeeTokensHeld;\n\n /// Total trading fees withdraw per asset\n /// lifetime fees = tradingFeeTokensHeld + tradingFeeTokensPaid\n mapping(address => uint256) public tradingFeeTokensPaid;\n\n /// 0.09% fee /// Origination fee paid for each loan.\n uint256 public borrowingFeePercent = 9 * 10**16;\n\n /// Total borrowing fees received and not withdrawn per asset.\n mapping(address => uint256) public borrowingFeeTokensHeld;\n\n /// Total borrowing fees withdraw per asset.\n /// lifetime fees = borrowingFeeTokensHeld + borrowingFeeTokensPaid\n mapping(address => uint256) public borrowingFeeTokensPaid;\n\n /// Current protocol token deposit balance.\n uint256 public protocolTokenHeld;\n\n /// Lifetime total payout of protocol token.\n uint256 public protocolTokenPaid;\n\n /// 5% fee share in form of SOV /// Fee share for affiliate program.\n uint256 public affiliateFeePercent = 5 * 10**18;\n\n /// 5% collateral discount /// Discount on collateral for liquidators.\n uint256 public liquidationIncentivePercent = 5 * 10**18;\n\n /// loanPool => underlying\n mapping(address => address) public loanPoolToUnderlying;\n\n /// underlying => loanPool\n mapping(address => address) public underlyingToLoanPool;\n\n /// Loan pools set.\n EnumerableBytes32Set.Bytes32Set internal loanPoolsSet;\n\n /// Supported tokens for swaps.\n mapping(address => bool) public supportedTokens;\n\n /// % disagreement between swap rate and reference rate.\n uint256 public maxDisagreement = 5 * 10**18;\n\n /// Used as buffer for swap source amount estimations.\n uint256 public sourceBuffer = 10000;\n\n /// Maximum support swap size in rBTC\n uint256 public maxSwapSize = 50 ether;\n\n /// Nonce per borrower. Used for loan id creation.\n mapping(address => uint256) public borrowerNonce;\n\n /// Rollover transaction costs around 0.0000168 rBTC, it is denominated in wrBTC.\n uint256 public rolloverBaseReward = 16800000000000;\n uint256 public rolloverFlexFeePercent = 0.1 ether; /// 0.1%\n\n IWrbtcERC20 public wrbtcToken;\n address public protocolTokenAddress;\n\n /// 50% fee rebate\n /// potocolToken reward to user, it is worth % of trading/borrowing fee.\n uint256 public feeRebatePercent = 50 * 10**18;\n\n address public admin;\n\n /// For modules interaction.\n address public protocolAddress;\n\n /**\n *** Affiliates ***\n **/\n\n /// The flag is set on the user's first trade.\n mapping(address => bool) public userNotFirstTradeFlag;\n\n /// User => referrer (affiliate).\n mapping(address => address) public affiliatesUserReferrer;\n\n /// List of referral addresses affiliated to the referrer.\n mapping(address => EnumerableAddressSet.AddressSet) internal referralsList;\n\n /// @dev Referral threshold for paying out to the referrer.\n /// The referrer reward is being accumulated and locked until the threshold is passed.\n uint256 public minReferralsToPayout = 3;\n\n /// @dev Total affiliate SOV rewards that held in the protocol\n /// (Because the minimum referrals is less than the rule)\n mapping(address => uint256) public affiliateRewardsHeld;\n\n /// @dev For affiliates SOV Bonus proccess.\n address public sovTokenAddress;\n address public lockedSOVAddress;\n\n /// @dev 20% fee share of trading token fee.\n /// Fee share of trading token fee for affiliate program.\n uint256 public affiliateTradingTokenFeePercent = 20 * 10**18;\n\n /// @dev Addresses of tokens in which commissions were paid to referrers.\n mapping(address => EnumerableAddressSet.AddressSet) internal affiliatesReferrerTokensList;\n\n /// @dev [referrerAddress][tokenAddress] is a referrer's token balance of accrued fees.\n mapping(address => mapping(address => uint256)) public affiliatesReferrerBalances;\n\n mapping(address => mapping(address => uint256)) public specialRebates; // Special rate rebates for spesific pair -- if not set, then use the default one\n bool public pause; //Flag to pause all protocol modules\n\n uint256 internal swapExtrernalFeePercent; /// Fee percentage for protocol swap\n\n /// @dev Defines the portion of the trading rebate rewards (SOV) which is to be paid out in a liquid form in basis points. The rest is vested. The max value is 9999 (means 99.99% liquid, 0.01% vested)\n uint256 internal tradingRebateRewardsBasisPoint;\n\n /// @dev Defines the defaultPath of conversion swap. This is created to prevent the non-rbtc pairs returning the shortest path which will not give the best rate.\n /// Will be used in internal swap.\n mapping(address => mapping(address => IERC20[])) internal defaultPathConversion;\n\n address internal pauser;\n\n /**\n * @notice Add signature and target to storage.\n * @dev Protocol is a proxy and requires a way to add every\n * module function dynamically during deployment.\n * */\n function _setTarget(bytes4 sig, address target) internal {\n logicTargets[sig] = target;\n\n if (target != address(0)) {\n logicTargetsSet.addBytes32(bytes32(sig));\n } else {\n logicTargetsSet.removeBytes32(bytes32(sig));\n }\n }\n\n modifier onlyAdminOrOwner() {\n require(isOwner() || admin == (msg.sender), \"unauthorized\");\n _;\n }\n\n modifier onlyPauserOrOwner() {\n require(isOwner() || pauser == (msg.sender), \"unauthorized\");\n _;\n }\n}\n" + }, + "contracts/escrow/Escrow.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Ethereum Pool to accept SOV Token.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice You can use this contract for deposit of SOV tokens for some time and withdraw later.\n */\ncontract Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalDeposit;\n /// @notice The release timestamp for the tokens deposited.\n uint256 public releaseTime;\n /// @notice The amount of token we would be accepting as deposit at max.\n uint256 public depositLimit;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The multisig contract which handles the fund.\n address public multisig;\n\n /// @notice The user balances.\n mapping(address => uint256) userBalances;\n\n /// @notice The current contract status.\n /// @notice Deployed - Deployed the contract.\n /// @notice Deposit - Time to deposit in the contract by the users.\n /// @notice Holding - Deposit is closed and now the holding period starts.\n /// @notice Withdraw - Time to withdraw in the contract by the users.\n /// @notice Expired - The contract is now closed completely.\n enum Status { Deployed, Deposit, Holding, Withdraw, Expired }\n Status public status;\n\n /* Events */\n\n /// @notice Emitted when the contract deposit starts.\n event EscrowActivated();\n\n /// @notice Emitted when the contract is put in holding state. No new token deposit accepted by User.\n event EscrowInHoldingState();\n\n /// @notice Emitted when the contract is put in withdraw state. Users can now withdraw tokens.\n event EscrowInWithdrawState();\n\n /// @notice Emitted when the contract is expired after withdraws are made/total token transfer.\n event EscrowFundExpired();\n\n /// @notice Emitted when a new multisig is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newMultisig The address which is added as the new multisig.\n /// @dev Can only be initiated by the current multisig.\n event NewMultisig(address indexed _initiator, address indexed _newMultisig);\n\n /// @notice Emitted when the release timestamp is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseTimestamp The updated release timestamp for the withdraw.\n event TokenReleaseUpdated(address indexed _initiator, uint256 _releaseTimestamp);\n\n /// @notice Emitted when the deposit limit is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _depositLimit The updated deposit limit.\n event TokenDepositLimitUpdated(address indexed _initiator, uint256 _depositLimit);\n\n /// @notice Emitted when a new token deposit is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when we reach the token deposit limit.\n event DepositLimitReached();\n\n /// @notice Emitted when a token withdraw is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdrawByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event TokenDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event TokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyMultisig() {\n require(msg.sender == multisig, \"Only Multisig can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n modifier checkRelease() {\n require(\n releaseTime != 0 && releaseTime <= block.timestamp,\n \"The release time has not started yet.\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_multisig != address(0), \"Invalid Multisig Address.\");\n\n SOV = IERC20(_SOV);\n multisig = _multisig;\n\n emit NewMultisig(msg.sender, _multisig);\n\n releaseTime = _releaseTime;\n depositLimit = _depositLimit;\n\n status = Status.Deployed;\n }\n\n /**\n * @notice This function is called once after deployment for starting the deposit action.\n * @dev Without calling this function, the contract will not start accepting tokens.\n */\n function init() external onlyMultisig checkStatus(Status.Deployed) {\n status = Status.Deposit;\n\n emit EscrowActivated();\n }\n\n /**\n * @notice Update Multisig.\n * @param _newMultisig The new owner of the tokens & contract.\n */\n function updateMultisig(address _newMultisig) external onlyMultisig {\n require(_newMultisig != address(0), \"New Multisig address invalid.\");\n\n multisig = _newMultisig;\n\n emit NewMultisig(msg.sender, _newMultisig);\n }\n\n /**\n * @notice Update Release Timestamp.\n * @param _newReleaseTime The new release timestamp for token release.\n * @dev Zero is also a valid timestamp, if the release time is not scheduled yet.\n */\n function updateReleaseTimestamp(uint256 _newReleaseTime) external onlyMultisig {\n releaseTime = _newReleaseTime;\n\n emit TokenReleaseUpdated(msg.sender, _newReleaseTime);\n }\n\n /**\n * @notice Update Deposit Limit.\n * @param _newDepositLimit The new deposit limit.\n * @dev IMPORTANT: Should not decrease than already deposited.\n */\n function updateDepositLimit(uint256 _newDepositLimit) external onlyMultisig {\n require(\n _newDepositLimit >= totalDeposit,\n \"Deposit already higher than the limit trying to be set.\"\n );\n depositLimit = _newDepositLimit;\n\n emit TokenDepositLimitUpdated(msg.sender, _newDepositLimit);\n }\n\n /**\n * @notice Deposit tokens to this contract by User.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the user inorder for this function to work.\n * These tokens can be withdrawn/transferred during Holding State by the Multisig.\n */\n function depositTokens(uint256 _amount) external checkStatus(Status.Deposit) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n uint256 amount = _amount;\n\n if (totalDeposit.add(_amount) >= depositLimit) {\n amount = depositLimit.sub(totalDeposit);\n emit DepositLimitReached();\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n userBalances[msg.sender] = userBalances[msg.sender].add(amount);\n totalDeposit = totalDeposit.add(amount);\n\n emit TokenDeposit(msg.sender, amount);\n }\n\n /**\n * @notice Update contract state to Holding.\n * @dev Once called, the contract no longer accepts any more deposits.\n * The multisig can now withdraw tokens from the contract after the contract is in Holding State.\n */\n function changeStateToHolding() external onlyMultisig checkStatus(Status.Deposit) {\n status = Status.Holding;\n\n emit EscrowInHoldingState();\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred. Zero address if the withdraw is to be done in Multisig.\n * @dev Can only be called after the token state is changed to Holding.\n */\n function withdrawTokensByMultisig(address _receiverAddress)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n address receiverAddress = msg.sender;\n if (_receiverAddress != address(0)) {\n receiverAddress = _receiverAddress;\n }\n\n uint256 value = SOV.balanceOf(address(this));\n /// Sending the amount to multisig.\n bool txStatus = SOV.transfer(receiverAddress, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdrawByMultisig(msg.sender, value);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n * Once the token deposit is higher than the total deposits done, the contract state is changed to Withdraw.\n */\n function depositTokensByMultisig(uint256 _amount)\n external\n onlyMultisig\n checkStatus(Status.Holding)\n {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDepositByMultisig(msg.sender, _amount);\n\n if (SOV.balanceOf(address(this)) >= totalDeposit) {\n status = Status.Withdraw;\n emit EscrowInWithdrawState();\n }\n }\n\n /**\n * @notice Withdraws token from the contract by User.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokens() public checkRelease checkStatus(Status.Withdraw) {\n uint256 amount = userBalances[msg.sender];\n userBalances[msg.sender] = 0;\n bool txStatus = SOV.transfer(msg.sender, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit TokenWithdraw(msg.sender, amount);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token balance of a particular user.\n * @return _addr The user address whose balance has to be checked.\n */\n function getUserBalance(address _addr) external view returns (uint256 balance) {\n return userBalances[_addr];\n }\n}\n" + }, + "contracts/escrow/EscrowReward.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Escrow.sol\";\nimport \"../locked/ILockedSOV.sol\";\n\n/**\n * @title A reward distribution contract for Sovryn Ethereum Pool Escrow Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice Multisig can use this contract for depositing of Reward tokens based on the total token deposit.\n */\ncontract EscrowReward is Escrow {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The total reward tokens deposited.\n /// @dev Used for calculating the reward % share of users related to total deposit.\n uint256 public totalRewardDeposit;\n\n /// @notice The Locked SOV contract.\n ILockedSOV public lockedSOV;\n\n /* Events */\n\n /// @notice Emitted when the Locked SOV Contract address is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _lockedSOV The address of the Locked SOV Contract.\n event LockedSOVUpdated(address indexed _initiator, address indexed _lockedSOV);\n\n /// @notice Emitted when a new reward token deposit is done by Multisig.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token deposited.\n event RewardDepositByMultisig(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a Reward token withdraw is done by User.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of token withdrawed.\n event RewardTokenWithdraw(address indexed _initiator, uint256 _amount);\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _lockedSOV The Locked SOV Contract address.\n * @param _SOV The SOV token address.\n * @param _multisig The owner of the tokens & contract.\n * @param _releaseTime The token release time, zero if undecided.\n * @param _depositLimit The amount of tokens we will be accepting.\n */\n constructor(\n address _lockedSOV,\n address _SOV,\n address _multisig,\n uint256 _releaseTime,\n uint256 _depositLimit\n ) public Escrow(_SOV, _multisig, _releaseTime, _depositLimit) {\n if (_lockedSOV != address(0)) {\n lockedSOV = ILockedSOV(_lockedSOV);\n }\n }\n\n /**\n * @notice Set the Locked SOV Contract Address if not already done.\n * @param _lockedSOV The Locked SOV Contract address.\n */\n function updateLockedSOV(address _lockedSOV) external onlyMultisig {\n require(_lockedSOV != address(0), \"Invalid Reward Token Address.\");\n\n lockedSOV = ILockedSOV(_lockedSOV);\n\n emit LockedSOVUpdated(msg.sender, _lockedSOV);\n }\n\n /**\n * @notice Deposit tokens to this contract by the Multisig.\n * @param _amount the amount of tokens deposited.\n * @dev The contract has to be approved by the multisig inorder for this function to work.\n */\n function depositRewardByMultisig(uint256 _amount) external onlyMultisig {\n require(\n status != Status.Withdraw,\n \"Reward Token deposit is only allowed before User Withdraw starts.\"\n );\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n totalRewardDeposit = totalRewardDeposit.add(_amount);\n txStatus = SOV.approve(address(lockedSOV), totalRewardDeposit);\n require(txStatus, \"Token Approval was not successful.\");\n\n emit RewardDepositByMultisig(msg.sender, _amount);\n }\n\n /**\n * @notice Withdraws token and reward from the contract by User. Reward is gone to lockedSOV contract for future vesting.\n * @dev Only works after the contract state is in Withdraw.\n */\n function withdrawTokensAndReward() external checkRelease checkStatus(Status.Withdraw) {\n // Reward calculation have to be done initially as the User Balance is zeroed out .\n uint256 reward = userBalances[msg.sender].mul(totalRewardDeposit).div(totalDeposit);\n withdrawTokens();\n\n lockedSOV.depositSOV(msg.sender, reward);\n\n emit RewardTokenWithdraw(msg.sender, reward);\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the reward a particular user can get.\n * @param _addr The address of the user whose reward is to be read.\n * @return reward The reward received by the user.\n */\n function getReward(address _addr) external view returns (uint256 reward) {\n if (userBalances[_addr].mul(totalRewardDeposit) == 0) {\n return 0;\n }\n return userBalances[_addr].mul(totalRewardDeposit).div(totalDeposit);\n }\n}\n" + }, + "contracts/events/AffiliatesEvents.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\ncontract AffiliatesEvents is ModulesCommonEvents {\n event SetAffiliatesReferrer(address indexed user, address indexed referrer);\n\n event SetAffiliatesReferrerFail(\n address indexed user,\n address indexed referrer,\n bool alreadySet,\n bool userNotFirstTrade\n );\n\n event SetUserNotFirstTradeFlag(address indexed user);\n\n event PayTradingFeeToAffiliate(\n address indexed referrer,\n address trader,\n address indexed token,\n bool indexed isHeld,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountPaid\n );\n\n event PayTradingFeeToAffiliateFail(\n address indexed referrer,\n address trader,\n address indexed token,\n uint256 tradingFeeTokenAmount,\n uint256 tokenBonusAmount,\n uint256 sovBonusAmount,\n uint256 sovBonusAmountTryingToPaid\n );\n\n event WithdrawAffiliatesReferrerTokenFees(\n address indexed referrer,\n address indexed receiver,\n address indexed tokenAddress,\n uint256 amount\n );\n}\n" + }, + "contracts/events/FeesEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title The Fees Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for fee payments.\n * */\ncontract FeesEvents {\n event PayLendingFee(address indexed payer, address indexed token, uint256 amount);\n\n event PayTradingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event PayBorrowingFee(\n address indexed payer,\n address indexed token,\n bytes32 indexed loanId,\n uint256 amount\n );\n\n event EarnReward(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n\n event EarnRewardFail(\n address indexed receiver,\n address indexed token,\n bytes32 indexed loanId,\n uint256 feeRebatePercent,\n uint256 amount,\n uint256 basisPoint\n );\n}\n" + }, + "contracts/events/LoanClosingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Closing Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan closing operations.\n * */\ncontract LoanClosingsEvents is ModulesCommonEvents {\n /// topic0: 0x6349c1a02ec126f7f4fc6e6837e1859006e90e9901635c442d29271e77b96fb6\n event CloseWithDeposit(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address closer,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0x2ed7b29b4ca95cf3bb9a44f703872a66e6aa5e8f07b675fa9a5c124a1e5d7352\n event CloseWithSwap(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n address closer,\n uint256 positionCloseSize,\n uint256 loanCloseAmount,\n uint256 exitPrice, // one unit of collateralToken, denominated in loanToken\n uint256 currentLeverage\n );\n\n /// topic0: 0x46fa03303782eb2f686515f6c0100f9a62dabe587b0d3f5a4fc0c822d6e532d3\n event Liquidate(\n address indexed user,\n address indexed liquidator,\n bytes32 indexed loanId,\n address lender,\n address loanToken,\n address collateralToken,\n uint256 repayAmount,\n uint256 collateralWithdrawAmount,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n event Rollover(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n uint256 principal,\n uint256 collateral,\n uint256 endTimestamp,\n address rewardReceiver,\n uint256 reward\n );\n\n event swapExcess(bool shouldRefund, uint256 amount, uint256 amountInRbtc, uint256 threshold);\n}\n" + }, + "contracts/events/LoanMaintenanceEvents.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Maintenance Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan maintenance operations.\n * */\ncontract LoanMaintenanceEvents is ModulesCommonEvents {\n event DepositCollateral(bytes32 indexed loanId, uint256 depositAmount, uint256 rate);\n}\n" + }, + "contracts/events/LoanOpeningsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Openings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan openings operations.\n * */\ncontract LoanOpeningsEvents is ModulesCommonEvents {\n /// topic0: 0x7bd8cbb7ba34b33004f3deda0fd36c92fc0360acbd97843360037b467a538f90\n event Borrow(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 newCollateral,\n uint256 interestRate,\n uint256 interestDuration,\n uint256 collateralToLoanRate,\n uint256 currentMargin\n );\n\n /// topic0: 0xf640c1cfe1a912a0b0152b5a542e5c2403142eed75b06cde526cee54b1580e5c\n event Trade(\n address indexed user,\n address indexed lender,\n bytes32 indexed loanId,\n address collateralToken,\n address loanToken,\n uint256 positionSize,\n uint256 borrowedAmount,\n uint256 interestRate,\n uint256 settlementDate,\n uint256 entryPrice, /// one unit of collateralToken, denominated in loanToken\n uint256 entryLeverage,\n uint256 currentLeverage\n );\n\n /// topic0: 0x0eef4f90457a741c97d76fcf13fa231fefdcc7649bdb3cb49157c37111c98433\n event DelegatedManagerSet(\n bytes32 indexed loanId,\n address indexed delegator,\n address indexed delegated,\n bool isActive\n );\n}\n" + }, + "contracts/events/LoanSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Loan Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for loan settings operations.\n * */\ncontract LoanSettingsEvents is ModulesCommonEvents {\n event LoanParamsSetup(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdSetup(bytes32 indexed id, address indexed owner);\n\n event LoanParamsDisabled(\n bytes32 indexed id,\n address owner,\n address indexed loanToken,\n address indexed collateralToken,\n uint256 minInitialMargin,\n uint256 maintenanceMargin,\n uint256 maxLoanTerm\n );\n event LoanParamsIdDisabled(bytes32 indexed id, address indexed owner);\n}\n" + }, + "contracts/events/ModulesCommonEvents.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title The common events for all modules\n * @notice This contract contains the events which will be used by all modules\n **/\n\ncontract ModulesCommonEvents {\n event ProtocolModuleContractReplaced(\n address indexed prevModuleContractAddress,\n address indexed newModuleContractAddress,\n bytes32 indexed module\n );\n}\n" + }, + "contracts/events/ProtocolSettingsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title The Protocol Settings Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for protocol settings operations.\n * */\ncontract ProtocolSettingsEvents is ModulesCommonEvents {\n event SetPriceFeedContract(address indexed sender, address oldValue, address newValue);\n\n event SetSwapsImplContract(address indexed sender, address oldValue, address newValue);\n\n event SetLoanPool(\n address indexed sender,\n address indexed loanPool,\n address indexed underlying\n );\n\n event SetSupportedTokens(address indexed sender, address indexed token, bool isActive);\n\n event SetLendingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetTradingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetBorrowingFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetSwapExternalFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateFeePercent(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetAffiliateTradingTokenFeePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetLiquidationIncentivePercent(\n address indexed sender,\n uint256 oldValue,\n uint256 newValue\n );\n\n event SetMaxSwapSize(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetFeesController(\n address indexed sender,\n address indexed oldController,\n address indexed newController\n );\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWethToken,\n address indexed newWethToken\n );\n\n event SetSovrynSwapContractRegistryAddress(\n address indexed sender,\n address indexed oldSovrynSwapContractRegistryAddress,\n address indexed newSovrynSwapContractRegistryAddress\n );\n\n event SetProtocolTokenAddress(\n address indexed sender,\n address indexed oldProtocolToken,\n address indexed newProtocolToken\n );\n\n event WithdrawFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 lendingAmount,\n uint256 tradingAmount,\n uint256 borrowingAmount,\n uint256 wRBTCConverted\n );\n\n event WithdrawLendingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawTradingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event WithdrawBorrowingFees(\n address indexed sender,\n address indexed token,\n address indexed receiver,\n uint256 amount\n );\n\n event SetRolloverBaseReward(address indexed sender, uint256 oldValue, uint256 newValue);\n\n event SetRebatePercent(\n address indexed sender,\n uint256 oldRebatePercent,\n uint256 newRebatePercent\n );\n\n event SetSpecialRebates(\n address indexed sender,\n address indexed sourceToken,\n address indexed destToken,\n uint256 oldSpecialRebatesPercent,\n uint256 newSpecialRebatesPercent\n );\n\n event SetProtocolAddress(\n address indexed sender,\n address indexed oldProtocol,\n address indexed newProtocol\n );\n\n event SetMinReferralsToPayoutAffiliates(\n address indexed sender,\n uint256 oldMinReferrals,\n uint256 newMinReferrals\n );\n\n event SetSOVTokenAddress(\n address indexed sender,\n address indexed oldTokenAddress,\n address indexed newTokenAddress\n );\n\n event SetLockedSOVAddress(\n address indexed sender,\n address indexed oldAddress,\n address indexed newAddress\n );\n\n event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);\n\n event SetTradingRebateRewardsBasisPoint(\n address indexed sender,\n uint256 oldBasisPoint,\n uint256 newBasisPoint\n );\n\n event SetRolloverFlexFeePercent(\n address indexed sender,\n uint256 oldRolloverFlexFeePercent,\n uint256 newRolloverFlexFeePercent\n );\n\n event SetDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event RemoveDefaultPathConversion(\n address indexed sender,\n address indexed sourceTokenAddress,\n address indexed destTokenAddress,\n IERC20[] defaultPath\n );\n\n event SetAdmin(address indexed sender, address indexed oldAdmin, address indexed newAdmin);\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n}\n" + }, + "contracts/events/SwapsEvents.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"./ModulesCommonEvents.sol\";\n\n/**\n * @title The Swaps Events contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the events for swap operations.\n * */\ncontract SwapsEvents is ModulesCommonEvents {\n event LoanSwap(\n bytes32 indexed loanId,\n address indexed sourceToken,\n address indexed destToken,\n address borrower,\n uint256 sourceAmount,\n uint256 destAmount\n );\n\n event ExternalSwap(\n address indexed user,\n address indexed sourceToken,\n address indexed destToken,\n uint256 sourceAmount,\n uint256 destAmount\n );\n}\n" + }, + "contracts/farm/ILiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\n\ninterface ILiquidityMining {\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external;\n\n function onTokensDeposited(address _user, uint256 _amount) external;\n\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256);\n}\n" + }, + "contracts/farm/LiquidityMining.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./LiquidityMiningStorage.sol\";\nimport \"./ILiquidityMining.sol\";\n\ncontract LiquidityMining is ILiquidityMining, LiquidityMiningStorage {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n /* Constants */\n\n uint256 public constant PRECISION = 1e12;\n // Bonus multiplier for early liquidity providers.\n // During bonus period each passed block will be calculated like N passed blocks, where N = BONUS_MULTIPLIER\n uint256 public constant BONUS_BLOCK_MULTIPLIER = 10;\n\n uint256 public constant SECONDS_PER_BLOCK = 30;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event PoolTokenAdded(address indexed user, address indexed poolToken, uint256 allocationPoint);\n event PoolTokenUpdated(\n address indexed user,\n address indexed poolToken,\n uint256 newAllocationPoint,\n uint256 oldAllocationPoint\n );\n event Deposit(address indexed user, address indexed poolToken, uint256 amount);\n event RewardClaimed(address indexed user, address indexed poolToken, uint256 amount);\n event Withdraw(address indexed user, address indexed poolToken, uint256 amount);\n event EmergencyWithdraw(\n address indexed user,\n address indexed poolToken,\n uint256 amount,\n uint256 accumulatedReward\n );\n\n /* Functions */\n\n /**\n * @notice Initialize mining.\n *\n * @param _SOV The SOV token.\n * @param _rewardTokensPerBlock The number of reward tokens per block.\n * @param _startDelayBlocks The number of blocks should be passed to start\n * mining.\n * @param _numberOfBonusBlocks The number of blocks when each block will\n * be calculated as N blocks (BONUS_BLOCK_MULTIPLIER).\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n * SOV rewards are not paid directly to liquidity providers. Instead they\n * are deposited into a lockedSOV vault contract.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n */\n function initialize(\n IERC20 _SOV,\n uint256 _rewardTokensPerBlock,\n uint256 _startDelayBlocks,\n uint256 _numberOfBonusBlocks,\n address _wrapper,\n ILockedSOV _lockedSOV,\n uint256 _unlockedImmediatelyPercent\n ) external onlyAuthorized {\n /// @dev Non-idempotent function. Must be called just once.\n require(address(SOV) == address(0), \"Already initialized\");\n require(address(_SOV) != address(0), \"Invalid token address\");\n require(_startDelayBlocks > 0, \"Invalid start block\");\n require(\n _unlockedImmediatelyPercent < 10000,\n \"Unlocked immediately percent has to be less than 10000.\"\n );\n\n SOV = _SOV;\n rewardTokensPerBlock = _rewardTokensPerBlock;\n startBlock = block.number + _startDelayBlocks;\n bonusEndBlock = startBlock + _numberOfBonusBlocks;\n wrapper = _wrapper;\n lockedSOV = _lockedSOV;\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets lockedSOV contract.\n * @param _lockedSOV The contract instance address of the lockedSOV vault.\n */\n function setLockedSOV(ILockedSOV _lockedSOV) external onlyAuthorized {\n require(address(_lockedSOV) != address(0), \"Invalid lockedSOV Address.\");\n lockedSOV = _lockedSOV;\n }\n\n /**\n * @notice Sets unlocked immediately percent.\n * @param _unlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setUnlockedImmediatelyPercent(uint256 _unlockedImmediatelyPercent)\n external\n onlyAuthorized\n {\n require(\n _unlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n unlockedImmediatelyPercent = _unlockedImmediatelyPercent;\n }\n\n /**\n * @notice Sets unlocked immediately percent overwrite for specific pool token.\n * @param _poolToken the address of pool token\n * @param _poolTokenUnlockedImmediatelyPercent The % which determines how much will be unlocked immediately.\n * @dev 10000 is 100%\n */\n function setPoolTokenUnlockedImmediatelyPercent(\n address _poolToken,\n uint256 _poolTokenUnlockedImmediatelyPercent\n ) external onlyAuthorized {\n require(\n _poolTokenUnlockedImmediatelyPercent <= 10000,\n \"Unlocked immediately percent has to be less than equal to 10000.\"\n );\n poolTokensUnlockedImmediatelyPercent[_poolToken] = _poolTokenUnlockedImmediatelyPercent;\n }\n\n /**\n * @notice sets wrapper proxy contract\n * @dev can be set to zero address to remove wrapper\n */\n function setWrapper(address _wrapper) external onlyAuthorized {\n wrapper = _wrapper;\n }\n\n /**\n * @notice stops mining by setting end block\n */\n function stopMining() external onlyAuthorized {\n require(endBlock == 0, \"Already stopped\");\n\n endBlock = block.number;\n }\n\n /**\n * @notice Transfers SOV tokens to given address.\n * Owner use this function to withdraw SOV from LM contract\n * into another account.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) external onlyAuthorized {\n require(_receiver != address(0), \"Receiver address invalid\");\n require(_amount != 0, \"Amount invalid\");\n\n /// @dev Do not transfer more SOV than available.\n uint256 SOVBal = SOV.balanceOf(address(this));\n if (_amount > SOVBal) {\n _amount = SOVBal;\n }\n\n /// @dev The actual transfer.\n require(SOV.transfer(_receiver, _amount), \"Transfer failed\");\n\n /// @dev Event log.\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Get the missed SOV balance of LM contract.\n *\n * @return The amount of SOV tokens according to totalUsersBalance\n * in excess of actual SOV balance of the LM contract.\n * */\n function getMissedBalance() external view returns (uint256) {\n uint256 balance = SOV.balanceOf(address(this));\n return balance >= totalUsersBalance ? 0 : totalUsersBalance.sub(balance);\n }\n\n /**\n * @notice adds a new lp to the pool. Can only be called by the owner or an admin\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _withUpdate the flag whether we need to update all pools\n */\n function add(\n address _poolToken,\n uint96 _allocationPoint,\n bool _withUpdate\n ) external onlyAuthorized {\n require(_allocationPoint > 0, \"Invalid allocation point\");\n require(_poolToken != address(0), \"Invalid token address\");\n require(poolIdList[_poolToken] == 0, \"Token already added\");\n\n if (_withUpdate) {\n updateAllPools();\n }\n\n uint256 lastRewardBlock = block.number > startBlock ? block.number : startBlock;\n totalAllocationPoint = totalAllocationPoint.add(_allocationPoint);\n\n poolInfoList.push(\n PoolInfo({\n poolToken: IERC20(_poolToken),\n allocationPoint: _allocationPoint,\n lastRewardBlock: lastRewardBlock,\n accumulatedRewardPerShare: 0\n })\n );\n //indexing starts from 1 in order to check whether token was already added\n poolIdList[_poolToken] = poolInfoList.length;\n\n emit PoolTokenAdded(msg.sender, _poolToken, _allocationPoint);\n }\n\n /**\n * @notice updates the given pool's reward tokens allocation point\n * @param _poolToken the address of pool token\n * @param _allocationPoint the allocation point (weight) for the given pool\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function update(\n address _poolToken,\n uint96 _allocationPoint,\n bool _updateAllFlag\n ) external onlyAuthorized {\n if (_updateAllFlag) {\n updateAllPools();\n } else {\n updatePool(_poolToken);\n }\n _updateToken(_poolToken, _allocationPoint);\n }\n\n function _updateToken(address _poolToken, uint96 _allocationPoint) internal {\n uint256 poolId = _getPoolId(_poolToken);\n\n uint256 previousAllocationPoint = poolInfoList[poolId].allocationPoint;\n totalAllocationPoint = totalAllocationPoint.sub(previousAllocationPoint).add(\n _allocationPoint\n );\n poolInfoList[poolId].allocationPoint = _allocationPoint;\n\n emit PoolTokenUpdated(msg.sender, _poolToken, _allocationPoint, previousAllocationPoint);\n }\n\n /**\n * @notice updates the given pools' reward tokens allocation points\n * @param _poolTokens array of addresses of pool tokens\n * @param _allocationPoints array of allocation points (weight) for the given pools\n * @param _updateAllFlag the flag whether we need to update all pools\n */\n function updateTokens(\n address[] calldata _poolTokens,\n uint96[] calldata _allocationPoints,\n bool _updateAllFlag\n ) external onlyAuthorized {\n require(_poolTokens.length == _allocationPoints.length, \"Arrays mismatch\");\n\n if (_updateAllFlag) {\n updateAllPools();\n }\n uint256 length = _poolTokens.length;\n for (uint256 i = 0; i < length; i++) {\n if (!_updateAllFlag) {\n updatePool(_poolTokens[i]);\n }\n _updateToken(_poolTokens[i], _allocationPoints[i]);\n }\n }\n\n /**\n * @notice returns reward multiplier over the given _from to _to block\n * @param _from the first block for a calculation\n * @param _to the last block for a calculation\n */\n function _getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n internal\n view\n returns (uint256)\n {\n if (_from < startBlock) {\n _from = startBlock;\n }\n if (endBlock > 0 && _to > endBlock) {\n _to = endBlock;\n }\n if (_to <= bonusEndBlock) {\n return _to.sub(_from).mul(BONUS_BLOCK_MULTIPLIER);\n } else if (_from >= bonusEndBlock) {\n return _to.sub(_from);\n } else {\n return\n bonusEndBlock.sub(_from).mul(BONUS_BLOCK_MULTIPLIER).add(_to.sub(bonusEndBlock));\n }\n }\n\n function _getUserAccumulatedReward(uint256 _poolId, address _user)\n internal\n view\n returns (uint256)\n {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_user];\n\n uint256 accumulatedRewardPerShare = pool.accumulatedRewardPerShare;\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (block.number > pool.lastRewardBlock && poolTokenBalance != 0) {\n (, uint256 accumulatedRewardPerShare_) = _getPoolAccumulatedReward(pool);\n accumulatedRewardPerShare = accumulatedRewardPerShare.add(accumulatedRewardPerShare_);\n }\n\n return\n user.accumulatedReward.add(\n user.amount.mul(accumulatedRewardPerShare).div(PRECISION).sub(user.rewardDebt)\n );\n }\n\n /**\n * @notice returns accumulated reward\n * @param _poolToken the address of pool token\n * @param _user the user address\n */\n function getUserAccumulatedReward(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n uint256 poolId = _getPoolId(_poolToken);\n return _getUserAccumulatedReward(poolId, _user);\n }\n\n /**\n * @notice returns estimated reward\n * @param _poolToken the address of pool token\n * @param _amount the amount of tokens to be deposited\n * @param _duration the duration of liquidity providing in seconds\n */\n function getEstimatedReward(\n address _poolToken,\n uint256 _amount,\n uint256 _duration\n ) external view returns (uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n uint256 start = block.number;\n uint256 end = start.add(_duration.div(SECONDS_PER_BLOCK));\n (, uint256 accumulatedRewardPerShare) =\n _getPoolAccumulatedReward(pool, _amount, start, end);\n return _amount.mul(accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Updates reward variables for all pools.\n * @dev Be careful of gas spending!\n */\n function updateAllPools() public {\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n _updatePool(i);\n }\n }\n\n /**\n * @notice Updates reward variables of the given pool to be up-to-date\n * @param _poolToken the address of pool token\n */\n function updatePool(address _poolToken) public {\n uint256 poolId = _getPoolId(_poolToken);\n _updatePool(poolId);\n }\n\n function _updatePool(uint256 _poolId) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n\n //this pool has been updated recently\n if (block.number <= pool.lastRewardBlock) {\n return;\n }\n\n uint256 poolTokenBalance = pool.poolToken.balanceOf(address(this));\n if (poolTokenBalance == 0) {\n pool.lastRewardBlock = block.number;\n return;\n }\n\n (uint256 accumulatedReward_, uint256 accumulatedRewardPerShare_) =\n _getPoolAccumulatedReward(pool);\n pool.accumulatedRewardPerShare = pool.accumulatedRewardPerShare.add(\n accumulatedRewardPerShare_\n );\n pool.lastRewardBlock = block.number;\n\n totalUsersBalance = totalUsersBalance.add(accumulatedReward_);\n }\n\n function _getPoolAccumulatedReward(PoolInfo storage _pool)\n internal\n view\n returns (uint256, uint256)\n {\n return _getPoolAccumulatedReward(_pool, 0, _pool.lastRewardBlock, block.number);\n }\n\n function _getPoolAccumulatedReward(\n PoolInfo storage _pool,\n uint256 _additionalAmount,\n uint256 _startBlock,\n uint256 _endBlock\n ) internal view returns (uint256, uint256) {\n uint256 passedBlocks = _getPassedBlocksWithBonusMultiplier(_startBlock, _endBlock);\n uint256 accumulatedReward =\n passedBlocks.mul(rewardTokensPerBlock).mul(_pool.allocationPoint).div(\n totalAllocationPoint\n );\n\n uint256 poolTokenBalance = _pool.poolToken.balanceOf(address(this));\n poolTokenBalance = poolTokenBalance.add(_additionalAmount);\n uint256 accumulatedRewardPerShare = accumulatedReward.mul(PRECISION).div(poolTokenBalance);\n return (accumulatedReward, accumulatedRewardPerShare);\n }\n\n /**\n * @notice deposits pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it or to msg.sender\n */\n function deposit(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n _deposit(_poolToken, _amount, _user, false);\n }\n\n /**\n * @notice if the lending pools directly mint/transfer tokens to this address, process it like a user deposit\n * @dev only callable by the pool which issues the tokens\n * @param _user the user address\n * @param _amount the minted amount\n */\n function onTokensDeposited(address _user, uint256 _amount) external {\n //the msg.sender is the pool token. if the msg.sender is not a valid pool token, _deposit will revert\n _deposit(msg.sender, _amount, _user, true);\n }\n\n /**\n * @notice internal function for depositing pool tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the address of user, tokens will be deposited to it\n * @param alreadyTransferred true if the pool tokens have already been transferred\n */\n function _deposit(\n address _poolToken,\n uint256 _amount,\n address _user,\n bool alreadyTransferred\n ) internal {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _user != address(0) ? _user : msg.sender;\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n\n _updatePool(poolId);\n //sends reward directly to the user\n _updateReward(pool, user);\n\n if (_amount > 0) {\n //receives pool tokens from msg.sender, it can be user or WrapperProxy contract\n if (!alreadyTransferred)\n pool.poolToken.safeTransferFrom(address(msg.sender), address(this), _amount);\n user.amount = user.amount.add(_amount);\n }\n _updateRewardDebt(pool, user);\n emit Deposit(userAddress, _poolToken, _amount);\n }\n\n /**\n * @notice transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimReward(address _poolToken, address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n _claimReward(poolId, userAddress, true);\n }\n\n function _claimReward(\n uint256 _poolId,\n address _userAddress,\n bool _isStakingTokens\n ) internal {\n PoolInfo storage pool = poolInfoList[_poolId];\n UserInfo storage user = userInfoMap[_poolId][_userAddress];\n\n _updatePool(_poolId);\n _updateReward(pool, user);\n _transferReward(address(pool.poolToken), user, _userAddress, _isStakingTokens, true);\n _updateRewardDebt(pool, user);\n }\n\n /**\n * @notice transfers reward tokens from all pools\n * @param _user the address of user to claim reward from (can be passed only by wrapper contract)\n */\n function claimRewardFromAllPools(address _user) external {\n address userAddress = _getUserAddress(_user);\n\n uint256 length = poolInfoList.length;\n for (uint256 i = 0; i < length; i++) {\n uint256 poolId = i;\n _claimReward(poolId, userAddress, false);\n }\n\n if (\n lockedSOV.getLockedBalance(userAddress) > 0 ||\n lockedSOV.getUnlockedBalance(userAddress) > 0\n ) {\n lockedSOV.withdrawAndStakeTokensFrom(userAddress);\n }\n }\n\n /**\n * @notice withdraws pool tokens and transfers reward tokens\n * @param _poolToken the address of pool token\n * @param _amount the amount of pool tokens\n * @param _user the user address will be used to process a withdrawal (can be passed only by wrapper contract)\n */\n function withdraw(\n address _poolToken,\n uint256 _amount,\n address _user\n ) external {\n require(poolIdList[_poolToken] != 0, \"Pool token not found\");\n address userAddress = _getUserAddress(_user);\n\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][userAddress];\n require(user.amount >= _amount, \"Not enough balance\");\n\n _updatePool(poolId);\n _updateReward(pool, user);\n _transferReward(_poolToken, user, userAddress, false, false);\n\n user.amount = user.amount.sub(_amount);\n\n //msg.sender is wrapper -> send to wrapper\n if (msg.sender == wrapper) {\n pool.poolToken.safeTransfer(address(msg.sender), _amount);\n }\n //msg.sender is user or pool token (lending pool) -> send to user\n else {\n pool.poolToken.safeTransfer(userAddress, _amount);\n }\n\n _updateRewardDebt(pool, user);\n emit Withdraw(userAddress, _poolToken, _amount);\n }\n\n function _getUserAddress(address _user) internal view returns (address) {\n address userAddress = msg.sender;\n if (_user != address(0)) {\n //only wrapper can pass _user parameter\n require(\n msg.sender == wrapper || poolIdList[msg.sender] != 0,\n \"only wrapper or pools may withdraw for a user\"\n );\n userAddress = _user;\n }\n return userAddress;\n }\n\n function _updateReward(PoolInfo storage pool, UserInfo storage user) internal {\n //update user accumulated reward\n if (user.amount > 0) {\n //add reward for the previous amount of deposited tokens\n uint256 accumulatedReward =\n user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION).sub(\n user.rewardDebt\n );\n user.accumulatedReward = user.accumulatedReward.add(accumulatedReward);\n }\n }\n\n function _updateRewardDebt(PoolInfo storage pool, UserInfo storage user) internal {\n //reward accumulated before amount update (should be subtracted during next reward calculation)\n user.rewardDebt = user.amount.mul(pool.accumulatedRewardPerShare).div(PRECISION);\n }\n\n /**\n * @notice Send reward in SOV to the lockedSOV vault.\n * @param _user The user info, to get its reward share.\n * @param _userAddress The address of the user, to send SOV in its behalf.\n * @param _isStakingTokens The flag whether we need to stake tokens\n * @param _isCheckingBalance The flag whether we need to throw error or don't process reward if SOV balance isn't enough\n */\n function _transferReward(\n address _poolToken,\n UserInfo storage _user,\n address _userAddress,\n bool _isStakingTokens,\n bool _isCheckingBalance\n ) internal {\n uint256 userAccumulatedReward = _user.accumulatedReward;\n /// @dev get unlock immediate percent of the pool token.\n uint256 calculatedUnlockedImmediatelyPercent = calcUnlockedImmediatelyPercent(_poolToken);\n\n /// @dev Transfer if enough SOV balance on this LM contract.\n uint256 balance = SOV.balanceOf(address(this));\n if (balance >= userAccumulatedReward) {\n totalUsersBalance = totalUsersBalance.sub(userAccumulatedReward);\n _user.accumulatedReward = 0;\n\n /// @dev If calculatedUnlockedImmediatelyPercent is 100%, transfer the reward to the LP (user).\n /// else, deposit it into lockedSOV vault contract, but first\n /// SOV deposit must be approved to move the SOV tokens\n /// from this LM contract into the lockedSOV vault.\n if (calculatedUnlockedImmediatelyPercent == 10000) {\n SOV.transfer(_userAddress, userAccumulatedReward);\n } else {\n require(SOV.approve(address(lockedSOV), userAccumulatedReward), \"Approve failed\");\n lockedSOV.deposit(\n _userAddress,\n userAccumulatedReward,\n calculatedUnlockedImmediatelyPercent\n );\n\n if (_isStakingTokens) {\n lockedSOV.withdrawAndStakeTokensFrom(_userAddress);\n }\n }\n\n /// @dev Event log.\n emit RewardClaimed(_userAddress, _poolToken, userAccumulatedReward);\n } else {\n require(!_isCheckingBalance, \"Claiming reward failed\");\n }\n }\n\n /**\n * @notice withdraws pool tokens without transferring reward tokens\n * @param _poolToken the address of pool token\n * @dev EMERGENCY ONLY\n */\n function emergencyWithdraw(address _poolToken) external {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n UserInfo storage user = userInfoMap[poolId][msg.sender];\n\n _updatePool(poolId);\n _updateReward(pool, user);\n\n totalUsersBalance = totalUsersBalance.sub(user.accumulatedReward);\n uint256 userAmount = user.amount;\n uint256 userAccumulatedReward = user.accumulatedReward;\n user.amount = 0;\n user.rewardDebt = 0;\n user.accumulatedReward = 0;\n pool.poolToken.safeTransfer(address(msg.sender), userAmount);\n\n emit EmergencyWithdraw(msg.sender, _poolToken, userAmount, userAccumulatedReward);\n }\n\n /**\n * @notice returns pool id\n * @param _poolToken the address of pool token\n */\n function getPoolId(address _poolToken) external view returns (uint256) {\n return _getPoolId(_poolToken);\n }\n\n function _getPoolId(address _poolToken) internal view returns (uint256) {\n uint256 poolId = poolIdList[_poolToken];\n require(poolId > 0, \"Pool token not found\");\n return poolId - 1;\n }\n\n /**\n * @notice returns count of pool tokens\n */\n function getPoolLength() external view returns (uint256) {\n return poolInfoList.length;\n }\n\n /**\n * @notice returns list of pool token's info\n */\n function getPoolInfoList() external view returns (PoolInfo[] memory) {\n return poolInfoList;\n }\n\n /**\n * @notice returns pool info for the given token\n * @param _poolToken the address of pool token\n */\n function getPoolInfo(address _poolToken) external view returns (PoolInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return poolInfoList[poolId];\n }\n\n /**\n * @notice returns list of [amount, accumulatedReward] for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserBalanceList(address _user) external view returns (uint256[2][] memory) {\n uint256 length = poolInfoList.length;\n uint256[2][] memory userBalanceList = new uint256[2][](length);\n for (uint256 i = 0; i < length; i++) {\n userBalanceList[i][0] = userInfoMap[i][_user].amount;\n userBalanceList[i][1] = _getUserAccumulatedReward(i, _user);\n }\n return userBalanceList;\n }\n\n /**\n * @notice returns UserInfo for the given pool and user\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserInfo(address _poolToken, address _user) public view returns (UserInfo memory) {\n uint256 poolId = _getPoolId(_poolToken);\n return userInfoMap[poolId][_user];\n }\n\n /**\n * @notice returns list of UserInfo for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserInfoList(address _user) external view returns (UserInfo[] memory) {\n uint256 length = poolInfoList.length;\n UserInfo[] memory userInfoList = new UserInfo[](length);\n for (uint256 i = 0; i < length; i++) {\n userInfoList[i] = userInfoMap[i][_user];\n }\n return userInfoList;\n }\n\n /**\n * @notice returns accumulated reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardList(address _user) external view returns (uint256[] memory) {\n uint256 length = poolInfoList.length;\n uint256[] memory rewardList = new uint256[](length);\n for (uint256 i = 0; i < length; i++) {\n rewardList[i] = _getUserAccumulatedReward(i, _user);\n }\n return rewardList;\n }\n\n /**\n * @notice returns the pool token balance a user has on the contract\n * @param _poolToken the address of pool token\n * @param _user the address of the user\n */\n function getUserPoolTokenBalance(address _poolToken, address _user)\n external\n view\n returns (uint256)\n {\n UserInfo memory ui = getUserInfo(_poolToken, _user);\n return ui.amount;\n }\n\n /**\n * @notice returns the accumulated liquid reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBePaidLiquid(address _user)\n external\n view\n returns (uint256)\n {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n calculatedUnlockedImmediatelyPercent.mul(_getUserAccumulatedReward(i, _user)).div(\n 10000\n )\n );\n }\n\n return result;\n }\n\n /**\n * @notice returns the accumulated vested reward for the given user for each pool token\n * @param _user the address of the user\n */\n function getUserAccumulatedRewardToBeVested(address _user) external view returns (uint256) {\n uint256 length = poolInfoList.length;\n uint256 result;\n for (uint256 i = 0; i < length; i++) {\n address _poolToken = address(poolInfoList[i].poolToken);\n uint256 calculatedUnlockedImmediatelyPercent =\n calcUnlockedImmediatelyPercent(_poolToken);\n result = result.add(\n (10000 - calculatedUnlockedImmediatelyPercent)\n .mul(_getUserAccumulatedReward(i, _user))\n .div(10000)\n );\n }\n\n return result;\n }\n\n /**\n * @dev calculate the unlocked immediate percentage of specific pool token\n * use the poolTokensUnlockedImmediatelyPercent by default, if it is not set, then use the unlockedImmediatelyPercent\n */\n function calcUnlockedImmediatelyPercent(address _poolToken) public view returns (uint256) {\n uint256 poolTokenUnlockedImmediatelyPercent =\n poolTokensUnlockedImmediatelyPercent[_poolToken];\n return\n poolTokenUnlockedImmediatelyPercent > 0\n ? poolTokenUnlockedImmediatelyPercent\n : unlockedImmediatelyPercent;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningConfigToken.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/IERC20_.sol\";\n\n/**\n * @title Dummy token with 0 total supply.\n *\n * @dev We need this token for having a flexibility with LiquidityMining configuration\n */\ncontract LiquidityMiningConfigToken is IERC20_ {\n function totalSupply() external view returns (uint256) {\n return 0;\n }\n\n function balanceOf(address account) external view returns (uint256) {\n return 0;\n }\n\n function transfer(address recipient, uint256 amount) external returns (bool) {\n return false;\n }\n\n function allowance(address owner, address spender) external view returns (uint256) {\n return 0;\n }\n\n function approve(address spender, uint256 amount) external returns (bool) {\n return false;\n }\n\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool) {\n return false;\n }\n}\n" + }, + "contracts/farm/LiquidityMiningProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./LiquidityMiningStorage.sol\";\nimport \"../proxy/UpgradableProxy.sol\";\n\n/**\n * @dev LiquidityMining contract should be upgradable, use UpgradableProxy\n */\ncontract LiquidityMiningProxy is LiquidityMiningStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/farm/LiquidityMiningStorage.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../utils/AdminRole.sol\";\n\ncontract LiquidityMiningStorage is AdminRole {\n // Info of each user.\n struct UserInfo {\n uint256 amount; // How many pool tokens the user has provided.\n uint256 rewardDebt; // Reward debt. See explanation below.\n uint256 accumulatedReward; //Reward that's ready to be transferred\n //\n // We do some fancy math here. Basically, any point in time, the amount of reward tokens\n // entitled to a user but is accumulated to be distributed is:\n //\n // accumulated reward = (user.amount * pool.accumulatedRewardPerShare) - user.rewardDebt\n //\n // Whenever a user deposits or withdraws LP tokens to a pool. Here's what happens:\n // 1. The pool's `accumulatedRewardPerShare` (and `lastRewardBlock`) gets updated.\n // 2. User receives the accumulated reward sent to his/her address.\n // 3. User's `amount` gets updated.\n // 4. User's `rewardDebt` gets updated.\n }\n\n // Info of each pool.\n struct PoolInfo {\n IERC20 poolToken; // Address of LP token contract.\n uint96 allocationPoint; // How many allocation points assigned to this pool. Amount of reward tokens to distribute per block.\n uint256 lastRewardBlock; // Last block number that reward tokens distribution occurs.\n uint256 accumulatedRewardPerShare; // Accumulated amount of reward tokens per share, times 1e12. See below.\n }\n\n // Rewards tokens created per block.\n uint256 public rewardTokensPerBlock;\n // The block number when reward token mining starts.\n uint256 public startBlock;\n // Block number when bonus reward token period ends.\n uint256 public bonusEndBlock;\n // Block number when reward token period ends.\n uint256 public endBlock;\n\n //Wrapper contract which will be a proxy between user and LM\n address public wrapper;\n\n // Info of each pool.\n PoolInfo[] public poolInfoList;\n // Mapping pool token address => pool id\n mapping(address => uint256) poolIdList;\n // Total allocation points. Must be the sum of all allocation points in all pools.\n uint256 public totalAllocationPoint;\n\n // Info of each user that stakes LP tokens.\n mapping(uint256 => mapping(address => UserInfo)) public userInfoMap;\n // Total balance this contract should have to handle withdrawal for all users\n uint256 public totalUsersBalance;\n\n /// @dev The SOV token\n IERC20 public SOV;\n\n /// @dev The locked vault contract to deposit LP's rewards into.\n ILockedSOV public lockedSOV;\n\n // The % which determines how much will be unlocked immediately.\n /// @dev 10000 is 100%\n uint256 public unlockedImmediatelyPercent;\n\n /// @dev overwrite the unlockedImmediatelyPercent for specific token.\n mapping(address => uint256) public poolTokensUnlockedImmediatelyPercent;\n}\n" + }, + "contracts/feeds/BProPriceFeed.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IMoCState.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The BPro Price Feed contract.\n *\n * This contract gets/sets the MoC (Money on Chain) address of its state\n * contract and queries its method bproUsdPrice to get bPro/USD valuation.\n * */\ncontract BProPriceFeed is IPriceFeedsExt, Ownable {\n address public mocStateAddress;\n\n event SetMoCStateAddress(address indexed mocStateAddress, address changerAddress);\n\n /**\n * @notice Initializes a new MoC state.\n *\n * @param _mocStateAddress MoC state address\n * */\n constructor(address _mocStateAddress) public {\n setMoCStateAddress(_mocStateAddress);\n }\n\n /**\n * @notice Get BPro USD price.\n *\n * @return the BPro USD Price [using mocPrecision]\n */\n function latestAnswer() external view returns (uint256) {\n IMoCState _mocState = IMoCState(mocStateAddress);\n return _mocState.bproUsdPrice();\n }\n\n /**\n * @notice Supposed to get the MoC update time, but instead\n * get the current timestamp.\n *\n * @return Always returns current block's timestamp.\n * */\n function latestTimestamp() external view returns (uint256) {\n return now; /// MoC state doesn't return update timestamp.\n }\n\n /**\n * @notice Set MoC state address.\n *\n * @param _mocStateAddress The MoC state address.\n * */\n function setMoCStateAddress(address _mocStateAddress) public onlyOwner {\n require(Address.isContract(_mocStateAddress), \"_mocStateAddress not a contract\");\n mocStateAddress = _mocStateAddress;\n emit SetMoCStateAddress(mocStateAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/IMoCState.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IMoCState {\n function getRbtcInBitPro(bytes32 bucket) external view returns (uint256);\n\n function globalMaxBPro() external view returns (uint256);\n\n function maxBPro(bytes32 bucket) external view returns (uint256);\n\n function absoluteMaxBPro() external view returns (uint256);\n\n function maxBProWithDiscount() external view returns (uint256);\n\n function bproTecPrice() external view returns (uint256);\n\n function bucketBProTecPrice(bytes32 bucket) external view returns (uint256);\n\n function bproDiscountPrice() external view returns (uint256);\n\n function bproUsdPrice() external view returns (uint256);\n\n function bproSpotDiscountRate() external view returns (uint256);\n\n function getBucketNBPro(bytes32 bucket) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IPriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface IPriceFeeds {\n function queryRate(address sourceToken, address destToken)\n external\n view\n returns (uint256 rate, uint256 precision);\n\n function queryPrecision(address sourceToken, address destToken)\n external\n view\n returns (uint256 precision);\n\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) external view returns (uint256 destAmount);\n\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) external view returns (uint256 sourceToDestSwapRate);\n\n function amountInEth(address Token, uint256 amount) external view returns (uint256 ethAmount);\n\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (uint256);\n\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralInEthAmount);\n\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) external view returns (uint256 currentMargin, uint256 collateralToLoanRate);\n\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) external view returns (bool);\n\n function getFastGasPrice(address payToken) external view returns (uint256);\n}\n" + }, + "contracts/feeds/IRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IRSKOracle {\n function updatePrice(uint256 price, uint256 timestamp) external;\n\n function getPricing() external view returns (uint256, uint256);\n\n function setOracleAddress(address addr) external;\n\n function clearOracleAddress() external;\n}\n" + }, + "contracts/feeds/IV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IV1PoolOracle {\n function read(uint256 price, uint256 timestamp)\n external\n view\n returns (\n uint256,\n uint256,\n uint256,\n uint256,\n uint256,\n uint256\n );\n\n function latestAnswer() external view returns (uint256);\n\n function liquidityPool() external view returns (address);\n\n function latestPrice(address _baseToken) external view returns (uint256 answer);\n}\n\ninterface ILiquidityPoolV1Converter {\n function reserveTokens(uint256 index) external view returns (address);\n}\n" + }, + "contracts/feeds/PriceFeedRSKOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IRSKOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @notice The Price Feed RSK Oracle contract.\n *\n * This contract implements RSK Oracle query functionality,\n * getting the price and the last timestamp from an external oracle contract.\n * */\ncontract PriceFeedRSKOracle is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public rskOracleAddress;\n\n /* Events */\n\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new RSK Oracle.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _rskOracleAddress) public {\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256 _price) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (_price, ) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestTimestamp() external view returns (uint256 _timestamp) {\n IRSKOracle _rskOracle = IRSKOracle(rskOracleAddress);\n (, _timestamp) = _rskOracle.getPricing();\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/PriceFeeds.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./PriceFeedsConstants.sol\";\n\ninterface IPriceFeedsExt {\n function latestAnswer() external view returns (uint256);\n}\n\n/**\n * @title The Price Feeds contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract queries the price feeds contracts where\n * oracles updates token prices computing relative token prices.\n * And besides it includes some calculations about loans such as\n * drawdown, margin and collateral.\n * */\ncontract PriceFeeds is Constants, Ownable {\n using SafeMath for uint256;\n\n /* Events */\n\n event GlobalPricingPaused(address indexed sender, bool indexed isPaused);\n\n /* Storage */\n\n /// Mapping of PriceFeedsExt instances.\n /// token => pricefeed\n mapping(address => IPriceFeedsExt) public pricesFeeds;\n\n /// Decimals of supported tokens.\n mapping(address => uint256) public decimals;\n\n /// Value on rBTC weis for the protocol token.\n uint256 public protocolTokenEthPrice = 0.0002 ether;\n\n /// Flag to pause pricings.\n bool public globalPricingPaused = false;\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires 3 parameters.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * @param _protocolTokenAddress The address of the protocol token.\n * @param _baseTokenAddress The address of the base token.\n * */\n constructor(\n address _wrbtcTokenAddress,\n address _protocolTokenAddress,\n address _baseTokenAddress\n ) public {\n /// Set decimals for this token.\n decimals[address(0)] = 18;\n decimals[_wrbtcTokenAddress] = 18;\n _setWrbtcToken(_wrbtcTokenAddress);\n _setProtocolTokenAddress(_protocolTokenAddress);\n _setBaseToken(_baseTokenAddress);\n }\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @dev Public wrapper for _queryRate internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function queryRate(address sourceToken, address destToken)\n public\n view\n returns (uint256 rate, uint256 precision)\n {\n return _queryRate(sourceToken, destToken);\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @dev Public wrapper for _getDecimalPrecision internal function.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function queryPrecision(address sourceToken, address destToken) public view returns (uint256) {\n return sourceToken != destToken ? _getDecimalPrecision(sourceToken, destToken) : 10**18;\n }\n\n /**\n * @notice Price conversor: Calculate the price of an amount of source\n * tokens in destiny token units.\n *\n * @dev NOTE: This function returns 0 during a pause, rather than a revert.\n * Ensure calling contracts handle correctly.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of the source tokens.\n *\n * @return destAmount The amount of destiny tokens equivalent in price\n * to the amount of source tokens.\n * */\n function queryReturn(\n address sourceToken,\n address destToken,\n uint256 sourceAmount\n ) public view returns (uint256 destAmount) {\n if (globalPricingPaused) {\n return 0;\n }\n\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n destAmount = sourceAmount.mul(rate).div(precision);\n }\n\n /**\n * @notice Calculate the swap rate between two tokens.\n *\n * Regarding slippage, there is a hardcoded slippage limit of 5%, enforced\n * by this function for all borrowing, lending and margin trading\n * originated swaps performed in the Sovryn exchange.\n *\n * This means all operations in the Sovryn exchange are subject to losing\n * up to 5% from the internal swap performed.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param sourceAmount The amount of source tokens.\n * @param destAmount The amount of destiny tokens.\n * @param maxSlippage The maximum slippage limit.\n *\n * @return sourceToDestSwapRate The swap rate between tokens.\n * */\n function checkPriceDisagreement(\n address sourceToken,\n address destToken,\n uint256 sourceAmount,\n uint256 destAmount,\n uint256 maxSlippage\n ) public view returns (uint256 sourceToDestSwapRate) {\n require(!globalPricingPaused, \"pricing is paused\");\n (uint256 rate, uint256 precision) = _queryRate(sourceToken, destToken);\n\n sourceToDestSwapRate = destAmount.mul(precision).div(sourceAmount);\n\n if (rate > sourceToDestSwapRate) {\n uint256 spreadValue = rate - sourceToDestSwapRate;\n spreadValue = spreadValue.mul(10**20).div(sourceToDestSwapRate);\n require(spreadValue <= maxSlippage, \"price disagreement\");\n }\n }\n\n /**\n * @notice Calculate the rBTC amount equivalent to a given token amount.\n * Native coin on RSK is rBTC. This code comes from Ethereum applications,\n * so Eth refers to 10**18 weis of native coin, i.e.: 1 rBTC.\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n *\n * @return ethAmount The amount of rBTC equivalent.\n * */\n function amountInEth(address tokenAddress, uint256 amount)\n public\n view\n returns (uint256 ethAmount)\n {\n /// Token is wrBTC, amount in rBTC is the same.\n if (tokenAddress == address(wrbtcToken)) {\n ethAmount = amount;\n } else {\n (uint256 toEthRate, uint256 toEthPrecision) =\n queryRate(tokenAddress, address(wrbtcToken));\n ethAmount = amount.mul(toEthRate).div(toEthPrecision);\n }\n }\n\n /**\n * @notice Calculate the maximum drawdown of a loan.\n *\n * A drawdown is commonly defined as the decline from a high peak to a\n * pullback low of a specific investment or equity in an account.\n *\n * Drawdown magnitude refers to the amount of value that a user loses\n * during the drawdown period.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param margin The relation between the position size and the loan.\n * margin = (total position size - loan) / loan\n *\n * @return maxDrawdown The maximum drawdown.\n * */\n function getMaxDrawdown(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 margin\n ) public view returns (uint256 maxDrawdown) {\n uint256 loanToCollateralAmount;\n if (collateralToken == loanToken) {\n loanToCollateralAmount = loanAmount;\n } else {\n (uint256 rate, uint256 precision) = queryRate(loanToken, collateralToken);\n loanToCollateralAmount = loanAmount.mul(rate).div(precision);\n }\n\n uint256 combined =\n loanToCollateralAmount.add(loanToCollateralAmount.mul(margin).div(10**20));\n\n maxDrawdown = collateralAmount > combined ? collateralAmount - combined : 0;\n }\n\n /**\n * @notice Calculate the margin and the collateral on rBTC.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralInEthAmount The amount of collateral on rBTC.\n * */\n function getCurrentMarginAndCollateralSize(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralInEthAmount) {\n (currentMargin, ) = getCurrentMargin(\n loanToken,\n collateralToken,\n loanAmount,\n collateralAmount\n );\n\n collateralInEthAmount = amountInEth(collateralToken, collateralAmount);\n }\n\n /**\n * @notice Calculate the margin of a loan.\n *\n * @dev current margin = (total position size - loan) / loan\n * The collateral amount passed as parameter equals the total position size.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n *\n * @return currentMargin The margin of the loan.\n * @return collateralToLoanRate The price ratio between collateral and\n * loan tokens.\n * */\n function getCurrentMargin(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount\n ) public view returns (uint256 currentMargin, uint256 collateralToLoanRate) {\n uint256 collateralToLoanAmount;\n if (collateralToken == loanToken) {\n collateralToLoanAmount = collateralAmount;\n collateralToLoanRate = 10**18;\n } else {\n uint256 collateralToLoanPrecision;\n (collateralToLoanRate, collateralToLoanPrecision) = queryRate(\n collateralToken,\n loanToken\n );\n\n collateralToLoanRate = collateralToLoanRate.mul(10**18).div(collateralToLoanPrecision);\n\n collateralToLoanAmount = collateralAmount.mul(collateralToLoanRate).div(10**18);\n }\n\n if (loanAmount != 0 && collateralToLoanAmount >= loanAmount) {\n return (\n collateralToLoanAmount.sub(loanAmount).mul(10**20).div(loanAmount),\n collateralToLoanRate\n );\n } else {\n return (0, collateralToLoanRate);\n }\n }\n\n /**\n * @notice Get assessment about liquidating a loan.\n *\n * @param loanToken The address of the loan token.\n * @param collateralToken The address of the collateral token.\n * @param loanAmount The amount of the loan.\n * @param collateralAmount The amount of the collateral.\n * @param maintenanceMargin The minimum margin before liquidation.\n *\n * @return True/false to liquidate the loan.\n * */\n function shouldLiquidate(\n address loanToken,\n address collateralToken,\n uint256 loanAmount,\n uint256 collateralAmount,\n uint256 maintenanceMargin\n ) public view returns (bool) {\n (uint256 currentMargin, ) =\n getCurrentMargin(loanToken, collateralToken, loanAmount, collateralAmount);\n\n return currentMargin <= maintenanceMargin;\n }\n\n /*\n * Owner functions\n */\n\n /**\n * @notice Set new value for protocolTokenEthPrice\n *\n * @param newPrice The new value for protocolTokenEthPrice\n * */\n function setProtocolTokenEthPrice(uint256 newPrice) external onlyOwner {\n require(newPrice != 0, \"invalid price\");\n protocolTokenEthPrice = newPrice;\n }\n\n /**\n * @notice Populate pricesFeeds mapping w/ values from feeds[]\n *\n * @param tokens The array of tokens to loop and get addresses.\n * @param feeds The array of contract instances for every token.\n * */\n function setPriceFeed(address[] calldata tokens, IPriceFeedsExt[] calldata feeds)\n external\n onlyOwner\n {\n require(tokens.length == feeds.length, \"count mismatch\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n pricesFeeds[tokens[i]] = feeds[i];\n }\n }\n\n /**\n * @notice Populate decimals mapping w/ values from tokens[].decimals\n *\n * @param tokens The array of tokens to loop and get values from.\n * */\n function setDecimals(IERC20[] calldata tokens) external onlyOwner {\n for (uint256 i = 0; i < tokens.length; i++) {\n decimals[address(tokens[i])] = tokens[i].decimals();\n }\n }\n\n /**\n * @notice Set flag globalPricingPaused\n *\n * @param isPaused The new status of pause (true/false).\n * */\n function setGlobalPricingPaused(bool isPaused) external onlyOwner {\n if (globalPricingPaused != isPaused) {\n globalPricingPaused = isPaused;\n\n emit GlobalPricingPaused(msg.sender, isPaused);\n }\n }\n\n /*\n * Internal functions\n */\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n /// Different tokens, query prices and perform division.\n if (sourceToken != destToken) {\n uint256 sourceRate;\n if (sourceToken != address(baseToken) && sourceToken != protocolTokenAddress) {\n IPriceFeedsExt _sourceFeed = pricesFeeds[sourceToken];\n require(address(_sourceFeed) != address(0), \"unsupported src feed\");\n\n /// Query token price on priceFeedsExt instance.\n sourceRate = _sourceFeed.latestAnswer();\n require(sourceRate != 0 && (sourceRate >> 128) == 0, \"price error\");\n } else {\n sourceRate = sourceToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n uint256 destRate;\n if (destToken != address(baseToken) && destToken != protocolTokenAddress) {\n IPriceFeedsExt _destFeed = pricesFeeds[destToken];\n require(address(_destFeed) != address(0), \"unsupported dst feed\");\n\n /// Query token price on priceFeedsExt instance.\n destRate = _destFeed.latestAnswer();\n require(destRate != 0 && (destRate >> 128) == 0, \"price error\");\n } else {\n destRate = destToken == protocolTokenAddress ? protocolTokenEthPrice : 10**18;\n }\n\n rate = sourceRate.mul(10**18).div(destRate);\n\n precision = _getDecimalPrecision(sourceToken, destToken);\n\n /// Same tokens, return 1 with decimals.\n } else {\n rate = 10**18;\n precision = 10**18;\n }\n }\n\n /**\n * @notice Calculate the relative precision between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return The precision ratio source/dest.\n * */\n function _getDecimalPrecision(address sourceToken, address destToken)\n internal\n view\n returns (uint256)\n {\n /// Same tokens, return 1 with decimals.\n if (sourceToken == destToken) {\n return 10**18;\n\n /// Different tokens, query ERC20 precisions and return 18 +- diff.\n } else {\n uint256 sourceTokenDecimals = decimals[sourceToken];\n if (sourceTokenDecimals == 0) sourceTokenDecimals = IERC20(sourceToken).decimals();\n\n uint256 destTokenDecimals = decimals[destToken];\n if (destTokenDecimals == 0) destTokenDecimals = IERC20(destToken).decimals();\n\n if (destTokenDecimals >= sourceTokenDecimals)\n return 10**(SafeMath.sub(18, destTokenDecimals - sourceTokenDecimals));\n else return 10**(SafeMath.add(18, sourceTokenDecimals - destTokenDecimals));\n }\n }\n}\n" + }, + "contracts/feeds/PriceFeedsConstants.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../openzeppelin/Address.sol\";\n\n/**\n * @title The Price Feeds Constants contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract keep the addresses of token instances for wrBTC, base token\n * and protocol token.\n * */\ncontract Constants {\n IWrbtcERC20 public wrbtcToken;\n IWrbtcERC20 public baseToken;\n address internal protocolTokenAddress;\n\n /**\n * @notice Set wrBTC token address.\n *\n * @param _wrbtcTokenAddress The address of the wrapped wrBTC token.\n * */\n function _setWrbtcToken(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"_wrbtcTokenAddress not a contract\");\n wrbtcToken = IWrbtcERC20(_wrbtcTokenAddress);\n }\n\n /**\n * @notice Set protocol token address.\n *\n * @param _protocolTokenAddress The address of the protocol token.\n * */\n function _setProtocolTokenAddress(address _protocolTokenAddress) internal {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n protocolTokenAddress = _protocolTokenAddress;\n }\n\n /**\n * @notice Set base token address.\n *\n * @param _baseTokenAddress The address of the base token.\n * */\n function _setBaseToken(address _baseTokenAddress) internal {\n require(Address.isContract(_baseTokenAddress), \"_baseTokenAddress not a contract\");\n baseToken = IWrbtcERC20(_baseTokenAddress);\n }\n}\n" + }, + "contracts/feeds/PriceFeedV1PoolOracle.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./PriceFeeds.sol\";\nimport \"./IV1PoolOracle.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./IPriceFeeds.sol\";\n\n/**\n * @notice The Price Feed V1 Pool Oracle contract.\n *\n * This contract implements V1 Pool Oracle query functionality,\n * getting the price from v1 pool oracle.\n * */\ncontract PriceFeedV1PoolOracle is IPriceFeedsExt, Ownable {\n using SafeMath for uint256;\n /* Storage */\n\n address public v1PoolOracleAddress;\n address public wRBTCAddress;\n address public docAddress;\n address public baseCurrency;\n\n /* Events */\n event SetV1PoolOracleAddress(address indexed v1PoolOracleAddress, address changerAddress);\n event SetWRBTCAddress(address indexed wRBTCAddress, address changerAddress);\n event SetDOCAddress(address indexed docAddress, address changerAddress);\n event SetBaseCurrency(address indexed baseCurrency, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new V1 Pool Oracle.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n * @param _wRBTCAddress The wrbtc token address.\n * @param _docAddress The doc token address.\n * */\n constructor(\n address _v1PoolOracleAddress,\n address _wRBTCAddress,\n address _docAddress,\n address _baseCurrency\n ) public {\n setRBTCAddress(_wRBTCAddress);\n setDOCAddress(_docAddress);\n setV1PoolOracleAddress(_v1PoolOracleAddress);\n setBaseCurrency(_baseCurrency);\n }\n\n /**\n * @notice Get the oracle price.\n * @return The price from Oracle.\n * */\n function latestAnswer() external view returns (uint256) {\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(v1PoolOracleAddress);\n\n uint256 _price = _v1PoolOracle.latestPrice(baseCurrency);\n\n // Need to convert to USD, since the V1 pool return value is based on BTC\n uint256 priceInUSD = _convertAnswerToUsd(_price);\n require(priceInUSD != 0, \"price error\");\n\n return priceInUSD;\n }\n\n function _convertAnswerToUsd(uint256 _valueInBTC) private view returns (uint256) {\n address _priceFeeds = msg.sender;\n\n uint256 precision = IPriceFeeds(_priceFeeds).queryPrecision(wRBTCAddress, docAddress);\n uint256 valueInUSD =\n IPriceFeeds(_priceFeeds).queryReturn(wRBTCAddress, docAddress, _valueInBTC);\n\n /// Need to multiply by query precision (doc's precision) and divide by 1*10^18 (Because the based price in v1 pool is using 18 decimals)\n return valueInUSD.mul(precision).div(1e18);\n }\n\n /**\n * @notice Set the V1 Pool Oracle address.\n *\n * @param _v1PoolOracleAddress The V1 Pool Oracle address.\n */\n function setV1PoolOracleAddress(address _v1PoolOracleAddress) public onlyOwner {\n require(Address.isContract(_v1PoolOracleAddress), \"_v1PoolOracleAddress not a contract\");\n IV1PoolOracle _v1PoolOracle = IV1PoolOracle(_v1PoolOracleAddress);\n address liquidityPool = _v1PoolOracle.liquidityPool();\n require(\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(0) == wRBTCAddress ||\n ILiquidityPoolV1Converter(liquidityPool).reserveTokens(1) == wRBTCAddress,\n \"one of the two reserves needs to be wrbtc\"\n );\n v1PoolOracleAddress = _v1PoolOracleAddress;\n emit SetV1PoolOracleAddress(v1PoolOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the rBtc address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the rBtc\n *\n * @param _wRBTCAddress The rBTC address\n */\n function setRBTCAddress(address _wRBTCAddress) public onlyOwner {\n require(_wRBTCAddress != address(0), \"wRBTC address cannot be zero address\");\n wRBTCAddress = _wRBTCAddress;\n emit SetWRBTCAddress(wRBTCAddress, msg.sender);\n }\n\n /**\n * @notice Set the DoC address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the DoC\n *\n * @param _docAddress The DoC address\n */\n function setDOCAddress(address _docAddress) public onlyOwner {\n require(_docAddress != address(0), \"DOC address cannot be zero address\");\n docAddress = _docAddress;\n emit SetDOCAddress(_docAddress, msg.sender);\n }\n\n /**\n * @notice Set the base currency address. That's the reserve address which is not WRBTC\n *\n * @param _baseCurrency The base currency address\n */\n function setBaseCurrency(address _baseCurrency) public onlyOwner {\n require(_baseCurrency != address(0), \"Base currency address cannot be zero address\");\n baseCurrency = _baseCurrency;\n emit SetBaseCurrency(_baseCurrency, msg.sender);\n }\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsLocal.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\n\n/**\n * @title Price Feeds Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the logic of setting and getting rates between two tokens.\n * */\ncontract PriceFeedsLocal is PriceFeeds {\n mapping(address => mapping(address => uint256)) public rates;\n\n /// uint256 public slippageMultiplier = 100 ether;\n\n /**\n * @notice Deploy local price feed contract.\n *\n * @param _wrbtcTokenAddress The address of the wrBTC instance.\n * @param _protocolTokenAddress The address of the protocol token instance.\n * */\n constructor(address _wrbtcTokenAddress, address _protocolTokenAddress)\n public\n PriceFeeds(_wrbtcTokenAddress, _protocolTokenAddress, _wrbtcTokenAddress)\n {}\n\n /**\n * @notice Calculate the price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n *\n * @return rate The price ratio source/dest.\n * @return precision The ratio precision.\n * */\n function _queryRate(address sourceToken, address destToken)\n internal\n view\n returns (uint256 rate, uint256 precision)\n {\n require(!globalPricingPaused, \"pricing is paused\");\n\n if (sourceToken == destToken) {\n rate = 10**18;\n precision = 10**18;\n } else {\n if (sourceToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = protocolTokenEthPrice;\n } else if (destToken == protocolTokenAddress) {\n /// Hack for testnet; only returns price in rBTC.\n rate = SafeMath.div(10**36, protocolTokenEthPrice);\n } else {\n if (rates[sourceToken][destToken] != 0) {\n rate = rates[sourceToken][destToken];\n } else {\n uint256 sourceToEther =\n rates[sourceToken][address(wrbtcToken)] != 0\n ? rates[sourceToken][address(wrbtcToken)]\n : 10**18;\n uint256 etherToDest =\n rates[address(wrbtcToken)][destToken] != 0\n ? rates[address(wrbtcToken)][destToken]\n : 10**18;\n\n rate = sourceToEther.mul(etherToDest).div(10**18);\n }\n }\n precision = _getDecimalPrecision(sourceToken, destToken);\n }\n }\n\n /**\n * @notice Owner set price ratio between two tokens.\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destiny tokens.\n * @param rate The price ratio source/dest.\n * */\n function setRates(\n address sourceToken,\n address destToken,\n uint256 rate\n ) public onlyOwner {\n if (sourceToken != destToken) {\n rates[sourceToken][destToken] = rate;\n rates[destToken][sourceToken] = SafeMath.div(10**36, rate);\n }\n }\n\n /*function setSlippageMultiplier(\n uint256 _slippageMultiplier)\n public\n onlyOwner\n {\n require (slippageMultiplier != _slippageMultiplier && _slippageMultiplier <= 100 ether);\n slippageMultiplier = _slippageMultiplier;\n }*/\n}\n" + }, + "contracts/feeds/testnet/PriceFeedsMoC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../PriceFeeds.sol\";\nimport \"../IRSKOracle.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\ninterface Medianizer {\n function peek() external view returns (bytes32, bool);\n}\n\n/**\n * @title Price Feed of MoC (Money on Chain) contract.\n *\n * This contract contains the logic to set MoC oracles\n * and query last price update.\n * */\ncontract PriceFeedsMoC is IPriceFeedsExt, Ownable {\n /* Storage */\n\n address public mocOracleAddress;\n address public rskOracleAddress;\n\n /* Events */\n\n event SetMoCOracleAddress(address indexed mocOracleAddress, address changerAddress);\n event SetRSKOracleAddress(address indexed rskOracleAddress, address changerAddress);\n\n /* Functions */\n\n /**\n * @notice Initialize a new MoC Oracle.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n * @param _rskOracleAddress The RSK Oracle address.\n * */\n constructor(address _mocOracleAddress, address _rskOracleAddress) public {\n setMoCOracleAddress(_mocOracleAddress);\n setRSKOracleAddress(_rskOracleAddress);\n }\n\n /**\n * @notice Get the las time oracle updated the price.\n * @return The latest time.\n */\n function latestAnswer() external view returns (uint256) {\n (bytes32 value, bool hasValue) = Medianizer(mocOracleAddress).peek();\n if (hasValue) {\n return uint256(value);\n } else {\n (uint256 price, ) = IRSKOracle(rskOracleAddress).getPricing();\n return price;\n }\n }\n\n /**\n * @notice Set the MoC Oracle address.\n *\n * @param _mocOracleAddress The MoC Oracle address.\n */\n function setMoCOracleAddress(address _mocOracleAddress) public onlyOwner {\n require(Address.isContract(_mocOracleAddress), \"_mocOracleAddress not a contract\");\n mocOracleAddress = _mocOracleAddress;\n emit SetMoCOracleAddress(mocOracleAddress, msg.sender);\n }\n\n /**\n * @notice Set the RSK Oracle address.\n *\n * @param _rskOracleAddress The RSK Oracle address.\n */\n function setRSKOracleAddress(address _rskOracleAddress) public onlyOwner {\n require(Address.isContract(_rskOracleAddress), \"_rskOracleAddress not a contract\");\n rskOracleAddress = _rskOracleAddress;\n emit SetRSKOracleAddress(rskOracleAddress, msg.sender);\n }\n}\n" + }, + "contracts/feeds/USDTPriceFeed.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./PriceFeeds.sol\";\n\n/**\n * @notice The Price Feed USDT contract.\n *\n * This contract implements USDT query functionality,\n * getting the price and the last timestamp from a\n * trivial formula, always returning 1 and now.\n * */\ncontract USDTPriceFeed is IPriceFeedsExt {\n uint256 private constant USDT_RATE = 1 ether;\n\n /**\n * @notice Get the USDT price.\n *\n * @return Always returns the trivial rate of 1.\n * */\n function latestAnswer() external view returns (uint256) {\n return USDT_RATE;\n }\n\n /**\n * @notice Get the las time the price was updated.\n * @return Always trivial current block's timestamp.\n */\n function latestTimestamp() external view returns (uint256) {\n return now;\n }\n}\n" + }, + "contracts/governance/ApprovalReceiver.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./ErrorDecoder.sol\";\nimport \"../token/IApproveAndCall.sol\";\n\n/**\n * @title Base contract for receiving approval from SOV token.\n */\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\n modifier onlyThisContract() {\n // Accepts calls only from receiveApproval function.\n require(msg.sender == address(this), \"unauthorized\");\n _;\n }\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external {\n // Accepts calls only from SOV token.\n require(msg.sender == _getToken(), \"unauthorized\");\n require(msg.sender == _token, \"unauthorized\");\n\n // Only allowed methods.\n bool isAllowed = false;\n bytes4[] memory selectors = _getSelectors();\n bytes4 sig = _getSig(_data);\n for (uint256 i = 0; i < selectors.length; i++) {\n if (sig == selectors[i]) {\n isAllowed = true;\n break;\n }\n }\n require(isAllowed, \"method is not allowed\");\n\n // Check sender and amount.\n address sender;\n uint256 amount;\n (, sender, amount) = abi.decode(\n abi.encodePacked(bytes28(0), _data),\n (bytes32, address, uint256)\n );\n require(sender == _sender, \"sender mismatch\");\n require(amount == _amount, \"amount mismatch\");\n\n _call(_data);\n }\n\n /**\n * @notice Returns token address, only this address can be a sender for receiveApproval.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, 0x. When overriden, the token address making the call.\n */\n function _getToken() internal view returns (address) {\n return address(0);\n }\n\n /**\n * @notice Returns list of function selectors allowed to be invoked.\n * @dev Should be overridden in child contracts, otherwise error will be thrown.\n * @return By default, empty array. When overriden, allowed selectors.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n return new bytes4[](0);\n }\n\n /**\n * @notice Makes call and reverts w/ enhanced error message.\n * @param _data Error message as bytes.\n */\n function _call(bytes memory _data) internal {\n (bool success, bytes memory returnData) = address(this).call(_data);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"receiveApproval: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"receiveApproval: \", string(returnData)));\n }\n }\n }\n\n /**\n * @notice Extracts the called function selector, a hash of the signature.\n * @dev The first four bytes of the call data for a function call specifies\n * the function to be called. It is the first (left, high-order in big-endian)\n * four bytes of the Keccak-256 (SHA-3) hash of the signature of the function.\n * Solidity doesn't yet support a casting of byte[4] to bytes4.\n * Example:\n * msg.data:\n * 0xcdcd77c000000000000000000000000000000000000000000000000000000000000\n * 000450000000000000000000000000000000000000000000000000000000000000001\n * selector (or method ID): 0xcdcd77c0\n * signature: baz(uint32,bool)\n * @param _data The msg.data from the low level call.\n * @return sig First 4 bytes of msg.data i.e. the selector, hash of the signature.\n */\n function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\n assembly {\n sig := mload(add(_data, 32))\n }\n }\n}\n" + }, + "contracts/governance/ErrorDecoder.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base contract to properly handle returned data on failed calls\n * @dev On EVM if the return data length of a call is less than 68,\n * then the transaction fails silently without a revert message!\n *\n * As described in the Solidity documentation\n * https://solidity.readthedocs.io/en/v0.5.17/control-structures.html#revert\n * the revert reason is an ABI-encoded string consisting of:\n * 0x08c379a0 // Function selector (method id) for \"Error(string)\" signature\n * 0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset\n * 0x000000000000000000000000000000000000000000000000000000000000001a // String length\n * 0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data\n *\n * Another example, debug data from test:\n * 0x08c379a0\n * 0000000000000000000000000000000000000000000000000000000000000020\n * 0000000000000000000000000000000000000000000000000000000000000034\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n *\n * Parsed into:\n * Data offset: 20\n * Length: 34\n * Error message:\n * 54696d656c6f636b3a3a73657444656c61793a2044656c6179206d7573742065\n * 7863656564206d696e696d756d2064656c61792e000000000000000000000000\n */\ncontract ErrorDecoder {\n uint256 constant ERROR_MESSAGE_SHIFT = 68; // EVM silent revert error string length\n\n /**\n * @notice Concats two error strings taking into account ERROR_MESSAGE_SHIFT.\n * @param str1 First string, usually a hardcoded context written by dev.\n * @param str2 Second string, usually the error message from the reverted call.\n * @return The concatenated error string\n */\n function _addErrorMessage(string memory str1, string memory str2)\n internal\n pure\n returns (string memory)\n {\n bytes memory bytesStr1 = bytes(str1);\n bytes memory bytesStr2 = bytes(str2);\n string memory str12 =\n new string(bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT);\n bytes memory bytesStr12 = bytes(str12);\n uint256 j = 0;\n for (uint256 i = 0; i < bytesStr1.length; i++) {\n bytesStr12[j++] = bytesStr1[i];\n }\n for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\n bytesStr12[j++] = bytesStr2[i];\n }\n return string(bytesStr12);\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../Staking/SafeMath96.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../../openzeppelin/Address.sol\";\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../interfaces/IConverterAMM.sol\";\n\n/**\n * @title The FeeSharingCollector contract.\n * @notice This contract withdraws fees to be paid to SOV Stakers from the protocol.\n * Stakers call withdraw() to get their share of the fees.\n *\n * @notice Staking is not only granting voting rights, but also access to fee\n * sharing according to the own voting power in relation to the total. Whenever\n * somebody decides to collect the fees from the protocol, they get transferred\n * to a proxy contract which invests the funds in the lending pool and keeps\n * the pool tokens.\n *\n * The fee sharing proxy will be set as feesController of the protocol contract.\n * This allows the fee sharing proxy to withdraw the fees. The fee sharing\n * proxy holds the pool tokens and keeps track of which user owns how many\n * tokens. In order to know how many tokens a user owns, the fee sharing proxy\n * needs to know the user’s weighted stake in relation to the total weighted\n * stake (aka total voting power).\n *\n * Because both values are subject to change, they may be different on each fee\n * withdrawal. To be able to calculate a user’s share of tokens when he wants\n * to withdraw, we need checkpoints.\n *\n * This contract is intended to be set as the protocol fee collector.\n * Anybody can invoke the withdrawFees function which uses\n * protocol.withdrawFees to obtain available fees from operations on a\n * certain token. These fees are deposited in the corresponding loanPool.\n * Also, the staking contract sends slashed tokens to this contract.\n * When a user calls the withdraw function, the contract transfers the fee sharing\n * rewards in proportion to the user’s weighted stake since the last withdrawal.\n *\n * The protocol initially collects fees in all tokens.\n * Then the FeeSharingCollector wihtdraws fees from the protocol.\n * When the fees are withdrawn all the tokens except SOV will be converted to wRBTC\n * and then transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n * */\ncontract FeeSharingCollector is\n SafeMath96,\n IFeeSharingCollector,\n Ownable,\n FeeSharingCollectorStorage\n{\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n address constant ZERO_ADDRESS = address(0);\n address public constant RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT =\n address(uint160(uint256(keccak256(\"RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\"))));\n\n /* Events */\n\n /// @notice Deprecated event after the unification between wrbtc & rbtc\n // event FeeWithdrawn(address indexed sender, address indexed token, uint256 amount);\n event FeeWithdrawnInRBTC(address indexed sender, uint256 amount);\n\n /// @notice An event emitted when tokens transferred.\n event TokensTransferred(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when checkpoint added.\n event CheckpointAdded(address indexed sender, address indexed token, uint256 amount);\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeWithdrawn(\n address indexed sender,\n address indexed receiver,\n address indexed token,\n uint256 amount\n );\n\n /// @notice An event emitted when user fee get withdrawn.\n event UserFeeProcessedNoWithdraw(\n address indexed sender,\n address indexed token,\n uint256 prevProcessedCheckpoints,\n uint256 newProcessedCheckpoints\n );\n\n /**\n * @notice An event emitted when fee from AMM get withdrawn.\n *\n * @param sender sender who initiate the withdrawn amm fees.\n * @param converter the converter address.\n * @param amount total amount of fee (Already converted to WRBTC).\n */\n event FeeAMMWithdrawn(address indexed sender, address indexed converter, uint256 amount);\n\n /// @notice An event emitted when converter address has been registered to be whitelisted.\n event WhitelistedConverter(address indexed sender, address converter);\n\n /// @notice An event emitted when converter address has been removed from whitelist.\n event UnwhitelistedConverter(address indexed sender, address converter);\n\n event RBTCWithdrawn(address indexed sender, address indexed receiver, uint256 amount);\n\n event SetWrbtcToken(\n address indexed sender,\n address indexed oldWrbtcToken,\n address indexed newWrbtcToken\n );\n\n event SetLoanTokenWrbtc(\n address indexed sender,\n address indexed oldLoanTokenWrbtc,\n address indexed newLoanTokenWrbtc\n );\n\n /* Modifier */\n modifier oneTimeExecution(bytes4 _funcSig) {\n require(\n !isFunctionExecuted[_funcSig],\n \"FeeSharingCollector: function can only be called once\"\n );\n _;\n isFunctionExecuted[_funcSig] = true;\n }\n\n /* Functions */\n\n /// @dev fallback function to support rbtc transfer when unwrap the wrbtc.\n function() external payable {}\n\n /**\n * @dev initialize function for fee sharing collector proxy\n * @param wrbtcToken wrbtc token address\n * @param loanWrbtcToken address of loan token wrbtc (IWrbtc)\n */\n function initialize(address wrbtcToken, address loanWrbtcToken)\n external\n onlyOwner\n oneTimeExecution(this.initialize.selector)\n {\n require(\n wrbtcTokenAddress == address(0) && loanTokenWrbtcAddress == address(0),\n \"wrbtcToken or loanWrbtcToken has been initialized\"\n );\n setWrbtcToken(wrbtcToken);\n setLoanTokenWrbtc(loanWrbtcToken);\n }\n\n /**\n * @notice Set the wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newWrbtcTokenAddress The new address of the wrbtc token.\n * */\n function setWrbtcToken(address newWrbtcTokenAddress) public onlyOwner {\n require(Address.isContract(newWrbtcTokenAddress), \"newWrbtcTokenAddress not a contract\");\n emit SetWrbtcToken(msg.sender, wrbtcTokenAddress, newWrbtcTokenAddress);\n wrbtcTokenAddress = newWrbtcTokenAddress;\n }\n\n /**\n * @notice Set the loan wrbtc token address of fee sharing collector.\n *\n * only owner can perform this action.\n *\n * @param newLoanTokenWrbtcAddress The new address of the loan wrbtc token.\n * */\n function setLoanTokenWrbtc(address newLoanTokenWrbtcAddress) public onlyOwner {\n require(\n Address.isContract(newLoanTokenWrbtcAddress),\n \"newLoanTokenWrbtcAddress not a contract\"\n );\n emit SetLoanTokenWrbtc(msg.sender, loanTokenWrbtcAddress, newLoanTokenWrbtcAddress);\n loanTokenWrbtcAddress = newLoanTokenWrbtcAddress;\n }\n\n /**\n * @notice Withdraw fees for the given token:\n * lendingFee + tradingFee + borrowingFee\n * the fees (except SOV) will be converted in wRBTC form, and then will be transferred to wRBTC loan pool.\n * For SOV, it will be directly deposited into the feeSharingCollector from the protocol.\n *\n * @param _tokens array address of the token\n * */\n function withdrawFees(address[] calldata _tokens) external {\n for (uint256 i = 0; i < _tokens.length; i++) {\n require(\n Address.isContract(_tokens[i]),\n \"FeeSharingCollector::withdrawFees: token is not a contract\"\n );\n }\n\n uint256 wrbtcAmountWithdrawn = protocol.withdrawFees(_tokens, address(this));\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap the wrbtc to rbtc, and hold the rbtc.\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFees: wrbtc token amount exceeds 96 bits\"\n );\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, amount96);\n }\n\n // note deprecated event since we unify the wrbtc & rbtc\n // emit FeeWithdrawn(msg.sender, RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, poolTokenAmount);\n\n // note new emitted event\n emit FeeWithdrawnInRBTC(msg.sender, wrbtcAmountWithdrawn);\n }\n\n /**\n * @notice Withdraw amm fees for the given converter addresses:\n * protocolFee from the conversion\n * the fees will be converted in wRBTC form, and then will be transferred to wRBTC loan pool\n *\n * @param _converters array addresses of the converters\n * */\n function withdrawFeesAMM(address[] memory _converters) public {\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n // Validate\n _validateWhitelistedConverter(_converters);\n\n uint96 totalPoolTokenAmount;\n for (uint256 i = 0; i < _converters.length; i++) {\n uint256 wrbtcAmountWithdrawn =\n IConverterAMM(_converters[i]).withdrawFees(address(this));\n\n if (wrbtcAmountWithdrawn > 0) {\n // unwrap wrbtc to rbtc, and hold the rbtc\n wrbtcToken.withdraw(wrbtcAmountWithdrawn);\n\n /// @notice Update unprocessed amount of tokens\n uint96 amount96 =\n safe96(\n wrbtcAmountWithdrawn,\n \"FeeSharingCollector::withdrawFeesAMM: wrbtc token amount exceeds 96 bits\"\n );\n\n totalPoolTokenAmount = add96(\n totalPoolTokenAmount,\n amount96,\n \"FeeSharingCollector::withdrawFeesAMM: total wrbtc token amount exceeds 96 bits\"\n );\n\n emit FeeAMMWithdrawn(msg.sender, _converters[i], wrbtcAmountWithdrawn);\n }\n }\n\n if (totalPoolTokenAmount > 0) {\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, totalPoolTokenAmount);\n }\n }\n\n /**\n * @notice Transfer tokens to this contract.\n * @dev We just update amount of tokens here and write checkpoint in a separate methods\n * in order to prevent adding checkpoints too often.\n * @param _token Address of the token.\n * @param _amount Amount to be transferred.\n * */\n function transferTokens(address _token, uint96 _amount) public {\n require(_token != ZERO_ADDRESS, \"FeeSharingCollector::transferTokens: invalid address\");\n require(_amount > 0, \"FeeSharingCollector::transferTokens: invalid amount\");\n\n /// @notice Transfer tokens from msg.sender\n bool success = IERC20(_token).transferFrom(address(msg.sender), address(this), _amount);\n require(success, \"Staking::transferTokens: token transfer failed\");\n\n // if _token is wrbtc, need to unwrap it to rbtc\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n if (_token == address(wrbtcToken)) {\n wrbtcToken.withdraw(_amount);\n _token = RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT;\n }\n\n _addCheckpoint(_token, _amount);\n\n emit TokensTransferred(msg.sender, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC / native tokens to this contract.\n * @dev We just write checkpoint here (based on the rbtc value that is sent) in a separate methods\n * in order to prevent adding checkpoints too often.\n * */\n function transferRBTC() external payable {\n uint96 _amount = uint96(msg.value);\n require(_amount > 0, \"FeeSharingCollector::transferRBTC: invalid value\");\n\n _addCheckpoint(RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT, _amount);\n\n emit TokensTransferred(msg.sender, ZERO_ADDRESS, _amount);\n }\n\n /**\n * @notice Add checkpoint with accumulated amount by function invocation.\n * @param _token Address of the token.\n * */\n function _addCheckpoint(address _token, uint96 _amount) internal {\n if (block.timestamp - lastFeeWithdrawalTime[_token] >= FEE_WITHDRAWAL_INTERVAL) {\n lastFeeWithdrawalTime[_token] = block.timestamp;\n uint96 amount =\n add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: amount exceeds 96 bits\"\n );\n\n /// @notice Reset unprocessed amount of tokens to zero.\n unprocessedAmount[_token] = 0;\n\n /// @notice Write a regular checkpoint.\n _writeTokenCheckpoint(_token, amount);\n } else {\n unprocessedAmount[_token] = add96(\n unprocessedAmount[_token],\n _amount,\n \"FeeSharingCollector::_addCheckpoint: unprocessedAmount exceeds 96 bits\"\n );\n }\n }\n\n function _withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n /// @dev Prevents block gas limit hit when processing checkpoints\n require(\n _maxCheckpoints > 0,\n \"FeeSharingCollector::withdraw: _maxCheckpoints should be positive\"\n );\n\n address user = msg.sender;\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n uint256 processedUserCheckpoints = processedCheckpoints[user][_token];\n (uint256 amount, uint256 end) =\n _getAccumulatedFees(user, _token, processedUserCheckpoints, _maxCheckpoints);\n if (amount == 0) {\n if (end > processedUserCheckpoints) {\n emit UserFeeProcessedNoWithdraw(msg.sender, _token, processedUserCheckpoints, end);\n processedCheckpoints[user][_token] = end;\n return (0, end);\n } else {\n // getting here most likely means smth wrong with the state\n revert(\"FeeSharingCollector::withdrawFees: no tokens for withdrawal\");\n }\n }\n\n processedCheckpoints[user][_token] = end;\n if (loanTokenWrbtcAddress == _token) {\n // We will change, so that feeSharingCollector will directly burn then loanToken (IWRBTC) to rbtc and send to the user --- by call burnToBTC function\n ILoanTokenWRBTC(_token).burnToBTC(_receiver, amount, false);\n } else {\n // Previously it directly send the loanToken to the user\n require(\n IERC20(_token).transfer(_receiver, amount),\n \"FeeSharingCollector::withdraw: withdrawal failed\"\n );\n }\n\n emit UserFeeWithdrawn(msg.sender, _receiver, _token, amount);\n\n return (amount, end);\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power. Therefore, staking more\n * SOV and/or staking for longer will increase your share of the fees\n * generated, meaning you will earn more from staking.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed. Must be positive value.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public nonReentrant {\n _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n /// @notice Validates if the checkpoint is payable for the user\n function validFromCheckpointsParam(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n address _user\n ) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n // _fromCheckpoint is checkpoint number, not array index, so should be > 1\n require(tokenData.fromCheckpoint > 1, \"_fromCheckpoint param must be > 1\");\n uint256 fromCheckpointIndex = tokenData.fromCheckpoint - 1;\n require(\n tokenData.fromCheckpoint > processedCheckpoints[_user][tokenData.tokenAddress],\n \"_fromCheckpoint param must be > userProcessedCheckpoints\"\n );\n require(\n tokenData.fromCheckpoint <= totalTokenCheckpoints[tokenData.tokenAddress],\n \"_fromCheckpoint should be <= totalTokenCheckpoints\"\n );\n\n Checkpoint memory prevCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex - 1];\n\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n prevCheckpoint.blockNumber - 1,\n prevCheckpoint.timestamp\n );\n require(\n weightedStake == 0,\n \"User weighted stake should be zero at previous checkpoint\"\n );\n\n Checkpoint memory fromCheckpoint =\n tokenCheckpoints[tokenData.tokenAddress][fromCheckpointIndex];\n weightedStake = staking.getPriorWeightedStake(\n _user,\n fromCheckpoint.blockNumber - 1,\n fromCheckpoint.timestamp\n );\n\n require(weightedStake > 0, \"User weighted stake should be > 0 at _fromCheckpoint\");\n }\n }\n\n function validRBTCBasedTokens(address[] memory _tokens) private view {\n for (uint256 i = 0; i < _tokens.length; i++) {\n address _token = _tokens[i];\n if (\n _token != RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT &&\n _token != wrbtcTokenAddress &&\n _token != loanTokenWrbtcAddress\n ) {\n revert(\"only rbtc-based tokens are allowed\");\n }\n }\n }\n\n /**\n * @notice Withdraw accumulated fee to the message sender/receiver.\n *\n * The Sovryn protocol collects fees on every trade/swap and loan.\n * These fees will be distributed to SOV stakers based on their voting\n * power as a percentage of total voting power.\n *\n * This function will directly burnToBTC and use the msg.sender (user) as the receiver\n *\n * @dev WARNING! This function skips all the checkpoints before '_fromCheckpoint' irreversibly, use with care\n *\n * @param _tokens Array of TokenWithSkippedCheckpointsWithdraw struct, which contains the token address, and fromCheckpoiint\n * fromCheckpoints Skips all the checkpoints before '_fromCheckpoint'\n * should be calculated offchain with getNextPositiveUserCheckpoint function\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n *\n * @return total processed checkpoints\n * */\n function _withdrawStartingFromCheckpoints(\n TokenWithSkippedCheckpointsWithdraw[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validFromCheckpointsParam(_tokens, msg.sender);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n TokenWithSkippedCheckpointsWithdraw memory tokenData = _tokens[i];\n if (_maxCheckpoints == 0) break;\n uint256 endToken;\n uint256 totalAmount;\n\n uint256 previousProcessedUserCheckpoints =\n processedCheckpoints[msg.sender][tokenData.tokenAddress];\n uint256 startingCheckpoint =\n tokenData.fromCheckpoint > previousProcessedUserCheckpoints\n ? tokenData.fromCheckpoint\n : previousProcessedUserCheckpoints;\n\n if (\n tokenData.tokenAddress == wrbtcTokenAddress ||\n tokenData.tokenAddress == loanTokenWrbtcAddress ||\n tokenData.tokenAddress == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT\n ) {\n (totalAmount, endToken) = _withdrawRbtcTokenStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n } else {\n (, endToken) = _withdrawStartingFromCheckpoint(\n tokenData.tokenAddress,\n tokenData.fromCheckpoint,\n _maxCheckpoints,\n _receiver\n );\n }\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint).add(1);\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n if (rbtcAmountToSend > 0) {\n // send all rbtc withdrawal\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Function to wrap:\n * 1. regular withdrawal for both rbtc & non-rbtc token\n * 2. skipped checkpoints withdrawal for both rbtc & non-rbtc token\n *\n * @param _nonRbtcTokensRegularWithdraw array of non-rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _rbtcTokensRegularWithdraw array of rbtc token address with no skipped checkpoints that will be withdrawn\n * @param _tokensWithSkippedCheckpoints array of rbtc & non-rbtc TokenWithSkippedCheckpointsWithdraw struct, which has skipped checkpoints that will be withdrawn\n *\n */\n function claimAllCollectedFees(\n address[] calldata _nonRbtcTokensRegularWithdraw,\n address[] calldata _rbtcTokensRegularWithdraw,\n TokenWithSkippedCheckpointsWithdraw[] calldata _tokensWithSkippedCheckpoints,\n uint32 _maxCheckpoints,\n address _receiver\n ) external nonReentrant {\n uint256 totalProcessedCheckpoints;\n\n /** Process normal multiple withdrawal for RBTC based tokens */\n if (_rbtcTokensRegularWithdraw.length > 0) {\n totalProcessedCheckpoints = _withdrawRbtcTokens(\n _rbtcTokensRegularWithdraw,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process normal non-rbtc token withdrawal */\n for (uint256 i = 0; i < _nonRbtcTokensRegularWithdraw.length; i++) {\n if (_maxCheckpoints == 0) break;\n uint256 endTokenCheckpoint;\n\n address _nonRbtcTokenAddress = _nonRbtcTokensRegularWithdraw[i];\n\n /** starting checkpoint is the previous processedCheckpoints for token */\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_nonRbtcTokenAddress];\n\n (, endTokenCheckpoint) = _withdraw(_nonRbtcTokenAddress, _maxCheckpoints, _receiver);\n\n uint256 _previousUsedCheckpoint = endTokenCheckpoint.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n _previousUsedCheckpoint.add(1);\n }\n\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n /** Process token with skipped checkpoints withdrawal */\n if (_tokensWithSkippedCheckpoints.length > 0) {\n totalProcessedCheckpoints = _withdrawStartingFromCheckpoints(\n _tokensWithSkippedCheckpoints,\n _maxCheckpoints,\n _receiver\n );\n _maxCheckpoints = safe32(\n _maxCheckpoints - totalProcessedCheckpoints,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n }\n\n function _withdrawStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10 meaning we should set 9 user's processed checkpoints\n // after _withdraw() the user's processedCheckpoints should be 10\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n (totalAmount, endTokenCheckpoint) = _withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function _withdrawRbtcToken(address _token, uint32 _maxCheckpoints)\n internal\n returns (uint256 totalAmount, uint256 endTokenCheckpoint)\n {\n address user = msg.sender;\n\n IWrbtcERC20 wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n (totalAmount, endTokenCheckpoint) = _getRBTCBalance(_token, user, _maxCheckpoints);\n\n if (totalAmount > 0) {\n processedCheckpoints[user][_token] = endTokenCheckpoint;\n if (_token == address(wrbtcToken)) {\n // unwrap the wrbtc\n wrbtcToken.withdraw(totalAmount);\n } else if (_token == loanTokenWrbtcAddress) {\n // pull out the iWRBTC to rbtc to this feeSharingCollector contract\n /** @dev will use the burned result from IWRBTC to RBTC as return total amount */\n totalAmount = ILoanTokenWRBTC(loanTokenWrbtcAddress).burnToBTC(\n address(this),\n totalAmount,\n false\n );\n }\n }\n }\n\n /**\n * @dev withdraw all of the RBTC balance based on particular checkpoints\n *\n * This function will withdraw RBTC balance which is passed as _token param, so it could be either of these:\n * - rbtc balance or\n * - wrbtc balance which will be unwrapped to rbtc or\n * - iwrbtc balance which will be unwrapped to rbtc or\n *\n *\n * @param _tokens array of either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _maxCheckpoints Maximum number of checkpoints to be processed to workaround block gas limit\n * @param _receiver An optional tokens receiver (msg.sender used if 0)\n */\n function _withdrawRbtcTokens(\n address[] memory _tokens,\n uint32 _maxCheckpoints,\n address _receiver\n ) internal returns (uint256 totalProcessedCheckpoints) {\n validRBTCBasedTokens(_tokens);\n\n if (_receiver == ZERO_ADDRESS) {\n _receiver = msg.sender;\n }\n\n uint256 rbtcAmountToSend;\n\n for (uint256 i = 0; i < _tokens.length; i++) {\n if (_maxCheckpoints == 0) break;\n address _token = _tokens[i];\n uint256 startingCheckpoint = processedCheckpoints[msg.sender][_token];\n\n (uint256 totalAmount, uint256 endToken) =\n _withdrawRbtcToken(_tokens[i], _maxCheckpoints);\n rbtcAmountToSend = rbtcAmountToSend.add(totalAmount);\n\n uint256 _previousUsedCheckpoint = endToken.sub(startingCheckpoint);\n if (startingCheckpoint > 0) {\n // we only need to add used checkpoint by 1 only if starting checkpoint > 0\n _previousUsedCheckpoint.add(1);\n }\n totalProcessedCheckpoints += _previousUsedCheckpoint;\n _maxCheckpoints = safe32(\n _maxCheckpoints - _previousUsedCheckpoint,\n \"FeeSharingCollector: maxCheckpoint iteration exceeds 32 bits\"\n );\n }\n\n // send all rbtc\n if (rbtcAmountToSend > 0) {\n (bool success, ) = _receiver.call.value(rbtcAmountToSend)(\"\");\n require(success, \"FeeSharingCollector::withdrawRBTC: Withdrawal failed\");\n\n emit RBTCWithdrawn(msg.sender, _receiver, rbtcAmountToSend);\n }\n }\n\n /**\n * @dev Withdraw either specific RBTC related token balance or all RBTC related tokens balances.\n * RBTC related here means, it could be either rbtc, wrbtc, or iwrbtc, depends on the _token param.\n */\n function _withdrawRbtcTokenStartingFromCheckpoint(\n address _token,\n uint256 _fromCheckpoint,\n uint32 _maxCheckpoints,\n address _receiver\n ) private returns (uint256 totalAmount, uint256 endTokenCheckpoint) {\n // @dev e.g. _fromCheckpoint == 10\n // after _withdraw() user's processedCheckpoints should be 10 =>\n // set processed checkpoints = 9, next maping index = 9 (10th checkpoint)\n uint256 prevFromCheckpoint = _fromCheckpoint.sub(1);\n if (prevFromCheckpoint > processedCheckpoints[msg.sender][_token]) {\n processedCheckpoints[msg.sender][_token] = prevFromCheckpoint;\n }\n return _withdrawRbtcToken(_token, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n external\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n return _getNextPositiveUserCheckpoint(_user, _token, _startFrom, _maxCheckpoints);\n }\n\n /**\n * @dev Returns first user's checkpoint with weighted stake > 0\n *\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint number to start from. If _startFrom < processedUserCheckpoints then starts from processedUserCheckpoints.\n * @param _maxCheckpoints Max checkpoints to process in a row to avoid timeout error\n * @return [checkpointNum: checkpoint number where user's weighted stake > 0, hasSkippedCheckpoints, hasFees]\n */\n function _getNextPositiveUserCheckpoint(\n address _user,\n address _token,\n uint256 _startFrom,\n uint256 _maxCheckpoints\n )\n internal\n view\n returns (\n uint256 checkpointNum,\n bool hasSkippedCheckpoints,\n bool hasFees\n )\n {\n if (staking.isVestingContract(_user)) {\n return (0, false, false);\n }\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n\n if (processedUserCheckpoints >= totalCheckpoints || totalCheckpoints == 0) {\n return (totalCheckpoints, false, false);\n }\n\n uint256 startFrom =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n\n uint256 end = startFrom.add(_maxCheckpoints);\n if (end >= totalCheckpoints) {\n end = totalCheckpoints;\n }\n\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startFrom; i < end; i++) {\n Checkpoint storage tokenCheckpoint = tokenCheckpoints[_token][i];\n uint96 weightedStake =\n staking.getPriorWeightedStake(\n _user,\n tokenCheckpoint.blockNumber - 1,\n tokenCheckpoint.timestamp\n );\n if (weightedStake > 0) {\n // i is the index and we need to return checkpoint num which is i + 1\n return (i + 1, i > processedUserCheckpoints, true);\n }\n }\n return (end, end > processedUserCheckpoints, false);\n }\n\n /**\n * @notice Get the accumulated loan pool fee of the message sender.\n * @param _user The address of the user or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @return The accumulated fee for the message sender.\n * */\n function getAccumulatedFees(address _user, address _token) public view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: 0\n });\n return amount;\n }\n\n /**\n * @notice Get the accumulated fee rewards for the message sender for a checkpoints range\n *\n * @dev This function is required to keep consistent with caching of weighted voting power when claiming fees\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The accumulated fees rewards for the _user in the given checkpoints interval: [_startFrom, _startFrom + maxCheckpoints].\n * */\n function getAccumulatedFeesForCheckpointsRange(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256) {\n uint256 amount;\n (amount, ) = _getAccumulatedFees(_user, _token, _startFrom, _maxCheckpoints);\n return amount;\n }\n\n /**\n * @dev Get all user fees reward per maxCheckpoint starting from latest processed checkpoint\n *\n * @dev e.g: Total user checkpoint for the particualar token = 300,\n * when we call this function with 50 maxCheckpoint, it will return 6 fee values in array form.\n * if there is no more fees, it will return empty array.\n *\n * @param _user The address of a user (staker) or contract.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _startFrom Checkpoint to start calculating fees from.\n * @param _maxCheckpoints maxCheckpoints to get accumulated fees for the _user\n * @return The next checkpoint num which is the starting point to fetch all of the fees, array of calculated fees.\n * */\n function getAllUserFeesPerMaxCheckpoints(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) external view returns (uint256[] memory fees) {\n require(_maxCheckpoints > 0, \"_maxCheckpoints must be > 0\");\n\n uint256 totalCheckpoints = totalTokenCheckpoints[_token];\n uint256 totalTokensCheckpointsIndex = totalCheckpoints > 0 ? totalCheckpoints - 1 : 0;\n\n if (totalTokensCheckpointsIndex < _startFrom) return fees;\n\n uint256 arrSize = totalTokensCheckpointsIndex.sub(_startFrom).div(_maxCheckpoints) + 1;\n\n fees = new uint256[](arrSize);\n\n for (uint256 i = 0; i < fees.length; i++) {\n (uint256 fee, ) =\n _getAccumulatedFees(\n _user,\n _token,\n _startFrom + i * _maxCheckpoints,\n _maxCheckpoints\n );\n fees[i] = fee;\n }\n\n return fees;\n }\n\n /**\n * @notice Gets accumulated fees for a user starting from a given checkpoint\n *\n * @param _user Address of the user's account.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of the pool token.\n * @param _maxCheckpoints Max checkpoints to process at once to fit into block gas limit\n * @param _startFrom Checkpoint num to start calculations from\n *\n * @return feesAmount - accumulated fees amount\n * @return endCheckpoint - last checkpoint of fees calculation\n * */\n function _getAccumulatedFees(\n address _user,\n address _token,\n uint256 _startFrom,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 feesAmount, uint256 endCheckpoint) {\n if (staking.isVestingContract(_user)) {\n return (0, 0);\n }\n uint256 processedUserCheckpoints = processedCheckpoints[_user][_token];\n uint256 startOfRange =\n _startFrom > processedUserCheckpoints ? _startFrom : processedUserCheckpoints;\n endCheckpoint = _maxCheckpoints > 0\n ? _getEndOfRange(startOfRange, _token, _maxCheckpoints)\n : totalTokenCheckpoints[_token];\n\n if (startOfRange >= totalTokenCheckpoints[_token]) {\n return (0, endCheckpoint);\n }\n\n uint256 cachedLockDate = 0;\n uint96 cachedWeightedStake = 0;\n // @note here processedUserCheckpoints is a number of processed checkpoints and\n // also an index for the next checkpoint because an array index starts wtih 0\n for (uint256 i = startOfRange; i < endCheckpoint; i++) {\n Checkpoint memory checkpoint = tokenCheckpoints[_token][i];\n uint256 lockDate = staking.timestampToLockDate(checkpoint.timestamp);\n uint96 weightedStake;\n if (lockDate == cachedLockDate) {\n weightedStake = cachedWeightedStake;\n } else {\n /// @dev We need to use \"checkpoint.blockNumber - 1\" here to calculate weighted stake\n /// For the same block like we did for total voting power in _writeTokenCheckpoint\n weightedStake = staking.getPriorWeightedStake(\n _user,\n checkpoint.blockNumber - 1,\n checkpoint.timestamp\n );\n cachedWeightedStake = weightedStake;\n cachedLockDate = lockDate;\n }\n uint256 share =\n uint256(checkpoint.numTokens).mul(weightedStake).div(\n uint256(checkpoint.totalWeightedStake)\n );\n feesAmount = feesAmount.add(share);\n }\n return (feesAmount, endCheckpoint);\n }\n\n /**\n * @notice Withdrawal should only be possible for blocks which were already\n * mined. If the fees are withdrawn in the same block as the user withdrawal\n * they are not considered by the withdrawing logic (to avoid inconsistencies).\n *\n * @param _start Start of the range.\n * @param _token RBTC dummy to fit into existing data structure or SOV. Former address of a pool token.\n * @param _maxCheckpoints Checkpoint index incremental.\n * */\n function _getEndOfRange(\n uint256 _start,\n address _token,\n uint32 _maxCheckpoints\n ) internal view returns (uint256) {\n uint256 nextCheckpointIndex = totalTokenCheckpoints[_token];\n if (nextCheckpointIndex == 0) {\n return 0;\n }\n uint256 end;\n\n if (_maxCheckpoints == 0) {\n /// @dev All checkpoints will be processed (only for getter outside of a transaction).\n end = nextCheckpointIndex;\n } else {\n end = safe32(\n _start + _maxCheckpoints,\n \"FeeSharingCollector::withdraw: checkpoint index exceeds 32 bits\"\n );\n if (end > nextCheckpointIndex) {\n end = nextCheckpointIndex;\n }\n }\n\n /// @dev Withdrawal should only be possible for blocks which were already mined.\n uint32 lastBlockNumber = tokenCheckpoints[_token][end - 1].blockNumber;\n if (block.number == lastBlockNumber) {\n end--;\n }\n return end;\n }\n\n /**\n * @notice Write a regular checkpoint w/ the foolowing data:\n * block number, block timestamp, total weighted stake and num of tokens.\n * @param _token The pool token address.\n * @param _numTokens The amount of pool tokens.\n * */\n function _writeTokenCheckpoint(address _token, uint96 _numTokens) internal {\n uint32 blockNumber =\n safe32(\n block.number,\n \"FeeSharingCollector::_writeCheckpoint: block number exceeds 32 bits\"\n );\n uint32 blockTimestamp =\n safe32(\n block.timestamp,\n \"FeeSharingCollector::_writeCheckpoint: block timestamp exceeds 32 bits\"\n );\n uint256 nextCheckpointsIndex = totalTokenCheckpoints[_token];\n\n uint96 totalWeightedStake = _getVoluntaryWeightedStake(blockNumber - 1, block.timestamp);\n require(totalWeightedStake > 0, \"Invalid totalWeightedStake\");\n if (\n nextCheckpointsIndex > 0 &&\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].blockNumber == blockNumber\n ) {\n tokenCheckpoints[_token][nextCheckpointsIndex - 1]\n .totalWeightedStake = totalWeightedStake;\n tokenCheckpoints[_token][nextCheckpointsIndex - 1].numTokens = _numTokens;\n } else {\n tokenCheckpoints[_token][nextCheckpointsIndex] = Checkpoint(\n blockNumber,\n blockTimestamp,\n totalWeightedStake,\n _numTokens\n );\n totalTokenCheckpoints[_token] = nextCheckpointsIndex + 1;\n }\n emit CheckpointAdded(msg.sender, _token, _numTokens);\n }\n\n /**\n * Queries the total weighted stake and the weighted stake of vesting contracts and returns the difference\n * @param blockNumber the blocknumber\n * @param timestamp the timestamp\n */\n function _getVoluntaryWeightedStake(uint32 blockNumber, uint256 timestamp)\n internal\n view\n returns (uint96 totalWeightedStake)\n {\n uint96 vestingWeightedStake = staking.getPriorVestingWeightedStake(blockNumber, timestamp);\n totalWeightedStake = staking.getPriorTotalVotingPower(blockNumber, timestamp);\n totalWeightedStake = sub96(\n totalWeightedStake,\n vestingWeightedStake,\n \"FeeSharingCollector::_getTotalVoluntaryWeightedStake: vested stake exceeds total stake\"\n );\n }\n\n /**\n * @dev Whitelisting converter address.\n *\n * @param converterAddress converter address to be whitelisted.\n */\n function addWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n require(Address.isContract(converterAddress), \"Non contract address given\");\n whitelistedConverterList.add(converterAddress);\n emit WhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @dev Removing converter address from whitelist.\n *\n * @param converterAddress converter address to be removed from whitelist.\n */\n function removeWhitelistedConverterAddress(address converterAddress) external onlyOwner {\n whitelistedConverterList.remove(converterAddress);\n emit UnwhitelistedConverter(msg.sender, converterAddress);\n }\n\n /**\n * @notice Getter to query all of the whitelisted converter.\n * @return All of the whitelisted converter list.\n */\n function getWhitelistedConverterList() external view returns (address[] memory converterList) {\n converterList = whitelistedConverterList.enumerate();\n }\n\n /**\n * @dev validate array of given address whether is whitelisted or not.\n * @dev if one of them is not whitelisted, then revert.\n *\n * @param converterAddresses array of converter addresses.\n */\n function _validateWhitelistedConverter(address[] memory converterAddresses) private view {\n for (uint256 i = 0; i < converterAddresses.length; i++) {\n require(whitelistedConverterList.contains(converterAddresses[i]), \"Invalid Converter\");\n }\n }\n\n function withdrawWRBTC(address receiver, uint256 wrbtcAmount) external onlyOwner {\n IERC20 wrbtcToken = IERC20(wrbtcTokenAddress);\n\n uint256 balance = wrbtcToken.balanceOf(address(this));\n require(wrbtcAmount <= balance, \"Insufficient balance\");\n\n wrbtcToken.safeTransfer(receiver, wrbtcAmount);\n }\n\n /**\n * @dev This function is dedicated to recover the wrong fee allocation for the 4 year vesting contracts.\n * This function can only be called once\n * The affected tokens to be withdrawn\n * 1. RBTC\n * 2. ZUSD\n * 3. SOV\n * The amount for all of the tokens above is hardcoded\n * The withdrawn tokens will be sent to the owner.\n */\n function recoverIncorrectAllocatedFees()\n external\n oneTimeExecution(this.recoverIncorrectAllocatedFees.selector)\n onlyOwner\n {\n uint256 rbtcAmount = 878778886164898400;\n uint256 zusdAmount = 16658600400155126000000;\n uint256 sovAmount = 6275898259771202000000;\n\n address zusdToken = 0xdB107FA69E33f05180a4C2cE9c2E7CB481645C2d;\n address sovToken = 0xEFc78fc7d48b64958315949279Ba181c2114ABBd;\n\n // Withdraw rbtc\n (bool success, ) = owner().call.value(rbtcAmount)(\"\");\n require(\n success,\n \"FeeSharingCollector::recoverIncorrectAllocatedFees: Withdrawal rbtc failed\"\n );\n\n // Withdraw ZUSD\n IERC20(zusdToken).safeTransfer(owner(), zusdAmount);\n\n // Withdraw SOV\n IERC20(sovToken).safeTransfer(owner(), sovAmount);\n }\n\n /**\n * @dev view function that calculate the total RBTC that includes:\n * - RBTC\n * - WRBTC\n * - iWRBTC * iWRBTC.tokenPrice()\n * @param _user address of the user.\n * @return rbtc balance of the given user's address.\n */\n function getAccumulatedRBTCFeeBalances(address _user) external view returns (uint256) {\n (uint256 _rbtcAmount, uint256 _wrbtcAmount, uint256 _iWrbtcAmount, , , ) =\n _getRBTCBalances(_user, 0);\n uint256 iWRBTCAmountInRBTC =\n _iWrbtcAmount.mul(ILoanTokenWRBTC(loanTokenWrbtcAddress).tokenPrice()).div(1e18);\n return _rbtcAmount.add(_wrbtcAmount).add(iWRBTCAmountInRBTC);\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _rbtcAmount rbtc amount\n * @return _wrbtcAmount wrbtc amount\n * @return _iWrbtcAmount iWrbtc (wrbtc lending pool token) amount * token price\n * @return _endRBTC end time of accumulated fee calculation for rbtc\n * @return _endWRBTC end time of accumulated fee calculation for wrbtc\n * @return _endIWRBTC end time of accumulated fee calculation for iwrbtc\n */\n function _getRBTCBalances(address _user, uint32 _maxCheckpoints)\n private\n view\n returns (\n uint256 _rbtcAmount,\n uint256 _wrbtcAmount,\n uint256 _iWrbtcAmount,\n uint256 _endRBTC,\n uint256 _endWRBTC,\n uint256 _endIWRBTC\n )\n {\n (_rbtcAmount, _endRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n\n (_wrbtcAmount, _endWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: wrbtcTokenAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n (_iWrbtcAmount, _endIWRBTC) = _getAccumulatedFees({\n _user: _user,\n _token: loanTokenWrbtcAddress,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n }\n\n /**\n * @dev private function that responsible to calculate the user's token that has RBTC as underlying token (rbtc, wrbtc, iWrbtc)\n *\n * @param _token either RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT or wrbtc address or iwrbtc address\n * @param _user address of the user.\n * @param _maxCheckpoints maximum checkpoints.\n *\n * @return _tokenAmount token (rbtc, or wrbtc, or iwrbtc) amount\n * @return _endToken end time of accumulated fee calculation for token (rbtc, or wrbtc, or iwrbtc )\n */\n function _getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) internal view returns (uint256 _tokenAmount, uint256 _endToken) {\n if (\n _token == RBTC_DUMMY_ADDRESS_FOR_CHECKPOINT ||\n _token == wrbtcTokenAddress ||\n _token == loanTokenWrbtcAddress\n ) {\n (_tokenAmount, _endToken) = _getAccumulatedFees({\n _user: _user,\n _token: _token,\n _startFrom: 0,\n _maxCheckpoints: _maxCheckpoints\n });\n } else {\n revert(\"FeeSharingCollector::_getRBTCBalance: only rbtc-based tokens are allowed\");\n }\n }\n\n // @todo update dependency `numTokenCheckpoints` -> `totalTokenCheckpoints` and deprecate numTokenCheckpoints function\n /**\n * @dev This getter function `numTokenCheckpoints` is added for backwards compatibility\n * broken when renamed `numTokenCheckpoints` storage variable to `totalTokenCheckpoints`.\n *\n * @param _token token address to get checkpoints for\n *\n * @return Total token checkpoints\n */\n function numTokenCheckpoints(address _token) external view returns (uint256) {\n return totalTokenCheckpoints[_token];\n }\n}\n\n/* Interfaces */\ninterface ILoanToken {\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n}\n\ninterface ILoanTokenWRBTC {\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function tokenPrice() external view returns (uint256 price);\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./FeeSharingCollectorStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title FeeSharingCollectorProxy contract.\n * @dev FeeSharingCollectorProxy contract should be upgradable, use UpgradableProxy.\n * FeeSharingCollectorStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract FeeSharingCollectorProxy is FeeSharingCollectorStorage, UpgradableProxy {\n /**\n * @notice Construct a new feeSharingCollectorProxy contract.\n * @param _protocol The address of the sovryn protocol.\n * @param _staking The address of the staking\n */\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n}\n" + }, + "contracts/governance/FeeSharingCollector/FeeSharingCollectorStorage.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../mixins/EnumerableAddressSet.sol\";\nimport \"../../interfaces/IWrbtcERC20.sol\";\n\n/**\n * @title FeeSharingCollectorStorage contact\n * @notice Just the storage part of FeeSharingCollector contract, and FeeSharingCollectorProxy. No functions,\n * only constant, variables and required structures (mappings)\n * */\ncontract FeeSharingCollectorStorage is Ownable {\n using EnumerableAddressSet for EnumerableAddressSet.AddressSet;\n uint256 constant FEE_WITHDRAWAL_INTERVAL = 172800;\n\n IProtocol public protocol;\n IStaking public staking;\n\n /// @notice Checkpoints by index per pool token address\n mapping(address => mapping(uint256 => Checkpoint)) public tokenCheckpoints;\n\n /// @notice The number of checkpoints for each token address.\n mapping(address => uint256) public totalTokenCheckpoints;\n\n /// @notice\n /// user => token => processed checkpoints\n mapping(address => mapping(address => uint256)) public processedCheckpoints;\n\n /// @notice Last time fees were withdrawn per pool token address:\n /// token => time\n mapping(address => uint256) public lastFeeWithdrawalTime;\n\n /// @notice Amount of tokens that were transferred, but not saved in checkpoints.\n /// token => amount\n mapping(address => uint96) public unprocessedAmount;\n\n struct Checkpoint {\n uint32 blockNumber;\n uint32 timestamp;\n uint96 totalWeightedStake;\n uint96 numTokens;\n }\n\n struct TokenWithSkippedCheckpointsWithdraw {\n address tokenAddress;\n uint256 fromCheckpoint;\n }\n\n /**\n * @dev Add extra modifier (Reentrancy) below.\n * Because we cannot add any additional storage slot before this storage contract after initial deployment\n */\n\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Additional storage for converter whitelist mechanism.\n * @dev Initialization here does not works. We need to create a separate setter & getter.\n * @dev Just set the visibility to internal should be fine.\n */\n EnumerableAddressSet.AddressSet internal whitelistedConverterList;\n\n mapping(bytes4 => bool) public isFunctionExecuted;\n\n /**\n * @dev Wrbtc token address\n */\n address public wrbtcTokenAddress;\n\n /**\n * @dev iWrbtc loan token address\n */\n address public loanTokenWrbtcAddress;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n\n/* Interfaces */\n\ninterface IProtocol {\n /**\n *\n * @param tokens The array address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function underlyingToLoanPool(address token) external view returns (address);\n\n function wrbtcToken() external view returns (IWrbtcERC20);\n\n function getSovTokenAddress() external view returns (address);\n}\n" + }, + "contracts/governance/GovernorAlpha.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./Staking/SafeMath96.sol\";\nimport \"./Timelock.sol\";\nimport \"./Staking/interfaces/IStaking.sol\";\nimport \"../rsk/RSKAddrValidator.sol\";\n\n/**\n * @title Governance Contract.\n * @notice This is an adapted clone of compound’s governance model. In general,\n * the process is the same: Token holders can make (executable) proposals if\n * they possess enough voting power, vote on proposals during a predefined\n * voting period and in the end evaluate the outcome. If successful, the\n * proposal will be scheduled on the timelock contract. Only after sufficient\n * time passed, it can be executed. A minimum voting power is required for\n * making a proposal as well as a minimum quorum.\n *\n * Voting power in the Bitocracy:\n * Stakers will receive voting power in the Bitocracy in return for their\n * staking commitment. This voting power is weighted by how much SOV is staked\n * and for how long the staking period is - staking more SOV over longer staking\n * periods results in higher voting power. With this voting power, users can\n * vote for or against any SIP in bitocracy.sovryn.app.\n * */\ncontract GovernorAlpha is SafeMath96 {\n /* Storage */\n\n /// @notice The name of this contract.\n string public constant NAME = \"Sovryn Governor Alpha\";\n\n /// @notice The maximum number of actions that can be included in a proposal.\n function proposalMaxOperations() public pure returns (uint256) {\n return 10;\n } // 10 actions\n\n /// @notice The delay before voting on a proposal may take place, once proposed.\n function votingDelay() public pure returns (uint256) {\n return 1;\n } // 1 block\n\n /// @notice The duration of voting on a proposal, in blocks.\n function votingPeriod() public pure returns (uint256) {\n return 2880;\n } // ~1 day in blocks (assuming 30s blocks)\n\n /// @notice The address of the Sovryn Protocol Timelock.\n ITimelock public timelock;\n\n /// @notice The address of the Sovryn staking contract.\n IStaking public staking;\n\n /// @notice The address of the Governor Guardian.\n address public guardian;\n\n /// @notice The total number of proposals.\n uint256 public proposalCount;\n\n /// @notice Percentage of current total voting power require to vote.\n uint96 public quorumPercentageVotes;\n\n // @notice Majority percentage.\n uint96 public majorityPercentageVotes;\n\n struct Proposal {\n /// @notice Unique id for looking up a proposal.\n uint256 id;\n /// @notice The block at which voting begins: holders must delegate their votes prior to this block.\n uint32 startBlock;\n /// @notice The block at which voting ends: votes must be cast prior to this block.\n uint32 endBlock;\n /// @notice Current number of votes in favor of this proposal.\n uint96 forVotes;\n /// @notice Current number of votes in opposition to this proposal.\n uint96 againstVotes;\n ///@notice the quorum required for this proposal.\n uint96 quorum;\n ///@notice the majority percentage required for this proposal.\n uint96 majorityPercentage;\n /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds.\n uint64 eta;\n /// @notice the start time is required for the staking contract.\n uint64 startTime;\n /// @notice Flag marking whether the proposal has been canceled.\n bool canceled;\n /// @notice Flag marking whether the proposal has been executed.\n bool executed;\n /// @notice Creator of the proposal.\n address proposer;\n /// @notice the ordered list of target addresses for calls to be made.\n address[] targets;\n /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made.\n uint256[] values;\n /// @notice The ordered list of function signatures to be called.\n string[] signatures;\n /// @notice The ordered list of calldata to be passed to each call.\n bytes[] calldatas;\n /// @notice Receipts of ballots for the entire set of voters.\n mapping(address => Receipt) receipts;\n }\n\n /// @notice Ballot receipt record for a voter\n struct Receipt {\n /// @notice Whether or not a vote has been cast.\n bool hasVoted;\n /// @notice Whether or not the voter supports the proposal.\n bool support;\n /// @notice The number of votes the voter had, which were cast.\n uint96 votes;\n }\n\n /// @notice Possible states that a proposal may be in.\n enum ProposalState {\n Pending,\n Active,\n Canceled,\n Defeated,\n Succeeded,\n Queued,\n Expired,\n Executed\n }\n\n /// @notice The official record of all proposals ever proposed.\n mapping(uint256 => Proposal) public proposals;\n\n /// @notice The latest proposal for each proposer.\n mapping(address => uint256) public latestProposalIds;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the ballot struct used by the contract.\n bytes32 public constant BALLOT_TYPEHASH = keccak256(\"Ballot(uint256 proposalId,bool support)\");\n\n /* Events */\n\n /// @notice An event emitted when a new proposal is created.\n event ProposalCreated(\n uint256 id,\n address proposer,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint256 startBlock,\n uint256 endBlock,\n string description\n );\n\n /// @notice An event emitted when a vote has been cast on a proposal.\n event VoteCast(address voter, uint256 proposalId, bool support, uint256 votes);\n\n /// @notice An event emitted when a proposal has been canceled.\n event ProposalCanceled(uint256 id);\n\n /// @notice An event emitted when a proposal has been queued in the Timelock.\n event ProposalQueued(uint256 id, uint256 eta);\n\n /// @notice An event emitted when a proposal has been executed in the Timelock.\n event ProposalExecuted(uint256 id);\n\n /* Functions */\n\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 _quorumPercentageVotes,\n uint96 _majorityPercentageVotes\n ) public {\n timelock = ITimelock(timelock_);\n staking = IStaking(staking_);\n guardian = guardian_;\n quorumPercentageVotes = _quorumPercentageVotes;\n majorityPercentageVotes = _majorityPercentageVotes;\n }\n\n /// @notice The number of votes required in order for a voter to become a proposer.\n function proposalThreshold() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(\n block.number - 1,\n \"GovernorAlpha::proposalThreshold: block number overflow\"\n ),\n block.timestamp\n );\n // 1% of current total voting power.\n return totalVotingPower / 100;\n }\n\n /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed.\n function quorumVotes() public view returns (uint96) {\n uint96 totalVotingPower =\n staking.getPriorTotalVotingPower(\n safe32(block.number - 1, \"GovernorAlpha::quorumVotes: block number overflow\"),\n block.timestamp\n );\n // 4% of current total voting power.\n return\n mul96(\n quorumPercentageVotes,\n totalVotingPower,\n \"GovernorAlpha::quorumVotes:multiplication overflow\"\n ) / 100;\n }\n\n /**\n * @notice Create a new proposal.\n * @param targets Array of contract addresses to perform proposal execution.\n * @param values Array of rBTC amounts to send on proposal execution.\n * @param signatures Array of function signatures to call on proposal execution.\n * @param calldatas Array of payloads for the calls on proposal execution.\n * @param description Text describing the purpose of the proposal.\n * */\n function propose(\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n string memory description\n ) public returns (uint256) {\n // note: passing this block's timestamp, but the number of the previous block.\n // todo: think if it would be better to pass block.timestamp - 30 (average block time)\n // (probably not because proposal starts in 1 block from now).\n uint96 threshold = proposalThreshold();\n require(\n staking.getPriorVotes(msg.sender, sub256(block.number, 1), block.timestamp) >\n threshold,\n \"GovernorAlpha::propose: proposer votes below proposal threshold\"\n );\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"GovernorAlpha::propose: proposal function information arity mismatch\"\n );\n require(targets.length != 0, \"GovernorAlpha::propose: must provide actions\");\n require(\n targets.length <= proposalMaxOperations(),\n \"GovernorAlpha::propose: too many actions\"\n );\n\n uint256 latestProposalId = latestProposalIds[msg.sender];\n if (latestProposalId != 0) {\n ProposalState proposersLatestProposalState = state(latestProposalId);\n require(\n proposersLatestProposalState != ProposalState.Active,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already active proposal\"\n );\n require(\n proposersLatestProposalState != ProposalState.Pending,\n \"GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal\"\n );\n }\n\n uint256 startBlock = add256(block.number, votingDelay());\n uint256 endBlock = add256(startBlock, votingPeriod());\n\n proposalCount++;\n\n /// @dev quorum: proposalThreshold is 1% of total votes, we can save gas using this pre calculated value.\n /// @dev startTime: Required by the staking contract. not used by the governance contract itself.\n Proposal memory newProposal =\n Proposal({\n id: proposalCount,\n startBlock: safe32(\n startBlock,\n \"GovernorAlpha::propose: start block number overflow\"\n ),\n endBlock: safe32(endBlock, \"GovernorAlpha::propose: end block number overflow\"),\n forVotes: 0,\n againstVotes: 0,\n quorum: mul96(\n quorumPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on quorum computation\"\n ),\n majorityPercentage: mul96(\n majorityPercentageVotes,\n threshold,\n \"GovernorAlpha::propose: overflow on majorityPercentage computation\"\n ),\n eta: 0,\n startTime: safe64(block.timestamp, \"GovernorAlpha::propose: startTime overflow\"),\n canceled: false,\n executed: false,\n proposer: msg.sender,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas\n });\n\n proposals[newProposal.id] = newProposal;\n latestProposalIds[newProposal.proposer] = newProposal.id;\n\n emit ProposalCreated(\n newProposal.id,\n msg.sender,\n targets,\n values,\n signatures,\n calldatas,\n startBlock,\n endBlock,\n description\n );\n return newProposal.id;\n }\n\n /**\n * @notice Enqueue a proposal and everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function queue(uint256 proposalId) public {\n require(\n state(proposalId) == ProposalState.Succeeded,\n \"GovernorAlpha::queue: proposal can only be queued if it is succeeded\"\n );\n Proposal storage proposal = proposals[proposalId];\n uint256 eta = add256(block.timestamp, timelock.delay());\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n _queueOrRevert(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n proposal.eta = safe64(eta, \"GovernorAlpha::queue: ETA overflow\");\n emit ProposalQueued(proposalId, eta);\n }\n\n /**\n * @notice Tries to enqueue a proposal, verifying it has not been previously queued.\n * @param target Contract addresses to perform proposal execution.\n * @param value rBTC amount to send on proposal execution.\n * @param signature Function signature to call on proposal execution.\n * @param data Payload for the call on proposal execution.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function _queueOrRevert(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) internal {\n require(\n !timelock.queuedTransactions(\n keccak256(abi.encode(target, value, signature, data, eta))\n ),\n \"GovernorAlpha::_queueOrRevert: proposal action already queued at eta\"\n );\n timelock.queueTransaction(target, value, signature, data, eta);\n }\n\n /**\n * @notice Execute a proposal by looping and performing everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function execute(uint256 proposalId) public payable {\n require(\n state(proposalId) == ProposalState.Queued,\n \"GovernorAlpha::execute: proposal can only be executed if it is queued\"\n );\n Proposal storage proposal = proposals[proposalId];\n proposal.executed = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.executeTransaction.value(proposal.values[i])(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n emit ProposalExecuted(proposalId);\n }\n\n /**\n * @notice Cancel a proposal by looping and cancelling everyone of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * */\n function cancel(uint256 proposalId) public {\n ProposalState state = state(proposalId);\n require(\n state != ProposalState.Executed,\n \"GovernorAlpha::cancel: cannot cancel executed proposal\"\n );\n\n Proposal storage proposal = proposals[proposalId];\n /// @notice Cancel only if sent by the guardian.\n require(msg.sender == guardian, \"GovernorAlpha::cancel: sender isn't a guardian\");\n\n proposal.canceled = true;\n\n for (uint256 i = 0; i < proposal.targets.length; i++) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n proposal.eta\n );\n }\n\n emit ProposalCanceled(proposalId);\n }\n\n /**\n * @notice Get a proposal list of its calls.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return Arrays of the 4 call parameters: targets, values, signatures, calldatas.\n * */\n function getActions(uint256 proposalId)\n public\n view\n returns (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas\n )\n {\n Proposal storage p = proposals[proposalId];\n return (p.targets, p.values, p.signatures, p.calldatas);\n }\n\n /**\n * @notice Get a proposal receipt.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param voter A governance stakeholder with voting power.\n * @return The voter receipt of the proposal.\n * */\n function getReceipt(uint256 proposalId, address voter) public view returns (Receipt memory) {\n return proposals[proposalId].receipts[voter];\n }\n\n /**\n * @notice Casts a vote by sender.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function castVote(uint256 proposalId, bool support) public {\n return _castVote(msg.sender, proposalId, support);\n }\n\n /**\n * @notice Voting with EIP-712 Signatures.\n *\n * Voting power can be delegated to any address, and then can be used to\n * vote on proposals. A key benefit to users of by-signature functionality\n * is that they can create a signed vote transaction for free, and have a\n * trusted third-party spend rBTC(or ETH) on gas fees and write it to the\n * blockchain for them.\n *\n * The third party in this scenario, submitting the SOV-holder’s signed\n * transaction holds a voting power that is for only a single proposal.\n * The signatory still holds the power to vote on their own behalf in\n * the proposal if the third party has not yet published the signed\n * transaction that was given to them.\n *\n * @dev The signature needs to be broken up into 3 parameters, known as\n * v, r and s:\n * const r = '0x' + sig.substring(2).substring(0, 64);\n * const s = '0x' + sig.substring(2).substring(64, 128);\n * const v = '0x' + sig.substring(2).substring(128, 130);\n *\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * @param v The recovery byte of the signature.\n * @param r Half of the ECDSA signature pair.\n * @param s Half of the ECDSA signature pair.\n * */\n function castVoteBySig(\n uint256 proposalId,\n bool support,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public {\n /**\n * @dev The DOMAIN_SEPARATOR is a hash that uniquely identifies a\n * smart contract. It is built from a string denoting it as an\n * EIP712 Domain, the name of the token contract, the version,\n * the chainId in case it changes, and the address that the\n * contract is deployed at.\n * */\n bytes32 domainSeparator =\n keccak256(\n abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this))\n );\n\n /// @dev GovernorAlpha uses BALLOT_TYPEHASH, while Staking uses DELEGATION_TYPEHASH\n bytes32 structHash = keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support));\n\n bytes32 digest = keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n address signatory = ecrecover(digest, v, r, s);\n\n /// @dev Verify address is not null and PK is not null either.\n require(\n RSKAddrValidator.checkPKNotZero(signatory),\n \"GovernorAlpha::castVoteBySig: invalid signature\"\n );\n return _castVote(signatory, proposalId, support);\n }\n\n /**\n * @notice Cast a vote, adding it to the total counting.\n * @param voter A governance stakeholder with voting power that is casting the vote.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @param support Vote value, yes or no.\n * */\n function _castVote(\n address voter,\n uint256 proposalId,\n bool support\n ) internal {\n require(\n state(proposalId) == ProposalState.Active,\n \"GovernorAlpha::_castVote: voting is closed\"\n );\n Proposal storage proposal = proposals[proposalId];\n Receipt storage receipt = proposal.receipts[voter];\n require(receipt.hasVoted == false, \"GovernorAlpha::_castVote: voter already voted\");\n uint96 votes = staking.getPriorVotes(voter, proposal.startBlock, proposal.startTime);\n\n if (support) {\n proposal.forVotes = add96(\n proposal.forVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n } else {\n proposal.againstVotes = add96(\n proposal.againstVotes,\n votes,\n \"GovernorAlpha::_castVote: vote overflow\"\n );\n }\n\n receipt.hasVoted = true;\n receipt.support = support;\n receipt.votes = votes;\n\n emit VoteCast(voter, proposalId, support, votes);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __acceptAdmin() public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__acceptAdmin: sender must be gov guardian\"\n );\n timelock.acceptAdmin();\n }\n\n /// @notice Sets guardian address to zero.\n function __abdicate() public {\n require(msg.sender == guardian, \"GovernorAlpha::__abdicate: sender must be gov guardian\");\n guardian = address(0);\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.queueTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /// @dev Timelock wrapper w/ sender check.\n function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {\n require(\n msg.sender == guardian,\n \"GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian\"\n );\n timelock.executeTransaction(\n address(timelock),\n 0,\n \"setPendingAdmin(address)\",\n abi.encode(newPendingAdmin),\n eta\n );\n }\n\n /**\n * @notice Get a proposal state.\n * @param proposalId Proposal index to access the list proposals[] from storage.\n * @return The state of the proposal: Canceled, Pending, Active, Defeated,\n * Succeeded, Executed, Expired.\n * */\n function state(uint256 proposalId) public view returns (ProposalState) {\n require(\n proposalCount >= proposalId && proposalId > 0,\n \"GovernorAlpha::state: invalid proposal id\"\n );\n Proposal storage proposal = proposals[proposalId];\n\n if (proposal.canceled) {\n return ProposalState.Canceled;\n }\n\n if (block.number <= proposal.startBlock) {\n return ProposalState.Pending;\n }\n\n if (block.number <= proposal.endBlock) {\n return ProposalState.Active;\n }\n\n uint96 totalVotes =\n add96(\n proposal.forVotes,\n proposal.againstVotes,\n \"GovernorAlpha:: state: forVotes + againstVotes > uint96\"\n );\n uint96 totalVotesMajorityPercentage =\n div96(totalVotes, 100, \"GovernorAlpha:: state: division error\");\n totalVotesMajorityPercentage = mul96(\n totalVotesMajorityPercentage,\n majorityPercentageVotes,\n \"GovernorAlpha:: state: totalVotes * majorityPercentage > uint96\"\n );\n if (proposal.forVotes <= totalVotesMajorityPercentage || totalVotes < proposal.quorum) {\n return ProposalState.Defeated;\n }\n\n if (proposal.eta == 0) {\n return ProposalState.Succeeded;\n }\n\n if (proposal.executed) {\n return ProposalState.Executed;\n }\n\n if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) {\n return ProposalState.Expired;\n }\n\n return ProposalState.Queued;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function add256(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"addition overflow\");\n return c;\n }\n\n /// @dev TODO: use OpenZeppelin's SafeMath function instead.\n function sub256(uint256 a, uint256 b) internal pure returns (uint256) {\n require(b <= a, \"subtraction underflow\");\n return a - b;\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n}\n\n/* Interfaces */\n\ninterface TimelockInterface {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\ninterface StakingInterface {\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n}\n" + }, + "contracts/governance/GovernorVault.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title Governance Vault.\n * @notice This contract stores tokens and rBTC only transfereble by owner,\n * i.e. Sovryn governance.\n * */\ncontract GovernorVault is Ownable {\n /* Events */\n\n event Deposited(address indexed sender, uint256 amount);\n event TokensTransferred(address indexed receiver, address indexed token, uint256 amount);\n event RbtcTransferred(address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer tokens.\n * @param _receiver The receiver of tokens.\n * @param _token The address of token contract.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _receiver,\n address _token,\n uint256 _amount\n ) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n require(_token != address(0), \"Invalid token address\");\n\n require(IERC20(_token).transfer(_receiver, _amount), \"Transfer failed\");\n emit TokensTransferred(_receiver, _token, _amount);\n }\n\n /**\n * @notice Transfer RBTC.\n * @param _receiver The receiver of RBTC.\n * @param _amount The amount to be transferred.\n * */\n function transferRbtc(address payable _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"Invalid receiver address\");\n\n address(_receiver).transfer(_amount);\n emit RbtcTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {\n if (msg.value > 0) {\n emit Deposited(msg.sender, msg.value);\n }\n }\n}\n" + }, + "contracts/governance/IFeeSharingCollector.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/FeeSharingCollector/FeeSharingCollector.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * */\ninterface IFeeSharingCollector {\n function withdrawFees(address[] calldata _token) external;\n\n function transferTokens(address _token, uint96 _amount) external;\n\n function withdraw(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external;\n}\n" + }, + "contracts/governance/Staking/interfaces/IStaking.sol": { + "content": "pragma solidity ^0.5.17;\n\npragma experimental ABIEncoderV2;\n\n/**\n * @title Interface for Staking modules governance/Staking/modules\n */\n\ninterface IStaking {\n /*************************** StakingAdminModule ***************************/\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external;\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external;\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external;\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external;\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) external;\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external;\n\n /**\n * @notice Allows the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external;\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external;\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external;\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external; // dummy - not implemented as of now\n\n /*************************** StakingGovernanceModule ***************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n external\n view\n returns (uint96);\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * TODO: WeightedStaking::getPriorTotalStakesForDate should probably better\n * be internal instead of a public function.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external;\n\n /*************************** StakingStakeModule ***************************/\n\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until) external;\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external;\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance);\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96);\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes);\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256);\n\n /*************************** StakingStorageModule ***************************/\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256);\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n /// @return uint256(MAX_VOTING_WEIGHT);\n function getStorageMaxVotingWeight() external pure returns (uint256);\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n /// @return uint256(WEIGHT_FACTOR);\n function getStorageWeightFactor() external pure returns (uint256);\n\n /// @return uint256(DEFAULT_WEIGHT_SCALING);\n function getStorageDefaultWeightScaling() external pure returns (uint256);\n\n /// @notice return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING))\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling);\n\n /// @notice The EIP-712 typehash for the contract's domain.\n /// @return uint256(DOMAIN_TYPEHASH);\n function getStorageDomainTypehash() external pure returns (uint256);\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n /// @return uint256(DELEGATION_TYPEHASH);\n function getStorageDelegationTypehash() external pure returns (uint256);\n\n /// @return name;\n function getStorageName() external view returns (string memory);\n\n /// AUTOGENERATED FUNCTIONS FROM THE STAKING STORAGE PUBLIC VARIABLES ///\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n function kickoffTS() external view returns (uint256);\n\n /// @notice The token to be staked\n function SOVToken() external view returns (address);\n\n /// @notice Stakers delegated voting power\n /// @param staker - the delegating address\n /// @param until - delegated voting\n /// @return _delegate - voting power delegated to address\n function delegates(address staker, uint256 until) external view returns (address _delegate);\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately\n /// see function unlockAllTokens() for details\n function allUnlocked() external view returns (bool);\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure\n function newStakingContract() external view returns (address);\n\n /// CHECKPOINTS\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint\n function totalStakingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n function numTotalStakingCheckpoints(uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n function delegateStakingCheckpoints(\n address delagatee,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n function numDelegateStakingCheckpoints(address delegatee, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n function userStakingCheckpoints(\n address user,\n uint256 date,\n uint32 index\n ) external view returns (Checkpoint memory);\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number\n function numUserStakingCheckpoints(address user, uint256 date)\n external\n view\n returns (uint32 checkpointsQty);\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n function nonces(address user) external view returns (uint256 nonce);\n\n /// SLASHING ///\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n function feeSharing() external view returns (address);\n\n /// @notice used for weight scaling when unstaking with slashing.\n /// @return uint96 DEFAULT_WEIGHT_SCALING\n function weightScaling() external view returns (uint96);\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n function vestingWhitelist(address isWhitelisted) external view returns (bool);\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n function admins(address isAdmin) external view returns (bool);\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n function vestingCodeHashes(bytes32 vestingLogicCodeHash) external view returns (bool);\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n function vestingCheckpoints(uint256 date, uint32 index)\n external\n view\n returns (Checkpoint memory);\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n function numVestingCheckpoints(uint256 date) external view returns (uint32 checkpointsQty);\n\n ///@notice vesting registry contract PROXY address\n function vestingRegistryLogic() external view returns (address);\n\n /// @dev user => flag whether user has pauser role.\n function pausers(address isPauser) external view returns (bool);\n\n /// @dev Staking contract is paused\n function paused() external view returns (bool);\n\n /// @dev Staking contract is frozen\n function frozen() external view returns (bool);\n\n /*************************** StakingVestingModule ***************************/\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool);\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external;\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external;\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes);\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96);\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values) external;\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n /*************************** StakingWithdrawModule ***************************/\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * @dev **WARNING** This function should not be no longer used by Sovryn Protocol.\n * Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external;\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting.\n * */\n function governanceWithdrawVesting(address vesting, address receiver) external;\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96);\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external;\n\n /*************************** WeightedStakingModule ***************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The date/timestamp of the unstaking time.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake);\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * TODO: WeightedStaking::weightedStakeByDate should probably better\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Returns public constant MAX_DURATION\n * preserved for backwards compatibility\n * Use getStorageMaxDurationToStakeTokens()\n * @return uint96 MAX_DURATION for staking\n **/\n function MAX_DURATION() external view returns (uint256);\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() external view returns (address);\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() external view returns (bool);\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) external;\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external;\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() external view returns (uint256);\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param maxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 maxIterations) external;\n}\n" + }, + "contracts/governance/Staking/modules/shared/CheckpointsShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\n\n/**\n * @title Checkpoints contract.\n * @notice Increases and decreases storage values for users, delegatees and\n * total daily stake.\n * */\ncontract CheckpointsShared is StakingStorageShared, SafeMath96 {\n /// @notice An event emitted when an account changes its delegate.\n event DelegateChanged(\n address indexed delegator,\n uint256 lockedUntil,\n address indexed fromDelegate,\n address indexed toDelegate\n );\n\n /// @notice An event emitted when a delegate account's stake balance changes.\n event DelegateStakeChanged(\n address indexed delegate,\n uint256 lockedUntil,\n uint256 previousBalance,\n uint256 newBalance\n );\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n event ContractCodeHashAdded(bytes32 hash);\n\n event ContractCodeHashRemoved(bytes32 hash);\n\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n event TeamVestingCancelled(address indexed caller, address receiver);\n\n event TeamVestingPartiallyCancelled(\n address indexed caller,\n address receiver,\n uint256 nextStartFrom\n );\n\n constructor() internal {\n // abstract\n }\n\n /**\n * @notice Increases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = add96(vested, value, \"CP01\"); // vested overflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Decreases the user's vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseVestingStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newVest = sub96(vested, value, \"CP02\"); // vested underflow\n _writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);\n }\n\n /**\n * @notice Writes on storage the user vested amount.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newVest The new vest balance.\n * */\n function _writeVestingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newVest\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP03\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n vestingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n vestingCheckpoints[lockedTS][nCheckpoints - 1].stake = newVest;\n } else {\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newVest);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP04\"); // staked overflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the user's stake for a giving lock date and writes a checkpoint.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseUserStake(\n address account,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\n uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP05\"); // staked underflow\n _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the user stake.\n * @param account The user address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeUserCheckpoint(\n address account,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP06\"); // block number > 32 bits\n\n if (\n nCheckpoints > 0 &&\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n userStakingCheckpoints[account][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numUserStakingCheckpoints[account][lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Increases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP07\"); // block number > 32 bits\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the delegatee's stake for a giving lock date and writes a checkpoint.\n * @param delegatee The delegatee address.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) internal {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = 0;\n // @dev We need to check delegate checkpoint value here,\n //\t\tbecause we had an issue in `stake` function:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n // @dev It can be greater than 0, but inconsistent after 3 transactions\n if (staked > value) {\n newStake = sub96(staked, value, \"CP08\"); // staked underflow\n }\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the delegate stake.\n * @param delegatee The delegate address.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeDelegateCheckpoint(\n address delegatee,\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP09\"); // block numb > 32 bits\n uint96 oldStake = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n\n if (\n nCheckpoints > 0 &&\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].fromBlock ==\n blockNumber\n ) {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints] = Checkpoint(\n blockNumber,\n newStake\n );\n numDelegateStakingCheckpoints[delegatee][lockedTS] = nCheckpoints + 1;\n }\n emit DelegateStakeChanged(delegatee, lockedTS, oldStake, newStake);\n }\n\n /**\n * @notice Increases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to add to the staked balance.\n * */\n function _increaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = add96(staked, value, \"CP10\"); // staked overflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Decreases the total stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to substract to the staked balance.\n * */\n function _decreaseDailyStake(uint256 lockedTS, uint96 value) internal {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\n uint96 newStake = sub96(staked, value, \"CP11\"); // staked underflow\n _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\n }\n\n /**\n * @notice Writes on storage the total stake.\n * @param lockedTS The lock date.\n * @param nCheckpoints The number of checkpoints, to find out the last one index.\n * @param newStake The new staked balance.\n * */\n function _writeStakingCheckpoint(\n uint256 lockedTS,\n uint32 nCheckpoints,\n uint96 newStake\n ) internal {\n uint32 blockNumber = safe32(block.number, \"CP12\"); // block num > 32 bits\n\n if (\n nCheckpoints > 0 &&\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber\n ) {\n totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake = newStake;\n } else {\n totalStakingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newStake);\n numTotalStakingCheckpoints[lockedTS] = nCheckpoints + 1;\n }\n }\n\n /**\n * @notice Get the current balance of an account locked until a certain date.\n * @param account The user address.\n * @param lockDate The lock date.\n * @return The stake amount.\n * */\n function _currentBalance(address account, uint256 lockDate) internal view returns (uint96) {\n uint32 _numUnserStakingCheckpoints = numUserStakingCheckpoints[account][lockDate] - 1;\n return userStakingCheckpoints[account][lockDate][_numUnserStakingCheckpoints].stake;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./StakingStorageShared.sol\";\nimport \"../../SafeMath96.sol\";\nimport \"../../../../openzeppelin/SafeMath.sol\";\nimport \"../../../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking modules shared functionality\n */\ncontract StakingShared is StakingStorageShared, SafeMath96 {\n using SafeMath for uint256;\n\n uint256 internal constant FOUR_WEEKS = 4 weeks;\n\n /**\n * @dev Throws if paused.\n */\n modifier whenNotPaused() {\n require(!paused, \"paused\"); // SS03\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\"); // SS01\n _;\n }\n\n /**\n\t * @dev Throws if called by any account other than the owner or admin or pauser.\n\t \n\tmodifier onlyAuthorizedOrPauser() {\n\t\trequire(isOwner() || admins[msg.sender] || pausers[msg.sender], \"unauthorized\"); // WS02\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if called by any account other than the owner or pauser.\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || pausers[msg.sender], \"unauthorized\"); // SS02\n _;\n }\n\n /**\n * @dev Throws if called by any account other than pauser.\n * @notice Uncomment when needed\n */\n /*\n\tmodifier onlyPauser() {\n\t\trequire(pausers[msg.sender], \"Not pauser\");\n\t\t_;\n\t}\n\t*/\n\n /**\n * @dev Throws if frozen.\n */\n modifier whenNotFrozen() {\n require(!frozen, \"paused\"); // SS04\n _;\n }\n\n constructor() internal {\n // abstract\n }\n\n function _notSameBlockAsStakingCheckpoint(uint256 lockDate, address stakeFor) internal view {\n uint32 nCheckpoints = numUserStakingCheckpoints[stakeFor][lockDate];\n bool notSameBlock =\n userStakingCheckpoints[stakeFor][lockDate][nCheckpoints - 1].fromBlock != block.number;\n require(notSameBlock, \"cannot be mined in the same block as last stake\"); // S20\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = kickoffTS;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / TWO_WEEKS;\n lockDate = periodFromKickoff * TWO_WEEKS + start;\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS14\n\n date = _adjustDateForOrigin(date);\n uint32 nCheckpoints = numUserStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (userStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return userStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (userStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = userStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return userStakingCheckpoints[account][date][lower].stake;\n }\n\n /**\n * @dev origin vesting contracts have different dates\n * we need to add 2 weeks to get end of period (by default, it's start)\n * @param date The staking date to compute the power for.\n * @return unlocking date.\n */\n function _adjustDateForOrigin(uint256 date) internal view returns (uint256) {\n uint256 adjustedDate = _timestampToLockDate(date);\n //origin vesting contracts have different dates\n //we need to add 2 weeks to get end of period (by default, it's start)\n if (adjustedDate != date) {\n date = adjustedDate + TWO_WEEKS;\n }\n return date;\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function _computeWeightByDate(uint256 date, uint256 startDate)\n internal\n pure\n returns (uint96 weight)\n {\n require(date >= startDate, \"date < startDate\"); // WS18\n uint256 remainingTime = (date - startDate);\n require(MAX_DURATION >= remainingTime, \"remaining time > max duration\"); // WS19\n /// @dev x = max days - remaining days\n uint96 x = uint96(MAX_DURATION - remainingTime) / (1 days);\n /// @dev w = (m^2 - x^2)/m^2 +1 (multiplied by the weight factor)\n weight = add96(\n WEIGHT_FACTOR,\n mul96(\n MAX_VOTING_WEIGHT * WEIGHT_FACTOR,\n sub96(\n MAX_DURATION_POW_2,\n x * x,\n \"weight underflow\" // WS20\n ),\n \"weight mul overflow\" // WS21\n ) / MAX_DURATION_POW_2,\n \"overflow on weight\" // WS22\n );\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function _isVestingContract(address stakerAddress) internal view returns (bool) {\n bool isVesting;\n bytes32 codeHash;\n\n assembly {\n codeHash := extcodehash(stakerAddress)\n }\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n}\n" + }, + "contracts/governance/Staking/modules/shared/StakingStorageShared.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../../openzeppelin/Ownable.sol\";\nimport \"../../../../interfaces/IERC20.sol\";\nimport \"../../../IFeeSharingCollector.sol\";\nimport \"../../../Vesting/IVestingRegistry.sol\";\n\n/**\n * @title StakingStorageShared contract is inherited by Staking modules.\n * @notice Just the storage part of stacking contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingProxy and Checkpoints contracts.\n *\n * What is SOV staking?\n * The purpose of the SOV token is to provide a pseudonymous,\n * censorship-resistant mechanism for governing the parameters of the Sovryn\n * protocol, while aligning the incentives of protocol governors with the\n * long-term success of the protocol. Any SOV token holder can choose to\n * stake (lock up) their tokens for a fixed period of time in return for\n * voting rights in the Bitocracy. Stakers are further incentivised through\n * fee and slashing rewards.\n * */\ncontract StakingStorageShared is Ownable {\n /// @notice 2 weeks in seconds.\n uint256 constant TWO_WEEKS = 1209600;\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n uint96 public constant MAX_VOTING_WEIGHT = 9;\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n uint96 public constant WEIGHT_FACTOR = 10;\n\n /// @notice The maximum duration to stake tokens for.\n uint256 public constant MAX_DURATION = 1092 days;\n\n /// @notice The maximum duration ^2\n uint96 constant MAX_DURATION_POW_2 = 1092 * 1092;\n\n /// @notice Default weight scaling.\n uint96 constant DEFAULT_WEIGHT_SCALING = 3;\n\n /// @notice Range for weight scaling.\n uint96 constant MIN_WEIGHT_SCALING = 1;\n uint96 constant MAX_WEIGHT_SCALING = 9;\n\n /// @notice The timestamp of contract creation. Base for the staking period calculation.\n uint256 public kickoffTS;\n\n string name = \"SOVStaking\";\n\n /// @notice The token to be staked.\n IERC20 public SOVToken;\n\n /// @notice A record of each accounts delegate.\n mapping(address => mapping(uint256 => address)) public delegates;\n\n /// @notice If this flag is set to true, all tokens are unlocked immediately.\n bool public allUnlocked = false;\n\n /// @notice The EIP-712 typehash for the contract's domain.\n bytes32 public constant DOMAIN_TYPEHASH =\n keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n bytes32 public constant DELEGATION_TYPEHASH =\n keccak256(\"Delegation(address delegatee,uint256 lockDate,uint256 nonce,uint256 expiry)\");\n\n /// @notice Used for stake migrations to a new staking contract with a different storage structure.\n address public newStakingContract;\n\n /*************************** Checkpoints *******************************/\n\n /// @notice A checkpoint for marking the stakes from a given block\n struct Checkpoint {\n uint32 fromBlock;\n uint96 stake;\n }\n\n /// @notice A record of tokens to be unstaked at a given time in total.\n /// For total voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev totalStakingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public totalStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date.\n /// @dev numTotalStakingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numTotalStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address.\n /// For delegatee voting power computation. Voting weights get adjusted bi-weekly.\n /// @dev delegateStakingCheckpoints[delegatee][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public delegateStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per delegate.\n /// @dev numDelegateStakingCheckpoints[delegatee][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numDelegateStakingCheckpoints;\n\n /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\n /// @dev userStakingCheckpoints[user][date][index] is a checkpoint.\n mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\n public userStakingCheckpoints;\n\n /// @notice The number of total staking checkpoints for each date per user.\n /// @dev numUserStakingCheckpoints[user][date] is a number.\n mapping(address => mapping(uint256 => uint32)) public numUserStakingCheckpoints;\n\n /// @notice A record of states for signing / validating signatures\n /// @dev nonces[user] is a number.\n mapping(address => uint256) public nonces;\n\n /*************************** Slashing *******************************/\n\n /// @notice the address of FeeSharingCollectorProxy contract, we need it for unstaking with slashing.\n IFeeSharingCollector public feeSharing;\n\n /// @notice used for weight scaling when unstaking with slashing.\n uint96 public weightScaling = DEFAULT_WEIGHT_SCALING;\n\n /// @notice List of vesting contracts, tokens for these contracts won't be slashed if unstaked by governance.\n /// @dev vestingWhitelist[contract] is true/false.\n mapping(address => bool) public vestingWhitelist;\n\n /// @dev user => flag whether user has admin role.\n /// @dev multisig should be an admin, admin can invoke only governanceWithdrawVesting function,\n /// \tthis function works only with Team Vesting contracts\n mapping(address => bool) public admins;\n\n /// @dev vesting contract code hash => flag whether it's registered code hash\n mapping(bytes32 => bool) public vestingCodeHashes;\n\n /// @notice A record of tokens to be unstaked from vesting contract at a given time (lockDate -> vest checkpoint)\n /// @dev vestingCheckpoints[date][index] is a checkpoint.\n mapping(uint256 => mapping(uint32 => Checkpoint)) public vestingCheckpoints;\n\n /// @notice The number of total vesting checkpoints for each date.\n /// @dev numVestingCheckpoints[date] is a number.\n mapping(uint256 => uint32) public numVestingCheckpoints;\n\n ///@notice vesting registry contract\n IVestingRegistry public vestingRegistryLogic;\n\n /// @dev user => flag whether user has pauser role.\n mapping(address => bool) public pausers;\n\n /// @dev Staking contract is paused\n bool public paused;\n\n /// @dev Staking contract is frozen\n bool public frozen;\n\n /// @dev max iterations that can be supported in 1 tx for the withdrawal\n uint256 internal maxVestingWithdrawIterations;\n\n constructor() internal {\n //abstract\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingAdminModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Admin Module.\n * @notice Implements administrative functionality pause, freeze and setting addresses and parameters\n * related to staking\n * */\ncontract StakingAdminModule is IFunctionsList, StakingShared {\n using Address for address payable;\n\n event AdminAdded(address admin);\n\n event AdminRemoved(address admin);\n\n /// @param pauser address to grant power to pause the contract\n /// @param added true - added, false - removed\n event PauserAddedOrRemoved(address indexed pauser, bool indexed added);\n\n /// @notice An event emitted when a staking is paused or unpaused\n /// @param setPaused true - pause, false - unpause\n event StakingPaused(bool indexed setPaused);\n\n /// @notice An event emitted when a staking is frozen or unfrozen\n /// @param setFrozen true - freeze, false - unfreeze\n event StakingFrozen(bool indexed setFrozen);\n\n /**\n * @notice Add account to Admins ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(_admin != address(0), \"cannot add the zero address as an admin\");\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from Admins ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) external onlyOwner whenNotFrozen {\n require(admins[_admin], \"address is not an admin\");\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Add account to pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function addPauser(address _pauser) external onlyOwner whenNotFrozen {\n require(_pauser != address(0), \"cannot add the zero address as a pauser\");\n pausers[_pauser] = true;\n emit PauserAddedOrRemoved(_pauser, true);\n }\n\n /**\n * @notice Remove account from pausers ACL.\n * @param _pauser The address to grant pauser permissions.\n * */\n function removePauser(address _pauser) external onlyOwner whenNotFrozen {\n require(pausers[_pauser], \"address is not a pauser\");\n delete pausers[_pauser];\n emit PauserAddedOrRemoved(_pauser, false);\n }\n\n /**\n * @notice Pause/unpause contract\n * @param _pause true when pausing, false when unpausing\n * */\n function pauseUnpause(bool _pause) public onlyPauserOrOwner whenNotFrozen {\n paused = _pause;\n emit StakingPaused(_pause);\n }\n\n /**\n * @notice Freeze contract - disable all functions\n * @param _freeze true when freezing, false when unfreezing\n * @dev When freezing, pause is always applied too. When unfreezing, the contract is left in paused stated.\n * */\n function freezeUnfreeze(bool _freeze) external onlyPauserOrOwner {\n require(_freeze != frozen, \"Cannot freeze/unfreeze to the same state\"); // WS25\n if (_freeze) pauseUnpause(true);\n frozen = _freeze;\n emit StakingFrozen(_freeze);\n }\n\n /**\n * @notice Allow the owner to set a fee sharing proxy contract.\n * We need it for unstaking with slashing.\n * @param _feeSharing The address of FeeSharingCollectorProxy contract.\n * */\n function setFeeSharing(address _feeSharing) external onlyOwner whenNotFrozen {\n require(_feeSharing != address(0), \"FeeSharing address shouldn't be 0\"); // S17\n feeSharing = IFeeSharingCollector(_feeSharing);\n }\n\n /**\n * @notice Allow the owner to set weight scaling.\n * We need it for unstaking with slashing.\n * @param _weightScaling The weight scaling.\n * */\n function setWeightScaling(uint96 _weightScaling) external onlyOwner whenNotFrozen {\n require(\n MIN_WEIGHT_SCALING <= _weightScaling && _weightScaling <= MAX_WEIGHT_SCALING,\n \"scaling doesn't belong to range [1, 9]\" // S18\n );\n weightScaling = _weightScaling;\n }\n\n /**\n * @notice Allow the owner to set a new staking contract.\n * As a consequence it allows the stakers to migrate their positions\n * to the new contract.\n * @dev Doesn't have any influence as long as migrateToNewStakingContract\n * is not implemented.\n * @param _newStakingContract The address of the new staking contract.\n * */\n function setNewStakingContract(address _newStakingContract) external onlyOwner whenNotFrozen {\n require(_newStakingContract != address(0), \"can't reset the new staking contract to 0\"); // S16\n newStakingContract = _newStakingContract;\n }\n\n /**\n * @notice Allow a staker to migrate his positions to the new staking contract.\n * @dev Staking contract needs to be set before by the owner.\n * Currently not implemented, just needed for the interface.\n * In case it's needed at some point in the future,\n * the implementation needs to be changed first.\n * */\n function migrateToNewStakingContract() external whenNotFrozen {\n require(newStakingContract != address(0), \"there is no new staking contract set\"); // S19\n revert(\"not implemented\");\n /// @dev implementation:\n /// @dev Iterate over all possible lock dates from now until now + MAX_DURATION.\n /// @dev Read the stake & delegate of the msg.sender\n /// @dev If stake > 0, stake it at the new contract until the lock date with the current delegate.\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](13);\n functionsList[0] = this.addAdmin.selector;\n functionsList[1] = this.removeAdmin.selector;\n functionsList[2] = this.addPauser.selector;\n functionsList[3] = this.removePauser.selector;\n functionsList[4] = this.pauseUnpause.selector;\n functionsList[5] = this.freezeUnfreeze.selector;\n functionsList[6] = this.setFeeSharing.selector;\n functionsList[7] = this.setWeightScaling.selector;\n functionsList[8] = this.setNewStakingContract.selector;\n functionsList[9] = this.owner.selector;\n functionsList[10] = this.isOwner.selector;\n functionsList[11] = this.transferOwnership.selector;\n functionsList[12] = this.migrateToNewStakingContract.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingGovernanceModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../openzeppelin/Address.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/IVesting.sol\";\n\n/**\n * @title Staking Governance Module contract\n * @notice Implements voting power and delegation functionality\n * */\ncontract StakingGovernanceModule is IFunctionsList, StakingShared, CheckpointsShared {\n using Address for address payable;\n\n /************* TOTAL VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Compute the total voting power at a given time.\n * @param blockNumber The block number, needed for checkpointing.\n * @param time The timestamp for which to calculate the total voting power.\n * @return The total voting power at the given time.\n * */\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n /// @dev Start the computation with the exact or previous unlocking date (voting weight remians the same until the next break point).\n uint256 start = _timestampToLockDate(time);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n totalVotingPower = add96(\n totalVotingPower,\n _totalPowerByDate(i, start, blockNumber),\n \"arrays mismatch\"\n ); // WS06\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorTotalStakesForDate(date, blockNumber);\n /// @dev weight is multiplied by some factor to allow decimals.\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS07\n }\n\n /****************************** DELEGATED VOTING POWER COMPUTATION ************************/\n\n /**\n * @notice Get the current votes balance for a user account.\n * @param account The address to get votes balance.\n * @dev This is a wrapper to simplify arguments. The actual computation is\n * performed on WeightedStaking parent contract.\n * @return The number of current votes for a user account.\n * */\n function getCurrentVotes(address account) external view returns (uint96) {\n return getPriorVotes(account, block.number - 1, block.timestamp);\n }\n\n /**\n * @notice Determine the prior number of votes for a delegatee as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will revert\n * to prevent misinformation.\n * Used for Voting, not for fee sharing.\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The number of votes the delegatee had as of the given block.\n * */\n function getPriorVotes(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96 votes) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n votes = add96(\n votes,\n _totalPowerByDateForDelegatee(account, i, start, blockNumber),\n \"overflow - total VP\"\n ); // WS09\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _totalPowerByDateForDelegatee(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 weight = _computeWeightByDate(date, startDate);\n uint96 staked = _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS10\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n date = _adjustDateForOrigin(date);\n return _getPriorStakeByDateForDelegatee(account, date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an account as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The staking date to compute the power for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorStakeByDateForDelegatee(\n address account,\n uint256 date,\n uint256 blockNumber\n ) internal view returns (uint96) {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined yet\"); // WS11\n\n uint32 nCheckpoints = numDelegateStakingCheckpoints[account][date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (delegateStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return delegateStakingCheckpoints[account][date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (delegateStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = delegateStakingCheckpoints[account][date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return delegateStakingCheckpoints[account][date][lower].stake;\n }\n\n /**************** SHARED FUNCTIONS *********************/\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for. Adjusted to the next valid lock date, as necessary\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n public\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorTotalStakesForDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of stake for an unlocking date as of a block number.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * @param date The date to check the stakes for.\n * @param blockNumber The block number to get the vote balance at.\n * @return The total number of votes as of the given block.\n * */\n function _getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS08\n\n uint32 nCheckpoints = numTotalStakingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n // First check most recent balance\n if (totalStakingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return totalStakingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n // Next check implicit zero balance\n if (totalStakingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\n Checkpoint memory cp = totalStakingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return totalStakingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Set new delegatee. Move from user's current delegate to a new\n * delegatee the stake balance.\n * @param delegator The user address to move stake balance from its current delegatee.\n * @param delegatee The new delegatee. The address to move stake balance to.\n * @param lockedTS The lock date.\n * @dev Reverts if delegator balance or delegatee is not valid, unless the sender is a vesting contract.\n * */\n function _delegate(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n address currentDelegate = delegates[delegator][lockedTS];\n uint96 delegatorBalance = _currentBalance(delegator, lockedTS);\n\n // vesting contracts will in multiple cases try to delegate a zero balance\n // or to the existing delegatee\n if (_isVestingContract(msg.sender)) {\n if (delegatorBalance == 0 || currentDelegate == delegatee) {\n return;\n }\n } else {\n require(delegatorBalance > 0, \"no stake to delegate\");\n require(currentDelegate != delegatee, \"cannot delegate to the existing delegatee\");\n }\n\n delegates[delegator][lockedTS] = delegatee;\n\n emit DelegateChanged(delegator, lockedTS, currentDelegate, delegatee);\n\n _moveDelegates(currentDelegate, delegatee, delegatorBalance, lockedTS);\n }\n\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n function _delegateNext(\n address delegator,\n address delegatee,\n uint256 lockedTS\n ) internal {\n if (_isVestingContract(msg.sender)) {\n uint256 nextLock = lockedTS.add(TWO_WEEKS);\n address currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n\n // @dev workaround for the issue with a delegation of the latest stake\n uint256 endDate = IVesting(msg.sender).endDate();\n nextLock = lockedTS.add(FOUR_WEEKS);\n if (nextLock == endDate) {\n currentDelegate = delegates[delegator][nextLock];\n if (currentDelegate != delegatee) {\n _delegate(delegator, delegatee, nextLock);\n }\n }\n }\n }\n\n /**\n * @notice Move an amount of delegate stake from a source address to a\n * destination address.\n * @param srcRep The address to get the staked amount from.\n * @param dstRep The address to send the staked amount to.\n * @param amount The staked amount to move.\n * @param lockedTS The lock date.\n * */\n function _moveDelegates(\n address srcRep,\n address dstRep,\n uint96 amount,\n uint256 lockedTS\n ) internal {\n if (srcRep != dstRep && amount > 0) {\n if (srcRep != address(0)) _decreaseDelegateStake(srcRep, lockedTS, amount);\n\n if (dstRep != address(0)) _increaseDelegateStake(dstRep, lockedTS, amount);\n }\n }\n\n /**\n * @notice Retrieve CHAIN_ID of the executing chain.\n *\n * Chain identifier (chainID) introduced in EIP-155 protects transaction\n * included into one chain from being included into another chain.\n * Basically, chain identifier is an integer number being used in the\n * processes of signing transactions and verifying transaction signatures.\n *\n * @dev As of version 0.5.12, Solidity includes an assembly function\n * chainid() that provides access to the new CHAINID opcode.\n *\n * TODO: chainId is included in block. So you can get chain id like\n * block timestamp or block number: block.chainid;\n * */\n function _getChainId() internal pure returns (uint256) {\n uint256 chainId;\n assembly {\n chainId := chainid()\n }\n return chainId;\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`.\n * @param delegatee The address to delegate votes to.\n * @param lockDate the date if the position to delegate.\n * */\n function delegate(address delegatee, uint256 lockDate) external whenNotPaused {\n require(delegatee != address(0), \"cannot delegate to the zero address\");\n _notSameBlockAsStakingCheckpoint(lockDate, msg.sender);\n\n _delegate(msg.sender, delegatee, lockDate);\n // @dev delegates tokens for lock date 2 weeks later than given lock date\n //\t\tif message sender is a contract\n _delegateNext(msg.sender, delegatee, lockDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](6);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStakeModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking contract staking functionality module\n * @notice Implements staking functionality\n **/\ncontract StakingStakeModule is IFunctionsList, StakingShared, CheckpointsShared, ApprovalReceiver {\n using SafeMath for uint256;\n\n /// @notice An event emitted when tokens get staked.\n event TokensStaked(\n address indexed staker,\n uint256 amount,\n uint256 lockedUntil,\n uint256 totalStaked\n );\n\n /// @notice An event emitted when a staking period gets extended.\n event ExtendedStakingDuration(\n address indexed staker,\n uint256 previousDate,\n uint256 newDate,\n uint256 amountStaked\n );\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stake(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stake(msg.sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Stake the given amount for the given duration of time.\n * @dev This function will be invoked from receiveApproval\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\n * @param sender The sender of SOV.approveAndCall\n * @param amount The number of tokens to stake.\n * @param until Timestamp indicating the date until which to stake.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n\n function stakeWithApproval(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external onlyThisContract whenNotPaused whenNotFrozen {\n _stake(sender, amount, until, stakeFor, delegatee, false);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * */\n function _stake(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted\n ) internal {\n _stakeOptionalTokenTransfer(\n sender,\n amount,\n until,\n stakeFor,\n delegatee,\n timeAdjusted,\n true // transfer SOV\n );\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param until The date until which the tokens will be staked.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param delegatee The address of the delegatee or stakeFor if default 0x0.\n * @param timeAdjusted Whether fixing date to stacking periods or not.\n * @param transferToken Should transfer SOV - false for multiple iterations like in stakeBySchedule\n * */\n function _stakeOptionalTokenTransfer(\n address sender,\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee,\n bool timeAdjusted,\n bool transferToken\n ) internal {\n require(amount > 0, \"amount needs to be bigger than 0\"); // S01\n\n if (!timeAdjusted) {\n until = _timestampToLockDate(until);\n }\n require(\n until > block.timestamp,\n \"Staking::_timestampToLockDate: staking period too short\"\n ); // S02\n\n /// @dev Stake for the sender if not specified otherwise.\n if (stakeFor == address(0)) {\n stakeFor = sender;\n }\n // must wait a block before staking again for that same deadline\n _notSameBlockAsStakingCheckpoint(until, stakeFor);\n\n /// @dev Delegate for stakeFor if not specified otherwise.\n if (delegatee == address(0)) {\n delegatee = stakeFor;\n }\n\n /// @dev Do not stake longer than the max duration.\n if (!timeAdjusted) {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n }\n\n uint96 previousBalance = _currentBalance(stakeFor, until);\n\n /// @dev Increase stake.\n _increaseStake(sender, amount, stakeFor, until, transferToken);\n\n // @dev Previous version wasn't working properly for the following case:\n //\t\tdelegate checkpoint wasn't updating for the second and next stakes for the same date\n //\t\tif first stake was withdrawn completely and stake was delegated to the staker\n //\t\t(no delegation to another address).\n address previousDelegatee = delegates[stakeFor][until];\n\n if (previousDelegatee != delegatee) {\n // @dev only the user that stakes for himself is allowed to delegate VP to another address\n // which works with vesting stakes and prevents vulnerability of delegating VP to an arbitrary address from\n // any address\n\n if (delegatee != stakeFor) {\n require(\n stakeFor == sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n } else if (sender != stakeFor && previousDelegatee != address(0)) {\n require(stakeFor == sender, \"Only sender is allowed to change delegatee\");\n }\n\n /// @dev Update delegatee.\n delegates[stakeFor][until] = delegatee;\n\n /// @dev Decrease stake on previous balance for previous delegatee.\n _decreaseDelegateStake(previousDelegatee, until, previousBalance);\n\n /// @dev Add previousBalance to amount.\n amount = add96(previousBalance, amount, \"add amounts failed\");\n }\n\n /// @dev Increase stake.\n _increaseDelegateStake(delegatee, until, amount);\n emit DelegateChanged(stakeFor, until, previousDelegatee, delegatee);\n }\n\n /**\n * @notice Extend the staking duration until the specified date.\n * @param previousLock The old unlocking timestamp.\n * @param until The new unlocking timestamp in seconds.\n * */\n function extendStakingDuration(uint256 previousLock, uint256 until)\n external\n whenNotPaused\n whenNotFrozen\n {\n previousLock = _timestampToLockDate(previousLock);\n until = _timestampToLockDate(until);\n\n _notSameBlockAsStakingCheckpoint(previousLock, msg.sender);\n\n /// @dev Do not exceed the max duration, no overflow possible.\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n if (until > latest) until = latest;\n\n require(previousLock < until, \"must increase staking duration\"); // S04\n\n /// @dev Update checkpoints.\n /// @dev TODO James: Can reading stake at block.number -1 cause trouble with multiple tx in a block?\n uint96 amount = _getPriorUserStakeByDate(msg.sender, previousLock, block.number - 1);\n require(amount > 0, \"no stakes till the prev lock date\"); // S05\n _decreaseUserStake(msg.sender, previousLock, amount);\n _increaseUserStake(msg.sender, until, amount);\n\n if (_isVestingContract(msg.sender)) {\n _decreaseVestingStake(previousLock, amount);\n _increaseVestingStake(until, amount);\n }\n\n _decreaseDailyStake(previousLock, amount);\n _increaseDailyStake(until, amount);\n\n /// @dev Delegate might change: if there is already a delegate set for the until date, it will remain the delegate for this position\n address delegateFrom = delegates[msg.sender][previousLock];\n delegates[msg.sender][previousLock] = address(0); //the previousLock delegates nullifying before reading that form `until` guards in case delegateTo == until\n address delegateTo = delegates[msg.sender][until];\n if (delegateTo == address(0)) {\n delegateTo = delegateFrom;\n delegates[msg.sender][until] = delegateFrom;\n }\n _decreaseDelegateStake(delegateFrom, previousLock, amount);\n _increaseDelegateStake(delegateTo, until, amount);\n\n emit ExtendedStakingDuration(msg.sender, previousLock, until, amount);\n }\n\n /**\n * @notice Send sender's tokens to this contract and update its staked balance.\n * @param sender The sender of the tokens.\n * @param amount The number of tokens to send.\n * @param stakeFor The beneficiary whose stake will be increased.\n * @param until The date until which the tokens will be staked.\n * @param transferToken if false - token transfer should be handled separately\n * */\n function _increaseStake(\n address sender,\n uint96 amount,\n address stakeFor,\n uint256 until,\n bool transferToken\n ) internal {\n /// @dev Retrieve the SOV tokens.\n if (transferToken)\n require(\n SOVToken.transferFrom(sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // IS10\n\n /// @dev Increase staked balance.\n uint96 balance = _currentBalance(stakeFor, until);\n balance = add96(balance, amount, \"increaseStake: overflow\"); // IS20\n\n /// @dev Update checkpoints.\n _increaseDailyStake(until, amount);\n _increaseUserStake(stakeFor, until, amount);\n\n if (_isVestingContract(stakeFor)) _increaseVestingStake(until, amount);\n\n emit TokensStaked(stakeFor, amount, until, balance);\n }\n\n /**\n * @dev DO NOT USE this misspelled function. Use stakeBySchedule function instead.\n * This function cannot be deprecated while we have non-upgradeable vesting contracts.\n * */\n function stakesBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external whenNotPaused whenNotFrozen {\n _stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param amount The amount of tokens to stake.\n * @param cliff The time interval to the first withdraw.\n * @param duration The staking duration.\n * @param intervalLength The length of each staking interval when cliff passed.\n * @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.\n * @param delegatee The address of the delegatee or 0x0 if there is none.\n * */\n function _stakeBySchedule(\n uint256 amount,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) internal {\n require(amount > 0, \"Invalid amount\");\n require(duration <= MAX_DURATION, \"Invalid duration\");\n require(intervalLength > 0, \"Invalid interval length\");\n require(intervalLength % TWO_WEEKS == 0, \"Invalid interval length\");\n if (delegatee != stakeFor && delegatee != address(0)) {\n require(\n stakeFor == msg.sender,\n \"Only stakeFor account is allowed to change delegatee\"\n );\n }\n /**\n * @dev Stake them until lock dates according to the vesting schedule.\n * Note: because staking is only possible in periods of 2 weeks,\n * the total duration might end up a bit shorter than specified\n * depending on the date of staking.\n * */\n uint256 start = _timestampToLockDate(block.timestamp + cliff);\n uint256 end = _timestampToLockDate(block.timestamp + duration);\n require(start <= end, \"Invalid schedule\");\n uint256 numIntervals;\n if (start < end) {\n numIntervals = (end - start) / intervalLength + 1;\n } else {\n numIntervals = 1;\n }\n uint256 stakedPerInterval = amount / numIntervals;\n\n /// @dev transferring total SOV amount before staking\n require(\n SOVToken.transferFrom(msg.sender, address(this), amount),\n \"Should transfer tokens successfully\"\n ); // SS10\n /// @dev stakedPerInterval might lose some dust on rounding. Add it to the first staking date.\n if (numIntervals >= 1) {\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(amount - stakedPerInterval * (numIntervals - 1)),\n start,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n /// @dev Stake the rest in 4 week intervals.\n for (uint256 i = start + intervalLength; i <= end; i += intervalLength) {\n /// @dev Stakes for itself, delegates to the owner.\n _notSameBlockAsStakingCheckpoint(i, stakeFor); // must wait a block before staking again for that same deadline\n _stakeOptionalTokenTransfer(\n msg.sender,\n uint96(stakedPerInterval),\n i,\n stakeFor,\n delegatee,\n true,\n false\n );\n }\n }\n\n /**\n * @notice Get the number of staked tokens held by the user account.\n * @dev Iterate checkpoints adding up stakes.\n * @param account The address of the account to get the balance of.\n * @return The number of tokens held.\n * */\n function balanceOf(address account) external view returns (uint96 balance) {\n for (uint256 i = kickoffTS; i <= block.timestamp + MAX_DURATION; i += TWO_WEEKS) {\n balance = add96(balance, _currentBalance(account, i), \"Staking::balanceOf: overflow\"); // S12\n }\n }\n\n /**\n * @notice Get the current number of tokens staked for a day.\n * @param lockedTS The timestamp to get the staked tokens for.\n * */\n function getCurrentStakedUntil(uint256 lockedTS) external view returns (uint96) {\n uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\n return nCheckpoints > 0 ? totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake : 0;\n }\n\n /**\n * @notice Get list of stakes for a user account.\n * @param account The address to get stakes.\n * @return The arrays of dates and stakes.\n * */\n function getStakes(address account)\n external\n view\n returns (uint256[] memory dates, uint96[] memory stakes)\n {\n uint256 latest = _timestampToLockDate(block.timestamp + MAX_DURATION);\n\n /// @dev Calculate stakes.\n uint256 count = 0;\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n if (_currentBalance(account, i) > 0) {\n count++;\n }\n }\n dates = new uint256[](count);\n stakes = new uint96[](count);\n\n /// @dev We need to iterate from first possible stake date after deployment to the latest from current time.\n uint256 j = 0;\n for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\n uint96 balance = _currentBalance(account, i);\n if (balance > 0) {\n dates[j] = i;\n stakes[j] = balance;\n j++;\n }\n }\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOVToken);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeWithApproval.selector;\n return selectors;\n }\n\n /**\n * @notice Unstaking is possible every 2 weeks only. This means, to\n * calculate the key value for the staking checkpoints, we need to\n * map the intended timestamp to the closest available date.\n * @param timestamp The unlocking timestamp.\n * @return The actual unlocking date (might be up to 2 weeks shorter than intended).\n * */\n function timestampToLockDate(uint256 timestamp) external view returns (uint256) {\n return _timestampToLockDate(timestamp);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](10);\n functionsList[0] = this.stake.selector;\n functionsList[1] = this.stakeWithApproval.selector;\n functionsList[2] = this.extendStakingDuration.selector;\n functionsList[3] = this.stakesBySchedule.selector;\n functionsList[4] = this.stakeBySchedule.selector;\n functionsList[5] = this.balanceOf.selector;\n functionsList[6] = this.getCurrentStakedUntil.selector;\n functionsList[7] = this.getStakes.selector;\n functionsList[8] = this.timestampToLockDate.selector;\n functionsList[9] = this.receiveApproval.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingStorageModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"./shared/StakingStorageShared.sol\";\n\n/**\n * @title Staking Storage Module\n * @notice Provides getters for public storage variables\n **/\ncontract StakingStorageModule is IFunctionsList, StakingStorageShared {\n function getStorageDefaultWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n /// @notice The maximum duration to stake tokens\n /// @return MAX_DURATION to stake tokens\n function getStorageMaxDurationToStakeTokens() external pure returns (uint256) {\n return MAX_DURATION;\n }\n\n /// @notice The maximum possible voting weight before adding +1 (actually 10, but need 9 for computation).\n function getStorageMaxVotingWeight() external pure returns (uint256) {\n return uint256(MAX_VOTING_WEIGHT);\n }\n\n /// @notice weight is multiplied with this factor (for allowing decimals, like 1.2x).\n /// @dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\n function getStorageWeightFactor() external pure returns (uint256) {\n return uint256(WEIGHT_FACTOR);\n }\n\n /// @notice Default weight scaling.\n function getStorageDefaulWeightScaling() external pure returns (uint256) {\n return uint256(DEFAULT_WEIGHT_SCALING);\n }\n\n function getStorageRangeForWeightScaling()\n external\n pure\n returns (uint256 minWeightScaling, uint256 maxWeightScaling)\n {\n return (uint256(MIN_WEIGHT_SCALING), uint256(MAX_WEIGHT_SCALING));\n }\n\n /// @notice The EIP-712 typehash for the contract's domain.\n function getStorageDomainTypehash() external pure returns (uint256) {\n return uint256(DOMAIN_TYPEHASH);\n }\n\n /// @notice The EIP-712 typehash for the delegation struct used by the contract.\n function getStorageDelegationTypehash() external pure returns (uint256) {\n return uint256(DELEGATION_TYPEHASH);\n }\n\n function getStorageName() external view returns (string memory) {\n return name;\n }\n\n /**\n * @notice Max iteration for direct withdrawal from staking to prevent out of gas issue.\n *\n * @return max iteration value.\n */\n function getMaxVestingWithdrawIterations() public view returns (uint256) {\n return maxVestingWithdrawIterations;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](32);\n functionsList[0] = this.getStorageMaxDurationToStakeTokens.selector;\n functionsList[1] = this.getStorageMaxVotingWeight.selector;\n functionsList[2] = this.getStorageWeightFactor.selector;\n functionsList[3] = this.getStorageDefaulWeightScaling.selector;\n functionsList[4] = this.getStorageRangeForWeightScaling.selector;\n functionsList[5] = this.getStorageDomainTypehash.selector;\n functionsList[6] = this.getStorageDelegationTypehash.selector;\n functionsList[7] = this.getStorageName.selector;\n functionsList[8] = this.kickoffTS.selector;\n functionsList[9] = this.SOVToken.selector;\n functionsList[10] = this.delegates.selector;\n functionsList[11] = this.allUnlocked.selector;\n functionsList[12] = this.newStakingContract.selector;\n functionsList[13] = this.totalStakingCheckpoints.selector;\n functionsList[14] = this.numTotalStakingCheckpoints.selector;\n functionsList[15] = this.delegateStakingCheckpoints.selector;\n functionsList[16] = this.numDelegateStakingCheckpoints.selector;\n functionsList[17] = this.userStakingCheckpoints.selector;\n functionsList[18] = this.numUserStakingCheckpoints.selector;\n functionsList[19] = this.nonces.selector;\n functionsList[20] = this.feeSharing.selector;\n functionsList[21] = this.weightScaling.selector;\n functionsList[22] = this.vestingWhitelist.selector;\n functionsList[23] = this.admins.selector;\n functionsList[24] = this.vestingCodeHashes.selector;\n functionsList[25] = this.vestingCheckpoints.selector;\n functionsList[26] = this.numVestingCheckpoints.selector;\n functionsList[27] = this.vestingRegistryLogic.selector;\n functionsList[28] = this.pausers.selector;\n functionsList[29] = this.paused.selector;\n functionsList[30] = this.frozen.selector;\n functionsList[31] = this.getMaxVestingWithdrawIterations.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingVestingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Staking Vesting Module contract\n * @notice Implements interaction with Vesting functionality: vesting registry, vesting staking\n * */\ncontract StakingVestingModule is IFunctionsList, StakingShared {\n event ContractCodeHashAdded(bytes32 hash);\n event ContractCodeHashRemoved(bytes32 hash);\n event VestingStakeSet(uint256 lockedTS, uint96 value);\n\n /**\n * @notice sets vesting registry\n * @param _vestingRegistryProxy the address of vesting registry proxy contract\n * @dev _vestingRegistryProxy can be set to 0 as this function can be reused by\n * various other functionalities without the necessity of linking it with Vesting Registry\n */\n function setVestingRegistry(address _vestingRegistryProxy) external onlyOwner whenNotFrozen {\n vestingRegistryLogic = IVestingRegistry(_vestingRegistryProxy);\n }\n\n /**\n * @notice Sets the users' vesting stakes for a giving lock dates and writes checkpoints.\n * @param lockedDates The arrays of lock dates.\n * @param values The array of values to add to the staked balance.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function setVestingStakes(uint256[] calldata lockedDates, uint96[] calldata values)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(lockedDates.length == values.length, \"arrays mismatch\"); // WS05\n\n uint256 length = lockedDates.length;\n for (uint256 i = 0; i < length; i++) {\n _setVestingStake(lockedDates[i], values[i]);\n }\n }\n\n /**\n * @notice Sets the users' vesting stake for a giving lock date and writes a checkpoint.\n * @param lockedTS The lock date.\n * @param value The value to be set.\n * TODO: remove - it was designed as a disposable function to initialize vesting checkpoints\n */\n function _setVestingStake(uint256 lockedTS, uint96 value) internal {\n require(\n lockedTS > kickoffTS,\n \"Invalid lock dates: must greater than contract creation timestamp\"\n );\n\n // locked date must be multiples of 14 days / TWO_WEEKS\n require(\n (lockedTS - kickoffTS) % TWO_WEEKS == 0,\n \"Invalid lock dates: not multiples of 14 days\"\n );\n\n // locked date must not exceed the MAX_DURATION\n if (lockedTS > block.timestamp) {\n require(\n lockedTS - block.timestamp <= MAX_DURATION,\n \"Invalid lock dates: exceed max duration\"\n );\n }\n\n // the value must not exceed the total staked at the given locked date\n uint32 nStakeCheckpoints = numTotalStakingCheckpoints[lockedTS];\n uint96 totalStaked = totalStakingCheckpoints[lockedTS][nStakeCheckpoints - 1].stake;\n require(\n value <= totalStaked,\n \"Invalid stake amount: greater than the total staked for given date\"\n );\n\n uint32 nCheckpoints = numVestingCheckpoints[lockedTS];\n uint32 blockNumber;\n\n Checkpoint memory recentCP = vestingCheckpoints[lockedTS][nCheckpoints - 1];\n if (nCheckpoints == 0) blockNumber = uint32(block.number) - 1;\n else blockNumber = recentCP.fromBlock + 1;\n\n vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, value);\n numVestingCheckpoints[lockedTS] = nCheckpoints + 1;\n\n emit VestingStakeSet(lockedTS, value);\n }\n\n /**\n * @notice Determine the prior number of stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param account The address of the account to check.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorUserStakeByDate(\n address account,\n uint256 date,\n uint256 blockNumber\n ) external view returns (uint96) {\n uint96 priorStake = _getPriorUserStakeByDate(account, date, blockNumber);\n // @dev we need to modify function in order to workaround issue with Vesting.withdrawTokens:\n //\t\treturn 1 instead of 0 if message sender is a contract.\n if (priorStake == 0 && _isVestingContract(msg.sender)) {\n priorStake = 1;\n }\n return priorStake;\n }\n\n /*************************** Weighted Vesting Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted vested amount for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n * TODO: WeightedStaking::getPriorVestingWeightedStake is using the variable name \"votes\"\n * to add up token stake, and that could be misleading.\n *\n * @param blockNumber The block number to get the vote balance at.\n * @param date The staking date to compute the power for.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorVestingWeightedStake(uint256 blockNumber, uint256 date)\n external\n view\n returns (uint96 votes)\n {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedVestingStakeByDate(i, start, blockNumber);\n if (weightedStake > 0) {\n votes = add96(votes, weightedStake, \"overflow on total weight\"); // WS15\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n power = _weightedVestingStakeByDate(date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function _weightedVestingStakeByDate(\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorVestingStakeByDate(date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul oveflow\") / WEIGHT_FACTOR; // WS16\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * certain lock date as of a block number.\n * @dev Block number must be a finalized block or else this function\n * will revert to prevent misinformation.\n * @param date The lock date. Adjusted to the next valid lock date, if necessary.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n external\n view\n returns (uint96)\n {\n date = _adjustDateForOrigin(date);\n return _getPriorVestingStakeByDate(date, blockNumber);\n }\n\n /**\n * @notice Determine the prior number of vested stake for an account until a\n * \t\tcertain lock date as of a block number.\n * @dev All functions of Staking contract use this internal version,\n * \t\twe need to modify public function in order to workaround issue with Vesting.withdrawTokens:\n * return 1 instead of 0 if message sender is a contract.\n * @param date The lock date.\n * @param blockNumber The block number to get the vote balance at.\n * @return The number of votes the account had as of the given block.\n * */\n function _getPriorVestingStakeByDate(uint256 date, uint256 blockNumber)\n internal\n view\n returns (uint96)\n {\n require(blockNumber < _getCurrentBlockNumber(), \"not determined\"); // WS17\n\n uint32 nCheckpoints = numVestingCheckpoints[date];\n if (nCheckpoints == 0) {\n return 0;\n }\n\n /// @dev First check most recent balance.\n if (vestingCheckpoints[date][nCheckpoints - 1].fromBlock <= blockNumber) {\n return vestingCheckpoints[date][nCheckpoints - 1].stake;\n }\n\n /// @dev Next check implicit zero balance.\n if (vestingCheckpoints[date][0].fromBlock > blockNumber) {\n return 0;\n }\n\n uint32 lower = 0;\n uint32 upper = nCheckpoints - 1;\n while (upper > lower) {\n uint32 center = upper - (upper - lower) / 2; /// @dev ceil, avoiding overflow.\n Checkpoint memory cp = vestingCheckpoints[date][center];\n if (cp.fromBlock == blockNumber) {\n return cp.stake;\n } else if (cp.fromBlock < blockNumber) {\n lower = center;\n } else {\n upper = center - 1;\n }\n }\n return vestingCheckpoints[date][lower].stake;\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) external onlyAuthorized whenNotFrozen {\n bytes32 codeHash = _getCodeHash(vesting);\n require(vestingCodeHashes[codeHash], \"not a registered vesting code hash\");\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) external view returns (bool) {\n bool isVesting;\n bytes32 codeHash = _getCodeHash(stakerAddress);\n if (address(vestingRegistryLogic) != address(0)) {\n isVesting = vestingRegistryLogic.isVestingAddress(stakerAddress);\n }\n\n if (isVesting) return true;\n if (vestingCodeHashes[codeHash]) return true;\n return false;\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](9);\n functionsList[0] = this.setVestingRegistry.selector;\n functionsList[1] = this.setVestingStakes.selector;\n functionsList[2] = this.getPriorUserStakeByDate.selector;\n functionsList[3] = this.getPriorVestingWeightedStake.selector;\n functionsList[4] = this.getPriorVestingStakeByDate.selector;\n functionsList[5] = this.addContractCodeHash.selector;\n functionsList[6] = this.removeContractCodeHash.selector;\n functionsList[7] = this.isVestingContract.selector;\n functionsList[8] = this.weightedVestingStakeByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/StakingWithdrawModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"../../../rsk/RSKAddrValidator.sol\";\nimport \"../../Vesting/ITeamVesting.sol\";\nimport \"../../Vesting/IVesting.sol\";\nimport \"./shared/StakingShared.sol\";\n\n/**\n * @title Staking withdrawal functionality module\n **/\ncontract StakingWithdrawModule is IFunctionsList, StakingShared, CheckpointsShared {\n using SafeMath for uint256;\n\n event MaxVestingWithdrawIterationsUpdated(uint256 oldMaxIterations, uint256 newMaxIterations);\n\n /// @dev Struct for direct withdraw function -- to avoid stack too deep issue\n struct VestingConfig {\n address vestingAddress;\n uint256 startDate;\n uint256 endDate;\n uint256 cliff;\n uint256 duration;\n address tokenOwner;\n }\n\n /// @notice An event emitted when staked tokens get withdrawn.\n event StakingWithdrawn(\n address indexed staker,\n uint256 amount,\n uint256 until,\n address indexed receiver,\n bool isGovernance\n );\n\n /// @notice An event emitted when vesting tokens get withdrawn.\n event VestingTokensWithdrawn(address vesting, address receiver);\n\n /// @notice An event emitted when the owner unlocks all tokens.\n event TokensUnlocked(uint256 amount);\n\n /**\n * @notice Withdraw the given amount of tokens if they are unlocked.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev If until is not a valid lock date, the next lock date after until is used.\n * */\n function withdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n // adjust until here to avoid adjusting multiple times, and to make sure an adjusted date is passed to\n // _notSameBlockAsStakingCheckpoint\n until = _adjustDateForOrigin(until);\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, false);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe need to check block.timestamp here\n _withdrawNext(until, receiver, false);\n }\n\n /**\n * @notice Governance withdraw vesting directly through staking contract.\n * This direct withdraw vesting solves the out of gas issue when there are too many iterations when withdrawing.\n * This function only allows cancelling vesting contract of the TeamVesting type.\n *\n * @param vesting The vesting address.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n */\n function cancelTeamVesting(\n address vesting,\n address receiver,\n uint256 startFrom\n ) external onlyAuthorized whenNotFrozen {\n /// require the caller only for team vesting contract.\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n _cancelTeamVesting(vesting, receiver, startFrom);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param _vesting The vesting address.\n * @param _receiver The receiving address.\n * @param _startFrom The start value for the iterations.\n * or just unlocked tokens (false).\n *\n * @return nextStartFrom is a timestamp to be used for next withdrawal.\n * @return notCompleted flag that indicates that the cancel team vesting is not completely done.\n * */\n function _cancelTeamVesting(\n address _vesting,\n address _receiver,\n uint256 _startFrom\n ) private returns (uint256 nextStartFrom, bool notCompleted) {\n require(_receiver != address(0), \"receiver address invalid\");\n\n ITeamVesting teamVesting = ITeamVesting(_vesting);\n\n VestingConfig memory vestingConfig =\n VestingConfig(\n _vesting,\n teamVesting.startDate(),\n teamVesting.endDate(),\n teamVesting.cliff(),\n teamVesting.duration(),\n teamVesting.tokenOwner()\n );\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them, as long as the itrations less than maxVestingWithdrawIterations.\n uint256 end = vestingConfig.endDate;\n\n uint256 defaultStart = vestingConfig.startDate + vestingConfig.cliff;\n\n _startFrom = _startFrom >= defaultStart ? _startFrom : defaultStart;\n\n /// @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 totalIterationValue =\n (_startFrom + (TWO_WEEKS * (maxVestingWithdrawIterations - 1)));\n uint256 adjustedEnd = end < totalIterationValue ? end : totalIterationValue;\n\n /// @dev Withdraw for each unlocked position.\n for (uint256 i = _startFrom; i <= adjustedEnd; i += TWO_WEEKS) {\n /// @dev Read amount to withdraw.\n uint96 tempStake = _getPriorUserStakeByDate(_vesting, i, block.number - 1);\n\n if (tempStake > 0) {\n /// @dev do governance direct withdraw for team vesting\n _withdrawFromTeamVesting(tempStake, i, _receiver, vestingConfig);\n }\n }\n\n if (adjustedEnd < end) {\n nextStartFrom = adjustedEnd + TWO_WEEKS;\n emit TeamVestingPartiallyCancelled(msg.sender, _receiver, nextStartFrom);\n return (nextStartFrom, true);\n } else {\n emit TeamVestingCancelled(msg.sender, _receiver);\n return (end, false);\n }\n }\n\n /**\n * @notice Send user' staked tokens to a receiver taking into account punishments.\n * Sovryn encourages long-term commitment and thinking. When/if you unstake before\n * the end of the staking period, a percentage of the original staking amount will\n * be slashed. This amount is also added to the reward pool and is distributed\n * between all other stakers.\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * Needs to be adjusted to the next valid lock date before calling this function.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdraw(\n uint96 amount,\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n // @dev it's very unlikely some one will have 1/10**18 SOV staked in Vesting contract\n //\t\tthis check is a part of workaround for Vesting.withdrawTokens issue\n if (amount == 1 && _isVestingContract(msg.sender)) {\n return;\n }\n _validateWithdrawParams(msg.sender, amount, until);\n\n /// @dev Determine the receiver.\n if (receiver == address(0)) receiver = msg.sender;\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(msg.sender, until, amount);\n if (_isVestingContract(msg.sender)) _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[msg.sender][until], until, amount);\n\n /// @dev Early unstaking should be punished.\n if (block.timestamp < until && !allUnlocked && !isGovernance) {\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n amount -= punishedAmount;\n\n /// @dev punishedAmount can be 0 if block.timestamp are very close to 'until'\n if (punishedAmount > 0) {\n require(address(feeSharing) != address(0), \"FeeSharing address wasn't set\"); // S08\n /// @dev Move punished amount to fee sharing.\n /// @dev Approve transfer here and let feeSharing do transfer and write checkpoint.\n SOVToken.approve(address(feeSharing), punishedAmount);\n feeSharing.transferTokens(address(SOVToken), punishedAmount);\n }\n }\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(msg.sender, amount, until, receiver, isGovernance);\n }\n\n /**\n * @notice Send user' staked tokens to a receiver.\n * This function is dedicated only for direct withdrawal from staking contract.\n * Currently only being used by cancelTeamVesting()\n *\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender.\n * @param vestingConfig The vesting config.\n * @dev VestingConfig struct intended to avoid stack too deep issue, and it contains this properties:\n address vestingAddress; // vesting contract address\n uint256 startDate; //start date of vesting\n uint256 endDate; // end date of vesting\n uint256 cliff; // after this time period the tokens begin to unlock\n uint256 duration; // after this period all the tokens will be unlocked\n address tokenOwner; // owner of the vested tokens\n * */\n function _withdrawFromTeamVesting(\n uint96 amount,\n uint256 until,\n address receiver,\n VestingConfig memory vestingConfig\n ) internal {\n address vesting = vestingConfig.vestingAddress;\n\n until = _timestampToLockDate(until);\n _validateWithdrawParams(vesting, amount, until);\n\n /// @dev Update the checkpoints.\n _decreaseDailyStake(until, amount);\n _decreaseUserStake(vesting, until, amount);\n\n _decreaseVestingStake(until, amount);\n _decreaseDelegateStake(delegates[vesting][until], until, amount);\n\n /// @dev transferFrom\n bool success = SOVToken.transfer(receiver, amount);\n require(success, \"Token transfer failed\"); // S09\n\n emit StakingWithdrawn(vesting, amount, until, receiver, true);\n }\n\n // @dev withdraws tokens for lock date 2 weeks later than given lock date\n function _withdrawNext(\n uint256 until,\n address receiver,\n bool isGovernance\n ) internal {\n if (_isVestingContract(msg.sender)) {\n // nextLock needs to be adjusted to the next valid lock date to make sure we don't accidentally\n // withdraw stakes that are in the future and would get slashed (if until is not\n // a valid lock date). but until is already handled in the withdraw function\n uint256 nextLock = until.add(TWO_WEEKS);\n if (isGovernance || block.timestamp >= nextLock) {\n uint96 stakes = _getPriorUserStakeByDate(msg.sender, nextLock, block.number - 1);\n if (stakes > 0) {\n _withdraw(stakes, nextLock, receiver, isGovernance);\n }\n }\n }\n }\n\n /**\n * @notice Get available and punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked. Adjusted to the next valid lock date, if necessary.\n * @return Amount to withraw and penalty amount\n * */\n function getWithdrawAmounts(uint96 amount, uint256 until)\n external\n view\n returns (uint96, uint96)\n {\n until = _adjustDateForOrigin(until);\n _validateWithdrawParams(msg.sender, amount, until);\n uint96 punishedAmount = _getPunishedAmount(amount, until);\n return (amount - punishedAmount, punishedAmount);\n }\n\n /**\n * @notice Get punished amount for withdrawing.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _getPunishedAmount(uint96 amount, uint256 until) internal view returns (uint96) {\n uint256 date = _timestampToLockDate(block.timestamp);\n uint96 weight = _computeWeightByDate(until, date); /// @dev (10 - 1) * WEIGHT_FACTOR\n weight = weight * weightScaling;\n return (amount * weight) / WEIGHT_FACTOR / 100;\n }\n\n /**\n * @notice Validate withdraw parameters.\n * @param account Address to be validated.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * */\n function _validateWithdrawParams(\n address account,\n uint96 amount,\n uint256 until\n ) internal view {\n require(amount > 0, \"Amount of tokens to withdraw must be > 0\"); // S10\n uint96 balance = _getPriorUserStakeByDate(account, until, block.number - 1);\n require(amount <= balance, \"Staking::withdraw: not enough balance\"); // S11\n }\n\n /**\n * @notice Allow the owner to unlock all tokens in case the staking contract\n * is going to be replaced\n * Note: Not reversible on purpose. once unlocked, everything is unlocked.\n * The owner should not be able to just quickly unlock to withdraw his own\n * tokens and lock again.\n * @dev Last resort.\n * */\n function unlockAllTokens() external onlyOwner whenNotFrozen {\n allUnlocked = true;\n emit TokensUnlocked(SOVToken.balanceOf(address(this)));\n }\n\n /**\n * @dev set max withdraw iterations.\n *\n * @param newMaxIterations new max iterations value.\n */\n function setMaxVestingWithdrawIterations(uint256 newMaxIterations)\n external\n onlyAuthorized\n whenNotFrozen\n {\n require(newMaxIterations > 0, \"Invalid max iterations\");\n emit MaxVestingWithdrawIterationsUpdated(maxVestingWithdrawIterations, newMaxIterations);\n maxVestingWithdrawIterations = newMaxIterations;\n }\n\n /**\n * @notice Withdraw tokens for vesting contract.\n * @param vesting The address of Vesting contract.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev This function is dedicated only to support backward compatibility for sovryn ecosystem that has been implementing this staking contract.\n * @dev Sovryn protocol will use the cancelTeamVesting function for the withdrawal moving forward.\n * https://github.com/DistributedCollective/Sovryn-smart-contracts/blob/4bbfe5bd0311ca71e4ef0e3af810d3791d8e4061/contracts/governance/Staking/modules/StakingWithdrawModule.sol#L78\n * */\n function governanceWithdrawVesting(address vesting, address receiver)\n public\n onlyAuthorized\n whenNotFrozen\n {\n require(vestingRegistryLogic.isTeamVesting(vesting), \"Only team vesting allowed\");\n\n ITeamVesting teamVesting = ITeamVesting(vesting);\n uint256 teamVestingStartDate = teamVesting.startDate();\n uint256 teamVestingCliff = teamVesting.cliff();\n\n uint256 nextStartFrom = teamVestingStartDate + teamVestingCliff;\n bool withdrawFlag = true;\n\n bool notCompleted;\n\n /**\n * The withdrawal is limited to certain iterations (set in maxVestingWithdrawIterations), so in order to withdraw all, we need to iterate until it is fully withdrawn.\n */\n while (withdrawFlag) {\n /**\n * notCompleted is the flag whether the withdrawal is fully withdrawn or not.\n * As long as the notCompleted is true, we will keep the iteration using the nextStartFrom.\n */\n (nextStartFrom, notCompleted) = _cancelTeamVesting(vesting, receiver, nextStartFrom);\n withdrawFlag = notCompleted ? true : false;\n }\n\n emit VestingTokensWithdrawn(vesting, receiver);\n }\n\n /**\n * @notice Withdraw the given amount of tokens.\n * @param amount The number of tokens to withdraw.\n * @param until The date until which the tokens were staked.\n * @param receiver The receiver of the tokens. If not specified, send to the msg.sender\n * @dev Can be invoked only by whitelisted contract passed to governanceWithdrawVesting\n * */\n function governanceWithdraw(\n uint96 amount,\n uint256 until,\n address receiver\n ) external whenNotFrozen {\n require(vestingWhitelist[msg.sender], \"unauthorized\"); // S07\n\n _notSameBlockAsStakingCheckpoint(until, msg.sender);\n\n _withdraw(amount, until, receiver, true);\n // @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract\n //\t\twe don't need to check block.timestamp here\n _withdrawNext(until, receiver, true);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.withdraw.selector;\n functionsList[1] = this.cancelTeamVesting.selector;\n functionsList[2] = this.getWithdrawAmounts.selector;\n functionsList[3] = this.unlockAllTokens.selector;\n functionsList[4] = this.setMaxVestingWithdrawIterations.selector;\n functionsList[5] = this.governanceWithdraw.selector;\n functionsList[6] = this.governanceWithdrawVesting.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/modules/WeightedStakingModule.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./shared/CheckpointsShared.sol\";\nimport \"./shared/StakingShared.sol\";\nimport \"../../../proxy/modules/interfaces/IFunctionsList.sol\";\n\n/**\n * @title Weighted Staking module contract.\n * @notice Implements getters for weighted staking functionality\n * */\ncontract WeightedStakingModule is IFunctionsList, StakingShared, CheckpointsShared {\n /*************************** User Weighted Stake computation for fee sharing *******************************/\n\n /**\n * @notice Determine the prior weighted stake for an account as of a block number.\n * Iterate through checkpoints adding up voting power.\n * @dev Block number must be a finalized block or else this function will\n * revert to prevent misinformation.\n * Used for fee sharing, not voting.\n *\n * @param account The address of the account to check.\n * @param blockNumber The block number to get the vote balance at.\n * @param date The start date/timestamp from which to calculate the weighted stake.\n * @return The weighted stake the account had as of the given block.\n * */\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96 priorWeightedStake) {\n return _getPriorWeightedStake(account, blockNumber, date);\n }\n\n function _getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) internal view returns (uint96 priorWeightedStake) {\n /// @dev If date is not an exact break point, start weight computation from the previous break point (alternative would be the next).\n uint256 start = _timestampToLockDate(date);\n uint256 end = start + MAX_DURATION;\n\n /// @dev Max 78 iterations.\n for (uint256 i = start; i <= end; i += TWO_WEEKS) {\n uint96 weightedStake = _weightedStakeByDate(account, i, start, blockNumber);\n if (weightedStake > 0) {\n priorWeightedStake = add96(\n priorWeightedStake,\n weightedStake,\n \"overflow on total weight calc\"\n ); // WS12\n }\n }\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for. Adjusted to the previous valid lock date, if necessary.\n * @param startDate The date for which we need to know the power of the stake. Adjusted to the previous valid lock date, if necessary.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power) {\n date = _timestampToLockDate(date);\n startDate = _timestampToLockDate(startDate);\n return _weightedStakeByDate(account, date, startDate, blockNumber);\n }\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The staking power.\n * */\n function _weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) internal view returns (uint96 power) {\n uint96 staked = _getPriorUserStakeByDate(account, date, blockNumber);\n if (staked > 0) {\n uint96 weight = _computeWeightByDate(date, startDate);\n power = mul96(staked, weight, \"mul overflow\") / WEIGHT_FACTOR; // WS13\n } else {\n power = 0;\n }\n }\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight)\n {\n return _computeWeightByDate(date, startDate);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](3);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/governance/Staking/SafeMath96.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n/**\n * @title SafeMath96 contract.\n * @notice Improved Solidity's arithmetic operations with added overflow checks.\n * @dev SafeMath96 uses uint96, unsigned integers of 96 bits length, so every\n * integer from 0 to 2^96-1 can be operated.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * SafeMath restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this contract instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n * */\ncontract SafeMath96 {\n function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {\n require(n < 2**32, errorMessage);\n return uint32(n);\n }\n\n function safe64(uint256 n, string memory errorMessage) internal pure returns (uint64) {\n require(n < 2**64, errorMessage);\n return uint64(n);\n }\n\n function safe96(uint256 n, string memory errorMessage) internal pure returns (uint96) {\n require(n < 2**96, errorMessage);\n return uint96(n);\n }\n\n /**\n * @notice Adds two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `+` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe addition a+b.\n * */\n function add96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n uint96 c = a + b;\n require(c >= a, errorMessage);\n return c;\n }\n\n /**\n * @notice Substracts two unsigned integers, reverting on underflow.\n * @dev Counterpart to Solidity's `-` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on underflow.\n * @return The safe substraction a-b.\n * */\n function sub96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n require(b <= a, errorMessage);\n return a - b;\n }\n\n /**\n * @notice Multiplies two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `*` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe product a*b.\n * */\n function mul96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n if (a == 0) {\n return 0;\n }\n\n uint96 c = a * b;\n require(c / a == b, errorMessage);\n\n return c;\n }\n\n /**\n * @notice Divides two unsigned integers, reverting on overflow.\n * @dev Counterpart to Solidity's `/` operator.\n * @param a First integer.\n * @param b Second integer.\n * @param errorMessage The revert message on overflow.\n * @return The safe division a/b.\n * */\n function div96(\n uint96 a,\n uint96 b,\n string memory errorMessage\n ) internal pure returns (uint96) {\n // Solidity only automatically asserts when dividing by 0\n require(b > 0, errorMessage);\n uint96 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n}\n" + }, + "contracts/governance/Staking/StakingProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./modules/shared/StakingStorageShared.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Staking Proxy contract.\n * @dev Staking contract should be upgradable, use UpgradableProxy.\n * StakingStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingProxy is StakingStorageShared, UpgradableProxy {\n /**\n * @notice Construct a new staking contract.\n * @param SOV The address of the SOV token address.\n */\n constructor(address SOV) public {\n SOVToken = IERC20(SOV);\n kickoffTS = block.timestamp;\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewards.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * @title Staking Rewards Contract.\n * @notice This is a trial incentive program.\n * In this, the SOV emitted and becoming liquid from the Adoption Fund could be utilized\n * to offset the higher APY's offered for Liquidity Mining events.\n * Vesting contract stakes are excluded from these rewards.\n * Only wallets which have staked previously liquid SOV are eligible for these rewards.\n * Tokenholders who stake their SOV receive staking rewards, a pro-rata share\n * of the revenue that the platform generates from various transaction fees\n * plus revenues from stakers who have a portion of their SOV slashed for\n * early unstaking.\n * */\ncontract StakingRewards is StakingRewardsStorage {\n using SafeMath for uint256;\n\n /// @notice Emitted when SOV is withdrawn\n /// @param receiver The address which recieves the SOV\n /// @param amount The amount withdrawn from the Smart Contract\n event RewardWithdrawn(address indexed receiver, uint256 amount);\n\n /**\n * @notice Replacement of constructor by initialize function for Upgradable Contracts\n * This function will be called only once by the owner.\n * @param _SOV SOV token address\n * @param _staking StakingProxy address should be passed\n * */\n function initialize(address _SOV, IStaking _staking) external onlyOwner {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n SOV = IERC20(_SOV);\n staking = _staking;\n startTime = staking.timestampToLockDate(block.timestamp);\n setMaxDuration(15 * TWO_WEEKS);\n deploymentBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Stops the current rewards program.\n * @dev All stakes existing on the contract at the point in time of\n * cancellation continue accruing rewards until the end of the staking\n * period being rewarded\n * */\n function stop() external onlyOwner {\n require(stopBlock == 0, \"Already stopped\");\n stopBlock = _getCurrentBlockNumber();\n }\n\n /**\n * @notice Collect rewards\n * @dev User calls this function to collect SOV staking rewards as per the SIP-0024 program.\n * The weighted stake is calculated using getPriorWeightedStake. Block number sent to the functon\n * must be a finalised block, hence we deduct 1 from the current block. User is only allowed to withdraw\n * after intervals of 14 days.\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * The issue is that we can only run for a max duration and if someone stakes for the\n * first time after the max duration is over, the reward will always return 0. Thus, we need to restart\n * from the duration that elapsed without generating rewards.\n * */\n function collectReward(uint256 restartTime) external {\n (uint256 withdrawalTime, uint256 amount) = getStakerCurrentReward(true, restartTime);\n require(withdrawalTime > 0 && amount > 0, \"no valid reward\");\n withdrawals[msg.sender] = withdrawalTime;\n _payReward(msg.sender, amount);\n }\n\n /**\n * @notice Withdraws all token from the contract by Multisig.\n * @param _receiverAddress The address where the tokens has to be transferred.\n */\n function withdrawTokensByOwner(address _receiverAddress) external onlyOwner {\n uint256 value = SOV.balanceOf(address(this));\n _transferSOV(_receiverAddress, value);\n }\n\n /**\n * @notice Changes average block time - based on blockchain\n * @dev If average block time significantly changes, we can update it here and use for block number calculation\n */\n function setAverageBlockTime(uint256 _averageBlockTime) external onlyOwner {\n averageBlockTime = _averageBlockTime;\n }\n\n /**\n * @notice This function computes the last staking checkpoint and calculates the corresponding\n * block number using the average block time which is then added to the mapping `checkpointBlockDetails`.\n */\n function setBlock() external {\n uint256 lastCheckpointTime = staking.timestampToLockDate(block.timestamp);\n _setBlock(lastCheckpointTime);\n }\n\n /**\n * @notice This function computes the block number using the average block time for a given historical\n * checkpoint which is added to the mapping `checkpointBlockDetails`.\n * @param _time Exact staking checkpoint time\n */\n function setHistoricalBlock(uint256 _time) external {\n _setBlock(_time);\n }\n\n /**\n * @notice Sets the max duration\n * @dev Rewards can be collected for a maximum duration at a time. This\n * is to avoid Block Gas Limit failures. Setting it zero would mean that it will loop\n * through the entire duration since the start of rewards program.\n * It should ideally be set to a value, for which the rewards can be easily processed.\n * @param _duration Max duration for which rewards can be collected at a go (in seconds)\n * */\n function setMaxDuration(uint256 _duration) public onlyOwner {\n maxDuration = _duration;\n }\n\n /**\n * @notice Internal function to calculate weighted stake\n * @dev If the rewards program is stopped, the user will still continue to\n * earn till the end of staking period based on the stop block.\n * @param _staker Staker address\n * @param _block Last finalised block\n * @param _date The date to compute prior weighted stakes\n * @return The weighted stake\n * */\n function _computeRewardForDate(\n address _staker,\n uint256 _block,\n uint256 _date\n ) internal view returns (uint256 weightedStake) {\n weightedStake = staking.getPriorWeightedStake(_staker, _block, _date);\n if (stopBlock > 0 && stopBlock < _block) {\n uint256 previousWeightedStake =\n staking.getPriorWeightedStake(_staker, stopBlock, _date);\n if (previousWeightedStake < weightedStake) {\n weightedStake = previousWeightedStake;\n }\n }\n }\n\n /**\n * @notice Internal function to pay rewards\n * @dev Base rate is annual, but we pay interest for 14 days,\n * which is 1/26 of one staking year (1092 days)\n * @param _staker User address\n * @param amount the reward amount\n * */\n function _payReward(address _staker, uint256 amount) internal {\n require(SOV.balanceOf(address(this)) >= amount, \"not enough funds to reward user\");\n claimedBalances[_staker] = claimedBalances[_staker].add(amount);\n _transferSOV(_staker, amount);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit RewardWithdrawn(_receiver, _amount);\n }\n\n /**\n * @notice Determine the current Block Number\n * @dev This is segregated from the _getPriorUserStakeByDate function to better test\n * advancing blocks functionality using Mock Contracts\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return block.number;\n }\n\n /**\n * @notice Internal function to calculate and set block\n * */\n function _setBlock(uint256 _checkpointTime) internal {\n uint256 currentTS = block.timestamp;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n require(checkpointBlockDetails[_checkpointTime] == 0, \"block number already set\");\n uint256 checkpointBlock =\n lastFinalisedBlock.sub(((currentTS.sub(_checkpointTime)).div(averageBlockTime)));\n checkpointBlockDetails[_checkpointTime] = checkpointBlock;\n }\n\n /**\n * @notice Get staker's current accumulated reward\n * @dev The collectReward() function internally calls this function to calculate reward amount\n * @param considerMaxDuration True: Runs for the maximum duration - used in tx not to run out of gas\n * False - to query total rewards\n * @param restartTime The time from which the staking rewards calculation shall restart.\n * @return The timestamp of last withdrawal\n * @return The accumulated reward\n */\n function getStakerCurrentReward(bool considerMaxDuration, uint256 restartTime)\n public\n view\n returns (uint256 lastWithdrawalInterval, uint256 amount)\n {\n uint256 weightedStake;\n uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;\n uint256 currentTS = block.timestamp;\n uint256 duration;\n address staker = msg.sender;\n uint256 lastWithdrawal = withdrawals[staker];\n\n uint256 lastStakingInterval = staking.timestampToLockDate(currentTS);\n lastWithdrawalInterval = lastWithdrawal > 0 ? lastWithdrawal : startTime;\n if (lastStakingInterval <= lastWithdrawalInterval) return (0, 0);\n /* Normally the restart time is 0. If this function returns a valid lastWithdrawalInterval\n\t\tand zero amount - that means there were no valid rewards for that period. So the new period must start\n\t\tfrom the end of the last interval or till the time no rewards are accumulated i.e. restartTime */\n if (restartTime >= lastWithdrawalInterval) {\n uint256 latestRestartTime = staking.timestampToLockDate(restartTime);\n lastWithdrawalInterval = latestRestartTime;\n }\n\n if (considerMaxDuration) {\n uint256 addedMaxDuration = lastWithdrawalInterval.add(maxDuration);\n duration = addedMaxDuration < currentTS\n ? staking.timestampToLockDate(addedMaxDuration)\n : lastStakingInterval;\n } else {\n duration = lastStakingInterval;\n }\n for (uint256 i = lastWithdrawalInterval; i < duration; i += TWO_WEEKS) {\n uint256 referenceBlock = checkpointBlockDetails[i];\n if (referenceBlock == 0) {\n referenceBlock = lastFinalisedBlock.sub(\n ((currentTS.sub(i)).div(averageBlockTime))\n );\n }\n if (referenceBlock < deploymentBlock) referenceBlock = deploymentBlock;\n weightedStake = weightedStake.add(_computeRewardForDate(staker, referenceBlock, i));\n }\n lastWithdrawalInterval = duration;\n amount = weightedStake.mul(BASE_RATE).div(DIVISOR);\n }\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StakingRewardsStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title StakingRewards Proxy contract.\n * @dev StakingRewards contract should be upgradable. Used UpgradableProxy.\n * StakingRewardsStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy with\n * the possibility of being enhanced and re-deployed.\n * */\ncontract StakingRewardsProxy is StakingRewardsStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/StakingRewards/StakingRewardsStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../../openzeppelin/Ownable.sol\";\n\n/**\n * @title Staking Rewards Storage Contract.\n * @notice Just the storage part of staking rewards contract, no functions,\n * only constant, variables and required structures (mappings).\n * Used by StackingRewardsProxy.\n *\n * What is SOV staking rewards - SIP-0024?\n * The purpose of the SOV staking rewards - SIP-0024 is to reward,\n * \"marginal stakers\" (ie, stakers by choice, not currently vesting) with liquid SOV\n * at the beginning of each new staking interval.\n * */\ncontract StakingRewardsStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n ///@notice the staking proxy contract address\n IStaking public staking;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 1209600;\n\n /// @notice Annual Base Rate - it is the maximum interest rate(APY)\n uint256 public constant BASE_RATE = 2975;\n\n /// @notice DIVISOR is set as 2600000 = 26 (num periods per year) * 10 (max voting weight) * 10000 (2975 -> 0.2975)\n uint256 public constant DIVISOR = 2600000;\n\n /// @notice Maximum duration to collect rewards at one go\n uint256 public maxDuration;\n\n /// @notice Represents the time when the contract is deployed\n uint256 public startTime;\n\n /// @notice Represents the block when the Staking Rewards pogram is stopped\n uint256 public stopBlock;\n\n /// @notice User Address -> Last Withdrawn Timestamp\n mapping(address => uint256) public withdrawals;\n\n /// @notice User Address -> Claimed Balance\n mapping(address => uint256) public claimedBalances;\n\n /// @notice Represents the block when the StakingRwards Program is started\n uint256 public deploymentBlock;\n\n /// Moved the variables from Initializable contract to resolve issue caused by incorrect Inheritance Order\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /// @notice BlockTime -> BlockNumber for a Staking Checkpoint\n mapping(uint256 => uint256) public checkpointBlockDetails;\n\n /// @notice Average Block Time - making it flexible\n uint256 public averageBlockTime;\n}\n" + }, + "contracts/governance/Timelock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"./ErrorDecoder.sol\";\n\ninterface ITimelock {\n function delay() external view returns (uint256);\n\n function GRACE_PERIOD() external view returns (uint256);\n\n function acceptAdmin() external;\n\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n\n/**\n * @title Sovryn Protocol Timelock contract, based on Compound system.\n *\n * @notice This contract lets Sovryn governance system set up its\n * own Time Lock instance to execute transactions proposed through the\n * GovernorAlpha contract instance.\n *\n * The Timelock contract allows its admin (Sovryn governance on\n * GovernorAlpha contract) to add arbitrary function calls to a\n * queue. This contract can only execute a function call if the\n * function call has been in the queue for at least 3 hours.\n *\n * Anytime the Timelock contract makes a function call, it must be the\n * case that the function call was first made public by having been publicly\n * added to the queue at least 3 hours prior.\n *\n * The intention is to provide GovernorAlpha contract the functionality to\n * queue proposal actions. This would mean that any changes made by Sovryn\n * governance of any contract would necessarily come with at least an\n * advanced warning. This makes the Sovryn system follow a “time-delayed,\n * opt-out” upgrade pattern (rather than an “instant, forced” upgrade pattern).\n *\n * Time-delaying admin actions gives users a chance to exit system if its\n * admins become malicious or compromised (or make a change that the users\n * do not like). Downside is that honest admins would be unable\n * to lock down functionality to protect users if a critical bug was found.\n *\n * Delayed transactions reduce the amount of trust required by users of Sovryn\n * and the overall risk for contracts building on top of it, as GovernorAlpha.\n * */\ncontract Timelock is ErrorDecoder, ITimelock {\n using SafeMath for uint256;\n\n uint256 public constant GRACE_PERIOD = 14 days;\n uint256 public constant MINIMUM_DELAY = 3 hours;\n uint256 public constant MAXIMUM_DELAY = 30 days;\n\n address public admin;\n address public pendingAdmin;\n uint256 public delay;\n\n mapping(bytes32 => bool) public queuedTransactions;\n\n event NewAdmin(address indexed newAdmin);\n event NewPendingAdmin(address indexed newPendingAdmin);\n event NewDelay(uint256 indexed newDelay);\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /**\n * @notice Function called on instance deployment of the contract.\n * @param admin_ Governance contract address.\n * @param delay_ Time to wait for queued transactions to be executed.\n * */\n constructor(address admin_, uint256 delay_) public {\n require(\n delay_ >= MINIMUM_DELAY,\n \"Timelock::constructor: Delay must exceed minimum delay.\"\n );\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n\n admin = admin_;\n delay = delay_;\n }\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external payable {}\n\n /**\n * @notice Set a new delay when executing the contract calls.\n * @param delay_ The amount of time to wait until execution.\n * */\n function setDelay(uint256 delay_) public {\n require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n require(delay_ >= MINIMUM_DELAY, \"Timelock::setDelay: Delay must exceed minimum delay.\");\n require(\n delay_ <= MAXIMUM_DELAY,\n \"Timelock::setDelay: Delay must not exceed maximum delay.\"\n );\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n /**\n * @notice Accept a new admin for the timelock.\n * */\n function acceptAdmin() public {\n require(\n msg.sender == pendingAdmin,\n \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\n );\n admin = msg.sender;\n pendingAdmin = address(0);\n\n emit NewAdmin(admin);\n }\n\n /**\n * @notice Set a new pending admin for the timelock.\n * @param pendingAdmin_ The new pending admin address.\n * */\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this),\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n /**\n * @notice Queue a new transaction from the governance contract.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function queueTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public returns (bytes32) {\n require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n require(\n eta >= getBlockTimestamp().add(delay),\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n /**\n * @notice Cancel a transaction.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function cancelTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public {\n require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n queuedTransactions[txHash] = false;\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n /**\n * @notice Executes a previously queued transaction from the governance.\n * @param target The contract to call.\n * @param value The amount to send in the transaction.\n * @param signature The stanndard representation of the function called.\n * @param data The ethereum transaction input data payload.\n * @param eta Estimated Time of Accomplishment. The timestamp that the\n * proposal will be available for execution, set once the vote succeeds.\n * */\n function executeTransaction(\n address target,\n uint256 value,\n string memory signature,\n bytes memory data,\n uint256 eta\n ) public payable returns (bytes memory) {\n require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(\n queuedTransactions[txHash],\n \"Timelock::executeTransaction: Transaction hasn't been queued.\"\n );\n require(\n getBlockTimestamp() >= eta,\n \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\n );\n require(\n getBlockTimestamp() <= eta.add(GRACE_PERIOD),\n \"Timelock::executeTransaction: Transaction is stale.\"\n );\n\n queuedTransactions[txHash] = false;\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call.value(value)(callData);\n if (!success) {\n if (returnData.length <= ERROR_MESSAGE_SHIFT) {\n revert(\"Timelock::executeTransaction: Transaction execution reverted.\");\n } else {\n revert(_addErrorMessage(\"Timelock::executeTransaction: \", string(returnData)));\n }\n }\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n /**\n * @notice A function used to get the current Block Timestamp.\n * @dev Timestamp of the current block in seconds since the epoch.\n * It is a Unix time stamp. So, it has the complete information about\n * the date, hours, minutes, and seconds (in UTC) when the block was\n * created.\n * */\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" + }, + "contracts/governance/Vesting/DevelopmentFund.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/SafeMath.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title A holding contract for Sovryn Development Fund.\n * @author Franklin Richards\n * @notice You can use this contract for timed token release from Dev Fund.\n */\ncontract DevelopmentFund {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The current contract status.\n enum Status { Deployed, Active, Expired }\n Status public status;\n\n /// @notice The owner of the locked tokens (usually Governance).\n address public lockedTokenOwner;\n /// @notice The owner of the unlocked tokens (usually MultiSig).\n address public unlockedTokenOwner;\n /// @notice The emergency transfer wallet/contract.\n address public safeVault;\n /// @notice The new locked token owner waiting to be approved.\n address public newLockedTokenOwner;\n\n /// @notice The last token release timestamp or the time of contract creation.\n uint256 public lastReleaseTime;\n\n /// @notice The release duration array in seconds.\n uint256[] public releaseDuration;\n /// @notice The release token amount.\n uint256[] public releaseTokenAmount;\n\n /* Events */\n\n /// @notice Emitted when the contract is activated.\n event DevelopmentFundActivated();\n\n /// @notice Emitted when the contract is expired due to total token transfer.\n event DevelopmentFundExpired();\n\n /// @notice Emitted when a new locked owner is added to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current locked owner.\n event NewLockedOwnerAdded(address indexed _initiator, address indexed _newLockedOwner);\n\n /// @notice Emitted when a new locked owner is approved to the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _oldLockedOwner The address of the previous locked owner.\n /// @param _newLockedOwner The address which is added as the new locked owner.\n /// @dev Can only be initiated by the current unlocked owner.\n event NewLockedOwnerApproved(\n address indexed _initiator,\n address indexed _oldLockedOwner,\n address indexed _newLockedOwner\n );\n\n /// @notice Emitted when a new unlocked owner is updated in the contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newUnlockedOwner The address which is updated as the new unlocked owner.\n /// @dev Can only be initiated by the current locked owner.\n event UnlockedOwnerUpdated(address indexed _initiator, address indexed _newUnlockedOwner);\n\n /// @notice Emitted when a new token deposit is done.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token deposited.\n event TokenDeposit(address indexed _initiator, uint256 _amount);\n\n /// @notice Emitted when a new release schedule is created.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _releaseCount The number of releases planned in the schedule.\n event TokenReleaseChanged(address indexed _initiator, uint256 _releaseCount);\n\n /// @notice Emitted when a unlocked owner transfers all the tokens to a safe vault.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token withdrawn.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done in an emergency situation only to a predetermined wallet by locked token owner.\n event LockedTokenTransferByUnlockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /// @notice Emitted when a unlocked owner withdraws the released tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The total amount of token withdrawn.\n /// @param _releaseCount The total number of releases done based on duration.\n event UnlockedTokenWithdrawalByUnlockedOwner(\n address indexed _initiator,\n uint256 _amount,\n uint256 _releaseCount\n );\n\n /// @notice Emitted when a locked owner transfers all the tokens to a receiver.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _receiver The address which receives this token transfer.\n /// @param _amount The total amount of token transferred.\n /// @dev This is done only by locked token owner.\n event LockedTokenTransferByLockedOwner(\n address indexed _initiator,\n address indexed _receiver,\n uint256 _amount\n );\n\n /* Modifiers */\n\n modifier onlyLockedTokenOwner() {\n require(msg.sender == lockedTokenOwner, \"Only Locked Token Owner can call this.\");\n _;\n }\n\n modifier onlyUnlockedTokenOwner() {\n require(msg.sender == unlockedTokenOwner, \"Only Unlocked Token Owner can call this.\");\n _;\n }\n\n modifier checkStatus(Status s) {\n require(status == s, \"The contract is not in the right state.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _lockedTokenOwner The owner of the locked tokens & contract.\n * @param _safeVault The emergency wallet/contract to transfer token.\n * @param _unlockedTokenOwner The owner of the unlocked tokens.\n * @param _lastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev Initial release schedule should be verified, error will result in either redeployment or calling changeTokenReleaseSchedule() after init() along with token transfer.\n */\n constructor(\n address _SOV,\n address _lockedTokenOwner,\n address _safeVault,\n address _unlockedTokenOwner,\n uint256 _lastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_lockedTokenOwner != address(0), \"Locked token & contract owner address invalid.\");\n require(_safeVault != address(0), \"Safe Vault address invalid.\");\n require(_unlockedTokenOwner != address(0), \"Unlocked token address invalid.\");\n\n SOV = IERC20(_SOV);\n lockedTokenOwner = _lockedTokenOwner;\n safeVault = _safeVault;\n unlockedTokenOwner = _unlockedTokenOwner;\n\n lastReleaseTime = _lastReleaseTime;\n /// If last release time passed is zero, then current time stamp will be used as the last release time.\n if (_lastReleaseTime == 0) {\n lastReleaseTime = block.timestamp;\n }\n\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n }\n\n /**\n * @notice This function is called once after deployment for token transfer based on schedule.\n * @dev Without calling this function, the contract will not work.\n */\n function init() public checkStatus(Status.Deployed) {\n uint256[] memory _releaseTokenAmount = releaseTokenAmount;\n require(_releaseTokenAmount.length != 0, \"Release Schedule not set.\");\n\n /// Getting the current release schedule total token amount.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _releaseTotalTokenAmount);\n require(txStatus, \"Not enough token sent to change release schedule.\");\n\n status = Status.Active;\n\n emit DevelopmentFundActivated();\n }\n\n /**\n * @notice Update Locked Token Owner.\n * @param _newLockedTokenOwner The owner of the locked tokens & contract.\n */\n function updateLockedTokenOwner(address _newLockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newLockedTokenOwner != address(0), \"New locked token owner address invalid.\");\n\n newLockedTokenOwner = _newLockedTokenOwner;\n\n emit NewLockedOwnerAdded(msg.sender, _newLockedTokenOwner);\n }\n\n /**\n * @notice Approve Locked Token Owner.\n * @dev This approval is an added security to avoid development fund takeover by a compromised locked token owner.\n */\n function approveLockedTokenOwner() public onlyUnlockedTokenOwner checkStatus(Status.Active) {\n require(newLockedTokenOwner != address(0), \"No new locked owner added.\");\n\n emit NewLockedOwnerApproved(msg.sender, lockedTokenOwner, newLockedTokenOwner);\n\n lockedTokenOwner = newLockedTokenOwner;\n\n newLockedTokenOwner = address(0);\n }\n\n /**\n * @notice Update Unlocked Token Owner.\n * @param _newUnlockedTokenOwner The new unlocked token owner.\n */\n function updateUnlockedTokenOwner(address _newUnlockedTokenOwner)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_newUnlockedTokenOwner != address(0), \"New unlocked token owner address invalid.\");\n\n unlockedTokenOwner = _newUnlockedTokenOwner;\n\n emit UnlockedOwnerUpdated(msg.sender, _newUnlockedTokenOwner);\n }\n\n /**\n * @notice Deposit tokens to this contract.\n * @param _amount the amount of tokens deposited.\n * @dev These tokens can be withdrawn/transferred any time by the lockedTokenOwner.\n */\n function depositTokens(uint256 _amount) public checkStatus(Status.Active) {\n require(_amount > 0, \"Amount needs to be bigger than zero.\");\n\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _amount);\n require(txStatus, \"Token transfer was not successful.\");\n\n emit TokenDeposit(msg.sender, _amount);\n }\n\n /**\n * @notice Change the Token release schedule. It creates a completely new schedule, and does not append on the previous one.\n * @param _newLastReleaseTime If the last release time is to be changed, zero if no change required.\n * @param _releaseDuration The time duration between each release calculated from `lastReleaseTime` in seconds.\n * @param _releaseTokenAmount The amount of token to be released in each duration/interval.\n * @dev _releaseDuration and _releaseTokenAmount should be specified in reverse order of release.\n */\n function changeTokenReleaseSchedule(\n uint256 _newLastReleaseTime,\n uint256[] memory _releaseDuration,\n uint256[] memory _releaseTokenAmount\n ) public onlyLockedTokenOwner checkStatus(Status.Active) {\n /// Checking if the schedule duration and token allocation length matches.\n require(\n _releaseDuration.length == _releaseTokenAmount.length,\n \"Release Schedule does not match.\"\n );\n\n /// If the last release time has to be changed, then you can pass a new one here.\n /// Or else, the duration of release will be calculated based on this timestamp.\n /// Even a future timestamp can be mentioned here.\n if (_newLastReleaseTime != 0) {\n lastReleaseTime = _newLastReleaseTime;\n }\n\n /// Checking if the contract have enough token balance for the release.\n uint256 _releaseTotalTokenAmount;\n for (uint256 amountIndex = 0; amountIndex < _releaseTokenAmount.length; amountIndex++) {\n _releaseTotalTokenAmount = _releaseTotalTokenAmount.add(\n _releaseTokenAmount[amountIndex]\n );\n }\n\n /// Getting the current token balance of the contract.\n uint256 remainingTokens = SOV.balanceOf(address(this));\n\n /// If the token balance is not sufficient, then we transfer the change to contract.\n if (remainingTokens < _releaseTotalTokenAmount) {\n bool txStatus =\n SOV.transferFrom(\n msg.sender,\n address(this),\n _releaseTotalTokenAmount.sub(remainingTokens)\n );\n require(txStatus, \"Not enough token sent to change release schedule.\");\n } else if (remainingTokens > _releaseTotalTokenAmount) {\n /// If there are more tokens than required, send the extra tokens back.\n bool txStatus =\n SOV.transfer(msg.sender, remainingTokens.sub(_releaseTotalTokenAmount));\n require(txStatus, \"Token not received by the Locked Owner.\");\n }\n\n /// Finally we update the token release schedule.\n releaseDuration = _releaseDuration;\n releaseTokenAmount = _releaseTokenAmount;\n\n emit TokenReleaseChanged(msg.sender, _releaseDuration.length);\n }\n\n /**\n * @notice Transfers all of the remaining tokens in an emergency situation.\n * @dev This could be called when governance or development fund might be compromised.\n */\n function transferTokensByUnlockedTokenOwner()\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(safeVault, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByUnlockedOwner(msg.sender, safeVault, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /**\n * @notice Withdraws all unlocked/released token.\n * @param _amount The amount to be withdrawn.\n */\n function withdrawTokensByUnlockedTokenOwner(uint256 _amount)\n public\n onlyUnlockedTokenOwner\n checkStatus(Status.Active)\n {\n require(_amount > 0, \"Zero can't be withdrawn.\");\n\n uint256 count; /// To know how many elements to be removed from the release schedule.\n uint256 amount = _amount; /// To know the total amount to be transferred.\n uint256 newLastReleaseTimeMemory = lastReleaseTime; /// Better to use memory than storage.\n uint256 releaseLength = releaseDuration.length.sub(1); /// Also checks if there are any elements in the release schedule.\n\n /// Getting the amount of tokens, the number of releases and calculating the total duration.\n while (\n amount > 0 &&\n newLastReleaseTimeMemory.add(releaseDuration[releaseLength]) < block.timestamp\n ) {\n if (amount >= releaseTokenAmount[releaseLength]) {\n amount = amount.sub(releaseTokenAmount[releaseLength]);\n newLastReleaseTimeMemory = newLastReleaseTimeMemory.add(\n releaseDuration[releaseLength]\n );\n count++;\n } else {\n /// This will be the last case, if correct amount is passed.\n releaseTokenAmount[releaseLength] = releaseTokenAmount[releaseLength].sub(amount);\n amount = 0;\n }\n releaseLength--;\n }\n\n /// Checking to see if atleast a single schedule was reached or not.\n require(count > 0 || amount == 0, \"No release schedule reached.\");\n\n /// If locked token owner tries to send a higher amount that schedule\n uint256 value = _amount.sub(amount);\n\n /// Now clearing up the release schedule.\n releaseDuration.length -= count;\n releaseTokenAmount.length -= count;\n\n /// Updating the last release time.\n lastReleaseTime = newLastReleaseTimeMemory;\n\n /// Sending the amount to unlocked token owner.\n bool txStatus = SOV.transfer(msg.sender, value);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit UnlockedTokenWithdrawalByUnlockedOwner(msg.sender, value, count);\n }\n\n /**\n * @notice Transfers all of the remaining tokens by the owner maybe for an upgrade.\n * @dev This could be called when the current development fund has to be upgraded.\n * @param _receiver The address which receives this token transfer.\n */\n function transferTokensByLockedTokenOwner(address _receiver)\n public\n onlyLockedTokenOwner\n checkStatus(Status.Active)\n {\n uint256 remainingTokens = SOV.balanceOf(address(this));\n bool txStatus = SOV.transfer(_receiver, remainingTokens);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n status = Status.Expired;\n\n emit LockedTokenTransferByLockedOwner(msg.sender, _receiver, remainingTokens);\n emit DevelopmentFundExpired();\n }\n\n /* Getter Functions */\n\n /**\n * @notice Function to read the current token release duration.\n * @return _currentReleaseDuration The current release duration.\n */\n function getReleaseDuration() public view returns (uint256[] memory _releaseTokenDuration) {\n return releaseDuration;\n }\n\n /**\n * @notice Function to read the current token release amount.\n * @return _currentReleaseTokenAmount The current release token amount.\n */\n function getReleaseTokenAmount()\n public\n view\n returns (uint256[] memory _currentReleaseTokenAmount)\n {\n return releaseTokenAmount;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../IFeeSharingCollector.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../proxy/UpgradableProxy.sol\";\nimport \"../../../openzeppelin/Address.sol\";\n\n/**\n * @title Four Year Vesting Contract.\n *\n * @notice A four year vesting contract.\n *\n * @dev Vesting contract is upgradable,\n * Make sure the vesting owner is multisig otherwise it will be\n * catastrophic.\n * */\ncontract FourYearVesting is FourYearVestingStorage, UpgradableProxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharingCollector Fee sharing proxy address.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n address _feeSharingCollector,\n uint256 _extendDurationFor\n ) public {\n require(Address.isContract(_logic), \"_logic not a contract\");\n require(_SOV != address(0), \"SOV address invalid\");\n require(Address.isContract(_SOV), \"_SOV not a contract\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(Address.isContract(_stakingAddress), \"_stakingAddress not a contract\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(Address.isContract(_feeSharingCollector), \"_feeSharingCollector not a contract\");\n require((_extendDurationFor % FOUR_WEEKS) == 0, \"invalid duration\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n tokenOwner = _tokenOwner;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n maxInterval = 18 * FOUR_WEEKS;\n extendDurationFor = _extendDurationFor;\n }\n\n /**\n * @notice Set address of the implementation - vesting owner.\n * @dev Overriding setImplementation function of UpgradableProxy. The logic can only be\n * modified when both token owner and veting owner approve. Since\n * setImplementation can only be called by vesting owner, we also need to check\n * if the new logic is already approved by the token owner.\n * @param _implementation Address of the implementation. Must match with what is set by token owner.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n require(Address.isContract(_implementation), \"_implementation not a contract\");\n require(newImplementation == _implementation, \"address mismatch\");\n _setImplementation(_implementation);\n newImplementation = address(0);\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"./FourYearVesting.sol\";\nimport \"./IFourYearVestingFactory.sol\";\n\n/**\n * @title Four Year Vesting Factory: Contract to deploy four year vesting contracts.\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract FourYearVestingFactory is IFourYearVestingFactory, Ownable {\n /// @dev Added an event to keep track of the vesting contract created for a token owner\n event FourYearVestingCreated(address indexed tokenOwner, address indexed vestingAddress);\n\n /**\n * @notice Deploys four year vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwnerMultisig The address of an owner of vesting contract.\n * @dev _vestingOwnerMultisig should ALWAYS be multisig.\n * @param _fourYearVestingLogic The implementation contract.\n * @param _extendDurationFor Duration till the unlocked tokens are extended.\n * @return The four year vesting contract address.\n * */\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external onlyOwner returns (address) {\n address fourYearVesting =\n address(\n new FourYearVesting(\n _fourYearVestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _feeSharing,\n _extendDurationFor\n )\n );\n Ownable(fourYearVesting).transferOwnership(_vestingOwnerMultisig);\n emit FourYearVestingCreated(_tokenOwner, fourYearVesting);\n return fourYearVesting;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./IFourYearVesting.sol\";\nimport \"../../ApprovalReceiver.sol\";\nimport \"./FourYearVestingStorage.sol\";\nimport \"../../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Four Year Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by FourYearVestingFactory contract.\n * */\ncontract FourYearVestingLogic is IFourYearVesting, FourYearVestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n\n /* Events */\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(address indexed caller, address receiver);\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n event TokenOwnerChanged(address indexed newOwner, address indexed oldOwner);\n\n /* Modifiers */\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Sets the max interval.\n * @param _interval Max interval for which tokens scheduled shall be staked.\n * */\n function setMaxInterval(uint256 _interval) external onlyOwner {\n require(_interval.mod(FOUR_WEEKS) == 0, \"invalid interval\");\n maxInterval = _interval;\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount)\n {\n (lastSchedule, remainingAmount) = _stakeTokens(msg.sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function stakeTokensWithApproval(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) external onlyThisContract returns (uint256 lastSchedule, uint256 remainingAmount) {\n (lastSchedule, remainingAmount) = _stakeTokens(_sender, _amount, _restartStakeSchedule);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) external onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n uint256 stakingEndDate = endDate;\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate.add(cliff); i <= stakingEndDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) external onlyTokenOwner {\n _withdrawTokens(receiver, false);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) external onlyTokenOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Change token owner - only vesting owner is allowed to change.\n * @dev Modifies token owner. This must be followed by approval\n * from token owner.\n * @param _newTokenOwner Address of new token owner.\n * */\n function changeTokenOwner(address _newTokenOwner) public onlyOwner {\n require(_newTokenOwner != address(0), \"invalid new token owner address\");\n require(_newTokenOwner != tokenOwner, \"same owner not allowed\");\n newTokenOwner = _newTokenOwner;\n }\n\n /**\n * @notice Approve token owner change - only token Owner.\n * @dev Token owner can only be modified\n * when both vesting owner and token owner have approved. This\n * function ascertains the approval of token owner.\n * */\n function approveOwnershipTransfer() public onlyTokenOwner {\n require(newTokenOwner != address(0), \"invalid address\");\n tokenOwner = newTokenOwner;\n newTokenOwner = address(0);\n emit TokenOwnerChanged(tokenOwner, msg.sender);\n }\n\n /**\n * @notice Set address of the implementation - only Token Owner.\n * @dev This function sets the new implementation address.\n * It must also be approved by the Vesting owner.\n * @param _newImplementation Address of the new implementation.\n * */\n function setImpl(address _newImplementation) public onlyTokenOwner {\n require(_newImplementation != address(0), \"invalid new implementation address\");\n newImplementation = _newImplementation;\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() external onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Extends stakes(unlocked till timeDuration) for four year vesting contracts.\n * @dev Tokens are vested for 4 years. Since the max staking\n * period is 3 years and the tokens are unlocked only after the first year(timeDuration) is\n * passed, hence, we usually extend the duration of staking for all unlocked tokens for the first\n * year by 3 years. In some cases, the timeDuration can differ.\n * */\n function extendStaking() external {\n uint256 timeDuration = startDate.add(extendDurationFor);\n uint256[] memory dates;\n uint96[] memory stakes;\n (dates, stakes) = staking.getStakes(address(this));\n\n for (uint256 i = 0; i < dates.length; i++) {\n if ((dates[i] < block.timestamp) && (dates[i] <= timeDuration) && (stakes[i] > 0)) {\n staking.extendStakingDuration(dates[i], dates[i].add(156 weeks));\n endDate = dates[i].add(156 weeks);\n } else {\n break;\n }\n }\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * @param _restartStakeSchedule The time from which staking schedule restarts.\n * The issue is that we can only stake tokens for a max duration. Thus, we need to restart\n * from the lastSchedule.\n * @return lastSchedule The max duration for which tokens were staked.\n * @return remainingAmount The amount outstanding - to be staked.\n * */\n function _stakeTokens(\n address _sender,\n uint256 _amount,\n uint256 _restartStakeSchedule\n ) internal returns (uint256 lastSchedule, uint256 remainingAmount) {\n // Creating a new staking schedule for the same vesting contract is disallowed unlike normal vesting\n require(\n (startDate == 0) ||\n (startDate > 0 && remainingStakeAmount > 0 && _restartStakeSchedule > 0),\n \"create new vesting address\"\n );\n uint256 restartDate;\n uint256 relativeAmount;\n // Calling the _stakeTokens function first time for the vesting contract\n // Runs for maxInterval only (consider maxInterval = 18 * 4 = 72 weeks)\n if (startDate == 0 && _restartStakeSchedule == 0) {\n startDate = staking.timestampToLockDate(block.timestamp); // Set only once\n durationLeft = duration; // We do not touch duration and cliff as they are used throughout\n cliffAdded = cliff; // Hence, durationLeft and cliffAdded is created\n }\n // Calling the _stakeTokens second/third time - we start from the end of previous interval\n // and the remaining amount(amount left after tokens are staked in the previous interval)\n if (_restartStakeSchedule > 0) {\n require(\n _restartStakeSchedule == lastStakingSchedule && _amount == remainingStakeAmount,\n \"invalid params\"\n );\n restartDate = _restartStakeSchedule;\n } else {\n restartDate = startDate;\n }\n // Runs only once when the _stakeTokens is called for the first time\n if (endDate == 0) {\n endDate = staking.timestampToLockDate(block.timestamp.add(duration));\n }\n uint256 addedMaxInterval = restartDate.add(maxInterval); // run for maxInterval\n if (addedMaxInterval < endDate) {\n // Runs for max interval\n lastStakingSchedule = addedMaxInterval;\n relativeAmount = (_amount.mul(maxInterval)).div(durationLeft); // (_amount * 18) / 39\n durationLeft = durationLeft.sub(maxInterval); // durationLeft - 18 periods(72 weeks)\n remainingStakeAmount = _amount.sub(relativeAmount); // Amount left to be staked in subsequent intervals\n } else {\n // Normal run\n lastStakingSchedule = endDate; // if staking intervals left < 18 periods(72 weeks)\n remainingStakeAmount = 0;\n durationLeft = 0;\n relativeAmount = _amount; // Stake all amount left\n }\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), relativeAmount);\n require(success, \"transfer failed\");\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), relativeAmount);\n\n staking.stakesBySchedule(\n relativeAmount,\n cliffAdded,\n duration.sub(durationLeft),\n FOUR_WEEKS,\n address(this),\n tokenOwner\n );\n if (durationLeft == 0) {\n // All tokens staked\n cliffAdded = 0;\n } else {\n cliffAdded = cliffAdded.add(maxInterval); // Add cliff to the end of previous maxInterval\n }\n\n emit TokensStaked(_sender, relativeAmount);\n return (lastStakingSchedule, remainingStakeAmount);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param isGovernance Whether all tokens (true)\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(address receiver, bool isGovernance) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n /// @dev In the unlikely case that all tokens have been unlocked early,\n /// allow to withdraw all of them.\n if (staking.allUnlocked() || isGovernance) {\n end = endDate;\n } else {\n end = block.timestamp;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n /// @dev For four year vesting, withdrawal of stakes for the first year is not allowed. These\n /// stakes are extended for three years. In some cases the withdrawal may be allowed at a different\n /// time and hence we use extendDurationFor.\n for (uint256 i = startDate.add(extendDurationFor); i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number.sub(1));\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n}\n" + }, + "contracts/governance/Vesting/fouryear/FourYearVestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../../openzeppelin/Ownable.sol\";\nimport \"../../../interfaces/IERC20.sol\";\nimport \"../../Staking/interfaces/IStaking.sol\";\nimport \"../../IFeeSharingCollector.sol\";\n\n/**\n * @title Four Year Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for four year vesting.\n * It is parent of FourYearVestingLogic and FourYearVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract FourYearVestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n // Used lower case for cliff and duration to maintain consistency with normal vesting\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public constant cliff = 4 weeks;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public constant duration = 156 weeks;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n /// @notice Maximum interval to stake tokens at one go\n uint256 public maxInterval;\n\n /// @notice End of previous staking schedule.\n uint256 public lastStakingSchedule;\n\n /// @notice Amount of shares left to be staked.\n uint256 public remainingStakeAmount;\n\n /// @notice Durations left.\n uint256 public durationLeft;\n\n /// @notice Cliffs added.\n uint256 public cliffAdded;\n\n /// @notice Address of new token owner.\n address public newTokenOwner;\n\n /// @notice Address of new implementation.\n address public newImplementation;\n\n /// @notice Duration(from start) till the time unlocked tokens are extended(for 3 years)\n uint256 public extendDurationFor;\n\n /// @dev Please add new state variables below this line. Mark them internal and\n /// add a getter function while upgrading the contracts.\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IFourYearVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IFourYearVesting {\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 _amount, uint256 _restartStakeSchedule)\n external\n returns (uint256 lastSchedule, uint256 remainingAmount);\n}\n" + }, + "contracts/governance/Vesting/fouryear/IFourYearVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Four Year Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by FourYearVestingFactory contract to override empty\n * implemention of deployFourYearVesting function\n * and use an instance of FourYearVestingFactory.\n */\ninterface IFourYearVestingFactory {\n function deployFourYearVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n address _feeSharing,\n address _vestingOwnerMultisig,\n address _fourYearVestingLogic,\n uint256 _extendDurationFor\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/GenericTokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\n\n/**\n * @title Token sender contract.\n *\n * @notice This contract includes functions to transfer tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract GenericTokenSender is AdminRole {\n /* Events */\n\n event TokensTransferred(address indexed token, address indexed receiver, uint256 amount);\n\n /* Functions */\n\n /**\n * @notice Transfer given amounts of tokens to the given addresses.\n * @param _token The address of the token.\n * @param _receivers The addresses of the receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferTokensUsingList(\n address _token,\n address[] calldata _receivers,\n uint256[] calldata _amounts\n ) external onlyAuthorized {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferTokens(_token, _receivers[i], _amounts[i]);\n }\n }\n\n function() external payable {}\n\n /**\n * @notice Transfer tokens to given address.\n * @param _token The address of the token.\n * @param _receiver The address of the token receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) external onlyAuthorized {\n _transferTokens(_token, _receiver, _amount);\n }\n\n function _transferTokens(\n address _token,\n address _receiver,\n uint256 _amount\n ) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n if (_token != address(0)) {\n require(IERC20(_token).transfer(_receiver, _amount), \"transfer failed\");\n } else {\n (bool success, ) = _receiver.call.value(_amount)(\"\");\n require(success, \"RBTC transfer failed\");\n }\n emit TokensTransferred(_token, _receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/ITeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for TeamVesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by Staking contract to cancel the team vesting\n * function having the vesting contract instance address.\n */\ninterface ITeamVesting {\n function startDate() external view returns (uint256);\n\n function cliff() external view returns (uint256);\n\n function endDate() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function tokenOwner() external view returns (address);\n\n function governanceWithdrawTokens(address receiver) external;\n}\n" + }, + "contracts/governance/Vesting/IVesting.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingLogic contract to implement stakeTokens function\n * and on VestingRegistry contract to call IVesting(vesting).stakeTokens function\n * at a vesting instance.\n */\ninterface IVesting {\n function duration() external returns (uint256);\n\n function endDate() external returns (uint256);\n\n function stakeTokens(uint256 amount) external;\n\n function tokenOwner() external view returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for Vesting Factory contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n * This interface is used by VestingFactory contract to override empty\n * implemention of deployVesting and deployTeamVesting functions\n * and on VestingRegistry contract to use an instance of VestingFactory.\n */\ninterface IVestingFactory {\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _owner\n ) external returns (address);\n}\n" + }, + "contracts/governance/Vesting/IVestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for upgradable Vesting Registry contract.\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IVestingRegistry {\n function getVesting(address _tokenOwner) external view returns (address);\n\n function getTeamVesting(address _tokenOwner) external view returns (address);\n\n function setVestingRegistry(address _vestingRegistryProxy) external;\n\n function isVestingAddress(address _vestingAddress) external view returns (bool);\n\n function isTeamVesting(address _vestingAddress) external view returns (bool);\n}\n" + }, + "contracts/governance/Vesting/OrigingVestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./VestingRegistry.sol\";\n\n/**\n * @title Temp contract for checking address, creating and staking tokens.\n * @notice It casts an instance of vestingRegistry and by using createVesting\n * function it creates a vesting, gets it and stakes some tokens w/ this vesting.\n * */\ncontract OrigingVestingCreator is Ownable {\n VestingRegistry public vestingRegistry;\n\n mapping(address => bool) processedList;\n\n constructor(address _vestingRegistry) public {\n vestingRegistry = VestingRegistry(_vestingRegistry);\n }\n\n /**\n * @notice Create a vesting, get it and stake some tokens w/ this vesting.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount of tokens to be vested.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyOwner {\n require(_tokenOwner != address(0), \"Invalid address\");\n require(!processedList[_tokenOwner], \"Already processed\");\n\n processedList[_tokenOwner] = true;\n\n vestingRegistry.createVesting(_tokenOwner, _amount, _cliff, _duration);\n address vesting = vestingRegistry.getVesting(_tokenOwner);\n vestingRegistry.stakeTokens(vesting, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/OriginInvestorsClaim.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./VestingRegistry.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\n\n/**\n * @title Origin investors claim vested cSOV tokens.\n * @notice // TODO: fund this contract with a total amount of SOV needed to distribute.\n * */\ncontract OriginInvestorsClaim is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// VestingRegistry public constant vestingRegistry = VestingRegistry(0x80B036ae59B3e38B573837c01BB1DB95515b7E6B);\n\n uint256 public totalAmount;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant SOV_VESTING_CLIFF = 6 weeks;\n\n uint256 public kickoffTS;\n uint256 public vestingTerm;\n uint256 public investorsQty;\n bool public investorsListInitialized;\n VestingRegistry public vestingRegistry;\n IStaking public staking;\n IERC20 public SOVToken;\n\n /// @dev user => flag : Whether user has admin role.\n mapping(address => bool) public admins;\n\n /// @dev investor => Amount : Origin investors entitled to claim SOV.\n mapping(address => uint256) public investorsAmountsList;\n\n /* Events */\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n event InvestorsAmountsListAppended(uint256 qty, uint256 amount);\n event ClaimVested(address indexed investor, uint256 amount);\n event ClaimTransferred(address indexed investor, uint256 amount);\n event InvestorsAmountsListInitialized(uint256 qty, uint256 totalAmount);\n\n /* Modifiers */\n\n /// @dev Throws if called by any account other than the owner or admin.\n modifier onlyAuthorized() {\n require(\n isOwner() || admins[msg.sender],\n \"OriginInvestorsClaim::onlyAuthorized: should be authorized\"\n );\n _;\n }\n\n /// @dev Throws if called by any account not whitelisted.\n modifier onlyWhitelisted() {\n require(\n investorsAmountsList[msg.sender] != 0,\n \"OriginInvestorsClaim::onlyWhitelisted: not whitelisted or already claimed\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an initialized investors list.\n modifier notInitialized() {\n require(\n !investorsListInitialized,\n \"OriginInvestorsClaim::notInitialized: the investors list should not be set as initialized\"\n );\n _;\n }\n\n /// @dev Throws if called w/ an uninitialized investors list.\n modifier initialized() {\n require(\n investorsListInitialized,\n \"OriginInvestorsClaim::initialized: the investors list has not been set yet\"\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Contract deployment requires one parameter:\n * @param vestingRegistryAddress The vestingRegistry contract instance address.\n * */\n constructor(address vestingRegistryAddress) public {\n vestingRegistry = VestingRegistry(vestingRegistryAddress);\n staking = IStaking(vestingRegistry.staking());\n kickoffTS = staking.kickoffTS();\n SOVToken = IERC20(staking.SOVToken());\n vestingTerm = kickoffTS + SOV_VESTING_CLIFF;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice In case we have unclaimed tokens or in emergency case\n * this function transfers all SOV tokens to a given address.\n * @param toAddress The recipient address of all this contract tokens.\n * */\n function authorizedBalanceWithdraw(address toAddress) public onlyAuthorized {\n require(\n SOVToken.transfer(toAddress, SOVToken.balanceOf(address(this))),\n \"OriginInvestorsClaim::authorizedTransferBalance: transfer failed\"\n );\n }\n\n /**\n * @notice Should be called after the investors list setup completed.\n * This function checks whether the SOV token balance of the contract is\n * enough and sets status list to initialized.\n * */\n function setInvestorsAmountsListInitialized() public onlyAuthorized notInitialized {\n require(\n SOVToken.balanceOf(address(this)) >= totalAmount,\n \"OriginInvestorsClaim::setInvestorsAmountsList: the contract is not enough financed\"\n );\n\n investorsListInitialized = true;\n\n emit InvestorsAmountsListInitialized(investorsQty, totalAmount);\n }\n\n /**\n * @notice The contract should be approved or transferred necessary\n * amount of SOV prior to calling the function.\n * @param investors The list of investors addresses to add to the list.\n * Duplicates will be skipped.\n * @param claimAmounts The list of amounts for investors investors[i]\n * will receive claimAmounts[i] of SOV.\n * */\n function appendInvestorsAmountsList(\n address[] calldata investors,\n uint256[] calldata claimAmounts\n ) external onlyAuthorized notInitialized {\n uint256 subQty;\n uint256 sumAmount;\n require(\n investors.length == claimAmounts.length,\n \"OriginInvestorsClaim::appendInvestorsAmountsList: investors.length != claimAmounts.length\"\n );\n\n for (uint256 i = 0; i < investors.length; i++) {\n if (investorsAmountsList[investors[i]] == 0) {\n investorsAmountsList[investors[i]] = claimAmounts[i];\n sumAmount = sumAmount.add(claimAmounts[i]);\n } else {\n subQty = subQty.add(1);\n }\n }\n\n investorsQty = investorsQty.add(investors.length.sub(subQty));\n totalAmount = totalAmount.add(sumAmount);\n emit InvestorsAmountsListAppended(investors.length.sub(subQty), sumAmount);\n }\n\n /**\n * @notice Claim tokens from this contract.\n * If vestingTerm is not yet achieved a vesting is created.\n * Otherwise tokens are tranferred.\n * */\n function claim() external onlyWhitelisted initialized {\n if (now < vestingTerm) {\n createVesting();\n } else {\n transfer();\n }\n }\n\n /**\n * @notice Transfer tokens from this contract to a vestingRegistry contract.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to vesting contract.\n * */\n function createVesting() internal {\n uint256 cliff = vestingTerm.sub(now);\n uint256 duration = cliff;\n uint256 amount = investorsAmountsList[msg.sender];\n address vestingContractAddress;\n\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n vestingContractAddress == address(0),\n \"OriginInvestorsClaim::withdraw: the claimer has an active vesting contract\"\n );\n\n delete investorsAmountsList[msg.sender];\n\n vestingRegistry.createVesting(msg.sender, amount, cliff, duration);\n vestingContractAddress = vestingRegistry.getVesting(msg.sender);\n require(\n SOVToken.transfer(address(vestingRegistry), amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n vestingRegistry.stakeTokens(vestingContractAddress, amount);\n\n emit ClaimVested(msg.sender, amount);\n }\n\n /**\n * @notice Transfer tokens from this contract to the sender.\n * Sender is removed from investor list and all its unvested tokens\n * are sent to its account.\n * */\n function transfer() internal {\n uint256 amount = investorsAmountsList[msg.sender];\n\n delete investorsAmountsList[msg.sender];\n\n /**\n * @dev Withdraw only for those claiming after the cliff, i.e. without vesting contracts.\n * Those with vestingContracts should withdraw using Vesting.withdrawTokens\n * from Vesting (VestingLogic) contract.\n * */\n require(\n SOVToken.transfer(msg.sender, amount),\n \"OriginInvestorsClaim::withdraw: SOV transfer failed\"\n );\n\n emit ClaimTransferred(msg.sender, amount);\n }\n}\n" + }, + "contracts/governance/Vesting/TeamVesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n//import \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../proxy/Proxy.sol\";\n\n/**\n * @title Team Vesting Contract.\n *\n * @notice A regular vesting contract, but the owner (governance) is able to\n * withdraw earlier without a slashing.\n *\n * @dev Vesting contracts shouldn't be upgradable,\n * use Proxy instead of UpgradableProxy.\n * */\ncontract TeamVesting is VestingStorage, Proxy {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollector\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_stakingAddress != address(0), \"staking address invalid\");\n require(_tokenOwner != address(0), \"token owner address invalid\");\n require(_duration >= _cliff, \"duration must be bigger than or equal to the cliff\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n\n _setImplementation(_logic);\n SOV = IERC20(_SOV);\n staking = IStaking(_stakingAddress);\n require(_duration <= staking.MAX_DURATION(), \"duration may not exceed the max duration\");\n tokenOwner = _tokenOwner;\n cliff = _cliff;\n duration = _duration;\n feeSharingCollector = IFeeSharingCollector(_feeSharingCollector);\n }\n}\n" + }, + "contracts/governance/Vesting/TokenSender.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\n/**\n * @title SOV Token sender contract.\n *\n * @notice This contract includes functions to transfer SOV tokens\n * to a recipient or to several recipients in a list. There is\n * an ACL control check by modifier.\n *\n */\ncontract TokenSender is Ownable {\n /* Storage */\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @dev user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n /* Events */\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n constructor(address _SOV) public {\n require(_SOV != address(0), \"SOV address invalid\");\n\n SOV = _SOV;\n }\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice Transfer given amounts of SOV to the given addresses.\n * @param _receivers The addresses of the SOV receivers.\n * @param _amounts The amounts to be transferred.\n * */\n function transferSOVusingList(address[] memory _receivers, uint256[] memory _amounts)\n public\n onlyAuthorized\n {\n require(_receivers.length == _amounts.length, \"arrays mismatch\");\n\n for (uint256 i = 0; i < _receivers.length; i++) {\n _transferSOV(_receivers[i], _amounts[i]);\n }\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyAuthorized {\n _transferSOV(_receiver, _amount);\n }\n\n function _transferSOV(address _receiver, uint256 _amount) internal {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n}\n" + }, + "contracts/governance/Vesting/Vesting.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./TeamVesting.sol\";\n\n/**\n * @title Vesting Contract.\n * @notice Team tokens and investor tokens are vested. Therefore, a smart\n * contract needs to be developed to enforce the vesting schedule.\n *\n * */\ncontract Vesting is TeamVesting {\n /**\n * @notice Setup the vesting schedule.\n * @param _logic The address of logic contract.\n * @param _SOV The SOV token address.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n constructor(\n address _logic,\n address _SOV,\n address _stakingAddress,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharingCollectorProxy\n )\n public\n TeamVesting(\n _logic,\n _SOV,\n _stakingAddress,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharingCollectorProxy\n )\n {}\n\n /**\n * @dev We need to add this implementation to prevent proxy call VestingLogic.governanceWithdrawTokens\n * @param receiver The receiver of the token withdrawal.\n * */\n function governanceWithdrawTokens(address receiver) public {\n revert(\"operation not supported\");\n }\n}\n" + }, + "contracts/governance/Vesting/VestingCreator.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"./VestingRegistryLogic.sol\";\nimport \"./VestingLogic.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingCreator is AdminRole {\n using SafeMath for uint256;\n\n ///@notice Boolean to check both vesting creation and staking is completed for a record\n bool vestingCreated;\n\n /// @notice 2 weeks in seconds.\n uint256 public constant TWO_WEEKS = 2 weeks;\n\n ///@notice the SOV token contract\n IERC20 public SOV;\n\n ///@notice the vesting registry contract\n VestingRegistryLogic public vestingRegistryLogic;\n\n ///@notice Holds Vesting Data\n struct VestingData {\n uint256 amount;\n uint256 cliff;\n uint256 duration;\n bool governanceControl; ///@dev true - tokens can be withdrawn by governance\n address tokenOwner;\n uint256 vestingCreationType;\n }\n\n ///@notice list of vesting to be processed\n VestingData[] public vestingDataList;\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event TokensStaked(address indexed vesting, address indexed tokenOwner, uint256 amount);\n event VestingDataRemoved(address indexed caller, address indexed tokenOwner);\n event DataCleared(address indexed caller);\n\n constructor(address _SOV, address _vestingRegistryProxy) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_vestingRegistryProxy != address(0), \"Vesting registry address invalid\");\n\n SOV = IERC20(_SOV);\n vestingRegistryLogic = VestingRegistryLogic(_vestingRegistryProxy);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_amount != 0, \"amount invalid\");\n require(SOV.transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings to be processed to the list\n */\n function addVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _amounts,\n uint256[] calldata _cliffs,\n uint256[] calldata _durations,\n bool[] calldata _governanceControls,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n require(\n _tokenOwners.length == _amounts.length &&\n _tokenOwners.length == _cliffs.length &&\n _tokenOwners.length == _durations.length &&\n _tokenOwners.length == _governanceControls.length,\n \"arrays mismatch\"\n );\n\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(\n _durations[i] >= _cliffs[i],\n \"duration must be bigger than or equal to the cliff\"\n );\n require(_amounts[i] > 0, \"vesting amount cannot be 0\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_cliffs[i].mod(TWO_WEEKS) == 0, \"cliffs should have intervals of two weeks\");\n require(\n _durations[i].mod(TWO_WEEKS) == 0,\n \"durations should have intervals of two weeks\"\n );\n VestingData memory vestingData =\n VestingData({\n amount: _amounts[i],\n cliff: _cliffs[i],\n duration: _durations[i],\n governanceControl: _governanceControls[i],\n tokenOwner: _tokenOwners[i],\n vestingCreationType: _vestingCreationTypes[i]\n });\n vestingDataList.push(vestingData);\n }\n }\n\n /**\n * @notice Creates vesting contract and stakes tokens\n * @dev Vesting and Staking are merged for calls that fits the gas limit\n */\n function processNextVesting() external {\n processVestingCreation();\n processStaking();\n }\n\n /**\n * @notice Creates vesting contract without staking any tokens\n * @dev Separating the Vesting and Staking to tackle Block Gas Limit\n */\n function processVestingCreation() public {\n require(!vestingCreated, \"staking not done for the previous vesting\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n _createAndGetVesting(vestingData);\n vestingCreated = true;\n }\n }\n\n /**\n * @notice Staking vested tokens\n * @dev it can be the case when vesting creation and tokens staking can't be done in one transaction because of block gas limit\n */\n function processStaking() public {\n require(vestingCreated, \"cannot stake without vesting creation\");\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n address vestingAddress =\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n require(SOV.approve(address(vesting), vestingData.amount), \"Approve failed\");\n vesting.stakeTokens(vestingData.amount);\n emit TokensStaked(vestingAddress, vestingData.tokenOwner, vestingData.amount);\n address tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n vestingCreated = false;\n }\n\n /**\n * @notice removes next vesting data from the list\n * @dev we process inverted list\n * @dev we should be able to remove incorrect vesting data that can't be processed\n */\n function removeNextVesting() external onlyAuthorized {\n address tokenOwnerDetails;\n if (vestingDataList.length > 0) {\n VestingData storage vestingData = vestingDataList[vestingDataList.length - 1];\n tokenOwnerDetails = vestingData.tokenOwner;\n vestingDataList.pop();\n emit VestingDataRemoved(msg.sender, tokenOwnerDetails);\n }\n }\n\n /**\n * @notice removes all data about unprocessed vestings to be processed\n */\n function clearVestingDataList() public onlyAuthorized {\n delete vestingDataList;\n emit DataCleared(msg.sender);\n }\n\n /**\n * @notice returns address after vesting creation\n */\n function getVestingAddress() external view returns (address) {\n return\n _getVesting(\n vestingDataList[vestingDataList.length - 1].tokenOwner,\n vestingDataList[vestingDataList.length - 1].cliff,\n vestingDataList[vestingDataList.length - 1].duration,\n vestingDataList[vestingDataList.length - 1].governanceControl,\n vestingDataList[vestingDataList.length - 1].vestingCreationType\n );\n }\n\n /**\n * @notice returns period i.e. ((duration - cliff) / 4 WEEKS)\n * @dev will be used for deciding if vesting and staking needs to be processed\n * in a single transaction or separate transactions\n */\n function getVestingPeriod() external view returns (uint256) {\n uint256 duration = vestingDataList[vestingDataList.length - 1].duration;\n uint256 cliff = vestingDataList[vestingDataList.length - 1].cliff;\n uint256 fourWeeks = TWO_WEEKS.mul(2);\n uint256 period = duration.sub(cliff).div(fourWeeks);\n return period;\n }\n\n /**\n * @notice returns count of vestings to be processed\n */\n function getUnprocessedCount() external view returns (uint256) {\n return vestingDataList.length;\n }\n\n /**\n * @notice returns total amount of vestings to be processed\n */\n function getUnprocessedAmount() public view returns (uint256) {\n uint256 amount = 0;\n uint256 length = vestingDataList.length;\n for (uint256 i = 0; i < length; i++) {\n amount = amount.add(vestingDataList[i].amount);\n }\n return amount;\n }\n\n /**\n * @notice checks if contract balance is enough to process all vestings\n */\n function isEnoughBalance() public view returns (bool) {\n return SOV.balanceOf(address(this)) >= getUnprocessedAmount();\n }\n\n /**\n * @notice returns missed balance to process all vestings\n */\n function getMissingBalance() external view returns (uint256) {\n if (isEnoughBalance()) {\n return 0;\n }\n return getUnprocessedAmount() - SOV.balanceOf(address(this));\n }\n\n /**\n * @notice creates TeamVesting or Vesting contract\n * @dev new contract won't be created if account already has contract of the same type\n */\n function _createAndGetVesting(VestingData memory vestingData)\n internal\n returns (address vesting)\n {\n if (vestingData.governanceControl) {\n vestingRegistryLogic.createTeamVesting(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n } else {\n vestingRegistryLogic.createVestingAddr(\n vestingData.tokenOwner,\n vestingData.amount,\n vestingData.cliff,\n vestingData.duration,\n vestingData.vestingCreationType\n );\n }\n return\n _getVesting(\n vestingData.tokenOwner,\n vestingData.cliff,\n vestingData.duration,\n vestingData.governanceControl,\n vestingData.vestingCreationType\n );\n }\n\n /**\n * @notice returns an address of TeamVesting or Vesting contract (depends on a governance control)\n */\n function _getVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n bool _governanceControl,\n uint256 _vestingCreationType\n ) internal view returns (address vestingAddress) {\n if (_governanceControl) {\n vestingAddress = vestingRegistryLogic.getTeamVesting(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n } else {\n vestingAddress = vestingRegistryLogic.getVestingAddr(\n _tokenOwner,\n _cliff,\n _duration,\n _vestingCreationType\n );\n }\n }\n}\n" + }, + "contracts/governance/Vesting/VestingFactory.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"./Vesting.sol\";\nimport \"./TeamVesting.sol\";\nimport \"./IVestingFactory.sol\";\n\n/**\n * @title Vesting Factory: Contract to deploy vesting contracts\n * of two types: vesting (TokenHolder) and team vesting (Multisig).\n * @notice Factory pattern allows to create multiple instances\n * of the same contract and keep track of them easier.\n * */\ncontract VestingFactory is IVestingFactory, Ownable {\n address public vestingLogic;\n\n constructor(address _vestingLogic) public {\n require(_vestingLogic != address(0), \"invalid vesting logic address\");\n vestingLogic = _vestingLogic;\n }\n\n /**\n * @notice Deploys Vesting contract.\n * @param _SOV the address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner /// @dev owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new Vesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n\n /**\n * @notice Deploys Team Vesting contract.\n * @param _SOV The address of SOV token.\n * @param _staking The address of staking contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @param _feeSharing The address of fee sharing contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @return The vesting contract address.\n * */\n function deployTeamVesting(\n address _SOV,\n address _staking,\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n address _feeSharing,\n address _vestingOwner\n )\n external\n onlyOwner //owner - VestingRegistry\n returns (address)\n {\n address vesting =\n address(\n new TeamVesting(\n vestingLogic,\n _SOV,\n _staking,\n _tokenOwner,\n _cliff,\n _duration,\n _feeSharing\n )\n );\n Ownable(vesting).transferOwnership(_vestingOwner);\n return vesting;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"../ApprovalReceiver.sol\";\nimport \"./VestingStorage.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Logic contract.\n * @notice Staking, delegating and withdrawal functionality.\n * @dev Deployed by a VestingFactory contract.\n * */\ncontract VestingLogic is IVesting, VestingStorage, ApprovalReceiver {\n using SafeMath for uint256;\n /* Events */\n\n event TokensStaked(address indexed caller, uint256 amount);\n event VotesDelegated(address indexed caller, address delegatee);\n event TokensWithdrawn(\n address indexed caller,\n address receiver,\n uint256 startFrom,\n uint256 end\n );\n event DividendsCollected(\n address indexed caller,\n address loanPoolToken,\n address receiver,\n uint32 maxCheckpoints\n );\n event MigratedToNewStakingContract(address indexed caller, address newStakingContract);\n\n /* Modifiers */\n\n /**\n * @dev Throws if called by any account other than the token owner or the contract owner.\n */\n modifier onlyOwners() {\n require(msg.sender == tokenOwner || isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Throws if called by any account other than the token owner.\n */\n modifier onlyTokenOwner() {\n require(msg.sender == tokenOwner, \"unauthorized\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(uint256 _amount) public {\n _stakeTokens(msg.sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule.\n * @dev This function will be invoked from receiveApproval.\n * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeTokensWithApproval\n * @param _sender The sender of SOV.approveAndCall\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokensWithApproval(address _sender, uint256 _amount) public onlyThisContract {\n _stakeTokens(_sender, _amount);\n }\n\n /**\n * @notice Stakes tokens according to the vesting schedule. Low level function.\n * @dev Once here the allowance of tokens is taken for granted.\n * @param _sender The sender of tokens to stake.\n * @param _amount The amount of tokens to stake.\n * */\n function _stakeTokens(address _sender, uint256 _amount) internal {\n /// @dev Maybe better to allow staking unil the cliff was reached.\n if (startDate == 0) {\n startDate = staking.timestampToLockDate(block.timestamp);\n }\n endDate = staking.timestampToLockDate(block.timestamp + duration);\n\n /// @dev Transfer the tokens to this contract.\n bool success = SOV.transferFrom(_sender, address(this), _amount);\n require(success);\n\n /// @dev Allow the staking contract to access them.\n SOV.approve(address(staking), _amount);\n\n staking.stakeBySchedule(_amount, cliff, duration, FOUR_WEEKS, address(this), tokenOwner);\n\n emit TokensStaked(_sender, _amount);\n }\n\n /**\n * @notice Delegate votes from `msg.sender` which are locked until lockDate\n * to `delegatee`.\n * @param _delegatee The address to delegate votes to.\n * */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i <= endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n\n /**\n * @notice Withdraws unlocked tokens from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * */\n function withdrawTokens(address receiver) public onlyOwners {\n uint256 startFrom = startDate + cliff;\n _withdrawTokens(receiver, startFrom, block.timestamp);\n }\n\n /**\n * @notice Withdraws unlocked tokens partially (based on the max withdraw iteration that has been set) from the staking contract and\n * forwards them to an address specified by the token owner.\n * @param receiver The receiving address.\n * @param startFrom The start value for the iterations.\n * @param maxWithdrawIterations max withdrawal iteration to work around block gas limit issue.\n * */\n function withdrawTokensStartingFrom(\n address receiver,\n uint256 startFrom,\n uint256 maxWithdrawIterations\n ) public onlyOwners {\n uint256 defaultStartFrom = startDate + cliff;\n\n startFrom = _timestampToLockDate(startFrom);\n startFrom = startFrom < defaultStartFrom ? defaultStartFrom : startFrom;\n\n // @dev max iterations need to be decreased by 1, otherwise the iteration will always be surplus by 1\n uint256 maxWithdrawDate = (startFrom + (FOUR_WEEKS * (maxWithdrawIterations.sub(1))));\n uint256 endAt = endDate < maxWithdrawDate ? endDate : maxWithdrawDate;\n _withdrawTokens(receiver, startFrom, endAt);\n }\n\n /**\n * @notice Withdraws tokens from the staking contract and forwards them\n * to an address specified by the token owner. Low level function.\n * @dev Once here the caller permission is taken for granted.\n * @param receiver The receiving address.\n * @param startFrom start withdrawal from date.\n * @param endAt end time for regular withdrawal\n * or just unlocked tokens (false).\n * */\n function _withdrawTokens(\n address receiver,\n uint256 startFrom,\n uint256 endAt\n ) internal {\n require(receiver != address(0), \"receiver address invalid\");\n\n uint96 stake;\n\n /// @dev Usually we just need to iterate over the possible dates until now.\n uint256 end;\n\n if (staking.allUnlocked()) {\n end = endAt < endDate ? endAt : endDate;\n } else {\n end = endAt < block.timestamp ? endAt : block.timestamp;\n if (end > endDate) end = endDate;\n }\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startFrom; i <= end; i += FOUR_WEEKS) {\n /// @dev Read amount to withdraw.\n stake = staking.getPriorUserStakeByDate(address(this), i, block.number - 1);\n\n /// @dev Withdraw if > 0\n if (stake > 0) {\n staking.withdraw(stake, i, receiver);\n }\n }\n\n emit TokensWithdrawn(msg.sender, receiver, startFrom, end);\n }\n\n /**\n * @notice Collect dividends from fee sharing proxy.\n * @param _loanPoolToken The loan pool token address.\n * @param _maxCheckpoints Maximum number of checkpoints to be processed.\n * @param _receiver The receiver of tokens or msg.sender\n * */\n function collectDividends(\n address _loanPoolToken,\n uint32 _maxCheckpoints,\n address _receiver\n ) public onlyOwners {\n require(_receiver != address(0), \"receiver address invalid\");\n\n /// @dev Invokes the fee sharing proxy.\n feeSharingCollector.withdraw(_loanPoolToken, _maxCheckpoints, _receiver);\n\n emit DividendsCollected(msg.sender, _loanPoolToken, _receiver, _maxCheckpoints);\n }\n\n /**\n * @notice Allows the owners to migrate the positions\n * to a new staking contract.\n * */\n function migrateToNewStakingContract() public onlyOwners {\n staking.migrateToNewStakingContract();\n staking = IStaking(staking.newStakingContract());\n emit MigratedToNewStakingContract(msg.sender, address(staking));\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getToken function to\n * register SOV token on this contract.\n * @return The address of SOV token.\n * */\n function _getToken() internal view returns (address) {\n return address(SOV);\n }\n\n /**\n * @notice Overrides default ApprovalReceiver._getSelectors function to\n * register stakeTokensWithApproval selector on this contract.\n * @return The array of registered selectors on this contract.\n * */\n function _getSelectors() internal pure returns (bytes4[] memory) {\n bytes4[] memory selectors = new bytes4[](1);\n selectors[0] = this.stakeTokensWithApproval.selector;\n return selectors;\n }\n\n function _timestampToLockDate(uint256 timestamp) internal view returns (uint256 lockDate) {\n // Optimize gas costs by reading kickoffTS from storage only once.\n uint256 start = startDate + cliff;\n require(timestamp >= start, \"timestamp < contract creation\"); // WS23\n /**\n * @dev If staking timestamp does not match any of the unstaking dates\n * , set the lockDate to the closest one before the timestamp.\n * E.g. Passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks.\n * */\n uint256 periodFromKickoff = (timestamp - start) / FOUR_WEEKS;\n lockDate = periodFromKickoff * FOUR_WEEKS + start;\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title Vesting Registry contract.\n *\n * @notice On January 25, 2020, Sovryn launched the Genesis Reservation system.\n * Sovryn community members who controlled a special NFT were granted access to\n * stake BTC or rBTC for cSOV tokens at a rate of 2500 satoshis per cSOV. Per\n * SIP-0003, up to 2,000,000 cSOV were made available in the Genesis event,\n * which will be redeemable on a 1:1 basis for cSOV, subject to approval by\n * existing SOV holders.\n *\n * On 15 Feb 2021 Sovryn is taking another step in its journey to decentralized\n * financial sovereignty with the vote on SIP 0005. This proposal will enable\n * participants of the Genesis Reservation system to redeem their reserved cSOV\n * tokens for SOV. They will also have the choice to redeem cSOV for rBTC if\n * they decide to exit the system.\n *\n * This contract deals with the vesting and redemption of cSOV tokens.\n * */\ncontract VestingRegistry is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The cSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract.\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVReImburse(address from, uint256 CSOVamount, uint256 reImburseAmount);\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing collector proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n //---ACL------------------------------------------------------------------\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * TODO: This ACL logic should be available on OpenZeppeling Ownable.sol\n * or on our own overriding sovrynOwnable. This same logic is repeated\n * on OriginInvestorsClaim.sol, TokenSender.sol and VestingRegistry2.sol\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice cSOV payout to sender with rBTC currency.\n * 1.- Check holder cSOV balance by adding up every cSOV token balance.\n * 2.- ReImburse rBTC if funds available.\n * 3.- And store holder address in processedList.\n */\n function reImburse() public isNotProcessed isNotBlacklisted {\n uint256 CSOVAmountWei = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n CSOVAmountWei = CSOVAmountWei.add(balance);\n }\n\n require(CSOVAmountWei > lockedAmount[msg.sender], \"holder has no CSOV\");\n CSOVAmountWei -= lockedAmount[msg.sender];\n processedList[msg.sender] = true;\n\n /**\n * @dev Found and fixed the SIP-0007 bug on VestingRegistry::reImburse formula.\n * More details at Documenting Code issues at point 11 in\n * https://docs.google.com/document/d/10idTD1K6JvoBmtPKGuJ2Ub_mMh6qTLLlTP693GQKMyU/\n * Previous buggy code: uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**10);\n * */\n uint256 reImburseAmount = (CSOVAmountWei.mul(priceSats)).div(10**8);\n require(address(this).balance >= reImburseAmount, \"Not enough funds to reimburse\");\n msg.sender.transfer(reImburseAmount);\n\n emit CSOVReImburse(msg.sender, CSOVAmountWei, reImburseAmount);\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice Exchange cSOV to SOV with 1:1 rate\n */\n function exchangeAllCSOV() public isNotProcessed isNotBlacklisted {\n processedList[msg.sender] = true;\n\n uint256 amount = 0;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n address CSOV = CSOVtokens[i];\n uint256 balance = IERC20(CSOV).balanceOf(msg.sender);\n amount += balance;\n }\n\n require(amount > lockedAmount[msg.sender], \"amount invalid\");\n amount -= lockedAmount[msg.sender];\n\n _createVestingForCSOV(amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule.\n * @param _vesting The address of Vesting contract.\n * @param _amount The amount of tokens to stake.\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n /// @dev TODO: Owner of OwnerVesting contracts - the same address as tokenOwner.\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry2.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\n/**\n * @title VestingRegistry 2 contract.\n * @notice One time contract needed to distribute tokens to origin sales investors.\n * */\ncontract VestingRegistry2 is Ownable {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice Constant used for computing the vesting dates.\n uint256 public constant FOUR_WEEKS = 4 weeks;\n\n uint256 public constant CSOV_VESTING_CLIFF = FOUR_WEEKS;\n uint256 public constant CSOV_VESTING_DURATION = 10 * FOUR_WEEKS;\n\n IVestingFactory public vestingFactory;\n\n /// @notice The SOV token contract.\n address public SOV;\n\n /// @notice The CSOV token contracts.\n address[] public CSOVtokens;\n\n uint256 public priceSats;\n\n /// @notice The staking contract address.\n address public staking;\n\n /// @notice Fee sharing proxy.\n address public feeSharingCollector;\n\n /// @notice The vesting owner (e.g. governance timelock address).\n address public vestingOwner;\n\n /// @dev TODO: Add to the documentation: address can have only one vesting of each type.\n /// @dev user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n /**\n * @dev Struct can be created to save storage slots, but it doesn't make\n * sense. We don't have a lot of blacklisted accounts or account with\n * locked amount.\n * */\n\n /// @dev user => flag whether user has already exchange cSOV or got a reimbursement.\n mapping(address => bool) public processedList;\n\n /// @dev user => flag whether user shouldn't be able to exchange or reimburse.\n mapping(address => bool) public blacklist;\n\n /// @dev user => amount of tokens should not be processed.\n mapping(address => uint256) public lockedAmount;\n\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, // MultisigVesting\n Vesting // TokenHolderVesting\n }\n\n /* Events */\n\n event CSOVTokensExchanged(address indexed caller, uint256 amount);\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /* Functions */\n\n /**\n * @notice Contract deployment settings.\n * @param _vestingFactory The address of vesting factory contract.\n * @param _SOV The SOV token address.\n * @param _CSOVtokens The array of cSOV tokens.\n * @param _priceSats The price of cSOV tokens in satoshis.\n * @param _staking The address of staking contract.\n * @param _feeSharingCollector The address of fee sharing proxy contract.\n * @param _vestingOwner The address of an owner of vesting contract.\n * @dev On Sovryn the vesting owner is Exchequer Multisig.\n * According to SIP-0007 The Exchequer Multisig is designated to hold\n * certain funds in the form of rBTC and SOV, in order to allow for\n * flexible deployment of such funds on:\n * + facilitating rBTC redemptions for Genesis pre-sale participants.\n * + deploying of SOV for the purposes of exchange listings, market\n * making, and partnerships with third parties.\n * */\n constructor(\n address _vestingFactory,\n address _SOV,\n address[] memory _CSOVtokens,\n uint256 _priceSats,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n _setCSOVtokens(_CSOVtokens);\n\n SOV = _SOV;\n priceSats = _priceSats;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n //---PostCSOV--------------------------------------------------------------\n\n modifier isNotProcessed() {\n require(!processedList[msg.sender], \"Address cannot be processed twice\");\n _;\n }\n\n modifier isNotBlacklisted() {\n require(!blacklist[msg.sender], \"Address blacklisted\");\n _;\n }\n\n /**\n * @notice Get contract balance.\n * @return The token balance of the contract.\n * */\n function budget() external view returns (uint256) {\n uint256 SCBudget = address(this).balance;\n return SCBudget;\n }\n\n /**\n * @notice Deposit function to receiving value (rBTC).\n * */\n function deposit() public payable {}\n\n /**\n * @notice Send all contract balance to an account.\n * @param to The account address to send the balance to.\n * */\n function withdrawAll(address payable to) public onlyOwner {\n to.transfer(address(this).balance);\n }\n\n //--------------------------------------------------------------------------------------------------------------------------------------\n\n /**\n * @notice Sets vesting factory address. High level endpoint.\n * @param _vestingFactory The address of vesting factory contract.\n *\n * @dev Splitting code on two functions: high level and low level\n * is a pattern that makes easy to extend functionality in a readable way,\n * without accidentally breaking the actual action being performed.\n * For example, checks should be done on high level endpoint, while core\n * functionality should be coded on the low level function.\n * */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets vesting factory address. Low level core function.\n * @param _vestingFactory The address of vesting factory contract.\n * */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Sets cSOV tokens array. High level endpoint.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function setCSOVtokens(address[] memory _CSOVtokens) public onlyOwner {\n _setCSOVtokens(_CSOVtokens);\n }\n\n /**\n * @notice Sets cSOV tokens array by looping through input. Low level function.\n * @param _CSOVtokens The array of cSOV tokens.\n * */\n function _setCSOVtokens(address[] memory _CSOVtokens) internal {\n for (uint256 i = 0; i < _CSOVtokens.length; i++) {\n require(_CSOVtokens[i] != address(0), \"CSOV address invalid\");\n }\n CSOVtokens = _CSOVtokens;\n }\n\n /**\n * @notice Set blacklist flag (true/false).\n * @param _account The address to be blacklisted.\n * @param _blacklisted The flag to add/remove to/from a blacklist.\n * */\n function setBlacklistFlag(address _account, bool _blacklisted) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n\n blacklist[_account] = _blacklisted;\n }\n\n /**\n * @notice Set amount to be subtracted from user token balance.\n * @param _account The address with locked amount.\n * @param _amount The amount to be locked.\n * */\n function setLockedAmount(address _account, uint256 _amount) public onlyOwner {\n require(_account != address(0), \"account address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n lockedAmount[_account] = _amount;\n }\n\n /**\n * @notice Transfer SOV tokens to given address.\n *\n * @dev This is a wrapper for ERC-20 transfer function w/\n * additional checks and triggering an event.\n *\n * @param _receiver The address of the SOV receiver.\n * @param _amount The amount to be transferred.\n * */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice cSOV tokens are moved and staked on Vesting contract.\n * @param _amount The amount of tokens to be vested.\n * */\n function _createVestingForCSOV(uint256 _amount) internal {\n address vesting =\n _getOrCreateVesting(msg.sender, CSOV_VESTING_CLIFF, CSOV_VESTING_DURATION);\n\n IERC20(SOV).approve(vesting, _amount);\n IVesting(vesting).stakeTokens(_amount);\n\n emit CSOVTokensExchanged(msg.sender, _amount);\n }\n\n /**\n * @notice Check a token address is among the cSOV token addresses.\n * @param _CSOV The cSOV token address.\n * */\n function _validateCSOV(address _CSOV) internal view {\n bool isValid = false;\n for (uint256 i = 0; i < CSOVtokens.length; i++) {\n if (_CSOV == CSOVtokens[i]) {\n isValid = true;\n break;\n }\n }\n require(isValid, \"wrong CSOV address\");\n }\n\n /**\n * @notice Create Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Create Team Vesting contract.\n * @param _tokenOwner The owner of the tokens.\n * @param _amount The amount to be staked.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice Stake tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n * */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice Query the vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The vesting contract address for the given token owner.\n * */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice Query the team vesting contract for an account.\n * @param _tokenOwner The owner of the tokens.\n * @return The team vesting contract address for the given token owner.\n * */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n /**\n * @notice If not exists, deploy a vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n /**\n * @notice If not exists, deploy a team vesting contract through factory.\n * @param _tokenOwner The owner of the tokens.\n * @param _cliff The time interval to the first withdraw in seconds.\n * @param _duration The total duration in seconds.\n * @return The team vesting contract address for the given token owner\n * whether it existed previously or not.\n * */\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistry3.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"../../openzeppelin/SafeMath.sol\";\n\ncontract VestingRegistry3 is Ownable {\n using SafeMath for uint256;\n\n IVestingFactory public vestingFactory;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n //@notice fee sharing proxy\n address public feeSharingCollector;\n //@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n //TODO add to the documentation: address can have only one vesting of each type\n //user => vesting type => vesting contract\n mapping(address => mapping(uint256 => address)) public vestingContracts;\n\n //user => flag whether user has admin role\n mapping(address => bool) public admins;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n constructor(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner\n ) public {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n\n _setVestingFactory(_vestingFactory);\n\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) public onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) public onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n\n IERC20(SOV).transfer(_receiver, _amount);\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateVesting(_tokenOwner, _cliff, _duration);\n emit VestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) public onlyAuthorized {\n address vesting = _getOrCreateTeamVesting(_tokenOwner, _cliff, _duration);\n emit TeamVestingCreated(_tokenOwner, vesting, _cliff, _duration, _amount);\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) public onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.Vesting)];\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n */\n function getTeamVesting(address _tokenOwner) public view returns (address) {\n return vestingContracts[_tokenOwner][uint256(VestingType.TeamVesting)];\n }\n\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n //TODO Owner of OwnerVesting contracts - the same address as tokenOwner\n address vesting =\n vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n\n function _getOrCreateTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration\n ) internal returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n if (vestingContracts[_tokenOwner][type_] == address(0)) {\n address vesting =\n vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n vestingContracts[_tokenOwner][type_] = vesting;\n }\n return vestingContracts[_tokenOwner][type_];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryLogic.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../interfaces/IERC20.sol\";\nimport \"../IFeeSharingCollector.sol\";\nimport \"./IVesting.sol\";\nimport \"./ITeamVesting.sol\";\nimport \"./VestingRegistryStorage.sol\";\n\ncontract VestingRegistryLogic is VestingRegistryStorage {\n event SOVTransferred(address indexed receiver, uint256 amount);\n event VestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TeamVestingCreated(\n address indexed tokenOwner,\n address vesting,\n uint256 cliff,\n uint256 duration,\n uint256 amount,\n uint256 vestingCreationType\n );\n event TokensStaked(address indexed vesting, uint256 amount);\n event VestingCreationAndTypesSet(\n address indexed vesting,\n VestingCreationAndTypeDetails vestingCreationAndType\n );\n\n /**\n * @notice Replace constructor with initialize function for Upgradable Contracts\n * This function will be called only once by the owner\n * */\n function initialize(\n address _vestingFactory,\n address _SOV,\n address _staking,\n address _feeSharingCollector,\n address _vestingOwner,\n address _lockedSOV,\n address[] calldata _vestingRegistries\n ) external onlyOwner initializer {\n require(_SOV != address(0), \"SOV address invalid\");\n require(_staking != address(0), \"staking address invalid\");\n require(_feeSharingCollector != address(0), \"feeSharingCollector address invalid\");\n require(_vestingOwner != address(0), \"vestingOwner address invalid\");\n require(_lockedSOV != address(0), \"LockedSOV address invalid\");\n\n _setVestingFactory(_vestingFactory);\n SOV = _SOV;\n staking = _staking;\n feeSharingCollector = _feeSharingCollector;\n vestingOwner = _vestingOwner;\n lockedSOV = LockedSOV(_lockedSOV);\n for (uint256 i = 0; i < _vestingRegistries.length; i++) {\n require(_vestingRegistries[i] != address(0), \"Vesting registry address invalid\");\n vestingRegistries.push(IVestingRegistry(_vestingRegistries[i]));\n }\n }\n\n /**\n * @notice sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function setVestingFactory(address _vestingFactory) external onlyOwner {\n _setVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice Internal function that sets vesting factory address\n * @param _vestingFactory the address of vesting factory contract\n */\n function _setVestingFactory(address _vestingFactory) internal {\n require(_vestingFactory != address(0), \"vestingFactory address invalid\");\n vestingFactory = IVestingFactory(_vestingFactory);\n }\n\n /**\n * @notice transfers SOV tokens to given address\n * @param _receiver the address of the SOV receiver\n * @param _amount the amount to be transferred\n */\n function transferSOV(address _receiver, uint256 _amount) external onlyOwner {\n require(_receiver != address(0), \"receiver address invalid\");\n require(_amount != 0, \"amount invalid\");\n require(IERC20(SOV).transfer(_receiver, _amount), \"transfer failed\");\n emit SOVTransferred(_receiver, _amount);\n }\n\n /**\n * @notice adds vestings that were deployed in previous vesting registries\n * @dev migration of data from previous vesting registy contracts\n */\n function addDeployedVestings(\n address[] calldata _tokenOwners,\n uint256[] calldata _vestingCreationTypes\n ) external onlyAuthorized {\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingCreationTypes[i] > 0, \"vesting creation type must be greater than 0\");\n _addDeployedVestings(_tokenOwners[i], _vestingCreationTypes[i]);\n }\n }\n\n /**\n * @notice adds four year vestings to vesting registry logic\n * @param _tokenOwners array of token owners\n * @param _vestingAddresses array of vesting addresses\n */\n function addFourYearVestings(\n address[] calldata _tokenOwners,\n address[] calldata _vestingAddresses\n ) external onlyAuthorized {\n require(_tokenOwners.length == _vestingAddresses.length, \"arrays mismatch\");\n uint256 vestingCreationType = 4;\n uint256 cliff = 4 weeks;\n uint256 duration = 156 weeks;\n for (uint256 i = 0; i < _tokenOwners.length; i++) {\n require(!isVesting[_vestingAddresses[i]], \"vesting exists\");\n require(_tokenOwners[i] != address(0), \"token owner cannot be 0 address\");\n require(_vestingAddresses[i] != address(0), \"vesting cannot be 0 address\");\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwners[i],\n uint256(VestingType.Vesting),\n cliff,\n duration,\n vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n vestingCreationType,\n _vestingAddresses[i]\n );\n vestingsOf[_tokenOwners[i]].push(uid);\n isVesting[_vestingAddresses[i]] = true;\n }\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @dev Calls a public createVestingAddr function with vestingCreationType. This is to accomodate the existing logic for LockedSOV\n * @dev vestingCreationType 0 = LockedSOV\n */\n function createVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAuthorized {\n createVestingAddr(_tokenOwner, _amount, _cliff, _duration, 3);\n }\n\n /**\n * @notice creates Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createVestingAddr(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.Vesting),\n _vestingCreationType\n );\n\n emit VestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice creates Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _amount the amount to be staked\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function createTeamVesting(\n address _tokenOwner,\n uint256 _amount,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) external onlyAuthorized {\n address vesting =\n _getOrCreateVesting(\n _tokenOwner,\n _cliff,\n _duration,\n uint256(VestingType.TeamVesting),\n _vestingCreationType\n );\n\n emit TeamVestingCreated(\n _tokenOwner,\n vesting,\n _cliff,\n _duration,\n _amount,\n _vestingCreationType\n );\n }\n\n /**\n * @notice stakes tokens according to the vesting schedule\n * @param _vesting the address of Vesting contract\n * @param _amount the amount of tokens to stake\n */\n function stakeTokens(address _vesting, uint256 _amount) external onlyAuthorized {\n require(_vesting != address(0), \"vesting address invalid\");\n require(_amount > 0, \"amount invalid\");\n\n IERC20(SOV).approve(_vesting, _amount);\n IVesting(_vesting).stakeTokens(_amount);\n emit TokensStaked(_vesting, _amount);\n }\n\n /**\n * @notice returns vesting contract address for the given token owner\n * @param _tokenOwner the owner of the tokens\n * @dev Calls a public getVestingAddr function with cliff and duration. This is to accomodate the existing logic for LockedSOV\n * @dev We need to use LockedSOV.changeRegistryCliffAndDuration function very judiciously\n * @dev vestingCreationType 0 - LockedSOV\n */\n function getVesting(address _tokenOwner) public view returns (address) {\n return getVestingAddr(_tokenOwner, lockedSOV.cliff(), lockedSOV.duration(), 3);\n }\n\n /**\n * @notice public function that returns vesting contract address for the given token owner, cliff, duration\n * @dev Important: Please use this instead of getVesting function\n */\n function getVestingAddr(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.Vesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice returns team vesting contract address for the given token owner, cliff, duration\n */\n function getTeamVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _vestingCreationType\n ) public view returns (address) {\n uint256 type_ = uint256(VestingType.TeamVesting);\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, type_, _cliff, _duration, _vestingCreationType)\n )\n );\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @dev check if the specific vesting address is team vesting or not\n * @dev read the vestingType from vestingCreationAndTypes storage\n *\n * @param _vestingAddress address of vesting contract\n *\n * @return true for teamVesting, false for normal vesting\n */\n function isTeamVesting(address _vestingAddress) external view returns (bool) {\n return (vestingCreationAndTypes[_vestingAddress].isSet &&\n vestingCreationAndTypes[_vestingAddress].vestingType ==\n uint32(VestingType.TeamVesting));\n }\n\n /**\n * @dev setter function to register existing vesting contract to vestingCreationAndTypes storage\n * @dev need to set the function visilibty to public to support VestingCreationAndTypeDetails struct as parameter\n *\n * @param _vestingAddresses array of vesting address\n * @param _vestingCreationAndTypes array for VestingCreationAndTypeDetails struct\n */\n function registerVestingToVestingCreationAndTypes(\n address[] memory _vestingAddresses,\n VestingCreationAndTypeDetails[] memory _vestingCreationAndTypes\n ) public onlyAuthorized {\n require(_vestingAddresses.length == _vestingCreationAndTypes.length, \"Unmatched length\");\n for (uint256 i = 0; i < _vestingCreationAndTypes.length; i++) {\n VestingCreationAndTypeDetails memory _vestingCreationAndType =\n _vestingCreationAndTypes[i];\n address _vestingAddress = _vestingAddresses[i];\n\n vestingCreationAndTypes[_vestingAddress] = _vestingCreationAndType;\n\n emit VestingCreationAndTypesSet(\n _vestingAddress,\n vestingCreationAndTypes[_vestingAddress]\n );\n }\n }\n\n /**\n * @notice Internal function to deploy Vesting/Team Vesting contract\n * @param _tokenOwner the owner of the tokens\n * @param _cliff the cliff in seconds\n * @param _duration the total duration in seconds\n * @param _type the type of vesting\n * @param _vestingCreationType the type of vesting created(e.g. Origin, Bug Bounty etc.)\n */\n function _getOrCreateVesting(\n address _tokenOwner,\n uint256 _cliff,\n uint256 _duration,\n uint256 _type,\n uint256 _vestingCreationType\n ) internal returns (address) {\n address vesting;\n uint256 uid =\n uint256(\n keccak256(\n abi.encodePacked(_tokenOwner, _type, _cliff, _duration, _vestingCreationType)\n )\n );\n if (vestings[uid].vestingAddress == address(0)) {\n if (_type == 1) {\n vesting = vestingFactory.deployVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n _tokenOwner\n );\n } else {\n vesting = vestingFactory.deployTeamVesting(\n SOV,\n staking,\n _tokenOwner,\n _cliff,\n _duration,\n feeSharingCollector,\n vestingOwner\n );\n }\n vestings[uid] = Vesting(_type, _vestingCreationType, vesting);\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vesting] = true;\n\n vestingCreationAndTypes[vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(_type),\n vestingCreationType: uint128(_vestingCreationType)\n });\n\n emit VestingCreationAndTypesSet(vesting, vestingCreationAndTypes[vesting]);\n }\n return vestings[uid].vestingAddress;\n }\n\n /**\n * @notice stores the addresses of Vesting contracts from all three previous versions of Vesting Registry\n */\n function _addDeployedVestings(address _tokenOwner, uint256 _vestingCreationType) internal {\n uint256 uid;\n uint256 i = _vestingCreationType - 1;\n\n address vestingAddress = vestingRegistries[i].getVesting(_tokenOwner);\n if (vestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(vestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.Vesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.Vesting),\n _vestingCreationType,\n vestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[vestingAddress] = true;\n }\n\n address teamVestingAddress = vestingRegistries[i].getTeamVesting(_tokenOwner);\n if (teamVestingAddress != address(0)) {\n VestingLogic vesting = VestingLogic(teamVestingAddress);\n uid = uint256(\n keccak256(\n abi.encodePacked(\n _tokenOwner,\n uint256(VestingType.TeamVesting),\n vesting.cliff(),\n vesting.duration(),\n _vestingCreationType\n )\n )\n );\n vestings[uid] = Vesting(\n uint256(VestingType.TeamVesting),\n _vestingCreationType,\n teamVestingAddress\n );\n vestingsOf[_tokenOwner].push(uid);\n isVesting[teamVestingAddress] = true;\n }\n }\n\n /**\n * @notice returns all vesting details for the given token owner\n */\n function getVestingsOf(address _tokenOwner) external view returns (Vesting[] memory) {\n uint256[] memory vestingIds = vestingsOf[_tokenOwner];\n uint256 length = vestingIds.length;\n Vesting[] memory _vestings = new Vesting[](vestingIds.length);\n for (uint256 i = 0; i < length; i++) {\n _vestings[i] = vestings[vestingIds[i]];\n }\n return _vestings;\n }\n\n /**\n * @notice returns cliff and duration for Vesting & TeamVesting contracts\n */\n function getVestingDetails(address _vestingAddress)\n external\n view\n returns (uint256 cliff, uint256 duration)\n {\n VestingLogic vesting = VestingLogic(_vestingAddress);\n return (vesting.cliff(), vesting.duration());\n }\n\n /**\n * @notice returns if the address is a vesting address\n */\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return isVesting[_vestingAddress];\n }\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./VestingRegistryStorage.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\n/**\n * @title Vesting Registry Proxy contract.\n * @dev Vesting Registry contract should be upgradable, use UpgradableProxy.\n * VestingRegistryStorage is deployed with the upgradable functionality\n * by using this contract instead, that inherits from UpgradableProxy\n * the possibility of being enhanced and re-deployed.\n * */\ncontract VestingRegistryProxy is VestingRegistryStorage, UpgradableProxy {\n\n}\n" + }, + "contracts/governance/Vesting/VestingRegistryStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Initializable.sol\";\nimport \"../../utils/AdminRole.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"./IVestingFactory.sol\";\nimport \"../../locked/LockedSOV.sol\";\nimport \"./IVestingRegistry.sol\";\n\n/**\n * @title Vesting Registry Storage Contract.\n *\n * @notice This contract is just the storage required for vesting registry.\n * It is parent of VestingRegistryProxy and VestingRegistryLogic.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\n\ncontract VestingRegistryStorage is Initializable, AdminRole {\n ///@notice the vesting factory contract\n IVestingFactory public vestingFactory;\n\n ///@notice the Locked SOV contract\n ///@dev NOTES: No need to update lockedSOV in this contract, since it might break the vestingRegistry if the new lockedSOV does not have the same value of cliff & duration.\n ILockedSOV public lockedSOV;\n\n ///@notice the list of vesting registries\n IVestingRegistry[] public vestingRegistries;\n\n ///@notice the SOV token contract\n address public SOV;\n\n ///@notice the staking contract address\n address public staking;\n\n ///@notice fee sharing proxy\n address public feeSharingCollector;\n\n ///@notice the vesting owner (e.g. governance timelock address)\n address public vestingOwner;\n\n enum VestingType {\n TeamVesting, //MultisigVesting\n Vesting //TokenHolderVesting\n }\n\n ///@notice Vesting details\n struct Vesting {\n uint256 vestingType;\n uint256 vestingCreationType;\n address vestingAddress;\n }\n\n ///@notice A record of vesting details for a unique id\n ///@dev vestings[uid] returns vesting data\n mapping(uint256 => Vesting) public vestings;\n\n ///@notice A record of all unique ids for a particular token owner\n ///@dev vestingsOf[tokenOwner] returns array of unique ids\n mapping(address => uint256[]) public vestingsOf;\n\n ///@notice A record of all vesting addresses\n ///@dev isVesting[address] returns if the address is a vesting address\n mapping(address => bool) public isVesting;\n\n /// @notice Store vesting creation type & vesting type information\n /// @dev it is packed into 1 single storage slot for cheaper gas usage\n struct VestingCreationAndTypeDetails {\n bool isSet;\n uint32 vestingType;\n uint128 vestingCreationType;\n }\n\n ///@notice A record of all vesting addresses with the detail\n ///@dev vestingDetail[vestingAddress] returns Vesting struct data\n ///@dev can be used to easily check the vesting type / creation type based on the vesting address itself\n mapping(address => VestingCreationAndTypeDetails) public vestingCreationAndTypes;\n}\n" + }, + "contracts/governance/Vesting/VestingStorage.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../openzeppelin/Ownable.sol\";\nimport \"../../interfaces/IERC20.sol\";\nimport \"../Staking/interfaces/IStaking.sol\";\nimport \"../IFeeSharingCollector.sol\";\n\n/**\n * @title Vesting Storage Contract.\n *\n * @notice This contract is just the storage required for vesting.\n * It is parent of VestingLogic and TeamVesting.\n *\n * @dev Use Ownable as a parent to align storage structure for Logic and Proxy contracts.\n * */\ncontract VestingStorage is Ownable {\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The staking contract address.\n IStaking public staking;\n\n /// @notice The owner of the vested tokens.\n address public tokenOwner;\n\n /// @notice Fee sharing Proxy.\n IFeeSharingCollector public feeSharingCollector;\n\n /// @notice The cliff. After this time period the tokens begin to unlock.\n uint256 public cliff;\n\n /// @notice The duration. After this period all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The start date of the vesting.\n uint256 public startDate;\n\n /// @notice The end date of the vesting.\n uint256 public endDate;\n\n /// @notice Constant used for computing the vesting dates.\n uint256 constant FOUR_WEEKS = 4 weeks;\n}\n" + }, + "contracts/interfaces/IChai.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IERC20.sol\";\n\ninterface IPot {\n function dsr() external view returns (uint256);\n\n function chi() external view returns (uint256);\n\n function rho() external view returns (uint256);\n}\n\ncontract IChai is IERC20 {\n function move(\n address src,\n address dst,\n uint256 wad\n ) external returns (bool);\n\n function join(address dst, uint256 wad) external;\n\n function draw(address src, uint256 wad) external;\n\n function exit(address src, uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IConverterAMM.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\ninterface IConverterAMM {\n function withdrawFees(address receiver) external returns (uint256);\n}\n" + }, + "contracts/interfaces/IERC20.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ncontract IERC20 {\n string public name;\n uint8 public decimals;\n string public symbol;\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address _who) external view returns (uint256);\n\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function approve(address _spender, uint256 _value) external returns (bool);\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/interfaces/IERC777.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777Token standard as defined in the EIP.\n *\n * This contract uses the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let\n * token holders and recipients react to token movements by using setting implementers\n * for the associated interfaces in said registry. See {IERC1820Registry} and\n * {ERC1820Implementer}.\n */\ninterface IERC777 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the smallest part of the token that is not divisible. This\n * means all token operations (creation, movement and destruction) must have\n * amounts that are a multiple of this number.\n *\n * For most token contracts, this value will equal 1.\n */\n function granularity() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by an account (`owner`).\n */\n function balanceOf(address owner) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * If send or receive hooks are registered for the caller and `recipient`,\n * the corresponding functions will be called with `data` and empty\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes calldata data\n ) external;\n\n /**\n * @dev Destroys `amount` tokens from the caller's account, reducing the\n * total supply.\n *\n * If a send hook is registered for the caller, the corresponding function\n * will be called with `data` and empty `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - the caller must have at least `amount` tokens.\n */\n function burn(uint256 amount, bytes calldata data) external;\n\n /**\n * @dev Returns true if an account is an operator of `tokenHolder`.\n * Operators can send and burn tokens on behalf of their owners. All\n * accounts are their own operator.\n *\n * See {operatorSend} and {operatorBurn}.\n */\n function isOperatorFor(address operator, address tokenHolder) external view returns (bool);\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor}.\n *\n * Emits an {AuthorizedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function authorizeOperator(address operator) external;\n\n /**\n * @dev Make an account an operator of the caller.\n *\n * See {isOperatorFor} and {defaultOperators}.\n *\n * Emits a {RevokedOperator} event.\n *\n * Requirements\n *\n * - `operator` cannot be calling address.\n */\n function revokeOperator(address operator) external;\n\n /**\n * @dev Returns the list of default operators. These accounts are operators\n * for all token holders, even if {authorizeOperator} was never called on\n * them.\n *\n * This list is immutable, but individual holders may revoke these via\n * {revokeOperator}, in which case {isOperatorFor} will return false.\n */\n function defaultOperators() external view returns (address[] memory);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must\n * be an operator of `sender`.\n *\n * If send or receive hooks are registered for `sender` and `recipient`,\n * the corresponding functions will be called with `data` and\n * `operatorData`. See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits a {Sent} event.\n *\n * Requirements\n *\n * - `sender` cannot be the zero address.\n * - `sender` must have at least `amount` tokens.\n * - the caller must be an operator for `sender`.\n * - `recipient` cannot be the zero address.\n * - if `recipient` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n /**\n * @dev Destoys `amount` tokens from `account`, reducing the total supply.\n * The caller must be an operator of `account`.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `data` and `operatorData`. See {IERC777Sender}.\n *\n * Emits a {Burned} event.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n * - the caller must be an operator for `account`.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes calldata data,\n bytes calldata operatorData\n ) external;\n\n event Sent(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Minted(\n address indexed operator,\n address indexed to,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event Burned(\n address indexed operator,\n address indexed from,\n uint256 amount,\n bytes data,\n bytes operatorData\n );\n\n event AuthorizedOperator(address indexed operator, address indexed tokenHolder);\n\n event RevokedOperator(address indexed operator, address indexed tokenHolder);\n}\n" + }, + "contracts/interfaces/IERC777Recipient.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP.\n *\n * Accounts can be notified of {IERC777} tokens being sent to them by having a\n * contract implement this interface (contract holders can be their own\n * implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Recipient {\n /**\n * @dev Called by an {IERC777} token contract whenever tokens are being\n * moved or created into a registered account (`to`). The type of operation\n * is conveyed by `from` being the zero address or not.\n *\n * This call occurs _after_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the post-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/IERC777Sender.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC777TokensSender standard as defined in the EIP.\n *\n * {IERC777} Token holders can be notified of operations performed on their\n * tokens by having a contract implement this interface (contract holders can be\n * their own implementer) and registering it on the\n * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry].\n *\n * See {IERC1820Registry} and {ERC1820Implementer}.\n */\ninterface IERC777Sender {\n /**\n * @dev Called by an {IERC777} token contract whenever a registered holder's\n * (`from`) tokens are about to be moved or destroyed. The type of operation\n * is conveyed by `to` being the zero address or not.\n *\n * This call occurs _before_ the token contract's state is updated, so\n * {IERC777-balanceOf}, etc., can be used to query the pre-operation state.\n *\n * This function may revert to prevent the operation from being executed.\n */\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes calldata userData,\n bytes calldata operatorData\n ) external;\n}\n" + }, + "contracts/interfaces/ILoanPool.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface ILoanPool {\n function tokenPrice() external view returns (uint256 price);\n\n function borrowInterestRate() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n}\n" + }, + "contracts/interfaces/ILoanTokenModules.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\ninterface ILoanTokenModules {\n /** EVENT */\n /// topic: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /// topic: 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /// topic: 0x628e75c63c1873bcd3885f7aee9f58ee36f60dc789b2a6b3a978c4189bc548ba\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n\n /// topic: 0xb4c03061fb5b7fed76389d5af8f2e0ddb09f8c70d1333abbb62582835e10accb\n event Mint(address indexed minter, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0x743033787f4738ff4d6a7225ce2bd0977ee5f86b91a902a58f5e4d0b297b4644\n event Burn(address indexed burner, uint256 tokenAmount, uint256 assetAmount, uint256 price);\n\n /// topic: 0xc688ff9bd4a1c369dd44c5cf64efa9db6652fb6b280aa765cd43f17d256b816e\n event FlashBorrow(address borrower, address target, address loanToken, uint256 loanAmount);\n\n /// topic: 0x9bbd2de400810774339120e2f8a2b517ed748595e944529bba8ebabf314d0591\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n event WithdrawRBTCTo(address indexed to, uint256 amount);\n\n event ToggledFunctionPaused(string functionId, bool prevFlag, bool newFlag);\n\n /** INTERFACE */\n\n /** START LOAN TOKEN SETTINGS LOWER ADMIN */\n struct LoanParams {\n /// @dev ID of loan params object.\n bytes32 id;\n /// @dev If false, this object has been disabled by the owner and can't\n /// be used for future loans.\n bool active;\n /// @dev Owner of this object.\n address owner;\n /// @dev The token being loaned.\n address loanToken;\n /// @dev The required collateral token.\n address collateralToken;\n /// @dev The minimum allowed initial margin.\n uint256 minInitialMargin;\n /// @dev An unhealthy loan when current margin is at or below this value.\n uint256 maintenanceMargin;\n /// @dev The maximum term for new loans (0 means there's no max term).\n uint256 maxLoanTerm;\n }\n\n function setAdmin(address _admin) external;\n\n function setPauser(address _pauser) external;\n\n function setupLoanParams(LoanParams[] calldata loanParamsList, bool areTorqueLoans) external;\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external;\n\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) external;\n\n function toggleFunctionPause(\n string calldata funcId, /// example: \"mint(uint256,uint256)\"\n bool isPaused\n ) external;\n\n function setTransactionLimits(address[] calldata addresses, uint256[] calldata limits)\n external;\n\n function changeLoanTokenNameAndSymbol(string calldata _name, string calldata _symbol) external;\n\n /** END LOAN TOKEN SETTINGS LOWER ADMIN */\n\n /** START LOAN TOKEN LOGIC STANDARD */\n function marginTrade(\n bytes32 loanId, /// 0 if new loan\n uint256 leverageAmount, /// Expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5).\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n bytes calldata loanDataBytes /// Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function marginTradeAffiliate(\n bytes32 loanId, // 0 if new loan\n uint256 leverageAmount, // expected in x * 10**18 where x is the actual leverage (2, 3, 4, or 5)\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress,\n address trader,\n uint256 minEntryPrice, // Value of loan token in collateral.\n address affiliateReferrer, // The user was brought by the affiliate (referrer).\n bytes calldata loanDataBytes // Arbitrary order data.\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to trade.\n );\n\n function borrowInterestRate() external view returns (uint256);\n\n function mint(address receiver, uint256 depositAmount) external returns (uint256 mintAmount);\n\n function burn(address receiver, uint256 burnAmount) external returns (uint256 loanAmountPaid);\n\n function checkPause(string calldata funcId) external view returns (bool isPaused);\n\n function nextBorrowInterestRate(uint256 borrowAmount) external view returns (uint256);\n\n function totalAssetBorrow() external view returns (uint256);\n\n function totalAssetSupply() external view returns (uint256);\n\n function borrow(\n bytes32 loanId, /// 0 if new loan.\n uint256 withdrawAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n uint256 collateralTokenSent, /// If 0, loanId must be provided; any rBTC sent must equal this value.\n address collateralTokenAddress, /// If address(0), this means rBTC and rBTC must be sent with the call or loanId must be provided.\n address borrower,\n address receiver,\n bytes calldata /// loanDataBytes: arbitrary order data (for future use).\n )\n external\n payable\n returns (\n uint256,\n uint256 /// Returns new principal and new collateral added to loan.\n );\n\n function transfer(address _to, uint256 _value) external returns (bool);\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) external returns (bool);\n\n function setLiquidityMiningAddress(address LMAddress) external;\n\n function getLiquidityMiningAddress() external view returns (address);\n\n function setStakingContractAddress(address _stakingContractAddress) external;\n\n function getStakingContractAddress() external view returns (address);\n\n function getEstimatedMarginDetails(\n uint256 leverageAmount,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n address collateralTokenAddress // address(0) means ETH\n )\n external\n view\n returns (\n uint256 principal,\n uint256 collateral,\n uint256 interestRate\n );\n\n function getDepositAmountForBorrow(\n uint256 borrowAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 depositAmount);\n\n function getBorrowAmountForDeposit(\n uint256 depositAmount,\n uint256 initialLoanDuration, /// Duration in seconds.\n address collateralTokenAddress /// address(0) means rBTC\n ) external view returns (uint256 borrowAmount);\n\n function checkPriceDivergence(\n uint256 loanTokenSent,\n address collateralTokenAddress,\n uint256 minEntryPrice\n ) external view;\n\n function getMaxEscrowAmount(uint256 leverageAmount)\n external\n view\n returns (uint256 maxEscrowAmount);\n\n function checkpointPrice(address _user) external view returns (uint256 price);\n\n function assetBalanceOf(address _owner) external view returns (uint256);\n\n function profitOf(address user) external view returns (int256);\n\n function tokenPrice() external view returns (uint256 price);\n\n function avgBorrowInterestRate() external view returns (uint256);\n\n function supplyInterestRate() external view returns (uint256);\n\n function nextSupplyInterestRate(uint256 supplyAmount) external view returns (uint256);\n\n function totalSupplyInterestRate(uint256 assetSupply) external view returns (uint256);\n\n function loanTokenAddress() external view returns (address);\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n external\n view\n returns (uint256, uint256);\n\n function withdrawRBTCTo(address payable _receiverAddress, uint256 _amount) external;\n\n /** START LOAN TOKEN BASE */\n function initialPrice() external view returns (uint256);\n\n /** START LOAN TOKEN LOGIC LM */\n function mint(\n address receiver,\n uint256 depositAmount,\n bool useLM\n ) external returns (uint256 minted);\n\n function burn(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 redeemed);\n\n /** START LOAN TOKEN LOGIC WRBTC */\n function mintWithBTC(address receiver, bool useLM)\n external\n payable\n returns (uint256 mintAmount);\n\n function burnToBTC(\n address receiver,\n uint256 burnAmount,\n bool useLM\n ) external returns (uint256 loanAmountPaid);\n\n function marketLiquidity() external view returns (uint256);\n\n function calculateSupplyInterestRate(uint256 assetBorrow, uint256 assetSupply)\n external\n view\n returns (uint256);\n\n /** START LOAN TOKEN LOGIC STORAGE */\n function pauser() external view returns (address);\n\n function liquidityMiningAddress() external view returns (address);\n\n function name() external view returns (string memory);\n\n function symbol() external view returns (string memory);\n\n /** START ADVANCED TOKEN */\n function approve(address _spender, uint256 _value) external returns (bool);\n\n /** START ADVANCED TOKEN STORAGE */\n function allowance(address _owner, address _spender) external view returns (uint256);\n\n function balanceOf(address _owner) external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function loanParamsIds(uint256) external view returns (bytes32);\n}\n" + }, + "contracts/interfaces/ISovryn.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\npragma experimental ABIEncoderV2;\n//TODO: stored in ./interfaces only while brownie isn't removed\n//TODO: move to contracts/interfaces after with brownie is removed\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\ncontract ISovryn is\n State,\n ProtocolSettingsEvents,\n LoanSettingsEvents,\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n LoanClosingsEvents,\n SwapsEvents,\n AffiliatesEvents,\n FeesEvents\n{\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n ////// Protocol //////\n\n function replaceContract(address target) external;\n\n function setTargets(string[] calldata sigsArr, address[] calldata targetsArr) external;\n\n function getTarget(string calldata sig) external view returns (address);\n\n ////// Protocol Settings //////\n\n function setSovrynProtocolAddress(address newProtocolAddress) external;\n\n function setSOVTokenAddress(address newSovTokenAddress) external;\n\n function setLockedSOVAddress(address newSOVLockedAddress) external;\n\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals) external;\n\n function setPriceFeedContract(address newContract) external;\n\n function setSwapsImplContract(address newContract) external;\n\n function setLoanPool(address[] calldata pools, address[] calldata assets) external;\n\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles) external;\n\n function setLendingFeePercent(uint256 newValue) external;\n\n function setTradingFeePercent(uint256 newValue) external;\n\n function setBorrowingFeePercent(uint256 newValue) external;\n\n function setSwapExternalFeePercent(uint256 newValue) external;\n\n function setAffiliateFeePercent(uint256 newValue) external;\n\n function setAffiliateTradingTokenFeePercent(uint256 newValue) external;\n\n function setLiquidationIncentivePercent(uint256 newAmount) external;\n\n function setMaxDisagreement(uint256 newAmount) external;\n\n function setSourceBuffer(uint256 newAmount) external;\n\n function setMaxSwapSize(uint256 newAmount) external;\n\n function setFeesController(address newController) external;\n\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n returns (uint256 totalWRBTCWithdrawn);\n\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external returns (bool);\n\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n returns (address, bool);\n\n function depositProtocolToken(uint256 amount) external;\n\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory);\n\n function isLoanPool(address loanPool) external view returns (bool);\n\n function setWrbtcToken(address wrbtcTokenAddress) external;\n\n function setSovrynSwapContractRegistryAddress(address registryAddress) external;\n\n function setProtocolTokenAddress(address _protocolTokenAddress) external;\n\n function setRolloverBaseReward(uint256 transactionCost) external;\n\n function setRebatePercent(uint256 rebatePercent) external;\n\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external;\n\n function getSpecialRebates(address sourceToken, address destToken)\n external\n view\n returns (uint256 specialRebatesPercent);\n\n function togglePaused(bool paused) external;\n\n function isProtocolPaused() external view returns (bool);\n\n ////// SwapsImplSovrynSwapModule //////\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (address);\n\n function getContractHexName(string calldata source) external pure returns (bytes32 result);\n\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn);\n\n ////// Loan Settings //////\n\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n returns (bytes32[] memory loanParamsIdList);\n\n // Deactivates LoanParams for future loans. Active loans using it are unaffected.\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external;\n\n function getLoanParams(bytes32[] calldata loanParamsIdList)\n external\n view\n returns (LoanParams[] memory loanParamsList);\n\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList);\n\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256);\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256);\n\n ////// Loan Openings //////\n\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId, // if 0, start a new loan\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n // lender: must match loan if loanId provided\n // borrower: must match loan if loanId provided\n // receiver: receiver of funds (address(0) assumes borrower address)\n // manager: delegated manager of loan unless address(0)\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n // newRate: new loan interest rate\n // newPrincipal: new loan size (borrowAmount + any borrowed interest)\n // torqueInterest: new amount of interest to escrow for Torque loan (determines initial loan length)\n // loanTokenReceived: total loanToken deposit (amount not sent to borrower in the case of Torque loans)\n // collateralTokenReceived: total collateralToken deposit\n bytes calldata loanDataBytes\n ) external payable returns (uint256 newPrincipal, uint256 newCollateral);\n\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external;\n\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256);\n\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 collateralAmountRequired);\n\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) external view returns (uint256 borrowAmount);\n\n ////// Loan Closings //////\n\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n );\n\n function rollover(bytes32 loanId, bytes calldata loanDataBytes) external;\n\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount // denominated in loanToken\n )\n external\n payable\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes calldata loanDataBytes\n )\n external\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n );\n\n ////// Loan Maintenance //////\n\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount // must match msg.value if ether is sent\n ) external payable;\n\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 actualWithdrawAmount);\n\n function withdrawAccruedInterest(address loanToken) external;\n\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n );\n\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n );\n\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; // collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);\n\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);\n\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData);\n\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2);\n\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external returns (uint256 secondsExtended);\n\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external returns (uint256 secondsReduced);\n\n ////// Swaps External //////\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256);\n\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view;\n\n ////// Affiliates Module //////\n\n function getUserNotFirstTradeFlag(address user) external view returns (bool);\n\n function setUserNotFirstTradeFlag(address user) external;\n\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n\n function setAffiliatesReferrer(address user, address referrer) external; //onlyCallableByLoanPools\n\n function getReferralsList(address referrer) external view returns (address[] memory refList);\n\n function getAffiliatesReferrerBalances(address referrer)\n external\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances);\n\n function getAffiliatesReferrerTokensList(address referrer)\n external\n view\n returns (address[] memory tokensList);\n\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n external\n view\n returns (uint256);\n\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) external;\n\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external;\n\n function getProtocolAddress() external view returns (address);\n\n function getSovTokenAddress() external view returns (address);\n\n function getLockedSOVAddress() external view returns (address);\n\n function getFeeRebatePercent() external view returns (uint256);\n\n function getMinReferralsToPayout() external view returns (uint256);\n\n function getAffiliatesUserReferrer(address user) external view returns (address referrer);\n\n function getAffiliateRewardsHeld(address referrer) external view returns (uint256);\n\n function getAffiliateTradingTokenFeePercent()\n external\n view\n returns (uint256 affiliateTradingTokenFeePercent);\n\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount);\n\n function getSwapExternalFeePercent() external view returns (uint256 swapExternalFeePercent);\n\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint) external;\n\n function getTradingRebateRewardsBasisPoint() external view returns (uint256);\n\n function getDedicatedSOVRebate() external view returns (uint256);\n\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;\n\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory);\n\n function setDefaultPathConversion(IERC20[] calldata defaultPath) external;\n\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external;\n\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount);\n\n function setAdmin(address newAdmin) external;\n\n function getAdmin() external view returns (address);\n\n function setPauser(address newPauser) external;\n\n function getPauser() external view returns (address);\n}\n" + }, + "contracts/interfaces/IWrbtc.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\ninterface IWrbtc {\n function deposit() external payable;\n\n function withdraw(uint256 wad) external;\n}\n" + }, + "contracts/interfaces/IWrbtcERC20.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity >=0.5.0 <0.6.0;\n\nimport \"./IWrbtc.sol\";\nimport \"./IERC20.sol\";\n\ncontract IWrbtcERC20 is IWrbtc, IERC20 {}\n" + }, + "contracts/locked/ILockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title The Locked SOV Interface.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This interface is an incomplete yet useful for future migration of LockedSOV Contract.\n * @dev Only use it if you know what you are doing.\n */\ninterface ILockedSOV {\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external;\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external;\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external;\n\n function cliff() external view returns (uint256);\n\n function duration() external view returns (uint256);\n\n function getLockedBalance(address _addr) external view returns (uint256 _balance);\n\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance);\n}\n" + }, + "contracts/locked/LockedSOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../governance/Vesting/VestingRegistry.sol\";\nimport \"../governance/Vesting/VestingLogic.sol\";\nimport \"./ILockedSOV.sol\";\n\n/**\n * @title The Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @notice This contract is used to receive reward from other contracts, Create Vesting and Stake Tokens.\n */\ncontract LockedSOV is ILockedSOV {\n using SafeMath for uint256;\n\n uint256 public constant MAX_BASIS_POINT = 10000;\n uint256 public constant MAX_DURATION = 37;\n\n /* Storage */\n\n /// @notice True if the migration to a new Locked SOV Contract has started.\n bool public migration;\n\n /// @notice The cliff is the time period after which the tokens begin to unlock.\n uint256 public cliff;\n /// @notice The duration is the time period after all tokens will have been unlocked.\n uint256 public duration;\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n /// @notice The Vesting registry contract.\n VestingRegistry public vestingRegistry;\n /// @notice The New (Future) Locked SOV.\n ILockedSOV public newLockedSOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) private lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) private unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) private isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /// @notice Emitted when Vesting Registry, Duration and/or Cliff is updated.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vestingRegistry The Vesting Registry Contract.\n /// @param _cliff The time period after which the tokens begin to unlock.\n /// @param _duration The time period after all tokens will have been unlocked.\n event RegistryCliffAndDurationUpdated(\n address indexed _initiator,\n address indexed _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n );\n\n /// @notice Emitted when a new deposit is made.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user to whose un/locked balance a new deposit was made.\n /// @param _sovAmount The amount of SOV to be added to the un/locked balance.\n /// @param _basisPoint The % (in Basis Point) which determines how much will be unlocked immediately.\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n /// @notice Emitted when a user withdraws the fund.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _sovAmount The amount of SOV withdrawn from the unlocked balance.\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n /// @notice Emitted when a user creates a vesting for himself.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _userAddress The user whose unlocked balance has to be withdrawn.\n /// @param _vesting The Vesting Contract.\n event VestingCreated(\n address indexed _initiator,\n address indexed _userAddress,\n address indexed _vesting\n );\n\n /// @notice Emitted when a user stakes tokens.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _vesting The Vesting Contract.\n /// @param _amount The amount of locked tokens staked by the user.\n event TokenStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /// @notice Emitted when an admin initiates a migration to new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newLockedSOV The address of the new Locked SOV Contract.\n event MigrationStarted(address indexed _initiator, address indexed _newLockedSOV);\n\n /// @notice Emitted when a user initiates the transfer to a new Locked SOV Contract.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _amount The amount of locked tokens to transfer from this contract to the new one.\n event UserTransfered(address indexed _initiator, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n modifier migrationAllowed {\n require(migration, \"Migration has not yet started.\");\n _;\n }\n\n /* Constructor */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV Token Address.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @param _admins The list of Admins to be added.\n */\n constructor(\n address _SOV,\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration,\n address[] memory _admins\n ) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n require(_vestingRegistry != address(0), \"Vesting registry address is invalid.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n SOV = IERC20(_SOV);\n vestingRegistry = VestingRegistry(_vestingRegistry);\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /* Public or External Functions */\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n * @dev Only callable by an Admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address.\");\n require(!isAdmin[_newAdmin], \"Address is already admin.\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n * @dev Only callable by an Admin.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin.\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice The function to update the Vesting Registry, Duration and Cliff.\n * @param _vestingRegistry The Vesting Registry Address.\n * @param _cliff The time period after which the tokens begin to unlock.\n * @param _duration The time period after all tokens will have been unlocked.\n * @dev IMPORTANT 1: You have to change Vesting Registry if you want to change Duration and/or Cliff.\n * IMPORTANT 2: `_cliff` and `_duration` is multiplied by 4 weeks in this function.\n */\n function changeRegistryCliffAndDuration(\n address _vestingRegistry,\n uint256 _cliff,\n uint256 _duration\n ) external onlyAdmin {\n require(\n address(vestingRegistry) != _vestingRegistry,\n \"Vesting Registry has to be different for changing duration and cliff.\"\n );\n /// If duration is also zero, then it is similar to Unlocked SOV.\n require(_duration != 0, \"Duration cannot be zero.\");\n require(_duration < MAX_DURATION, \"Duration is too long.\");\n\n vestingRegistry = VestingRegistry(_vestingRegistry);\n\n cliff = _cliff * 4 weeks;\n duration = _duration * 4 weeks;\n\n emit RegistryCliffAndDurationUpdated(msg.sender, _vestingRegistry, _cliff, _duration);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // MAX_BASIS_POINT is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < MAX_BASIS_POINT, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(MAX_BASIS_POINT);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice A function to withdraw the unlocked balance.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdraw(address _receiverAddress) public {\n _withdraw(msg.sender, _receiverAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n /**\n * @notice Creates vesting if not already created and Stakes tokens for a user.\n * @dev Only use this function if the `duration` is small.\n */\n function createVestingAndStake() public {\n _createVestingAndStake(msg.sender);\n }\n\n function _createVestingAndStake(address _sender) private {\n address vestingAddr = _getVesting(_sender);\n\n if (vestingAddr == address(0)) {\n vestingAddr = _createVesting(_sender);\n }\n\n _stakeTokens(_sender, vestingAddr);\n }\n\n /**\n * @notice Creates vesting contract (if it hasn't been created yet) for the calling user.\n * @return _vestingAddress The New Vesting Contract Created.\n */\n function createVesting() public returns (address _vestingAddress) {\n _vestingAddress = _createVesting(msg.sender);\n }\n\n /**\n * @notice Stakes tokens for a user who already have a vesting created.\n * @dev The user should already have a vesting created, else this function will throw error.\n */\n function stakeTokens() public {\n VestingLogic vesting = VestingLogic(_getVesting(msg.sender));\n\n require(\n cliff == vesting.cliff() && duration == vesting.duration(),\n \"Wrong Vesting Schedule.\"\n );\n\n _stakeTokens(msg.sender, address(vesting));\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _receiverAddress If specified, the unlocked balance will go to this address, else to msg.sender.\n */\n function withdrawAndStakeTokens(address _receiverAddress) external {\n _withdraw(msg.sender, _receiverAddress);\n _createVestingAndStake(msg.sender);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n /**\n * @notice Function to start the process of migration to new contract.\n * @param _newLockedSOV The new locked sov contract address.\n */\n function startMigration(address _newLockedSOV) external onlyAdmin {\n require(_newLockedSOV != address(0), \"New Locked SOV Address is Invalid.\");\n newLockedSOV = ILockedSOV(_newLockedSOV);\n SOV.approve(_newLockedSOV, SOV.balanceOf(address(this)));\n migration = true;\n\n emit MigrationStarted(msg.sender, _newLockedSOV);\n }\n\n /**\n * @notice Function to transfer the locked balance from this contract to new LockedSOV Contract.\n * @dev Address is not specified to discourage selling lockedSOV to other address.\n */\n function transfer() external migrationAllowed {\n uint256 amount = lockedBalances[msg.sender];\n lockedBalances[msg.sender] = 0;\n\n newLockedSOV.depositSOV(msg.sender, amount);\n\n emit UserTransfered(msg.sender, amount);\n }\n\n /* Internal Functions */\n\n /**\n * @notice Creates a Vesting Contract for a user.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n * @dev Does not do anything if Vesting Contract was already created.\n */\n function _createVesting(address _tokenOwner) internal returns (address _vestingAddress) {\n /// Here zero is given in place of amount, as amount is not really used in `vestingRegistry.createVesting()`.\n vestingRegistry.createVesting(_tokenOwner, 0, cliff, duration);\n _vestingAddress = _getVesting(_tokenOwner);\n emit VestingCreated(msg.sender, _tokenOwner, _vestingAddress);\n }\n\n /**\n * @notice Returns the Vesting Contract Address.\n * @param _tokenOwner The owner of the vesting contract.\n * @return _vestingAddress The Vesting Contract Address.\n */\n function _getVesting(address _tokenOwner) internal view returns (address _vestingAddress) {\n return vestingRegistry.getVesting(_tokenOwner);\n }\n\n /**\n * @notice Stakes the tokens in a particular vesting contract.\n * @param _vesting The Vesting Contract Address.\n */\n function _stakeTokens(address _sender, address _vesting) internal {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n require(SOV.approve(_vesting, amount), \"Approve failed.\");\n VestingLogic(_vesting).stakeTokens(amount);\n\n emit TokenStaked(_sender, _vesting, amount);\n }\n\n /* Getter or Read Functions */\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) external view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n\n /**\n * @notice The function to check is an address is admin or not.\n * @param _addr The address of the user to check the admin status.\n * @return _status True if admin, False otherwise.\n */\n function adminStatus(address _addr) external view returns (bool _status) {\n return isAdmin[_addr];\n }\n}\n" + }, + "contracts/mixins/EnumerableAddressSet.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Based on Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * As of v2.5.0, only `address` sets are supported.\n *\n * Include with `using EnumerableSet for EnumerableSet.AddressSet;`.\n *\n * _Available since v2.5.0._\n */\nlibrary EnumerableAddressSet {\n struct AddressSet {\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping(address => uint256) index;\n address[] values;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n * Returns false if the value was already in the set.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n * Returns false if the value was not present in the set.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n // If the element we're deleting is the last one, we can just remove it without doing a swap\n if (lastIndex != toDeleteIndex) {\n address lastValue = set.values[lastIndex];\n\n // Move the last value to the index where the deleted value is\n set.values[toDeleteIndex] = lastValue;\n // Update the index for the moved value\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n // Delete the index entry for the deleted value\n delete set.index[value];\n\n // Delete the old entry for the moved value\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns an array with all values in the set. O(N).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(AddressSet storage set) internal view returns (address[] memory) {\n address[] memory output = new address[](set.values.length);\n for (uint256 i; i < set.values.length; i++) {\n output[i] = set.values[i];\n }\n return output;\n }\n\n /**\n * @dev Returns a chunk of array as recommended in enumerate() to avoid running of gas.\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n \n * @param start start index of chunk\n * @param count num of element to return; if count == 0 then returns all the elements from the @param start\n */\n function enumerateChunk(\n AddressSet storage set,\n uint256 start,\n uint256 count\n ) internal view returns (address[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = (set.values.length < end || count == 0) ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new address[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @dev Returns the number of elements on the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /** @dev Returns the element stored at position `index` in the set. O(1).\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function get(AddressSet storage set, uint256 index) internal view returns (address) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes32Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.\n * */\nlibrary EnumerableBytes32Set {\n struct Bytes32Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes32 => uint256) index;\n bytes32[] values;\n }\n\n /**\n * @notice Add an address value to a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to add.\n *\n * @return False if the value was already in the set.\n */\n function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return addBytes32(set, value);\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove an address value from a set. O(1).\n *\n * @param set The set of values.\n * @param addrvalue The address to remove.\n *\n * @return False if the address was not present in the set.\n */\n function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return removeBytes32(set, value);\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes32 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function containsAddress(Bytes32Set storage set, address addrvalue)\n internal\n view\n returns (bool)\n {\n bytes32 value;\n assembly {\n value := addrvalue\n }\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes32Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes32[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes32[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/EnumerableBytes4Set.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\n/**\n * @title Library for managing loan sets.\n *\n * @notice Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * Include with `using EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`.\n * */\nlibrary EnumerableBytes4Set {\n struct Bytes4Set {\n /// Position of the value in the `values` array, plus 1 because index 0\n /// means a value is not in the set.\n mapping(bytes4 => uint256) index;\n bytes4[] values;\n }\n\n /**\n * @notice Add a value to a set. O(1).\n *\n * @param set The set of values.\n * @param value The new value to add.\n *\n * @return False if the value was already in the set.\n */\n function addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (!contains(set, value)) {\n set.index[value] = set.values.push(value);\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Remove a value from a set. O(1).\n *\n * @param set The set of values.\n * @param value The value to remove.\n *\n * @return False if the value was not present in the set.\n */\n function removeBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {\n if (contains(set, value)) {\n uint256 toDeleteIndex = set.index[value] - 1;\n uint256 lastIndex = set.values.length - 1;\n\n /// If the element we're deleting is the last one,\n /// we can just remove it without doing a swap.\n if (lastIndex != toDeleteIndex) {\n bytes4 lastValue = set.values[lastIndex];\n\n /// Move the last value to the index where the deleted value is.\n set.values[toDeleteIndex] = lastValue;\n\n /// Update the index for the moved value.\n set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based\n }\n\n /// Delete the index entry for the deleted value.\n delete set.index[value];\n\n /// Delete the old entry for the moved value.\n set.values.pop();\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @notice Find out whether a value exists in the set.\n *\n * @param set The set of values.\n * @param value The value to find.\n *\n * @return True if the value is in the set. O(1).\n */\n function contains(Bytes4Set storage set, bytes4 value) internal view returns (bool) {\n return set.index[value] != 0;\n }\n\n /**\n * @notice Get all set values.\n *\n * @param set The set of values.\n * @param start The offset of the returning set.\n * @param count The limit of number of values to return.\n *\n * @return An array with all values in the set. O(N).\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * WARNING: This function may run out of gas on large sets: use {length} and\n * {get} instead in these cases.\n */\n function enumerate(\n Bytes4Set storage set,\n uint256 start,\n uint256 count\n ) internal view returns (bytes4[] memory output) {\n uint256 end = start + count;\n require(end >= start, \"addition overflow\");\n end = set.values.length < end ? set.values.length : end;\n if (end == 0 || start >= end) {\n return output;\n }\n\n output = new bytes4[](end - start);\n for (uint256 i; i < end - start; i++) {\n output[i] = set.values[i + start];\n }\n return output;\n }\n\n /**\n * @notice Get the legth of the set.\n *\n * @param set The set of values.\n *\n * @return the number of elements on the set. O(1).\n */\n function length(Bytes4Set storage set) internal view returns (uint256) {\n return set.values.length;\n }\n\n /**\n * @notice Get an item from the set by its index.\n *\n * @dev Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n *\n * @param set The set of values.\n * @param index The index of the value to return.\n *\n * @return the element stored at position `index` in the set. O(1).\n */\n function get(Bytes4Set storage set, uint256 index) internal view returns (bytes4) {\n return set.values[index];\n }\n}\n" + }, + "contracts/mixins/FeesHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/FeesEvents.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ISovryn.sol\";\nimport \"../core/objects/LoanParamsStruct.sol\";\n\n/**\n * @title The Fees Helper contract.\n *\n * This contract calculates and pays lending/borrow fees and rewards.\n * */\ncontract FeesHelper is State, FeesEvents {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Calculate trading fee.\n * @param feeTokenAmount The amount of tokens to trade.\n * @return The fee of the trade.\n * */\n function _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(tradingFeePercent).divCeil(10**20);\n }\n\n /**\n * @notice Calculate swap external fee.\n * @param feeTokenAmount The amount of token to swap.\n * @return The fee of the swap.\n */\n function _getSwapExternalFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(swapExtrernalFeePercent).divCeil(10**20);\n }\n\n /*\n\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\tfunction _getTradingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - tradingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);\n\t}*/\n\n /**\n * @notice Calculate the loan origination fee.\n * @param feeTokenAmount The amount of tokens to borrow.\n * @return The fee of the loan.\n * */\n function _getBorrowingFee(uint256 feeTokenAmount) internal view returns (uint256) {\n return feeTokenAmount.mul(borrowingFeePercent).divCeil(10**20);\n /*\n\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t// cannot be applied solely nor with LoanOpenings.sol as it drives to some other tests failure\n\t\tuint256 collateralAmountRequired =\n\t\t\tfeeTokenAmount.mul(10**20).divCeil(\n\t\t\t\t10**20 - borrowingFeePercent // never will overflow\n\t\t\t);\n\t\treturn collateralAmountRequired.sub(feeTokenAmount);*/\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the affiliates referrer.\n *\n * @param referrer The affiliate referrer address to send the reward to.\n * @param trader The account that performs this trade.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n *\n * @return affiliatesBonusSOVAmount the total SOV amount that is distributed to the referrer\n * @return affiliatesBonusTokenAmount the total Token Base on the trading fee pairs that is distributed to the referrer\n * */\n function _payTradingFeeToAffiliate(\n address referrer,\n address trader,\n address feeToken,\n uint256 tradingFee\n ) internal returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount) {\n (affiliatesBonusSOVAmount, affiliatesBonusTokenAmount) = ProtocolAffiliatesInterface(\n address(this)\n )\n .payTradingFeeToAffiliatesReferrer(referrer, trader, feeToken, tradingFee);\n }\n\n /**\n * @notice Settle the trading fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the trading fee is paid.\n * @param tradingFee The amount of tokens accrued as fees on the trading.\n * */\n function _payTradingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 tradingFee\n ) internal {\n uint256 protocolTradingFee = tradingFee; /// Trading fee paid to protocol.\n if (tradingFee != 0) {\n if (affiliatesUserReferrer[user] != address(0)) {\n _payTradingFeeToAffiliate(\n affiliatesUserReferrer[user],\n user,\n feeToken,\n protocolTradingFee\n );\n protocolTradingFee = (\n protocolTradingFee.sub(protocolTradingFee.mul(affiliateFeePercent).div(10**20))\n )\n .sub(protocolTradingFee.mul(affiliateTradingTokenFeePercent).div(10**20));\n }\n\n /// Increase the storage variable keeping track of the accumulated fees.\n tradingFeeTokensHeld[feeToken] = tradingFeeTokensHeld[feeToken].add(\n protocolTradingFee\n );\n\n emit PayTradingFee(user, feeToken, loanId, protocolTradingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, tradingFee);\n }\n }\n\n /**\n * @notice Settle the borrowing fee and pay the token reward to the user.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associated loan - used for logging only.\n * @param feeToken The address of the token in which the borrowig fee is paid.\n * @param borrowingFee The height of the fee.\n * */\n function _payBorrowingFee(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 borrowingFee\n ) internal {\n if (borrowingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n borrowingFeeTokensHeld[feeToken] = borrowingFeeTokensHeld[feeToken].add(borrowingFee);\n\n emit PayBorrowingFee(user, feeToken, loanId, borrowingFee);\n\n /// Pay the token reward to the user.\n _payFeeReward(user, loanId, feeToken, feeTokenPair, borrowingFee);\n }\n }\n\n /**\n * @notice Settle the lending fee (based on the interest). Pay no token reward to the user.\n * @param user The address to send the reward to.\n * @param feeToken The address of the token in which the lending fee is paid.\n * @param lendingFee The height of the fee.\n * */\n function _payLendingFee(\n address user,\n address feeToken,\n uint256 lendingFee\n ) internal {\n if (lendingFee != 0) {\n /// Increase the storage variable keeping track of the accumulated fees.\n lendingFeeTokensHeld[feeToken] = lendingFeeTokensHeld[feeToken].add(lendingFee);\n\n emit PayLendingFee(user, feeToken, lendingFee);\n\n //// NOTE: Lenders do not receive a fee reward ////\n }\n }\n\n /// Settle and pay borrowers based on the fees generated by their interest payments.\n function _settleFeeRewardForInterestExpense(\n LoanInterest storage loanInterestLocal,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n address user,\n uint256 interestTime\n ) internal {\n /// This represents the fee generated by a borrower's interest payment.\n uint256 interestExpenseFee =\n interestTime\n .sub(loanInterestLocal.updatedTimestamp)\n .mul(loanInterestLocal.owedPerDay)\n .mul(lendingFeePercent)\n .div(1 days * 10**20);\n\n loanInterestLocal.updatedTimestamp = interestTime;\n\n if (interestExpenseFee != 0) {\n _payFeeReward(user, loanId, feeToken, feeTokenPair, interestExpenseFee);\n }\n }\n\n /**\n * @notice Pay the potocolToken reward to user. The reward is worth 50% of the trading/borrowing fee.\n * @param user The address to send the reward to.\n * @param loanId The Id of the associeated loan - used for logging only.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * */\n function _payFeeReward(\n address user,\n bytes32 loanId,\n address feeToken,\n address feeTokenPair,\n uint256 feeAmount\n ) internal {\n uint256 rewardAmount;\n uint256 _feeRebatePercent = feeRebatePercent;\n address _priceFeeds = priceFeeds;\n\n if (specialRebates[feeToken][feeTokenPair] > 0) {\n _feeRebatePercent = specialRebates[feeToken][feeTokenPair];\n }\n\n /// Note: this should be refactored.\n /// Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// Price rewards using BZRX price rather than vesting token price.\n feeAmount.mul(_feeRebatePercent).div(10**20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n // Check the dedicated SOV that is used to pay trading rebate rewards\n uint256 dedicatedSOV = ISovryn(address(this)).getDedicatedSOVRebate();\n if (rewardAmount != 0 && dedicatedSOV >= rewardAmount) {\n IERC20(sovTokenAddress).approve(lockedSOVAddress, rewardAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"deposit(address,uint256,uint256)\",\n user,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n )\n );\n\n if (success) {\n protocolTokenPaid = protocolTokenPaid.add(rewardAmount);\n\n emit EarnReward(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n } else {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n } else if (rewardAmount != 0 && dedicatedSOV < rewardAmount) {\n emit EarnRewardFail(\n user,\n sovTokenAddress,\n loanId,\n _feeRebatePercent,\n rewardAmount,\n tradingRebateRewardsBasisPoint\n );\n }\n }\n}\n" + }, + "contracts/mixins/InterestUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"./FeesHelper.sol\";\n\n/**\n * @title The Interest User contract.\n *\n * This contract pays loan interests.\n * */\ncontract InterestUser is VaultController, FeesHelper {\n using SafeERC20 for IERC20;\n\n /// Triggered whenever interest is paid to lender.\n event PayInterestTransfer(\n address indexed interestToken,\n address indexed lender,\n uint256 effectiveInterest\n );\n\n /**\n * @notice Internal function to pay interest of a loan.\n * @dev Calls _payInterestTransfer internal function to transfer tokens.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * */\n function _payInterest(address lender, address interestToken) internal {\n LenderInterest storage lenderInterestLocal = lenderInterest[lender][interestToken];\n\n uint256 interestOwedNow = 0;\n if (lenderInterestLocal.owedPerDay != 0 && lenderInterestLocal.updatedTimestamp != 0) {\n interestOwedNow = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(1 days);\n\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n\n if (interestOwedNow > lenderInterestLocal.owedTotal)\n interestOwedNow = lenderInterestLocal.owedTotal;\n\n if (interestOwedNow != 0) {\n lenderInterestLocal.paidTotal = lenderInterestLocal.paidTotal.add(interestOwedNow);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.sub(interestOwedNow);\n\n _payInterestTransfer(lender, interestToken, interestOwedNow);\n }\n } else {\n lenderInterestLocal.updatedTimestamp = block.timestamp;\n }\n }\n\n /**\n * @notice Internal function to transfer tokens for the interest of a loan.\n * @param lender The account address of the lender.\n * @param interestToken The token address to pay interest with.\n * @param interestOwedNow The amount of interest to pay.\n * */\n function _payInterestTransfer(\n address lender,\n address interestToken,\n uint256 interestOwedNow\n ) internal {\n uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).div(10**20);\n /// TODO: refactor: data incapsulation violation and DRY design principles\n /// uint256 lendingFee = interestOwedNow.mul(lendingFeePercent).divCeil(10**20); is better but produces errors in tests because of this\n\n _payLendingFee(lender, interestToken, lendingFee);\n\n /// Transfers the interest to the lender, less the interest fee.\n vaultWithdraw(interestToken, lender, interestOwedNow.sub(lendingFee));\n\n /// Event Log\n emit PayInterestTransfer(interestToken, lender, interestOwedNow.sub(lendingFee));\n }\n}\n" + }, + "contracts/mixins/LiquidationHelper.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\n/**\n * @title The Liquidation Helper contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract computes the liquidation amount.\n * */\ncontract LiquidationHelper is State {\n /**\n * @notice Compute how much needs to be liquidated in order to restore the\n * desired margin (maintenance + 5%).\n *\n * @param principal The total borrowed amount (in loan tokens).\n * @param collateral The collateral (in collateral tokens).\n * @param currentMargin The current margin.\n * @param maintenanceMargin The maintenance (minimum) margin.\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n *\n * @return maxLiquidatable The collateral you can get liquidating.\n * @return maxSeizable The loan you available for liquidation.\n * @return incentivePercent The discount on collateral.\n * */\n function _getLiquidationAmounts(\n uint256 principal,\n uint256 collateral,\n uint256 currentMargin,\n uint256 maintenanceMargin,\n uint256 collateralToLoanRate\n )\n internal\n view\n returns (\n uint256 maxLiquidatable,\n uint256 maxSeizable,\n uint256 incentivePercent\n )\n {\n incentivePercent = liquidationIncentivePercent;\n if (currentMargin > maintenanceMargin || collateralToLoanRate == 0) {\n return (maxLiquidatable, maxSeizable, incentivePercent);\n } else if (currentMargin <= incentivePercent) {\n return (principal, collateral, currentMargin);\n }\n\n /// 5 percentage points above maintenance.\n uint256 desiredMargin = maintenanceMargin.add(5 ether);\n\n /// maxLiquidatable = ((1 + desiredMargin)*principal - collateralToLoanRate*collateral) / (desiredMargin - 0.05)\n maxLiquidatable = desiredMargin.add(10**20).mul(principal).div(10**20);\n maxLiquidatable = maxLiquidatable.sub(collateral.mul(collateralToLoanRate).div(10**18));\n maxLiquidatable = maxLiquidatable.mul(10**20).div(desiredMargin.sub(incentivePercent));\n if (maxLiquidatable > principal) {\n maxLiquidatable = principal;\n }\n\n /// maxSeizable = maxLiquidatable * (1 + incentivePercent) / collateralToLoanRate\n maxSeizable = maxLiquidatable.mul(incentivePercent.add(10**20));\n maxSeizable = maxSeizable.div(collateralToLoanRate).div(100);\n if (maxSeizable > collateral) {\n maxSeizable = collateral;\n }\n\n return (maxLiquidatable, maxSeizable, incentivePercent);\n }\n}\n" + }, + "contracts/mixins/ModuleCommonFunctionalities.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\n\ncontract ModuleCommonFunctionalities is State {\n modifier whenNotPaused() {\n require(!pause, \"Paused\");\n _;\n }\n}\n" + }, + "contracts/mixins/ProtocolTokenUser.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\n\n/**\n * @title The Protocol Token User contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to withdraw protocol tokens.\n * */\ncontract ProtocolTokenUser is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Internal function to withdraw an amount of protocol tokens from this contract.\n *\n * @param receiver The address of the recipient.\n * @param amount The amount of tokens to withdraw.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function _withdrawProtocolToken(address receiver, uint256 amount)\n internal\n returns (address, bool)\n {\n uint256 withdrawAmount = amount;\n\n uint256 tokenBalance = protocolTokenHeld;\n if (withdrawAmount > tokenBalance) {\n withdrawAmount = tokenBalance;\n }\n if (withdrawAmount == 0) {\n return (protocolTokenAddress, false);\n }\n\n protocolTokenHeld = tokenBalance.sub(withdrawAmount);\n\n IERC20(protocolTokenAddress).safeTransfer(receiver, withdrawAmount);\n\n return (protocolTokenAddress, true);\n }\n}\n" + }, + "contracts/mixins/RewardHelper.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title The Reward Helper contract.\n * @notice This contract calculates the reward for rollover transactions.\n *\n * A rollover is a renewal of a deposit. Instead of liquidating a deposit\n * on maturity, you can roll it over into a new deposit. The outstanding\n * principal of the old deposit is rolled over with or without the interest\n * outstanding on it.\n * */\ncontract RewardHelper is State {\n using SafeMath for uint256;\n\n /**\n * @notice Calculate the reward of a rollover transaction.\n *\n * @param collateralToken The address of the collateral token.\n * @param loanToken The address of the loan token.\n * @param positionSize The amount of value of the position.\n *\n * @return The base fee + the flex fee.\n */\n function _getRolloverReward(\n address collateralToken,\n address loanToken,\n uint256 positionSize\n ) internal view returns (uint256 reward) {\n uint256 positionSizeInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(loanToken, collateralToken, positionSize);\n uint256 rolloverBaseRewardInCollateralToken =\n IPriceFeeds(priceFeeds).queryReturn(\n address(wrbtcToken),\n collateralToken,\n rolloverBaseReward\n );\n\n return\n rolloverBaseRewardInCollateralToken\n .mul(2) /// baseFee\n .add(positionSizeInCollateralToken.mul(rolloverFlexFeePercent).div(10**20)); /// flexFee = 0.1% of position size\n }\n}\n" + }, + "contracts/mixins/VaultController.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../core/State.sol\";\n\n/**\n * @title The Vault Controller contract.\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized margin\n * trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract implements functionality to deposit and withdraw wrBTC and\n * other tokens from the vault.\n * */\ncontract VaultController is State {\n using SafeERC20 for IERC20;\n\n event VaultDeposit(address indexed asset, address indexed from, uint256 amount);\n event VaultWithdraw(address indexed asset, address indexed to, uint256 amount);\n\n /**\n * @notice Deposit wrBTC into the vault.\n *\n * @param from The address of the account paying the deposit.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherDeposit(address from, uint256 value) internal {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n _wrbtcToken.deposit.value(value)();\n\n emit VaultDeposit(address(_wrbtcToken), from, value);\n }\n\n /**\n * @notice Withdraw wrBTC from the vault.\n *\n * @param to The address of the recipient.\n * @param value The amount of wrBTC tokens to transfer.\n */\n function vaultEtherWithdraw(address to, uint256 value) internal {\n if (value != 0) {\n IWrbtcERC20 _wrbtcToken = wrbtcToken;\n uint256 balance = address(this).balance;\n if (value > balance) {\n _wrbtcToken.withdraw(value - balance);\n }\n Address.sendValue(to, value);\n\n emit VaultWithdraw(address(_wrbtcToken), to, value);\n }\n }\n\n /**\n * @notice Deposit tokens into the vault.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying the deposit.\n * @param value The amount of tokens to transfer.\n */\n function vaultDeposit(\n address token,\n address from,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransferFrom(from, address(this), value);\n\n emit VaultDeposit(token, from, value);\n }\n }\n\n /**\n * @notice Withdraw tokens from the vault.\n *\n * @param token The address of the token instance.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultWithdraw(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n IERC20(token).safeTransfer(to, value);\n\n emit VaultWithdraw(token, to, value);\n }\n }\n\n /**\n * @notice Transfer tokens from an account into another one.\n *\n * @param token The address of the token instance.\n * @param from The address of the account paying.\n * @param to The address of the recipient.\n * @param value The amount of tokens to transfer.\n */\n function vaultTransfer(\n address token,\n address from,\n address to,\n uint256 value\n ) internal {\n if (value != 0) {\n if (from == address(this)) {\n IERC20(token).safeTransfer(to, value);\n } else {\n IERC20(token).safeTransferFrom(from, to, value);\n }\n }\n }\n\n /**\n * @notice Approve an allowance of tokens to be spent by an account.\n *\n * @param token The address of the token instance.\n * @param to The address of the spender.\n * @param value The amount of tokens to allow.\n */\n function vaultApprove(\n address token,\n address to,\n uint256 value\n ) internal {\n if (value != 0 && IERC20(token).allowance(address(this), to) != 0) {\n IERC20(token).safeApprove(to, 0);\n }\n IERC20(token).safeApprove(to, value);\n }\n}\n" + }, + "contracts/mockup/BlockMockUp.sol": { + "content": "pragma solidity 0.5.17;\n\n/**\n * @title Used to get and set mock block number.\n */\ncontract BlockMockUp {\n uint256 public blockNum;\n\n /**\n * @notice To get the `blockNum`.\n * @return _blockNum The block number.\n */\n function getBlockNum() public view returns (uint256 _blockNum) {\n return blockNum;\n }\n\n /**\n * @notice To set the `blockNum`.\n * @param _blockNum The block number.\n */\n function setBlockNum(uint256 _blockNum) public {\n blockNum = _blockNum;\n }\n}\n" + }, + "contracts/mockup/FeeSharingCollectorMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/FeeSharingCollector/FeeSharingCollector.sol\";\n\ncontract FeeSharingCollectorMockup is FeeSharingCollector {\n struct TestData {\n address loanPoolToken;\n uint32 maxCheckpoints;\n address receiver;\n }\n\n TestData public testData;\n\n constructor(IProtocol _protocol, IStaking _staking) public {\n protocol = _protocol;\n staking = _staking;\n }\n\n function withdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n testData = TestData(_token, _maxCheckpoints, _receiver);\n }\n\n function trueWithdraw(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n\n function addCheckPoint(address loanPoolToken, uint256 poolTokenAmount) public {\n uint96 amount96 =\n safe96(\n poolTokenAmount,\n \"FeeSharingCollectorProxy::withdrawFees: pool token amount exceeds 96 bits\"\n );\n _addCheckpoint(loanPoolToken, amount96);\n }\n\n function setTotalTokenCheckpoints(address _token, uint256 qty) public {\n totalTokenCheckpoints[_token] = qty;\n }\n\n function setUserProcessedCheckpoints(\n address _user,\n address _token,\n uint256 num\n ) public {\n processedCheckpoints[_user][_token] = num;\n }\n\n function getFullAccumulatedFees(\n address _user,\n address _token,\n uint32 _maxCheckpoints\n ) public view returns (uint256 amount, uint256 end) {\n (amount, end) = _getAccumulatedFees(_user, _token, 0, _maxCheckpoints);\n }\n\n function endOfRangeWithZeroMaxCheckpoint(address _token) public view returns (uint256) {\n return _getEndOfRange(0, _token, 0);\n }\n\n function getRBTCBalance(\n address _token,\n address _user,\n uint32 _maxCheckpoints\n ) public view returns (uint256 _tokenAmount, uint256 _endToken) {\n return _getRBTCBalance(_token, _user, _maxCheckpoints);\n }\n\n function testWithdrawReentrancy(\n address _token,\n uint32 _maxCheckpoints,\n address _receiver\n ) public {\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n super.withdraw(_token, _maxCheckpoints, _receiver);\n }\n}\n" + }, + "contracts/mockup/GovernorAlphaMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/GovernorAlpha.sol\";\n\ncontract GovernorAlphaMockup is GovernorAlpha {\n constructor(\n address timelock_,\n address staking_,\n address guardian_,\n uint96 quorumVotes_,\n uint96 _minPercentageVotes\n ) public GovernorAlpha(timelock_, staking_, guardian_, quorumVotes_, _minPercentageVotes) {}\n\n function votingPeriod() public pure returns (uint256) {\n return 10;\n }\n\n function queueProposals(uint256[] calldata proposalIds) external {\n for (uint256 i = 0; i < proposalIds.length; i++) {\n queue(proposalIds[i]);\n }\n }\n}\n" + }, + "contracts/mockup/LiquidityMiningMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract LiquidityMiningMockup is LiquidityMining {\n function getPassedBlocksWithBonusMultiplier(uint256 _from, uint256 _to)\n public\n view\n returns (uint256)\n {\n return _getPassedBlocksWithBonusMultiplier(_from, _to);\n }\n\n function getPoolAccumulatedReward(address _poolToken) public view returns (uint256, uint256) {\n uint256 poolId = _getPoolId(_poolToken);\n PoolInfo storage pool = poolInfoList[poolId];\n return _getPoolAccumulatedReward(pool);\n }\n}\n" + }, + "contracts/mockup/LiquidityPoolV1ConverterMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/IERC20.sol\";\n\ncontract LiquidityPoolV1ConverterMockup {\n IERC20[] public reserveTokens;\n IERC20 wrbtcToken;\n uint256 totalFeeMockupValue;\n address feesController;\n\n constructor(IERC20 _token0, IERC20 _token1) public {\n reserveTokens.push(_token0);\n reserveTokens.push(_token1);\n }\n\n function setFeesController(address _feesController) public {\n feesController = _feesController;\n }\n\n function setWrbtcToken(IERC20 _wrbtcToken) public {\n wrbtcToken = _wrbtcToken;\n }\n\n function setTotalFeeMockupValue(uint256 _totalFeeMockupValue) public {\n totalFeeMockupValue = _totalFeeMockupValue;\n }\n\n function withdrawFees(address _receiver) external returns (uint256) {\n require(msg.sender == feesController, \"unauthorized\");\n\n // transfer wrbtc\n wrbtcToken.transfer(_receiver, totalFeeMockupValue);\n return totalFeeMockupValue;\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/LoanClosingsWith.sol\";\n\ncontract LoanClosingsWithMockup is LoanClosingsWith {\n function worthTheTransfer(address, uint256) internal returns (bool) {\n return true;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanClosingsWithoutInvariantCheck.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"./LoanClosingsWithMockup.sol\";\n\ncontract LoanClosingsWithoutInvariantCheck is LoanClosingsWithMockup {\n /** Override the modifier of invariant check so that we can test the shared reentrancy guard */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n _;\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicLMMockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\n\ncontract LoanTokenLogicLMMockup is LoanTokenLogicLM {\n function burn(address receiver, uint256 burnAmount)\n external\n nonReentrant\n returns (uint256 loanAmountPaid)\n {\n _callOptionalReturn(\n 0x2c34D66a5ca8686330e100372Eb3FDFB5aEECD0B, //Random EOA for testing\n abi.encodeWithSelector(IERC20(receiver).transfer.selector, receiver, burnAmount),\n \"error\"\n );\n }\n}\n" + }, + "contracts/mockup/LoanTokenLogicV2Mockup.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicV1Mockup is LoanTokenLogicStandard {\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](27);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n // res[31] = this.totalSupply.selector;\n res[25] = this.balanceOf.selector;\n res[26] = this.allowance.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n\ncontract LoanTokenLogicV2Mockup is LoanTokenLogicStandard {\n function testNewFunction() external pure returns (bool) {\n return true;\n }\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](29);\n\n // Loan Token Logic Standard\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mockup\n res[28] = this.testNewFunction.selector;\n\n return (res, stringToBytes32(\"LoanTokenLogic\"));\n }\n}\n" + }, + "contracts/mockup/lockedSOVFailedMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An interface for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete interface of the Locked SOV Contract.\n */\ncontract LockedSOVFailedMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The user balances.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n revert(\"For testing purposes\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/LockedSOVMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title An mockup for the Locked SOV Contract.\n * @author Franklin Richards - powerhousefrank@protonmail.com\n * @dev This is not a complete mockup of the Locked SOV Contract.\n */\ncontract LockedSOVMockup {\n using SafeMath for uint256;\n\n /* Storage */\n\n /// @notice The SOV token contract.\n IERC20 public SOV;\n\n /// @notice The locked user balances.\n mapping(address => uint256) lockedBalances;\n /// @notice The unlocked user balances.\n mapping(address => uint256) unlockedBalances;\n /// @notice The contracts/wallets with admin power.\n mapping(address => bool) isAdmin;\n\n /* Events */\n\n /// @notice Emitted when a new Admin is added to the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _newAdmin The address of the new admin.\n event AdminAdded(address indexed _initiator, address indexed _newAdmin);\n\n /// @notice Emitted when an admin is removed from the admin list.\n /// @param _initiator The address which initiated this event to be emitted.\n /// @param _removedAdmin The address of the removed admin.\n event AdminRemoved(address indexed _initiator, address indexed _removedAdmin);\n\n event Deposited(\n address indexed _initiator,\n address indexed _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n );\n\n event Withdrawn(address indexed _initiator, address indexed _userAddress, uint256 _sovAmount);\n\n event TokensStaked(address indexed _initiator, address indexed _vesting, uint256 _amount);\n\n /* Modifiers */\n\n modifier onlyAdmin {\n require(isAdmin[msg.sender], \"Only admin can call this.\");\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Setup the required parameters.\n * @param _SOV The SOV token address.\n * @param _admins The list of admins to be added.\n */\n constructor(address _SOV, address[] memory _admins) public {\n require(_SOV != address(0), \"Invalid SOV Address.\");\n SOV = IERC20(_SOV);\n for (uint256 index = 0; index < _admins.length; index++) {\n isAdmin[_admins[index]] = true;\n }\n }\n\n /**\n * @notice The function to add a new admin.\n * @param _newAdmin The address of the new admin.\n */\n function addAdmin(address _newAdmin) public onlyAdmin {\n require(_newAdmin != address(0), \"Invalid Address\");\n require(!isAdmin[_newAdmin], \"Address is already admin\");\n isAdmin[_newAdmin] = true;\n\n emit AdminAdded(msg.sender, _newAdmin);\n }\n\n /**\n * @notice The function to remove an admin.\n * @param _adminToRemove The address of the admin which should be removed.\n */\n function removeAdmin(address _adminToRemove) public onlyAdmin {\n require(isAdmin[_adminToRemove], \"Address is not an admin\");\n isAdmin[_adminToRemove] = false;\n\n emit AdminRemoved(msg.sender, _adminToRemove);\n }\n\n /**\n * @notice Adds SOV to the user balance (Locked and Unlocked Balance based on `_basisPoint`).\n * @param _userAddress The user whose locked balance has to be updated with `_sovAmount`.\n * @param _sovAmount The amount of SOV to be added to the locked and/or unlocked balance.\n * @param _basisPoint The % (in Basis Point)which determines how much will be unlocked immediately.\n */\n function deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) external {\n _deposit(_userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Adds SOV to the locked balance of a user.\n * @param _userAddress The user whose locked balance has to be updated with _sovAmount.\n * @param _sovAmount The amount of SOV to be added to the locked balance.\n * @dev This is here because there are dependency with other contracts.\n */\n function depositSOV(address _userAddress, uint256 _sovAmount) external {\n _deposit(_userAddress, _sovAmount, 0);\n }\n\n function _deposit(\n address _userAddress,\n uint256 _sovAmount,\n uint256 _basisPoint\n ) private {\n // 10000 is not included because if 100% is unlocked, then LockedSOV is not required to be used.\n require(_basisPoint < 10000, \"Basis Point has to be less than 10000.\");\n bool txStatus = SOV.transferFrom(msg.sender, address(this), _sovAmount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n uint256 unlockedBal = _sovAmount.mul(_basisPoint).div(10000);\n\n unlockedBalances[_userAddress] = unlockedBalances[_userAddress].add(unlockedBal);\n lockedBalances[_userAddress] = lockedBalances[_userAddress].add(_sovAmount).sub(\n unlockedBal\n );\n\n emit Deposited(msg.sender, _userAddress, _sovAmount, _basisPoint);\n }\n\n /**\n * @notice Withdraws unlocked tokens and Stakes Locked tokens for a user who already have a vesting created.\n * @param _userAddress The address of user tokens will be withdrawn.\n */\n function withdrawAndStakeTokensFrom(address _userAddress) external {\n _withdraw(_userAddress, _userAddress);\n _createVestingAndStake(_userAddress);\n }\n\n function _withdraw(address _sender, address _receiverAddress) private {\n address userAddr = _receiverAddress;\n if (_receiverAddress == address(0)) {\n userAddr = _sender;\n }\n\n uint256 amount = unlockedBalances[_sender];\n unlockedBalances[_sender] = 0;\n\n bool txStatus = SOV.transfer(userAddr, amount);\n require(txStatus, \"Token transfer was not successful. Check receiver address.\");\n\n emit Withdrawn(_sender, userAddr, amount);\n }\n\n function _createVestingAndStake(address _sender) private {\n uint256 amount = lockedBalances[_sender];\n lockedBalances[_sender] = 0;\n\n emit TokensStaked(_sender, address(0), amount);\n }\n\n /**\n * @notice The function to get the locked balance of a user.\n * @param _addr The address of the user to check the locked balance.\n * @return _balance The locked balance of the address `_addr`.\n */\n function getLockedBalance(address _addr) public view returns (uint256 _balance) {\n return lockedBalances[_addr];\n }\n\n /**\n * @notice The function to get the unlocked balance of a user.\n * @param _addr The address of the user to check the unlocked balance.\n * @return _balance The unlocked balance of the address `_addr`.\n */\n function getUnlockedBalance(address _addr) external view returns (uint256 _balance) {\n return unlockedBalances[_addr];\n }\n}\n" + }, + "contracts/mockup/MockAffiliates.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/Affiliates.sol\";\n\ncontract MockAffiliates is Affiliates {\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n }\n}\n" + }, + "contracts/mockup/MockFourYearVestingLogic.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/Vesting/fouryear/FourYearVestingLogic.sol\";\n\ncontract MockFourYearVestingLogic is FourYearVestingLogic {\n /**\n * @notice gets duration left\n */\n function getDurationLeft() external view returns (uint256) {\n return durationLeft;\n }\n}\n" + }, + "contracts/mockup/MockLoanTokenLogic.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogic is LoanTokenLogic {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](31);\n\n // Loan Token Logic\n res[0] = this.borrow.selector;\n res[1] = this.marginTrade.selector;\n res[2] = this.marginTradeAffiliate.selector;\n res[3] = this.transfer.selector;\n res[4] = this.transferFrom.selector;\n res[5] = this.profitOf.selector;\n res[6] = this.tokenPrice.selector;\n res[7] = this.checkpointPrice.selector;\n res[8] = this.marketLiquidity.selector;\n res[9] = this.avgBorrowInterestRate.selector;\n res[10] = this.borrowInterestRate.selector;\n res[11] = this.nextBorrowInterestRate.selector;\n res[12] = this.supplyInterestRate.selector;\n res[13] = this.nextSupplyInterestRate.selector;\n res[14] = this.totalSupplyInterestRate.selector;\n res[15] = this.totalAssetBorrow.selector;\n res[16] = this.totalAssetSupply.selector;\n res[17] = this.getMaxEscrowAmount.selector;\n res[18] = this.assetBalanceOf.selector;\n res[19] = this.getEstimatedMarginDetails.selector;\n res[20] = this.getDepositAmountForBorrow.selector;\n res[21] = this.getBorrowAmountForDeposit.selector;\n res[22] = this.checkPriceDivergence.selector;\n res[23] = this.calculateSupplyInterestRate.selector;\n\n // Advanced Token\n res[24] = this.approve.selector;\n\n // Advanced Token Storage\n res[25] = this.totalSupply.selector;\n res[26] = this.balanceOf.selector;\n res[27] = this.allowance.selector;\n\n // Mock\n res[28] = this.setAffiliatesReferrer.selector;\n res[29] = this.setUserNotFirstTradeFlag.selector;\n res[30] = this.getMarginBorrowAmountAndRate.selector;\n\n return (res, stringToBytes32(\"MockLoanTokenLogic\"));\n }\n\n function setAffiliatesReferrer(address user, address referrer) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setAffiliatesReferrer(user, referrer);\n }\n\n function setUserNotFirstTradeFlag(address user) public {\n ProtocolAffiliatesInterface(sovrynContractAddress).setUserNotFirstTradeFlag(user);\n }\n\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n\n /*function initialize(address target) external onlyOwner {\n\t\t_setTarget(this.setAffiliatesUserReferrer.selector, target);\n\t}*/\n}\n\ncontract ILoanTokenModulesMock is ILoanTokenModules {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user) external;\n}\n" + }, + "contracts/mockup/MockLoanTokenLogicLM.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../modules/Affiliates.sol\";\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogicLM.sol\";\nimport \"../modules/interfaces/ProtocolAffiliatesInterface.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\ncontract MockLoanTokenLogicLM is LoanTokenLogicLM {\n /*function getAffiliatesUserReferrer(address user) public view returns (address) {\n\t\treturn affiliatesUserReferrer[user]; // REFACTOR: will be useful if affiliatesUserReferrer visibillity is not public\n\t}*/\n\n function getListFunctionSignatures()\n external\n pure\n returns (bytes4[] memory functionSignatures, bytes32 moduleName)\n {\n bytes4[] memory res = new bytes4[](4);\n\n /** LoanTokenLogicLM function signature */\n res[0] = bytes4(keccak256(\"mint(address,uint256)\"));\n res[1] = bytes4(keccak256(\"mint(address,uint256,bool)\"));\n res[2] = bytes4(keccak256(\"burn(address,uint256)\"));\n res[3] = bytes4(keccak256(\"burn(address,uint256,bool)\"));\n\n return (res, stringToBytes32(\"MockLoanTokenLogicLM\"));\n }\n}\n" + }, + "contracts/mockup/modules/IWeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract IWeightedStakingModuleMockup {\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) external;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) external;\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external view returns (uint96);\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) external;\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) external;\n\n /**\n * @notice Compute the voting power for a specific date.\n * Power = stake * weight\n * be internal instead of a public function.\n * @param account The user address.\n * @param date The staking date to compute the power for.\n * @param startDate The date for which we need to know the power of the stake.\n * @param blockNumber The block number, needed for checkpointing.\n * @return The stacking power.\n * */\n function weightedStakeByDate(\n address account,\n uint256 date,\n uint256 startDate,\n uint256 blockNumber\n ) external view returns (uint96 power);\n\n /**\n * @notice Compute the weight for a specific date.\n * @param date The unlocking date.\n * @param startDate We compute the weight for the tokens staked until 'date' on 'startDate'.\n * @return The weighted stake the account had as of the given block.\n * */\n function computeWeightByDate(uint256 date, uint256 startDate)\n external\n pure\n returns (uint96 weight);\n\n /**\n * @notice Receives approval from SOV token.\n * @param _data The data will be used for low level call.\n */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/mockup/modules/StakingModuleBlockMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/StakingGovernanceModule.sol\";\nimport \"../../governance/Staking/modules/StakingStakeModule.sol\";\nimport \"../../governance/Staking/modules/StakingVestingModule.sol\";\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\nimport \"../BlockMockUp.sol\";\n\ncontract StakingModuleBlockMockup is\n IFunctionsList,\n StakingGovernanceModule,\n StakingStakeModule,\n StakingVestingModule,\n WeightedStakingModule\n{\n uint96 public priorWeightedStake;\n mapping(uint256 => uint96) public priorWeightedStakeAtBlock;\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n function balanceOf_MultipliedByTwo(address account) external view returns (uint256) {\n return this.balanceOf(account) * 2;\n }\n\n uint96 priorTotalVotingPower;\n\n function MOCK_priorTotalVotingPower(uint96 _priorTotalVotingPower) public {\n priorTotalVotingPower = _priorTotalVotingPower;\n }\n\n function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\n public\n view\n returns (uint96 totalVotingPower)\n {\n return\n priorTotalVotingPower != 0\n ? priorTotalVotingPower\n : super.getPriorTotalVotingPower(blockNumber, time);\n }\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n /**\n * @notice Add vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function addContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = true;\n emit ContractCodeHashAdded(codeHash);\n }\n\n /**\n * @notice Remove vesting contract's code hash to a map of code hashes.\n * @param vesting The address of Vesting contract.\n * @dev We need it to use _isVestingContract() function instead of isContract()\n */\n function removeContractCodeHash(address vesting) public onlyAuthorized {\n bytes32 codeHash = _getCodeHash(vesting);\n vestingCodeHashes[codeHash] = false;\n emit ContractCodeHashRemoved(codeHash);\n }\n\n /**\n * @notice Return hash of contract code\n */\n function _getCodeHash(address _contract) internal view returns (bytes32) {\n bytes32 codeHash;\n assembly {\n codeHash := extcodehash(_contract)\n }\n return codeHash;\n }\n\n /**\n * @notice Return flag whether the given address is a registered vesting contract.\n * @param stakerAddress the address to check\n */\n function isVestingContract(address stakerAddress) public view returns (bool) {\n bytes32 codeHash = _getCodeHash(stakerAddress);\n return vestingCodeHashes[codeHash];\n }\n\n function getPriorWeightedStakeAtBlock(uint256 blockNum) public view returns (uint256) {\n return uint256(priorWeightedStakeAtBlock[blockNum]);\n }\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n // StakingGovernanceModule\n bytes4[] memory functionsList = new bytes4[](31);\n functionsList[0] = this.getPriorTotalVotingPower.selector;\n functionsList[1] = this.getCurrentVotes.selector;\n functionsList[2] = this.getPriorVotes.selector;\n functionsList[3] = this.getPriorStakeByDateForDelegatee.selector;\n functionsList[4] = this.getPriorTotalStakesForDate.selector;\n functionsList[5] = this.delegate.selector;\n\n // StakingStakeModule\n functionsList[6] = this.stake.selector;\n functionsList[7] = this.stakeWithApproval.selector;\n functionsList[8] = this.extendStakingDuration.selector;\n functionsList[9] = this.stakesBySchedule.selector;\n functionsList[10] = this.stakeBySchedule.selector;\n functionsList[11] = this.balanceOf.selector;\n functionsList[12] = this.getCurrentStakedUntil.selector;\n functionsList[13] = this.getStakes.selector;\n functionsList[14] = this.timestampToLockDate.selector;\n\n //StakingVestingModule\n functionsList[15] = this.setVestingRegistry.selector;\n functionsList[16] = this.setVestingStakes.selector;\n functionsList[17] = this.getPriorUserStakeByDate.selector;\n functionsList[18] = this.getPriorVestingWeightedStake.selector;\n functionsList[19] = this.getPriorVestingStakeByDate.selector;\n functionsList[20] = this.addContractCodeHash.selector;\n functionsList[21] = this.removeContractCodeHash.selector;\n functionsList[22] = this.isVestingContract.selector;\n\n //BlockMockup\n functionsList[23] = this.setBlockMockUpAddr.selector;\n functionsList[24] = this.MOCK_priorWeightedStake.selector;\n functionsList[25] = this.MOCK_priorWeightedStakeAtBlock.selector;\n\n //WeightedStakingModule\n functionsList[26] = this.getPriorWeightedStake.selector;\n functionsList[27] = this.weightedStakeByDate.selector;\n functionsList[28] = this.computeWeightByDate.selector;\n functionsList[29] = this.priorWeightedStakeAtBlock.selector;\n functionsList[30] = this.getPriorWeightedStakeAtBlock.selector;\n\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/modules/StakingSharedModuleMock.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/shared/StakingShared.sol\";\nimport \"../BlockMockUp.sol\";\nimport \"../../proxy/modules/interfaces/IFunctionsList.sol\";\n\ncontract StakingModuleMock is IFunctionsList, StakingShared {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](1);\n functionList[0] = this.setBlockMockUpAddr.selector;\n }\n}\n" + }, + "contracts/mockup/modules/StakingWrapperMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../../interfaces/IERC20.sol\";\n\ncontract StakingWrapperMockup {\n uint256 constant TWO_WEEKS = 1209600;\n\n IStaking staking;\n IERC20 token;\n\n constructor(IStaking _staking, IERC20 _token) public {\n staking = _staking;\n token = _token;\n }\n\n function stake2times(\n uint96 amount,\n uint256 until,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stake(amount, until, stakeFor, delegatee);\n }\n\n function stakeAndExtend(uint96 amount, uint256 until) external {\n require(token.transferFrom(msg.sender, address(this), amount));\n token.approve(address(staking), amount);\n\n staking.stake(amount, until, address(this), address(this));\n staking.extendStakingDuration(until, until + TWO_WEEKS);\n }\n\n function stakeAndStakeBySchedule(\n uint96 amount,\n uint256 until,\n uint256 cliff,\n uint256 duration,\n uint256 intervalLength,\n address stakeFor,\n address delegatee\n ) external {\n require(token.transferFrom(msg.sender, address(this), amount * 2));\n token.approve(address(staking), amount * 2);\n\n staking.stake(amount, until, stakeFor, delegatee);\n staking.stakeBySchedule(amount, cliff, duration, intervalLength, stakeFor, delegatee);\n }\n}\n" + }, + "contracts/mockup/modules/WeightedStakingModuleMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/modules/WeightedStakingModule.sol\";\n\ncontract WeightedStakingModuleMockup is WeightedStakingModule {\n uint96 priorWeightedStake;\n\n function MOCK_priorWeightedStake(uint96 _priorWeightedStake) public {\n priorWeightedStake = _priorWeightedStake;\n }\n\n mapping(uint256 => uint96) priorWeightedStakeAtBlock;\n\n function MOCK_priorWeightedStakeAtBlock(uint96 _priorWeightedStake, uint256 _block) public {\n priorWeightedStakeAtBlock[_block] = _priorWeightedStake;\n }\n\n function getPriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public view returns (uint96) {\n uint96 _priorWeightedStake;\n\n if (priorWeightedStakeAtBlock[blockNumber] != 0) {\n _priorWeightedStake = priorWeightedStakeAtBlock[blockNumber];\n } else {\n _priorWeightedStake = priorWeightedStake != 0\n ? priorWeightedStake\n : _getPriorWeightedStake(account, blockNumber, date);\n }\n\n return _priorWeightedStake;\n }\n\n function calculatePriorWeightedStake(\n address account,\n uint256 blockNumber,\n uint256 date\n ) public {\n getPriorWeightedStake(account, blockNumber, date);\n }\n\n /**\n * @dev We need this function to simulate zero delegate checkpoint value.\n */\n function setDelegateStake(\n address delegatee,\n uint256 lockedTS,\n uint96 value\n ) public {\n uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];\n uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;\n _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, 0);\n }\n\n function getFunctionsList() external pure returns (bytes4[] memory) {\n bytes4[] memory functionsList = new bytes4[](7);\n functionsList[0] = this.getPriorWeightedStake.selector;\n functionsList[1] = this.weightedStakeByDate.selector;\n functionsList[2] = this.computeWeightByDate.selector;\n functionsList[3] = this.MOCK_priorWeightedStake.selector;\n functionsList[4] = this.MOCK_priorWeightedStakeAtBlock.selector;\n functionsList[5] = this.calculatePriorWeightedStake.selector;\n functionsList[6] = this.setDelegateStake.selector;\n return functionsList;\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanToken.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n//@todo can I change this proxy to EIP-1822 proxy standard, please. https://eips.ethereum.org/EIPS/eip-1822. It's really hard to work with this.\ncontract PreviousLoanToken is AdvancedTokenStorage {\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress and wrbtcTokenAddress\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n\n constructor(\n address _newOwner,\n address _newTarget,\n address _sovrynContractAddress,\n address _wrbtcTokenAddress\n ) public {\n transferOwnership(_newOwner);\n _setTarget(_newTarget);\n _setSovrynContractAddress(_sovrynContractAddress);\n _setWrbtcTokenAddress(_wrbtcTokenAddress);\n }\n\n function() external payable {\n if (gasleft() <= 2300) {\n return;\n }\n\n address target = target_;\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n\n function setTarget(address _newTarget) public onlyOwner {\n _setTarget(_newTarget);\n }\n\n function _setTarget(address _newTarget) internal {\n require(Address.isContract(_newTarget), \"target not a contract\");\n target_ = _newTarget;\n }\n\n function _setSovrynContractAddress(address _sovrynContractAddress) internal {\n require(Address.isContract(_sovrynContractAddress), \"sovryn not a contract\");\n sovrynContractAddress = _sovrynContractAddress;\n }\n\n function _setWrbtcTokenAddress(address _wrbtcTokenAddress) internal {\n require(Address.isContract(_wrbtcTokenAddress), \"wrbtc not a contract\");\n wrbtcTokenAddress = _wrbtcTokenAddress;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function initialize(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n}\n" + }, + "contracts/mockup/previousLoanToken/PreviousLoanTokenSettingsLowerAdmin.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../connectors/loantoken/interfaces/ProtocolSettingsLike.sol\";\nimport \"../../connectors/loantoken/AdvancedTokenStorage.sol\";\n\n// It is a LoanToken implementation!\ncontract PreviousLoanTokenSettingsLowerAdmin is AdvancedTokenStorage {\n using SafeMath for uint256;\n\n // It is important to maintain the variables order so the delegate calls can access sovrynContractAddress\n\n // ------------- MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n address public sovrynContractAddress;\n address public wrbtcTokenAddress;\n address internal target_;\n // ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------\n\n event SetTransactionLimits(address[] addresses, uint256[] limits);\n\n //@todo check for restrictions in this contract\n modifier onlyAdmin() {\n require(msg.sender == address(this) || msg.sender == owner(), \"unauthorized\");\n _;\n }\n\n //@todo add check for double init, idk but init usually can be called only once.\n function init(\n address _loanTokenAddress,\n string memory _name,\n string memory _symbol\n ) public onlyOwner {\n loanTokenAddress = _loanTokenAddress;\n\n name = _name;\n symbol = _symbol;\n decimals = IERC20(loanTokenAddress).decimals();\n\n initialPrice = 10**18; // starting price of 1\n }\n\n function() external {\n revert(\"LoanTokenSettingsLowerAdmin - fallback not allowed\");\n }\n\n function setupLoanParams(\n LoanParamsStruct.LoanParams[] memory loanParamsList,\n bool areTorqueLoans\n ) public onlyAdmin {\n bytes32[] memory loanParamsIdList;\n address _loanTokenAddress = loanTokenAddress;\n\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsList[i].loanToken = _loanTokenAddress;\n loanParamsList[i].maxLoanTerm = areTorqueLoans ? 0 : 28 days;\n }\n\n loanParamsIdList = ProtocolSettingsLike(sovrynContractAddress).setupLoanParams(\n loanParamsList\n );\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n loanParamsIds[\n uint256(\n keccak256(\n abi.encodePacked(\n loanParamsList[i].collateralToken,\n areTorqueLoans // isTorqueLoan\n )\n )\n )\n ] = loanParamsIdList[i];\n }\n }\n\n function disableLoanParams(address[] calldata collateralTokens, bool[] calldata isTorqueLoans)\n external\n onlyAdmin\n {\n require(collateralTokens.length == isTorqueLoans.length, \"count mismatch\");\n\n bytes32[] memory loanParamsIdList = new bytes32[](collateralTokens.length);\n for (uint256 i = 0; i < collateralTokens.length; i++) {\n uint256 id =\n uint256(keccak256(abi.encodePacked(collateralTokens[i], isTorqueLoans[i])));\n loanParamsIdList[i] = loanParamsIds[id];\n delete loanParamsIds[id];\n }\n\n ProtocolSettingsLike(sovrynContractAddress).disableLoanParams(loanParamsIdList);\n }\n\n // These params should be percentages represented like so: 5% = 5000000000000000000\n // rateMultiplier + baseRate can't exceed 100%\n function setDemandCurve(\n uint256 _baseRate,\n uint256 _rateMultiplier,\n uint256 _lowUtilBaseRate,\n uint256 _lowUtilRateMultiplier,\n uint256 _targetLevel,\n uint256 _kinkLevel,\n uint256 _maxScaleRate\n ) public onlyAdmin {\n require(_rateMultiplier.add(_baseRate) <= WEI_PERCENT_PRECISION, \"curve params too high\");\n require(\n _lowUtilRateMultiplier.add(_lowUtilBaseRate) <= WEI_PERCENT_PRECISION,\n \"curve params too high\"\n );\n\n require(\n _targetLevel <= WEI_PERCENT_PRECISION && _kinkLevel <= WEI_PERCENT_PRECISION,\n \"levels too high\"\n );\n\n baseRate = _baseRate;\n rateMultiplier = _rateMultiplier;\n lowUtilBaseRate = _lowUtilBaseRate;\n lowUtilRateMultiplier = _lowUtilRateMultiplier;\n\n targetLevel = _targetLevel; // 80 ether\n kinkLevel = _kinkLevel; // 90 ether\n maxScaleRate = _maxScaleRate; // 100 ether\n }\n\n function toggleFunctionPause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public onlyAdmin {\n // keccak256(\"iToken_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xd46a704bc285dbd6ff5ad3863506260b1df02812f4f857c8cc852317a6ac64f2)\n )\n );\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /**\n * sets the transaction limit per token address\n * @param addresses the token addresses\n * @param limits the limit denominated in the currency of the token address\n * */\n function setTransactionLimits(address[] memory addresses, uint256[] memory limits)\n public\n onlyOwner\n {\n require(addresses.length == limits.length, \"mismatched array lengths\");\n for (uint256 i = 0; i < addresses.length; i++) {\n transactionLimit[addresses[i]] = limits[i];\n }\n emit SetTransactionLimits(addresses, limits);\n }\n}\n" + }, + "contracts/mockup/PriceFeedsMoCMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../feeds/testnet/PriceFeedsMoC.sol\";\n\n// This contract is only for test purposes\n// https://github.com/money-on-chain/Amphiraos-Oracle/blob/master/contracts/medianizer/medianizer.sol\ncontract PriceFeedsMoCMockup is Medianizer {\n uint256 public value;\n bool public has;\n\n function peek() external view returns (bytes32, bool) {\n return (bytes32(value), has);\n }\n\n function setValue(uint256 _value) public {\n value = _value;\n }\n\n function setHas(bool _has) public {\n has = _has;\n }\n}\n" + }, + "contracts/mockup/ProtocolSettingsMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../modules/ProtocolSettings.sol\";\n\ncontract ProtocolSettingsMockup is ProtocolSettings {\n function setLendingFeeTokensHeld(address token, uint256 amout) public {\n lendingFeeTokensHeld[token] = amout;\n }\n\n function setTradingFeeTokensHeld(address token, uint256 amout) public {\n tradingFeeTokensHeld[token] = amout;\n }\n\n function setBorrowingFeeTokensHeld(address token, uint256 amout) public {\n borrowingFeeTokensHeld[token] = amout;\n }\n\n function initialize(address target) external onlyOwner {\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n\n _setTarget(this.setLendingFeeTokensHeld.selector, target);\n _setTarget(this.setTradingFeeTokensHeld.selector, target);\n _setTarget(this.setBorrowingFeeTokensHeld.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n\n _setTarget(this.getDefaultPathConversion.selector, target);\n }\n}\n" + }, + "contracts/mockup/proxy/ImplementationMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\n\ncontract ImplementationMockup is StorageMockup {\n function setValue(uint256 _value) public {\n value = _value;\n emit ValueChanged(_value);\n }\n\n function getValue() public view returns (uint256) {\n return value;\n }\n}\n" + }, + "contracts/mockup/proxy/ProxyMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./StorageMockup.sol\";\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract ProxyMockup is StorageMockup, UpgradableProxy {}\n" + }, + "contracts/mockup/proxy/StorageMockup.sol": { + "content": "pragma solidity ^0.5.17;\n\ncontract StorageMockup {\n uint256 value;\n\n event ValueChanged(uint256 value);\n}\n" + }, + "contracts/mockup/RBTCWrapperProxyMockup.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../farm/LiquidityMining.sol\";\n\ncontract RBTCWrapperProxyMockup {\n LiquidityMining public liquidityMining;\n\n constructor(LiquidityMining _liquidityMining) public {\n liquidityMining = _liquidityMining;\n }\n\n function claimReward(address _poolToken) public {\n liquidityMining.claimReward(_poolToken, msg.sender);\n }\n\n function claimRewardFromAllPools() public {\n liquidityMining.claimRewardFromAllPools(msg.sender);\n }\n\n function withdraw(address _poolToken, uint256 _amount) public {\n liquidityMining.withdraw(_poolToken, _amount, msg.sender);\n }\n}\n" + }, + "contracts/mockup/StakingRewardsMockUp.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../governance/StakingRewards/StakingRewards.sol\";\nimport \"./BlockMockUp.sol\";\n\n/**\n * @title Staking Rewards Contract MockUp\n * @notice This is used for Testing\n * */\ncontract StakingRewardsMockUp is StakingRewards {\n ///@notice the block mock up contract\n BlockMockUp public blockMockUp;\n\n using SafeMath for uint256;\n\n /**\n * @notice gets block number from BlockMockUp\n * @param _blockMockUp the address of BlockMockUp\n */\n function setBlockMockUpAddr(address _blockMockUp) public onlyOwner {\n require(_blockMockUp != address(0), \"block mockup address invalid\");\n blockMockUp = BlockMockUp(_blockMockUp);\n }\n\n /**\n * @notice Determine the current Block Number from BlockMockUp\n * */\n function _getCurrentBlockNumber() internal view returns (uint256) {\n return blockMockUp.getBlockNum();\n }\n}\n" + }, + "contracts/mockup/TimelockHarness.sol": { + "content": "pragma solidity ^0.5.16;\n\nimport \"../governance/Timelock.sol\";\n\ninterface Administered {\n function _acceptAdmin() external returns (uint256);\n}\n\ncontract TimelockHarness is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, delay_) {}\n\n function setDelayWithoutChecking(uint256 delay_) public {\n delay = delay_;\n\n emit NewDelay(delay);\n }\n\n function harnessSetPendingAdmin(address pendingAdmin_) public {\n pendingAdmin = pendingAdmin_;\n }\n\n function harnessSetAdmin(address admin_) public {\n admin = admin_;\n }\n}\n\ncontract TimelockTest is Timelock {\n constructor(address admin_, uint256 delay_) public Timelock(admin_, 2 days) {\n delay = delay_;\n }\n\n function harnessSetAdmin(address admin_) public {\n require(msg.sender == admin);\n admin = admin_;\n }\n\n function harnessAcceptAdmin(Administered administered) public {\n administered._acceptAdmin();\n }\n}\n" + }, + "contracts/mockup/VestingLogicMockup.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../governance/Vesting/VestingLogic.sol\";\n\ncontract VestingLogicMockup is VestingLogic {\n /**\n * @dev we had a bug in a loop: \"i < endDate\" instead of \"i <= endDate\"\n */\n function delegate(address _delegatee) public onlyTokenOwner {\n require(_delegatee != address(0), \"delegatee address invalid\");\n\n /// @dev Withdraw for each unlocked position.\n /// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS\n ///\t\tworkaround found, but it doesn't work with TWO_WEEKS\n for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) {\n staking.delegate(_delegatee, i);\n }\n emit VotesDelegated(msg.sender, _delegatee);\n }\n}\n" + }, + "contracts/mockup/VestingRegistryLogicMockUp.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\nimport \"../governance/Vesting/VestingRegistryLogic.sol\";\n\ncontract VestingRegistryLogicMockup is VestingRegistryLogic {\n function isVestingAddress(address _vestingAddress) external view returns (bool isVestingAddr) {\n return true;\n }\n\n function setTeamVesting(address _vesting, uint256 _vestingCreationType) external {\n vestingCreationAndTypes[_vesting] = VestingCreationAndTypeDetails({\n isSet: true,\n vestingType: uint32(VestingType.TeamVesting),\n vestingCreationType: uint128(_vestingCreationType)\n });\n }\n}\n" + }, + "contracts/modules/Affiliates.sol": { + "content": "/**\n * Copyright 2017-2020, Sovryn, All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../events/AffiliatesEvents.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../locked/ILockedSOV.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Affiliates contract.\n * @notice Track referrals and reward referrers (affiliates) with tokens.\n * In-detail specifications are found at https://wiki.sovryn.app/en/community/Affiliates\n * @dev Module: Affiliates upgradable\n * Storage: from State, functions called from Protocol by delegatecall\n */\ncontract Affiliates is State, AffiliatesEvents, ModuleCommonFunctionalities {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Void constructor.\n */\n // solhint-disable-next-line no-empty-blocks\n constructor() public {}\n\n /**\n * @notice Avoid calls to this contract except for those explicitly declared.\n */\n function() external {\n revert(\"Affiliates - fallback not allowed\");\n }\n\n /**\n * @notice Set delegate callable functions by proxy contract.\n * @dev This contract is designed as a module, this way logic can be\n * expanded and upgraded w/o losing storage that is kept in the protocol (State.sol)\n * initialize() is used to register in the proxy external (module) functions\n * to be called via the proxy.\n * @param target The address of a new logic implementation.\n */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setAffiliatesReferrer.selector];\n _setTarget(this.setAffiliatesReferrer.selector, target);\n _setTarget(this.getUserNotFirstTradeFlag.selector, target);\n _setTarget(this.getReferralsList.selector, target);\n _setTarget(this.setUserNotFirstTradeFlag.selector, target);\n _setTarget(this.payTradingFeeToAffiliatesReferrer.selector, target);\n _setTarget(this.getAffiliatesReferrerBalances.selector, target);\n _setTarget(this.getAffiliatesReferrerTokenBalance.selector, target);\n _setTarget(this.getAffiliatesReferrerTokensList.selector, target);\n _setTarget(this.withdrawAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.withdrawAllAffiliatesReferrerTokenFees.selector, target);\n _setTarget(this.getMinReferralsToPayout.selector, target);\n _setTarget(this.getAffiliatesUserReferrer.selector, target);\n _setTarget(this.getAffiliateRewardsHeld.selector, target);\n _setTarget(this.getAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.getAffiliatesTokenRewardsValueInRbtc.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"Affiliates\");\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from loan pools.\n */\n modifier onlyCallableByLoanPools() {\n require(loanPoolToUnderlying[msg.sender] != address(0), \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Function modifier to avoid any other calls not coming from within protocol functions.\n */\n modifier onlyCallableInternal() {\n require(msg.sender == protocolAddress, \"Affiliates: not authorized\");\n _;\n }\n\n /**\n * @notice Data structure comprised of 3 flags to compute the result of setting a referrer.\n */\n struct SetAffiliatesReferrerResult {\n bool success;\n bool alreadySet;\n bool userNotFirstTradeFlag;\n }\n\n /**\n * @notice Loan pool calls this function to tell affiliates\n * a user coming from a referrer is trading and should be registered if not yet.\n * Taking into account some user status flags may lead to the user and referrer\n * become added or not to the affiliates record.\n *\n * @param user The address of the user that is trading on loan pools.\n * @param referrer The address of the referrer the user is coming from.\n */\n function setAffiliatesReferrer(address user, address referrer)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n SetAffiliatesReferrerResult memory result;\n\n result.userNotFirstTradeFlag = getUserNotFirstTradeFlag(user);\n result.alreadySet = affiliatesUserReferrer[user] != address(0);\n result.success = !(result.userNotFirstTradeFlag || result.alreadySet || user == referrer);\n if (result.success) {\n affiliatesUserReferrer[user] = referrer;\n referralsList[referrer].add(user);\n emit SetAffiliatesReferrer(user, referrer);\n } else {\n emit SetAffiliatesReferrerFail(\n user,\n referrer,\n result.alreadySet,\n result.userNotFirstTradeFlag\n );\n }\n }\n\n /**\n * @notice Getter to query the referrals coming from a referrer.\n * @param referrer The address of a given referrer.\n * @return The referralsList mapping value by referrer.\n */\n function getReferralsList(address referrer) external view returns (address[] memory refList) {\n refList = referralsList[referrer].enumerate();\n return refList;\n }\n\n /**\n * @notice Getter to query the not-first-trade flag of a user.\n * @param user The address of a given user.\n * @return The userNotFirstTradeFlag mapping value by user.\n */\n function getUserNotFirstTradeFlag(address user) public view returns (bool) {\n return userNotFirstTradeFlag[user];\n }\n\n /**\n * @notice Setter to toggle on the not-first-trade flag of a user.\n * @param user The address of a given user.\n */\n function setUserNotFirstTradeFlag(address user)\n external\n onlyCallableByLoanPools\n whenNotPaused\n {\n if (!userNotFirstTradeFlag[user]) {\n userNotFirstTradeFlag[user] = true;\n emit SetUserNotFirstTradeFlag(user);\n }\n }\n\n /**\n * @notice Internal getter to query the fee share for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function _getAffiliatesTradingFeePercentForSOV() internal view returns (uint256) {\n return affiliateFeePercent;\n }\n\n /**\n * @notice Internal to calculate the affiliates trading token fee amount.\n * Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * This _getReferrerTradingFeeForToken calculates the first one\n * by applying a custom percentage multiplier.\n * @param feeTokenAmount The trading token fee amount.\n * @return The affiliates share of the trading token fee amount.\n */\n function _getReferrerTradingFeeForToken(uint256 feeTokenAmount)\n internal\n view\n returns (uint256)\n {\n return feeTokenAmount.mul(getAffiliateTradingTokenFeePercent()).div(10**20);\n }\n\n /**\n * @notice Getter to query the fee share of trading token fee for affiliate program.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The percentage of fee share w/ 18 decimals.\n */\n function getAffiliateTradingTokenFeePercent() public view returns (uint256) {\n return affiliateTradingTokenFeePercent;\n }\n\n /**\n * @notice Getter to query referral threshold for paying out to the referrer.\n * @dev It returns a value defined at protocol storage (State.sol)\n * @return The minimum number of referrals set by Protocol.\n */\n function getMinReferralsToPayout() public view returns (uint256) {\n return minReferralsToPayout;\n }\n\n /**\n * @notice Get the sovToken reward of a trade.\n * @dev The reward is worth x% of the trading fee.\n * @param feeToken The address of the token in which the trading/borrowing fee was paid.\n * @param feeAmount The height of the fee.\n * @return The reward amount.\n * */\n function _getSovBonusAmount(address feeToken, uint256 feeAmount)\n internal\n view\n returns (uint256)\n {\n uint256 rewardAmount;\n address _priceFeeds = priceFeeds;\n\n /// @dev Calculate the reward amount, querying the price feed.\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n feeToken,\n sovTokenAddress, /// dest token = SOV\n feeAmount.mul(_getAffiliatesTradingFeePercentForSOV()).div(1e20)\n )\n );\n // solhint-disable-next-line no-inline-assembly\n assembly {\n if eq(success, 1) {\n rewardAmount := mload(add(data, 32))\n }\n }\n\n return rewardAmount;\n }\n\n /**\n * @notice Protocol calls this function to pay the affiliates rewards to a user (referrer).\n *\n * @dev Affiliates program has 2 kind of rewards:\n * 1. x% based on the fee of the token that is traded (in form of the token itself).\n * 2. x% based on the fee of the token that is traded (in form of SOV).\n * Both are paid in this function.\n *\n * @dev Actually they are not paid, but just holded by protocol until user claims them by\n * actively calling withdrawAffiliatesReferrerTokenFees() function,\n * and/or when unvesting lockedSOV.\n *\n * @dev To be precise, what this function does is updating the registers of the rewards\n * for the referrer including the assignment of the SOV tokens as rewards to the\n * referrer's vesting contract.\n *\n * @param referrer The address of the referrer.\n * @param trader The address of the trader.\n * @param token The address of the token in which the trading/borrowing fee was paid.\n * @param tradingFeeTokenBaseAmount Total trading fee amount, the base for calculating referrer's fees.\n *\n * @return referrerBonusSovAmount The amount of SOV tokens paid to the referrer (through a vesting contract, lockedSOV).\n * @return referrerBonusTokenAmount The amount of trading tokens paid directly to the referrer.\n */\n function payTradingFeeToAffiliatesReferrer(\n address referrer,\n address trader,\n address token,\n uint256 tradingFeeTokenBaseAmount\n )\n external\n onlyCallableInternal\n whenNotPaused\n returns (uint256 referrerBonusSovAmount, uint256 referrerBonusTokenAmount)\n {\n bool isHeld = referralsList[referrer].length() < getMinReferralsToPayout();\n bool bonusPaymentIsSuccess = true;\n uint256 paidReferrerBonusSovAmount;\n\n /// Process token fee rewards first.\n referrerBonusTokenAmount = _getReferrerTradingFeeForToken(tradingFeeTokenBaseAmount);\n if (!affiliatesReferrerTokensList[referrer].contains(token))\n affiliatesReferrerTokensList[referrer].add(token);\n affiliatesReferrerBalances[referrer][token] = affiliatesReferrerBalances[referrer][token]\n .add(referrerBonusTokenAmount);\n\n /// Then process SOV rewards.\n referrerBonusSovAmount = _getSovBonusAmount(token, tradingFeeTokenBaseAmount);\n uint256 rewardsHeldByProtocol = affiliateRewardsHeld[referrer];\n\n if (isHeld) {\n /// If referrals less than minimum, temp the rewards SOV to the storage\n affiliateRewardsHeld[referrer] = rewardsHeldByProtocol.add(referrerBonusSovAmount);\n } else {\n /// If referrals >= minimum, directly send all of the remain rewards to locked sov\n /// Call depositSOV() in LockedSov contract\n /// Set the affiliaterewardsheld = 0\n if (affiliateRewardsHeld[referrer] > 0) {\n affiliateRewardsHeld[referrer] = 0;\n }\n\n paidReferrerBonusSovAmount = referrerBonusSovAmount.add(rewardsHeldByProtocol);\n IERC20(sovTokenAddress).approve(lockedSOVAddress, paidReferrerBonusSovAmount);\n\n (bool success, ) =\n lockedSOVAddress.call(\n abi.encodeWithSignature(\n \"depositSOV(address,uint256)\",\n referrer,\n paidReferrerBonusSovAmount\n )\n );\n\n if (!success) {\n bonusPaymentIsSuccess = false;\n }\n }\n\n if (bonusPaymentIsSuccess) {\n emit PayTradingFeeToAffiliate(\n referrer,\n trader, // trader\n token,\n isHeld,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n } else {\n emit PayTradingFeeToAffiliateFail(\n referrer,\n trader, // trader\n token,\n tradingFeeTokenBaseAmount,\n referrerBonusTokenAmount,\n referrerBonusSovAmount,\n paidReferrerBonusSovAmount\n );\n }\n\n return (referrerBonusSovAmount, referrerBonusTokenAmount);\n }\n\n /**\n * @notice Referrer calls this function to receive its reward in a given token.\n * It will send the other (non-SOV) reward tokens from trading protocol fees,\n * to the referrer’s wallet.\n * @dev Rewards are held by protocol in different tokens coming from trading fees.\n * Referrer has to claim them one by one for every token with accumulated balance.\n * @param token The address of the token to withdraw.\n * @param receiver The address of the withdrawal beneficiary.\n * @param amount The amount of tokens to claim. If greater than balance, just sends balance.\n */\n function withdrawAffiliatesReferrerTokenFees(\n address token,\n address receiver,\n uint256 amount\n ) public whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n uint256 referrerTokenBalance = affiliatesReferrerBalances[referrer][token];\n uint256 withdrawAmount = referrerTokenBalance > amount ? amount : referrerTokenBalance;\n\n require(withdrawAmount > 0, \"Affiliates: cannot withdraw zero amount\");\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n uint256 newReferrerTokenBalance = referrerTokenBalance.sub(withdrawAmount);\n\n if (newReferrerTokenBalance == 0) {\n _removeAffiliatesReferrerToken(referrer, token);\n } else {\n affiliatesReferrerBalances[referrer][token] = newReferrerTokenBalance;\n }\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawAffiliatesReferrerTokenFees(referrer, receiver, token, withdrawAmount);\n }\n\n /**\n * @notice Withdraw to msg.sender all token fees for a referrer.\n * @dev It's done by looping through its available tokens.\n * @param receiver The address of the withdrawal beneficiary.\n */\n function withdrawAllAffiliatesReferrerTokenFees(address receiver) external whenNotPaused {\n require(receiver != address(0), \"Affiliates: cannot withdraw to zero address\");\n address referrer = msg.sender;\n\n require(\n referralsList[referrer].length() >= getMinReferralsToPayout(),\n \"Your referrals has not reached the minimum request\"\n );\n\n (address[] memory tokenAddresses, uint256[] memory tokenBalances) =\n getAffiliatesReferrerBalances(referrer);\n for (uint256 i; i < tokenAddresses.length; i++) {\n withdrawAffiliatesReferrerTokenFees(tokenAddresses[i], receiver, tokenBalances[i]);\n }\n }\n\n /**\n * @notice Internal function to delete a referrer's token balance.\n * @param referrer The address of the referrer.\n * @param token The address of the token specifying the balance to remove.\n */\n function _removeAffiliatesReferrerToken(address referrer, address token) internal {\n delete affiliatesReferrerBalances[referrer][token];\n affiliatesReferrerTokensList[referrer].remove(token);\n }\n\n /**\n * @notice Get all token balances of a referrer.\n * @param referrer The address of the referrer.\n * @return referrerTokensList The array of available tokens (keys).\n * @return referrerTokensBalances The array of token balances (values).\n */\n function getAffiliatesReferrerBalances(address referrer)\n public\n view\n returns (address[] memory referrerTokensList, uint256[] memory referrerTokensBalances)\n {\n referrerTokensList = getAffiliatesReferrerTokensList(referrer);\n referrerTokensBalances = new uint256[](referrerTokensList.length);\n for (uint256 i; i < referrerTokensList.length; i++) {\n referrerTokensBalances[i] = getAffiliatesReferrerTokenBalance(\n referrer,\n referrerTokensList[i]\n );\n }\n return (referrerTokensList, referrerTokensBalances);\n }\n\n /**\n * @dev Get all token rewards estimation value in rbtc.\n *\n * @param referrer Address of referrer.\n *\n * @return The value estimation in rbtc.\n */\n function getAffiliatesTokenRewardsValueInRbtc(address referrer)\n external\n view\n returns (uint256 rbtcTotalAmount)\n {\n address[] memory tokensList = getAffiliatesReferrerTokensList(referrer);\n address _priceFeeds = priceFeeds;\n\n for (uint256 i; i < tokensList.length; i++) {\n // Get the value of each token in rbtc\n\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).queryReturn.selector,\n tokensList[i], // source token\n address(wrbtcToken), // dest token = SOV\n affiliatesReferrerBalances[referrer][tokensList[i]] // total token rewards\n )\n );\n\n assembly {\n if eq(success, 1) {\n rbtcTotalAmount := add(rbtcTotalAmount, mload(add(data, 32)))\n }\n }\n }\n }\n\n /**\n * @notice Get all available tokens at the affiliates program for a given referrer.\n * @param referrer The address of a given referrer.\n * @return tokensList The list of available tokens.\n */\n function getAffiliatesReferrerTokensList(address referrer)\n public\n view\n returns (address[] memory tokensList)\n {\n tokensList = affiliatesReferrerTokensList[referrer].enumerate();\n return tokensList;\n }\n\n /**\n * @notice Getter to query the affiliate balance for a given referrer and token.\n * @param referrer The address of the referrer.\n * @param token The address of the token to get balance for.\n * @return The affiliatesReferrerBalances mapping value by referrer and token keys.\n */\n function getAffiliatesReferrerTokenBalance(address referrer, address token)\n public\n view\n returns (uint256)\n {\n return affiliatesReferrerBalances[referrer][token];\n }\n\n /**\n * @notice Getter to query the address of referrer for a given user.\n * @param user The address of the user.\n * @return The address on affiliatesUserReferrer mapping value by user key.\n */\n function getAffiliatesUserReferrer(address user) public view returns (address) {\n return affiliatesUserReferrer[user];\n }\n\n /**\n * @notice Getter to query the reward amount held for a given referrer.\n * @param referrer The address of the referrer.\n * @return The affiliateRewardsHeld mapping value by referrer key.\n */\n function getAffiliateRewardsHeld(address referrer) public view returns (uint256) {\n return affiliateRewardsHeld[referrer];\n }\n}\n" + }, + "contracts/modules/interfaces/ProtocolAffiliatesInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolAffiliatesInterface {\n function setAffiliatesReferrer(address user, address referrer) external;\n\n function setUserNotFirstTradeFlag(address user_) external;\n\n function getUserNotFirstTradeFlag(address user_) external returns (bool);\n\n function payTradingFeeToAffiliatesReferrer(\n address affiliate,\n address trader,\n address token,\n uint256 amount\n ) external returns (uint256 affiliatesBonusSOVAmount, uint256 affiliatesBonusTokenAmount);\n}\n" + }, + "contracts/modules/interfaces/ProtocolSwapExternalInterface.sol": { + "content": "/**\n * Copyright 2020, Denis Savelev. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\ninterface ProtocolSwapExternalInterface {\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes calldata swapData\n ) external returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed);\n}\n" + }, + "contracts/modules/LoanClosingsLiquidation.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsLiquidation contract.\n * @notice Ways to close a loan: liquidation. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsLiquidation is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.liquidate.selector];\n _setTarget(this.liquidate.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsLiquidation\"\n );\n }\n\n /**\n * @notice Liquidate an unhealty loan.\n *\n * @dev Public wrapper for _liquidate internal function.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * loanId is the ID of the loan, which is created on loan opening.\n * It can be obtained either by parsing the Trade event or by reading\n * the open loans from the contract by calling getActiveLoans or getUserLoans.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount // denominated in loanToken\n )\n external\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n return _liquidate(loanId, receiver, closeAmount);\n }\n\n /**\n * @notice Internal function for liquidating an unhealthy loan.\n *\n * The caller needs to approve the closeAmount prior to calling. Will\n * not liquidate more than is needed to restore the desired margin\n * (maintenance +5%).\n *\n * Whenever the current margin of a loan falls below maintenance margin,\n * it needs to be liquidated. Anybody can initiate a liquidation and buy\n * the collateral tokens at a discounted rate (5%).\n *\n * @param loanId The ID of the loan to liquidate.\n * @param receiver The receiver of the seized amount.\n * @param closeAmount The amount to close in loanTokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return seizedAmount The seized amount in the collateral token.\n * @return seizedToken The loan token address.\n * */\n function _liquidate(\n bytes32 loanId,\n address receiver,\n uint256 closeAmount\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 seizedAmount,\n address seizedToken\n )\n {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin <= loanParamsLocal.maintenanceMargin, \"healthy position\");\n\n loanCloseAmount = closeAmount;\n\n //amounts to restore the desired margin (maintencance + 5%)\n (uint256 maxLiquidatable, uint256 maxSeizable, ) =\n _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n\n if (loanCloseAmount < maxLiquidatable) {\n //close maxLiquidatable if tiny position will remain\n uint256 remainingAmount = maxLiquidatable - loanCloseAmount;\n remainingAmount = _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingAmount <= TINY_AMOUNT) {\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable.mul(loanCloseAmount).div(maxLiquidatable);\n }\n } else if (loanCloseAmount > maxLiquidatable) {\n // adjust down the close amount to the max\n loanCloseAmount = maxLiquidatable;\n seizedAmount = maxSeizable;\n } else {\n seizedAmount = maxSeizable;\n }\n\n require(loanCloseAmount != 0, \"nothing to liquidate\");\n\n // liquidator deposits the principal being closed\n _returnPrincipalWithDeposit(loanParamsLocal.loanToken, address(this), loanCloseAmount);\n\n // a portion of the principal is repaid to the lender out of interest refunded\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n loanLocal.borrower\n );\n\n if (loanCloseAmount > loanCloseAmountLessInterest) {\n // full interest refund goes to the borrower\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanCloseAmount - loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmountLessInterest != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n seizedToken = loanParamsLocal.collateralToken;\n\n if (seizedAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(seizedAmount);\n\n _withdrawAsset(seizedToken, receiver, seizedAmount);\n }\n\n _closeLoan(loanLocal, loanCloseAmount);\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n seizedAmount,\n collateralToLoanRate,\n 0,\n currentMargin,\n CloseTypes.Liquidation\n );\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsRollover.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsRollover contract.\n * @notice Ways to close a loan: rollover. Margin trade\n * positions are always closed with a swap.\n *\n * */\ncontract LoanClosingsRollover is LoanClosingsShared, LiquidationHelper {\n uint256 internal constant MONTH = 365 days / 12;\n\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.rollover.selector];\n _setTarget(this.rollover.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"LoanClosingsRollover\"\n );\n }\n\n /**\n * @notice Roll over a loan.\n *\n * @dev Public wrapper for _rollover internal function.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * The function rollover on the protocol contract extends the loan\n * duration by the maximum term (28 days for margin trades at the moment\n * of writing), pays the interest to the lender and refunds the caller\n * for the gas cost by sending 2 * the gas cost using the fast gas price\n * as base for the calculation.\n *\n * @param loanId The ID of the loan to roll over.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n * */\n function rollover(\n bytes32 loanId,\n bytes calldata // for future use /*loanDataBytes*/\n ) external nonReentrant globallyNonReentrant iTokenSupplyUnchanged(loanId) whenNotPaused {\n // restrict to EOAs to prevent griefing attacks, during interest rate recalculation\n require(msg.sender == tx.origin, \"EOAs call\");\n\n return\n _rollover(\n loanId,\n \"\" // loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for roll over a loan.\n *\n * Each loan has a duration. In case of a margin trade it is set to 28\n * days, in case of borrowing, it can be set by the user. On loan\n * openning, the user pays the interest for this duration in advance.\n * If closing early, he gets the excess refunded. If it is not closed\n * before the end date, it needs to be rolled over. On rollover the\n * interest is paid for the next period. In case of margin trading\n * it's 28 days, in case of borrowing it's a month.\n *\n * @param loanId The ID of the loan to roll over.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n * */\n function _rollover(bytes32 loanId, bytes memory loanDataBytes) internal {\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n require(block.timestamp > loanLocal.endTimestamp.sub(3600), \"healthy position\");\n require(loanPoolToUnderlying[loanLocal.lender] != address(0), \"invalid lender\");\n\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n // Handle back interest: calculates interest owned since the loan endtime passed but the loan remained open\n uint256 backInterestTime;\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestTime = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestTime.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(1 days);\n }\n\n //note: to avoid code duplication, it would be nicer to store loanParamsLocal.maxLoanTerm in a local variable\n //however, we've got stack too deep issues if we do so.\n if (loanParamsLocal.maxLoanTerm != 0) {\n // fixed-term loan, so need to query iToken for latest variable rate\n uint256 owedPerDay =\n loanLocal.principal.mul(ILoanPool(loanLocal.lender).borrowInterestRate()).div(\n 365 * 10**20\n );\n\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(\n loanInterestLocal.owedPerDay\n );\n\n loanInterestLocal.owedPerDay = owedPerDay;\n\n //if the loan has been open for longer than an additional period, add at least 1 additional day\n if (backInterestTime >= loanParamsLocal.maxLoanTerm) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n }\n //extend by the max loan term\n else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(loanParamsLocal.maxLoanTerm);\n }\n } else {\n // loanInterestLocal.owedPerDay doesn't change\n if (backInterestTime >= MONTH) {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(backInterestTime).add(1 days);\n } else {\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(MONTH);\n }\n }\n\n uint256 interestAmountRequired = loanLocal.endTimestamp.sub(block.timestamp);\n interestAmountRequired = interestAmountRequired.mul(loanInterestLocal.owedPerDay);\n interestAmountRequired = interestAmountRequired.div(1 days);\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n\n // add backInterestOwed\n interestAmountRequired = interestAmountRequired.add(backInterestOwed);\n\n // collect interest (needs to be converted from the collateral)\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n 0, //min swap 0 -> swap connector estimates the amount of source tokens to use\n interestAmountRequired, //required destination tokens\n true, // returnTokenIsCollateral\n loanDataBytes\n );\n\n //received more tokens than needed to pay the interest\n if (destTokenAmountReceived > interestAmountRequired) {\n // swap rest back to collateral, if the amount is big enough to cover gas cost\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n )\n ) {\n (destTokenAmountReceived, , ) = _swapBackExcess(\n loanLocal,\n loanParamsLocal,\n destTokenAmountReceived - interestAmountRequired, //amount to be swapped\n loanDataBytes\n );\n sourceTokenAmountUsed = sourceTokenAmountUsed.sub(destTokenAmountReceived);\n }\n //else give it to the protocol as a lending fee\n else {\n _payLendingFee(\n loanLocal.borrower,\n loanParamsLocal.loanToken,\n destTokenAmountReceived - interestAmountRequired\n );\n }\n }\n\n //subtract the interest from the collateral\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n if (backInterestOwed != 0) {\n // pay out backInterestOwed\n\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n uint256 rolloverReward =\n _getRolloverReward(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.principal\n );\n\n if (rolloverReward != 0) {\n // if the reward > collateral:\n if (rolloverReward > loanLocal.collateral) {\n // 1. pay back the remaining loan to the lender\n // 2. pay the remaining collateral to msg.sender\n // 3. close the position & emit close event\n _closeWithSwap(\n loanLocal.id,\n msg.sender,\n loanLocal.collateral,\n false,\n \"\" // loanDataBytes\n );\n } else {\n // pay out reward to caller\n loanLocal.collateral = loanLocal.collateral.sub(rolloverReward);\n\n _withdrawAsset(loanParamsLocal.collateralToken, msg.sender, rolloverReward);\n }\n }\n\n if (loanLocal.collateral > 0) {\n //close whole loan if tiny position will remain\n if (_getAmountInRbtc(loanParamsLocal.loanToken, loanLocal.principal) <= TINY_AMOUNT) {\n _closeWithSwap(\n loanLocal.id,\n loanLocal.borrower,\n loanLocal.collateral, // swap all collaterals\n false,\n \"\" /// loanDataBytes\n );\n } else {\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n require(\n currentMargin > 3 ether, // ensure there's more than 3% margin remaining\n \"unhealthy position\"\n );\n }\n }\n\n if (loanLocal.active) {\n emit Rollover(\n loanLocal.borrower, // user (borrower)\n loanLocal.lender, // lender\n loanLocal.id, // loanId\n loanLocal.principal, // principal\n loanLocal.collateral, // collateral\n loanLocal.endTimestamp, // endTimestamp\n msg.sender, // rewardReceiver\n rolloverReward // reward\n );\n }\n }\n\n /**\n * @notice Swap back excessive loan tokens to collateral tokens.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount The amount to be swapped.\n * @param loanDataBytes Additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived The amount of destiny tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _swapBackExcess(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n swapAmount, // maxSourceTokenAmount\n 0, // requiredDestTokenAmount\n false, // bypassFee\n loanDataBytes\n );\n require(sourceTokenAmountUsed <= swapAmount, \"excessive source amount\");\n }\n}\n" + }, + "contracts/modules/LoanClosingsShared.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanClosingsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/RewardHelper.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../interfaces/ILoanTokenModules.sol\";\n\n/**\n * @title LoanClosingsShared contract.\n * @notice This contract should only contains the internal function that is being used / utilized by\n * LoanClosingsLiquidation, LoanClosingsRollover & LoanClosingsWith contract\n *\n * */\ncontract LoanClosingsShared is\n LoanClosingsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n RewardHelper,\n ModuleCommonFunctionalities\n{\n uint256 internal constant MONTH = 365 days / 12;\n //0.00001 BTC, would be nicer in State.sol, but would require a redeploy of the complete protocol, so adding it here instead\n //because it's not shared state anyway and only used by this contract\n uint256 public constant paySwapExcessToBorrowerThreshold = 10000000000000;\n\n uint256 public constant TINY_AMOUNT = 25e13;\n\n enum CloseTypes { Deposit, Swap, Liquidation }\n\n /** modifier for invariant check */\n modifier iTokenSupplyUnchanged(bytes32 loanId) {\n Loan storage loanLocal = loans[loanId];\n\n require(loanLocal.lender != address(0), \"Invalid loan token pool address\");\n\n uint256 previousITokenSupply = ILoanTokenModules(loanLocal.lender).totalSupply();\n\n _;\n\n /// Validate iToken total supply\n require(\n previousITokenSupply == ILoanTokenModules(loanLocal.lender).totalSupply(),\n \"loan token supply invariant check failure\"\n );\n }\n\n /**\n * @dev computes the interest which needs to be refunded to the borrower based on the amount he's closing and either\n * subtracts it from the amount which still needs to be paid back (in case outstanding amount > interest) or withdraws the\n * excess to the borrower (in case interest > outstanding).\n * @param loanLocal the loan\n * @param loanParamsLocal the loan params\n * @param loanCloseAmount the amount to be closed (base for the computation)\n * @param receiver the address of the receiver (usually the borrower)\n * */\n function _settleInterestToPrincipal(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 loanCloseAmount,\n address receiver\n ) internal returns (uint256) {\n uint256 loanCloseAmountLessInterest = loanCloseAmount;\n\n //compute the interest which neeeds to be refunded to the borrower (because full interest is paid on loan )\n uint256 interestRefundToBorrower =\n _settleInterest(loanParamsLocal, loanLocal, loanCloseAmountLessInterest);\n\n uint256 interestAppliedToPrincipal;\n //if the outstanding loan is bigger than the interest to be refunded, reduce the amount to be paid back / closed by the interest\n if (loanCloseAmountLessInterest >= interestRefundToBorrower) {\n // apply all of borrower interest refund torwards principal\n interestAppliedToPrincipal = interestRefundToBorrower;\n\n // principal needed is reduced by this amount\n loanCloseAmountLessInterest -= interestRefundToBorrower;\n\n // no interest refund remaining\n interestRefundToBorrower = 0;\n } else {\n //if the interest refund is bigger than the outstanding loan, the user needs to get back the interest\n // principal fully covered by excess interest\n interestAppliedToPrincipal = loanCloseAmountLessInterest;\n\n // amount refunded is reduced by this amount\n interestRefundToBorrower -= loanCloseAmountLessInterest;\n\n // principal fully covered by excess interest\n loanCloseAmountLessInterest = 0;\n\n if (interestRefundToBorrower != 0) {\n // refund overage\n _withdrawAsset(loanParamsLocal.loanToken, receiver, interestRefundToBorrower);\n }\n }\n\n //pay the interest to the lender\n //note: this is a waste of gas, because the loanCloseAmountLessInterest is withdrawn to the lender, too. It could be done at once.\n if (interestAppliedToPrincipal != 0) {\n // The lender always gets back an ERC20 (even wrbtc), so we call withdraw directly rather than\n // use the _withdrawAsset helper function\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, interestAppliedToPrincipal);\n }\n\n return loanCloseAmountLessInterest;\n }\n\n // The receiver always gets back an ERC20 (even wrbtc)\n function _returnPrincipalWithDeposit(\n address loanToken,\n address receiver,\n uint256 principalNeeded\n ) internal {\n if (principalNeeded != 0) {\n if (msg.value == 0) {\n vaultTransfer(loanToken, msg.sender, receiver, principalNeeded);\n } else {\n require(loanToken == address(wrbtcToken), \"wrong asset sent\");\n require(msg.value >= principalNeeded, \"not enough ether\");\n wrbtcToken.deposit.value(principalNeeded)();\n if (receiver != address(this)) {\n vaultTransfer(loanToken, address(this), receiver, principalNeeded);\n }\n if (msg.value > principalNeeded) {\n // refund overage\n Address.sendValue(msg.sender, msg.value - principalNeeded);\n }\n }\n } else {\n require(msg.value == 0, \"wrong asset sent\");\n }\n }\n\n /**\n * @dev checks if the amount of the asset to be transfered is worth the transfer fee\n * @param asset the asset to be transfered\n * @param amount the amount to be transfered\n * @return True if the amount is bigger than the threshold\n * */\n function worthTheTransfer(address asset, uint256 amount) internal returns (bool) {\n uint256 amountInRbtc = _getAmountInRbtc(asset, amount);\n emit swapExcess(\n amountInRbtc > paySwapExcessToBorrowerThreshold,\n amount,\n amountInRbtc,\n paySwapExcessToBorrowerThreshold\n );\n\n return amountInRbtc > paySwapExcessToBorrowerThreshold;\n }\n\n /**\n * swaps collateral tokens for loan tokens\n * @param loanLocal the loan object\n * @param loanParamsLocal the loan parameters\n * @param swapAmount the amount to be swapped\n * @param principalNeeded the required destination token amount\n * @param returnTokenIsCollateral if true -> required destination token amount will be passed on, else not\n * note: quite dirty. should be refactored.\n * @param loanDataBytes additional loan data (not in use for token swaps)\n * */\n function _doCollateralSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 collateralToLoanSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed, collateralToLoanSwapRate) = _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n swapAmount, // minSourceTokenAmount\n loanLocal.collateral, // maxSourceTokenAmount\n returnTokenIsCollateral\n ? principalNeeded // requiredDestTokenAmount\n : 0,\n false, // bypassFee\n loanDataBytes\n );\n require(destTokenAmountReceived >= principalNeeded, \"insufficient dest amount\");\n require(sourceTokenAmountUsed <= loanLocal.collateral, \"excessive source amount\");\n }\n\n /**\n * @notice Withdraw asset to receiver.\n *\n * @param assetToken The loan token.\n * @param receiver The address of the receiver.\n * @param assetAmount The loan token amount.\n * */\n function _withdrawAsset(\n address assetToken,\n address receiver,\n uint256 assetAmount\n ) internal {\n if (assetAmount != 0) {\n if (assetToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, assetAmount);\n } else {\n vaultWithdraw(assetToken, receiver, assetAmount);\n }\n }\n }\n\n /**\n * @notice Internal function to close a loan.\n *\n * @param loanLocal The loan object.\n * @param loanCloseAmount The amount to close: principal or lower.\n *\n * */\n function _closeLoan(Loan storage loanLocal, uint256 loanCloseAmount) internal {\n require(loanCloseAmount != 0, \"nothing to close\");\n\n if (loanCloseAmount == loanLocal.principal) {\n loanLocal.principal = 0;\n loanLocal.active = false;\n loanLocal.endTimestamp = block.timestamp;\n loanLocal.pendingTradesId = 0;\n activeLoansSet.removeBytes32(loanLocal.id);\n lenderLoanSets[loanLocal.lender].removeBytes32(loanLocal.id);\n borrowerLoanSets[loanLocal.borrower].removeBytes32(loanLocal.id);\n } else {\n loanLocal.principal = loanLocal.principal.sub(loanCloseAmount);\n }\n }\n\n function _settleInterest(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 closePrincipal\n ) internal returns (uint256) {\n // pay outstanding interest to lender\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 interestTime = block.timestamp;\n if (interestTime > loanLocal.endTimestamp) {\n interestTime = loanLocal.endTimestamp;\n }\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n interestTime\n );\n\n uint256 owedPerDayRefund;\n if (closePrincipal < loanLocal.principal) {\n owedPerDayRefund = loanInterestLocal.owedPerDay.mul(closePrincipal).div(\n loanLocal.principal\n );\n } else {\n owedPerDayRefund = loanInterestLocal.owedPerDay;\n }\n\n // update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.sub(owedPerDayRefund);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.sub(owedPerDayRefund);\n\n // update borrower interest\n uint256 interestRefundToBorrower = loanLocal.endTimestamp.sub(interestTime);\n interestRefundToBorrower = interestRefundToBorrower.mul(owedPerDayRefund);\n interestRefundToBorrower = interestRefundToBorrower.div(1 days);\n\n if (closePrincipal < loanLocal.principal) {\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(\n interestRefundToBorrower\n );\n } else {\n loanInterestLocal.depositTotal = 0;\n }\n\n // update remaining lender interest values\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.sub(\n closePrincipal\n );\n\n uint256 owedTotal = lenderInterestLocal.owedTotal;\n lenderInterestLocal.owedTotal = owedTotal > interestRefundToBorrower\n ? owedTotal - interestRefundToBorrower\n : 0;\n\n return interestRefundToBorrower;\n }\n\n /**\n * @notice Check sender is borrower or delegatee and loan id exists.\n *\n * @param loanId byte32 of the loan id.\n * */\n function _checkAuthorized(bytes32 loanId) internal view {\n Loan storage loanLocal = loans[loanId];\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n }\n\n /**\n * @notice Internal function for closing a position by swapping the\n * collateral back to loan tokens, paying the lender and withdrawing\n * the remainder.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collatral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid\n * out in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(swapAmount != 0, \"swapAmount == 0\");\n\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't swap more than collateral.\n swapAmount = swapAmount > loanLocal.collateral ? loanLocal.collateral : swapAmount;\n\n //close whole loan if tiny position will remain\n if (loanLocal.collateral - swapAmount > 0) {\n if (\n _getAmountInRbtc(\n loanParamsLocal.collateralToken,\n loanLocal.collateral - swapAmount\n ) <= TINY_AMOUNT\n ) {\n swapAmount = loanLocal.collateral;\n }\n }\n\n uint256 loanCloseAmountLessInterest;\n if (swapAmount == loanLocal.collateral || returnTokenIsCollateral) {\n /// loanCloseAmountLessInterest will be passed as required amount amount of destination tokens.\n /// this means, the actual swapAmount passed to the swap contract does not matter at all.\n /// the source token amount will be computed depending on the required amount amount of destination tokens.\n loanCloseAmount = swapAmount == loanLocal.collateral\n ? loanLocal.principal\n : loanLocal.principal.mul(swapAmount).div(loanLocal.collateral);\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Computes the interest refund for the borrower and sends it to the lender to cover part of the principal.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n } else {\n /// loanCloseAmount is calculated after swap; for this case we want to swap the entire source amount\n /// and determine the loanCloseAmount and withdraw amount based on that.\n loanCloseAmountLessInterest = 0;\n }\n\n uint256 coveredPrincipal;\n uint256 usedCollateral;\n\n /// swapAmount repurposed for collateralToLoanSwapRate to avoid stack too deep error.\n (coveredPrincipal, usedCollateral, withdrawAmount, swapAmount) = _coverPrincipalWithSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount, /// The amount of source tokens to swap (only matters if !returnTokenIsCollateral or loanCloseAmountLessInterest = 0)\n loanCloseAmountLessInterest, /// This is the amount of destination tokens we want to receive (only matters if returnTokenIsCollateral)\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (loanCloseAmountLessInterest == 0) {\n /// Condition prior to swap: swapAmount != loanLocal.collateral && !returnTokenIsCollateral\n\n /// Amounts that is closed.\n loanCloseAmount = coveredPrincipal;\n if (coveredPrincipal != loanLocal.principal) {\n loanCloseAmount = loanCloseAmount.mul(usedCollateral).div(loanLocal.collateral);\n }\n require(loanCloseAmount != 0, \"loanCloseAmount == 0\");\n\n /// Amount that is returned to the lender.\n loanCloseAmountLessInterest = _settleInterestToPrincipal(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n receiver\n );\n\n /// Remaining amount withdrawn to the receiver.\n withdrawAmount = withdrawAmount.add(coveredPrincipal).sub(loanCloseAmountLessInterest);\n } else {\n /// Pay back the amount which was covered by the swap.\n loanCloseAmountLessInterest = coveredPrincipal;\n }\n\n require(loanCloseAmountLessInterest != 0, \"closeAmount is 0 after swap\");\n\n /// Reduce the collateral by the amount which was swapped for the closure.\n if (usedCollateral != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(usedCollateral);\n }\n\n /// Repays principal to lender.\n /// The lender always gets back an ERC20 (even wrbtc), so we call\n /// withdraw directly rather than use the _withdrawAsset helper function.\n vaultWithdraw(loanParamsLocal.loanToken, loanLocal.lender, loanCloseAmountLessInterest);\n\n withdrawToken = returnTokenIsCollateral\n ? loanParamsLocal.collateralToken\n : loanParamsLocal.loanToken;\n\n if (withdrawAmount != 0) {\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n usedCollateral,\n swapAmount, /// collateralToLoanSwapRate\n CloseTypes.Swap\n );\n }\n\n /**\n * @notice Close a loan.\n *\n * @dev Wrapper for _closeLoan internal function.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan params.\n * @param loanCloseAmount The amount to close: principal or lower.\n * @param collateralCloseAmount The amount of collateral to close.\n * @param collateralToLoanSwapRate The price rate collateral/loan token.\n * @param closeType The type of loan close.\n * */\n function _finalizeClose(\n Loan storage loanLocal,\n LoanParams storage loanParamsLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanSwapRate,\n CloseTypes closeType\n ) internal {\n _closeLoan(loanLocal, loanCloseAmount);\n\n address _priceFeeds = priceFeeds;\n uint256 currentMargin;\n uint256 collateralToLoanRate;\n\n /// This is still called even with full loan close to return collateralToLoanRate\n (bool success, bytes memory data) =\n _priceFeeds.staticcall(\n abi.encodeWithSelector(\n IPriceFeeds(_priceFeeds).getCurrentMargin.selector,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n )\n );\n assembly {\n if eq(success, 1) {\n currentMargin := mload(add(data, 32))\n collateralToLoanRate := mload(add(data, 64))\n }\n }\n /// Note: We can safely skip the margin check if closing\n /// via closeWithDeposit or if closing the loan in full by any method.\n require(\n closeType == CloseTypes.Deposit ||\n loanLocal.principal == 0 || /// loan fully closed\n currentMargin > loanParamsLocal.maintenanceMargin,\n \"unhealthy position\"\n );\n\n _emitClosingEvents(\n loanParamsLocal,\n loanLocal,\n loanCloseAmount,\n collateralCloseAmount,\n collateralToLoanRate,\n collateralToLoanSwapRate,\n currentMargin,\n closeType\n );\n }\n\n /**\n * swaps a share of a loan's collateral or the complete collateral in order to cover the principle.\n * @param loanLocal the loan\n * @param loanParamsLocal the loan parameters\n * @param swapAmount in case principalNeeded == 0 or !returnTokenIsCollateral, this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens needed for the swap is estimated by the connector.\n * @param principalNeeded the required amount of destination tokens in order to cover the principle (only used if returnTokenIsCollateral)\n * @param returnTokenIsCollateral tells if the user wants to withdraw his remaining collateral + profit in collateral tokens\n * @notice Swaps a share of a loan's collateral or the complete collateral\n * in order to cover the principle.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param swapAmount In case principalNeeded == 0 or !returnTokenIsCollateral,\n * this is the amount which is going to be swapped.\n * Else, swapAmount doesn't matter, because the amount of source tokens\n * needed for the swap is estimated by the connector.\n * @param principalNeeded The required amount of destination tokens in order to\n * cover the principle (only used if returnTokenIsCollateral).\n * @param returnTokenIsCollateral Tells if the user wants to withdraw his\n * remaining collateral + profit in collateral tokens.\n *\n * @return coveredPrincipal The amount of principal that is covered.\n * @return usedCollateral The amount of collateral used.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return collateralToLoanSwapRate The swap rate of collateral.\n * */\n function _coverPrincipalWithSwap(\n Loan memory loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 swapAmount,\n uint256 principalNeeded,\n bool returnTokenIsCollateral,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 coveredPrincipal,\n uint256 usedCollateral,\n uint256 withdrawAmount,\n uint256 collateralToLoanSwapRate\n )\n {\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n (\n destTokenAmountReceived,\n sourceTokenAmountUsed,\n collateralToLoanSwapRate\n ) = _doCollateralSwap(\n loanLocal,\n loanParamsLocal,\n swapAmount,\n principalNeeded,\n returnTokenIsCollateral,\n loanDataBytes\n );\n\n if (returnTokenIsCollateral) {\n coveredPrincipal = principalNeeded;\n\n /// Better fill than expected.\n if (destTokenAmountReceived > coveredPrincipal) {\n /// Send excess to borrower if the amount is big enough to be\n /// worth the gas fees.\n if (\n worthTheTransfer(\n loanParamsLocal.loanToken,\n destTokenAmountReceived - coveredPrincipal\n )\n ) {\n _withdrawAsset(\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n destTokenAmountReceived - coveredPrincipal\n );\n }\n /// Else, give the excess to the lender (if it goes to the\n /// borrower, they're very confused. causes more trouble than it's worth)\n else {\n coveredPrincipal = destTokenAmountReceived;\n }\n }\n withdrawAmount = swapAmount > sourceTokenAmountUsed\n ? swapAmount - sourceTokenAmountUsed\n : 0;\n } else {\n require(sourceTokenAmountUsed == swapAmount, \"swap error\");\n\n if (swapAmount == loanLocal.collateral) {\n /// sourceTokenAmountUsed == swapAmount == loanLocal.collateral\n\n coveredPrincipal = principalNeeded;\n withdrawAmount = destTokenAmountReceived - principalNeeded;\n } else {\n /// sourceTokenAmountUsed == swapAmount < loanLocal.collateral\n\n if (destTokenAmountReceived >= loanLocal.principal) {\n /// Edge case where swap covers full principal.\n\n coveredPrincipal = loanLocal.principal;\n withdrawAmount = destTokenAmountReceived - loanLocal.principal;\n\n /// Excess collateral refunds to the borrower.\n _withdrawAsset(\n loanParamsLocal.collateralToken,\n loanLocal.borrower,\n loanLocal.collateral - sourceTokenAmountUsed\n );\n sourceTokenAmountUsed = loanLocal.collateral;\n } else {\n coveredPrincipal = destTokenAmountReceived;\n withdrawAmount = 0;\n }\n }\n }\n\n usedCollateral = sourceTokenAmountUsed > swapAmount ? sourceTokenAmountUsed : swapAmount;\n }\n\n function _emitClosingEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 loanCloseAmount,\n uint256 collateralCloseAmount,\n uint256 collateralToLoanRate,\n uint256 collateralToLoanSwapRate,\n uint256 currentMargin,\n CloseTypes closeType\n ) internal {\n if (closeType == CloseTypes.Deposit) {\n emit CloseWithDeposit(\n loanLocal.borrower, /// user (borrower)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n msg.sender, /// closer\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n loanCloseAmount, /// loanCloseAmount\n collateralCloseAmount, /// collateralCloseAmount\n collateralToLoanRate, /// collateralToLoanRate\n currentMargin /// currentMargin\n );\n } else if (closeType == CloseTypes.Swap) {\n /// exitPrice = 1 / collateralToLoanSwapRate\n if (collateralToLoanSwapRate != 0) {\n collateralToLoanSwapRate = SafeMath.div(10**36, collateralToLoanSwapRate);\n }\n\n /// currentLeverage = 100 / currentMargin\n if (currentMargin != 0) {\n currentMargin = SafeMath.div(10**38, currentMargin);\n }\n\n emit CloseWithSwap(\n loanLocal.borrower, /// user (trader)\n loanLocal.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n msg.sender, /// closer\n collateralCloseAmount, /// positionCloseSize\n loanCloseAmount, /// loanCloseAmount\n collateralToLoanSwapRate, /// exitPrice (1 / collateralToLoanSwapRate)\n currentMargin /// currentLeverage\n );\n } else if (closeType == CloseTypes.Liquidation) {\n emit Liquidate(\n loanLocal.borrower, // user (borrower)\n msg.sender, // liquidator\n loanLocal.id, // loanId\n loanLocal.lender, // lender\n loanParamsLocal.loanToken, // loanToken\n loanParamsLocal.collateralToken, // collateralToken\n loanCloseAmount, // loanCloseAmount\n collateralCloseAmount, // collateralCloseAmount\n collateralToLoanRate, // collateralToLoanRate\n currentMargin // currentMargin\n );\n }\n }\n\n /**\n * @dev returns amount of the asset converted to RBTC\n * @param asset the asset to be transferred\n * @param amount the amount to be transferred\n * @return amount in RBTC\n * */\n function _getAmountInRbtc(address asset, uint256 amount) internal view returns (uint256) {\n (uint256 rbtcRate, uint256 rbtcPrecision) =\n IPriceFeeds(priceFeeds).queryRate(asset, address(wrbtcToken));\n return amount.mul(rbtcRate).div(rbtcPrecision);\n }\n\n /**\n * @dev private function which check the loanLocal & loanParamsLocal does exist\n *\n * @param loanId bytes32 of loanId\n *\n * @return Loan storage\n * @return LoanParams storage\n */\n function _checkLoan(bytes32 loanId) internal view returns (Loan storage, LoanParams storage) {\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n return (loanLocal, loanParamsLocal);\n }\n}\n" + }, + "contracts/modules/LoanClosingsWith.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../interfaces/ILoanPool.sol\";\nimport \"./LoanClosingsShared.sol\";\n\n/**\n * @title LoanClosingsWith contract.\n * @notice Close a loan w/deposit, close w/swap. There are 2 functions for ending a loan on the\n * protocol contract: closeWithSwap and closeWithDeposit. Margin trade\n * positions are always closed with a swap.\n *\n * Loans are liquidated if the position goes below margin maintenance.\n * */\ncontract LoanClosingsWith is LoanClosingsShared {\n constructor() public {}\n\n function() external {\n revert(\"fallback not allowed\");\n }\n\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.closeWithDeposit.selector];\n _setTarget(this.closeWithDeposit.selector, target);\n _setTarget(this.closeWithSwap.selector, target);\n _setTarget(this.checkCloseWithDepositIsTinyPosition.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanClosingsWith\");\n }\n\n /**\n * @notice Closes a loan by doing a deposit.\n *\n * @dev Public wrapper for _closeWithDeposit internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens. (e.g. rBTC on a iSUSD contract).\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n public\n payable\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return _closeWithDeposit(loanId, receiver, depositAmount);\n }\n\n /**\n * @notice Close a position by swapping the collateral back to loan tokens\n * paying the lender and withdrawing the remainder.\n *\n * @dev Public wrapper for _closeWithSwap internal function.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder (unused collateral + profit).\n * @param swapAmount Defines how much of the position should be closed and\n * is denominated in collateral tokens.\n * If swapAmount >= collateral, the complete position will be closed.\n * Else if returnTokenIsCollateral, (swapAmount/collateral) * principal will be swapped (partial closure).\n * Else coveredPrincipal\n * @param returnTokenIsCollateral Defines if the remainder should be paid out\n * in collateral tokens or underlying loan tokens.\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function closeWithSwap(\n bytes32 loanId,\n address receiver,\n uint256 swapAmount, // denominated in collateralToken\n bool returnTokenIsCollateral, // true: withdraws collateralToken, false: withdraws loanToken\n bytes memory // for future use /*loanDataBytes*/\n )\n public\n nonReentrant\n globallyNonReentrant\n iTokenSupplyUnchanged(loanId)\n whenNotPaused\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n _checkAuthorized(loanId);\n return\n _closeWithSwap(\n loanId,\n receiver,\n swapAmount,\n returnTokenIsCollateral,\n \"\" /// loanDataBytes\n );\n }\n\n /**\n * @notice Internal function for closing a loan by doing a deposit.\n *\n * @param loanId The id of the loan.\n * @param receiver The receiver of the remainder.\n * @param depositAmount Defines how much of the position should be closed.\n * It is denominated in loan tokens.\n * If depositAmount > principal, the complete loan will be closed\n * else deposit amount (partial closure).\n *\n * @return loanCloseAmount The amount of the collateral token of the loan.\n * @return withdrawAmount The withdraw amount in the collateral token.\n * @return withdrawToken The loan token address.\n * */\n function _closeWithDeposit(\n bytes32 loanId,\n address receiver,\n uint256 depositAmount /// Denominated in loanToken.\n )\n internal\n returns (\n uint256 loanCloseAmount,\n uint256 withdrawAmount,\n address withdrawToken\n )\n {\n require(depositAmount != 0, \"depositAmount == 0\");\n\n //TODO should we skip this check if invoked from rollover ?\n (Loan storage loanLocal, LoanParams storage loanParamsLocal) = _checkLoan(loanId);\n\n /// Can't close more than the full principal.\n loanCloseAmount = depositAmount > loanLocal.principal\n ? loanLocal.principal\n : depositAmount;\n\n //revert if tiny position remains\n uint256 remainingAmount = loanLocal.principal - loanCloseAmount;\n if (remainingAmount > 0) {\n require(\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount) > TINY_AMOUNT,\n \"Tiny amount when closing with deposit\"\n );\n }\n\n uint256 loanCloseAmountLessInterest =\n _settleInterestToPrincipal(loanLocal, loanParamsLocal, loanCloseAmount, receiver);\n\n if (loanCloseAmountLessInterest != 0) {\n _returnPrincipalWithDeposit(\n loanParamsLocal.loanToken,\n loanLocal.lender,\n loanCloseAmountLessInterest\n );\n }\n\n if (loanCloseAmount == loanLocal.principal) {\n withdrawAmount = loanLocal.collateral;\n } else {\n withdrawAmount = loanLocal.collateral.mul(loanCloseAmount).div(loanLocal.principal);\n }\n\n withdrawToken = loanParamsLocal.collateralToken;\n\n if (withdrawAmount != 0) {\n loanLocal.collateral = loanLocal.collateral.sub(withdrawAmount);\n _withdrawAsset(withdrawToken, receiver, withdrawAmount);\n }\n\n _finalizeClose(\n loanLocal,\n loanParamsLocal,\n loanCloseAmount,\n withdrawAmount, /// collateralCloseAmount\n 0, /// collateralToLoanSwapRate\n CloseTypes.Deposit\n );\n }\n\n /**\n * @notice Function to check whether the given loanId & deposit amount when closing with deposit will cause the tiny position\n *\n * @param loanId The id of the loan.\n * @param depositAmount Defines how much the deposit amount to close the position.\n *\n * @return isTinyPosition true is indicating tiny position, false otherwise.\n * @return tinyPositionAmount will return 0 for non tiny position, and will return the amount of tiny position if true\n */\n function checkCloseWithDepositIsTinyPosition(bytes32 loanId, uint256 depositAmount)\n external\n view\n returns (bool isTinyPosition, uint256 tinyPositionAmount)\n {\n (Loan memory loanLocal, LoanParams memory loanParamsLocal) = _checkLoan(loanId);\n\n if (depositAmount < loanLocal.principal) {\n uint256 remainingAmount = loanLocal.principal - depositAmount;\n uint256 remainingRBTCAmount =\n _getAmountInRbtc(loanParamsLocal.loanToken, remainingAmount);\n if (remainingRBTCAmount < TINY_AMOUNT) {\n isTinyPosition = true;\n tinyPositionAmount = remainingRBTCAmount;\n }\n }\n\n return (isTinyPosition, tinyPositionAmount);\n }\n}\n" + }, + "contracts/modules/LoanMaintenance.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../events/LoanMaintenanceEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../mixins/LiquidationHelper.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Maintenance contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to query loan data and to modify its status\n * by withdrawing or depositing collateral.\n * */\ncontract LoanMaintenance is\n LoanOpeningsEvents,\n LoanMaintenanceEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n LiquidationHelper,\n ModuleCommonFunctionalities\n{\n // Keep the old LoanReturnData for backward compatibility (especially for the watcher)\n struct LoanReturnData {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n }\n\n // The new struct which contained borrower & creation time of a loan\n struct LoanReturnDataV2 {\n bytes32 loanId;\n address loanToken;\n address collateralToken;\n address borrower;\n uint256 principal;\n uint256 collateral;\n uint256 interestOwedPerDay;\n uint256 interestDepositRemaining;\n uint256 startRate; /// collateralToLoanRate\n uint256 startMargin;\n uint256 maintenanceMargin;\n uint256 currentMargin;\n uint256 maxLoanTerm;\n uint256 endTimestamp;\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n uint256 creationTimestamp;\n }\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set initial values of proxy targets.\n *\n * @param target The address of the logic contract instance.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.depositCollateral.selector];\n _setTarget(this.depositCollateral.selector, target);\n _setTarget(this.withdrawCollateral.selector, target);\n _setTarget(this.withdrawAccruedInterest.selector, target);\n _setTarget(this.extendLoanDuration.selector, target);\n _setTarget(this.reduceLoanDuration.selector, target);\n _setTarget(this.getLenderInterestData.selector, target);\n _setTarget(this.getLoanInterestData.selector, target);\n _setTarget(this.getUserLoans.selector, target);\n _setTarget(this.getUserLoansV2.selector, target);\n _setTarget(this.getLoan.selector, target);\n _setTarget(this.getLoanV2.selector, target);\n _setTarget(this.getActiveLoans.selector, target);\n _setTarget(this.getActiveLoansV2.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanMaintenance\");\n }\n\n /**\n * @notice Increase the margin of a position by depositing additional collateral.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function depositCollateral(\n bytes32 loanId,\n uint256 depositAmount /// must match msg.value if ether is sent\n ) external payable nonReentrant whenNotPaused {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.value == 0 || loanParamsLocal.collateralToken == address(wrbtcToken),\n \"wrong asset sent\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(depositAmount);\n\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.collateralToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n\n (uint256 collateralToLoanRate, ) =\n IPriceFeeds(priceFeeds).queryRate(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n\n emit DepositCollateral(loanId, depositAmount, collateralToLoanRate);\n }\n\n /**\n * @notice Withdraw from the collateral. This reduces the margin of a position.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in collateral tokens.\n *\n * @return actualWithdrawAmount The amount withdrawn taking into account drawdowns.\n * */\n function withdrawCollateral(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 actualWithdrawAmount) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral,\n loanParamsLocal.maintenanceMargin\n );\n\n if (withdrawAmount > maxDrawdown) {\n actualWithdrawAmount = maxDrawdown;\n } else {\n actualWithdrawAmount = withdrawAmount;\n }\n\n loanLocal.collateral = loanLocal.collateral.sub(actualWithdrawAmount);\n\n if (loanParamsLocal.collateralToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, actualWithdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.collateralToken, receiver, actualWithdrawAmount);\n }\n }\n\n /**\n * @notice Withdraw accrued loan interest.\n *\n * @dev Wrapper for _payInterest internal function.\n *\n * @param loanToken The loan token address.\n * */\n function withdrawAccruedInterest(address loanToken) external whenNotPaused {\n /// Pay outstanding interest to lender.\n _payInterest(\n msg.sender, /// Lender.\n loanToken\n );\n }\n\n /**\n * @notice Extend the loan duration by as much time as depositAmount can buy.\n *\n * @param loanId A unique ID representing the loan.\n * @param depositAmount The amount to be deposited in loan tokens. Used to pay the interest for the new duration.\n * @param useCollateral Whether pay interests w/ the collateral. If true, depositAmount of loan tokens\n *\t\t\t\t\t\twill be purchased with the collateral.\n * // param calldata The payload for the call. These loan DataBytes are additional loan data (not in use for token swaps).\n *\n * @return secondsExtended The amount of time in seconds the loan is extended.\n * */\n function extendLoanDuration(\n bytes32 loanId,\n uint256 depositAmount,\n bool useCollateral,\n bytes calldata /// loanDataBytes, for future use.\n ) external payable nonReentrant whenNotPaused returns (uint256 secondsExtended) {\n require(depositAmount != 0, \"depositAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n !useCollateral ||\n msg.sender == loanLocal.borrower ||\n delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(\n msg.value == 0 || (!useCollateral && loanParamsLocal.loanToken == address(wrbtcToken)),\n \"wrong asset sent\"\n );\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n /// Handle back interest: calculates interest owned since the loan\n /// endtime passed but the loan remained open.\n uint256 backInterestOwed;\n if (block.timestamp > loanLocal.endTimestamp) {\n backInterestOwed = block.timestamp.sub(loanLocal.endTimestamp);\n backInterestOwed = backInterestOwed.mul(loanInterestLocal.owedPerDay);\n backInterestOwed = backInterestOwed.div(86400);\n\n require(depositAmount > backInterestOwed, \"deposit cannot cover back interest\");\n }\n\n /// Deposit interest.\n if (useCollateral) {\n /// Used the whole converted loanToken to extend the loan duration\n depositAmount = _doCollateralSwap(loanLocal, loanParamsLocal, depositAmount);\n } else {\n if (msg.value == 0) {\n vaultDeposit(loanParamsLocal.loanToken, msg.sender, depositAmount);\n } else {\n require(msg.value == depositAmount, \"ether deposit mismatch\");\n vaultEtherDeposit(msg.sender, msg.value);\n }\n }\n\n if (backInterestOwed != 0) {\n depositAmount = depositAmount.sub(backInterestOwed);\n\n /// Pay out backInterestOwed\n _payInterestTransfer(loanLocal.lender, loanParamsLocal.loanToken, backInterestOwed);\n }\n\n secondsExtended = depositAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.add(secondsExtended);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(depositAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .add(depositAmount);\n }\n\n /**\n * @notice Reduce the loan duration by withdrawing from the deposited interest.\n *\n * @param loanId A unique ID representing the loan.\n * @param receiver The account getting the withdrawal.\n * @param withdrawAmount The amount to be withdrawn in loan tokens.\n *\n * @return secondsReduced The amount of time in seconds the loan is reduced.\n * */\n function reduceLoanDuration(\n bytes32 loanId,\n address receiver,\n uint256 withdrawAmount\n ) external nonReentrant whenNotPaused returns (uint256 secondsReduced) {\n require(withdrawAmount != 0, \"withdrawAmount is 0\");\n Loan storage loanLocal = loans[loanId];\n LoanParams storage loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n require(loanLocal.active, \"loan is closed\");\n require(\n msg.sender == loanLocal.borrower || delegatedManagers[loanLocal.id][msg.sender],\n \"unauthorized\"\n );\n require(loanParamsLocal.maxLoanTerm == 0, \"indefinite-term only\");\n require(loanLocal.endTimestamp > block.timestamp, \"loan term has ended\");\n\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 interestDepositRemaining =\n loanLocal.endTimestamp.sub(block.timestamp).mul(loanInterestLocal.owedPerDay).div(\n 86400\n );\n require(withdrawAmount < interestDepositRemaining, \"withdraw amount too high\");\n\n /// Withdraw interest.\n if (loanParamsLocal.loanToken == address(wrbtcToken)) {\n vaultEtherWithdraw(receiver, withdrawAmount);\n } else {\n vaultWithdraw(loanParamsLocal.loanToken, receiver, withdrawAmount);\n }\n\n secondsReduced = withdrawAmount.mul(86400).div(loanInterestLocal.owedPerDay);\n\n require(loanLocal.endTimestamp > secondsReduced, \"loan too short\");\n\n loanLocal.endTimestamp = loanLocal.endTimestamp.sub(secondsReduced);\n\n require(loanLocal.endTimestamp > block.timestamp, \"loan too short\");\n\n uint256 maxDuration = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxDuration > 3600, \"loan too short\");\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.sub(withdrawAmount);\n\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken].owedTotal = lenderInterest[\n loanLocal.lender\n ][loanParamsLocal.loanToken]\n .owedTotal\n .sub(withdrawAmount);\n }\n\n /**\n * @notice Get current lender interest data totals for all loans\n * with a specific oracle and interest token.\n *\n * @param lender The lender address.\n * @param loanToken The loan token address.\n *\n * @return interestPaid The total amount of interest that has been paid to a lender so far.\n * @return interestPaidDate The date of the last interest pay out, or 0 if no interest has been withdrawn yet.\n * @return interestOwedPerDay The amount of interest the lender is earning per day.\n * @return interestUnPaid The total amount of interest the lender is owned and not yet withdrawn.\n * @return interestFeePercent The fee retained by the protocol before interest is paid to the lender.\n * @return principalTotal The total amount of outstanding principal the lender has loaned.\n * */\n function getLenderInterestData(address lender, address loanToken)\n external\n view\n returns (\n uint256 interestPaid,\n uint256 interestPaidDate,\n uint256 interestOwedPerDay,\n uint256 interestUnPaid,\n uint256 interestFeePercent,\n uint256 principalTotal\n )\n {\n LenderInterest memory lenderInterestLocal = lenderInterest[lender][loanToken];\n\n interestUnPaid = block\n .timestamp\n .sub(lenderInterestLocal.updatedTimestamp)\n .mul(lenderInterestLocal.owedPerDay)\n .div(86400);\n if (interestUnPaid > lenderInterestLocal.owedTotal)\n interestUnPaid = lenderInterestLocal.owedTotal;\n\n return (\n lenderInterestLocal.paidTotal,\n lenderInterestLocal.paidTotal != 0 ? lenderInterestLocal.updatedTimestamp : 0,\n lenderInterestLocal.owedPerDay,\n lenderInterestLocal.updatedTimestamp != 0 ? interestUnPaid : 0,\n lendingFeePercent,\n lenderInterestLocal.principalTotal\n );\n }\n\n /**\n * @notice Get current interest data for a loan.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loanToken The loan token that interest is paid in.\n * @return interestOwedPerDay The amount of interest the borrower is paying per day.\n * @return interestDepositTotal The total amount of interest the borrower has deposited.\n * @return interestDepositRemaining The amount of deposited interest that is not yet owed to a lender.\n * */\n function getLoanInterestData(bytes32 loanId)\n external\n view\n returns (\n address loanToken,\n uint256 interestOwedPerDay,\n uint256 interestDepositTotal,\n uint256 interestDepositRemaining\n )\n {\n loanToken = loanParams[loans[loanId].loanParamsId].loanToken;\n interestOwedPerDay = loanInterest[loanId].owedPerDay;\n interestDepositTotal = loanInterest[loanId].depositTotal;\n\n uint256 endTimestamp = loans[loanId].endTimestamp;\n uint256 interestTime = block.timestamp > endTimestamp ? endTimestamp : block.timestamp;\n interestDepositRemaining = endTimestamp > interestTime\n ? endTimestamp.sub(interestTime).mul(interestOwedPerDay).div(86400)\n : 0;\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoans(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @notice Get all user loans.\n *\n * Only returns data for loans that are active.\n *\n * @param user The user address.\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param isLender Whether the user is lender or borrower.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The array of loans as query result.\n * */\n function getUserLoansV2(\n address user,\n uint256 start,\n uint256 count,\n uint256 loanType,\n bool isLender,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n EnumerableBytes32Set.Bytes32Set storage set =\n isLender ? lenderLoanSets[user] : borrowerLoanSets[user];\n\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n set.get(i + start - 1), /// loanId\n loanType,\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData) {\n return\n _getLoan(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get one loan data structure by matching ID.\n *\n * Wrapper to internal _getLoan call.\n *\n * @param loanId A unique ID representing the loan.\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2) {\n return\n _getLoanV2(\n loanId,\n 0, /// loanType\n false /// unsafeOnly\n );\n }\n\n /**\n * @notice Get all active loans.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ loan information.\n * */\n function getActiveLoans(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnData[] memory loansData) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansData;\n }\n\n loansData = new LoanReturnData[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnData memory loanData =\n _getLoan(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanData.loanId == 0) continue;\n\n loansData[itemCount] = loanData;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansData, itemCount)\n }\n }\n }\n\n /**\n * @dev New view function which will return the loan data.\n * @dev This function was created to support backward compatibility\n * @dev As in we the old getActiveLoans function is not expected to be changed by the wathcers.\n *\n * @param start The lower loan ID to start with.\n * @param count The maximum number of results.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loanData The data structure\n * @return extendedLoanData The data structure which contained (borrower & creation time)\n */\n function getActiveLoansV2(\n uint256 start,\n uint256 count,\n bool unsafeOnly\n ) external view returns (LoanReturnDataV2[] memory loansDataV2) {\n uint256 end = start.add(count).min256(activeLoansSet.length());\n if (start >= end) {\n return loansDataV2;\n }\n\n loansDataV2 = new LoanReturnDataV2[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n LoanReturnDataV2 memory loanDataV2 =\n _getLoanV2(\n activeLoansSet.get(i + start - 1), /// loanId\n 0, /// loanType\n unsafeOnly\n );\n if (loanDataV2.loanId == 0) continue;\n\n loansDataV2[itemCount] = loanDataV2;\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loansDataV2, itemCount)\n }\n }\n }\n\n /**\n * @notice Internal function to get one loan data structure.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data structure w/ the loan information.\n * */\n function _getLoan(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnData memory loanData) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanData;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanData;\n }\n\n return\n LoanReturnData({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable\n });\n }\n\n /**\n * @notice Internal function to get one loan data structure v2.\n *\n * @param loanId A unique ID representing the loan.\n * @param loanType The type of loan.\n * loanType 0: all loans.\n * loanType 1: margin trade loans.\n * loanType 2: non-margin trade loans.\n * @param unsafeOnly The safe filter (True/False).\n *\n * @return loansData The data v2 structure w/ the loan information.\n * */\n function _getLoanV2(\n bytes32 loanId,\n uint256 loanType,\n bool unsafeOnly\n ) internal view returns (LoanReturnDataV2 memory loanDataV2) {\n Loan memory loanLocal = loans[loanId];\n LoanParams memory loanParamsLocal = loanParams[loanLocal.loanParamsId];\n\n if (loanType != 0) {\n if (\n !((loanType == 1 && loanParamsLocal.maxLoanTerm != 0) ||\n (loanType == 2 && loanParamsLocal.maxLoanTerm == 0))\n ) {\n return loanDataV2;\n }\n }\n\n LoanInterest memory loanInterestLocal = loanInterest[loanId];\n\n (uint256 currentMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n\n uint256 maxLiquidatable;\n uint256 maxSeizable;\n if (currentMargin <= loanParamsLocal.maintenanceMargin) {\n (maxLiquidatable, maxSeizable, ) = _getLiquidationAmounts(\n loanLocal.principal,\n loanLocal.collateral,\n currentMargin,\n loanParamsLocal.maintenanceMargin,\n collateralToLoanRate\n );\n } else if (unsafeOnly) {\n return loanDataV2;\n }\n\n return\n LoanReturnDataV2({\n loanId: loanId,\n loanToken: loanParamsLocal.loanToken,\n collateralToken: loanParamsLocal.collateralToken,\n borrower: loanLocal.borrower,\n principal: loanLocal.principal,\n collateral: loanLocal.collateral,\n interestOwedPerDay: loanInterestLocal.owedPerDay,\n interestDepositRemaining: loanLocal.endTimestamp >= block.timestamp\n ? loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(loanInterestLocal.owedPerDay)\n .div(86400)\n : 0,\n startRate: loanLocal.startRate,\n startMargin: loanLocal.startMargin,\n maintenanceMargin: loanParamsLocal.maintenanceMargin,\n currentMargin: currentMargin,\n maxLoanTerm: loanParamsLocal.maxLoanTerm,\n endTimestamp: loanLocal.endTimestamp,\n maxLiquidatable: maxLiquidatable,\n maxSeizable: maxSeizable,\n creationTimestamp: loanLocal.startTimestamp\n });\n }\n\n /**\n * @notice Internal function to collect interest from the collateral.\n *\n * @param loanLocal The loan object.\n * @param loanParamsLocal The loan parameters.\n * @param depositAmount The amount of underlying tokens provided on the loan.\n * */\n function _doCollateralSwap(\n Loan storage loanLocal,\n LoanParams memory loanParamsLocal,\n uint256 depositAmount\n ) internal returns (uint256 purchasedLoanToken) {\n /// Reverts in _loanSwap if amountNeeded can't be bought.\n (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed, ) =\n _loanSwap(\n loanLocal.id,\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken,\n loanLocal.borrower,\n loanLocal.collateral, /// minSourceTokenAmount\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n depositAmount, /// requiredDestTokenAmount (partial spend of loanLocal.collateral to fill this amount)\n true, /// bypassFee\n \"\" /// loanDataBytes\n );\n loanLocal.collateral = loanLocal.collateral.sub(sourceTokenAmountUsed);\n\n /// Ensure the loan is still healthy.\n (uint256 currentMargin, ) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(currentMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n return destTokenAmountReceived;\n }\n}\n" + }, + "contracts/modules/LoanOpenings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanOpeningsEvents.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../mixins/InterestUser.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../connectors/loantoken/lib/MarginTradeStructHelpers.sol\";\n\n/**\n * @title Loan Openings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to borrow and trade.\n * */\ncontract LoanOpenings is\n LoanOpeningsEvents,\n VaultController,\n InterestUser,\n SwapsUser,\n ModuleCommonFunctionalities\n{\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.borrowOrTradeFromPool.selector];\n _setTarget(this.borrowOrTradeFromPool.selector, target);\n _setTarget(this.setDelegatedManager.selector, target);\n _setTarget(this.getEstimatedMarginExposure.selector, target);\n _setTarget(this.getRequiredCollateral.selector, target);\n _setTarget(this.getBorrowAmount.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanOpenings\");\n }\n\n /**\n * @notice Borrow or trade from pool.\n *\n * @dev Note: Only callable by loan pools (iTokens).\n * Wrapper to _borrowOrTrade internal function.\n *\n * @param loanParamsId The ID of the loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return newPrincipal The new loan size.\n * @return newCollateral The new collateral amount.\n * */\n function borrowOrTradeFromPool(\n bytes32 loanParamsId,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses calldata sentAddresses,\n MarginTradeStructHelpers.SentAmounts calldata sentValues,\n bytes calldata loanDataBytes\n )\n external\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 newPrincipal, uint256 newCollateral)\n {\n require(msg.value == 0 || loanDataBytes.length != 0, \"loanDataBytes required with ether\");\n\n /// Only callable by loan pools.\n require(loanPoolToUnderlying[msg.sender] != address(0), \"not authorized\");\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsId];\n require(loanParamsLocal.id != 0, \"loanParams not exists\");\n\n /// Get required collateral.\n uint256 collateralAmountRequired =\n _getRequiredCollateral(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentValues.newPrincipal,\n initialMargin,\n isTorqueLoan\n );\n require(collateralAmountRequired != 0, \"collateral is 0\");\n\n return\n _borrowOrTrade(\n loanParamsLocal,\n loanId,\n isTorqueLoan,\n collateralAmountRequired,\n initialMargin,\n sentAddresses,\n sentValues,\n loanDataBytes\n );\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @dev Wrapper for _setDelegatedManager internal function.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function setDelegatedManager(\n bytes32 loanId,\n address delegated,\n bool toggle\n ) external whenNotPaused {\n require(loans[loanId].borrower == msg.sender, \"unauthorized\");\n\n _setDelegatedManager(loanId, msg.sender, delegated, toggle);\n }\n\n /**\n * @notice Get the estimated margin exposure.\n *\n * Margin is the money borrowed from a broker to purchase an investment\n * and is the difference between the total value of investment and the\n * loan amount. Margin trading refers to the practice of using borrowed\n * funds from a broker to trade a financial asset, which forms the\n * collateral for the loan from the broker.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param loanTokenSent The amount of loan tokens sent.\n * @param collateralTokenSent The amount of collateral tokens sent.\n * @param interestRate The interest rate. Percentage w/ 18 decimals.\n * @param newPrincipal The updated amount of principal (current debt).\n *\n * @return The margin exposure.\n * */\n function getEstimatedMarginExposure(\n address loanToken,\n address collateralToken,\n uint256 loanTokenSent,\n uint256 collateralTokenSent,\n uint256 interestRate,\n uint256 newPrincipal\n ) external view returns (uint256) {\n uint256 maxLoanTerm = 2419200; // 28 days\n\n uint256 owedPerDay = newPrincipal.mul(interestRate).div(365 * 10**20);\n\n uint256 interestAmountRequired = maxLoanTerm.mul(owedPerDay).div(86400);\n\n uint256 swapAmount = loanTokenSent.sub(interestAmountRequired);\n uint256 tradingFee = _getTradingFee(swapAmount);\n if (tradingFee != 0) {\n swapAmount = swapAmount.sub(tradingFee);\n }\n\n uint256 receivedAmount = _swapsExpectedReturn(loanToken, collateralToken, swapAmount);\n if (receivedAmount == 0) {\n return 0;\n } else {\n return collateralTokenSent.add(receivedAmount);\n }\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Calls internal _getRequiredCollateral and add fees.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralAmountRequired The required collateral.\n * */\n function getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 collateralAmountRequired) {\n if (marginAmount != 0) {\n collateralAmountRequired = _getRequiredCollateral(\n loanToken,\n collateralToken,\n newPrincipal,\n marginAmount,\n isTorqueLoan\n );\n\n // p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n // cannot be applied solely as it drives to some other tests failure\n /*\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (collateralAmountRequired != 0 && feePercent != 0) {\n\t\t\t\tcollateralAmountRequired = collateralAmountRequired.mul(10**20).divCeil(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t);\n\t\t\t}*/\n\n uint256 fee =\n isTorqueLoan\n ? _getBorrowingFee(collateralAmountRequired)\n : _getTradingFee(collateralAmountRequired);\n if (fee != 0) {\n collateralAmountRequired = collateralAmountRequired.add(fee);\n }\n }\n }\n\n /**\n * @notice Get the borrow amount of a trade loan.\n *\n * @dev Basically borrowAmount = collateral / marginAmount\n *\n * Collateral is something that helps secure a loan. When you borrow money,\n * you agree that your lender can take something and sell it to get their\n * money back if you fail to repay the loan. That's the collateral.\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param collateralTokenAmount The amount of collateral.\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return borrowAmount The borrow amount.\n * */\n function getBorrowAmount(\n address loanToken,\n address collateralToken,\n uint256 collateralTokenAmount,\n uint256 marginAmount,\n bool isTorqueLoan\n ) public view returns (uint256 borrowAmount) {\n if (marginAmount != 0) {\n if (isTorqueLoan) {\n marginAmount = marginAmount.add(10**20); /// Adjust for over-collateralized loan.\n }\n uint256 collateral = collateralTokenAmount;\n uint256 fee = isTorqueLoan ? _getBorrowingFee(collateral) : _getTradingFee(collateral);\n if (fee != 0) {\n collateral = collateral.sub(fee);\n }\n if (loanToken == collateralToken) {\n borrowAmount = collateral.mul(10**20).div(marginAmount);\n } else {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestPrecision != 0) {\n borrowAmount = collateral\n .mul(10**20)\n .mul(sourceToDestRate)\n .div(marginAmount)\n .div(sourceToDestPrecision);\n }\n }\n /*\n\t\t\t// p3.9 from bzx peckshield-audit-report-bZxV2-v1.0rc1.pdf\n\t\t\t// cannot be applied solely as it drives to some other tests failure\n\t\t\tuint256 feePercent = isTorqueLoan ? borrowingFeePercent : tradingFeePercent;\n\t\t\tif (borrowAmount != 0 && feePercent != 0) {\n\t\t\t\tborrowAmount = borrowAmount\n\t\t\t\t\t.mul(\n\t\t\t\t\t10**20 - feePercent // never will overflow\n\t\t\t\t)\n\t\t\t\t\t.divCeil(10**20);\n\t\t\t}*/\n }\n }\n\n /**\n * @notice Borrow or trade.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * @param collateralAmountRequired The required amount of collateral.\n * @param initialMargin The initial amount of margin.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return The new loan size.\n * @return The new collateral amount.\n * */\n function _borrowOrTrade(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n bool isTorqueLoan,\n uint256 collateralAmountRequired,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bytes memory loanDataBytes\n ) internal returns (uint256, uint256) {\n require(\n loanParamsLocal.collateralToken != loanParamsLocal.loanToken,\n \"collateral/loan match\"\n );\n require(initialMargin >= loanParamsLocal.minInitialMargin, \"initialMargin too low\");\n\n /// maxLoanTerm == 0 indicates a Torque loan and requires that torqueInterest != 0\n require(\n loanParamsLocal.maxLoanTerm != 0 || sentValues.interestInitialAmount != 0, /// torqueInterest\n \"invalid interest\"\n );\n\n /// Initialize loan.\n Loan storage loanLocal =\n loans[\n _initializeLoan(\n loanParamsLocal,\n loanId,\n initialMargin,\n sentAddresses,\n sentValues.newPrincipal\n )\n ];\n\n // Get required interest.\n uint256 amount =\n _initializeInterest(\n loanParamsLocal,\n loanLocal,\n sentValues.interestRate, /// newRate\n sentValues.newPrincipal, /// newPrincipal,\n sentValues.interestInitialAmount /// torqueInterest\n );\n\n /// substract out interest from usable loanToken sent.\n sentValues.loanTokenSent = sentValues.loanTokenSent.sub(amount);\n\n if (isTorqueLoan) {\n require(sentValues.loanTokenSent == 0, \"surplus loan token\");\n\n uint256 borrowingFee = _getBorrowingFee(sentValues.collateralTokenSent);\n // need to temp into local state to avoid\n address _collateralToken = loanParamsLocal.collateralToken;\n address _loanToken = loanParamsLocal.loanToken;\n if (borrowingFee != 0) {\n _payBorrowingFee(\n sentAddresses.borrower, /// borrower\n loanLocal.id,\n _collateralToken, /// fee token\n _loanToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n borrowingFee\n );\n\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.sub(borrowingFee);\n }\n } else {\n /// Update collateral after trade.\n uint256 receivedAmount;\n (receivedAmount, , sentValues.loanToCollateralSwapRate) = _loanSwap(\n loanId,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n sentAddresses.borrower, /// borrower\n sentValues.loanTokenSent, /// loanTokenUsable (minSourceTokenAmount)\n 0, /// maxSourceTokenAmount (0 means minSourceTokenAmount)\n 0, /// requiredDestTokenAmount (enforces that all of loanTokenUsable is swapped)\n false, /// bypassFee\n loanDataBytes\n );\n sentValues.collateralTokenSent = sentValues.collateralTokenSent.add(receivedAmount);\n\n /// Check the minEntryPrice with the rate\n require(\n sentValues.loanToCollateralSwapRate >= sentValues.minEntryPrice,\n \"entry price above the minimum\"\n );\n }\n\n /// Settle collateral.\n require(\n _isCollateralSatisfied(\n loanParamsLocal,\n loanLocal,\n initialMargin,\n sentValues.collateralTokenSent,\n collateralAmountRequired\n ),\n \"collateral insufficient\"\n );\n\n loanLocal.collateral = loanLocal.collateral.add(sentValues.collateralTokenSent);\n\n if (isTorqueLoan) {\n /// reclaiming variable -> interestDuration\n sentValues.interestDuration = loanLocal.endTimestamp.sub(block.timestamp);\n } else {\n /// reclaiming variable -> entryLeverage = 100 / initialMargin\n sentValues.entryLeverage = SafeMath.div(10**38, initialMargin);\n }\n\n _finalizeOpen(loanParamsLocal, loanLocal, sentAddresses, sentValues, isTorqueLoan);\n\n return (sentValues.newPrincipal, sentValues.collateralTokenSent); /// newPrincipal, newCollateral\n }\n\n /**\n * @notice Finalize an open loan.\n *\n * @dev Finalize it by updating local parameters of the loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _finalizeOpen(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n bool isTorqueLoan\n ) internal {\n /// @dev TODO: here the actual used rate and margin should go.\n (uint256 initialMargin, uint256 collateralToLoanRate) =\n IPriceFeeds(priceFeeds).getCurrentMargin(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral\n );\n require(initialMargin > loanParamsLocal.maintenanceMargin, \"unhealthy position\");\n\n if (loanLocal.startTimestamp == block.timestamp) {\n uint256 loanToCollateralPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken\n );\n uint256 collateralToLoanPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(\n loanParamsLocal.collateralToken,\n loanParamsLocal.loanToken\n );\n uint256 totalSwapRate = loanToCollateralPrecision.mul(collateralToLoanPrecision);\n loanLocal.startRate = isTorqueLoan\n ? collateralToLoanRate\n : totalSwapRate.div(sentValues.loanToCollateralSwapRate);\n }\n\n _emitOpeningEvents(\n loanParamsLocal,\n loanLocal,\n sentAddresses,\n sentValues,\n collateralToLoanRate,\n initialMargin,\n isTorqueLoan\n );\n }\n\n /**\n * @notice Emit the opening events.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param sentValues The values to send:\n * interestRate: New loan interest rate.\n * newPrincipal: New loan size (borrowAmount + any borrowed interest).\n * interestInitialAmount: New amount of interest to escrow for Torque loan (determines initial loan length).\n * loanTokenReceived: Total loanToken deposit (amount not sent to borrower in the case of Torque loans).\n * collateralTokenSent: Total collateralToken deposit.\n * minEntryPrice: Minimum entry price for checking price divergence (Value of loan token in collateral).\n * @param collateralToLoanRate The exchange rate from collateral to loan\n * tokens.\n * @param margin The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n * */\n function _emitOpeningEvents(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n MarginTradeStructHelpers.SentAmounts memory sentValues,\n uint256 collateralToLoanRate,\n uint256 margin,\n bool isTorqueLoan\n ) internal {\n if (isTorqueLoan) {\n emit Borrow(\n sentAddresses.borrower, /// user (borrower)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.loanToken, /// loanToken\n loanParamsLocal.collateralToken, /// collateralToken\n sentValues.newPrincipal, /// newPrincipal\n sentValues.collateralTokenSent, /// newCollateral\n sentValues.interestRate, /// interestRate\n sentValues.interestDuration, /// interestDuration\n collateralToLoanRate, /// collateralToLoanRate,\n margin /// currentMargin\n );\n } else {\n /// currentLeverage = 100 / currentMargin\n margin = SafeMath.div(10**38, margin);\n\n emit Trade(\n sentAddresses.borrower, /// user (trader)\n sentAddresses.lender, /// lender\n loanLocal.id, /// loanId\n loanParamsLocal.collateralToken, /// collateralToken\n loanParamsLocal.loanToken, /// loanToken\n sentValues.collateralTokenSent, /// positionSize\n sentValues.newPrincipal, /// borrowedAmount\n sentValues.interestRate, /// interestRate,\n loanLocal.endTimestamp, /// settlementDate\n sentValues.loanToCollateralSwapRate, /// entryPrice (loanToCollateralSwapRate)\n sentValues.entryLeverage, /// entryLeverage\n margin /// currentLeverage\n );\n }\n }\n\n /**\n * @notice Set the delegated manager.\n *\n * @param loanId The ID of the loan. If 0, start a new loan.\n * @param delegator The address of previous manager.\n * @param delegated The address of the delegated manager.\n * @param toggle The flag true/false for the delegated manager.\n * */\n function _setDelegatedManager(\n bytes32 loanId,\n address delegator,\n address delegated,\n bool toggle\n ) internal {\n delegatedManagers[loanId][delegated] = toggle;\n\n emit DelegatedManagerSet(loanId, delegator, delegated, toggle);\n }\n\n /**\n * @notice Calculate whether the collateral is satisfied.\n *\n * @dev Basically check collateral + drawdown >= 98% of required.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param initialMargin The initial amount of margin.\n * @param newCollateral The amount of new collateral.\n * @param collateralAmountRequired The amount of required collateral.\n *\n * @return Whether the collateral is satisfied.\n * */\n function _isCollateralSatisfied(\n LoanParams memory loanParamsLocal,\n Loan memory loanLocal,\n uint256 initialMargin,\n uint256 newCollateral,\n uint256 collateralAmountRequired\n ) internal view returns (bool) {\n /// Allow at most 2% under-collateralized.\n collateralAmountRequired = collateralAmountRequired.mul(98 ether).div(100 ether);\n\n if (newCollateral < collateralAmountRequired) {\n /// Check that existing collateral is sufficient coverage.\n if (loanLocal.collateral != 0) {\n uint256 maxDrawdown =\n IPriceFeeds(priceFeeds).getMaxDrawdown(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanLocal.principal,\n loanLocal.collateral,\n initialMargin\n );\n return newCollateral.add(maxDrawdown) >= collateralAmountRequired;\n } else {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @notice Initialize a loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanId The ID of the loan.\n * @param initialMargin The amount of margin of the trade.\n * @param sentAddresses The addresses to send tokens: lender, borrower,\n * receiver and manager:\n * lender: must match loan if loanId provided.\n * borrower: must match loan if loanId provided.\n * receiver: receiver of funds (address(0) assumes borrower address).\n * manager: delegated manager of loan unless address(0).\n * @param newPrincipal New loan size (borrowAmount + any borrowed interest).\n * @return The loanId.\n * */\n function _initializeLoan(\n LoanParams memory loanParamsLocal,\n bytes32 loanId,\n uint256 initialMargin,\n MarginTradeStructHelpers.SentAddresses memory sentAddresses,\n uint256 newPrincipal\n ) internal returns (bytes32) {\n require(loanParamsLocal.active, \"loanParams disabled\");\n\n address lender = sentAddresses.lender;\n address borrower = sentAddresses.borrower;\n address manager = sentAddresses.manager;\n\n Loan memory loanLocal;\n\n if (loanId == 0) {\n borrowerNonce[borrower]++;\n loanId = keccak256(\n abi.encodePacked(loanParamsLocal.id, lender, borrower, borrowerNonce[borrower])\n );\n require(loans[loanId].id == 0, \"loan exists\");\n\n loanLocal = Loan({\n id: loanId,\n loanParamsId: loanParamsLocal.id,\n pendingTradesId: 0,\n active: true,\n principal: newPrincipal,\n collateral: 0, /// calculated later\n startTimestamp: block.timestamp,\n endTimestamp: 0, /// calculated later\n startMargin: initialMargin,\n startRate: 0, /// queried later\n borrower: borrower,\n lender: lender\n });\n\n activeLoansSet.addBytes32(loanId);\n lenderLoanSets[lender].addBytes32(loanId);\n borrowerLoanSets[borrower].addBytes32(loanId);\n } else {\n loanLocal = loans[loanId];\n require(\n loanLocal.active && block.timestamp < loanLocal.endTimestamp,\n \"loan has ended\"\n );\n require(loanLocal.borrower == borrower, \"borrower mismatch\");\n require(loanLocal.lender == lender, \"lender mismatch\");\n require(loanLocal.loanParamsId == loanParamsLocal.id, \"loanParams mismatch\");\n\n loanLocal.principal = loanLocal.principal.add(newPrincipal);\n }\n\n if (manager != address(0)) {\n _setDelegatedManager(loanId, borrower, manager, true);\n }\n\n loans[loanId] = loanLocal;\n\n return loanId;\n }\n\n /**\n * @notice Initialize a loan interest.\n *\n * @dev A Torque loan is an indefinite-term loan.\n *\n * @param loanParamsLocal The loan parameters.\n * @param loanLocal The loan object.\n * @param newRate The new interest rate of the loan.\n * @param newPrincipal The new principal amount of the loan.\n * @param torqueInterest The interest rate of the Torque loan.\n *\n * @return interestAmountRequired The interest amount required.\n * */\n function _initializeInterest(\n LoanParams memory loanParamsLocal,\n Loan storage loanLocal,\n uint256 newRate,\n uint256 newPrincipal,\n uint256 torqueInterest /// ignored for fixed-term loans\n ) internal returns (uint256 interestAmountRequired) {\n /// Pay outstanding interest to lender.\n _payInterest(loanLocal.lender, loanParamsLocal.loanToken);\n\n LoanInterest storage loanInterestLocal = loanInterest[loanLocal.id];\n LenderInterest storage lenderInterestLocal =\n lenderInterest[loanLocal.lender][loanParamsLocal.loanToken];\n\n uint256 maxLoanTerm = loanParamsLocal.maxLoanTerm;\n\n _settleFeeRewardForInterestExpense(\n loanInterestLocal,\n loanLocal.id,\n loanParamsLocal.loanToken, /// fee token\n loanParamsLocal.collateralToken, /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n loanLocal.borrower,\n block.timestamp\n );\n\n uint256 previousDepositRemaining;\n if (maxLoanTerm == 0 && loanLocal.endTimestamp != 0) {\n previousDepositRemaining = loanLocal\n .endTimestamp\n .sub(block.timestamp) /// block.timestamp < endTimestamp was confirmed earlier.\n .mul(loanInterestLocal.owedPerDay)\n .div(86400);\n }\n\n uint256 owedPerDay = newPrincipal.mul(newRate).div(365 * 10**20);\n\n /// Update stored owedPerDay\n loanInterestLocal.owedPerDay = loanInterestLocal.owedPerDay.add(owedPerDay);\n lenderInterestLocal.owedPerDay = lenderInterestLocal.owedPerDay.add(owedPerDay);\n\n if (maxLoanTerm == 0) {\n /// Indefinite-term (Torque) loan.\n\n /// torqueInterest != 0 was confirmed earlier.\n loanLocal.endTimestamp = torqueInterest\n .add(previousDepositRemaining)\n .mul(86400)\n .div(loanInterestLocal.owedPerDay)\n .add(block.timestamp);\n\n maxLoanTerm = loanLocal.endTimestamp.sub(block.timestamp);\n\n /// Loan term has to at least be greater than one hour.\n require(maxLoanTerm > 3600, \"loan too short\");\n\n interestAmountRequired = torqueInterest;\n } else {\n /// Fixed-term loan.\n\n if (loanLocal.endTimestamp == 0) {\n loanLocal.endTimestamp = block.timestamp.add(maxLoanTerm);\n }\n\n interestAmountRequired = loanLocal\n .endTimestamp\n .sub(block.timestamp)\n .mul(owedPerDay)\n .div(86400);\n }\n\n loanInterestLocal.depositTotal = loanInterestLocal.depositTotal.add(\n interestAmountRequired\n );\n\n /// Update remaining lender interest values.\n lenderInterestLocal.principalTotal = lenderInterestLocal.principalTotal.add(newPrincipal);\n lenderInterestLocal.owedTotal = lenderInterestLocal.owedTotal.add(interestAmountRequired);\n }\n\n /**\n * @notice Get the required collateral.\n *\n * @dev Basically collateral = newPrincipal * marginAmount\n *\n * @param loanToken The loan token instance address.\n * @param collateralToken The collateral token instance address.\n * @param newPrincipal The updated amount of principal (current debt).\n * @param marginAmount The amount of margin of the trade.\n * @param isTorqueLoan Whether the loan is a Torque loan.\n *\n * @return collateralTokenAmount The required collateral.\n * */\n function _getRequiredCollateral(\n address loanToken,\n address collateralToken,\n uint256 newPrincipal,\n uint256 marginAmount,\n bool isTorqueLoan\n ) internal view returns (uint256 collateralTokenAmount) {\n if (loanToken == collateralToken) {\n collateralTokenAmount = newPrincipal.mul(marginAmount).div(10**20);\n } else {\n /// Using the price feed instead of the swap expected return\n /// because we need the rate in the inverse direction\n /// so the swap is probably farther off than the price feed.\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(collateralToken, loanToken);\n if (sourceToDestRate != 0) {\n collateralTokenAmount = newPrincipal\n .mul(sourceToDestPrecision)\n .div(sourceToDestRate)\n .mul(marginAmount)\n .div(10**20);\n /*TODO: review\n\t\t\t\tcollateralTokenAmount = newPrincipal.mul(sourceToDestPrecision).mul(marginAmount).div(sourceToDestRate).div(10**20);*/\n }\n }\n // ./tests/loan-token/TradingTestToken.test.js\n if (isTorqueLoan && collateralTokenAmount != 0) {\n collateralTokenAmount = collateralTokenAmount.mul(10**20).div(marginAmount).add(\n collateralTokenAmount\n );\n }\n }\n}\n" + }, + "contracts/modules/LoanSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/LoanSettingsEvents.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Loan Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to get and set loan parameters.\n * */\ncontract LoanSettings is State, LoanSettingsEvents, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"LoanSettings - fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.setupLoanParams.selector];\n _setTarget(this.setupLoanParams.selector, target);\n _setTarget(this.disableLoanParams.selector, target);\n _setTarget(this.getLoanParams.selector, target);\n _setTarget(this.getLoanParamsList.selector, target);\n _setTarget(this.getTotalPrincipal.selector, target);\n _setTarget(this.minInitialMargin.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"LoanSettings\");\n }\n\n /**\n * @notice Setup loan parameters, by looping every loan\n * and populating its parameters.\n *\n * @dev For each loan calls _setupLoanParams internal function.\n *\n * @param loanParamsList The array of loan parameters.\n *\n * @return loanParamsIdList The array of loan parameters IDs.\n * */\n function setupLoanParams(LoanParams[] calldata loanParamsList)\n external\n whenNotPaused\n returns (bytes32[] memory loanParamsIdList)\n {\n loanParamsIdList = new bytes32[](loanParamsList.length);\n for (uint256 i = 0; i < loanParamsList.length; i++) {\n loanParamsIdList[i] = _setupLoanParams(loanParamsList[i]);\n }\n }\n\n /**\n * @notice Deactivate LoanParams for future loans. Active loans\n * using it are unaffected.\n *\n * @param loanParamsIdList The array of loan parameters IDs to deactivate.\n * */\n function disableLoanParams(bytes32[] calldata loanParamsIdList) external whenNotPaused {\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n require(msg.sender == loanParams[loanParamsIdList[i]].owner, \"unauthorized owner\");\n loanParams[loanParamsIdList[i]].active = false;\n\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n emit LoanParamsDisabled(\n loanParamsLocal.id,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdDisabled(loanParamsLocal.id, loanParamsLocal.owner);\n }\n }\n\n /**\n * @notice Get loan parameters for every matching IDs.\n *\n * @param loanParamsIdList The array of loan parameters IDs to match.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParams(bytes32[] memory loanParamsIdList)\n public\n view\n returns (LoanParams[] memory loanParamsList)\n {\n loanParamsList = new LoanParams[](loanParamsIdList.length);\n uint256 itemCount;\n\n for (uint256 i = 0; i < loanParamsIdList.length; i++) {\n LoanParams memory loanParamsLocal = loanParams[loanParamsIdList[i]];\n if (loanParamsLocal.id == 0) {\n continue;\n }\n loanParamsList[itemCount] = loanParamsLocal;\n itemCount++;\n }\n\n if (itemCount < loanParamsList.length) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get loan parameters for an owner and a given page\n * defined by an offset and a limit.\n *\n * @param owner The address of the loan owner.\n * @param start The page offset.\n * @param count The page limit.\n *\n * @return loanParamsList The result array of loan parameters.\n * */\n function getLoanParamsList(\n address owner,\n uint256 start,\n uint256 count\n ) external view returns (bytes32[] memory loanParamsList) {\n EnumerableBytes32Set.Bytes32Set storage set = userLoanParamSets[owner];\n uint256 end = start.add(count).min256(set.length());\n if (start >= end) {\n return loanParamsList;\n }\n\n loanParamsList = new bytes32[](count);\n uint256 itemCount;\n for (uint256 i = end - start; i > 0; i--) {\n if (itemCount == count) {\n break;\n }\n loanParamsList[itemCount] = set.get(i + start - 1);\n itemCount++;\n }\n\n if (itemCount < count) {\n assembly {\n mstore(loanParamsList, itemCount)\n }\n }\n }\n\n /**\n * @notice Get the total principal of the loans by a lender.\n *\n * @param lender The address of the lender.\n * @param loanToken The address of the token instance.\n *\n * @return The total principal of the loans.\n * */\n function getTotalPrincipal(address lender, address loanToken) external view returns (uint256) {\n return lenderInterest[lender][loanToken].principalTotal;\n }\n\n /**\n * @notice Setup a loan parameters.\n *\n * @param loanParamsLocal The loan parameters.\n *\n * @return loanParamsId The loan parameters ID.\n * */\n function _setupLoanParams(LoanParams memory loanParamsLocal) internal returns (bytes32) {\n bytes32 loanParamsId =\n keccak256(\n abi.encodePacked(\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm,\n block.timestamp\n )\n );\n require(loanParams[loanParamsId].id == 0, \"loanParams exists\");\n\n require(\n loanParamsLocal.loanToken != address(0) &&\n loanParamsLocal.collateralToken != address(0) &&\n loanParamsLocal.minInitialMargin > loanParamsLocal.maintenanceMargin &&\n (loanParamsLocal.maxLoanTerm == 0 || loanParamsLocal.maxLoanTerm > 3600), /// A defined maxLoanTerm has to be greater than one hour.\n \"invalid params\"\n );\n\n loanParamsLocal.id = loanParamsId;\n loanParamsLocal.active = true;\n loanParamsLocal.owner = msg.sender;\n\n loanParams[loanParamsId] = loanParamsLocal;\n userLoanParamSets[msg.sender].addBytes32(loanParamsId);\n\n emit LoanParamsSetup(\n loanParamsId,\n loanParamsLocal.owner,\n loanParamsLocal.loanToken,\n loanParamsLocal.collateralToken,\n loanParamsLocal.minInitialMargin,\n loanParamsLocal.maintenanceMargin,\n loanParamsLocal.maxLoanTerm\n );\n emit LoanParamsIdSetup(loanParamsId, loanParamsLocal.owner);\n\n return loanParamsId;\n }\n\n function minInitialMargin(bytes32 loanParamsId) external view returns (uint256) {\n return loanParams[loanParamsId].minInitialMargin;\n }\n}\n" + }, + "contracts/modules/ProtocolSettings.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../events/ProtocolSettingsEvents.sol\";\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../mixins/ProtocolTokenUser.sol\";\nimport \"../modules/interfaces/ProtocolSwapExternalInterface.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\nimport \"../governance/IFeeSharingCollector.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\n\n/**\n * @title Protocol Settings contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to customize protocol settings.\n * */\ncontract ProtocolSettings is\n State,\n ProtocolTokenUser,\n ProtocolSettingsEvents,\n ModuleCommonFunctionalities\n{\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyAdminOrOwner {\n address prevModuleContractAddress = logicTargets[this.setPriceFeedContract.selector];\n _setTarget(this.setPriceFeedContract.selector, target);\n _setTarget(this.setSwapsImplContract.selector, target);\n _setTarget(this.setLoanPool.selector, target);\n _setTarget(this.setSupportedTokens.selector, target);\n _setTarget(this.setLendingFeePercent.selector, target);\n _setTarget(this.setTradingFeePercent.selector, target);\n _setTarget(this.setBorrowingFeePercent.selector, target);\n _setTarget(this.setSwapExternalFeePercent.selector, target);\n _setTarget(this.setAffiliateFeePercent.selector, target);\n _setTarget(this.setAffiliateTradingTokenFeePercent.selector, target);\n _setTarget(this.setLiquidationIncentivePercent.selector, target);\n _setTarget(this.setMaxDisagreement.selector, target);\n _setTarget(this.setSourceBuffer.selector, target);\n _setTarget(this.setMaxSwapSize.selector, target);\n _setTarget(this.setFeesController.selector, target);\n _setTarget(this.withdrawFees.selector, target);\n _setTarget(this.withdrawLendingFees.selector, target);\n _setTarget(this.withdrawTradingFees.selector, target);\n _setTarget(this.withdrawBorrowingFees.selector, target);\n _setTarget(this.withdrawProtocolToken.selector, target);\n _setTarget(this.depositProtocolToken.selector, target);\n _setTarget(this.getLoanPoolsList.selector, target);\n _setTarget(this.isLoanPool.selector, target);\n _setTarget(this.setSovrynSwapContractRegistryAddress.selector, target);\n _setTarget(this.setWrbtcToken.selector, target);\n _setTarget(this.setProtocolTokenAddress.selector, target);\n _setTarget(this.setRolloverBaseReward.selector, target);\n _setTarget(this.setRebatePercent.selector, target);\n _setTarget(this.setSpecialRebates.selector, target);\n _setTarget(this.setSovrynProtocolAddress.selector, target);\n _setTarget(this.setSOVTokenAddress.selector, target);\n _setTarget(this.setLockedSOVAddress.selector, target);\n _setTarget(this.setMinReferralsToPayoutAffiliates.selector, target);\n _setTarget(this.getSpecialRebates.selector, target);\n _setTarget(this.getProtocolAddress.selector, target);\n _setTarget(this.getSovTokenAddress.selector, target);\n _setTarget(this.getLockedSOVAddress.selector, target);\n _setTarget(this.getFeeRebatePercent.selector, target);\n _setTarget(this.togglePaused.selector, target);\n _setTarget(this.isProtocolPaused.selector, target);\n _setTarget(this.getSwapExternalFeePercent.selector, target);\n _setTarget(this.setTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getTradingRebateRewardsBasisPoint.selector, target);\n _setTarget(this.getDedicatedSOVRebate.selector, target);\n _setTarget(this.setRolloverFlexFeePercent.selector, target);\n _setTarget(this.getDefaultPathConversion.selector, target);\n _setTarget(this.setDefaultPathConversion.selector, target);\n _setTarget(this.removeDefaultPathConversion.selector, target);\n _setTarget(this.setAdmin.selector, target);\n _setTarget(this.getAdmin.selector, target);\n _setTarget(this.setPauser.selector, target);\n _setTarget(this.getPauser.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"ProtocolSettings\");\n }\n\n /**\n * setting wrong address will break inter module functions calling\n * should be set once\n */\n function setSovrynProtocolAddress(address newProtocolAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address oldProtocolAddress = protocolAddress;\n protocolAddress = newProtocolAddress;\n\n emit SetProtocolAddress(msg.sender, oldProtocolAddress, newProtocolAddress);\n }\n\n function setSOVTokenAddress(address newSovTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newSovTokenAddress), \"newSovTokenAddress not a contract\");\n\n address oldTokenAddress = sovTokenAddress;\n sovTokenAddress = newSovTokenAddress;\n\n emit SetSOVTokenAddress(msg.sender, oldTokenAddress, newSovTokenAddress);\n }\n\n function setLockedSOVAddress(address newLockedSOVAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(newLockedSOVAddress), \"newLockSOVAddress not a contract\");\n\n address oldLockedSOVAddress = lockedSOVAddress;\n lockedSOVAddress = newLockedSOVAddress;\n\n emit SetLockedSOVAddress(msg.sender, oldLockedSOVAddress, newLockedSOVAddress);\n }\n\n /**\n * @notice Set the basis point of trading rebate rewards (SOV), max value is 9999 (99.99% liquid, 0.01% vested).\n *\n * @param newBasisPoint Basis point value.\n */\n function setTradingRebateRewardsBasisPoint(uint256 newBasisPoint)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newBasisPoint <= 9999, \"value too high\");\n\n uint256 oldBasisPoint = tradingRebateRewardsBasisPoint;\n tradingRebateRewardsBasisPoint = newBasisPoint;\n\n emit SetTradingRebateRewardsBasisPoint(msg.sender, oldBasisPoint, newBasisPoint);\n }\n\n /**\n * @notice Update the minimum number of referrals to get affiliates rewards.\n *\n * @param newMinReferrals The new minimum number of referrals.\n * */\n function setMinReferralsToPayoutAffiliates(uint256 newMinReferrals)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n uint256 oldMinReferrals = minReferralsToPayout;\n minReferralsToPayout = newMinReferrals;\n\n emit SetMinReferralsToPayoutAffiliates(msg.sender, oldMinReferrals, newMinReferrals);\n }\n\n /**\n * @notice Set the address of the Price Feed instance.\n *\n * @param newContract The address of the Price Feed new instance.\n * */\n function setPriceFeedContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = priceFeeds;\n priceFeeds = newContract;\n\n emit SetPriceFeedContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set the address of the asset swapper instance.\n *\n * @param newContract The address of the asset swapper new instance.\n * */\n function setSwapsImplContract(address newContract) external onlyAdminOrOwner whenNotPaused {\n address oldContract = swapsImpl;\n swapsImpl = newContract;\n\n emit SetSwapsImplContract(msg.sender, oldContract, newContract);\n }\n\n /**\n * @notice Set a list of loan pools and its tokens.\n *\n * @param pools The array of addresses of new loan pool instances.\n * @param assets The array of addresses of the corresponding underlying tokens.\n * */\n function setLoanPool(address[] calldata pools, address[] calldata assets)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(pools.length == assets.length, \"count mismatch\");\n\n for (uint256 i = 0; i < pools.length; i++) {\n require(pools[i] != assets[i], \"pool == asset\");\n require(pools[i] != address(0), \"pool == 0\");\n require(\n assets[i] != address(0) || loanPoolToUnderlying[pools[i]] != address(0),\n \"pool not exists\"\n );\n if (assets[i] == address(0)) {\n underlyingToLoanPool[loanPoolToUnderlying[pools[i]]] = address(0);\n loanPoolToUnderlying[pools[i]] = address(0);\n loanPoolsSet.removeAddress(pools[i]);\n } else {\n loanPoolToUnderlying[pools[i]] = assets[i];\n underlyingToLoanPool[assets[i]] = pools[i];\n loanPoolsSet.addAddress(pools[i]);\n }\n\n emit SetLoanPool(msg.sender, pools[i], assets[i]);\n }\n }\n\n /**\n * @notice Set a list of supported tokens by populating the\n * storage supportedTokens mapping.\n *\n * @param addrs The array of addresses of the tokens.\n * @param toggles The array of flags indicating whether\n * the corresponding token is supported or not.\n * */\n function setSupportedTokens(address[] calldata addrs, bool[] calldata toggles)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(addrs.length == toggles.length, \"count mismatch\");\n\n for (uint256 i = 0; i < addrs.length; i++) {\n supportedTokens[addrs[i]] = toggles[i];\n\n emit SetSupportedTokens(msg.sender, addrs[i], toggles[i]);\n }\n }\n\n /**\n * @notice Set the value of lendingFeePercent storage variable.\n *\n * @param newValue The new value for lendingFeePercent.\n * */\n function setLendingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = lendingFeePercent;\n lendingFeePercent = newValue;\n\n emit SetLendingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of tradingFeePercent storage variable.\n *\n * @param newValue The new value for tradingFeePercent.\n * */\n function setTradingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = tradingFeePercent;\n tradingFeePercent = newValue;\n\n emit SetTradingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of borrowingFeePercent storage variable.\n *\n * @param newValue The new value for borrowingFeePercent.\n * */\n function setBorrowingFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = borrowingFeePercent;\n borrowingFeePercent = newValue;\n\n emit SetBorrowingFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of swapExtrernalFeePercent storage variable\n *\n * @param newValue the new value for swapExternalFeePercent\n */\n function setSwapExternalFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = swapExtrernalFeePercent;\n swapExtrernalFeePercent = newValue;\n\n emit SetSwapExternalFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateFeePercent storage variable.\n *\n * @param newValue The new value for affiliateFeePercent.\n * */\n function setAffiliateFeePercent(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateFeePercent;\n affiliateFeePercent = newValue;\n\n emit SetAffiliateFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of affiliateTradingTokenFeePercent storage variable.\n *\n * @param newValue The new value for affiliateTradingTokenFeePercent.\n * */\n function setAffiliateTradingTokenFeePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = affiliateTradingTokenFeePercent;\n affiliateTradingTokenFeePercent = newValue;\n\n emit SetAffiliateTradingTokenFeePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of liquidationIncentivePercent storage variable.\n *\n * @param newValue The new value for liquidationIncentivePercent.\n * */\n function setLiquidationIncentivePercent(uint256 newValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newValue <= 10**20, \"value too high\");\n uint256 oldValue = liquidationIncentivePercent;\n liquidationIncentivePercent = newValue;\n\n emit SetLiquidationIncentivePercent(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the value of the maximum swap spread.\n *\n * @param newValue The new value for maxDisagreement.\n * */\n function setMaxDisagreement(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n maxDisagreement = newValue;\n }\n\n /**\n * @notice Set the value of the maximum source buffer.\n *\n * @dev To avoid rounding issues on the swap rate a small buffer is implemented.\n *\n * @param newValue The new value for the maximum source buffer.\n * */\n function setSourceBuffer(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n sourceBuffer = newValue;\n }\n\n /**\n * @notice Set the value of the swap size limit.\n *\n * @param newValue The new value for the maximum swap size.\n * */\n function setMaxSwapSize(uint256 newValue) external onlyAdminOrOwner whenNotPaused {\n uint256 oldValue = maxSwapSize;\n maxSwapSize = newValue;\n\n emit SetMaxSwapSize(msg.sender, oldValue, newValue);\n }\n\n /**\n * @notice Set the address of the feesController instance.\n *\n * @dev The fee sharing proxy must be the feesController of the\n * protocol contract. This allows the fee sharing proxy\n * to withdraw the fees.\n *\n * @param newController The new address of the feesController.\n * */\n function setFeesController(address newController) external onlyAdminOrOwner whenNotPaused {\n address oldController = feesController;\n feesController = newController;\n\n emit SetFeesController(msg.sender, oldController, newController);\n }\n\n /**\n * @notice Set the pauser address of sovryn protocol.\n *\n * only pauser or owner can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Get pauser address.\n *\n *\n * @return pauser address.\n */\n function getPauser() external view returns (address) {\n return pauser;\n }\n\n /*\n * @notice Set the admin address of sovryn protocol.\n *\n * only owner can perform this action.\n *\n * @param newAdmin The new address of the admin.\n * */\n function setAdmin(address newAdmin) external onlyOwner {\n emit SetAdmin(msg.sender, admin, newAdmin);\n admin = newAdmin;\n }\n\n /**\n * @dev Get admin address.\n *\n *\n * @return admin address.\n */\n function getAdmin() external view returns (address) {\n return admin;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * from three sources: lending, trading and borrowing.\n * The fees (except SOV) will be converted to wRBTC.\n * For SOV, it will be deposited directly to feeSharingCollector from the protocol.\n *\n * @param tokens The array of address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n *\n * @return The withdrawn total amount in wRBTC\n * */\n function withdrawFees(address[] calldata tokens, address receiver)\n external\n whenNotPaused\n returns (uint256 totalWRBTCWithdrawn)\n {\n require(msg.sender == feesController, \"unauthorized\");\n\n for (uint256 i = 0; i < tokens.length; i++) {\n uint256 lendingBalance = lendingFeeTokensHeld[tokens[i]];\n if (lendingBalance > 0) {\n lendingFeeTokensHeld[tokens[i]] = 0;\n lendingFeeTokensPaid[tokens[i]] = lendingFeeTokensPaid[tokens[i]].add(\n lendingBalance\n );\n }\n\n uint256 tradingBalance = tradingFeeTokensHeld[tokens[i]];\n if (tradingBalance > 0) {\n tradingFeeTokensHeld[tokens[i]] = 0;\n tradingFeeTokensPaid[tokens[i]] = tradingFeeTokensPaid[tokens[i]].add(\n tradingBalance\n );\n }\n\n uint256 borrowingBalance = borrowingFeeTokensHeld[tokens[i]];\n if (borrowingBalance > 0) {\n borrowingFeeTokensHeld[tokens[i]] = 0;\n borrowingFeeTokensPaid[tokens[i]] = borrowingFeeTokensPaid[tokens[i]].add(\n borrowingBalance\n );\n }\n\n uint256 tempAmount = lendingBalance.add(tradingBalance).add(borrowingBalance);\n\n if (tempAmount == 0) {\n continue;\n }\n\n uint256 amountConvertedToWRBTC;\n if (tokens[i] == address(sovTokenAddress)) {\n IERC20(tokens[i]).approve(feesController, tempAmount);\n IFeeSharingCollector(feesController).transferTokens(\n address(sovTokenAddress),\n uint96(tempAmount)\n );\n amountConvertedToWRBTC = 0;\n } else {\n if (tokens[i] == address(wrbtcToken)) {\n amountConvertedToWRBTC = tempAmount;\n\n IERC20(address(wrbtcToken)).safeTransfer(receiver, amountConvertedToWRBTC);\n } else {\n IERC20(tokens[i]).approve(protocolAddress, tempAmount);\n\n (amountConvertedToWRBTC, ) = ProtocolSwapExternalInterface(protocolAddress)\n .swapExternal(\n tokens[i], // source token address\n address(wrbtcToken), // dest token address\n feesController, // set feeSharingCollector as receiver\n protocolAddress, // protocol as the sender\n tempAmount, // source token amount\n 0, // reqDestToken\n 0, // minReturn\n \"\" // loan data bytes\n );\n\n /// Will revert if disagreement found.\n IPriceFeeds(priceFeeds).checkPriceDisagreement(\n tokens[i],\n address(wrbtcToken),\n tempAmount,\n amountConvertedToWRBTC,\n maxDisagreement\n );\n }\n\n totalWRBTCWithdrawn = totalWRBTCWithdrawn.add(amountConvertedToWRBTC);\n }\n\n emit WithdrawFees(\n msg.sender,\n tokens[i],\n receiver,\n lendingBalance,\n tradingBalance,\n borrowingBalance,\n amountConvertedToWRBTC\n );\n }\n\n return totalWRBTCWithdrawn;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from lending operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawLendingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = lendingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n lendingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n lendingFeeTokensPaid[token] = lendingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawLendingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from trading operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawTradingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = tradingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n tradingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n tradingFeeTokensPaid[token] = tradingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawTradingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The feesController calls this function to withdraw fees\n * accrued from borrowing operations.\n *\n * @param token The address of the token instance.\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of fees to get, ignored if greater than balance.\n *\n * @return Whether withdrawal was successful.\n * */\n function withdrawBorrowingFees(\n address token,\n address receiver,\n uint256 amount\n ) external whenNotPaused returns (bool) {\n require(msg.sender == feesController, \"unauthorized\");\n\n uint256 withdrawAmount = amount;\n\n uint256 balance = borrowingFeeTokensHeld[token];\n if (withdrawAmount > balance) {\n withdrawAmount = balance;\n }\n if (withdrawAmount == 0) {\n return false;\n }\n\n borrowingFeeTokensHeld[token] = balance.sub(withdrawAmount);\n borrowingFeeTokensPaid[token] = borrowingFeeTokensPaid[token].add(withdrawAmount);\n\n IERC20(token).safeTransfer(receiver, withdrawAmount);\n\n emit WithdrawBorrowingFees(msg.sender, token, receiver, withdrawAmount);\n\n return true;\n }\n\n /**\n * @notice The owner calls this function to withdraw protocol tokens.\n *\n * @dev Wrapper for ProtocolTokenUser::_withdrawProtocolToken internal function.\n *\n * @param receiver The address of the withdrawal recipient.\n * @param amount The amount of tokens to get.\n *\n * @return The protocol token address.\n * @return Withdrawal success (true/false).\n * */\n function withdrawProtocolToken(address receiver, uint256 amount)\n external\n onlyAdminOrOwner\n whenNotPaused\n returns (address, bool)\n {\n return _withdrawProtocolToken(receiver, amount);\n }\n\n /**\n * @notice The owner calls this function to deposit protocol tokens.\n *\n * @param amount The tokens of fees to send.\n * */\n function depositProtocolToken(uint256 amount) external onlyAdminOrOwner whenNotPaused {\n /// @dev Update local balance\n protocolTokenHeld = protocolTokenHeld.add(amount);\n\n /// @dev Send the tokens\n IERC20(protocolTokenAddress).safeTransferFrom(msg.sender, address(this), amount);\n }\n\n /**\n * @notice Get a list of loan pools.\n *\n * @param start The offset.\n * @param count The limit.\n *\n * @return The array of loan pools.\n * */\n function getLoanPoolsList(uint256 start, uint256 count)\n external\n view\n returns (bytes32[] memory)\n {\n return loanPoolsSet.enumerate(start, count);\n }\n\n /**\n * @notice Check whether a token is a pool token.\n *\n * @dev By querying its underlying token.\n *\n * @param loanPool The token address to check.\n * */\n function isLoanPool(address loanPool) external view returns (bool) {\n return loanPoolToUnderlying[loanPool] != address(0);\n }\n\n /**\n * @notice Set the contract registry address of the SovrynSwap network.\n *\n * @param registryAddress the address of the registry contract.\n * */\n function setSovrynSwapContractRegistryAddress(address registryAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(registryAddress), \"registryAddress not a contract\");\n\n address oldSovrynSwapContractRegistryAddress = sovrynSwapContractRegistryAddress;\n sovrynSwapContractRegistryAddress = registryAddress;\n\n emit SetSovrynSwapContractRegistryAddress(\n msg.sender,\n oldSovrynSwapContractRegistryAddress,\n sovrynSwapContractRegistryAddress\n );\n }\n\n /**\n * @notice Set the wrBTC contract address.\n *\n * @param wrbtcTokenAddress The address of the wrBTC contract.\n * */\n function setWrbtcToken(address wrbtcTokenAddress) external onlyAdminOrOwner whenNotPaused {\n require(Address.isContract(wrbtcTokenAddress), \"wrbtcTokenAddress not a contract\");\n\n address oldwrbtcToken = address(wrbtcToken);\n wrbtcToken = IWrbtcERC20(wrbtcTokenAddress);\n\n emit SetWrbtcToken(msg.sender, oldwrbtcToken, wrbtcTokenAddress);\n }\n\n /**\n * @notice Set the protocol token contract address.\n *\n * @param _protocolTokenAddress The address of the protocol token contract.\n * */\n function setProtocolTokenAddress(address _protocolTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(Address.isContract(_protocolTokenAddress), \"_protocolTokenAddress not a contract\");\n\n address oldProtocolTokenAddress = protocolTokenAddress;\n protocolTokenAddress = _protocolTokenAddress;\n\n emit SetProtocolTokenAddress(msg.sender, oldProtocolTokenAddress, _protocolTokenAddress);\n }\n\n /**\n * @notice Set rollover base reward. It should be denominated in wrBTC.\n *\n * @param baseRewardValue The base reward.\n * */\n function setRolloverBaseReward(uint256 baseRewardValue)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(baseRewardValue > 0, \"Base reward is zero\");\n\n uint256 oldValue = rolloverBaseReward;\n rolloverBaseReward = baseRewardValue;\n\n emit SetRolloverBaseReward(msg.sender, oldValue, rolloverBaseReward);\n }\n\n /**\n * @notice Set the fee rebate percent.\n *\n * @param rebatePercent The fee rebate percent.\n * */\n function setRebatePercent(uint256 rebatePercent) external onlyAdminOrOwner whenNotPaused {\n require(rebatePercent <= 10**20, \"Fee rebate is too high\");\n\n uint256 oldRebatePercent = feeRebatePercent;\n feeRebatePercent = rebatePercent;\n\n emit SetRebatePercent(msg.sender, oldRebatePercent, rebatePercent);\n }\n\n /**\n * @notice Set the special fee rebate percent for specific pair\n *\n * @param specialRebatesPercent The new special fee rebate percent.\n * */\n function setSpecialRebates(\n address sourceToken,\n address destToken,\n uint256 specialRebatesPercent\n ) external onlyAdminOrOwner whenNotPaused {\n // Set max special rebates to 1000%\n require(specialRebatesPercent <= 1000e18, \"Special fee rebate is too high\");\n\n uint256 oldSpecialRebatesPercent = specialRebates[sourceToken][destToken];\n specialRebates[sourceToken][destToken] = specialRebatesPercent;\n\n emit SetSpecialRebates(\n msg.sender,\n sourceToken,\n destToken,\n oldSpecialRebatesPercent,\n specialRebatesPercent\n );\n }\n\n /**\n * @notice Get a rebate percent of specific pairs.\n *\n * @param sourceTokenAddress The source of pairs.\n * @param destTokenAddress The dest of pairs.\n *\n * @return The percent rebates of the pairs.\n * */\n function getSpecialRebates(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (uint256 specialRebatesPercent)\n {\n return specialRebates[sourceTokenAddress][destTokenAddress];\n }\n\n function getProtocolAddress() external view returns (address) {\n return protocolAddress;\n }\n\n function getSovTokenAddress() external view returns (address) {\n return sovTokenAddress;\n }\n\n function getLockedSOVAddress() external view returns (address) {\n return lockedSOVAddress;\n }\n\n function getFeeRebatePercent() external view returns (uint256) {\n return feeRebatePercent;\n }\n\n function togglePaused(bool paused) external onlyPauserOrOwner {\n require(paused != pause, \"Can't toggle\");\n pause = paused;\n emit TogglePaused(msg.sender, !paused, paused);\n }\n\n function isProtocolPaused() external view returns (bool) {\n return pause;\n }\n\n function getSwapExternalFeePercent() external view returns (uint256) {\n return swapExtrernalFeePercent;\n }\n\n /**\n * @notice Get the basis point of trading rebate rewards.\n *\n * @return The basis point value.\n */\n function getTradingRebateRewardsBasisPoint() external view returns (uint256) {\n return tradingRebateRewardsBasisPoint;\n }\n\n /**\n * @dev Get how much SOV that is dedicated to pay the trading rebate rewards.\n * @notice If SOV balance is less than the fees held, it will return 0.\n *\n * @return total dedicated SOV.\n */\n function getDedicatedSOVRebate() public view returns (uint256) {\n uint256 sovProtocolBalance = IERC20(sovTokenAddress).balanceOf(address(this));\n uint256 sovFees =\n lendingFeeTokensHeld[sovTokenAddress].add(tradingFeeTokensHeld[sovTokenAddress]).add(\n borrowingFeeTokensHeld[sovTokenAddress]\n );\n\n return sovProtocolBalance >= sovFees ? sovProtocolBalance.sub(sovFees) : 0;\n }\n\n /**\n * @notice Set rolloverFlexFeePercent (max value is 1%)\n *\n * @param newRolloverFlexFeePercent uint256 value of new rollover flex fee percentage (0.1 ether = 0.1%)\n */\n function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(newRolloverFlexFeePercent <= 1e18, \"value too high\");\n uint256 oldRolloverFlexFeePercent = rolloverFlexFeePercent;\n rolloverFlexFeePercent = newRolloverFlexFeePercent;\n\n emit SetRolloverFlexFeePercent(\n msg.sender,\n oldRolloverFlexFeePercent,\n newRolloverFlexFeePercent\n );\n }\n\n /**\n * @dev Get default path conversion for pairs.\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address.\n *\n * @return default path of the conversion.\n */\n function getDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n view\n returns (IERC20[] memory)\n {\n return defaultPathConversion[sourceTokenAddress][destTokenAddress];\n }\n\n /**\n * @dev Set default path conversion for pairs.\n *\n * @param defaultPath array of addresses for the default path.\n *\n */\n function setDefaultPathConversion(IERC20[] calldata defaultPath)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n address sourceTokenAddress = address(defaultPath[0]);\n address destTokenAddress = address(defaultPath[defaultPath.length - 1]);\n\n uint256 defaultPathLength = defaultPath.length;\n require(defaultPathLength >= 3, \"ERR_PATH_LENGTH\");\n\n for (uint256 i = 0; i < defaultPathLength; i++) {\n require(Address.isContract(address(defaultPath[i])), \"ERR_PATH_NON_CONTRACT_ADDR\");\n }\n\n defaultPathConversion[sourceTokenAddress][destTokenAddress] = defaultPath;\n\n emit SetDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPath\n );\n }\n\n /**\n * @dev Remove the default path conversion for pairs\n *\n * @param sourceTokenAddress source token address.\n * @param destTokenAddress destination token address\n */\n function removeDefaultPathConversion(address sourceTokenAddress, address destTokenAddress)\n external\n onlyAdminOrOwner\n whenNotPaused\n {\n require(\n defaultPathConversion[sourceTokenAddress][destTokenAddress].length > 0,\n \"DEFAULT_PATH_EMPTY\"\n );\n\n IERC20[] memory defaultPathValue =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n delete defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n emit RemoveDefaultPathConversion(\n msg.sender,\n sourceTokenAddress,\n destTokenAddress,\n defaultPathValue\n );\n }\n}\n" + }, + "contracts/modules/SwapsExternal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../core/State.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../swaps/SwapsUser.sol\";\nimport \"../mixins/ModuleCommonFunctionalities.sol\";\n\n/**\n * @title Swaps External contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains functions to calculate and execute swaps.\n * */\ncontract SwapsExternal is VaultController, SwapsUser, ModuleCommonFunctionalities {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress = logicTargets[this.swapExternal.selector];\n _setTarget(this.swapExternal.selector, target);\n _setTarget(this.getSwapExpectedReturn.selector, target);\n _setTarget(this.checkPriceDivergence.selector, target);\n emit ProtocolModuleContractReplaced(prevModuleContractAddress, target, \"SwapsExternal\");\n }\n\n /**\n * @notice Perform a swap w/ tokens or rBTC as source currency.\n *\n * @dev External wrapper that calls SwapsUser::_swapsCall\n * after turning potential incoming rBTC into wrBTC tokens.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param receiver The address of the recipient account.\n * @param returnToSender The address of the sender account.\n * @param sourceTokenAmount The amount of source tokens.\n * @param requiredDestTokenAmount The amount of required destiny tokens.\n * @param minReturn Minimum amount (position size) in the collateral tokens.\n * @param swapData Additional swap data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function swapExternal(\n address sourceToken,\n address destToken,\n address receiver,\n address returnToSender,\n uint256 sourceTokenAmount,\n uint256 requiredDestTokenAmount,\n uint256 minReturn,\n bytes memory swapData\n )\n public\n payable\n nonReentrant\n whenNotPaused\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(sourceTokenAmount != 0, \"sourceTokenAmount == 0\");\n checkPriceDivergence(sourceToken, destToken, sourceTokenAmount, minReturn);\n\n /// @dev Get payed value, be it rBTC or tokenized.\n if (msg.value != 0) {\n if (sourceToken == address(0)) {\n sourceToken = address(wrbtcToken);\n }\n require(sourceToken == address(wrbtcToken), \"sourceToken mismatch\");\n require(msg.value == sourceTokenAmount, \"sourceTokenAmount mismatch\");\n\n /// @dev Update wrBTC balance for this contract.\n wrbtcToken.deposit.value(sourceTokenAmount)();\n } else {\n if (address(this) != msg.sender) {\n IERC20(sourceToken).safeTransferFrom(msg.sender, address(this), sourceTokenAmount);\n }\n }\n\n /// @dev Perform the swap w/ tokens.\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n receiver,\n returnToSender,\n msg.sender /// user\n ],\n [\n sourceTokenAmount, /// minSourceTokenAmount\n sourceTokenAmount, /// maxSourceTokenAmount\n requiredDestTokenAmount\n ],\n 0, /// loanId (not tied to a specific loan)\n false, /// bypassFee\n swapData,\n true // the flag for swapExternal (so that it will use the swapExternalFeePercent)\n );\n\n emit ExternalSwap(\n msg.sender, /// user\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Get the swap expected return value.\n *\n * @dev External wrapper that calls SwapsUser::_swapsExpectedReturn\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n *\n * @return The expected return value.\n * */\n function getSwapExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n }\n\n /**\n * @notice Check the slippage based on the swapExpectedReturn.\n *\n * @param sourceToken The address of the source token instance.\n * @param destToken The address of the destiny token instance.\n * @param sourceTokenAmount The amount of source tokens.\n * @param minReturn The amount (max slippage) that will be compared to the swapsExpectedReturn.\n *\n */\n function checkPriceDivergence(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount,\n uint256 minReturn\n ) public view {\n uint256 destTokenAmount = _swapsExpectedReturn(sourceToken, destToken, sourceTokenAmount);\n require(destTokenAmount >= minReturn, \"destTokenAmountReceived too low\");\n }\n}\n" + }, + "contracts/modules/SwapsImplSovrynSwapModule.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../swaps/connectors/SwapsImplSovrynSwapLib.sol\";\nimport \"../events/ModulesCommonEvents.sol\";\n\ncontract SwapsImplSovrynSwapModule is State, ModulesCommonEvents {\n /**\n * @notice Empty public constructor.\n * */\n constructor() public {}\n\n /**\n * @notice Fallback function is to react to receiving value (rBTC).\n * */\n function() external {\n revert(\"fallback not allowed\");\n }\n\n /**\n * @notice Set function selectors on target contract.\n *\n * @param target The address of the target contract.\n * */\n function initialize(address target) external onlyOwner {\n address prevModuleContractAddress =\n logicTargets[this.getSovrynSwapNetworkContract.selector];\n _setTarget(this.getSovrynSwapNetworkContract.selector, target);\n _setTarget(this.getContractHexName.selector, target);\n _setTarget(this.swapsImplExpectedRate.selector, target);\n _setTarget(this.swapsImplExpectedReturn.selector, target);\n emit ProtocolModuleContractReplaced(\n prevModuleContractAddress,\n target,\n \"SwapsImplSovrynSwapModule\"\n );\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n return SwapsImplSovrynSwapLib.getContractHexName(source);\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n return SwapsImplSovrynSwapLib.getSovrynSwapNetworkContract(sovrynSwapRegistryAddress);\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function swapsImplExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256) {\n return\n SwapsImplSovrynSwapLib.getExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function swapsImplExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) external view returns (uint256 expectedReturn) {\n return\n SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceTokenAddress,\n destTokenAddress,\n sourceTokenAmount\n );\n }\n}\n" + }, + "contracts/multisig/MultiSigKeyHolders.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../openzeppelin/Ownable.sol\";\n\n/**\n * @title Multi Signature Key Holders contract.\n *\n * This contract contains the implementation of functions to add and remove\n * key holders w/ rBTC and BTC addresses.\n * */\ncontract MultiSigKeyHolders is Ownable {\n /* Storage */\n\n uint256 public constant MAX_OWNER_COUNT = 50;\n\n string private constant ERROR_INVALID_ADDRESS = \"Invalid address\";\n string private constant ERROR_INVALID_REQUIRED = \"Invalid required\";\n\n /// Flag and index for Ethereum address.\n mapping(address => Data) private isEthereumAddressAdded;\n\n /// List of Ethereum addresses.\n address[] private ethereumAddresses;\n\n /// Required number of signatures for the Ethereum multisig.\n uint256 public ethereumRequired = 2;\n\n /// Flag and index for Bitcoin address.\n mapping(string => Data) private isBitcoinAddressAdded;\n\n /// List of Bitcoin addresses.\n string[] private bitcoinAddresses;\n\n /// Required number of signatures for the Bitcoin multisig.\n uint256 public bitcoinRequired = 2;\n\n /// Helps removing items from array.\n struct Data {\n bool added;\n uint248 index;\n }\n\n /* Events */\n\n event EthereumAddressAdded(address indexed account);\n event EthereumAddressRemoved(address indexed account);\n event EthereumRequirementChanged(uint256 required);\n event BitcoinAddressAdded(string account);\n event BitcoinAddressRemoved(string account);\n event BitcoinRequirementChanged(uint256 required);\n\n /* Modifiers */\n\n modifier validRequirement(uint256 ownerCount, uint256 _required) {\n require(\n ownerCount <= MAX_OWNER_COUNT &&\n _required <= ownerCount &&\n _required != 0 &&\n ownerCount != 0,\n ERROR_INVALID_REQUIRED\n );\n _;\n }\n\n /* Functions */\n\n /**\n * @notice Add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function addEthereumAddress(address _address) public onlyOwner {\n _addEthereumAddress(_address);\n }\n\n /**\n * @notice Add rBTC addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add rBTC address to the key holders.\n * @param _address The address to be added.\n * */\n function _addEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (!isEthereumAddressAdded[_address].added) {\n isEthereumAddressAdded[_address] = Data({\n added: true,\n index: uint248(ethereumAddresses.length)\n });\n ethereumAddresses.push(_address);\n }\n\n emit EthereumAddressAdded(_address);\n }\n\n /**\n * @notice Remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeEthereumAddress(address _address) public onlyOwner {\n _removeEthereumAddress(_address);\n }\n\n /**\n * @notice Remove rBTC addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeEthereumAddresses(address[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeEthereumAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove rBTC address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeEthereumAddress(address _address) internal {\n require(_address != address(0), ERROR_INVALID_ADDRESS);\n\n if (isEthereumAddressAdded[_address].added) {\n uint248 index = isEthereumAddressAdded[_address].index;\n if (index != ethereumAddresses.length - 1) {\n ethereumAddresses[index] = ethereumAddresses[ethereumAddresses.length - 1];\n isEthereumAddressAdded[ethereumAddresses[index]].index = index;\n }\n ethereumAddresses.length--;\n delete isEthereumAddressAdded[_address];\n }\n\n emit EthereumAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether rBTC address is a key holder.\n * @param _address The rBTC address to be checked.\n * */\n function isEthereumAddressOwner(address _address) public view returns (bool) {\n return isEthereumAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of rBTC key holders.\n * */\n function getEthereumAddresses() public view returns (address[] memory) {\n return ethereumAddresses;\n }\n\n /**\n * @notice Set flag ethereumRequired to true/false.\n * @param _required The new value of the ethereumRequired flag.\n * */\n function changeEthereumRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(ethereumAddresses.length, _required)\n {\n ethereumRequired = _required;\n emit EthereumRequirementChanged(_required);\n }\n\n /**\n * @notice Add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function addBitcoinAddress(string memory _address) public onlyOwner {\n _addBitcoinAddress(_address);\n }\n\n /**\n * @notice Add bitcoin addresses to the key holders.\n * @param _address The addresses to be added.\n * */\n function addBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _addBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to add bitcoin address to the key holders.\n * @param _address The address to be added.\n * */\n function _addBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (!isBitcoinAddressAdded[_address].added) {\n isBitcoinAddressAdded[_address] = Data({\n added: true,\n index: uint248(bitcoinAddresses.length)\n });\n bitcoinAddresses.push(_address);\n }\n\n emit BitcoinAddressAdded(_address);\n }\n\n /**\n * @notice Remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function removeBitcoinAddress(string memory _address) public onlyOwner {\n _removeBitcoinAddress(_address);\n }\n\n /**\n * @notice Remove bitcoin addresses to the key holders.\n * @param _address The addresses to be removed.\n * */\n function removeBitcoinAddresses(string[] memory _address) public onlyOwner {\n for (uint256 i = 0; i < _address.length; i++) {\n _removeBitcoinAddress(_address[i]);\n }\n }\n\n /**\n * @notice Internal function to remove bitcoin address to the key holders.\n * @param _address The address to be removed.\n * */\n function _removeBitcoinAddress(string memory _address) internal {\n require(bytes(_address).length != 0, ERROR_INVALID_ADDRESS);\n\n if (isBitcoinAddressAdded[_address].added) {\n uint248 index = isBitcoinAddressAdded[_address].index;\n if (index != bitcoinAddresses.length - 1) {\n bitcoinAddresses[index] = bitcoinAddresses[bitcoinAddresses.length - 1];\n isBitcoinAddressAdded[bitcoinAddresses[index]].index = index;\n }\n bitcoinAddresses.length--;\n delete isBitcoinAddressAdded[_address];\n }\n\n emit BitcoinAddressRemoved(_address);\n }\n\n /**\n * @notice Get whether bitcoin address is a key holder.\n * @param _address The bitcoin address to be checked.\n * */\n function isBitcoinAddressOwner(string memory _address) public view returns (bool) {\n return isBitcoinAddressAdded[_address].added;\n }\n\n /**\n * @notice Get array of bitcoin key holders.\n * */\n function getBitcoinAddresses() public view returns (string[] memory) {\n return bitcoinAddresses;\n }\n\n /**\n * @notice Set flag bitcoinRequired to true/false.\n * @param _required The new value of the bitcoinRequired flag.\n * */\n function changeBitcoinRequirement(uint256 _required)\n public\n onlyOwner\n validRequirement(bitcoinAddresses.length, _required)\n {\n bitcoinRequired = _required;\n emit BitcoinRequirementChanged(_required);\n }\n\n /**\n * @notice Add rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress the rBTC addresses to be added.\n * @param _bitcoinAddress the bitcoin addresses to be added.\n * */\n function addEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _addEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _addBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n\n /**\n * @notice Remove rBTC and bitcoin addresses to the key holders.\n * @param _ethereumAddress The rBTC addresses to be removed.\n * @param _bitcoinAddress The bitcoin addresses to be removed.\n * */\n function removeEthereumAndBitcoinAddresses(\n address[] memory _ethereumAddress,\n string[] memory _bitcoinAddress\n ) public onlyOwner {\n for (uint256 i = 0; i < _ethereumAddress.length; i++) {\n _removeEthereumAddress(_ethereumAddress[i]);\n }\n for (uint256 i = 0; i < _bitcoinAddress.length; i++) {\n _removeBitcoinAddress(_bitcoinAddress[i]);\n }\n }\n}\n" + }, + "contracts/openzeppelin/Address.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n // for accounts without code, i.e. `keccak256('')`\n bytes32 codehash;\n bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n codehash := extcodehash(account)\n }\n return (codehash != accountHash && codehash != 0x0);\n }\n\n /**\n * @dev Converts an `address` into `address payable`. Note that this is\n * simply a type cast: the actual underlying value is not changed.\n *\n * _Available since v2.4.0._\n */\n function toPayable(address account) internal pure returns (address payable) {\n return address(uint160(account));\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html\n * #use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n *\n * _Available since v2.4.0._\n */\n function sendValue(address recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n // solhint-disable-next-line avoid-call-value\n (bool success, ) = recipient.call.value(amount)(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n}\n" + }, + "contracts/openzeppelin/Context.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n // Empty internal constructor, to prevent people from mistakenly deploying\n // an instance of this contract, which should be used via inheritance.\n constructor() internal {}\n\n // solhint-disable-previous-line no-empty-blocks\n\n function _msgSender() internal view returns (address payable) {\n return msg.sender;\n }\n\n function _msgData() internal view returns (bytes memory) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n" + }, + "contracts/openzeppelin/ERC20.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./Context.sol\";\nimport \"./IERC20_.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20Mintable}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20_ {\n using SafeMath for uint256;\n\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n _transfer(_msgSender(), recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public returns (bool) {\n _approve(_msgSender(), spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20};\n *\n * Requirements:\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for `sender`'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n _msgSender(),\n _allowances[sender][_msgSender()].sub(\n amount,\n \"ERC20: transfer amount exceeds allowance\"\n )\n );\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n _approve(\n _msgSender(),\n spender,\n _allowances[_msgSender()][spender].sub(\n subtractedValue,\n \"ERC20: decreased allowance below zero\"\n )\n );\n return true;\n }\n\n /**\n * @dev Moves tokens `amount` from `sender` to `recipient`.\n *\n * This is internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal {\n require(sender != address(0), \"ERC20: transfer from the zero address\");\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n _balances[sender] = _balances[sender].sub(\n amount,\n \"ERC20: transfer amount exceeds balance\"\n );\n _balances[recipient] = _balances[recipient].add(amount);\n emit Transfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n _balances[account] = _balances[account].sub(amount, \"ERC20: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.\n *\n * This is internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`.`amount` is then deducted\n * from the caller's allowance.\n *\n * See {_burn} and {_approve}.\n */\n function _burnFrom(address account, uint256 amount) internal {\n _burn(account, amount);\n _approve(\n account,\n _msgSender(),\n _allowances[account][_msgSender()].sub(amount, \"ERC20: burn amount exceeds allowance\")\n );\n }\n}\n" + }, + "contracts/openzeppelin/ERC20Detailed.sol": { + "content": "pragma solidity ^0.5.0;\n\nimport \"./IERC20_.sol\";\n\n/**\n * @dev Optional functions from the ERC20 standard.\n */\ncontract ERC20Detailed is IERC20_ {\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of\n * these values are immutable: they can only be set once during\n * construction.\n */\n constructor(\n string memory name,\n string memory symbol,\n uint8 decimals\n ) public {\n _name = name;\n _symbol = symbol;\n _decimals = decimals;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n}\n" + }, + "contracts/openzeppelin/IERC20_.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20_ {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n" + }, + "contracts/openzeppelin/Initializable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n */\ncontract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n bool private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Modifier to protect an initializer function from being invoked twice.\n */\n modifier initializer() {\n require(_initializing || !_initialized, \"Initializable: contract is already initialized\");\n\n bool isTopLevelCall = !_initializing;\n if (isTopLevelCall) {\n _initializing = true;\n _initialized = true;\n }\n\n _;\n\n if (isTopLevelCall) {\n _initializing = false;\n }\n }\n}\n" + }, + "contracts/openzeppelin/Ownable.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(isOwner(), \"unauthorized\");\n _;\n }\n\n /**\n * @dev Returns true if the caller is the current owner.\n */\n function isOwner() public view returns (bool) {\n return _msgSender() == _owner;\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public onlyOwner {\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n */\n function _transferOwnership(address newOwner) internal {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n}\n" + }, + "contracts/openzeppelin/PausableOz.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"./Ownable.sol\";\n\ncontract PausableOz is Ownable {\n /**\n * @dev Emitted when the pause is triggered by the owner (`account`).\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by the owner (`account`).\n */\n event Unpaused(address account);\n\n bool internal _paused;\n\n constructor() internal {}\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n */\n modifier whenNotPaused() {\n require(!_paused, \"Pausable: paused\");\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n */\n modifier whenPaused() {\n require(_paused, \"Pausable: not paused\");\n _;\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/openzeppelin/ReentrancyGuard.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title Helps contracts guard against reentrancy attacks.\n * @author Remco Bloemen , Eenae \n * @dev If you mark a function `nonReentrant`, you should also\n * mark it `external`.\n */\ncontract ReentrancyGuard {\n /// @dev Constant for unlocked guard state - non-zero to prevent extra gas costs.\n /// See: https://github.com/OpenZeppelin/openzeppelin-solidity/issues/1056\n uint256 internal constant REENTRANCY_GUARD_FREE = 1;\n\n /// @dev Constant for locked guard state\n uint256 internal constant REENTRANCY_GUARD_LOCKED = 2;\n\n /**\n * @dev We use a single lock for the whole contract.\n */\n uint256 internal reentrancyLock = REENTRANCY_GUARD_FREE;\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * If you mark a function `nonReentrant`, you should also\n * mark it `external`. Calling one `nonReentrant` function from\n * another is not supported. Instead, you can implement a\n * `private` function doing the actual work, and an `external`\n * wrapper marked as `nonReentrant`.\n */\n modifier nonReentrant() {\n require(reentrancyLock == REENTRANCY_GUARD_FREE, \"nonReentrant\");\n reentrancyLock = REENTRANCY_GUARD_LOCKED;\n _;\n reentrancyLock = REENTRANCY_GUARD_FREE;\n }\n}\n" + }, + "contracts/openzeppelin/SafeERC20.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\nimport \"./SafeMath.sol\";\nimport \"./Address.sol\";\nimport \"../interfaces/IERC20.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n function safeTransfer(\n IERC20 token,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n }\n\n function safeTransferFrom(\n IERC20 token,\n address from,\n address to,\n uint256 value\n ) internal {\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.transferFrom.selector, from, to, value)\n );\n }\n\n function safeApprove(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n // safeApprove should only be called when setting an initial allowance,\n // or when resetting it to zero. To increase and decrease it, use\n // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n // solhint-disable-next-line max-line-length\n require(\n (value == 0) || (token.allowance(address(this), spender) == 0),\n \"SafeERC20: approve from non-zero to non-zero allowance\"\n );\n callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n }\n\n function safeIncreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance = token.allowance(address(this), spender).add(value);\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n function safeDecreaseAllowance(\n IERC20 token,\n address spender,\n uint256 value\n ) internal {\n uint256 newAllowance =\n token.allowance(address(this), spender).sub(\n value,\n \"SafeERC20: decreased allowance below zero\"\n );\n callOptionalReturn(\n token,\n abi.encodeWithSelector(token.approve.selector, spender, newAllowance)\n );\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n */\n function callOptionalReturn(IERC20 token, bytes memory data) private {\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n // we're implementing it ourselves.\n\n // A Solidity high level call has three parts:\n // 1. The target address is checked to verify it contains contract code\n // 2. The call itself is made, and success asserted\n // 3. The return value is decoded, which in turn checks the size of the returned data.\n // solhint-disable-next-line max-line-length\n require(address(token).isContract(), \"SafeERC20: call to non-contract\");\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, bytes memory returndata) = address(token).call(data);\n require(success, \"SafeERC20: low-level call failed\");\n\n if (returndata.length > 0) {\n // Return data is optional\n // solhint-disable-next-line max-line-length\n require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n }\n }\n}\n" + }, + "contracts/openzeppelin/SafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n require(c >= a, \"SafeMath: addition overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, \"SafeMath: subtraction overflow\");\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n * - Subtraction cannot overflow.\n *\n * _Available since v2.4.0._\n */\n function sub(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b <= a, errorMessage);\n uint256 c = a - b;\n\n return c;\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n * - Multiplication cannot overflow.\n */\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n uint256 c = a * b;\n require(c / a == b, \"SafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\n return div(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function div(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n uint256 c = a / b;\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n return c;\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\n return divCeil(a, b, \"SafeMath: division by zero\");\n }\n\n /**\n * @dev Integer division of two numbers, rounding up and truncating the quotient\n */\n function divCeil(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n // Solidity only automatically asserts when dividing by 0\n require(b != 0, errorMessage);\n\n if (a == 0) {\n return 0;\n }\n uint256 c = ((a - 1) / b) + 1;\n\n return c;\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n */\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n return mod(a, b, \"SafeMath: modulo by zero\");\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n * Reverts with custom message when dividing by zero.\n *\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\n * opcode (which leaves remaining gas untouched) while Solidity uses an\n * invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n * - The divisor cannot be zero.\n *\n * _Available since v2.4.0._\n */\n function mod(\n uint256 a,\n uint256 b,\n string memory errorMessage\n ) internal pure returns (uint256) {\n require(b != 0, errorMessage);\n return a % b;\n }\n\n function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\n return _a < _b ? _a : _b;\n }\n}\n" + }, + "contracts/openzeppelin/SignedSafeMath.sol": { + "content": "pragma solidity >=0.5.0 <0.6.0;\n\n/**\n * @title SignedSafeMath\n * @dev Signed math operations with safety checks that revert on error.\n */\nlibrary SignedSafeMath {\n int256 private constant _INT256_MIN = -2**255;\n\n /**\n * @dev Returns the multiplication of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `*` operator.\n *\n * Requirements:\n *\n * - Multiplication cannot overflow.\n */\n function mul(int256 a, int256 b) internal pure returns (int256) {\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n // benefit is lost if 'b' is also tested.\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n if (a == 0) {\n return 0;\n }\n\n require(!(a == -1 && b == _INT256_MIN), \"SignedSafeMath: multiplication overflow\");\n\n int256 c = a * b;\n require(c / a == b, \"SignedSafeMath: multiplication overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the integer division of two signed integers. Reverts on\n * division by zero. The result is rounded towards zero.\n *\n * Counterpart to Solidity's `/` operator. Note: this function uses a\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\n * uses an invalid opcode to revert (consuming all remaining gas).\n *\n * Requirements:\n *\n * - The divisor cannot be zero.\n */\n function div(int256 a, int256 b) internal pure returns (int256) {\n require(b != 0, \"SignedSafeMath: division by zero\");\n require(!(b == -1 && a == _INT256_MIN), \"SignedSafeMath: division overflow\");\n\n int256 c = a / b;\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a - b;\n require((b >= 0 && c <= a) || (b < 0 && c > a), \"SignedSafeMath: subtraction overflow\");\n\n return c;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a + b;\n require((b >= 0 && c >= a) || (b < 0 && c < a), \"SignedSafeMath: addition overflow\");\n\n return c;\n }\n}\n" + }, + "contracts/proxy/modules/interfaces/IFunctionsList.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\ninterface IFunctionsList {\n function getFunctionsList() external pure returns (bytes4[] memory functionSignatures);\n}\n" + }, + "contracts/proxy/modules/interfaces/IModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\n/**\n * ModulesProxyRegistry Interface\n */\n\ncontract IModulesProxyRegistry {\n event AddModule(address indexed moduleAddress);\n event ReplaceModule(address indexed oldAddress, address indexed newAddress);\n event RemoveModule(address indexed moduleAddress);\n event SetModuleFuncImplementation(\n bytes4 indexed _funcSig,\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use ReplaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external;\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl) external;\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external;\n\n /// @notice to disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external;\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external;\n\n /// @param _sig function signature to get impmementation address for\n /// @return function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address);\n\n /// @notice verifies if no functions from the module deployed already registered\n /// @param _impl module implementation address to verify\n /// @return true if module can be added\n function canAddModule(address _impl) external view returns (bool);\n\n /// @notice Multiple modules verification if no functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return True if all modules can be added, false otherwise\n function canNotAddModules(address[] calldata _implementations)\n external\n view\n returns (address[] memory modules);\n\n /// @notice used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n );\n}\n" + }, + "contracts/proxy/modules/ModulesProxy.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"./ModulesProxyRegistry.sol\";\n\n/**\n * ModulesProxy serves as a storage processed by a set of logic contracts - modules\n * Modules functions are registered in the contract's slots generated per func sig\n * All the function calls except for own Proxy functions are delegated to\n * the registered functions\n * The ModulesProxy is designed as a universal solution for refactorig contracts\n * reaching a 24K size limit (EIP-170)\n *\n * Upgradability is implemented at a module level to provide consistency\n * It does not allow to replace separate functions - only the whole module\n * meaning that if a module being registered contains other modules function signatures\n * then these modulea should be replaced completely - all the functions should be removed\n * to avoid leftovers or accidental replacements and therefore functional inconsistency.\n *\n * A module is either a new non-overlapping with registered modules\n * or a complete replacement of another registered module\n * in which case all the old module functions are unregistered and then\n * the new module functions are registered\n * There is also a separate function to unregister a module which unregisters all the functions\n * There is no option to unregister a subset of module functions - one should use pausable functionality\n * to achieve this\n */\n\ncontract ModulesProxy is ModulesProxyRegistry {\n // Uncomment for using beforeFallback() hook\n /*\n bytes private constant BEFORE_FALLBACK_SIG = abi.encodeWithSignature(\"beforeFallback()\");\n bytes4 private constant BEFORE_FALLBACK_SIG_BYTES4 = bytes4(keccak256(abi.encodePacked(\"beforeFallback()\")));\n */\n\n /**\n * @notice Fallback function delegates calls to modules.\n * Returns whatever the implementation call returns.\n * Has a hook to execute before delegating calls\n * To activate register a module with beforeFallback() function\n */\n function() external payable {\n /*\n // Commented to safe gas by default\n // Uncomment for using beforeFallback() hook \n // Implement and register beforeFallback() function in a module\n address beforeFallback = _getFuncImplementation(BEFORE_FALLBACK_SIG_BYTES4);\n if (beforeFallback != address(0)) {\n (bool success, ) = beforeFallback.delegatecall(bytes(0x39b0111a)); // abi.encodeWithSignature(\"beforeFallback()\")\n require(success, \"ModulesProxy::fallback: beforeFallback() fail\"); //MP02\n }\n */\n\n address target = _getFuncImplementation(msg.sig);\n require(target != address(0), \"ModulesProxy:target module not registered\"); // MP03\n\n bytes memory data = msg.data;\n assembly {\n let result := delegatecall(gas, target, add(data, 0x20), mload(data), 0, 0)\n let size := returndatasize\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, size)\n switch result\n case 0 {\n revert(ptr, size)\n }\n default {\n return(ptr, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/modules/ModulesProxyRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.5.17;\n\nimport \"../../utils/Utils.sol\";\nimport \"../../utils/ProxyOwnable.sol\";\nimport \"../modules/interfaces/IFunctionsList.sol\";\nimport \"../modules/interfaces/IModulesProxyRegistry.sol\";\nimport \"../../openzeppelin/Address.sol\";\n\n/**\n * ModulesProxyRegistry provides modules registration/removing/replacing functionality to ModulesProxy\n * Designed to be inherited\n */\n\ncontract ModulesProxyRegistry is IModulesProxyRegistry, ProxyOwnable {\n using Address for address;\n\n bytes32 internal constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n\n ///@notice Constructor is internal to make contract abstract\n constructor() internal {\n // abstract\n }\n\n /// @notice Add module functions.\n /// Overriding functions is not allowed. To replace modules use replaceModule function.\n /// @param _impl Module implementation address\n function addModule(address _impl) external onlyProxyOwner {\n _addModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function addModules(address[] calldata _implementations) external onlyProxyOwner {\n _addModules(_implementations);\n }\n\n /// @notice Replace module - remove the previous, add the new one\n /// @param _oldModuleImpl Module implementation address to remove\n /// @param _newModuleImpl Module implementation address to add\n function replaceModule(address _oldModuleImpl, address _newModuleImpl)\n external\n onlyProxyOwner\n {\n _replaceModule(_oldModuleImpl, _newModuleImpl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementationsFrom Modules to replace\n /// @param _implementationsTo Replacing modules\n function replaceModules(\n address[] calldata _implementationsFrom,\n address[] calldata _implementationsTo\n ) external onlyProxyOwner {\n require(\n _implementationsFrom.length == _implementationsTo.length,\n \"ModulesProxyRegistry::replaceModules: arrays sizes must be equal\"\n ); //MR10\n\n // because the order of addresses is arbitrary, all modules are removed first to avoid collisions\n _removeModules(_implementationsFrom);\n _addModules(_implementationsTo);\n }\n\n /// @notice To disable module - set all its functions implementation to address(0)\n /// @param _impl implementation address\n function removeModule(address _impl) external onlyProxyOwner {\n _removeModule(_impl);\n }\n\n /// @notice Add modules functions.\n /// @param _implementations Modules implementation addresses\n function removeModules(address[] calldata _implementations) external onlyProxyOwner {\n _removeModules(_implementations);\n }\n\n /// @param _sig Function signature to get impmementation address for\n /// @return Function's contract implelementation address\n function getFuncImplementation(bytes4 _sig) external view returns (address) {\n return _getFuncImplementation(_sig);\n }\n\n /// @notice Verifies if no functions from the module already registered\n /// @param _impl Module implementation address to verify\n /// @return True if module can be added\n function canAddModule(address _impl) external view returns (bool) {\n return _canAddModule(_impl);\n }\n\n /// @notice Multiple modules verification if there are functions from the modules already registered\n /// @param _implementations modules implementation addresses to verify\n /// @return addresses of registered modules\n function canNotAddModules(address[] memory _implementations)\n public\n view\n returns (address[] memory)\n {\n for (uint256 i = 0; i < _implementations.length; i++) {\n if (_canAddModule(_implementations[i])) {\n delete _implementations[i];\n }\n }\n return _implementations;\n }\n\n /// @notice Used externally to verify module being added for clashing\n /// @param _newModule module implementation which functions to verify\n /// @return Clashing functions signatures and corresponding modules (contracts) addresses\n function checkClashingFuncSelectors(address _newModule)\n external\n view\n returns (\n address[] memory clashingModules,\n bytes4[] memory clashingModulesFuncSelectors,\n bytes4[] memory clashingProxyRegistryFuncSelectors\n )\n {\n require(\n _newModule.isContract(),\n \"ModulesProxyRegistry::checkClashingFuncSelectors: address is not a contract\"\n ); //MR06\n bytes4[] memory newModuleFunctions = IFunctionsList(_newModule).getFunctionsList();\n bytes4[] memory proxyRegistryFunctions = _getFunctionsList(); //registry functions list\n uint256 clashingProxyRegistryFuncsSize;\n uint256 clashingArraySize;\n uint256 clashingArrayIndex;\n uint256 clashingRegistryArrayIndex;\n\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0) && funcImpl != _newModule) {\n clashingArraySize++;\n } else if (_isFuncClashingWithProxyFunctions(newModuleFunctions[i]))\n clashingProxyRegistryFuncsSize++;\n }\n clashingModules = new address[](clashingArraySize);\n clashingModulesFuncSelectors = new bytes4[](clashingArraySize);\n clashingProxyRegistryFuncSelectors = new bytes4[](clashingProxyRegistryFuncsSize);\n\n if (clashingArraySize == 0 && clashingProxyRegistryFuncsSize == 0)\n //return empty arrays\n return (\n clashingModules,\n clashingModulesFuncSelectors,\n clashingProxyRegistryFuncSelectors\n );\n for (uint256 i = 0; i < newModuleFunctions.length; i++) {\n address funcImpl = _getFuncImplementation(newModuleFunctions[i]);\n if (funcImpl != address(0)) {\n clashingModules[clashingArrayIndex] = funcImpl;\n clashingModulesFuncSelectors[clashingArrayIndex] = newModuleFunctions[i];\n clashingArrayIndex++;\n }\n for (uint256 j = 0; j < proxyRegistryFunctions.length; j++) {\n //ModulesProxyRegistry has a clashing function selector\n if (proxyRegistryFunctions[j] == newModuleFunctions[i]) {\n clashingProxyRegistryFuncSelectors[\n clashingRegistryArrayIndex\n ] = proxyRegistryFunctions[j];\n clashingRegistryArrayIndex++;\n }\n }\n }\n }\n\n /// Verifies the deployed contract address is a registered module contract\n /// @param _impl deployment address to verify\n /// @return true if _impl address is a registered module\n function isModuleRegistered(address _impl) external view returns (bool) {\n return _getFirstRegisteredModuleAddress(_impl) == _impl;\n }\n\n /****************** INTERNAL FUNCTIONS ******************/\n\n function _getFirstRegisteredModuleAddress(address _impl) internal view returns (address) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_getRegisteredModuleAddress: address is not a contract\"\n );\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n address _moduleImpl = _getFuncImplementation(functions[i]);\n if (_moduleImpl != address(0)) {\n return (_moduleImpl);\n }\n }\n return address(0);\n }\n\n function _getFuncImplementation(bytes4 _sig) internal view returns (address) {\n //TODO: add querying Registry for logic address and then delegate call to it OR use proxy memory slots like this:\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n address implementation;\n assembly {\n implementation := sload(key)\n }\n return implementation;\n }\n\n function _addModule(address _impl) internal {\n require(_impl.isContract(), \"ModulesProxyRegistry::_addModule: address is not a contract\"); //MR01\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++) {\n require(\n _getFuncImplementation(functions[i]) == address(0),\n \"ModulesProxyRegistry::_addModule: function already registered - use replaceModule function\"\n ); //MR02\n require(functions[i] != bytes4(0), \"does not allow empty function id\"); // MR03\n require(\n !_isFuncClashingWithProxyFunctions(functions[i]),\n \"ModulesProxyRegistry::_addModule: has a function with the same signature\"\n ); //MR09\n _setModuleFuncImplementation(functions[i], _impl);\n }\n emit AddModule(_impl);\n }\n\n function _addModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _addModule(_implementations[i]);\n }\n }\n\n function _removeModule(address _impl) internal onlyProxyOwner {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_removeModule: address is not a contract\"\n ); //MR07\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n _setModuleFuncImplementation(functions[i], address(0));\n\n emit RemoveModule(_impl);\n }\n\n function _removeModules(address[] memory _implementations) internal {\n for (uint256 i = 0; i < _implementations.length; i++) {\n _removeModule(_implementations[i]);\n }\n }\n\n function _replaceModule(address _oldModuleImpl, address _newModuleImpl) internal {\n if (_oldModuleImpl != _newModuleImpl) {\n require(\n _newModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _newModuleImpl is not a contract\"\n ); //MR03\n require(\n _oldModuleImpl.isContract(),\n \"ModulesProxyRegistry::_replaceModule - _oldModuleImpl is not a contract\"\n ); //MR04\n _removeModule(_oldModuleImpl);\n _addModule(_newModuleImpl);\n\n emit ReplaceModule(_oldModuleImpl, _newModuleImpl);\n }\n }\n\n function _setModuleFuncImplementation(bytes4 _sig, address _impl) internal {\n emit SetModuleFuncImplementation(_sig, _getFuncImplementation(_sig), _impl);\n\n bytes32 key = keccak256(abi.encode(_sig, KEY_IMPLEMENTATION));\n assembly {\n sstore(key, _impl)\n }\n }\n\n function _isFuncClashingWithProxyFunctions(bytes4 _sig) internal pure returns (bool) {\n bytes4[] memory functionList = _getFunctionsList();\n for (uint256 i = 0; i < functionList.length; i++) {\n if (_sig == functionList[i])\n //ModulesProxyRegistry has function with the same id\n return true;\n }\n return false;\n }\n\n function _canAddModule(address _impl) internal view returns (bool) {\n require(\n _impl.isContract(),\n \"ModulesProxyRegistry::_canAddModule: address is not a contract\"\n ); //MR06\n bytes4[] memory functions = IFunctionsList(_impl).getFunctionsList();\n for (uint256 i = 0; i < functions.length; i++)\n if (_getFuncImplementation(functions[i]) != address(0)) return (false);\n return true;\n }\n\n function _getFunctionsList() internal pure returns (bytes4[] memory) {\n bytes4[] memory functionList = new bytes4[](13);\n functionList[0] = this.getFuncImplementation.selector;\n functionList[1] = this.addModule.selector;\n functionList[2] = this.addModules.selector;\n functionList[3] = this.removeModule.selector;\n functionList[4] = this.removeModules.selector;\n functionList[5] = this.replaceModule.selector;\n functionList[6] = this.replaceModules.selector;\n functionList[7] = this.canAddModule.selector;\n functionList[8] = this.canNotAddModules.selector;\n functionList[9] = this.setProxyOwner.selector;\n functionList[10] = this.getProxyOwner.selector;\n functionList[11] = this.checkClashingFuncSelectors.selector;\n functionList[12] = this.isModuleRegistered.selector;\n return functionList;\n }\n}\n" + }, + "contracts/proxy/Proxy.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Base Proxy contract.\n * @notice The proxy performs delegated calls to the contract implementation\n * it is pointing to. This way upgradable contracts are possible on blockchain.\n *\n * Delegating proxy contracts are widely used for both upgradeability and gas\n * savings. These proxies rely on a logic contract (also known as implementation\n * contract or master copy) that is called using delegatecall. This allows\n * proxies to keep a persistent state (storage and balance) while the code is\n * delegated to the logic contract.\n *\n * Proxy contract is meant to be inherited and its internal functions\n * _setImplementation and _setProxyOwner to be called when upgrades become\n * neccessary.\n *\n * The loan token (iToken) contract as well as the protocol contract act as\n * proxies, delegating all calls to underlying contracts. Therefore, if you\n * want to interact with them using web3, you need to use the ABIs from the\n * contracts containing the actual logic or the interface contract.\n * ABI for LoanToken contracts: LoanTokenLogicStandard\n * ABI for Protocol contract: ISovryn\n *\n * @dev UpgradableProxy is the contract that inherits Proxy and wraps these\n * functions.\n * */\ncontract Proxy {\n bytes32 private constant KEY_IMPLEMENTATION = keccak256(\"key.implementation\");\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);\n event ImplementationChanged(\n address indexed _oldImplementation,\n address indexed _newImplementation\n );\n\n /**\n * @notice Set sender as an owner.\n * */\n constructor() public {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @notice Throw error if called not by an owner.\n * */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Proxy:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the implementation.\n * @param _implementation Address of the implementation.\n * */\n function _setImplementation(address _implementation) internal {\n require(_implementation != address(0), \"Proxy::setImplementation: invalid address\");\n emit ImplementationChanged(getImplementation(), _implementation);\n\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n sstore(key, _implementation)\n }\n }\n\n /**\n * @notice Return address of the implementation.\n * @return Address of the implementation.\n * */\n function getImplementation() public view returns (address _implementation) {\n bytes32 key = KEY_IMPLEMENTATION;\n assembly {\n _implementation := sload(key)\n }\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"Proxy::setProxyOwner: invalid address\");\n emit OwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Return address of the owner.\n * @return Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n\n /**\n * @notice Fallback function performs a delegate call\n * to the actual implementation address is pointing this proxy.\n * Returns whatever the implementation call returns.\n * */\n function() external payable {\n address implementation = getImplementation();\n require(implementation != address(0), \"Proxy::(): implementation not found\");\n\n assembly {\n let pointer := mload(0x40)\n calldatacopy(pointer, 0, calldatasize)\n let result := delegatecall(gas, implementation, pointer, calldatasize, 0, 0)\n let size := returndatasize\n returndatacopy(pointer, 0, size)\n\n switch result\n case 0 {\n revert(pointer, size)\n }\n default {\n return(pointer, size)\n }\n }\n }\n}\n" + }, + "contracts/proxy/UpgradableProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Proxy.sol\";\n\n/**\n * @title Upgradable Proxy contract.\n * @notice A disadvantage of the immutable ledger is that nobody can change the\n * source code of a smart contract after it’s been deployed. In order to fix\n * bugs or introduce new features, smart contracts need to be upgradable somehow.\n *\n * Although it is not possible to upgrade the code of an already deployed smart\n * contract, it is possible to set-up a proxy contract architecture that will\n * allow to use new deployed contracts as if the main logic had been upgraded.\n *\n * A proxy architecture pattern is such that all message calls go through a\n * Proxy contract that will redirect them to the latest deployed contract logic.\n * To upgrade, a new version of the contract is deployed, and the Proxy is\n * updated to reference the new contract address.\n * */\ncontract UpgradableProxy is Proxy {\n /**\n * @notice Set address of the implementation.\n * @dev Wrapper for _setImplementation that exposes the function\n * as public for owner to be able to set a new version of the\n * contract as current pointing implementation.\n * @param _implementation Address of the implementation.\n * */\n function setImplementation(address _implementation) public onlyProxyOwner {\n _setImplementation(_implementation);\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n}\n" + }, + "contracts/reentrancy/Mutex.sol": { + "content": "pragma solidity ^0.5.17;\n\n/*\n * @title Global Mutex contract\n *\n * @notice A mutex contract that allows only one function to be called at a time out\n * of a large set of functions. *Anyone* in the network can freely use any instance\n * of this contract to add a universal mutex to any function in any contract.\n */\ncontract Mutex {\n /*\n * We use an uint to store the mutex state.\n */\n uint256 public value;\n\n /*\n * @notice Increment the mutex state and return the new value.\n *\n * @dev This is the function that will be called by anyone to change the mutex\n * state. It is purposely not protected by any access control\n */\n function incrementAndGetValue() external returns (uint256) {\n /*\n * increment value using unsafe math. This is safe because we are\n * pretty certain no one will ever increment the value 2^256 times\n * in a single transaction.\n */\n return ++value;\n }\n}\n" + }, + "contracts/reentrancy/SharedReentrancyGuard.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"./Mutex.sol\";\n\n/*\n * @title Abstract contract for shared reentrancy guards\n *\n * @notice Exposes a single modifier `globallyNonReentrant` that can be used to ensure\n * that there's no reentrancy between *any* functions marked with the modifier.\n *\n * @dev The Mutex contract address is hardcoded because the address is deployed using a\n * special deployment method (similar to ERC1820Registry). This contract therefore has no\n * state and is thus safe to add to the inheritance chain of upgradeable contracts.\n */\ncontract SharedReentrancyGuard {\n /*\n * This is the address of the mutex contract that will be used as the\n * reentrancy guard.\n *\n * The address is hardcoded to avoid changing the memory layout of\n * derived contracts (possibly upgradable). Hardcoding the address is possible,\n * because the Mutex contract is always deployed to the same address, with the\n * same method used in the deployment of ERC1820Registry.\n */\n Mutex private constant MUTEX = Mutex(0xba10edD6ABC7696Eae685839217BdcC42139612b);\n\n /*\n * This is the modifier that will be used to protect functions from\n * reentrancy. It will call the mutex contract to increment the mutex\n * state and then revert if the mutex state was changed by another\n * nested call.\n */\n modifier globallyNonReentrant() {\n uint256 previous = MUTEX.incrementAndGetValue();\n\n _;\n\n /*\n * If the mutex state was changed by a nested function call, then\n * the value of the state variable will be different from the previous value.\n */\n require(previous == MUTEX.value(), \"reentrancy violation\");\n }\n}\n" + }, + "contracts/rsk/RSKAddrValidator.sol": { + "content": "// SPDX-License-Identifier:MIT\npragma solidity ^0.5.17;\n\nlibrary RSKAddrValidator {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n * */\n function checkPKNotZero(address addr) internal pure returns (bool) {\n return (addr != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 && addr != address(0));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key.\n * */\n function safeEquals(address addr1, address addr2) internal pure returns (bool) {\n return (addr1 == addr2 &&\n addr1 != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\n addr1 != address(0));\n }\n}\n" + }, + "contracts/swaps/connectors/interfaces/IContractRegistry.sol": { + "content": "pragma solidity 0.5.17;\n\ncontract IContractRegistry {\n function addressOf(bytes32 contractName) public view returns (address);\n}\n" + }, + "contracts/swaps/connectors/interfaces/ISovrynSwapNetwork.sol": { + "content": "pragma solidity >=0.5.8 <=0.5.17;\n\nimport \"../../../interfaces/IERC20.sol\";\n\ncontract ISovrynSwapNetwork {\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256);\n\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256);\n\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory);\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwap.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../../core/State.sol\";\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\n\n/**\n * @dev WARNING: This contract is deprecated, all public functions are moved to the protocol modules.\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\ncontract SwapsImplSovrynSwap is State {\n using SafeERC20 for IERC20;\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n constructor() internal {\n // abstract\n }\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destination tokens.\n * @param receiverAddress The address who will received the swap token results\n * @param returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * @param minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * @param maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address receiverAddress,\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n require(\n supportedTokens[sourceTokenAddress] && supportedTokens[destTokenAddress],\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = estimateSourceTokenAmount(\n sourceTokenAddress,\n destTokenAddress,\n requiredDestTokenAmount,\n maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n allowTransfer(sourceTokenAmountUsed, sourceTokenAddress, address(sovrynSwapNetwork));\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n uint256 sourceToDestPrecision =\n IPriceFeeds(priceFeeds).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n internalExpectedRate(\n sourceTokenAddress,\n destTokenAddress,\n maxSourceTokenAmount,\n sovrynSwapContractRegistryAddress\n );\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > sourceBuffer) buffer = sourceBuffer;\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistryAddress\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistryAddress);\n\n IERC20[] memory path =\n getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * @param sovrynSwapContractRegistry The sovryn swap contract reigstry address.\n * @param defaultPath The default path for specific pairs.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address sovrynSwapContractRegistry,\n IERC20[] memory defaultPath\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(sovrynSwapContractRegistry);\n\n IERC20[] memory path =\n defaultPath.length >= 3\n ? defaultPath\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n defaultPathConversion[sourceTokenAddress][destTokenAddress];\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/SwapsImplSovrynSwapLib.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../../feeds/IPriceFeeds.sol\";\nimport \"../../openzeppelin/SafeERC20.sol\";\nimport \"./interfaces/ISovrynSwapNetwork.sol\";\nimport \"./interfaces/IContractRegistry.sol\";\nimport \"../../interfaces/ISovryn.sol\";\n\n/**\n * @title Swaps Implementation Sovryn contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate\n * calculations for Sovryn network.\n * */\nlibrary SwapsImplSovrynSwapLib {\n using SafeMath for uint256;\n using SafeERC20 for IERC20;\n\n struct SwapParams {\n address sourceTokenAddress;\n address destTokenAddress;\n address receiverAddress;\n address returnToSenderAddress;\n uint256 minSourceTokenAmount;\n uint256 maxSourceTokenAmount;\n uint256 requiredDestTokenAmount;\n }\n\n /// bytes32 contractName = hex\"42616e636f724e6574776f726b\"; /// \"SovrynSwapNetwork\"\n\n /**\n * Get the hex name of a contract.\n * @param source The name of the contract.\n * */\n function getContractHexName(string memory source) public pure returns (bytes32 result) {\n assembly {\n result := mload(add(source, 32))\n }\n }\n\n /**\n * Look up the Sovryn swap network contract registered at the given address.\n * @param sovrynSwapRegistryAddress The address of the registry.\n * */\n function getSovrynSwapNetworkContract(address sovrynSwapRegistryAddress)\n public\n view\n returns (ISovrynSwapNetwork)\n {\n /// State variable sovrynSwapContractRegistryAddress is part of\n /// State.sol and set in ProtocolSettings.sol and this function\n /// needs to work without delegate call as well -> therefore pass it.\n IContractRegistry contractRegistry = IContractRegistry(sovrynSwapRegistryAddress);\n return\n ISovrynSwapNetwork(\n contractRegistry.addressOf(getContractHexName(\"SovrynSwapNetwork\"))\n );\n }\n\n /**\n * Swap the source token for the destination token on the oracle based AMM.\n * On loan opening: minSourceTokenAmount = maxSourceTokenAmount and requiredDestTokenAmount = 0\n * -> swap the minSourceTokenAmount\n * On loan rollover: (swap interest) minSourceTokenAmount = 0, maxSourceTokenAmount = complete collateral and requiredDestTokenAmount > 0\n * -> amount of required source tokens to swap is estimated (want to fill requiredDestTokenAmount, not more). maxSourceTokenAMount is not exceeded.\n * On loan closure: minSourceTokenAmount <= maxSourceTokenAmount and requiredDestTokenAmount >= 0\n * -> same as on rollover. minimum amount is not considered at all.\n *\n * @param params SwapParams struct\n * sourceTokenAddress The address of the source tokens.\n * destTokenAddress The address of the destination tokens.\n * receiverAddress The address who will received the swap token results\n * returnToSenderAddress The address to return unspent tokens to (when called by the protocol, it's always the protocol contract).\n * minSourceTokenAmount The minimum amount of source tokens to swapped (only considered if requiredDestTokens == 0).\n * maxSourceTokenAmount The maximum amount of source tokens to swapped.\n * requiredDestTokenAmount The required amount of destination tokens.\n * */\n function swap(SwapParams memory params)\n public\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n require(params.sourceTokenAddress != params.destTokenAddress, \"source == dest\");\n\n ISovryn iSovryn = ISovryn(address(this));\n require(\n iSovryn.supportedTokens(params.sourceTokenAddress) &&\n iSovryn.supportedTokens(params.destTokenAddress),\n \"invalid tokens\"\n );\n\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(iSovryn.sovrynSwapContractRegistryAddress());\n\n IERC20[] memory path =\n _getConversionPath(\n params.sourceTokenAddress,\n params.destTokenAddress,\n sovrynSwapNetwork\n );\n\n uint256 minReturn = 1;\n sourceTokenAmountUsed = params.minSourceTokenAmount;\n\n /// If the required amount of destination tokens is passed, we need to\n /// calculate the estimated amount of source tokens regardless of the\n /// minimum source token amount (name is misleading).\n if (params.requiredDestTokenAmount > 0) {\n sourceTokenAmountUsed = _estimateSourceTokenAmount(\n params.sourceTokenAddress,\n params.destTokenAddress,\n params.requiredDestTokenAmount,\n params.maxSourceTokenAmount\n );\n /// sovrynSwapNetwork.rateByPath does not return a rate, but instead the amount of destination tokens returned.\n require(\n sovrynSwapNetwork.rateByPath(path, sourceTokenAmountUsed) >=\n params.requiredDestTokenAmount,\n \"insufficient source tokens provided.\"\n );\n minReturn = params.requiredDestTokenAmount;\n }\n\n require(sourceTokenAmountUsed > 0, \"cannot swap 0 tokens\");\n\n _allowTransfer(\n sourceTokenAmountUsed,\n params.sourceTokenAddress,\n address(sovrynSwapNetwork)\n );\n\n /// @dev Note: the kyber connector uses .call() to interact with kyber\n /// to avoid bubbling up. here we allow bubbling up.\n destTokenAmountReceived = sovrynSwapNetwork.convertByPath(\n path,\n sourceTokenAmountUsed,\n minReturn,\n params.receiverAddress,\n address(0),\n 0\n );\n\n /// If the sender is not the protocol (calling with delegatecall),\n /// return the remainder to the specified address.\n /// @dev Note: for the case that the swap is used without the\n /// protocol. Not sure if it should, though. needs to be discussed.\n if (params.returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < params.maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(params.sourceTokenAddress).safeTransfer(\n params.returnToSenderAddress,\n params.maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Check whether the existing allowance suffices to transfer\n * the needed amount of tokens.\n * If not, allows the transfer of an arbitrary amount of tokens.\n *\n * @param tokenAmount The amount to transfer.\n * @param tokenAddress The address of the token to transfer.\n * @param sovrynSwapNetwork The address of the sovrynSwap network contract.\n * */\n function _allowTransfer(\n uint256 tokenAmount,\n address tokenAddress,\n address sovrynSwapNetwork\n ) internal {\n uint256 tempAllowance = IERC20(tokenAddress).allowance(address(this), sovrynSwapNetwork);\n if (tempAllowance < tokenAmount) {\n IERC20(tokenAddress).safeApprove(sovrynSwapNetwork, uint256(-1));\n }\n }\n\n /**\n * @notice Calculate the number of source tokens to provide in order to\n * obtain the required destination amount.\n *\n * @param sourceTokenAddress The address of the source token address.\n * @param destTokenAddress The address of the destination token address.\n * @param requiredDestTokenAmount The number of destination tokens needed.\n * @param maxSourceTokenAmount The maximum number of source tokens to spend.\n *\n * @return The estimated amount of source tokens needed.\n * Minimum: minSourceTokenAmount, maximum: maxSourceTokenAmount\n * */\n function _estimateSourceTokenAmount(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 requiredDestTokenAmount,\n uint256 maxSourceTokenAmount\n ) internal view returns (uint256 estimatedSourceAmount) {\n ISovryn iSovryn = ISovryn(address(this));\n uint256 sourceToDestPrecision =\n IPriceFeeds(iSovryn.priceFeeds()).queryPrecision(sourceTokenAddress, destTokenAddress);\n if (sourceToDestPrecision == 0) return maxSourceTokenAmount;\n\n /// Compute the expected rate for the maxSourceTokenAmount -> if spending less, we can't get a worse rate.\n uint256 expectedRate =\n getExpectedRate(sourceTokenAddress, destTokenAddress, maxSourceTokenAmount);\n\n /// Compute the source tokens needed to get the required amount with the worst case rate.\n estimatedSourceAmount = requiredDestTokenAmount.mul(sourceToDestPrecision).div(\n expectedRate\n );\n\n /// If the actual rate is exactly the same as the worst case rate, we get rounding issues. So, add a small buffer.\n /// buffer = min(estimatedSourceAmount/1000 , sourceBuffer) with sourceBuffer = 10000\n uint256 buffer = estimatedSourceAmount.div(1000);\n if (buffer > iSovryn.sourceBuffer()) buffer = iSovryn.sourceBuffer();\n estimatedSourceAmount = estimatedSourceAmount.add(buffer);\n\n /// Never spend more than the maximum.\n if (estimatedSourceAmount == 0 || estimatedSourceAmount > maxSourceTokenAmount)\n return maxSourceTokenAmount;\n }\n\n /**\n * @notice Get the expected rate for 1 source token when exchanging the\n * given amount of source tokens.\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the rate for.\n * */\n function getExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n uint256 expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n\n /// Return the rate for 1 token with 18 decimals.\n return expectedReturn.mul(10**18).div(sourceTokenAmount);\n }\n\n /**\n * @notice Get the expected return amount when exchanging the given\n * amount of source tokens.\n *\n * @notice Right now, this function is being called directly by _swapsExpectedReturn from the protocol\n * So, this function is not using _getConversionPath function since it will try to read the defaultPath storage which is stored in the protocol's slot, and it will cause an issue for direct call.\n * Instead, this function is accepting additional parameters called defaultPath which value can be declared by the caller (protocol in this case).\n *\n * @param sourceTokenAddress The address of the source token contract.\n * @param destTokenAddress The address of the destination token contract.\n * @param sourceTokenAmount The amount of source tokens to get the return for.\n * */\n function getExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount\n ) public view returns (uint256 expectedReturn) {\n ISovrynSwapNetwork sovrynSwapNetwork =\n getSovrynSwapNetworkContract(\n ISovryn(address(this)).sovrynSwapContractRegistryAddress()\n );\n\n IERC20[] memory path =\n _getConversionPath(sourceTokenAddress, destTokenAddress, sovrynSwapNetwork);\n\n /// Is returning the total amount of destination tokens.\n expectedReturn = sovrynSwapNetwork.rateByPath(path, sourceTokenAmount);\n }\n\n function _getConversionPath(\n address sourceTokenAddress,\n address destTokenAddress,\n ISovrynSwapNetwork sovrynSwapNetwork\n ) private view returns (IERC20[] memory path) {\n IERC20[] memory _defaultPathConversion =\n ISovryn(address(this)).getDefaultPathConversion(sourceTokenAddress, destTokenAddress);\n\n /// will use the defaultPath if it's set, otherwise query from the SovrynSwapNetwork.\n path = _defaultPathConversion.length >= 3\n ? _defaultPathConversion\n : sovrynSwapNetwork.conversionPath(\n IERC20(sourceTokenAddress),\n IERC20(destTokenAddress)\n );\n }\n}\n" + }, + "contracts/swaps/connectors/testnet/SwapsImplLocal.sol": { + "content": "/**\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../../../core/State.sol\";\nimport \"../../../openzeppelin/SafeERC20.sol\";\nimport \"../../../feeds/IPriceFeeds.sol\";\nimport \"../../../testhelpers/TestToken.sol\";\n\n/**\n * @title Swaps Implementation Local contract.\n *\n * @notice This contract code comes from bZx. bZx is a protocol for tokenized\n * margin trading and lending https://bzx.network similar to the dYdX protocol.\n *\n * This contract contains the implementation of swap process and rate calculations.\n * */\ncontract SwapsImplLocal is State {\n using SafeERC20 for IERC20;\n\n /**\n * @notice Swap two tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n *\n * @return destTokenAmountReceived The amount of destiny tokens sent.\n * @return sourceTokenAmountUsed The amount of source tokens spent.\n * */\n function internalSwap(\n address sourceTokenAddress,\n address destTokenAddress,\n address, /*receiverAddress*/\n address returnToSenderAddress,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount\n ) public payable returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed) {\n require(sourceTokenAddress != destTokenAddress, \"source == dest\");\n\n (uint256 tradeRate, uint256 precision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n if (requiredDestTokenAmount == 0) {\n sourceTokenAmountUsed = minSourceTokenAmount;\n destTokenAmountReceived = minSourceTokenAmount.mul(tradeRate).div(precision);\n } else {\n destTokenAmountReceived = requiredDestTokenAmount;\n sourceTokenAmountUsed = requiredDestTokenAmount.mul(precision).div(tradeRate);\n require(sourceTokenAmountUsed <= minSourceTokenAmount, \"destAmount too great\");\n }\n\n TestToken(sourceTokenAddress).burn(address(this), sourceTokenAmountUsed);\n TestToken(destTokenAddress).mint(address(this), destTokenAmountReceived);\n\n if (returnToSenderAddress != address(this)) {\n if (sourceTokenAmountUsed < maxSourceTokenAmount) {\n /// Send unused source token back.\n IERC20(sourceTokenAddress).safeTransfer(\n returnToSenderAddress,\n maxSourceTokenAmount - sourceTokenAmountUsed\n );\n }\n }\n }\n\n /**\n * @notice Calculate the expected price rate of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n *\n * @return precision The expected price rate.\n * */\n function internalExpectedRate(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * @notice Calculate the expected return of swapping a given amount\n * of tokens.\n *\n * @param sourceTokenAddress The address of the source tokens.\n * @param destTokenAddress The address of the destiny tokens.\n * @param sourceTokenAmount The amount of source tokens.\n * @param unused Fourth parameter ignored.\n * @param defaultPath defaultPath for swap.\n *\n * @return precision The expected return.\n * */\n function internalExpectedReturn(\n address sourceTokenAddress,\n address destTokenAddress,\n uint256 sourceTokenAmount,\n address unused,\n IERC20[] memory defaultPath\n ) public view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(sourceTokenAddress, destTokenAddress);\n\n return sourceTokenAmount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n}\n" + }, + "contracts/swaps/SwapsUser.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC . All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../core/State.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"../events/SwapsEvents.sol\";\nimport \"../mixins/FeesHelper.sol\";\nimport \"./connectors/SwapsImplSovrynSwapLib.sol\";\n\n/**\n * @title Perform token swaps for loans and trades.\n * */\ncontract SwapsUser is State, SwapsEvents, FeesHelper {\n /**\n * @notice Internal loan swap.\n *\n * @param loanId The ID of the loan.\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of destination tokens.\n * @param user The user address.\n * @param minSourceTokenAmount The minimum amount of source tokens to swap.\n * @param maxSourceTokenAmount The maximum amount of source tokens to swap.\n * @param requiredDestTokenAmount The required amount of destination tokens.\n * @param bypassFee To bypass or not the fee.\n * @param loanDataBytes The payload for the call. These loan DataBytes are\n * additional loan data (not in use for token swaps).\n *\n * @return destTokenAmountReceived\n * @return sourceTokenAmountUsed\n * @return sourceToDestSwapRate\n * */\n function _loanSwap(\n bytes32 loanId,\n address sourceToken,\n address destToken,\n address user,\n uint256 minSourceTokenAmount,\n uint256 maxSourceTokenAmount,\n uint256 requiredDestTokenAmount,\n bool bypassFee,\n bytes memory loanDataBytes\n )\n internal\n returns (\n uint256 destTokenAmountReceived,\n uint256 sourceTokenAmountUsed,\n uint256 sourceToDestSwapRate\n )\n {\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall(\n [\n sourceToken,\n destToken,\n address(this), // receiver\n address(this), // returnToSender\n user\n ],\n [minSourceTokenAmount, maxSourceTokenAmount, requiredDestTokenAmount],\n loanId,\n bypassFee,\n loanDataBytes,\n false // swap external flag, set to false so that it will use the tradingFeePercent\n );\n\n /// Will revert if swap size too large.\n _checkSwapSize(sourceToken, sourceTokenAmountUsed);\n\n /// Will revert if disagreement found.\n sourceToDestSwapRate = IPriceFeeds(priceFeeds).checkPriceDisagreement(\n sourceToken,\n destToken,\n sourceTokenAmountUsed,\n destTokenAmountReceived,\n maxDisagreement\n );\n\n emit LoanSwap(\n loanId,\n sourceToken,\n destToken,\n user,\n sourceTokenAmountUsed,\n destTokenAmountReceived\n );\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Wrapper for _swapsCall_internal function.\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n * @param loanId The Id of the associated loan.\n * @param miscBool True/false to bypassFee.\n * @param loanDataBytes Additional loan data (not in use yet).\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall(\n address[5] memory addrs,\n uint256[3] memory vals,\n bytes32 loanId,\n bool miscBool, /// bypassFee\n bytes memory loanDataBytes,\n bool isSwapExternal\n ) internal returns (uint256, uint256) {\n /// addrs[0]: sourceToken\n /// addrs[1]: destToken\n /// addrs[2]: receiver\n /// addrs[3]: returnToSender\n /// addrs[4]: user\n /// vals[0]: minSourceTokenAmount\n /// vals[1]: maxSourceTokenAmount\n /// vals[2]: requiredDestTokenAmount\n\n require(vals[0] != 0 || vals[1] != 0, \"min or max source token amount needs to be set\");\n\n if (vals[1] == 0) {\n vals[1] = vals[0];\n }\n require(vals[0] <= vals[1], \"sourceAmount larger than max\");\n\n uint256 destTokenAmountReceived;\n uint256 sourceTokenAmountUsed;\n\n uint256 tradingFee;\n if (!miscBool) {\n /// bypassFee\n if (vals[2] == 0) {\n /// condition: vals[0] will always be used as sourceAmount\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[0]);\n } else {\n tradingFee = _getTradingFee(vals[0]);\n }\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId,\n addrs[0], /// sourceToken (feeToken)\n addrs[1], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n vals[0] = vals[0].sub(tradingFee);\n }\n } else {\n /// Condition: unknown sourceAmount will be used.\n\n if (isSwapExternal) {\n tradingFee = _getSwapExternalFee(vals[2]);\n } else {\n tradingFee = _getTradingFee(vals[2]);\n }\n\n if (tradingFee != 0) {\n vals[2] = vals[2].add(tradingFee);\n }\n }\n }\n\n require(loanDataBytes.length == 0, \"invalid state\");\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = _swapsCall_internal(addrs, vals);\n\n if (vals[2] == 0) {\n /// There's no minimum destTokenAmount, but all of vals[0]\n /// (minSourceTokenAmount) must be spent.\n require(sourceTokenAmountUsed == vals[0], \"swap too large to fill\");\n\n if (tradingFee != 0) {\n sourceTokenAmountUsed = sourceTokenAmountUsed.add(tradingFee);\n }\n } else {\n /// There's a minimum destTokenAmount required, but\n /// sourceTokenAmountUsed won't be greater\n /// than vals[1] (maxSourceTokenAmount)\n require(sourceTokenAmountUsed <= vals[1], \"swap fill too large\");\n require(destTokenAmountReceived >= vals[2], \"insufficient swap liquidity\");\n\n if (tradingFee != 0) {\n _payTradingFee(\n addrs[4], /// user\n loanId, /// loanId,\n addrs[1], /// destToken (feeToken)\n addrs[0], /// pairToken (used to check if there is any special rebates or not) -- to pay fee reward\n tradingFee\n );\n\n destTokenAmountReceived = destTokenAmountReceived.sub(tradingFee);\n }\n }\n\n return (destTokenAmountReceived, sourceTokenAmountUsed);\n }\n\n /**\n * @notice Calculate amount of source and destination tokens.\n *\n * @dev Calls swapsImpl::internalSwap\n *\n * @param addrs The array of addresses.\n * @param vals The array of values.\n *\n * @return destTokenAmountReceived The amount of destination tokens received.\n * @return sourceTokenAmountUsed The amount of source tokens used.\n * */\n function _swapsCall_internal(address[5] memory addrs, uint256[3] memory vals)\n internal\n returns (uint256 destTokenAmountReceived, uint256 sourceTokenAmountUsed)\n {\n SwapsImplSovrynSwapLib.SwapParams memory swapParams;\n\n swapParams.sourceTokenAddress = addrs[0];\n swapParams.destTokenAddress = addrs[1];\n swapParams.receiverAddress = addrs[2];\n swapParams.returnToSenderAddress = addrs[3];\n swapParams.minSourceTokenAmount = vals[0];\n swapParams.maxSourceTokenAmount = vals[1];\n swapParams.requiredDestTokenAmount = vals[2];\n\n (destTokenAmountReceived, sourceTokenAmountUsed) = SwapsImplSovrynSwapLib.swap(swapParams);\n }\n\n /**\n * @notice Calculate expected amount of destination tokens.\n *\n * @dev Calls swapsImpl::internalExpectedReturn\n *\n * @param sourceToken The address of the source tokens.\n * @param destToken The address of the destination tokens.\n * @param sourceTokenAmount The amount of the source tokens.\n *\n * @param destTokenAmount The amount of destination tokens.\n * */\n function _swapsExpectedReturn(\n address sourceToken,\n address destToken,\n uint256 sourceTokenAmount\n ) internal view returns (uint256 destTokenAmount) {\n destTokenAmount = SwapsImplSovrynSwapLib.getExpectedReturn(\n sourceToken,\n destToken,\n sourceTokenAmount\n );\n }\n\n /**\n * @notice Verify that the amount of tokens are under the swap limit.\n *\n * @dev Calls priceFeeds::amountInEth\n *\n * @param tokenAddress The address of the token to calculate price.\n * @param amount The amount of tokens to calculate price.\n * */\n function _checkSwapSize(address tokenAddress, uint256 amount) internal view {\n uint256 _maxSwapSize = maxSwapSize;\n if (_maxSwapSize != 0) {\n uint256 amountInEth;\n if (tokenAddress == address(wrbtcToken)) {\n amountInEth = amount;\n } else {\n amountInEth = IPriceFeeds(priceFeeds).amountInEth(tokenAddress, amount);\n }\n require(amountInEth <= _maxSwapSize, \"swap too large\");\n }\n }\n}\n" + }, + "contracts/testhelpers/FlashLoanerTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n// \"SPDX-License-Identifier: Apache-2.0\"\n\nimport \"../interfaces/IERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./ITokenFlashLoanTest.sol\";\n\ncontract FlashLoanerTest is Ownable {\n function initiateFlashLoanTest(\n address loanToken,\n address iToken,\n uint256 flashLoanAmount\n ) internal returns (bytes memory success) {\n ITokenFlashLoanTest iTokenContract = ITokenFlashLoanTest(iToken);\n return\n iTokenContract.flashBorrow(\n flashLoanAmount,\n address(this),\n address(this),\n \"\",\n abi.encodeWithSignature(\n \"executeOperation(address,address,uint256)\",\n loanToken,\n iToken,\n flashLoanAmount\n )\n );\n }\n\n function repayFlashLoan(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) internal {\n IERC20(loanToken).transfer(iToken, loanAmount);\n }\n\n function executeOperation(\n address loanToken,\n address iToken,\n uint256 loanAmount\n ) external returns (bytes memory success) {\n emit BalanceOf(IERC20(loanToken).balanceOf(address(this)));\n emit ExecuteOperation(loanToken, iToken, loanAmount);\n repayFlashLoan(loanToken, iToken, loanAmount);\n return bytes(\"1\");\n }\n\n function doStuffWithFlashLoan(\n address token,\n address iToken,\n uint256 amount\n ) external onlyOwner {\n bytes memory result;\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n result = initiateFlashLoanTest(token, iToken, amount);\n\n emit BalanceOf(IERC20(token).balanceOf(address(this)));\n\n // after loan checks and what not.\n if (hashCompareWithLengthCheck(bytes(\"1\"), result)) {\n revert(\"failed executeOperation\");\n }\n }\n\n function hashCompareWithLengthCheck(bytes memory a, bytes memory b)\n internal\n pure\n returns (bool)\n {\n if (a.length != b.length) {\n return false;\n } else {\n return keccak256(a) == keccak256(b);\n }\n }\n\n event ExecuteOperation(address loanToken, address iToken, uint256 loanAmount);\n\n event BalanceOf(uint256 balance);\n}\n" + }, + "contracts/testhelpers/interfaces/IERC1820Registry.sol": { + "content": "pragma solidity ^0.5.0;\n\n/**\n * @dev Interface of the global ERC1820 Registry, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register\n * implementers for interfaces in this registry, as well as query support.\n *\n * Implementers may be shared by multiple accounts, and can also implement more\n * than a single interface for each account. Contracts can implement interfaces\n * for themselves, but externally-owned accounts (EOA) must delegate this to a\n * contract.\n *\n * {IERC165} interfaces can also be queried via the registry.\n *\n * For an in-depth explanation and source code analysis, see the EIP text.\n */\ninterface IERC1820Registry {\n /**\n * @dev Sets `newManager` as the manager for `account`. A manager of an\n * account is able to set interface implementers for it.\n *\n * By default, each account is its own manager. Passing a value of `0x0` in\n * `newManager` will reset the manager to this initial state.\n *\n * Emits a {ManagerChanged} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n */\n function setManager(address account, address newManager) external;\n\n /**\n * @dev Returns the manager for `account`.\n *\n * See {setManager}.\n */\n function getManager(address account) external view returns (address);\n\n /**\n * @dev Sets the `implementer` contract as `account`'s implementer for\n * `interfaceHash`.\n *\n * `account` being the zero address is an alias for the caller's address.\n * The zero address can also be used in `implementer` to remove an old one.\n *\n * See {interfaceHash} to learn how these are created.\n *\n * Emits an {InterfaceImplementerSet} event.\n *\n * Requirements:\n *\n * - the caller must be the current manager for `account`.\n * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not\n * end in 28 zeroes).\n * - `implementer` must implement {IERC1820Implementer} and return true when\n * queried for support, unless `implementer` is the caller. See\n * {IERC1820Implementer-canImplementInterfaceForAddress}.\n */\n function setInterfaceImplementer(\n address account,\n bytes32 interfaceHash,\n address implementer\n ) external;\n\n /**\n * @dev Returns the implementer of `interfaceHash` for `account`. If no such\n * implementer is registered, returns the zero address.\n *\n * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28\n * zeroes), `account` will be queried for support of it.\n *\n * `account` being the zero address is an alias for the caller's address.\n */\n function getInterfaceImplementer(address account, bytes32 interfaceHash)\n external\n view\n returns (address);\n\n /**\n * @dev Returns the interface hash for an `interfaceName`, as defined in the\n * corresponding\n * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].\n */\n function interfaceHash(string calldata interfaceName) external pure returns (bytes32);\n\n /**\n * @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n * @param account Address of the contract for which to update the cache.\n * @param interfaceId ERC165 interface for which to update the cache.\n */\n function updateERC165Cache(address account, bytes4 interfaceId) external;\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not.\n * If the result is not cached a direct lookup on the contract address is performed.\n * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n * {updateERC165Cache} with the contract address.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165Interface(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n /**\n * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache.\n * @param account Address of the contract to check.\n * @param interfaceId ERC165 interface to check.\n * @return True if `account` implements `interfaceId`, false otherwise.\n */\n function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId)\n external\n view\n returns (bool);\n\n event InterfaceImplementerSet(\n address indexed account,\n bytes32 indexed interfaceHash,\n address indexed implementer\n );\n\n event ManagerChanged(address indexed account, address indexed newManager);\n}\n" + }, + "contracts/testhelpers/ITokenFlashLoanTest.sol": { + "content": "pragma solidity ^0.5.17;\npragma experimental ABIEncoderV2;\n\n// \"SPDX-License-Identifier: Apache-2.0\"\n\ninterface ITokenFlashLoanTest {\n function flashBorrow(\n uint256 borrowAmount,\n address borrower,\n address target,\n string calldata signature,\n bytes calldata data\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/testhelpers/LoanTokenLogicTest.sol": { + "content": "pragma solidity 0.5.17;\npragma experimental ABIEncoderV2;\n\nimport \"../connectors/loantoken/modules/beaconLogicLM/LoanTokenLogic.sol\";\n\ncontract LoanTokenLogicTest is LoanTokenLogic {\n function getMarginBorrowAmountAndRate(uint256 leverageAmount, uint256 depositAmount)\n public\n view\n returns (uint256, uint256)\n {\n return _getMarginBorrowAmountAndRate(leverageAmount, depositAmount);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestNonReentrantValueSetter.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../reentrancy/SharedReentrancyGuard.sol\";\n\ncontract TestNonReentrantValueSetter is SharedReentrancyGuard {\n uint256 public value;\n\n // This will fail if another globallyNonReentrant function has already been entered\n function setValue(uint256 newValue) public globallyNonReentrant {\n value = newValue;\n }\n\n // this will always fail if `other.setValue` is globallyNonReentrant\n function setOtherContractValueNonReentrant(address other, uint256 newValue)\n external\n globallyNonReentrant\n {\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n\n // this is intentionally not globallyNonReentrant and should work even if both contracts are non-reentrant\n function setThisAndOtherContractValue(address other, uint256 newValue) external {\n setValue(newValue);\n TestNonReentrantValueSetter(other).setValue(newValue);\n }\n}\n" + }, + "contracts/testhelpers/reentrancy/TestValueSetterProxy.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../proxy/UpgradableProxy.sol\";\n\ncontract TestValueSetterProxy is UpgradableProxy {\n // This is here for the memory layout\n uint256 public value;\n}\n" + }, + "contracts/testhelpers/staking/StakingTester.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../../governance/Staking/interfaces/IStaking.sol\";\nimport \"../TestToken.sol\";\n\ncontract StakingTester {\n IStaking public staking;\n TestToken public token;\n\n constructor(address _staking, address _token) public {\n staking = IStaking(_staking);\n token = TestToken(_token);\n }\n\n function stakeAndWithdraw(uint96 _amount, uint256 _until) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _until, address(this), address(this));\n staking.withdraw(_amount, _until, address(this));\n }\n\n function stakeAndDelegate(\n uint96 _amount,\n address _delegatee,\n uint256 _lockDate\n ) public {\n token.mint(address(this), _amount);\n token.approve(address(staking), _amount);\n staking.stake(_amount, _lockDate, address(this), address(this));\n staking.delegate(_delegatee, _lockDate);\n }\n}\n" + }, + "contracts/testhelpers/TestCoverage.sol": { + "content": "/**\n * In order to test some functionalities like Pausable::pausable() modifier,\n * it is required to add a contract to invoke them and get a full coverage on tests.\n */\n\npragma solidity 0.5.17;\n\nimport \"../connectors/loantoken/Pausable.sol\";\nimport \"../governance/Staking/SafeMath96.sol\";\nimport \"../mixins/EnumerableBytes32Set.sol\";\nimport \"../mixins/VaultController.sol\";\nimport \"../connectors/loantoken/AdvancedToken.sol\";\nimport \"../connectors/loantoken/LoanTokenLogicStorage.sol\";\n\ncontract TestCoverage is\n Pausable,\n SafeMath96,\n VaultController,\n AdvancedToken,\n LoanTokenLogicStorage\n{\n /// @dev Pausable is currently an unused contract that still is operative\n /// because margin trade flashloan functionality has been commented out.\n /// In case it were restored, contract would become used again, so for a\n /// complete test coverage it is required to test it.\n\n function dummyPausableFunction() external pausable(msg.sig) {\n /// @dev do nothing, just to check if modifier is working\n }\n\n /// @dev This function should be located on Pausable contract in the case\n /// it has to be used again by flashloan restoration.\n function togglePause(\n string memory funcId, // example: \"mint(uint256,uint256)\"\n bool isPaused\n ) public {\n /// keccak256(\"Pausable_FunctionPause\")\n bytes32 slot =\n keccak256(\n abi.encodePacked(\n bytes4(keccak256(abi.encodePacked(funcId))),\n uint256(0xa7143c84d793a15503da6f19bf9119a2dac94448ca45d77c8bf08f57b2e91047)\n )\n );\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n sstore(slot, isPaused)\n }\n }\n\n /// @dev Testing internal functions of governance/Staking/SafeMath96.sol\n function testSafeMath96_safe32(uint256 n) public pure returns (uint32) {\n // Public wrapper for SafeMath96 internal function\n return safe32(n, \"overflow\");\n }\n\n function testSafeMath96_safe64(uint256 n) public pure returns (uint64) {\n // Public wrapper for SafeMath96 internal function\n return safe64(n, \"overflow\");\n }\n\n function testSafeMath96_safe96(uint256 n) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return safe96(n, \"overflow\");\n }\n\n function testSafeMath96_sub96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return sub96(a, b, \"underflow\");\n }\n\n function testSafeMath96_mul96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return mul96(a, b, \"overflow\");\n }\n\n function testSafeMath96_div96(uint96 a, uint96 b) public pure returns (uint96) {\n // Public wrapper for SafeMath96 internal function\n return div96(a, b, \"division by 0\");\n }\n\n using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;\n EnumerableBytes32Set.Bytes32Set internal aSet;\n\n function testEnum_AddRemove(bytes32 a, bytes32 b) public returns (bool) {\n aSet.addBytes32(a);\n return aSet.removeBytes32(b);\n }\n\n function testEnum_AddAddress(address a, address b) public returns (bool) {\n aSet.addAddress(a);\n return aSet.containsAddress(b);\n }\n\n function testEnum_AddAddressesAndEnumerate(\n address a,\n address b,\n uint256 start,\n uint256 count\n ) public returns (bytes32[] memory) {\n aSet.addAddress(a);\n aSet.addAddress(b);\n return aSet.enumerate(start, count);\n }\n\n /// @dev Wrapper to test internal function never called along current codebase\n function testVaultController_vaultApprove(\n address token,\n address to,\n uint256 value\n ) public {\n vaultApprove(token, to, value);\n }\n\n /// @dev mint wrapper w/o previous checks\n function testMint(\n address _to,\n uint256 _tokenAmount,\n uint256 _assetAmount,\n uint256 _price\n ) public {\n _mint(_to, _tokenAmount, _assetAmount, _price);\n }\n\n /// @dev wrapper for a function unreachable to tests\n function testStringToBytes32(string memory source) public pure returns (bytes32 result) {\n return stringToBytes32(source);\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some ERC777 from the lending pool.\n * 2. Close the loan with closeWithDeposit function in the protocol.\n * 3. Burn all iERC777.\n *\n * The cross-reentrancy happened in step#3. It might happened through a hook function (tokensToSend) that is implemented in this contract to support the ERC777 transfer.\n * Inside the hook function, it will try to mint the iERC777.\n * The details about the hook functions can be found here: https://eips.ethereum.org/EIPS/eip-777#hooks\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithDeposit function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyERC777 {\n address public loanToken;\n address public WRBTC;\n address public SUSD; /// ERC777\n ProtocolLike public sovrynProtocol;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iUSDTBalance;\n }\n\n function() external payable {}\n\n constructor(\n address _loanToken,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanToken = _loanToken;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777TokensSender\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: WRBTC has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n });\n\n IERC20(WRBTC).approve(loanToken, initial.susdBalance);\n\n ILoanTokenModules(loanToken).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n WRBTC,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanToken).loanParamsIds(\n uint256(keccak256(abi.encodePacked(WRBTC, true)))\n );\n bytes32 loan_id =\n keccak256(abi.encodePacked(loanParamsLocalId, loanToken, _borrower, _borrowerNonce));\n\n // STEP 3 close the borrowed position with a deposit\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(address(sovrynProtocol), _SUSDBalance);\n sovrynProtocol.closeWithDeposit(\n loan_id,\n address(this),\n collateralTokenSent.mul(20).div(100) // make it 20% higher from initial borrow amount\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iSUSD\n uint256 _iSUSDBalance = ILoanTokenModules(loanToken).balanceOf(_borrower);\n ILoanTokenModules(loanToken).burn(_receiver, _iSUSDBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iUSDTBalance: ILoanTokenModules(loanToken).balanceOf(_borrower)\n // });\n }\n\n function tokensToSend(\n address operator,\n address from,\n address to,\n uint256,\n bytes calldata,\n bytes calldata\n ) external {\n if (operator == address(sovrynProtocol) && to == loanToken && from == address(this)) {\n uint256 _SUSDBalance = IERC20(SUSD).balanceOf(address(this));\n IERC20(SUSD).approve(loanToken, _SUSDBalance);\n\n ILoanTokenModules(loanToken).mint(address(this), 1000000 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n}\n" + }, + "contracts/testhelpers/TestCrossReentrancyRBTC.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../interfaces/ILoanTokenModules.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"../connectors/loantoken/interfaces/ProtocolLike.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../interfaces/IWrbtcERC20.sol\";\nimport \"../mockup/MockLoanTokenLogic.sol\";\n\n/**\n * @dev This is the smart contract wrapper that is designed to test the cross-reentrancy attack between the protocol & loan token contract.\n * The cross-reentrancy can be triggered from the closeWithSwap, closeWithDeposit, liquidate, rollover since it might send the RBTC / ERC777 back to the receiver for refunding the excess of the swap.\n * This wrapper function will try to:\n * 1. Borrow some WRBTC from the lending pool.\n * 2. Close the loan with closeWithSwap function in the protocol.\n * 3. Burn all iWRBTC.\n *\n * The refund happened in step #3, which will send back the RBTC back to this contract.\n * Then, this contract will try to do another iWRBTC minting to the loan token --> this is where the cross-reentrancy happened between the protocol & the loan token contract.\n *\n * This function should never been passed in the unit testing since we have:\n * 1. invariant check for the loan token (iToken) total supply for closeWithSwap function.\n * 2. global reentrancy guard between the protocol & the loan token.\n */\n\ncontract TestCrossReentrancyRBTC {\n address public loanTokenWRBTC;\n address public WRBTC;\n address public SUSD;\n ProtocolLike public sovrynProtocol;\n\n using SafeMath for uint256;\n\n struct balanceState {\n uint256 rbtcBalance;\n uint256 wrbtcBalance;\n uint256 susdBalance;\n uint256 iWRBTCBalance;\n }\n\n function() external payable {\n if (msg.sender == address(sovrynProtocol)) {\n uint256 latestRBTCBalance = address(this).balance;\n IWrbtcERC20(WRBTC).deposit.value(14 ether)();\n uint256 _WRBTCBalance = IERC20(WRBTC).balanceOf(address(this));\n IERC20(WRBTC).approve(loanTokenWRBTC, _WRBTCBalance);\n\n ILoanTokenModules(loanTokenWRBTC).mint(address(this), 14 ether); // unable to reentrant mint here since mint function have reentrancy guard in place\n }\n }\n\n constructor(\n address _loanTokenWRBTC,\n address _WRBTC,\n address _SUSD,\n address _sovrynProtocol\n ) public {\n loanTokenWRBTC = _loanTokenWRBTC;\n WRBTC = _WRBTC;\n SUSD = _SUSD;\n sovrynProtocol = ProtocolLike(_sovrynProtocol);\n }\n\n function testCrossReentrancy(uint256 withdrawAmount, uint256 collateralTokenSent) public {\n address _receiver = address(this);\n address _borrower = address(this);\n\n // step 1, borrow\n // prerequisite: SUSD has been transferred to this contract\n balanceState memory initial =\n balanceState({\n rbtcBalance: address(this).balance,\n wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n susdBalance: IERC20(SUSD).balanceOf(address(this)),\n iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n });\n\n IERC20(SUSD).approve(loanTokenWRBTC, initial.susdBalance);\n\n ILoanTokenModules(loanTokenWRBTC).borrow(\n bytes32(0),\n withdrawAmount,\n 10000,\n collateralTokenSent,\n SUSD,\n _borrower,\n _receiver,\n \"\"\n );\n\n uint256 _borrowerNonce = sovrynProtocol.borrowerNonce(_borrower);\n bytes32 loanParamsLocalId =\n ILoanTokenModules(loanTokenWRBTC).loanParamsIds(\n uint256(keccak256(abi.encodePacked(SUSD, true)))\n );\n bytes32 loan_id =\n keccak256(\n abi.encodePacked(loanParamsLocalId, loanTokenWRBTC, _borrower, _borrowerNonce)\n );\n\n // STEP 3 close the borrowed position with a swap (probably works just as well with deposit)\n sovrynProtocol.closeWithSwap(\n loan_id,\n msg.sender,\n collateralTokenSent.mul(200).div(100), // make it 20% higher from initial collateral sent to make sure whole position is closed\n true,\n \"\"\n );\n\n /** Rest of code Should not be executed as in there will be reverted in step #3 because of invariant check.\n if it's got executed, means that there is an cross-reentrancy vulnerability */\n // STEP 4 Burn all iRBTC\n uint256 _iWRBTCBalance = ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower);\n ILoanTokenModules(loanTokenWRBTC).burn(_receiver, _iWRBTCBalance);\n\n /** Used for debugging */\n // balanceState memory finalBalance =\n // balanceState({\n // rbtcBalance: address(this).balance,\n // wrbtcBalance: IERC20(WRBTC).balanceOf(address(this)),\n // susdBalance: IERC20(SUSD).balanceOf(address(this)),\n // iWRBTCBalance: ILoanTokenModules(loanTokenWRBTC).balanceOf(_borrower)\n // });\n }\n}\n" + }, + "contracts/testhelpers/TestLibraries.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../rsk/RSKAddrValidator.sol\";\n\n// contract for testing libraries\ncontract TestLibraries {\n /*\n * @param addr it is an address to check that it does not originates from\n * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\n * also an address from PK = ZERO. So we check for both of them.\n */\n function RSKAddrValidator_checkPKNotZero(address addr) public pure returns (bool) {\n return (RSKAddrValidator.checkPKNotZero(addr));\n }\n\n /*\n * Safely compares two addresses, checking they do not originate from\n * a zero private key\n */\n function RSKAddrValidator_safeEquals(address addr1, address addr2) public pure returns (bool) {\n return (RSKAddrValidator.safeEquals(addr1, addr2));\n }\n}\n" + }, + "contracts/testhelpers/TestSovrynSwap.sol": { + "content": "/**\n * Test file simulating the SovrynSwap network\n * */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeERC20.sol\";\nimport \"../feeds/IPriceFeeds.sol\";\nimport \"./TestToken.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestSovrynSwap {\n using SafeERC20 for IERC20;\n using SafeMath for uint256;\n\n address public priceFeeds;\n\n constructor(address feed) public {\n priceFeeds = feed;\n }\n\n /**\n * simulating the contract registry. always returns the address of this contract\n * */\n function addressOf(bytes32 contractName) public view returns (address) {\n return address(this);\n }\n\n /**\n * calculates the return tokens when swapping _amount, makes sure the return is bigger than _minReturn,\n * mints and burns the test tokens accordingly.\n * */\n function convertByPath(\n IERC20[] calldata _path,\n uint256 _amount,\n uint256 _minReturn,\n address _beneficiary,\n address _affiliateAccount,\n uint256 _affiliateFee\n ) external payable returns (uint256) {\n //compute the return for the amount of tokens provided\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n uint256 actualReturn = _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n\n require(actualReturn >= _minReturn, \"insufficient source tokens provided\");\n\n TestToken(address(_path[0])).burn(address(msg.sender), _amount);\n TestToken(address(_path[1])).mint(address(_beneficiary), actualReturn);\n return actualReturn;\n }\n\n /**\n * queries the rate from the Price Feed contract and computes the expected return amount based on the\n * amout of source tokens to be swapped.\n * */\n function rateByPath(IERC20[] calldata _path, uint256 _amount) external view returns (uint256) {\n (uint256 sourceToDestRate, uint256 sourceToDestPrecision) =\n IPriceFeeds(priceFeeds).queryRate(address(_path[0]), address(_path[1]));\n\n return _amount.mul(sourceToDestRate).div(sourceToDestPrecision);\n }\n\n /**\n * returns the conversion path -> always a direct path\n * */\n function conversionPath(IERC20 _sourceToken, IERC20 _targetToken)\n external\n view\n returns (IERC20[] memory)\n {\n IERC20[] memory path = new IERC20[](2);\n path[0] = _sourceToken;\n path[1] = _targetToken;\n return path;\n }\n}\n" + }, + "contracts/testhelpers/TestToken.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestToken {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balances[_who], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[_who] = balances[_who].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(_who, _value);\n emit Transfer(_who, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/testhelpers/TestTokenERC777.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Context.sol\";\nimport \"../openzeppelin/SafeMath.sol\";\nimport \"../openzeppelin/Address.sol\";\nimport \"../interfaces/IERC777.sol\";\nimport \"../interfaces/IERC777Recipient.sol\";\nimport \"../interfaces/IERC777Sender.sol\";\nimport \"../interfaces/IERC20.sol\";\nimport \"./interfaces/IERC1820Registry.sol\";\n\ncontract TestTokenERC777 is Context, IERC777, IERC20 {\n using SafeMath for uint256;\n using Address for address;\n\n IERC1820Registry internal constant ERC1820_REGISTRY =\n IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n\n mapping(address => uint256) private _balances;\n\n uint256 private _totalSupply;\n\n // We inline the result of the following hashes because Solidity doesn't resolve them at compile time.\n // See https://github.com/ethereum/solidity/issues/4024.\n\n // keccak256(\"ERC777TokensSender\")\n bytes32 private constant TOKENS_SENDER_INTERFACE_HASH =\n 0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895;\n\n // keccak256(\"ERC777TokensRecipient\")\n bytes32 private constant TOKENS_RECIPIENT_INTERFACE_HASH =\n 0xb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b;\n\n // This isn't ever read from - it's only used to respond to the defaultOperators query.\n address[] private _defaultOperatorsArray;\n\n // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators).\n mapping(address => bool) private _defaultOperators;\n\n // For each account, a mapping of its operators and revoked default operators.\n mapping(address => mapping(address => bool)) private _operators;\n mapping(address => mapping(address => bool)) private _revokedDefaultOperators;\n\n // ERC20-allowances\n mapping(address => mapping(address => uint256)) private _allowances;\n\n /**\n * @dev `defaultOperators` may be an empty array.\n */\n constructor(\n string memory _name,\n string memory _symbol,\n uint256 _initialSupply,\n uint8 _decimals,\n address[] memory defaultOperators\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n _defaultOperatorsArray = defaultOperators;\n for (uint256 i = 0; i < _defaultOperatorsArray.length; i++) {\n _defaultOperators[_defaultOperatorsArray[i]] = true;\n }\n\n _mint(msg.sender, msg.sender, _initialSupply, \"\", \"\");\n\n // register interfaces\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC777Token\"),\n address(this)\n );\n ERC1820_REGISTRY.setInterfaceImplementer(\n address(this),\n keccak256(\"ERC20Token\"),\n address(this)\n );\n }\n\n /**\n * @dev See {IERC777-granularity}.\n *\n * This implementation always returns `1`.\n */\n function granularity() public view returns (uint256) {\n return 1;\n }\n\n /**\n * @dev See {IERC777-totalSupply}.\n */\n function totalSupply() public view returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev Returns the amount of tokens owned by an account (`tokenHolder`).\n */\n function balanceOf(address tokenHolder) public view returns (uint256) {\n return _balances[tokenHolder];\n }\n\n /**\n * @dev See {IERC777-send}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function send(\n address recipient,\n uint256 amount,\n bytes memory data\n ) public {\n _send(_msgSender(), _msgSender(), recipient, amount, data, \"\", true);\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient}\n * interface if it is a contract.\n *\n * Also emits a {Sent} event.\n */\n function transfer(address recipient, uint256 amount) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n\n address from = _msgSender();\n\n _callTokensToSend(from, from, recipient, amount, \"\", \"\");\n\n _move(from, from, recipient, amount, \"\", \"\");\n\n _callTokensReceived(from, from, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev See {IERC777-burn}.\n *\n * Also emits a {IERC20-Transfer} event for ERC20 compatibility.\n */\n function burn(uint256 amount, bytes memory data) public {\n _burn(_msgSender(), _msgSender(), amount, data, \"\");\n }\n\n /**\n * @dev See {IERC777-isOperatorFor}.\n */\n function isOperatorFor(address operator, address tokenHolder) public view returns (bool) {\n return\n operator == tokenHolder ||\n (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||\n _operators[tokenHolder][operator];\n }\n\n /**\n * @dev See {IERC777-authorizeOperator}.\n */\n function authorizeOperator(address operator) public {\n require(_msgSender() != operator, \"ERC777: authorizing self as operator\");\n\n if (_defaultOperators[operator]) {\n delete _revokedDefaultOperators[_msgSender()][operator];\n } else {\n _operators[_msgSender()][operator] = true;\n }\n\n emit AuthorizedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-revokeOperator}.\n */\n function revokeOperator(address operator) public {\n require(operator != _msgSender(), \"ERC777: revoking self as operator\");\n\n if (_defaultOperators[operator]) {\n _revokedDefaultOperators[_msgSender()][operator] = true;\n } else {\n delete _operators[_msgSender()][operator];\n }\n\n emit RevokedOperator(operator, _msgSender());\n }\n\n /**\n * @dev See {IERC777-defaultOperators}.\n */\n function defaultOperators() public view returns (address[] memory) {\n return _defaultOperatorsArray;\n }\n\n /**\n * @dev See {IERC777-operatorSend}.\n *\n * Emits {Sent} and {IERC20-Transfer} events.\n */\n function operatorSend(\n address sender,\n address recipient,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), sender),\n \"ERC777: caller is not an operator for holder\"\n );\n _send(_msgSender(), sender, recipient, amount, data, operatorData, true);\n }\n\n /**\n * @dev See {IERC777-operatorBurn}.\n *\n * Emits {Burned} and {IERC20-Transfer} events.\n */\n function operatorBurn(\n address account,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) public {\n require(\n isOperatorFor(_msgSender(), account),\n \"ERC777: caller is not an operator for holder\"\n );\n _burn(_msgSender(), account, amount, data, operatorData);\n }\n\n /**\n * @dev See {IERC20-allowance}.\n *\n * Note that operator and allowance concepts are orthogonal: operators may\n * not have allowance, and accounts with allowance may not be operators\n * themselves.\n */\n function allowance(address holder, address spender) public view returns (uint256) {\n return _allowances[holder][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Note that accounts cannot have allowance issued by their operators.\n */\n function approve(address spender, uint256 value) public returns (bool) {\n address holder = _msgSender();\n _approve(holder, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Note that operator and allowance concepts are orthogonal: operators cannot\n * call `transferFrom` (unless they have allowance), and accounts with\n * allowance cannot call `operatorSend` (unless they are operators).\n *\n * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events.\n */\n function transferFrom(\n address holder,\n address recipient,\n uint256 amount\n ) public returns (bool) {\n require(recipient != address(0), \"ERC777: transfer to the zero address\");\n require(holder != address(0), \"ERC777: transfer from the zero address\");\n\n address spender = _msgSender();\n\n _callTokensToSend(spender, holder, recipient, amount, \"\", \"\");\n\n _move(spender, holder, recipient, amount, \"\", \"\");\n\n _approve(\n holder,\n spender,\n _allowances[holder][spender].sub(amount, \"ERC777: transfer amount exceeds allowance\")\n );\n\n _callTokensReceived(spender, holder, recipient, amount, \"\", \"\", false);\n\n return true;\n }\n\n /**\n * @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * If a send hook is registered for `account`, the corresponding function\n * will be called with `operator`, `data` and `operatorData`.\n *\n * See {IERC777Sender} and {IERC777Recipient}.\n *\n * Emits {Minted} and {IERC20-Transfer} events.\n *\n * Requirements\n *\n * - `account` cannot be the zero address.\n * - if `account` is a contract, it must implement the {IERC777Recipient}\n * interface.\n */\n function _mint(\n address operator,\n address account,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n require(account != address(0), \"ERC777: mint to the zero address\");\n\n // Update state variables\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n\n _callTokensReceived(operator, address(0), account, amount, userData, operatorData, true);\n\n emit Minted(operator, account, amount, userData, operatorData);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Send tokens\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _send(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n require(from != address(0), \"ERC777: send from the zero address\");\n require(to != address(0), \"ERC777: send to the zero address\");\n\n _callTokensToSend(operator, from, to, amount, userData, operatorData);\n\n _move(operator, from, to, amount, userData, operatorData);\n\n _callTokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData,\n requireReceptionAck\n );\n }\n\n /**\n * @dev Burn tokens\n * @param operator address operator requesting the operation\n * @param from address token holder address\n * @param amount uint256 amount of tokens to burn\n * @param data bytes extra information provided by the token holder\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _burn(\n address operator,\n address from,\n uint256 amount,\n bytes memory data,\n bytes memory operatorData\n ) internal {\n require(from != address(0), \"ERC777: burn from the zero address\");\n\n _callTokensToSend(operator, from, address(0), amount, data, operatorData);\n\n // Update state variables\n _balances[from] = _balances[from].sub(amount, \"ERC777: burn amount exceeds balance\");\n _totalSupply = _totalSupply.sub(amount);\n\n emit Burned(operator, from, amount, data, operatorData);\n emit Transfer(from, address(0), amount);\n }\n\n function _move(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) private {\n _balances[from] = _balances[from].sub(amount, \"ERC777: transfer amount exceeds balance\");\n _balances[to] = _balances[to].add(amount);\n\n emit Sent(operator, from, to, amount, userData, operatorData);\n emit Transfer(from, to, amount);\n }\n\n function _approve(\n address holder,\n address spender,\n uint256 value\n ) internal {\n // TODO: restore this require statement if this function becomes internal, or is called at a new callsite. It is\n // currently unnecessary.\n //require(holder != address(0), \"ERC777: approve from the zero address\");\n require(spender != address(0), \"ERC777: approve to the zero address\");\n\n _allowances[holder][spender] = value;\n emit Approval(holder, spender, value);\n }\n\n /**\n * @dev Call from.tokensToSend() if the interface is registered\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n */\n function _callTokensToSend(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(from, TOKENS_SENDER_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Sender(implementer).tokensToSend(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n }\n }\n\n /**\n * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but\n * tokensReceived() was not registered for the recipient\n * @param operator address operator requesting the transfer\n * @param from address token holder address\n * @param to address recipient address\n * @param amount uint256 amount of tokens to transfer\n * @param userData bytes extra information provided by the token holder (if any)\n * @param operatorData bytes extra information provided by the operator (if any)\n * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient\n */\n function _callTokensReceived(\n address operator,\n address from,\n address to,\n uint256 amount,\n bytes memory userData,\n bytes memory operatorData,\n bool requireReceptionAck\n ) internal {\n address implementer =\n ERC1820_REGISTRY.getInterfaceImplementer(to, TOKENS_RECIPIENT_INTERFACE_HASH);\n if (implementer != address(0)) {\n IERC777Recipient(implementer).tokensReceived(\n operator,\n from,\n to,\n amount,\n userData,\n operatorData\n );\n } else if (requireReceptionAck) {\n require(\n !to.isContract(),\n \"ERC777: token recipient contract has no implementer for ERC777TokensRecipient\"\n );\n }\n }\n\n function mint(address _to, uint256 _value) public {\n // Update state variables\n _totalSupply = _totalSupply.add(_value);\n _balances[_to] = _balances[_to].add(_value);\n\n emit Minted(msg.sender, _to, _value, \"\", \"\");\n }\n\n function burn(address _who, uint256 _value) public {\n require(_value <= balanceOf(_who), \"balance too low\");\n\n _burn(msg.sender, _who, _value, \"\", \"\");\n }\n}\n" + }, + "contracts/testhelpers/TestTokenLimited.sol": { + "content": "/**\n * Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.\n * Licensed under the Apache License, Version 2.0.\n */\n\npragma solidity 0.5.17;\n\nimport \"../openzeppelin/SafeMath.sol\";\n\ncontract TestTokenLimited {\n using SafeMath for uint256;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n event AllowanceUpdate(\n address indexed owner,\n address indexed spender,\n uint256 valueBefore,\n uint256 valueAfter\n );\n event Mint(address indexed minter, uint256 value);\n event Burn(address indexed burner, uint256 value);\n\n string public name;\n string public symbol;\n uint8 public decimals;\n\n mapping(address => uint256) internal balances;\n mapping(address => mapping(address => uint256)) internal allowed;\n uint256 internal totalSupply_;\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals,\n uint256 _initialAmount\n ) public {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n if (_initialAmount != 0) {\n mint(msg.sender, _initialAmount);\n }\n }\n\n function approve(address _spender, uint256 _value) public returns (bool) {\n allowed[msg.sender][_spender] = _value;\n emit Approval(msg.sender, _spender, _value);\n return true;\n }\n\n function transfer(address _to, uint256 _value) public returns (bool) {\n require(_value <= balances[msg.sender] && _to != address(0), \"invalid transfer\");\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Transfer(msg.sender, _to, _value);\n return true;\n }\n\n function transferFrom(\n address _from,\n address _to,\n uint256 _value\n ) public returns (bool) {\n uint256 allowanceAmount = allowed[_from][msg.sender];\n require(\n _value <= balances[_from] && _value <= allowanceAmount && _to != address(0),\n \"invalid transfer\"\n );\n\n balances[_from] = balances[_from].sub(_value);\n balances[_to] = balances[_to].add(_value);\n if (allowanceAmount < uint256(-1)) {\n allowed[_from][msg.sender] = allowanceAmount.sub(_value);\n /// @dev Allowance mapping update requires an event log\n emit AllowanceUpdate(_from, msg.sender, allowanceAmount, allowed[_from][msg.sender]);\n }\n\n emit Transfer(_from, _to, _value);\n return true;\n }\n\n function mint(address _to, uint256 _value) public {\n require(_to != address(0), \"no burn allowed\");\n require(_value <= 100000 ether, \"max mint amount exceeded\");\n totalSupply_ = totalSupply_.add(_value);\n balances[_to] = balances[_to].add(_value);\n\n emit Mint(_to, _value);\n emit Transfer(address(0), _to, _value);\n }\n\n function burn(uint256 _value) public {\n require(_value <= balances[msg.sender], \"balance too low\");\n // no need to require _value <= totalSupply, since that would imply the\n // sender's balance is greater than the totalSupply, which *should* be an assertion failure\n\n balances[msg.sender] = balances[msg.sender].sub(_value);\n totalSupply_ = totalSupply_.sub(_value);\n\n emit Burn(msg.sender, _value);\n emit Transfer(msg.sender, address(0), _value);\n }\n\n function totalSupply() public view returns (uint256) {\n return totalSupply_;\n }\n\n function balanceOf(address _owner) public view returns (uint256) {\n return balances[_owner];\n }\n\n function allowance(address _owner, address _spender) public view returns (uint256) {\n return allowed[_owner][_spender];\n }\n}\n" + }, + "contracts/token/IApproveAndCall.sol": { + "content": "pragma solidity ^0.5.17;\n\n/**\n * @title Interface for contract governance/ApprovalReceiver.sol\n * @dev Interfaces are used to cast a contract address into a callable instance.\n */\ninterface IApproveAndCall {\n /**\n * @notice Receives approval from SOV token.\n * @param _sender The sender of SOV.approveAndCall function.\n * @param _amount The amount was approved.\n * @param _token The address of token.\n * @param _data The data will be used for low level call.\n * */\n function receiveApproval(\n address _sender,\n uint256 _amount,\n address _token,\n bytes calldata _data\n ) external;\n}\n" + }, + "contracts/token/SOV.sol": { + "content": "pragma solidity ^0.5.17;\n\nimport \"../openzeppelin/ERC20Detailed.sol\";\nimport \"../openzeppelin/ERC20.sol\";\nimport \"../openzeppelin/Ownable.sol\";\nimport \"./IApproveAndCall.sol\";\n\n/**\n * @title Sovryn Token: SOV is an ERC-20 token contract for Sovryn governance.\n *\n * @notice This contract accounts for all holders' balances.\n *\n * @dev This contract represents a token with dynamic supply.\n * The owner of the token contract can mint/burn tokens to/from any account\n * based upon previous governance voting and approval.\n * */\ncontract SOV is ERC20, ERC20Detailed, Ownable {\n string constant NAME = \"Sovryn Token\";\n string constant SYMBOL = \"SOV\";\n uint8 constant DECIMALS = 18;\n\n /**\n * @notice Constructor called on deployment, initiates the contract.\n * @dev On deployment, some amount of tokens will be minted for the owner.\n * @param _initialAmount The amount of tokens to be minted on contract creation.\n * */\n constructor(uint256 _initialAmount) public ERC20Detailed(NAME, SYMBOL, DECIMALS) {\n if (_initialAmount != 0) {\n _mint(msg.sender, _initialAmount);\n }\n }\n\n /**\n * @notice Creates new tokens and sends them to the recipient.\n * @dev Don't create more than 2^96/10 tokens before updating the governance first.\n * @param _account The recipient address to get the minted tokens.\n * @param _amount The amount of tokens to be minted.\n * */\n function mint(address _account, uint256 _amount) public onlyOwner {\n _mint(_account, _amount);\n }\n\n /**\n * @notice Approves and then calls the receiving contract.\n * Useful to encapsulate sending tokens to a contract in one call.\n * Solidity has no native way to send tokens to contracts.\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\n * @param _spender The contract address to spend the tokens.\n * @param _amount The amount of tokens to be sent.\n * @param _data Parameters for the contract call, such as endpoint signature.\n * */\n function approveAndCall(\n address _spender,\n uint256 _amount,\n bytes memory _data\n ) public {\n approve(_spender, _amount);\n IApproveAndCall(_spender).receiveApproval(msg.sender, _amount, address(this), _data);\n }\n}\n" + }, + "contracts/utils/AdminRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/Ownable.sol\";\n\ncontract AdminRole is Ownable {\n /// @dev user => flag whether user has admin role.\n mapping(address => bool) public admins;\n\n event AdminAdded(address admin);\n event AdminRemoved(address admin);\n\n /**\n * @dev Throws if called by any account other than the owner or admin.\n * or on our own overriding sovrynOwnable.\n */\n modifier onlyAuthorized() {\n require(isOwner() || admins[msg.sender], \"unauthorized\");\n _;\n }\n\n /**\n * @notice Add account to ACL.\n * @param _admin The addresses of the account to grant permissions.\n * */\n function addAdmin(address _admin) public onlyOwner {\n admins[_admin] = true;\n emit AdminAdded(_admin);\n }\n\n /**\n * @notice Remove account from ACL.\n * @param _admin The addresses of the account to revoke permissions.\n * */\n function removeAdmin(address _admin) public onlyOwner {\n admins[_admin] = false;\n emit AdminRemoved(_admin);\n }\n}\n" + }, + "contracts/utils/PausableRole.sol": { + "content": "pragma solidity 0.5.17;\n\nimport \"../openzeppelin/PausableOz.sol\";\n\ncontract PausableRole is PausableOz {\n address public pauser;\n\n event SetPauser(address indexed sender, address indexed oldPauser, address indexed newPauser);\n\n /**\n * @dev Modifier to make a function callable only when the caller is pauser or owner\n */\n modifier onlyPauserOrOwner() {\n require(isOwner() || msg.sender == pauser, \"Pausable: unauthorized\"); // SS02\n _;\n }\n\n /**\n * @notice Set the pauser address.\n *\n * only pauser can perform this action.\n *\n * @param newPauser The new address of the pauser.\n * */\n function setPauser(address newPauser) external onlyOwner {\n address oldPauser = pauser;\n pauser = newPauser;\n\n emit SetPauser(msg.sender, oldPauser, newPauser);\n }\n\n /**\n * @dev Called by the owner to pause, triggers stopped state.\n */\n function pause() public onlyPauserOrOwner whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Called by the owner to unpause, returns to normal state.\n */\n function unpause() public onlyPauserOrOwner whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "contracts/utils/ProxyOwnable.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\n/**\n * Based on OpenZeppelin's Ownable contract:\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\n *\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract ProxyOwnable {\n bytes32 private constant KEY_OWNER = keccak256(\"key.proxy.owner\");\n\n event ProxyOwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() internal {\n _setProxyOwner(msg.sender);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyProxyOwner() {\n require(msg.sender == getProxyOwner(), \"Ownable:: access denied\");\n _;\n }\n\n /**\n * @notice Set address of the owner.\n * @param _owner Address of the owner.\n * */\n function _setProxyOwner(address _owner) internal {\n require(_owner != address(0), \"ProxyOwnable::setProxyOwner: invalid address\");\n emit ProxyOwnershipTransferred(getProxyOwner(), _owner);\n\n bytes32 key = KEY_OWNER;\n assembly {\n sstore(key, _owner)\n }\n }\n\n /**\n * @notice Set address of the owner (only owner can call this function)\n * @param _owner Address of the owner.\n * */\n function setProxyOwner(address _owner) public onlyProxyOwner {\n _setProxyOwner(_owner);\n }\n\n /**\n * @notice Return address of the owner.\n * @return _owner Address of the owner.\n * */\n function getProxyOwner() public view returns (address _owner) {\n bytes32 key = KEY_OWNER;\n assembly {\n _owner := sload(key)\n }\n }\n}\n" + }, + "contracts/utils/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.5.17;\n\nlibrary Utils {\n function stringToBytes32(string memory source) internal pure returns (bytes32 result) {\n bytes memory tempEmptyStringTest = bytes(source);\n if (tempEmptyStringTest.length == 0) {\n return 0x0;\n }\n\n assembly {\n result := mload(add(source, 32))\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + }, + "remappings": [] + } +} \ No newline at end of file diff --git a/external/deployments/rskMainnet/BorrowerOperations.json b/external/deployments/rskMainnet/BorrowerOperations.json new file mode 100644 index 000000000..a80b19d2e --- /dev/null +++ b/external/deployments/rskMainnet/BorrowerOperations.json @@ -0,0 +1,1391 @@ +{ + "address": "0x5B9dB4B8bdeF3e57323187a9AC2639C5DEe5FD39", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_oldImplementation", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_newImplementation", + "type": "address" + } + ], + "name": "ImplementationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + } + ], + "name": "CollSurplusPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + } + ], + "name": "FeeDistributorAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + } + ], + "name": "GasPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_massetManagerAddress", + "type": "address" + } + ], + "name": "MassetManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + } + ], + "name": "StabilityPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "arrayIndex", + "type": "uint256" + } + ], + "name": "TroveCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newTroveManagerAddress", + "type": "address" + } + ], + "name": "TroveManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum BorrowerOperations.BorrowerOperation", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "ZEROStakingAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDFee", + "type": "uint256" + } + ], + "name": "ZUSDBorrowingFeePaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "BORROWING_FEE_FLOOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "addColl", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "adjustNueTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "adjustNueTroveWithPermit2", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "adjustTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "claimCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "closeNueTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "closeNueTroveWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "closeTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeDistributor", + "outputs": [ + { + "internalType": "contract IFeeDistributor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + } + ], + "name": "getCompositeDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMassetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "massetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "moveETHGainToTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "openNueTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "openTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "repayZUSD", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "repayZusdFromDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "repayZusdFromDLLRWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_massetManagerAddress", + "type": "address" + } + ], + "name": "setMassetManagerAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManager", + "outputs": [ + { + "internalType": "contract ITroveManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawColl", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawZUSD", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawZusdAndConvertToDLLR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "zeroStaking", + "outputs": [ + { + "internalType": "contract IZEROStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zeroStakingAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0x330ad35d02b52b6f132C3C31730Dd8F79Cb58b7E", + "transactionIndex": 0, + "gasUsed": "5799498", + "logsBloom": "0x00000800000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000001000000000000000000000000000000000000000", + "blockHash": "0x7de331c1815635488605d3e00b15a43084f7a6002e2ddf43d01f2c61ae10f888", + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748936, + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "address": "0x330ad35d02b52b6f132C3C31730Dd8F79Cb58b7E", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x7de331c1815635488605d3e00b15a43084f7a6002e2ddf43d01f2c61ae10f888" + } + ], + "blockNumber": 4748936, + "cumulativeGasUsed": "5799498", + "status": 1, + "byzantium": true + }, + "numDeployments": 10, + "bytecode": "0x60a06040523480156200001157600080fd5b506040516200556638038062005566833981016040819052620000349162000123565b62000048336001600160e01b036200005e16565b60601b6001600160601b031916608052620001b2565b6001600160a01b038116620000905760405162461bcd60e51b8152600401620000879062000170565b60405180910390fd5b6001600160a01b038116620000ad6001600160e01b036200010216565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f29062000153565b6040519081900390209190915550565b600080604051620001139062000153565b6040519081900390205492915050565b60006020828403121562000135578081fd5b81516001600160a01b03811681146200014c578182fd5b9392505050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160601c61538c620001da600039806106a552806110db5280612327525061538c6000f3fe60806040526004361061025c5760003560e01c80637778a3db11610144578063a20baee6116100b6578063c6a6cf201161007a578063c6a6cf2014610601578063e9fc346114610614578063ea9638bf14610629578063ec5472fd1461063c578063ec9f7d4614610651578063f92d3433146106665761025c565b8063a20baee614610414578063a3f4df7e14610595578063ae918754146105b7578063afbc74b5146105cc578063b5c89bab146105ec5761025c565b8063860665b311610108578063860665b314610510578063887105d314610523578063893d20e814610538578063899fe15e1461054d5780638d5c3dc11461056d5780639f070670146105805761025c565b80637778a3db14610486578063795d26c3146104a65780637d4f595d146104bb5780637e3eefdc146104db5780637f7dde4a146104fb5761025c565b8063485f190f116101dd5780636f0b0c1c116101a15780636f0b0c1c146103ff57806372fe25aa14610414578063734f622d14610429578063741bef1a14610449578063759b30341461045e578063763a0ef3146104735761025c565b8063485f190f146103795780634ff814431461038c5780635530273c146103ac57806368647db1146103cc5780636ea56960146103df5761025c565b80631a777717116102245780631a777717146102ed5780631bf435551461030d5780632771510a1461032f5780633cc742251461034f5780633d83908a146103645761025c565b80630d43e8ad146102615780630e704d501461028c5780630ff9a512146102a357806312261ee7146102b857806313af4035146102cd575b600080fd5b34801561026d57600080fd5b5061027661067b565b604051610283919061485c565b60405180910390f35b34801561029857600080fd5b506102a161068a565b005b3480156102af57600080fd5b50610276610694565b3480156102c457600080fd5b506102766106a3565b3480156102d957600080fd5b506102a16102e83660046142d7565b6106c7565b3480156102f957600080fd5b506102a161030836600461455d565b610714565b34801561031957600080fd5b5061032261072b565b60405161028391906152d8565b34801561033b57600080fd5b506102a161034a3660046142d7565b610738565b34801561035b57600080fd5b506102766107c6565b34801561037057600080fd5b506102766107d5565b6102a1610387366004614631565b6107e4565b34801561039857600080fd5b506103226103a7366004614507565b61094e565b3480156103b857600080fd5b506102a16103c7366004614537565b610961565b6102a16103da36600461430f565b610977565b3480156103eb57600080fd5b506102a16103fa366004614631565b61098d565b34801561040b57600080fd5b506102a161099e565b34801561042057600080fd5b506103226109fc565b34801561043557600080fd5b506102a1610444366004614391565b610a08565b34801561045557600080fd5b50610276610dcc565b34801561046a57600080fd5b50610322610ddb565b6102a1610481366004614758565b610de8565b34801561049257600080fd5b506102a16104a136600461449a565b610e04565b3480156104b257600080fd5b50610322610ef5565b3480156104c757600080fd5b506102a16104d63660046144b5565b611014565b3480156104e757600080fd5b506103226104f6366004614631565b61110a565b34801561050757600080fd5b50610276611385565b6102a161051e366004614631565b611394565b34801561052f57600080fd5b506103226113a1565b34801561054457600080fd5b50610276611470565b34801561055957600080fd5b506102a16105683660046145ae565b61148f565b6102a161057b3660046146e0565b6114aa565b34801561058c57600080fd5b506102766114c2565b3480156105a157600080fd5b506105aa6114d1565b6040516102839190614944565b3480156105c357600080fd5b506102766114ff565b3480156105d857600080fd5b506102a16105e7366004614537565b61150e565b3480156105f857600080fd5b50610276611520565b6102a161060f36600461467a565b61152f565b34801561062057600080fd5b5061027661153e565b6102a1610637366004614347565b61154d565b34801561064857600080fd5b50610276611567565b34801561065d57600080fd5b50610276611576565b34801561067257600080fd5b50610322611585565b600d546001600160a01b031681565b610692611607565b565b6009546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6106cf611470565b6001600160a01b0316336001600160a01b0316146107085760405162461bcd60e51b81526004016106ff90614e2d565b60405180910390fd5b610711816119f6565b50565b610725600080866000878787611a81565b50505050565b6809c2007651b250000081565b610740611470565b6001600160a01b0316336001600160a01b0316146107705760405162461bcd60e51b81526004016106ff90614e2d565b600c80546001600160a01b0319166001600160a01b0383161790556040517f6926b3375b54960080b7d8a184061f39a02e8c3bf64aa9df7e75359fdc00d814906107bb90839061485c565b60405180910390a150565b6001546001600160a01b031681565b6004546001600160a01b031681565b600c546001600160a01b031661080c5760405162461bcd60e51b81526004016106ff90615237565b6108198484848430611c37565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b39261084f9291169087906004016148b1565b602060405180830381600087803b15801561086957600080fd5b505af115801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a1919061447e565b6108bd5760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b926108f592911690879033906004016148f5565b602060405180830381600087803b15801561090f57600080fd5b505af1158015610923573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610947919061451f565b5050505050565b600061095982612262565b90505b919050565b61097233846000808686600061227d565b505050565b6109893360008060008686600061227d565b5050565b61072533600085600186868a61227d565b60075460405163b32beb5b60e01b81526001600160a01b039091169063b32beb5b906109ce90339060040161485c565b600060405180830381600087803b1580156109e857600080fd5b505af1158015610725573d6000803e3d6000fd5b670de0b6b3a764000081565b610a10611470565b6001600160a01b0316336001600160a01b031614610a405760405162461bcd60e51b81526004016106ff90614e2d565b610a498c61228d565b610a528b61228d565b610a5b8a61228d565b610a648961228d565b610a6d8861228d565b610a768761228d565b610a7f8661228d565b610a888561228d565b610a918461228d565b610a9a8361228d565b610aa38261228d565b610aac8161228d565b600d80546001600160a01b03199081166001600160a01b038f8116919091179092556003805482168e84161790556004805482168d84161790556000805482168c84161790556001805482168b84161790556005805482168a8416179055600680548216898416179055600780548216888416179055600280548216878416179055600b80548216868416179055600a8054821685841617905560098054821692841692831790556008805490911690911790556040517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db990610b90908e9061485c565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a56788a604051610bc7919061485c565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd88289604051610bfe919061485c565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b88604051610c35919061485c565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f87604051610c6c919061485c565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa086604051610ca3919061485c565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d85604051610cda919061485c565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db26484604051610d11919061485c565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe7880083604051610d48919061485c565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d82604051610d7f919061485c565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd81604051610db6919061485c565b60405180910390a1505050505050505050505050565b6002546001600160a01b031681565b6801158e460913d0000081565b610df98989898989898989896122d2565b505050505050505050565b600c546001600160a01b0316610e2c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a255391610e5e9133910161485c565b60206040518083038186803b158015610e7657600080fd5b505afa158015610e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eae919061451f565b600c54909150610eec906001600160a01b0316610eda836801158e460913d0000063ffffffff6124ab16565b600a546001600160a01b0316856124f6565b50610989611607565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f71919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b505afa158015610fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffb919061451f565b905061100d828263ffffffff6127a716565b9250505090565b600c546001600160a01b031661103c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a25539161106e9133910161485c565b60206040518083038186803b15801561108657600080fd5b505afa15801561109a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110be919061451f565b600c54600a54919250611101916001600160a01b039182169116867f000000000000000000000000000000000000000000000000000000000000000087876127cc565b50610725611607565b600a546040516370a0823160e01b8152600091309183916001600160a01b0316906370a082319061113f90859060040161485c565b60206040518083038186803b15801561115757600080fd5b505afa15801561116b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118f919061451f565b905061119f33838888888c612a19565b6111af818763ffffffff6127a716565b600a546040516370a0823160e01b81526001600160a01b03909116906370a08231906111df90869060040161485c565b60206040518083038186803b1580156111f757600080fd5b505afa15801561120b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122f919061451f565b1461124c5760405162461bcd60e51b81526004016106ff90614ac1565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611282929116908a906004016148b1565b602060405180830381600087803b15801561129c57600080fd5b505af11580156112b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d4919061447e565b6112f05760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611328929116908a9033906004016148f5565b602060405180830381600087803b15801561134257600080fd5b505af1158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a919061451f565b979650505050505050565b6000546001600160a01b031681565b6107258484848433611c37565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b60008060405161147f9061483f565b6040519081900390205492915050565b6114a260008088600089898989896122d2565b505050505050565b6114b987878787878787611a81565b50505050505050565b6003546001600160a01b031681565b60405180604001604052806012815260200171426f72726f7765724f7065726174696f6e7360701b81525081565b600b546001600160a01b031681565b6109723360008560008686600061227d565b600c546001600160a01b031681565b6114a23386868686868c61227d565b600c546001600160a01b031690565b611555612a2b565b6109728360008060008686600061227d565b6008546001600160a01b031681565b600a546001600160a01b031681565b6003546040805163f92d343360e01b815290516000926001600160a01b03169163f92d3433916004808301926020929190829003018186803b1580156115ca57600080fd5b505afa1580156115de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611602919061451f565b905090565b600454600054600a546001600160a01b0392831692918216911661162b8333612a55565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561167157600080fd5b505af1158015611685573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a9919061451f565b90506116b481612af6565b604051630b07655760e01b81526001600160a01b03851690630b076557906116e090339060040161485c565b600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50506040516309019aaf60e31b8152600092506001600160a01b038716915063480cd5789061174190339060040161485c565b60206040518083038186803b15801561175957600080fd5b505afa15801561176d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611791919061451f565b90506000856001600160a01b031663d66a2553336040518263ffffffff1660e01b81526004016117c1919061485c565b60206040518083038186803b1580156117d957600080fd5b505afa1580156117ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611811919061451f565b90506118368433611831846801158e460913d0000063ffffffff6124ab16565b612b1c565b600061184783600084600088612bb8565b905061185281612c43565b604051631fc5750960e31b81526001600160a01b0388169063fe2ba8489061187e90339060040161485c565b600060405180830381600087803b15801561189857600080fd5b505af11580156118ac573d6000803e3d6000fd5b50506040516365e89c5760e11b81526001600160a01b038a16925063cbd138ae91506118dc90339060040161485c565b600060405180830381600087803b1580156118f657600080fd5b505af115801561190a573d6000803e3d6000fd5b50505050336001600160a01b03166000805160206153378339815191526000806000600160405161193e9493929190614918565b60405180910390a261196a868633611965866801158e460913d0000063ffffffff6124ab16565b612ce8565b60065461198d90879087906001600160a01b03166801158e460913d00000612ce8565b6040516364a197f360e01b81526001600160a01b038716906364a197f3906119bb90339087906004016148b1565b600060405180830381600087803b1580156119d557600080fd5b505af11580156119e9573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038116611a1c5760405162461bcd60e51b81526004016106ff90614af8565b806001600160a01b0316611a2e611470565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611a719061483f565b6040519081900390209190915550565b600c546001600160a01b0316611aa95760405162461bcd60e51b81526004016106ff90615237565b83158015611ab75750600085115b15611add57600c54600a54611adb916001600160a01b0390811691889116846124f6565b505b611aed3387878787878d30612da2565b838015611afa5750600085115b156114b957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611b359291169089906004016148b1565b602060405180830381600087803b158015611b4f57600080fd5b505af1158015611b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b87919061447e565b611ba35760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611bdb92911690899033906004016148f5565b602060405180830381600087803b158015611bf557600080fd5b505af1158015611c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2d919061451f565b5050505050505050565b611c3f614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152611c77614131565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611cc757600080fd5b505af1158015611cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cff919061451f565b808252600090611d0e9061337a565b9050611d1a8882613415565b8251611d269033613501565b6040820187905280611d6757611d4683600001518460400151898b6135a3565b602083018190526040830151611d619163ffffffff6127a716565b60408301525b611d74826040015161375c565b611d818260400151612262565b60608301819052611d8e57fe5b611da13483606001518460000151613785565b60808301526060820151611db69034906137c4565b60a08301528015611dd357611dce82608001516137f9565b611e06565b611de0826080015161389e565b6000611df9346001856060015160018760000151612bb8565b9050611e0481612c43565b505b8251604051635d6b480f60e01b81526001600160a01b0390911690635d6b480f90611e389033906001906004016148b1565b600060405180830381600087803b158015611e5257600080fd5b505af1158015611e66573d6000803e3d6000fd5b505084516040516372423c1760e01b81526001600160a01b0390911692506372423c179150611e9b90339034906004016148b1565b602060405180830381600087803b158015611eb557600080fd5b505af1158015611ec9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eed919061451f565b5082516060830151604051639976cf4560e01b81526001600160a01b0390921691639976cf4591611f23913391906004016148b1565b602060405180830381600087803b158015611f3d57600080fd5b505af1158015611f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f75919061451f565b5082516040516382fe3eb960e01b81526001600160a01b03909116906382fe3eb990611fa590339060040161485c565b600060405180830381600087803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b50508451604051630c7940bd60e11b81526001600160a01b0390911692506318f2817a915061200690339060040161485c565b602060405180830381600087803b15801561202057600080fd5b505af1158015612034573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612058919061451f565b60c0830152600b5460a08301516040516346f7cf8760e01b81526001600160a01b03909216916346f7cf8791612097913391908b908b906004016148ca565b600060405180830381600087803b1580156120b157600080fd5b505af11580156120c5573d6000803e3d6000fd5b505084516040516315d549f160e01b81526001600160a01b0390911692506315d549f191506120f890339060040161485c565b602060405180830381600087803b15801561211257600080fd5b505af1158015612126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214a919061451f565b60e0830181905260405133917f59cfd0cd754bc5748b6770e94a4ffa5f678d885cb899dcfadc5734edb97c67ab9161218291906152d8565b60405180910390a2612198836020015134613943565b6121b183602001518460400151868a86604001516139bf565b602083015160408401516006546121dd9291906001600160a01b03166801158e460913d00000806139bf565b606082015160c083015160405133926000805160206153378339815191529261220b92349190600090614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc0022741836020015160405161225091906152d8565b60405180910390a25050505050505050565b6000610959826801158e460913d0000063ffffffff6127a716565b6114b98787878787878733612da2565b6001600160a01b0381166122b35760405162461bcd60e51b81526004016106ff90614c3a565b803b806109895760405162461bcd60e51b81526004016106ff90614fde565b600c546001600160a01b03166122fa5760405162461bcd60e51b81526004016106ff90615237565b851580156123085750600087115b1561234f57600c54600a5461234d916001600160a01b039081169116857f000000000000000000000000000000000000000000000000000000000000000086866127cc565b505b61235f3389898989898f30612da2565b85801561236c5750600087115b15610df957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b3926123a7929116908b906004016148b1565b602060405180830381600087803b1580156123c157600080fd5b505af11580156123d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f9919061447e565b6124155760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b9261244d929116908b9033906004016148f5565b602060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f919061451f565b50505050505050505050565b60006124ed83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a79565b90505b92915050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561253257600080fd5b505afa158015612546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061256a91906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161259a919061485c565b60206040518083038186803b1580156125b257600080fd5b505afa1580156125c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ea919061451f565b9050306001600160a01b03831663605629d633838a893561261160408c0160208d01614803565b8b604001358c606001356040518863ffffffff1660e01b815260040161263d9796959493929190614870565b600060405180830381600087803b15801561265757600080fd5b505af115801561266b573d6000803e3d6000fd5b50505050866126fc83856001600160a01b03166370a08231856040518263ffffffff1660e01b81526004016126a0919061485c565b60206040518083038186803b1580156126b857600080fd5b505afa1580156126cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f0919061451f565b9063ffffffff6124ab16565b146127195760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c9223906127499089908b9033906004016148f5565b602060405180830381600087803b15801561276357600080fd5b505af1158015612777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279b919061451f565b98975050505050505050565b6000828201838110156124ed5760405162461bcd60e51b81526004016106ff90614a8a565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284091906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612870919061485c565b60206040518083038186803b15801561288857600080fd5b505afa15801561289c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c0919061451f565b87516020015190915030906001600160a01b0388166330f28b7a8a6128e58585613aa5565b338b8b6040518663ffffffff1660e01b8152600401612908959493929190615267565b600060405180830381600087803b15801561292257600080fd5b505af1158015612936573d6000803e3d6000fd5b505050508061296b84866001600160a01b03166370a08231866040518263ffffffff1660e01b81526004016126a0919061485c565b146129885760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c9223906129b8908d90859033906004016148f5565b602060405180830381600087803b1580156129d257600080fd5b505af11580156129e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0a919061451f565b9b9a5050505050505050505050565b6114a28660008660018787878c612da2565b6005546001600160a01b031633146106925760405162461bcd60e51b81526004016106ff9061507c565b6040516321e3780160e01b81526000906001600160a01b038416906321e3780190612a8490859060040161485c565b60206040518083038186803b158015612a9c57600080fd5b505afa158015612ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad4919061451f565b9050806001146109725760405162461bcd60e51b81526004016106ff90614ddf565b612aff8161337a565b156107115760405162461bcd60e51b81526004016106ff90614b8a565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190612b4a90869060040161485c565b60206040518083038186803b158015612b6257600080fd5b505afa158015612b76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9a919061451f565b10156109725760405162461bcd60e51b81526004016106ff90614997565b600080612bc36113a1565b90506000612bcf610ef5565b905086612beb57612be6828963ffffffff6124ab16565b612bfb565b612bfb828963ffffffff6127a716565b915084612c1757612c12818763ffffffff6124ab16565b612c27565b612c27818763ffffffff6127a716565b90506000612c36838387613785565b9998505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9157600080fd5b505afa158015612ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc9919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614d70565b60405163121cbc4d60e11b81526001600160a01b03851690632439789a90612d149084906004016152d8565b600060405180830381600087803b158015612d2e57600080fd5b505af1158015612d42573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b0386169250639dc29fac9150612d7490859085906004016148b1565b600060405180830381600087803b158015612d8e57600080fd5b505af1158015611c2d573d6000803e3d6000fd5b612daa614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152612de2614176565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e3257600080fd5b505af1158015612e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6a919061451f565b808252612e769061337a565b15156101c08201528615612e9c57612e9384826101c00151613415565b612e9c88613ad7565b612ea589613af7565b612eaf8989613b1e565b8151612ebb908b612a55565b336001600160a01b038b161480612ef157506005546001600160a01b031633148015612ee75750600034115b8015612ef1575087155b612ef757fe5b8151604051630b07655760e01b81526001600160a01b0390911690630b07655790612f26908d9060040161485c565b600060405180830381600087803b158015612f4057600080fd5b505af1158015612f54573d6000803e3d6000fd5b50505050612f62348a613b51565b15156060830152602082015260408101889052868015612f855750806101c00151155b15612fc057612f9e826000015183604001518a876135a3565b61012082018190526040820151612fba9163ffffffff6127a716565b60408201525b815160405163d66a255360e01b81526001600160a01b039091169063d66a255390612fef908d9060040161485c565b60206040518083038186803b15801561300757600080fd5b505afa15801561301b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303f919061451f565b608082015281516040516309019aaf60e31b81526001600160a01b039091169063480cd57890613073908d9060040161485c565b60206040518083038186803b15801561308b57600080fd5b505afa15801561309f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c3919061451f565b60a08201819052608082015182516130dc929190613785565b8160c001818152505061310c8160a0015182608001518360200151846060015185604001518c8760000151613b70565b60e082015260a081015189111561311f57fe5b613130816101c001518a8984613b94565b8615801561313e5750600088115b156131855761316061315b82604001516126f08460800151613c08565b61375c565b61317281608001518260400151613c23565b61318582604001518b8360400151612b1c565b6131a382600001518b8360200151846060015185604001518c613c5b565b6101408301526101608201528151604051630c7940bd60e11b81526001600160a01b03909116906318f2817a906131de908d9060040161485c565b602060405180830381600087803b1580156131f857600080fd5b505af115801561320c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613230919061451f565b8161018001818152505061325c8160a0015182608001518360200151846060015185604001518c613e89565b6101a08201819052600b5460405163015f109360e51b81526001600160a01b0390911691632be2126091613298918e918b908b906004016148ca565b600060405180830381600087803b1580156132b257600080fd5b505af11580156132c6573d6000803e3d6000fd5b50505050896001600160a01b031660008051602061533783398151915282610140015183610160015184610180015160026040516133079493929190614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc002274182610120015160405161334d91906152d8565b60405180910390a261249f8260200151836040015133846020015185606001518d8d88604001518b613eba565b60008061338683613f5e565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133d657600080fd5b505afa1580156133ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061340e919061451f565b1192915050565b801561344857670de0b6b3a76400008211156134435760405162461bcd60e51b81526004016106ff90614c71565b610989565b600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561349657600080fd5b505afa1580156134aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ce919061451f565b82101580156134e55750670de0b6b3a76400008211155b6109895760405162461bcd60e51b81526004016106ff906150c5565b6040516321e3780160e01b81526000906001600160a01b038416906321e378019061353090859060040161485c565b60206040518083038186803b15801561354857600080fd5b505afa15801561355c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613580919061451f565b905080600114156109725760405162461bcd60e51b81526004016106ff90615115565b6000846001600160a01b0316635dba4c4a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135e057600080fd5b505af11580156135f4573d6000803e3d6000fd5b5050604051630631203b60e41b8152600092506001600160a01b038816915063631203b0906136279087906004016152d8565b60206040518083038186803b15801561363f57600080fd5b505afa158015613653573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613677919061451f565b9050613684818585613f8a565b600d546040516340c10f1960e01b81526001600160a01b03878116926340c10f19926136b8929091169085906004016148b1565b600060405180830381600087803b1580156136d257600080fd5b505af11580156136e6573d6000803e3d6000fd5b50505050600d60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561373a57600080fd5b505af115801561374e573d6000803e3d6000fd5b509298975050505050505050565b6809c2007651b25000008110156107115760405162461bcd60e51b81526004016106ff90614f81565b600082156137b85760006137af846137a3878663ffffffff613fca16565b9063ffffffff61400416565b91506137bd9050565b506000195b9392505050565b600081156137f0576137e9826137a38568056bc75e2d6310000063ffffffff613fca16565b90506124f0565b506000196124f0565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561384757600080fd5b505afa15801561385b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387f919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614be3565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156138ec57600080fd5b505afa158015613900573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613924919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614f12565b6000826001600160a01b03168260405161395c9061483c565b60006040518083038185875af1925050503d8060008114613999576040519150601f19603f3d011682016040523d82523d6000602084013e61399e565b606091505b50509050806109725760405162461bcd60e51b81526004016106ff906149f4565b60405163f2e91d7160e01b81526001600160a01b0386169063f2e91d71906139eb9084906004016152d8565b600060405180830381600087803b158015613a0557600080fd5b505af1158015613a19573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b03871692506340c10f199150613a4b90869086906004016148b1565b600060405180830381600087803b158015613a6557600080fd5b505af1158015610df9573d6000803e3d6000fd5b60008184841115613a9d5760405162461bcd60e51b81526004016106ff9190614944565b505050900390565b613aad6141f0565b613ab56141f0565b5050604080518082019091526001600160a01b03929092168252602082015290565b600081116107115760405162461bcd60e51b81526004016106ff9061514c565b341580613b02575080155b6107115760405162461bcd60e51b81526004016106ff90614b3a565b34151580613b2b57508115155b80613b3557508015155b6109895760405162461bcd60e51b81526004016106ff90614cc3565b6000808315613b6557508290506001613b69565b8291505b9250929050565b6000806000613b838a8a8a8a8a8a614046565b915091506000612a0a838387613785565b8315613bcd57613ba38361409c565b8115613bc857613bb68160e001516137f9565b613bc88160e001518260c001516140ba565b610725565b613bda8160e0015161389e565b613bf7816020015182606001518360400151858560000151612bb8565b610100820181905261072590612c43565b6000610959826801158e460913d0000063ffffffff6124ab16565b613c3c826801158e460913d0000063ffffffff6124ab16565b8111156109895760405162461bcd60e51b81526004016106ff90615013565b600080600085613cea5760405163d3d6f84360e01b81526001600160a01b038a169063d3d6f84390613c93908b908b906004016148b1565b602060405180830381600087803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce5919061451f565b613d6a565b6040516372423c1760e01b81526001600160a01b038a16906372423c1790613d18908b908b906004016148b1565b602060405180830381600087803b158015613d3257600080fd5b505af1158015613d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d6a919061451f565b9050600084613df857604051630930874960e11b81526001600160a01b038b16906312610e9290613da1908c908a906004016148b1565b602060405180830381600087803b158015613dbb57600080fd5b505af1158015613dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df3919061451f565b613e78565b604051639976cf4560e01b81526001600160a01b038b1690639976cf4590613e26908c908a906004016148b1565b602060405180830381600087803b158015613e4057600080fd5b505af1158015613e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e78919061451f565b919a91995090975050505050505050565b6000806000613e9c898989898989614046565b915091506000613eac83836137c4565b9a9950505050505050505050565b8215613ed257613ecd89898387866139bf565b613ede565b613ede89898987612ce8565b8415613ef357613eee8987613943565b610df9565b6040516364a197f360e01b81526001600160a01b038a16906364a197f390613f21908a908a906004016148b1565b600060405180830381600087803b158015613f3b57600080fd5b505af1158015613f4f573d6000803e3d6000fd5b50505050505050505050505050565b600080613f696113a1565b90506000613f75610ef5565b9050613f82828286613785565b949350505050565b6000613fa8836137a386670de0b6b3a764000063ffffffff613fca16565b9050818111156107255760405162461bcd60e51b81526004016106ff90615200565b600082613fd9575060006124f0565b82820282848281613fe657fe5b04146124ed5760405162461bcd60e51b81526004016106ff90614d2f565b60006124ed83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506140da565b600080878786614065576140608a8963ffffffff6124ab16565b614075565b6140758a8963ffffffff6127a716565b91508461408c57613df3898763ffffffff6124ab16565b613e78898763ffffffff6127a716565b80156107115760405162461bcd60e51b81526004016106ff90614e5e565b808210156109895760405162461bcd60e51b81526004016106ff906151a3565b600081836140fb5760405162461bcd60e51b81526004016106ff9190614944565b50600083858161410757fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806101e00160405280600081526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b80356124f081615313565b60008083601f840112614223578182fd5b50813567ffffffffffffffff81111561423a578182fd5b602083019150836020828501011115613b6957600080fd5b600060808284031215614263578081fd5b50919050565b6000818303608081121561427b578182fd5b61428560606152e1565b9150604081121561429557600080fd5b506142a060406152e1565b82356142ab81615313565b808252506020830135602082015280825250604082013560208201526060820135604082015292915050565b6000602082840312156142e8578081fd5b81356124ed81615313565b600060208284031215614304578081fd5b81516124ed81615313565b60008060408385031215614321578081fd5b823561432c81615313565b9150602083013561433c81615313565b809150509250929050565b60008060006060848603121561435b578081fd5b833561436681615313565b9250602084013561437681615313565b9150604084013561438681615313565b809150509250925092565b6000806000806000806000806000806000806101808d8f0312156143b3578788fd5b8c356143be81615313565b9b5060208d01356143ce81615313565b9a5060408d01356143de81615313565b995060608d01356143ee81615313565b985060808d01356143fe81615313565b975060a08d013561440e81615313565b965061441d8e60c08f01614207565b955061442c8e60e08f01614207565b945061443c8e6101008f01614207565b935061444c8e6101208f01614207565b925061445c8e6101408f01614207565b915061446c8e6101608f01614207565b90509295989b509295989b509295989b565b60006020828403121561448f578081fd5b81516124ed81615328565b6000608082840312156144ab578081fd5b6124ed8383614252565b600080600060a084860312156144c9578283fd5b6144d38585614269565b9250608084013567ffffffffffffffff8111156144ee578283fd5b6144fa86828701614212565b9497909650939450505050565b600060208284031215614518578081fd5b5035919050565b600060208284031215614530578081fd5b5051919050565b60008060006060848603121561454b578283fd5b83359250602084013561437681615313565b60008060008060e08587031215614572578182fd5b84359350602085013561458481615313565b9250604085013561459481615313565b91506145a38660608701614252565b905092959194509250565b60008060008060008061010087890312156145c7578384fd5b8635955060208701356145d981615313565b945060408701356145e981615313565b93506145f88860608901614269565b925060e087013567ffffffffffffffff811115614613578283fd5b61461f89828a01614212565b979a9699509497509295939492505050565b60008060008060808587031215614646578182fd5b8435935060208501359250604085013561465f81615313565b9150606085013561466f81615313565b939692955090935050565b60008060008060008060c08789031215614692578384fd5b86359550602087013594506040870135935060608701356146b281615328565b925060808701356146c281615313565b915060a08701356146d281615313565b809150509295509295509295565b6000806000806000806000610140888a0312156146fb578081fd5b873596506020880135955060408801359450606088013561471b81615328565b9350608088013561472b81615313565b925060a088013561473b81615313565b915061474a8960c08a01614252565b905092959891949750929550565b60008060008060008060008060006101608a8c031215614776578283fd5b8935985060208a0135975060408a0135965060608a013561479681615328565b955060808a01356147a681615313565b945060a08a01356147b681615313565b93506147c58b60c08c01614269565b92506101408a013567ffffffffffffffff8111156147e1578283fd5b6147ed8c828d01614212565b8194508093505050509295985092959850929598565b600060208284031215614814578081fd5b813560ff811681146124ed578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b84815260208101849052604081018390526080810161493683615308565b606083015295945050505050565b6000602080835283518082850152825b8181101561497057858101830151858201604001528201614954565b818111156149815783604083870101525b50601f01601f1916929092016040019392505050565b6020808252603d908201527f426f72726f7765724f70733a2043616c6c657220646f65736e7420686176652060408201527f656e6f756768205a55534420746f206d616b652072657061796d656e74000000606082015260800190565b6020808252602d908201527f426f72726f7765724f70733a2053656e64696e672045544820746f204163746960408201526c1d99541bdbdb0819985a5b1959609a1b606082015260800190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f5a555344206973206e6f7420626f72726f77656420636f72726563746c790000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60208082526030908201527f426f72726f7765724f7065726174696f6e733a2043616e6e6f7420776974686460408201526f1c985dc8185b99081859190818dbdb1b60821b606082015260800190565b60208082526039908201527f426f72726f7765724f70733a204f7065726174696f6e206e6f74207065726d696040820152787474656420647572696e67205265636f76657279204d6f646560381b606082015260800190565b60208082526037908201527f426f72726f7765724f70733a204f7065726174696f6e206d757374206c65617660408201527632903a3937bb32903bb4ba341024a1a9101f1e9021a1a960491b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526032908201527f4d6178206665652070657263656e74616765206d757374206c657373207468616040820152716e206f7220657175616c20746f203130302560701b606082015260800190565b60208082526046908201527f426f72726f7765724f70733a205468657265206d75737420626520656974686560408201527f72206120636f6c6c61746572616c206368616e6765206f7220612064656274206060820152656368616e676560d01b608082015260a00190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20544352203c20434352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252602e908201527f426f72726f7765724f70733a2054726f766520646f6573206e6f74206578697360408201526d1d081bdc881a5cc818db1bdcd95960921b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252603e908201527f426f72726f7765724f70733a20436f6c6c61746572616c20776974686472617760408201527f616c206e6f74207065726d6974746564205265636f76657279204d6f64650000606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20494352203c204d4352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252603a908201527f426f72726f7765724f70733a2054726f76652773206e65742064656274206d7560408201527f73742062652067726561746572207468616e206d696e696d756d000000000000606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526043908201527f426f72726f7765724f70733a20416d6f756e7420726570616964206d7573742060408201527f6e6f74206265206c6172676572207468616e207468652054726f76652773206460608201526219589d60ea1b608082015260a00190565b60208082526029908201527f426f72726f7765724f70733a2043616c6c6572206973206e6f742053746162696040820152681b1a5d1e48141bdbdb60ba1b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252601c908201527f426f72726f7765724f70733a2054726f76652069732061637469766500000000604082015260600190565b60208082526037908201527f426f72726f7765724f70733a204465627420696e637265617365207265717569604082015276726573206e6f6e2d7a65726f20646562744368616e676560481b606082015260800190565b6020808252603e908201527f426f72726f7765724f70733a2043616e6e6f7420646563726561736520796f7560408201527f722054726f766527732049435220696e205265636f76657279204d6f64650000606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b60208082526016908201527513585cdcd95d081859191c995cdcc81b9bdd081cd95d60521b604082015260600190565b6000610100615277838951614824565b60208801516040840152604088015160608401526152986080840188614824565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b60405181810167ffffffffffffffff8111828210171561530057600080fd5b604052919050565b806003811061095c57fe5b6001600160a01b038116811461071157600080fd5b801515811461071157600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212209d20681b7b6630050fbad5344b16d370ece553865b2bf0ccb789b394933ed00f64736f6c634300060b0033", + "deployedBytecode": "0x60806040526004361061025c5760003560e01c80637778a3db11610144578063a20baee6116100b6578063c6a6cf201161007a578063c6a6cf2014610601578063e9fc346114610614578063ea9638bf14610629578063ec5472fd1461063c578063ec9f7d4614610651578063f92d3433146106665761025c565b8063a20baee614610414578063a3f4df7e14610595578063ae918754146105b7578063afbc74b5146105cc578063b5c89bab146105ec5761025c565b8063860665b311610108578063860665b314610510578063887105d314610523578063893d20e814610538578063899fe15e1461054d5780638d5c3dc11461056d5780639f070670146105805761025c565b80637778a3db14610486578063795d26c3146104a65780637d4f595d146104bb5780637e3eefdc146104db5780637f7dde4a146104fb5761025c565b8063485f190f116101dd5780636f0b0c1c116101a15780636f0b0c1c146103ff57806372fe25aa14610414578063734f622d14610429578063741bef1a14610449578063759b30341461045e578063763a0ef3146104735761025c565b8063485f190f146103795780634ff814431461038c5780635530273c146103ac57806368647db1146103cc5780636ea56960146103df5761025c565b80631a777717116102245780631a777717146102ed5780631bf435551461030d5780632771510a1461032f5780633cc742251461034f5780633d83908a146103645761025c565b80630d43e8ad146102615780630e704d501461028c5780630ff9a512146102a357806312261ee7146102b857806313af4035146102cd575b600080fd5b34801561026d57600080fd5b5061027661067b565b604051610283919061485c565b60405180910390f35b34801561029857600080fd5b506102a161068a565b005b3480156102af57600080fd5b50610276610694565b3480156102c457600080fd5b506102766106a3565b3480156102d957600080fd5b506102a16102e83660046142d7565b6106c7565b3480156102f957600080fd5b506102a161030836600461455d565b610714565b34801561031957600080fd5b5061032261072b565b60405161028391906152d8565b34801561033b57600080fd5b506102a161034a3660046142d7565b610738565b34801561035b57600080fd5b506102766107c6565b34801561037057600080fd5b506102766107d5565b6102a1610387366004614631565b6107e4565b34801561039857600080fd5b506103226103a7366004614507565b61094e565b3480156103b857600080fd5b506102a16103c7366004614537565b610961565b6102a16103da36600461430f565b610977565b3480156103eb57600080fd5b506102a16103fa366004614631565b61098d565b34801561040b57600080fd5b506102a161099e565b34801561042057600080fd5b506103226109fc565b34801561043557600080fd5b506102a1610444366004614391565b610a08565b34801561045557600080fd5b50610276610dcc565b34801561046a57600080fd5b50610322610ddb565b6102a1610481366004614758565b610de8565b34801561049257600080fd5b506102a16104a136600461449a565b610e04565b3480156104b257600080fd5b50610322610ef5565b3480156104c757600080fd5b506102a16104d63660046144b5565b611014565b3480156104e757600080fd5b506103226104f6366004614631565b61110a565b34801561050757600080fd5b50610276611385565b6102a161051e366004614631565b611394565b34801561052f57600080fd5b506103226113a1565b34801561054457600080fd5b50610276611470565b34801561055957600080fd5b506102a16105683660046145ae565b61148f565b6102a161057b3660046146e0565b6114aa565b34801561058c57600080fd5b506102766114c2565b3480156105a157600080fd5b506105aa6114d1565b6040516102839190614944565b3480156105c357600080fd5b506102766114ff565b3480156105d857600080fd5b506102a16105e7366004614537565b61150e565b3480156105f857600080fd5b50610276611520565b6102a161060f36600461467a565b61152f565b34801561062057600080fd5b5061027661153e565b6102a1610637366004614347565b61154d565b34801561064857600080fd5b50610276611567565b34801561065d57600080fd5b50610276611576565b34801561067257600080fd5b50610322611585565b600d546001600160a01b031681565b610692611607565b565b6009546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6106cf611470565b6001600160a01b0316336001600160a01b0316146107085760405162461bcd60e51b81526004016106ff90614e2d565b60405180910390fd5b610711816119f6565b50565b610725600080866000878787611a81565b50505050565b6809c2007651b250000081565b610740611470565b6001600160a01b0316336001600160a01b0316146107705760405162461bcd60e51b81526004016106ff90614e2d565b600c80546001600160a01b0319166001600160a01b0383161790556040517f6926b3375b54960080b7d8a184061f39a02e8c3bf64aa9df7e75359fdc00d814906107bb90839061485c565b60405180910390a150565b6001546001600160a01b031681565b6004546001600160a01b031681565b600c546001600160a01b031661080c5760405162461bcd60e51b81526004016106ff90615237565b6108198484848430611c37565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b39261084f9291169087906004016148b1565b602060405180830381600087803b15801561086957600080fd5b505af115801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a1919061447e565b6108bd5760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b926108f592911690879033906004016148f5565b602060405180830381600087803b15801561090f57600080fd5b505af1158015610923573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610947919061451f565b5050505050565b600061095982612262565b90505b919050565b61097233846000808686600061227d565b505050565b6109893360008060008686600061227d565b5050565b61072533600085600186868a61227d565b60075460405163b32beb5b60e01b81526001600160a01b039091169063b32beb5b906109ce90339060040161485c565b600060405180830381600087803b1580156109e857600080fd5b505af1158015610725573d6000803e3d6000fd5b670de0b6b3a764000081565b610a10611470565b6001600160a01b0316336001600160a01b031614610a405760405162461bcd60e51b81526004016106ff90614e2d565b610a498c61228d565b610a528b61228d565b610a5b8a61228d565b610a648961228d565b610a6d8861228d565b610a768761228d565b610a7f8661228d565b610a888561228d565b610a918461228d565b610a9a8361228d565b610aa38261228d565b610aac8161228d565b600d80546001600160a01b03199081166001600160a01b038f8116919091179092556003805482168e84161790556004805482168d84161790556000805482168c84161790556001805482168b84161790556005805482168a8416179055600680548216898416179055600780548216888416179055600280548216878416179055600b80548216868416179055600a8054821685841617905560098054821692841692831790556008805490911690911790556040517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db990610b90908e9061485c565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a56788a604051610bc7919061485c565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd88289604051610bfe919061485c565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b88604051610c35919061485c565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f87604051610c6c919061485c565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa086604051610ca3919061485c565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d85604051610cda919061485c565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db26484604051610d11919061485c565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe7880083604051610d48919061485c565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d82604051610d7f919061485c565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd81604051610db6919061485c565b60405180910390a1505050505050505050505050565b6002546001600160a01b031681565b6801158e460913d0000081565b610df98989898989898989896122d2565b505050505050505050565b600c546001600160a01b0316610e2c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a255391610e5e9133910161485c565b60206040518083038186803b158015610e7657600080fd5b505afa158015610e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eae919061451f565b600c54909150610eec906001600160a01b0316610eda836801158e460913d0000063ffffffff6124ab16565b600a546001600160a01b0316856124f6565b50610989611607565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f71919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b505afa158015610fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffb919061451f565b905061100d828263ffffffff6127a716565b9250505090565b600c546001600160a01b031661103c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a25539161106e9133910161485c565b60206040518083038186803b15801561108657600080fd5b505afa15801561109a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110be919061451f565b600c54600a54919250611101916001600160a01b039182169116867f000000000000000000000000000000000000000000000000000000000000000087876127cc565b50610725611607565b600a546040516370a0823160e01b8152600091309183916001600160a01b0316906370a082319061113f90859060040161485c565b60206040518083038186803b15801561115757600080fd5b505afa15801561116b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118f919061451f565b905061119f33838888888c612a19565b6111af818763ffffffff6127a716565b600a546040516370a0823160e01b81526001600160a01b03909116906370a08231906111df90869060040161485c565b60206040518083038186803b1580156111f757600080fd5b505afa15801561120b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122f919061451f565b1461124c5760405162461bcd60e51b81526004016106ff90614ac1565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611282929116908a906004016148b1565b602060405180830381600087803b15801561129c57600080fd5b505af11580156112b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d4919061447e565b6112f05760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611328929116908a9033906004016148f5565b602060405180830381600087803b15801561134257600080fd5b505af1158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a919061451f565b979650505050505050565b6000546001600160a01b031681565b6107258484848433611c37565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b60008060405161147f9061483f565b6040519081900390205492915050565b6114a260008088600089898989896122d2565b505050505050565b6114b987878787878787611a81565b50505050505050565b6003546001600160a01b031681565b60405180604001604052806012815260200171426f72726f7765724f7065726174696f6e7360701b81525081565b600b546001600160a01b031681565b6109723360008560008686600061227d565b600c546001600160a01b031681565b6114a23386868686868c61227d565b600c546001600160a01b031690565b611555612a2b565b6109728360008060008686600061227d565b6008546001600160a01b031681565b600a546001600160a01b031681565b6003546040805163f92d343360e01b815290516000926001600160a01b03169163f92d3433916004808301926020929190829003018186803b1580156115ca57600080fd5b505afa1580156115de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611602919061451f565b905090565b600454600054600a546001600160a01b0392831692918216911661162b8333612a55565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561167157600080fd5b505af1158015611685573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a9919061451f565b90506116b481612af6565b604051630b07655760e01b81526001600160a01b03851690630b076557906116e090339060040161485c565b600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50506040516309019aaf60e31b8152600092506001600160a01b038716915063480cd5789061174190339060040161485c565b60206040518083038186803b15801561175957600080fd5b505afa15801561176d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611791919061451f565b90506000856001600160a01b031663d66a2553336040518263ffffffff1660e01b81526004016117c1919061485c565b60206040518083038186803b1580156117d957600080fd5b505afa1580156117ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611811919061451f565b90506118368433611831846801158e460913d0000063ffffffff6124ab16565b612b1c565b600061184783600084600088612bb8565b905061185281612c43565b604051631fc5750960e31b81526001600160a01b0388169063fe2ba8489061187e90339060040161485c565b600060405180830381600087803b15801561189857600080fd5b505af11580156118ac573d6000803e3d6000fd5b50506040516365e89c5760e11b81526001600160a01b038a16925063cbd138ae91506118dc90339060040161485c565b600060405180830381600087803b1580156118f657600080fd5b505af115801561190a573d6000803e3d6000fd5b50505050336001600160a01b03166000805160206153378339815191526000806000600160405161193e9493929190614918565b60405180910390a261196a868633611965866801158e460913d0000063ffffffff6124ab16565b612ce8565b60065461198d90879087906001600160a01b03166801158e460913d00000612ce8565b6040516364a197f360e01b81526001600160a01b038716906364a197f3906119bb90339087906004016148b1565b600060405180830381600087803b1580156119d557600080fd5b505af11580156119e9573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038116611a1c5760405162461bcd60e51b81526004016106ff90614af8565b806001600160a01b0316611a2e611470565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611a719061483f565b6040519081900390209190915550565b600c546001600160a01b0316611aa95760405162461bcd60e51b81526004016106ff90615237565b83158015611ab75750600085115b15611add57600c54600a54611adb916001600160a01b0390811691889116846124f6565b505b611aed3387878787878d30612da2565b838015611afa5750600085115b156114b957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611b359291169089906004016148b1565b602060405180830381600087803b158015611b4f57600080fd5b505af1158015611b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b87919061447e565b611ba35760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611bdb92911690899033906004016148f5565b602060405180830381600087803b158015611bf557600080fd5b505af1158015611c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2d919061451f565b5050505050505050565b611c3f614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152611c77614131565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611cc757600080fd5b505af1158015611cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cff919061451f565b808252600090611d0e9061337a565b9050611d1a8882613415565b8251611d269033613501565b6040820187905280611d6757611d4683600001518460400151898b6135a3565b602083018190526040830151611d619163ffffffff6127a716565b60408301525b611d74826040015161375c565b611d818260400151612262565b60608301819052611d8e57fe5b611da13483606001518460000151613785565b60808301526060820151611db69034906137c4565b60a08301528015611dd357611dce82608001516137f9565b611e06565b611de0826080015161389e565b6000611df9346001856060015160018760000151612bb8565b9050611e0481612c43565b505b8251604051635d6b480f60e01b81526001600160a01b0390911690635d6b480f90611e389033906001906004016148b1565b600060405180830381600087803b158015611e5257600080fd5b505af1158015611e66573d6000803e3d6000fd5b505084516040516372423c1760e01b81526001600160a01b0390911692506372423c179150611e9b90339034906004016148b1565b602060405180830381600087803b158015611eb557600080fd5b505af1158015611ec9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eed919061451f565b5082516060830151604051639976cf4560e01b81526001600160a01b0390921691639976cf4591611f23913391906004016148b1565b602060405180830381600087803b158015611f3d57600080fd5b505af1158015611f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f75919061451f565b5082516040516382fe3eb960e01b81526001600160a01b03909116906382fe3eb990611fa590339060040161485c565b600060405180830381600087803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b50508451604051630c7940bd60e11b81526001600160a01b0390911692506318f2817a915061200690339060040161485c565b602060405180830381600087803b15801561202057600080fd5b505af1158015612034573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612058919061451f565b60c0830152600b5460a08301516040516346f7cf8760e01b81526001600160a01b03909216916346f7cf8791612097913391908b908b906004016148ca565b600060405180830381600087803b1580156120b157600080fd5b505af11580156120c5573d6000803e3d6000fd5b505084516040516315d549f160e01b81526001600160a01b0390911692506315d549f191506120f890339060040161485c565b602060405180830381600087803b15801561211257600080fd5b505af1158015612126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214a919061451f565b60e0830181905260405133917f59cfd0cd754bc5748b6770e94a4ffa5f678d885cb899dcfadc5734edb97c67ab9161218291906152d8565b60405180910390a2612198836020015134613943565b6121b183602001518460400151868a86604001516139bf565b602083015160408401516006546121dd9291906001600160a01b03166801158e460913d00000806139bf565b606082015160c083015160405133926000805160206153378339815191529261220b92349190600090614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc0022741836020015160405161225091906152d8565b60405180910390a25050505050505050565b6000610959826801158e460913d0000063ffffffff6127a716565b6114b98787878787878733612da2565b6001600160a01b0381166122b35760405162461bcd60e51b81526004016106ff90614c3a565b803b806109895760405162461bcd60e51b81526004016106ff90614fde565b600c546001600160a01b03166122fa5760405162461bcd60e51b81526004016106ff90615237565b851580156123085750600087115b1561234f57600c54600a5461234d916001600160a01b039081169116857f000000000000000000000000000000000000000000000000000000000000000086866127cc565b505b61235f3389898989898f30612da2565b85801561236c5750600087115b15610df957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b3926123a7929116908b906004016148b1565b602060405180830381600087803b1580156123c157600080fd5b505af11580156123d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f9919061447e565b6124155760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b9261244d929116908b9033906004016148f5565b602060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f919061451f565b50505050505050505050565b60006124ed83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a79565b90505b92915050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561253257600080fd5b505afa158015612546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061256a91906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161259a919061485c565b60206040518083038186803b1580156125b257600080fd5b505afa1580156125c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ea919061451f565b9050306001600160a01b03831663605629d633838a893561261160408c0160208d01614803565b8b604001358c606001356040518863ffffffff1660e01b815260040161263d9796959493929190614870565b600060405180830381600087803b15801561265757600080fd5b505af115801561266b573d6000803e3d6000fd5b50505050866126fc83856001600160a01b03166370a08231856040518263ffffffff1660e01b81526004016126a0919061485c565b60206040518083038186803b1580156126b857600080fd5b505afa1580156126cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f0919061451f565b9063ffffffff6124ab16565b146127195760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c9223906127499089908b9033906004016148f5565b602060405180830381600087803b15801561276357600080fd5b505af1158015612777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279b919061451f565b98975050505050505050565b6000828201838110156124ed5760405162461bcd60e51b81526004016106ff90614a8a565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284091906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612870919061485c565b60206040518083038186803b15801561288857600080fd5b505afa15801561289c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c0919061451f565b87516020015190915030906001600160a01b0388166330f28b7a8a6128e58585613aa5565b338b8b6040518663ffffffff1660e01b8152600401612908959493929190615267565b600060405180830381600087803b15801561292257600080fd5b505af1158015612936573d6000803e3d6000fd5b505050508061296b84866001600160a01b03166370a08231866040518263ffffffff1660e01b81526004016126a0919061485c565b146129885760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c9223906129b8908d90859033906004016148f5565b602060405180830381600087803b1580156129d257600080fd5b505af11580156129e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0a919061451f565b9b9a5050505050505050505050565b6114a28660008660018787878c612da2565b6005546001600160a01b031633146106925760405162461bcd60e51b81526004016106ff9061507c565b6040516321e3780160e01b81526000906001600160a01b038416906321e3780190612a8490859060040161485c565b60206040518083038186803b158015612a9c57600080fd5b505afa158015612ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad4919061451f565b9050806001146109725760405162461bcd60e51b81526004016106ff90614ddf565b612aff8161337a565b156107115760405162461bcd60e51b81526004016106ff90614b8a565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190612b4a90869060040161485c565b60206040518083038186803b158015612b6257600080fd5b505afa158015612b76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9a919061451f565b10156109725760405162461bcd60e51b81526004016106ff90614997565b600080612bc36113a1565b90506000612bcf610ef5565b905086612beb57612be6828963ffffffff6124ab16565b612bfb565b612bfb828963ffffffff6127a716565b915084612c1757612c12818763ffffffff6124ab16565b612c27565b612c27818763ffffffff6127a716565b90506000612c36838387613785565b9998505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9157600080fd5b505afa158015612ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc9919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614d70565b60405163121cbc4d60e11b81526001600160a01b03851690632439789a90612d149084906004016152d8565b600060405180830381600087803b158015612d2e57600080fd5b505af1158015612d42573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b0386169250639dc29fac9150612d7490859085906004016148b1565b600060405180830381600087803b158015612d8e57600080fd5b505af1158015611c2d573d6000803e3d6000fd5b612daa614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152612de2614176565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e3257600080fd5b505af1158015612e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6a919061451f565b808252612e769061337a565b15156101c08201528615612e9c57612e9384826101c00151613415565b612e9c88613ad7565b612ea589613af7565b612eaf8989613b1e565b8151612ebb908b612a55565b336001600160a01b038b161480612ef157506005546001600160a01b031633148015612ee75750600034115b8015612ef1575087155b612ef757fe5b8151604051630b07655760e01b81526001600160a01b0390911690630b07655790612f26908d9060040161485c565b600060405180830381600087803b158015612f4057600080fd5b505af1158015612f54573d6000803e3d6000fd5b50505050612f62348a613b51565b15156060830152602082015260408101889052868015612f855750806101c00151155b15612fc057612f9e826000015183604001518a876135a3565b61012082018190526040820151612fba9163ffffffff6127a716565b60408201525b815160405163d66a255360e01b81526001600160a01b039091169063d66a255390612fef908d9060040161485c565b60206040518083038186803b15801561300757600080fd5b505afa15801561301b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303f919061451f565b608082015281516040516309019aaf60e31b81526001600160a01b039091169063480cd57890613073908d9060040161485c565b60206040518083038186803b15801561308b57600080fd5b505afa15801561309f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c3919061451f565b60a08201819052608082015182516130dc929190613785565b8160c001818152505061310c8160a0015182608001518360200151846060015185604001518c8760000151613b70565b60e082015260a081015189111561311f57fe5b613130816101c001518a8984613b94565b8615801561313e5750600088115b156131855761316061315b82604001516126f08460800151613c08565b61375c565b61317281608001518260400151613c23565b61318582604001518b8360400151612b1c565b6131a382600001518b8360200151846060015185604001518c613c5b565b6101408301526101608201528151604051630c7940bd60e11b81526001600160a01b03909116906318f2817a906131de908d9060040161485c565b602060405180830381600087803b1580156131f857600080fd5b505af115801561320c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613230919061451f565b8161018001818152505061325c8160a0015182608001518360200151846060015185604001518c613e89565b6101a08201819052600b5460405163015f109360e51b81526001600160a01b0390911691632be2126091613298918e918b908b906004016148ca565b600060405180830381600087803b1580156132b257600080fd5b505af11580156132c6573d6000803e3d6000fd5b50505050896001600160a01b031660008051602061533783398151915282610140015183610160015184610180015160026040516133079493929190614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc002274182610120015160405161334d91906152d8565b60405180910390a261249f8260200151836040015133846020015185606001518d8d88604001518b613eba565b60008061338683613f5e565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133d657600080fd5b505afa1580156133ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061340e919061451f565b1192915050565b801561344857670de0b6b3a76400008211156134435760405162461bcd60e51b81526004016106ff90614c71565b610989565b600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561349657600080fd5b505afa1580156134aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ce919061451f565b82101580156134e55750670de0b6b3a76400008211155b6109895760405162461bcd60e51b81526004016106ff906150c5565b6040516321e3780160e01b81526000906001600160a01b038416906321e378019061353090859060040161485c565b60206040518083038186803b15801561354857600080fd5b505afa15801561355c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613580919061451f565b905080600114156109725760405162461bcd60e51b81526004016106ff90615115565b6000846001600160a01b0316635dba4c4a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135e057600080fd5b505af11580156135f4573d6000803e3d6000fd5b5050604051630631203b60e41b8152600092506001600160a01b038816915063631203b0906136279087906004016152d8565b60206040518083038186803b15801561363f57600080fd5b505afa158015613653573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613677919061451f565b9050613684818585613f8a565b600d546040516340c10f1960e01b81526001600160a01b03878116926340c10f19926136b8929091169085906004016148b1565b600060405180830381600087803b1580156136d257600080fd5b505af11580156136e6573d6000803e3d6000fd5b50505050600d60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561373a57600080fd5b505af115801561374e573d6000803e3d6000fd5b509298975050505050505050565b6809c2007651b25000008110156107115760405162461bcd60e51b81526004016106ff90614f81565b600082156137b85760006137af846137a3878663ffffffff613fca16565b9063ffffffff61400416565b91506137bd9050565b506000195b9392505050565b600081156137f0576137e9826137a38568056bc75e2d6310000063ffffffff613fca16565b90506124f0565b506000196124f0565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561384757600080fd5b505afa15801561385b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387f919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614be3565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156138ec57600080fd5b505afa158015613900573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613924919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614f12565b6000826001600160a01b03168260405161395c9061483c565b60006040518083038185875af1925050503d8060008114613999576040519150601f19603f3d011682016040523d82523d6000602084013e61399e565b606091505b50509050806109725760405162461bcd60e51b81526004016106ff906149f4565b60405163f2e91d7160e01b81526001600160a01b0386169063f2e91d71906139eb9084906004016152d8565b600060405180830381600087803b158015613a0557600080fd5b505af1158015613a19573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b03871692506340c10f199150613a4b90869086906004016148b1565b600060405180830381600087803b158015613a6557600080fd5b505af1158015610df9573d6000803e3d6000fd5b60008184841115613a9d5760405162461bcd60e51b81526004016106ff9190614944565b505050900390565b613aad6141f0565b613ab56141f0565b5050604080518082019091526001600160a01b03929092168252602082015290565b600081116107115760405162461bcd60e51b81526004016106ff9061514c565b341580613b02575080155b6107115760405162461bcd60e51b81526004016106ff90614b3a565b34151580613b2b57508115155b80613b3557508015155b6109895760405162461bcd60e51b81526004016106ff90614cc3565b6000808315613b6557508290506001613b69565b8291505b9250929050565b6000806000613b838a8a8a8a8a8a614046565b915091506000612a0a838387613785565b8315613bcd57613ba38361409c565b8115613bc857613bb68160e001516137f9565b613bc88160e001518260c001516140ba565b610725565b613bda8160e0015161389e565b613bf7816020015182606001518360400151858560000151612bb8565b610100820181905261072590612c43565b6000610959826801158e460913d0000063ffffffff6124ab16565b613c3c826801158e460913d0000063ffffffff6124ab16565b8111156109895760405162461bcd60e51b81526004016106ff90615013565b600080600085613cea5760405163d3d6f84360e01b81526001600160a01b038a169063d3d6f84390613c93908b908b906004016148b1565b602060405180830381600087803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce5919061451f565b613d6a565b6040516372423c1760e01b81526001600160a01b038a16906372423c1790613d18908b908b906004016148b1565b602060405180830381600087803b158015613d3257600080fd5b505af1158015613d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d6a919061451f565b9050600084613df857604051630930874960e11b81526001600160a01b038b16906312610e9290613da1908c908a906004016148b1565b602060405180830381600087803b158015613dbb57600080fd5b505af1158015613dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df3919061451f565b613e78565b604051639976cf4560e01b81526001600160a01b038b1690639976cf4590613e26908c908a906004016148b1565b602060405180830381600087803b158015613e4057600080fd5b505af1158015613e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e78919061451f565b919a91995090975050505050505050565b6000806000613e9c898989898989614046565b915091506000613eac83836137c4565b9a9950505050505050505050565b8215613ed257613ecd89898387866139bf565b613ede565b613ede89898987612ce8565b8415613ef357613eee8987613943565b610df9565b6040516364a197f360e01b81526001600160a01b038a16906364a197f390613f21908a908a906004016148b1565b600060405180830381600087803b158015613f3b57600080fd5b505af1158015613f4f573d6000803e3d6000fd5b50505050505050505050505050565b600080613f696113a1565b90506000613f75610ef5565b9050613f82828286613785565b949350505050565b6000613fa8836137a386670de0b6b3a764000063ffffffff613fca16565b9050818111156107255760405162461bcd60e51b81526004016106ff90615200565b600082613fd9575060006124f0565b82820282848281613fe657fe5b04146124ed5760405162461bcd60e51b81526004016106ff90614d2f565b60006124ed83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506140da565b600080878786614065576140608a8963ffffffff6124ab16565b614075565b6140758a8963ffffffff6127a716565b91508461408c57613df3898763ffffffff6124ab16565b613e78898763ffffffff6127a716565b80156107115760405162461bcd60e51b81526004016106ff90614e5e565b808210156109895760405162461bcd60e51b81526004016106ff906151a3565b600081836140fb5760405162461bcd60e51b81526004016106ff9190614944565b50600083858161410757fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806101e00160405280600081526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b80356124f081615313565b60008083601f840112614223578182fd5b50813567ffffffffffffffff81111561423a578182fd5b602083019150836020828501011115613b6957600080fd5b600060808284031215614263578081fd5b50919050565b6000818303608081121561427b578182fd5b61428560606152e1565b9150604081121561429557600080fd5b506142a060406152e1565b82356142ab81615313565b808252506020830135602082015280825250604082013560208201526060820135604082015292915050565b6000602082840312156142e8578081fd5b81356124ed81615313565b600060208284031215614304578081fd5b81516124ed81615313565b60008060408385031215614321578081fd5b823561432c81615313565b9150602083013561433c81615313565b809150509250929050565b60008060006060848603121561435b578081fd5b833561436681615313565b9250602084013561437681615313565b9150604084013561438681615313565b809150509250925092565b6000806000806000806000806000806000806101808d8f0312156143b3578788fd5b8c356143be81615313565b9b5060208d01356143ce81615313565b9a5060408d01356143de81615313565b995060608d01356143ee81615313565b985060808d01356143fe81615313565b975060a08d013561440e81615313565b965061441d8e60c08f01614207565b955061442c8e60e08f01614207565b945061443c8e6101008f01614207565b935061444c8e6101208f01614207565b925061445c8e6101408f01614207565b915061446c8e6101608f01614207565b90509295989b509295989b509295989b565b60006020828403121561448f578081fd5b81516124ed81615328565b6000608082840312156144ab578081fd5b6124ed8383614252565b600080600060a084860312156144c9578283fd5b6144d38585614269565b9250608084013567ffffffffffffffff8111156144ee578283fd5b6144fa86828701614212565b9497909650939450505050565b600060208284031215614518578081fd5b5035919050565b600060208284031215614530578081fd5b5051919050565b60008060006060848603121561454b578283fd5b83359250602084013561437681615313565b60008060008060e08587031215614572578182fd5b84359350602085013561458481615313565b9250604085013561459481615313565b91506145a38660608701614252565b905092959194509250565b60008060008060008061010087890312156145c7578384fd5b8635955060208701356145d981615313565b945060408701356145e981615313565b93506145f88860608901614269565b925060e087013567ffffffffffffffff811115614613578283fd5b61461f89828a01614212565b979a9699509497509295939492505050565b60008060008060808587031215614646578182fd5b8435935060208501359250604085013561465f81615313565b9150606085013561466f81615313565b939692955090935050565b60008060008060008060c08789031215614692578384fd5b86359550602087013594506040870135935060608701356146b281615328565b925060808701356146c281615313565b915060a08701356146d281615313565b809150509295509295509295565b6000806000806000806000610140888a0312156146fb578081fd5b873596506020880135955060408801359450606088013561471b81615328565b9350608088013561472b81615313565b925060a088013561473b81615313565b915061474a8960c08a01614252565b905092959891949750929550565b60008060008060008060008060006101608a8c031215614776578283fd5b8935985060208a0135975060408a0135965060608a013561479681615328565b955060808a01356147a681615313565b945060a08a01356147b681615313565b93506147c58b60c08c01614269565b92506101408a013567ffffffffffffffff8111156147e1578283fd5b6147ed8c828d01614212565b8194508093505050509295985092959850929598565b600060208284031215614814578081fd5b813560ff811681146124ed578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b84815260208101849052604081018390526080810161493683615308565b606083015295945050505050565b6000602080835283518082850152825b8181101561497057858101830151858201604001528201614954565b818111156149815783604083870101525b50601f01601f1916929092016040019392505050565b6020808252603d908201527f426f72726f7765724f70733a2043616c6c657220646f65736e7420686176652060408201527f656e6f756768205a55534420746f206d616b652072657061796d656e74000000606082015260800190565b6020808252602d908201527f426f72726f7765724f70733a2053656e64696e672045544820746f204163746960408201526c1d99541bdbdb0819985a5b1959609a1b606082015260800190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f5a555344206973206e6f7420626f72726f77656420636f72726563746c790000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60208082526030908201527f426f72726f7765724f7065726174696f6e733a2043616e6e6f7420776974686460408201526f1c985dc8185b99081859190818dbdb1b60821b606082015260800190565b60208082526039908201527f426f72726f7765724f70733a204f7065726174696f6e206e6f74207065726d696040820152787474656420647572696e67205265636f76657279204d6f646560381b606082015260800190565b60208082526037908201527f426f72726f7765724f70733a204f7065726174696f6e206d757374206c65617660408201527632903a3937bb32903bb4ba341024a1a9101f1e9021a1a960491b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526032908201527f4d6178206665652070657263656e74616765206d757374206c657373207468616040820152716e206f7220657175616c20746f203130302560701b606082015260800190565b60208082526046908201527f426f72726f7765724f70733a205468657265206d75737420626520656974686560408201527f72206120636f6c6c61746572616c206368616e6765206f7220612064656274206060820152656368616e676560d01b608082015260a00190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20544352203c20434352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252602e908201527f426f72726f7765724f70733a2054726f766520646f6573206e6f74206578697360408201526d1d081bdc881a5cc818db1bdcd95960921b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252603e908201527f426f72726f7765724f70733a20436f6c6c61746572616c20776974686472617760408201527f616c206e6f74207065726d6974746564205265636f76657279204d6f64650000606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20494352203c204d4352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252603a908201527f426f72726f7765724f70733a2054726f76652773206e65742064656274206d7560408201527f73742062652067726561746572207468616e206d696e696d756d000000000000606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526043908201527f426f72726f7765724f70733a20416d6f756e7420726570616964206d7573742060408201527f6e6f74206265206c6172676572207468616e207468652054726f76652773206460608201526219589d60ea1b608082015260a00190565b60208082526029908201527f426f72726f7765724f70733a2043616c6c6572206973206e6f742053746162696040820152681b1a5d1e48141bdbdb60ba1b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252601c908201527f426f72726f7765724f70733a2054726f76652069732061637469766500000000604082015260600190565b60208082526037908201527f426f72726f7765724f70733a204465627420696e637265617365207265717569604082015276726573206e6f6e2d7a65726f20646562744368616e676560481b606082015260800190565b6020808252603e908201527f426f72726f7765724f70733a2043616e6e6f7420646563726561736520796f7560408201527f722054726f766527732049435220696e205265636f76657279204d6f64650000606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b60208082526016908201527513585cdcd95d081859191c995cdcc81b9bdd081cd95d60521b604082015260600190565b6000610100615277838951614824565b60208801516040840152604088015160608401526152986080840188614824565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b60405181810167ffffffffffffffff8111828210171561530057600080fd5b604052919050565b806003811061095c57fe5b6001600160a01b038116811461071157600080fd5b801515811461071157600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212209d20681b7b6630050fbad5344b16d370ece553865b2bf0ccb789b394933ed00f64736f6c634300060b0033", + "implementation": "0x330ad35d02b52b6f132C3C31730Dd8F79Cb58b7E" +} diff --git a/external/deployments/rskMainnet/BorrowerOperations_Implementation.json b/external/deployments/rskMainnet/BorrowerOperations_Implementation.json new file mode 100644 index 000000000..dfcd222b8 --- /dev/null +++ b/external/deployments/rskMainnet/BorrowerOperations_Implementation.json @@ -0,0 +1,1572 @@ +{ + "address": "0xD603B4c5F7BF13a2AA510F2c625546dB4138D330", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + } + ], + "name": "CollSurplusPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + } + ], + "name": "FeeDistributorAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + } + ], + "name": "GasPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_massetManagerAddress", + "type": "address" + } + ], + "name": "MassetManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + } + ], + "name": "StabilityPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "arrayIndex", + "type": "uint256" + } + ], + "name": "TroveCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newTroveManagerAddress", + "type": "address" + } + ], + "name": "TroveManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum BorrowerOperations.BorrowerOperation", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "ZEROStakingAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDFee", + "type": "uint256" + } + ], + "name": "ZUSDBorrowingFeePaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "BORROWING_FEE_FLOOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "addColl", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "adjustNueTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "adjustNueTroveWithPermit2", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "adjustTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "claimCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "closeNueTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "closeNueTroveWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "closeTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeDistributor", + "outputs": [ + { + "internalType": "contract IFeeDistributor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + } + ], + "name": "getCompositeDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMassetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "massetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "moveETHGainToTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "openNueTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "openTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "repayZUSD", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "repayZusdFromDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "repayZusdFromDLLRWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_massetManagerAddress", + "type": "address" + } + ], + "name": "setMassetManagerAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManager", + "outputs": [ + { + "internalType": "contract ITroveManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawColl", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawZUSD", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawZusdAndConvertToDLLR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "zeroStaking", + "outputs": [ + { + "internalType": "contract IZEROStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zeroStakingAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0x330ad35d02b52b6f132C3C31730Dd8F79Cb58b7E", + "transactionIndex": 0, + "gasUsed": "5799498", + "logsBloom": "0x00000800000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000001000000000000000000000000000000000000000", + "blockHash": "0x7de331c1815635488605d3e00b15a43084f7a6002e2ddf43d01f2c61ae10f888", + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748936, + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "address": "0x330ad35d02b52b6f132C3C31730Dd8F79Cb58b7E", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x7de331c1815635488605d3e00b15a43084f7a6002e2ddf43d01f2c61ae10f888" + } + ], + "blockNumber": 4748936, + "cumulativeGasUsed": "5799498", + "status": 1, + "byzantium": true + }, + "args": ["0x000000000022d473030f116ddee9f6b43ac78ba3"], + "numDeployments": 3, + "solcInputHash": "849fadfa265e27de6fba2f2d99bdf763", + "metadata": "{\"compiler\":{\"version\":\"0.6.11+commit.5ef660b1\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_permit2\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_activePoolAddress\",\"type\":\"address\"}],\"name\":\"ActivePoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_collSurplusPoolAddress\",\"type\":\"address\"}],\"name\":\"CollSurplusPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_defaultPoolAddress\",\"type\":\"address\"}],\"name\":\"DefaultPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_feeDistributorAddress\",\"type\":\"address\"}],\"name\":\"FeeDistributorAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_gasPoolAddress\",\"type\":\"address\"}],\"name\":\"GasPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_massetManagerAddress\",\"type\":\"address\"}],\"name\":\"MassetManagerAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newPriceFeedAddress\",\"type\":\"address\"}],\"name\":\"PriceFeedAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_sortedTrovesAddress\",\"type\":\"address\"}],\"name\":\"SortedTrovesAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_stabilityPoolAddress\",\"type\":\"address\"}],\"name\":\"StabilityPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"arrayIndex\",\"type\":\"uint256\"}],\"name\":\"TroveCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newTroveManagerAddress\",\"type\":\"address\"}],\"name\":\"TroveManagerAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_coll\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"enum BorrowerOperations.BorrowerOperation\",\"name\":\"operation\",\"type\":\"uint8\"}],\"name\":\"TroveUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_zeroStakingAddress\",\"type\":\"address\"}],\"name\":\"ZEROStakingAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ZUSDFee\",\"type\":\"uint256\"}],\"name\":\"ZUSDBorrowingFeePaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_zusdTokenAddress\",\"type\":\"address\"}],\"name\":\"ZUSDTokenAddressChanged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BORROWING_FEE_FLOOR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DECIMAL_PRECISION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_NET_DEBT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZUSD_GAS_COMPENSATION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_100pct\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activePool\",\"outputs\":[{\"internalType\":\"contract IActivePool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"addColl\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_collWithdrawal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDChange\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_isDebtIncrease\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"adjustNueTrove\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_collWithdrawal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDChange\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_isDebtIncrease\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"adjustNueTroveWithPermit2\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_collWithdrawal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDChange\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_isDebtIncrease\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"adjustTrove\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimCollateral\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"closeNueTrove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"closeNueTroveWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"closeTrove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultPool\",\"outputs\":[{\"internalType\":\"contract IDefaultPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeDistributor\",\"outputs\":[{\"internalType\":\"contract IFeeDistributor\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"}],\"name\":\"getCompositeDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemColl\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getMassetManager\",\"outputs\":[{\"internalType\":\"contract IMassetManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquityBaseParams\",\"outputs\":[{\"internalType\":\"contract ILiquityBaseParams\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"massetManager\",\"outputs\":[{\"internalType\":\"contract IMassetManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"moveETHGainToTrove\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"openNueTrove\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"openTrove\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceFeed\",\"outputs\":[{\"internalType\":\"contract IPriceFeed\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ZUSDAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"repayZUSD\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"repayZusdFromDLLR\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"repayZusdFromDLLRWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_feeDistributorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_liquityBaseParamsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_troveManagerAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_activePoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_defaultPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_stabilityPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_gasPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_collSurplusPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_priceFeedAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_sortedTrovesAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zusdTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zeroStakingAddress\",\"type\":\"address\"}],\"name\":\"setAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_massetManagerAddress\",\"type\":\"address\"}],\"name\":\"setMassetManagerAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortedTroves\",\"outputs\":[{\"internalType\":\"contract ISortedTroves\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"troveManager\",\"outputs\":[{\"internalType\":\"contract ITroveManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_collWithdrawal\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"withdrawColl\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"withdrawZUSD\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"withdrawZusdAndConvertToDLLR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zeroStaking\",\"outputs\":[{\"internalType\":\"contract IZEROStaking\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zeroStakingAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zusdToken\",\"outputs\":[{\"internalType\":\"contract IZUSDToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getOwner()\":{\"returns\":{\"_owner\":\"Address of the owner. \"}},\"setAddresses(address,address,address,address,address,address,address,address,address,address,address,address)\":{\"details\":\"initializer function, checks addresses are contracts\",\"params\":{\"_activePoolAddress\":\"ActivePool contract address\",\"_collSurplusPoolAddress\":\"CollSurplusPool contract address\",\"_defaultPoolAddress\":\"DefaultPool contract address\",\"_feeDistributorAddress\":\"feeDistributor contract address\",\"_gasPoolAddress\":\"GasPool contract address\",\"_liquityBaseParamsAddress\":\"LiquidityBaseParams contract address\",\"_priceFeedAddress\":\"PrideFeed contract address\",\"_sortedTrovesAddress\":\"SortedTroves contract address\",\"_stabilityPoolAddress\":\"StabilityPool contract address\",\"_troveManagerAddress\":\"TroveManager contract address\",\"_zeroStakingAddress\":\"ZEROStaking contract address\",\"_zusdTokenAddress\":\"ZUSDToken contract address\"}},\"setOwner(address)\":{\"params\":{\"_owner\":\"Address of the owner. \"}},\"withdrawZusdAndConvertToDLLR(uint256,uint256,address,address)\":{\"returns\":{\"_0\":\"DLLR amount minted\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"MIN_NET_DEBT()\":{\"notice\":\"Minimum amount of net ZUSD debt a trove must have\"},\"ZUSD_GAS_COMPENSATION()\":{\"notice\":\"Amount of ZUSD to be locked in gas pool on opening troves\"},\"addColl(address,address)\":{\"notice\":\"Send ETH as collateral to a trove\"},\"claimCollateral()\":{\"notice\":\"Claim remaining collateral from a redemption or from a liquidation with ICR > MCR in Recovery Mode\"},\"closeNueTrove((uint256,uint8,bytes32,bytes32))\":{\"notice\":\"allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE. This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\"},\"closeNueTroveWithPermit2(((address,uint256),uint256,uint256),bytes)\":{\"notice\":\"allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE. This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\"},\"closeTrove()\":{\"notice\":\"allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a ZUSD balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` ZUSD.\"},\"constructor\":\"Constructor \",\"getOwner()\":{\"notice\":\"Return address of the owner.\"},\"moveETHGainToTrove(address,address,address)\":{\"notice\":\"Send ETH as collateral to a trove. Called by only the Stability Pool.\"},\"permit2()\":{\"notice\":\"CONSTANT / IMMUTABLE VARIABLE ONLY \"},\"repayZUSD(uint256,address,address)\":{\"notice\":\"Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\"},\"repayZusdFromDLLR(uint256,address,address,(uint256,uint8,bytes32,bytes32))\":{\"notice\":\"Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly\"},\"repayZusdFromDLLRWithPermit2(uint256,address,address,((address,uint256),uint256,uint256),bytes)\":{\"notice\":\"Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly\"},\"setAddresses(address,address,address,address,address,address,address,address,address,address,address,address)\":{\"notice\":\"Called only once on init, to set addresses of other Zero contracts. Callable only by owner\"},\"setOwner(address)\":{\"notice\":\"Set address of the owner (only owner can call this function)\"},\"withdrawColl(uint256,address,address)\":{\"notice\":\"Withdraw ETH collateral from a trove\"},\"withdrawZUSD(uint256,uint256,address,address)\":{\"notice\":\"Withdraw ZUSD tokens from a trove: mint new ZUSD tokens to the owner, and increase the trove's debt accordingly\"},\"withdrawZusdAndConvertToDLLR(uint256,uint256,address,address)\":{\"notice\":\"Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction Zero Line of Credit owner can borrow a specified amount of ZUSD and convert it to DLLR via Sovryn Mynt\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/BorrowerOperations.sol\":\"BorrowerOperations\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"contracts/BorrowerOperations.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./Interfaces/ITroveManager.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/IZEROStaking.sol\\\";\\nimport \\\"./Interfaces/IFeeDistributor.sol\\\";\\nimport \\\"./Dependencies/LiquityBase.sol\\\";\\nimport \\\"./Dependencies/CheckContract.sol\\\";\\nimport \\\"./Dependencies/console.sol\\\";\\nimport \\\"./BorrowerOperationsStorage.sol\\\";\\nimport \\\"./Dependencies/Mynt/MyntLib.sol\\\";\\nimport \\\"./Interfaces/IPermit2.sol\\\";\\n\\ncontract BorrowerOperations is\\n LiquityBase,\\n BorrowerOperationsStorage,\\n CheckContract,\\n IBorrowerOperations\\n{\\n /** CONSTANT / IMMUTABLE VARIABLE ONLY */\\n IPermit2 public immutable permit2;\\n\\n /* --- Variable container structs ---\\n\\n Used to hold, return and assign variables inside a function, in order to avoid the error:\\n \\\"CompilerError: Stack too deep\\\". */\\n\\n struct LocalVariables_adjustTrove {\\n uint256 price;\\n uint256 collChange;\\n uint256 netDebtChange;\\n bool isCollIncrease;\\n uint256 debt;\\n uint256 coll;\\n uint256 oldICR;\\n uint256 newICR;\\n uint256 newTCR;\\n uint256 ZUSDFee;\\n uint256 newDebt;\\n uint256 newColl;\\n uint256 stake;\\n uint256 newNICR;\\n bool isRecoveryMode;\\n }\\n\\n struct LocalVariables_openTrove {\\n uint256 price;\\n uint256 ZUSDFee;\\n uint256 netDebt;\\n uint256 compositeDebt;\\n uint256 ICR;\\n uint256 NICR;\\n uint256 stake;\\n uint256 arrayIndex;\\n }\\n\\n struct ContractsCache {\\n ITroveManager troveManager;\\n IActivePool activePool;\\n IZUSDToken zusdToken;\\n }\\n\\n enum BorrowerOperation {\\n openTrove,\\n closeTrove,\\n adjustTrove\\n }\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n event MassetManagerAddressChanged(address _massetManagerAddress);\\n\\n event TroveCreated(address indexed _borrower, uint256 arrayIndex);\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n BorrowerOperation operation\\n );\\n event ZUSDBorrowingFeePaid(address indexed _borrower, uint256 _ZUSDFee);\\n\\n /** Constructor */\\n constructor(address _permit2) public {\\n permit2 = IPermit2(_permit2);\\n }\\n\\n // --- Dependency setters ---\\n\\n function setAddresses(\\n address _feeDistributorAddress,\\n address _liquityBaseParamsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _defaultPoolAddress,\\n address _stabilityPoolAddress,\\n address _gasPoolAddress,\\n address _collSurplusPoolAddress,\\n address _priceFeedAddress,\\n address _sortedTrovesAddress,\\n address _zusdTokenAddress,\\n address _zeroStakingAddress\\n ) external override onlyOwner {\\n // This makes impossible to open a trove with zero withdrawn ZUSD\\n assert(MIN_NET_DEBT > 0);\\n\\n checkContract(_feeDistributorAddress);\\n checkContract(_liquityBaseParamsAddress);\\n checkContract(_troveManagerAddress);\\n checkContract(_activePoolAddress);\\n checkContract(_defaultPoolAddress);\\n checkContract(_stabilityPoolAddress);\\n checkContract(_gasPoolAddress);\\n checkContract(_collSurplusPoolAddress);\\n checkContract(_priceFeedAddress);\\n checkContract(_sortedTrovesAddress);\\n checkContract(_zusdTokenAddress);\\n checkContract(_zeroStakingAddress);\\n\\n feeDistributor = IFeeDistributor(_feeDistributorAddress);\\n liquityBaseParams = ILiquityBaseParams(_liquityBaseParamsAddress);\\n troveManager = ITroveManager(_troveManagerAddress);\\n activePool = IActivePool(_activePoolAddress);\\n defaultPool = IDefaultPool(_defaultPoolAddress);\\n stabilityPoolAddress = _stabilityPoolAddress;\\n gasPoolAddress = _gasPoolAddress;\\n collSurplusPool = ICollSurplusPool(_collSurplusPoolAddress);\\n priceFeed = IPriceFeed(_priceFeedAddress);\\n sortedTroves = ISortedTroves(_sortedTrovesAddress);\\n zusdToken = IZUSDToken(_zusdTokenAddress);\\n zeroStakingAddress = _zeroStakingAddress;\\n zeroStaking = IZEROStaking(_zeroStakingAddress);\\n\\n emit FeeDistributorAddressChanged(_feeDistributorAddress);\\n emit TroveManagerAddressChanged(_troveManagerAddress);\\n emit ActivePoolAddressChanged(_activePoolAddress);\\n emit DefaultPoolAddressChanged(_defaultPoolAddress);\\n emit StabilityPoolAddressChanged(_stabilityPoolAddress);\\n emit GasPoolAddressChanged(_gasPoolAddress);\\n emit CollSurplusPoolAddressChanged(_collSurplusPoolAddress);\\n emit PriceFeedAddressChanged(_priceFeedAddress);\\n emit SortedTrovesAddressChanged(_sortedTrovesAddress);\\n emit ZUSDTokenAddressChanged(_zusdTokenAddress);\\n emit ZEROStakingAddressChanged(_zeroStakingAddress);\\n }\\n\\n function setMassetManagerAddress(address _massetManagerAddress) external onlyOwner {\\n massetManager = IMassetManager(_massetManagerAddress);\\n emit MassetManagerAddressChanged(_massetManagerAddress);\\n }\\n\\n function openTrove(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable override {\\n _openTrove(_maxFeePercentage, _ZUSDAmount, _upperHint, _lowerHint, msg.sender);\\n }\\n\\n function openNueTrove(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable override {\\n require(address(massetManager) != address(0), \\\"Masset address not set\\\");\\n\\n _openTrove(_maxFeePercentage, _ZUSDAmount, _upperHint, _lowerHint, address(this));\\n require(\\n zusdToken.approve(address(massetManager), _ZUSDAmount),\\n \\\"Failed to approve ZUSD amount for Mynt mAsset to redeem\\\"\\n );\\n massetManager.mintTo(address(zusdToken), _ZUSDAmount, msg.sender);\\n }\\n\\n // --- Borrower Trove Operations ---\\n function _openTrove(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint,\\n address _tokensRecipient\\n ) internal {\\n ContractsCache memory contractsCache = ContractsCache(troveManager, activePool, zusdToken);\\n LocalVariables_openTrove memory vars;\\n\\n vars.price = priceFeed.fetchPrice();\\n bool isRecoveryMode = _checkRecoveryMode(vars.price);\\n\\n _requireValidMaxFeePercentage(_maxFeePercentage, isRecoveryMode);\\n _requireTroveisNotActive(contractsCache.troveManager, msg.sender);\\n\\n vars.ZUSDFee;\\n vars.netDebt = _ZUSDAmount;\\n\\n if (!isRecoveryMode) {\\n vars.ZUSDFee = _triggerBorrowingFee(\\n contractsCache.troveManager,\\n contractsCache.zusdToken,\\n _ZUSDAmount,\\n _maxFeePercentage\\n );\\n vars.netDebt = vars.netDebt.add(vars.ZUSDFee);\\n }\\n _requireAtLeastMinNetDebt(vars.netDebt);\\n\\n // ICR is based on the composite debt, i.e. the requested ZUSD amount + ZUSD borrowing fee + ZUSD gas comp.\\n vars.compositeDebt = _getCompositeDebt(vars.netDebt);\\n assert(vars.compositeDebt > 0);\\n\\n vars.ICR = LiquityMath._computeCR(msg.value, vars.compositeDebt, vars.price);\\n vars.NICR = LiquityMath._computeNominalCR(msg.value, vars.compositeDebt);\\n\\n if (isRecoveryMode) {\\n _requireICRisAboveCCR(vars.ICR);\\n } else {\\n _requireICRisAboveMCR(vars.ICR);\\n uint256 newTCR = _getNewTCRFromTroveChange(\\n msg.value,\\n true,\\n vars.compositeDebt,\\n true,\\n vars.price\\n ); // bools: coll increase, debt increase\\n _requireNewTCRisAboveCCR(newTCR);\\n }\\n\\n // Set the trove struct's properties\\n contractsCache.troveManager.setTroveStatus(msg.sender, 1);\\n contractsCache.troveManager.increaseTroveColl(msg.sender, msg.value);\\n contractsCache.troveManager.increaseTroveDebt(msg.sender, vars.compositeDebt);\\n\\n contractsCache.troveManager.updateTroveRewardSnapshots(msg.sender);\\n vars.stake = contractsCache.troveManager.updateStakeAndTotalStakes(msg.sender);\\n\\n sortedTroves.insert(msg.sender, vars.NICR, _upperHint, _lowerHint);\\n vars.arrayIndex = contractsCache.troveManager.addTroveOwnerToArray(msg.sender);\\n emit TroveCreated(msg.sender, vars.arrayIndex);\\n\\n // Move the ether to the Active Pool, and mint the ZUSDAmount to the borrower\\n _activePoolAddColl(contractsCache.activePool, msg.value);\\n _mintZusdAndIncreaseActivePoolDebt(\\n contractsCache.activePool,\\n contractsCache.zusdToken,\\n _tokensRecipient,\\n _ZUSDAmount,\\n vars.netDebt\\n );\\n // Move the ZUSD gas compensation to the Gas Pool\\n _mintZusdAndIncreaseActivePoolDebt(\\n contractsCache.activePool,\\n contractsCache.zusdToken,\\n gasPoolAddress,\\n ZUSD_GAS_COMPENSATION,\\n ZUSD_GAS_COMPENSATION\\n );\\n\\n emit TroveUpdated(\\n msg.sender,\\n vars.compositeDebt,\\n msg.value,\\n vars.stake,\\n BorrowerOperation.openTrove\\n );\\n emit ZUSDBorrowingFeePaid(msg.sender, vars.ZUSDFee);\\n }\\n\\n /// Send ETH as collateral to a trove\\n function addColl(address _upperHint, address _lowerHint) external payable override {\\n _adjustTrove(msg.sender, 0, 0, false, _upperHint, _lowerHint, 0);\\n }\\n\\n /// Send ETH as collateral to a trove. Called by only the Stability Pool.\\n function moveETHGainToTrove(\\n address _borrower,\\n address _upperHint,\\n address _lowerHint\\n ) external payable override {\\n _requireCallerIsStabilityPool();\\n _adjustTrove(_borrower, 0, 0, false, _upperHint, _lowerHint, 0);\\n }\\n\\n /// Withdraw ETH collateral from a trove\\n function withdrawColl(\\n uint256 _collWithdrawal,\\n address _upperHint,\\n address _lowerHint\\n ) external override {\\n _adjustTrove(msg.sender, _collWithdrawal, 0, false, _upperHint, _lowerHint, 0);\\n }\\n\\n /// Withdraw ZUSD tokens from a trove: mint new ZUSD tokens to the owner, and increase the trove's debt accordingly\\n function withdrawZUSD(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external override {\\n _adjustTrove(msg.sender, 0, _ZUSDAmount, true, _upperHint, _lowerHint, _maxFeePercentage);\\n }\\n\\n /// Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction\\n /// Zero Line of Credit owner can borrow a specified amount of ZUSD and convert it to DLLR via Sovryn Mynt\\n ///@return DLLR amount minted\\n function withdrawZusdAndConvertToDLLR(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external override returns (uint256) {\\n address thisAddress = address(this);\\n uint256 balanceBefore = zusdToken.balanceOf(thisAddress);\\n\\n _withdrawZusdTo(\\n msg.sender,\\n thisAddress,\\n _ZUSDAmount,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage\\n );\\n\\n require(\\n zusdToken.balanceOf(thisAddress) == balanceBefore.add(_ZUSDAmount),\\n \\\"ZUSD is not borrowed correctly\\\"\\n );\\n require(\\n zusdToken.approve(address(massetManager), _ZUSDAmount),\\n \\\"Failed to approve ZUSD amount for Mynt mAsset to redeem\\\"\\n );\\n return massetManager.mintTo(address(zusdToken), _ZUSDAmount, msg.sender);\\n }\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZUSD(\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external override {\\n _adjustTrove(msg.sender, 0, _ZUSDAmount, false, _upperHint, _lowerHint, 0);\\n }\\n\\n /// Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly\\n function repayZusdFromDLLR(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external override {\\n _adjustNueTrove(0, 0, _dllrAmount, false, _upperHint, _lowerHint, _permitParams);\\n }\\n\\n /// Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly\\n function repayZusdFromDLLRWithPermit2(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external override {\\n _adjustNueTroveWithPermit2(0, 0, _dllrAmount, false, _upperHint, _lowerHint, _permit, _signature);\\n }\\n\\n function adjustTrove(\\n uint256 _maxFeePercentage,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint\\n ) external payable override {\\n _adjustTrove(\\n msg.sender,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage\\n );\\n }\\n\\n // in case of _isDebtIncrease = false MassetManager contract must have an approval of NUE tokens\\n function adjustNueTrove(\\n uint256 _maxFeePercentage,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external payable override {\\n _adjustNueTrove(\\n _maxFeePercentage,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _permitParams\\n );\\n }\\n\\n // in case of _isDebtIncrease = false MassetManager contract must have an approval of NUE tokens\\n function adjustNueTroveWithPermit2(\\n uint256 _maxFeePercentage,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external payable override {\\n _adjustNueTroveWithPermit2(\\n _maxFeePercentage,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _permit,\\n _signature\\n );\\n }\\n\\n // in case of _isDebtIncrease = false Masset Manager contract must have an approval of NUE tokens\\n function _adjustNueTrove(\\n uint256 _maxFeePercentage,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) internal {\\n require(address(massetManager) != address(0), \\\"Masset address not set\\\");\\n\\n if (!_isDebtIncrease && _ZUSDChange > 0) {\\n MyntLib.redeemZusdFromDllrWithPermit(\\n massetManager,\\n _ZUSDChange,\\n address(zusdToken),\\n _permitParams\\n );\\n }\\n _adjustSenderTrove(\\n msg.sender,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage,\\n address(this)\\n );\\n if (_isDebtIncrease && _ZUSDChange > 0) {\\n require(\\n zusdToken.approve(address(massetManager), _ZUSDChange),\\n \\\"Failed to approve ZUSD amount for Mynt mAsset to redeem\\\"\\n );\\n massetManager.mintTo(address(zusdToken), _ZUSDChange, msg.sender);\\n }\\n }\\n\\n // in case of _isDebtIncrease = false Masset Manager contract must have an approval of NUE tokens\\n function _adjustNueTroveWithPermit2(\\n uint256 _maxFeePercentage,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) internal {\\n require(address(massetManager) != address(0), \\\"Masset address not set\\\");\\n\\n if (!_isDebtIncrease && _ZUSDChange > 0) {\\n MyntLib.redeemZusdFromDllrWithPermit2(\\n massetManager,\\n address(zusdToken),\\n _permit,\\n permit2,\\n _signature\\n );\\n }\\n _adjustSenderTrove(\\n msg.sender,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage,\\n address(this)\\n );\\n if (_isDebtIncrease && _ZUSDChange > 0) {\\n require(\\n zusdToken.approve(address(massetManager), _ZUSDChange),\\n \\\"Failed to approve ZUSD amount for Mynt mAsset to redeem\\\"\\n );\\n massetManager.mintTo(address(zusdToken), _ZUSDChange, msg.sender);\\n }\\n }\\n\\n function _adjustTrove(\\n address _borrower,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n uint256 _maxFeePercentage\\n ) internal {\\n _adjustSenderTrove(\\n _borrower,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage,\\n msg.sender\\n );\\n }\\n\\n // _withdrawZusd: _adjustTrove(msg.sender, 0, _ZUSDAmount, true, _upperHint, _lowerHint, _maxFeePercentage);\\n function _withdrawZusdTo(\\n address _borrower,\\n address _receiver,\\n uint256 _ZUSDChange,\\n address _upperHint,\\n address _lowerHint,\\n uint256 _maxFeePercentage\\n ) internal {\\n _adjustSenderTrove(\\n _borrower,\\n 0,\\n _ZUSDChange,\\n true,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage,\\n _receiver\\n );\\n }\\n\\n /**\\n * _adjustSenderTrove(): Alongside a debt change, this function can perform either a collateral top-up or a collateral withdrawal.\\n *\\n * It therefore expects either a positive msg.value, or a positive _collWithdrawal argument.\\n *\\n * If both are positive, it will revert.\\n */\\n function _adjustSenderTrove(\\n address _borrower,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n uint256 _maxFeePercentage,\\n address _tokensRecipient\\n ) internal {\\n ContractsCache memory contractsCache = ContractsCache(troveManager, activePool, zusdToken);\\n LocalVariables_adjustTrove memory vars;\\n\\n vars.price = priceFeed.fetchPrice();\\n vars.isRecoveryMode = _checkRecoveryMode(vars.price);\\n\\n if (_isDebtIncrease) {\\n _requireValidMaxFeePercentage(_maxFeePercentage, vars.isRecoveryMode);\\n _requireNonZeroDebtChange(_ZUSDChange);\\n }\\n _requireSingularCollChange(_collWithdrawal);\\n _requireNonZeroAdjustment(_collWithdrawal, _ZUSDChange);\\n _requireTroveisActive(contractsCache.troveManager, _borrower);\\n\\n // Confirm the operation is either a borrower adjusting their own trove, or a pure ETH transfer from the Stability Pool to a trove\\n assert(\\n msg.sender == _borrower ||\\n (msg.sender == stabilityPoolAddress && msg.value > 0 && _ZUSDChange == 0)\\n );\\n\\n contractsCache.troveManager.applyPendingRewards(_borrower);\\n\\n // Get the collChange based on whether or not ETH was sent in the transaction\\n (vars.collChange, vars.isCollIncrease) = _getCollChange(msg.value, _collWithdrawal);\\n\\n vars.netDebtChange = _ZUSDChange;\\n\\n // If the adjustment incorporates a debt increase and system is in Normal Mode, then trigger a borrowing fee\\n if (_isDebtIncrease && !vars.isRecoveryMode) {\\n vars.ZUSDFee = _triggerBorrowingFee(\\n contractsCache.troveManager,\\n contractsCache.zusdToken,\\n _ZUSDChange,\\n _maxFeePercentage\\n );\\n vars.netDebtChange = vars.netDebtChange.add(vars.ZUSDFee); // The raw debt change includes the fee\\n }\\n\\n vars.debt = contractsCache.troveManager.getTroveDebt(_borrower);\\n vars.coll = contractsCache.troveManager.getTroveColl(_borrower);\\n\\n // Get the trove's old ICR before the adjustment, and what its new ICR will be after the adjustment\\n vars.oldICR = LiquityMath._computeCR(vars.coll, vars.debt, vars.price);\\n vars.newICR = _getNewICRFromTroveChange(\\n vars.coll,\\n vars.debt,\\n vars.collChange,\\n vars.isCollIncrease,\\n vars.netDebtChange,\\n _isDebtIncrease,\\n vars.price\\n );\\n assert(_collWithdrawal <= vars.coll);\\n\\n // Check the adjustment satisfies all conditions for the current system mode\\n _requireValidAdjustmentInCurrentMode(\\n vars.isRecoveryMode,\\n _collWithdrawal,\\n _isDebtIncrease,\\n vars\\n );\\n\\n // When the adjustment is a debt repayment, check it's a valid amount and that the caller has enough ZUSD\\n if (!_isDebtIncrease && _ZUSDChange > 0) {\\n _requireAtLeastMinNetDebt(_getNetDebt(vars.debt).sub(vars.netDebtChange));\\n _requireValidZUSDRepayment(vars.debt, vars.netDebtChange);\\n _requireSufficientZUSDBalance(contractsCache.zusdToken, _borrower, vars.netDebtChange);\\n }\\n\\n (vars.newColl, vars.newDebt) = _updateTroveFromAdjustment(\\n contractsCache.troveManager,\\n _borrower,\\n vars.collChange,\\n vars.isCollIncrease,\\n vars.netDebtChange,\\n _isDebtIncrease\\n );\\n vars.stake = contractsCache.troveManager.updateStakeAndTotalStakes(_borrower);\\n\\n // Re-insert trove in to the sorted list\\n vars.newNICR = _getNewNominalICRFromTroveChange(\\n vars.coll,\\n vars.debt,\\n vars.collChange,\\n vars.isCollIncrease,\\n vars.netDebtChange,\\n _isDebtIncrease\\n );\\n sortedTroves.reInsert(_borrower, vars.newNICR, _upperHint, _lowerHint);\\n\\n emit TroveUpdated(\\n _borrower,\\n vars.newDebt,\\n vars.newColl,\\n vars.stake,\\n BorrowerOperation.adjustTrove\\n );\\n emit ZUSDBorrowingFeePaid(msg.sender, vars.ZUSDFee);\\n\\n // Use the unmodified _ZUSDChange here, as we don't send the fee to the user\\n _moveTokensAndETHfromAdjustment(\\n contractsCache.activePool,\\n contractsCache.zusdToken,\\n msg.sender,\\n vars.collChange,\\n vars.isCollIncrease,\\n _ZUSDChange,\\n _isDebtIncrease,\\n vars.netDebtChange,\\n _tokensRecipient\\n );\\n }\\n\\n function closeTrove() external override {\\n _closeTrove();\\n }\\n\\n function closeNueTrove(IMassetManager.PermitParams calldata _permitParams) external override {\\n require(address(massetManager) != address(0), \\\"Masset address not set\\\");\\n\\n uint256 debt = troveManager.getTroveDebt(msg.sender);\\n\\n MyntLib.redeemZusdFromDllrWithPermit(\\n massetManager,\\n debt.sub(ZUSD_GAS_COMPENSATION),\\n address(zusdToken),\\n _permitParams\\n );\\n _closeTrove();\\n }\\n\\n function closeNueTroveWithPermit2(ISignatureTransfer.PermitTransferFrom memory _permit, bytes calldata _signature) external override {\\n require(address(massetManager) != address(0), \\\"Masset address not set\\\");\\n\\n uint256 debt = troveManager.getTroveDebt(msg.sender);\\n\\n MyntLib.redeemZusdFromDllrWithPermit2(\\n massetManager,\\n address(zusdToken),\\n _permit,\\n permit2,\\n _signature\\n );\\n\\n _closeTrove();\\n }\\n\\n function _closeTrove() internal {\\n ITroveManager troveManagerCached = troveManager;\\n IActivePool activePoolCached = activePool;\\n IZUSDToken zusdTokenCached = zusdToken;\\n\\n _requireTroveisActive(troveManagerCached, msg.sender);\\n uint256 price = priceFeed.fetchPrice();\\n _requireNotInRecoveryMode(price);\\n\\n troveManagerCached.applyPendingRewards(msg.sender);\\n\\n uint256 coll = troveManagerCached.getTroveColl(msg.sender);\\n uint256 debt = troveManagerCached.getTroveDebt(msg.sender);\\n\\n _requireSufficientZUSDBalance(\\n zusdTokenCached,\\n msg.sender,\\n debt.sub(ZUSD_GAS_COMPENSATION)\\n );\\n\\n uint256 newTCR = _getNewTCRFromTroveChange(coll, false, debt, false, price);\\n _requireNewTCRisAboveCCR(newTCR);\\n\\n troveManagerCached.removeStake(msg.sender);\\n troveManagerCached.closeTrove(msg.sender);\\n\\n emit TroveUpdated(msg.sender, 0, 0, 0, BorrowerOperation.closeTrove);\\n\\n // Burn the repaid ZUSD from the user's balance and the gas compensation from the Gas Pool\\n _burnZusdAndDecreaseActivePoolDebt(\\n activePoolCached,\\n zusdTokenCached,\\n msg.sender,\\n debt.sub(ZUSD_GAS_COMPENSATION)\\n );\\n _burnZusdAndDecreaseActivePoolDebt(\\n activePoolCached,\\n zusdTokenCached,\\n gasPoolAddress,\\n ZUSD_GAS_COMPENSATION\\n );\\n\\n // Send the collateral back to the user\\n activePoolCached.sendETH(msg.sender, coll);\\n }\\n\\n /**\\n * Claim remaining collateral from a redemption or from a liquidation with ICR > MCR in Recovery Mode\\n */\\n function claimCollateral() external override {\\n // send ETH from CollSurplus Pool to owner\\n collSurplusPool.claimColl(msg.sender);\\n }\\n\\n // --- Helper functions ---\\n\\n function _triggerBorrowingFee(\\n ITroveManager _troveManager,\\n IZUSDToken _zusdToken,\\n uint256 _ZUSDAmount,\\n uint256 _maxFeePercentage\\n ) internal returns (uint256) {\\n _troveManager.decayBaseRateFromBorrowing(); // decay the baseRate state variable\\n uint256 ZUSDFee = _troveManager.getBorrowingFee(_ZUSDAmount);\\n\\n _requireUserAcceptsFee(ZUSDFee, _ZUSDAmount, _maxFeePercentage);\\n _zusdToken.mint(address(feeDistributor), ZUSDFee);\\n feeDistributor.distributeFees();\\n\\n return ZUSDFee;\\n }\\n\\n function _getUSDValue(uint256 _coll, uint256 _price) internal pure returns (uint256) {\\n uint256 usdValue = _price.mul(_coll).div(DECIMAL_PRECISION);\\n\\n return usdValue;\\n }\\n\\n function _getCollChange(uint256 _collReceived, uint256 _requestedCollWithdrawal)\\n internal\\n pure\\n returns (uint256 collChange, bool isCollIncrease)\\n {\\n if (_collReceived != 0) {\\n collChange = _collReceived;\\n isCollIncrease = true;\\n } else {\\n collChange = _requestedCollWithdrawal;\\n }\\n }\\n\\n /// Update trove's coll and debt based on whether they increase or decrease\\n function _updateTroveFromAdjustment(\\n ITroveManager _troveManager,\\n address _borrower,\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _debtChange,\\n bool _isDebtIncrease\\n ) internal returns (uint256, uint256) {\\n uint256 newColl = (_isCollIncrease)\\n ? _troveManager.increaseTroveColl(_borrower, _collChange)\\n : _troveManager.decreaseTroveColl(_borrower, _collChange);\\n uint256 newDebt = (_isDebtIncrease)\\n ? _troveManager.increaseTroveDebt(_borrower, _debtChange)\\n : _troveManager.decreaseTroveDebt(_borrower, _debtChange);\\n\\n return (newColl, newDebt);\\n }\\n\\n function _moveTokensAndETHfromAdjustment(\\n IActivePool _activePool,\\n IZUSDToken _zusdToken,\\n address _borrower,\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n uint256 _netDebtChange,\\n address _tokensRecipient\\n ) internal {\\n if (_isDebtIncrease) {\\n _mintZusdAndIncreaseActivePoolDebt(\\n _activePool,\\n _zusdToken,\\n _tokensRecipient,\\n _ZUSDChange,\\n _netDebtChange\\n );\\n } else {\\n _burnZusdAndDecreaseActivePoolDebt(_activePool, _zusdToken, _borrower, _ZUSDChange);\\n }\\n\\n if (_isCollIncrease) {\\n _activePoolAddColl(_activePool, _collChange);\\n } else {\\n _activePool.sendETH(_borrower, _collChange);\\n }\\n }\\n\\n /// Send ETH to Active Pool and increase its recorded ETH balance\\n function _activePoolAddColl(IActivePool _activePool, uint256 _amount) internal {\\n (bool success, ) = address(_activePool).call{ value: _amount }(\\\"\\\");\\n require(success, \\\"BorrowerOps: Sending ETH to ActivePool failed\\\");\\n }\\n\\n /// Issue the specified amount of ZUSD to _account and increases the total active debt (_netDebtIncrease potentially includes a ZUSDFee)\\n function _mintZusdAndIncreaseActivePoolDebt(\\n IActivePool _activePool,\\n IZUSDToken _zusdToken,\\n address _account,\\n uint256 _ZUSDAmount,\\n uint256 _netDebtIncrease\\n ) internal {\\n _activePool.increaseZUSDDebt(_netDebtIncrease);\\n _zusdToken.mint(_account, _ZUSDAmount);\\n }\\n\\n /// Burn the specified amount of ZUSD from _account and decreases the total active debt\\n function _burnZusdAndDecreaseActivePoolDebt(\\n IActivePool _activePool,\\n IZUSDToken _zusdToken,\\n address _account,\\n uint256 _ZUSD\\n ) internal {\\n _activePool.decreaseZUSDDebt(_ZUSD);\\n _zusdToken.burn(_account, _ZUSD);\\n }\\n\\n // --- 'Require' wrapper functions ---\\n\\n function _requireSingularCollChange(uint256 _collWithdrawal) internal view {\\n require(\\n msg.value == 0 || _collWithdrawal == 0,\\n \\\"BorrowerOperations: Cannot withdraw and add coll\\\"\\n );\\n }\\n\\n function _requireCallerIsBorrower(address _borrower) internal view {\\n require(\\n msg.sender == _borrower,\\n \\\"BorrowerOps: Caller must be the borrower for a withdrawal\\\"\\n );\\n }\\n\\n function _requireNonZeroAdjustment(uint256 _collWithdrawal, uint256 _ZUSDChange)\\n internal\\n view\\n {\\n require(\\n msg.value != 0 || _collWithdrawal != 0 || _ZUSDChange != 0,\\n \\\"BorrowerOps: There must be either a collateral change or a debt change\\\"\\n );\\n }\\n\\n function _requireTroveisActive(ITroveManager _troveManager, address _borrower) internal view {\\n uint256 status = _troveManager.getTroveStatus(_borrower);\\n require(status == 1, \\\"BorrowerOps: Trove does not exist or is closed\\\");\\n }\\n\\n function _requireTroveisNotActive(ITroveManager _troveManager, address _borrower)\\n internal\\n view\\n {\\n uint256 status = _troveManager.getTroveStatus(_borrower);\\n require(status != 1, \\\"BorrowerOps: Trove is active\\\");\\n }\\n\\n function _requireNonZeroDebtChange(uint256 _ZUSDChange) internal pure {\\n require(_ZUSDChange > 0, \\\"BorrowerOps: Debt increase requires non-zero debtChange\\\");\\n }\\n\\n function _requireNotInRecoveryMode(uint256 _price) internal view {\\n require(\\n !_checkRecoveryMode(_price),\\n \\\"BorrowerOps: Operation not permitted during Recovery Mode\\\"\\n );\\n }\\n\\n function _requireNoCollWithdrawal(uint256 _collWithdrawal) internal pure {\\n require(\\n _collWithdrawal == 0,\\n \\\"BorrowerOps: Collateral withdrawal not permitted Recovery Mode\\\"\\n );\\n }\\n\\n function _requireValidAdjustmentInCurrentMode(\\n bool _isRecoveryMode,\\n uint256 _collWithdrawal,\\n bool _isDebtIncrease,\\n LocalVariables_adjustTrove memory _vars\\n ) internal view {\\n /*\\n *In Recovery Mode, only allow:\\n *\\n * - Pure collateral top-up\\n * - Pure debt repayment\\n * - Collateral top-up with debt repayment\\n * - A debt increase combined with a collateral top-up which makes the ICR >= 150% and improves the ICR (and by extension improves the TCR).\\n *\\n * In Normal Mode, ensure:\\n *\\n * - The new ICR is above MCR\\n * - The adjustment won't pull the TCR below CCR\\n */\\n if (_isRecoveryMode) {\\n _requireNoCollWithdrawal(_collWithdrawal);\\n if (_isDebtIncrease) {\\n _requireICRisAboveCCR(_vars.newICR);\\n _requireNewICRisAboveOldICR(_vars.newICR, _vars.oldICR);\\n }\\n } else {\\n // if Normal Mode\\n _requireICRisAboveMCR(_vars.newICR);\\n _vars.newTCR = _getNewTCRFromTroveChange(\\n _vars.collChange,\\n _vars.isCollIncrease,\\n _vars.netDebtChange,\\n _isDebtIncrease,\\n _vars.price\\n );\\n _requireNewTCRisAboveCCR(_vars.newTCR);\\n }\\n }\\n\\n function _requireICRisAboveMCR(uint256 _newICR) internal view {\\n require(\\n _newICR >= liquityBaseParams.MCR(),\\n \\\"BorrowerOps: An operation that would result in ICR < MCR is not permitted\\\"\\n );\\n }\\n\\n function _requireICRisAboveCCR(uint256 _newICR) internal view {\\n require(\\n _newICR >= liquityBaseParams.CCR(),\\n \\\"BorrowerOps: Operation must leave trove with ICR >= CCR\\\"\\n );\\n }\\n\\n function _requireNewICRisAboveOldICR(uint256 _newICR, uint256 _oldICR) internal pure {\\n require(\\n _newICR >= _oldICR,\\n \\\"BorrowerOps: Cannot decrease your Trove's ICR in Recovery Mode\\\"\\n );\\n }\\n\\n function _requireNewTCRisAboveCCR(uint256 _newTCR) internal view {\\n require(\\n _newTCR >= liquityBaseParams.CCR(),\\n \\\"BorrowerOps: An operation that would result in TCR < CCR is not permitted\\\"\\n );\\n }\\n\\n function _requireAtLeastMinNetDebt(uint256 _netDebt) internal pure {\\n require(\\n _netDebt >= MIN_NET_DEBT,\\n \\\"BorrowerOps: Trove's net debt must be greater than minimum\\\"\\n );\\n }\\n\\n function _requireValidZUSDRepayment(uint256 _currentDebt, uint256 _debtRepayment)\\n internal\\n pure\\n {\\n require(\\n _debtRepayment <= _currentDebt.sub(ZUSD_GAS_COMPENSATION),\\n \\\"BorrowerOps: Amount repaid must not be larger than the Trove's debt\\\"\\n );\\n }\\n\\n function _requireCallerIsStabilityPool() internal view {\\n require(msg.sender == stabilityPoolAddress, \\\"BorrowerOps: Caller is not Stability Pool\\\");\\n }\\n\\n function _requireSufficientZUSDBalance(\\n IZUSDToken _zusdToken,\\n address _borrower,\\n uint256 _debtRepayment\\n ) internal view {\\n require(\\n _zusdToken.balanceOf(_borrower) >= _debtRepayment,\\n \\\"BorrowerOps: Caller doesnt have enough ZUSD to make repayment\\\"\\n );\\n }\\n\\n function _requireValidMaxFeePercentage(uint256 _maxFeePercentage, bool _isRecoveryMode)\\n internal\\n view\\n {\\n if (_isRecoveryMode) {\\n require(\\n _maxFeePercentage <= DECIMAL_PRECISION,\\n \\\"Max fee percentage must less than or equal to 100%\\\"\\n );\\n } else {\\n require(\\n _maxFeePercentage >= liquityBaseParams.BORROWING_FEE_FLOOR() &&\\n _maxFeePercentage <= DECIMAL_PRECISION,\\n \\\"Max fee percentage must be between 0.5% and 100%\\\"\\n );\\n }\\n }\\n\\n // --- ICR and TCR getters ---\\n\\n /// Compute the new collateral ratio, considering the change in coll and debt. Assumes 0 pending rewards.\\n function _getNewNominalICRFromTroveChange(\\n uint256 _coll,\\n uint256 _debt,\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _debtChange,\\n bool _isDebtIncrease\\n ) internal pure returns (uint256) {\\n (uint256 newColl, uint256 newDebt) = _getNewTroveAmounts(\\n _coll,\\n _debt,\\n _collChange,\\n _isCollIncrease,\\n _debtChange,\\n _isDebtIncrease\\n );\\n\\n uint256 newNICR = LiquityMath._computeNominalCR(newColl, newDebt);\\n return newNICR;\\n }\\n\\n /// Compute the new collateral ratio, considering the change in coll and debt. Assumes 0 pending rewards.\\n function _getNewICRFromTroveChange(\\n uint256 _coll,\\n uint256 _debt,\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _debtChange,\\n bool _isDebtIncrease,\\n uint256 _price\\n ) internal pure returns (uint256) {\\n (uint256 newColl, uint256 newDebt) = _getNewTroveAmounts(\\n _coll,\\n _debt,\\n _collChange,\\n _isCollIncrease,\\n _debtChange,\\n _isDebtIncrease\\n );\\n\\n uint256 newICR = LiquityMath._computeCR(newColl, newDebt, _price);\\n return newICR;\\n }\\n\\n function _getNewTroveAmounts(\\n uint256 _coll,\\n uint256 _debt,\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _debtChange,\\n bool _isDebtIncrease\\n ) internal pure returns (uint256, uint256) {\\n uint256 newColl = _coll;\\n uint256 newDebt = _debt;\\n\\n newColl = _isCollIncrease ? _coll.add(_collChange) : _coll.sub(_collChange);\\n newDebt = _isDebtIncrease ? _debt.add(_debtChange) : _debt.sub(_debtChange);\\n\\n return (newColl, newDebt);\\n }\\n\\n function _getNewTCRFromTroveChange(\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _debtChange,\\n bool _isDebtIncrease,\\n uint256 _price\\n ) internal view returns (uint256) {\\n uint256 totalColl = getEntireSystemColl();\\n uint256 totalDebt = getEntireSystemDebt();\\n\\n totalColl = _isCollIncrease ? totalColl.add(_collChange) : totalColl.sub(_collChange);\\n totalDebt = _isDebtIncrease ? totalDebt.add(_debtChange) : totalDebt.sub(_debtChange);\\n\\n uint256 newTCR = LiquityMath._computeCR(totalColl, totalDebt, _price);\\n return newTCR;\\n }\\n\\n function getCompositeDebt(uint256 _debt) external view override returns (uint256) {\\n return _getCompositeDebt(_debt);\\n }\\n\\n function BORROWING_FEE_FLOOR() external view override returns (uint256) {\\n return liquityBaseParams.BORROWING_FEE_FLOOR();\\n }\\n\\n function getMassetManager() external view override returns (IMassetManager) {\\n return massetManager;\\n }\\n}\\n\",\"keccak256\":\"0x957479bda38a67e573ea703be0178601a038fad630b4d3a8b6be5b291bf3b641\",\"license\":\"MIT\"},\"contracts/BorrowerOperationsStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./Interfaces/IActivePool.sol\\\";\\nimport \\\"./Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./Interfaces/ITroveManager.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/IZEROStaking.sol\\\";\\nimport \\\"./Interfaces/IFeeDistributor.sol\\\";\\nimport \\\"./Dependencies/Ownable.sol\\\";\\nimport \\\"./Dependencies/Mynt/IMassetManager.sol\\\";\\n\\ncontract BorrowerOperationsStorage is Ownable {\\n string public constant NAME = \\\"BorrowerOperations\\\";\\n\\n // --- Connected contract declarations ---\\n\\n ITroveManager public troveManager;\\n\\n address stabilityPoolAddress;\\n\\n address gasPoolAddress;\\n\\n ICollSurplusPool collSurplusPool;\\n\\n IZEROStaking public zeroStaking;\\n address public zeroStakingAddress;\\n\\n IZUSDToken public zusdToken;\\n\\n // A doubly linked list of Troves, sorted by their collateral ratios\\n ISortedTroves public sortedTroves;\\n\\n IMassetManager public massetManager;\\n IFeeDistributor public feeDistributor;\\n}\\n\",\"keccak256\":\"0x5708a00804a19b3fb47bc20dc2457775228a3d7b09c4f5b33d11c4995fe77c94\",\"license\":\"MIT\"},\"contracts/Dependencies/BaseMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\n\\ncontract BaseMath {\\n uint constant public DECIMAL_PRECISION = 1e18;\\n}\\n\",\"keccak256\":\"0x7e1369ca5cb09e818e345a2def19a261401f79c985a6030b55b7311dd6f53be4\",\"license\":\"MIT\"},\"contracts/Dependencies/CheckContract.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n\\ncontract CheckContract {\\n /**\\n * @dev Check that the account is an already deployed non-destroyed contract.\\n * See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L12\\n */\\n function checkContract(address _account) internal view {\\n require(_account != address(0), \\\"Account cannot be zero address\\\");\\n\\n uint256 size;\\n // solhint-disable-next-line no-inline-assembly\\n assembly { size := extcodesize(_account) }\\n require(size > 0, \\\"Account code size cannot be zero\\\");\\n }\\n}\\n\",\"keccak256\":\"0x4c7dc4d0197c27ebc7de671b00458a9ff45f57223aeb520e6ddd2eb6d2d89e5c\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on the OpenZeppelin IER20 interface:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol\\n *\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\\n function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n function name() external view returns (string memory);\\n function symbol() external view returns (string memory);\\n function decimals() external view returns (uint8);\\n \\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\",\"keccak256\":\"0xe0b2473eba89df8d27d7cea2a99fce788c212f3fd393c9508e449e51a3f220fa\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC2612.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * @dev Interface of the ERC2612 standard as defined in the EIP.\\n *\\n * Adds the {permit} method, which can be used to change one's\\n * {IERC20-allowance} without having to send a transaction, by signing a\\n * message. This allows users to spend tokens without having to hold Ether.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2612.\\n * \\n * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/\\n */\\ninterface IERC2612 {\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,\\n * given `owner`'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(address owner, address spender, uint256 amount, \\n uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;\\n \\n /**\\n * @dev Returns the current ERC2612 nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases `owner`'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n *\\n * `owner` can limit the time a Permit is valid for by setting `deadline` to \\n * a value in the near future. The deadline argument can be set to uint(-1) to \\n * create Permits that effectively never expire.\\n */\\n function nonces(address owner) external view returns (uint256);\\n \\n function version() external view returns (string memory);\\n function permitTypeHash() external view returns (bytes32);\\n function domainSeparator() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xd376458452f8b480bfea549637bd71d3f9eb1f12e9d59d1beff373417462d67f\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./BaseMath.sol\\\";\\nimport \\\"./LiquityMath.sol\\\";\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IPriceFeed.sol\\\";\\nimport \\\"../Interfaces/ILiquityBase.sol\\\";\\nimport \\\"../Interfaces/ILiquityBaseParams.sol\\\";\\n\\n/**\\n * Base contract for TroveManager, BorrowerOperations and StabilityPool. Contains global system constants and\\n * common functions.\\n */\\ncontract LiquityBase is BaseMath, ILiquityBase {\\n using SafeMath for uint256;\\n\\n uint256 public constant _100pct = 1000000000000000000; // 1e18 == 100%\\n\\n /// Amount of ZUSD to be locked in gas pool on opening troves\\n uint256 public constant ZUSD_GAS_COMPENSATION = 20e18;\\n\\n /// Minimum amount of net ZUSD debt a trove must have\\n uint256 public constant MIN_NET_DEBT = 180e18;\\n\\n IActivePool public activePool;\\n\\n IDefaultPool public defaultPool;\\n\\n IPriceFeed public override priceFeed;\\n\\n ILiquityBaseParams public override liquityBaseParams;\\n\\n // --- Gas compensation functions ---\\n\\n // Returns the composite debt (drawn debt + gas compensation) of a trove, for the purpose of ICR calculation\\n function _getCompositeDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.add(ZUSD_GAS_COMPENSATION);\\n }\\n\\n function _getNetDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.sub(ZUSD_GAS_COMPENSATION);\\n }\\n\\n /// Return the amount of ETH to be drawn from a trove's collateral and sent as gas compensation.\\n function _getCollGasCompensation(uint256 _entireColl) internal view returns (uint256) {\\n return _entireColl / liquityBaseParams.PERCENT_DIVISOR();\\n }\\n\\n function getEntireSystemColl() public view returns (uint256 entireSystemColl) {\\n uint256 activeColl = activePool.getETH();\\n uint256 liquidatedColl = defaultPool.getETH();\\n\\n return activeColl.add(liquidatedColl);\\n }\\n\\n function getEntireSystemDebt() public view returns (uint256 entireSystemDebt) {\\n uint256 activeDebt = activePool.getZUSDDebt();\\n uint256 closedDebt = defaultPool.getZUSDDebt();\\n\\n return activeDebt.add(closedDebt);\\n }\\n\\n function _getTCR(uint256 _price) internal view returns (uint256 TCR) {\\n uint256 entireSystemColl = getEntireSystemColl();\\n uint256 entireSystemDebt = getEntireSystemDebt();\\n\\n TCR = LiquityMath._computeCR(entireSystemColl, entireSystemDebt, _price);\\n\\n return TCR;\\n }\\n\\n function _checkRecoveryMode(uint256 _price) internal view returns (bool) {\\n uint256 TCR = _getTCR(_price);\\n\\n return TCR < liquityBaseParams.CCR();\\n }\\n\\n function _requireUserAcceptsFee(\\n uint256 _fee,\\n uint256 _amount,\\n uint256 _maxFeePercentage\\n ) internal pure {\\n uint256 feePercentage = _fee.mul(DECIMAL_PRECISION).div(_amount);\\n require(feePercentage <= _maxFeePercentage, \\\"Fee exceeded provided maximum\\\");\\n }\\n}\\n\",\"keccak256\":\"0x100b8a1c17caa95f5c9977e88f9263847a1977a365ca0a795753dd74aa1d6d7c\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./console.sol\\\";\\n\\nlibrary LiquityMath {\\n using SafeMath for uint;\\n\\n uint internal constant DECIMAL_PRECISION = 1e18;\\n\\n /* Precision for Nominal ICR (independent of price). Rationale for the value:\\n *\\n * - Making it \\u201ctoo high\\u201d could lead to overflows.\\n * - Making it \\u201ctoo low\\u201d could lead to an ICR equal to zero, due to truncation from Solidity floor division. \\n *\\n * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH,\\n * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.\\n *\\n */\\n uint internal constant NICR_PRECISION = 1e20;\\n\\n function _min(uint _a, uint _b) internal pure returns (uint) {\\n return (_a < _b) ? _a : _b;\\n }\\n\\n function _max(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a : _b;\\n }\\n\\n /* \\n * Multiply two decimal numbers and use normal rounding rules:\\n * -round product up if 19'th mantissa digit >= 5\\n * -round product down if 19'th mantissa digit < 5\\n *\\n * Used only inside the exponentiation, _decPow().\\n */\\n function decMul(uint x, uint y) internal pure returns (uint decProd) {\\n uint prod_xy = x.mul(y);\\n\\n decProd = prod_xy.add(DECIMAL_PRECISION / 2).div(DECIMAL_PRECISION);\\n }\\n\\n /* \\n * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.\\n * \\n * Uses the efficient \\\"exponentiation by squaring\\\" algorithm. O(log(n)) complexity. \\n * \\n * Called by two functions that represent time in units of minutes:\\n * 1) TroveManager._calcDecayedBaseRate\\n * 2) CommunityIssuance._getCumulativeIssuanceFraction \\n * \\n * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals\\n * \\\"minutes in 1000 years\\\": 60 * 24 * 365 * 1000\\n * \\n * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be\\n * negligibly different from just passing the cap, since: \\n *\\n * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years\\n * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible\\n */\\n function _decPow(uint _base, uint _minutes) internal pure returns (uint) {\\n \\n if (_minutes > 525600000) {_minutes = 525600000;} // cap to avoid overflow\\n \\n if (_minutes == 0) {return DECIMAL_PRECISION;}\\n\\n uint y = DECIMAL_PRECISION;\\n uint x = _base;\\n uint n = _minutes;\\n\\n // Exponentiation-by-squaring\\n while (n > 1) {\\n if (n % 2 == 0) {\\n x = decMul(x, x);\\n n = n.div(2);\\n } else { // if (n % 2 != 0)\\n y = decMul(x, y);\\n x = decMul(x, x);\\n n = (n.sub(1)).div(2);\\n }\\n }\\n\\n return decMul(x, y);\\n }\\n\\n function _getAbsoluteDifference(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a.sub(_b) : _b.sub(_a);\\n }\\n\\n function _computeNominalCR(uint _coll, uint _debt) internal pure returns (uint) {\\n if (_debt > 0) {\\n return _coll.mul(NICR_PRECISION).div(_debt);\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1;\\n }\\n }\\n\\n function _computeCR(uint _coll, uint _debt, uint _price) internal pure returns (uint) {\\n if (_debt > 0) {\\n uint newCollRatio = _coll.mul(_price).div(_debt);\\n\\n return newCollRatio;\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1; \\n }\\n }\\n}\\n\",\"keccak256\":\"0x7a95ed70d8937e0896c054b433ad0dfc87a9cfd028cae1694098e9d5d68127cd\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IDLLR.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\nimport \\\"../IERC20.sol\\\";\\n\\n/// Public interface for Sovryn Dollar DLLR (Meta Asset Token of Sovryn Mynt) exposing specific functions\\ninterface IDLLR is IERC20 {\\n /**\\n * @notice Only owner can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _recipient Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transfer(address _recipient, uint256 _amount) external override returns (bool);\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _amount\\n ) external override returns (bool);\\n\\n /**\\n * @notice transfer utilizing EIP-2612, to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @dev By calling this function, the allowance will be overwritten by the total amount.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of the token that will be transferred.\\n * @param _deadline Expiration time of the signature.\\n * @param _v Last 1 byte of ECDSA signature.\\n * @param _r First 32 bytes of ECDSA signature.\\n * @param _s 32 bytes after _r in ECDSA signature.\\n */\\n function transferWithPermit(\\n address _from,\\n address _to,\\n uint256 _amount,\\n uint256 _deadline,\\n uint8 _v,\\n bytes32 _r,\\n bytes32 _s\\n ) external;\\n\\n /**\\n * @notice Approves and then calls the receiving contract.\\n * Useful to encapsulate sending tokens to a contract in one call.\\n * Solidity has no native way to send tokens to contracts.\\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\\n * @param _spender The contract address to spend the tokens.\\n * @param _amount The amount of tokens to be sent.\\n * @param _data Parameters for the contract call, such as endpoint signature.\\n */\\n function approveAndCall(address _spender, uint256 _amount, bytes calldata _data) external;\\n}\\n\",\"keccak256\":\"0x1fcc09759323769fcaa430bef598cf08a9f5e98ce6a9bdd6faa79d8b7b6ecce2\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IMassetManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IMassetManager {\\n struct PermitParams {\\n uint256 deadline;\\n uint8 v;\\n bytes32 r;\\n bytes32 s;\\n }\\n\\n function mintTo(\\n address _bAsset,\\n uint256 _bAssetQuantity,\\n address _recipient\\n ) external returns (uint256);\\n\\n function getToken() external view returns (address);\\n\\n /**\\n * @dev Credits a recipient with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @param _recipient Address to credit with withdrawn bAssets.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeemTo(\\n address _bAsset,\\n uint256 _massetQuantity,\\n address _recipient\\n ) external returns (uint256 massetRedeemed);\\n}\\n\",\"keccak256\":\"0x3e8de462d45e8f07ef83b6b6e7eb90a5d09f21d3bcbb1225e8f781488ab4a771\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/MyntLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IMassetManager.sol\\\";\\nimport \\\"./IDLLR.sol\\\";\\nimport \\\"../SafeMath.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"../../Interfaces/IPermit2.sol\\\";\\n\\nlibrary MyntLib {\\n using SafeMath for uint256;\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @dev WARNING!! Do not us this lib function on RSK network because there is a griefing attack issue in the DLLR contract.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _dllrAmount The amount of the DLLR (mAsset) token that will be burned in exchange for _toToken\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permitParams EIP-2612 permit params:\\n * _deadline Expiration time of the signature.\\n * _v Last 1 byte of ECDSA signature.\\n * _r First 32 bytes of ECDSA signature.\\n * _s 32 bytes after _r in ECDSA signature.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit(\\n IMassetManager _myntMassetManager,\\n uint256 _dllrAmount,\\n address _toToken,\\n IMassetManager.PermitParams calldata _permitParams\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n dllr.transferWithPermit(\\n msg.sender,\\n thisAddress,\\n _dllrAmount,\\n _permitParams.deadline,\\n _permitParams.v,\\n _permitParams.r,\\n _permitParams.s\\n );\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit via a canonical Permit2 contract\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permit permit data, in form of PermitTransferFrom struct.\\n * @param _permit2 permit2 contract address\\n * @param _signature signatue of the permit data.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit2(\\n IMassetManager _myntMassetManager,\\n address _toToken,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n IPermit2 _permit2,\\n bytes calldata _signature\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n uint256 _dllrAmount = _permit.permitted.amount;\\n\\n _permit2.permitTransferFrom(\\n _permit,\\n _generateTransferDetails(thisAddress, _dllrAmount),\\n msg.sender,\\n _signature\\n );\\n\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @dev view function to construct SignatureTransferDetails struct to be used by Permit2\\n *\\n * @param _to ultimate recipient\\n * @param _amount amount of transfer\\n *\\n * @return SignatureTransferDetails struct object \\n */\\n function _generateTransferDetails(address _to, uint256 _amount) private view returns (ISignatureTransfer.SignatureTransferDetails memory) {\\n ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer.SignatureTransferDetails({\\n to: _to,\\n requestedAmount: _amount\\n });\\n\\n return transferDetails;\\n }\\n}\\n\",\"keccak256\":\"0x6f0c78d8c4ea0b5b5e6bbe8d78374b9d2d367ffc07054dde36b9cbe2061944b6\",\"license\":\"MIT\"},\"contracts/Dependencies/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's Ownable contract:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\\n *\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable {\\n bytes32 private constant KEY_OWNER = keccak256(\\\"key.ownable.owner\\\");\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor () internal {\\n _setOwner(msg.sender);\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(msg.sender == getOwner(), \\\"Ownable:: access denied\\\");\\n _;\\n }\\n\\n /**\\n * @notice Set address of the owner.\\n * @param _owner Address of the owner.\\n * */\\n function _setOwner(address _owner) internal {\\n require(_owner != address(0), \\\"Ownable::setOwner: invalid address\\\");\\n emit OwnershipTransferred(getOwner(), _owner);\\n\\n bytes32 key = KEY_OWNER;\\n assembly {\\n sstore(key, _owner)\\n }\\n }\\n\\n /**\\n * @notice Set address of the owner (only owner can call this function)\\n * @param _owner Address of the owner.\\n * */\\n function setOwner(address _owner) public onlyOwner {\\n _setOwner(_owner);\\n }\\n\\n /**\\n * @notice Return address of the owner.\\n * @return _owner Address of the owner.\\n * */\\n function getOwner() public view returns (address _owner) {\\n bytes32 key = KEY_OWNER;\\n assembly {\\n _owner := sload(key)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xb5fc626e0b227fc0feb1d84440585015a0a5f586547d298534a604dd113efec6\",\"license\":\"MIT\"},\"contracts/Dependencies/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's SafeMath:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol\\n *\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x666b890992a066cc791f36c2975cd595d9761a014c654c385ed36ffaf658f3fd\",\"license\":\"MIT\"},\"contracts/Dependencies/console.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Buidler's helper contract for console logging\\nlibrary console {\\n\\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\\n\\n\\tfunction log() internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log()\\\"));\\n\\t\\tignored;\\n\\t}\\tfunction logInt(int p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(int)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logUint(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logString(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBool(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logAddress(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes(bytes memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logByte(byte p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(byte)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes1(bytes1 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes1)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes2(bytes2 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes2)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes3(bytes3 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes3)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes4(bytes4 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes4)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes5(bytes5 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes5)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes6(bytes6 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes6)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes7(bytes7 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes7)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes8(bytes8 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes8)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes9(bytes9 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes9)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes10(bytes10 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes10)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes11(bytes11 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes11)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes12(bytes12 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes12)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes13(bytes13 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes13)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes14(bytes14 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes14)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes15(bytes15 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes15)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes16(bytes16 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes16)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes17(bytes17 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes17)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes18(bytes18 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes18)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes19(bytes19 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes19)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes20(bytes20 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes20)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes21(bytes21 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes21)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes22(bytes22 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes22)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes23(bytes23 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes23)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes24(bytes24 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes24)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes25(bytes25 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes25)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes26(bytes26 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes26)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes27(bytes27 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes27)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes28(bytes28 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes28)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes29(bytes29 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes29)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes30(bytes30 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes30)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes31(bytes31 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes31)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes32(bytes32 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes32)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n}\\n\",\"keccak256\":\"0x6fa1de4ffe22b8f58b0b64d65db11dd5037be9b9db47b365a72adb489e217000\",\"license\":\"MIT\"},\"contracts/Interfaces/IActivePool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\n/**\\n * The Active Pool holds the ETH collateral and ZUSD debt (but not ZUSD tokens) for all active troves.\\n *\\n * When a trove is liquidated, it's ETH and ZUSD debt are transferred from the Active Pool, to either the\\n * Stability Pool, the Default Pool, or both, depending on the liquidation conditions.\\n *\\n */\\ninterface IActivePool is IPool {\\n // --- Events ---\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolZUSDDebtUpdated(uint _ZUSDDebt);\\n event ActivePoolETHBalanceUpdated(uint _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH amount to given account. Updates ActivePool balance. Only callable by BorrowerOperations, TroveManager or StabilityPool.\\n /// @param _account account to receive the ETH amount\\n /// @param _amount ETH amount to send\\n function sendETH(address _account, uint _amount) external;\\n}\\n\",\"keccak256\":\"0xdd5f1b6fae4050b4c885a85a10c2d0e73b82187a51736d009065aaeea33bf0d0\",\"license\":\"MIT\"},\"contracts/Interfaces/IAllowanceTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title AllowanceTransfer\\n/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface IAllowanceTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an ordered nonce.\\n event NonceInvalidation(\\n address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.\\n event Approval(\\n address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.\\n event Permit(\\n address indexed owner,\\n address indexed token,\\n address indexed spender,\\n uint160 amount,\\n uint48 expiration,\\n uint48 nonce\\n );\\n\\n /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.\\n event Lockdown(address indexed owner, address token, address spender);\\n\\n /// @notice The permit data for a token\\n struct PermitDetails {\\n // ERC20 token address\\n address token;\\n // the maximum amount allowed to spend\\n uint160 amount;\\n // timestamp at which a spender's token allowances become invalid\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice The permit message signed for a single token allowance\\n struct PermitSingle {\\n // the permit data for a single token alownce\\n PermitDetails details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The permit message signed for multiple token allowances\\n struct PermitBatch {\\n // the permit data for multiple token allowances\\n PermitDetails[] details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The saved permissions\\n /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n struct PackedAllowance {\\n // amount allowed\\n uint160 amount;\\n // permission expiry\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice A token spender pair.\\n struct TokenSpenderPair {\\n // the token the spender is approved\\n address token;\\n // the spender address\\n address spender;\\n }\\n\\n /// @notice Details for a token transfer.\\n struct AllowanceTransferDetails {\\n // the owner of the token\\n address from;\\n // the recipient of the token\\n address to;\\n // the amount of the token\\n uint160 amount;\\n // the token to be transferred\\n address token;\\n }\\n\\n /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.\\n /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]\\n /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.\\n function allowance(address user, address token, address spender)\\n external\\n view\\n returns (uint160 amount, uint48 expiration, uint48 nonce);\\n\\n /// @notice Approves the spender to use up to amount of the specified token up until the expiration\\n /// @param token The token to approve\\n /// @param spender The spender address to approve\\n /// @param amount The approved amount of the token\\n /// @param expiration The timestamp at which the approval is no longer valid\\n /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n function approve(address token, address spender, uint160 amount, uint48 expiration) external;\\n\\n /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitSingle Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;\\n\\n /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitBatch Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;\\n\\n /// @notice Transfer approved tokens from one address to another\\n /// @param from The address to transfer from\\n /// @param to The address of the recipient\\n /// @param amount The amount of the token to transfer\\n /// @param token The token address to transfer\\n /// @dev Requires the from address to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(address from, address to, uint160 amount, address token) external;\\n\\n /// @notice Transfer approved tokens in a batch\\n /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers\\n /// @dev Requires the from addresses to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;\\n\\n /// @notice Enables performing a \\\"lockdown\\\" of the sender's Permit2 identity\\n /// by batch revoking approvals\\n /// @param approvals Array of approvals to revoke.\\n function lockdown(TokenSpenderPair[] calldata approvals) external;\\n\\n /// @notice Invalidate nonces for a given (token, spender) pair\\n /// @param token The token to invalidate nonces for\\n /// @param spender The spender to invalidate nonces for\\n /// @param newNonce The new nonce to set. Invalidates all nonces less than it.\\n /// @dev Can't invalidate more than 2**16 nonces per transaction.\\n function invalidateNonces(address token, address spender, uint48 newNonce) external;\\n}\\n\",\"keccak256\":\"0xf15059fb68f89542908f963f22e18c0b0ae9997a6f9aaf6a9fb46aa2424acac9\",\"license\":\"MIT\"},\"contracts/Interfaces/IBorrowerOperations.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface IBorrowerOperations {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event TroveCreated(address indexed _borrower, uint256 arrayIndex);\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event ZUSDBorrowingFeePaid(address indexed _borrower, uint256 _ZUSDFee);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeDistributorAddress feeDistributor contract address\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _defaultPoolAddress DefaultPool contract address\\n * @param _stabilityPoolAddress StabilityPool contract address\\n * @param _gasPoolAddress GasPool contract address\\n * @param _collSurplusPoolAddress CollSurplusPool contract address\\n * @param _priceFeedAddress PrideFeed contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n address _feeDistributorAddress,\\n address _liquityBaseParamsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _defaultPoolAddress,\\n address _stabilityPoolAddress,\\n address _gasPoolAddress,\\n address _collSurplusPoolAddress,\\n address _priceFeedAddress,\\n address _sortedTrovesAddress,\\n address _zusdTokenAddress,\\n address _zeroStakingAddress\\n ) external;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * This method is identical to `openTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openNueTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /// @notice payable function that adds the received Ether to the caller's active Trove.\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function addColl(address _upperHint, address _lowerHint) external payable;\\n\\n /// @notice send ETH as collateral to a trove. Called by only the Stability Pool.\\n /// @param _user user trove address\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function moveETHGainToTrove(\\n address _user,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice withdraws `_amount` of collateral from the caller\\u2019s Trove.\\n * Executes only if the user has an active Trove, the withdrawal would not pull the user\\u2019s Trove below the minimum collateralization ratio,\\n * and the resulting total collateralization ratio of the system is above 150%.\\n * @param _amount collateral amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawColl(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice issues `_amount` of ZUSD from the caller\\u2019s Trove to the caller.\\n * Executes only if the Trove's collateralization ratio would remain above the minimum, and the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _amount ZUSD amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawZUSD(\\n uint256 _maxFee,\\n uint256 _amount,\\n address _upperHint,\\n address _lowerHint\\n ) external;\\n\\n /// Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction\\n function withdrawZusdAndConvertToDLLR(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external returns (uint256);\\n\\n /// @notice repay `_amount` of ZUSD to the caller\\u2019s Trove, subject to leaving 50 debt in the Trove (which corresponds to the 50 ZUSD gas compensation).\\n /// @param _amount ZUSD amount to repay\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function repayZUSD(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLR(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLRWithPermit2(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a ZUSD balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` ZUSD.\\n */\\n function closeTrove() external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTrove(IMassetManager.PermitParams calldata _permitParams) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTroveWithPermit2(ISignatureTransfer.PermitTransferFrom memory _permit, bytes calldata _signature) external;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTroveWithPermit2(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external payable;\\n\\n /**\\n * @notice when a borrower\\u2019s Trove has been fully redeemed from and closed, or liquidated in Recovery Mode with a collateralization ratio above 110%,\\n * this function allows the borrower to claim their ETH collateral surplus that remains in the system (collateral - debt upon redemption; collateral - 110% of the debt upon liquidation).\\n */\\n function claimCollateral() external;\\n\\n function getCompositeDebt(uint256 _debt) external view returns (uint256);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint256);\\n\\n function getMassetManager() external view returns (IMassetManager);\\n}\\n\",\"keccak256\":\"0x75da117f4bc4cca15fc16ca0466c68894f1befed0471ea7a670fa9b466ef2bc5\",\"license\":\"MIT\"},\"contracts/Interfaces/ICollSurplusPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ICollSurplusPool {\\n // --- Events ---\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n\\n event CollBalanceUpdated(address indexed _account, uint256 _newBalance);\\n event EtherSent(address _to, uint256 _amount);\\n\\n // --- Contract setters ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH state variable\\n function getETH() external view returns (uint256);\\n\\n /// @param _account account to retrieve collateral\\n /// @return collateral\\n function getCollateral(address _account) external view returns (uint256);\\n\\n /// @notice adds amount to current account balance. Only callable by TroveManager.\\n /// @param _account account to add amount\\n /// @param _amount amount to add\\n function accountSurplus(address _account, uint256 _amount) external;\\n\\n /// @notice claims collateral for given account. Only callable by BorrowerOperations.\\n /// @param _account account to send claimable collateral\\n function claimColl(address _account) external;\\n}\\n\",\"keccak256\":\"0xac983936efe70d19205bff65a18b4e6000d489d4e4d1e2e92f951873cee91048\",\"license\":\"MIT\"},\"contracts/Interfaces/IDefaultPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\ninterface IDefaultPool is IPool {\\n // --- Events ---\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event DefaultPoolZUSDDebtUpdated(uint256 _ZUSDDebt);\\n event DefaultPoolETHBalanceUpdated(uint256 _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH to Active Pool\\n /// @param _amount ETH to send\\n function sendETHToActivePool(uint256 _amount) external;\\n}\\n\",\"keccak256\":\"0xfb2607676b2eb0f2defd248b4dd32895820048317f29aa6bdb572403a3e3d44e\",\"license\":\"MIT\"},\"contracts/Interfaces/IEIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\ninterface IEIP712 {\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xff52e9168eaa532ebacdad2ab6197f60171e3aa2fa2c1d6397d9da4d7782a543\",\"license\":\"MIT\"},\"contracts/Interfaces/IFeeDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/// Common interface for Fee Distributor.\\ninterface IFeeDistributor {\\n // --- Events ---\\n\\n event FeeSharingCollectorAddressChanged(address _feeSharingCollectorAddress);\\n event ZeroStakingAddressChanged(address _zeroStakingAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event WrbtcAddressChanged(address _wrbtcAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event ZUSDDistributed(uint256 _zusdDistributedAmount);\\n event RBTCistributed(uint256 _rbtcDistributedAmount);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeSharingCollectorAddress FeeSharingCollector address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n * @param _borrowerOperationsAddress borrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _wrbtcAddress wrbtc ERC20 contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _feeSharingCollectorAddress,\\n address _zeroStakingAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _wrbtcAddress,\\n address _zusdTokenAddress,\\n address _activePoolAddress\\n ) external;\\n\\n function distributeFees() external;\\n}\\n\",\"keccak256\":\"0x4b9bc6eaa8a9ea5e0570ffd84c0af2a92e74b001ae1ee1c8518d76382691a07f\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPriceFeed.sol\\\";\\nimport \\\"./ILiquityBaseParams.sol\\\";\\n\\ninterface ILiquityBase {\\n /// @return PriceFeed contract\\n function priceFeed() external view returns (IPriceFeed);\\n\\n /// @return LiquityBaseParams contract\\n function liquityBaseParams() external view returns (ILiquityBaseParams);\\n}\\n\",\"keccak256\":\"0xa4a57bd79e64d56a687c28d2a35c55b733fde8dda2a7ba861606eed3211724e1\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBaseParams.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ILiquityBaseParams {\\n\\n /// Minimum collateral ratio for individual troves\\n function MCR() external view returns (uint);\\n\\n /// Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.\\n function CCR() external view returns (uint);\\n\\n function PERCENT_DIVISOR() external view returns (uint);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint);\\n\\n /**\\n * Half-life of 12h. 12h = 720 min\\n * (1/2) = d^720 => d = (1/2)^(1/720)\\n */\\n function REDEMPTION_FEE_FLOOR() external view returns (uint);\\n\\n function MAX_BORROWING_FEE() external view returns (uint);\\n\\n}\",\"keccak256\":\"0xef8c0e8ad5d13d604c11b04983ff5bdd41768b646f2b33f45ddd988adec204e0\",\"license\":\"MIT\"},\"contracts/Interfaces/IPermit2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {ISignatureTransfer} from \\\"./ISignatureTransfer.sol\\\";\\nimport {IAllowanceTransfer} from \\\"./IAllowanceTransfer.sol\\\";\\n\\n/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer.\\n/// @dev Users must approve Permit2 before calling any of the transfer functions.\\ninterface IPermit2 is ISignatureTransfer, IAllowanceTransfer {\\n// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval.\\n}\\n\",\"keccak256\":\"0x3df819f5ca8de7324a676839d72e9f44c0f789c41c13bf0a892f3bb98d72ee86\",\"license\":\"MIT\"},\"contracts/Interfaces/IPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the Pools.\\ninterface IPool {\\n // --- Events ---\\n\\n event ETHBalanceUpdated(uint _newBalance);\\n event ZUSDBalanceUpdated(uint _newBalance);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event EtherSent(address _to, uint _amount);\\n\\n // --- Functions ---\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH pool balance\\n function getETH() external view returns (uint);\\n\\n /// @return ZUSD debt pool balance\\n function getZUSDDebt() external view returns (uint);\\n\\n /// @notice Increases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to add to the pool debt\\n function increaseZUSDDebt(uint _amount) external;\\n\\n /// @notice Decreases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to subtract to the pool debt\\n function decreaseZUSDDebt(uint _amount) external;\\n}\\n\",\"keccak256\":\"0x148e87ab38c6176d74f36c9e8989b99e768a7b18d8a045f1f01d6583b986806d\",\"license\":\"MIT\"},\"contracts/Interfaces/IPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IPriceFeed {\\n // --- Events ---\\n event LastGoodPriceUpdated(uint256 _lastGoodPrice);\\n\\n // --- Function ---\\n\\n /// @notice Returns the latest price obtained from the Oracle. Called by Zero functions that require a current price.\\n /// It uses the main price feed and fallback to the backup one in case of an error. If both fail return the last\\n /// good price seen.\\n /// @dev It's also callable by anyone externally\\n /// @return The price\\n function fetchPrice() external returns (uint256);\\n}\\n\",\"keccak256\":\"0x85fd97219a8156209d2cb5c6ae7c5ead01d893db000bf575023fcef0e62f9591\",\"license\":\"MIT\"},\"contracts/Interfaces/ISignatureTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title SignatureTransfer\\n/// @notice Handles ERC20 token transfers through signature based actions\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface ISignatureTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an unordered nonce.\\n event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);\\n\\n /// @notice The token and amount details for a transfer signed in the permit transfer signature\\n struct TokenPermissions {\\n // ERC20 token address\\n address token;\\n // the maximum amount that can be spent\\n uint256 amount;\\n }\\n\\n /// @notice The signed permit message for a single token transfer\\n struct PermitTransferFrom {\\n TokenPermissions permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice Specifies the recipient address and amount for batched transfers.\\n /// @dev Recipients and amounts correspond to the index of the signed token permissions array.\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount.\\n struct SignatureTransferDetails {\\n // recipient address\\n address to;\\n // spender requested amount\\n uint256 requestedAmount;\\n }\\n\\n /// @notice Used to reconstruct the signed permit message for multiple token transfers\\n /// @dev Do not need to pass in spender address as it is required that it is msg.sender\\n /// @dev Note that a user still signs over a spender address\\n struct PermitBatchTransferFrom {\\n // the tokens and corresponding amounts permitted for a transfer\\n TokenPermissions[] permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection\\n /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order\\n /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce\\n /// @dev It returns a uint256 bitmap\\n /// @dev The index, or wordPosition is capped at type(uint248).max\\n function nonceBitmap(address, uint256) external view returns (uint256);\\n\\n /// @notice Transfers a token using a signed permit message\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails The spender's requested transfer details for the permitted token\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitTransferFrom memory permit,\\n SignatureTransferDetails calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Transfers multiple tokens using a signed permit message\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails Specifies the recipient and requested amount for the token transfer\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitBatchTransferFrom memory permit,\\n SignatureTransferDetails[] calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Invalidates the bits specified in mask for the bitmap at the word position\\n /// @dev The wordPos is maxed at type(uint248).max\\n /// @param wordPos A number to index the nonceBitmap at\\n /// @param mask A bitmap masked against msg.sender's current bitmap at the word position\\n function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;\\n}\\n\",\"keccak256\":\"0x7efc63c119694e23dd76e44a5b125999829026bbc23409de7646a6a45e1ac341\",\"license\":\"MIT\"},\"contracts/Interfaces/ISortedTroves.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the SortedTroves Doubly Linked List.\\ninterface ISortedTroves {\\n // --- Events ---\\n\\n event SortedTrovesAddressChanged(address _sortedDoublyLLAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event NodeAdded(address _id, uint256 _NICR);\\n event NodeRemoved(address _id);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts and size. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _size max size of troves list\\n * @param _TroveManagerAddress TroveManager contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n */\\n function setParams(\\n uint256 _size,\\n address _TroveManagerAddress,\\n address _borrowerOperationsAddress\\n ) external;\\n\\n /**\\n * @dev Add a node to the list\\n * @param _id Node's id\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function insert(\\n address _id,\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Remove a node from the list\\n * @param _id Node's id\\n */\\n function remove(address _id) external;\\n\\n /**\\n * @dev Re-insert the node at a new position, based on its new NICR\\n * @param _id Node's id\\n * @param _newICR Node's new NICR\\n * @param _prevId Id of previous node for the new insert position\\n * @param _nextId Id of next node for the new insert position\\n */\\n function reInsert(\\n address _id,\\n uint256 _newICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Checks if the list contains a node\\n * @param _id Node's id\\n * @return true if list contains a node with given id\\n */\\n function contains(address _id) external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is full\\n * @return true if list is full\\n */\\n function isFull() external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is empty\\n * @return true if list is empty\\n */\\n function isEmpty() external view returns (bool);\\n\\n /**\\n * @return list current size\\n */\\n function getSize() external view returns (uint256);\\n\\n /**\\n * @return list max size\\n */\\n function getMaxSize() external view returns (uint256);\\n\\n /**\\n * @return the first node in the list (node with the largest NICR)\\n */\\n function getFirst() external view returns (address);\\n\\n /**\\n * @return the last node in the list (node with the smallest NICR)\\n */\\n function getLast() external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the next node (with a smaller NICR) in the list for a given node\\n */\\n function getNext(address _id) external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the previous node (with a larger NICR) in the list for a given node\\n */\\n function getPrev(address _id) external view returns (address);\\n\\n /**\\n * @notice Check if a pair of nodes is a valid insertion point for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function validInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (bool);\\n\\n /**\\n * @notice Find the insert position for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function findInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (address, address);\\n}\\n\",\"keccak256\":\"0x7328ad009da6230ddea1559564428464a5c3ace2258fb534dfbba5b5a8c7c60d\",\"license\":\"MIT\"},\"contracts/Interfaces/IStabilityPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/*\\n * The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors.\\n *\\n * When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with\\n * ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned.\\n *\\n * Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits.\\n * They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors,\\n * in the same proportion.\\n *\\n * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40%\\n * of the total ZUSD in the Stability Pool, depletes 40% of each deposit.\\n *\\n * A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit,\\n * multiplying it by some factor in range ]0,1[\\n *\\n * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations:\\n * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf\\n *\\n * --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS ---\\n *\\n * An SOV issuance event occurs at every deposit operation, and every liquidation.\\n *\\n * Each deposit is tagged with the address of the front end through which it was made.\\n *\\n * All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned\\n * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate.\\n *\\n * Please see the system Readme for an overview:\\n * https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers\\n */\\ninterface IStabilityPool {\\n // --- Events ---\\n\\n event StabilityPoolETHBalanceUpdated(uint _newBalance);\\n event StabilityPoolZUSDBalanceUpdated(uint _newBalance);\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event SortedTrovesAddressChanged(address _newSortedTrovesAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);\\n\\n event P_Updated(uint _P);\\n event S_Updated(uint _S, uint128 _epoch, uint128 _scale);\\n event G_Updated(uint _G, uint128 _epoch, uint128 _scale);\\n event EpochUpdated(uint128 _currentEpoch);\\n event ScaleUpdated(uint128 _currentScale);\\n\\n event FrontEndRegistered(address indexed _frontEnd, uint _kickbackRate);\\n event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd);\\n\\n event DepositSnapshotUpdated(address indexed _depositor, uint _P, uint _S, uint _G);\\n event FrontEndSnapshotUpdated(address indexed _frontEnd, uint _P, uint _G);\\n event UserDepositChanged(address indexed _depositor, uint _newDeposit);\\n event FrontEndStakeChanged(\\n address indexed _frontEnd,\\n uint _newFrontEndStake,\\n address _depositor\\n );\\n\\n event ETHGainWithdrawn(address indexed _depositor, uint _ETH, uint _ZUSDLoss);\\n event SOVPaidToDepositor(address indexed _depositor, uint _SOV);\\n event SOVPaidToFrontEnd(address indexed _frontEnd, uint _SOV);\\n event EtherSent(address _to, uint _amount);\\n\\n event WithdrawFromSpAndConvertToDLLR(\\n address _depositor,\\n uint256 _zusdAmountRequested,\\n uint256 _dllrAmountReceived\\n );\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Liquity contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _priceFeedAddress PriceFeed contract address\\n * @param _communityIssuanceAddress CommunityIssuanceAddress\\n */\\n function setAddresses(\\n address _liquityBaseParamsAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _zusdTokenAddress,\\n address _sortedTrovesAddress,\\n address _priceFeedAddress,\\n address _communityIssuanceAddress\\n ) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend is registered or zero address\\n * - Sender is not a registered frontend\\n * - _amount is not zero\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Tags the deposit with the provided front end tag param, if it's a new deposit\\n * - Sends depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Increases deposit and tagged front end's stake, and takes new snapshots for each.\\n * @param _amount amount to provide\\n * @param _frontEndTag frontend address to receive accumulated SOV gains\\n */\\n function provideToSP(uint _amount, address _frontEndTag) external;\\n\\n /**\\n * @notice Initial checks:\\n * - _amount is zero or there are no under collateralized troves left in the system\\n * - User has a non zero deposit\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Removes the deposit's front end tag if it is a full withdrawal\\n * - Sends all depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.\\n *\\n * If _amount > userDeposit, the user withdraws all of their compounded deposit.\\n * @param _amount amount to withdraw\\n */\\n function withdrawFromSP(uint _amount) external;\\n\\n /**\\n * @notice Initial checks:\\n * - User has a non zero deposit\\n * - User has an open trove\\n * - User has some ETH gain\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Sends all depositor's SOV gain to depositor\\n * - Sends all tagged front end's SOV gain to the tagged front end\\n * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove\\n * - Leaves their compounded deposit in the Stability Pool\\n * - Updates snapshots for deposit and tagged front end stake\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend (sender) not already registered\\n * - User (sender) has no deposit\\n * - _kickbackRate is in the range [0, 100%]\\n * ---\\n * Front end makes a one-time selection of kickback rate upon registering\\n * @param _kickbackRate kickback rate selected by frontend\\n */\\n function registerFrontEnd(uint _kickbackRate) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Caller is TroveManager\\n * ---\\n * Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible)\\n * and transfers the Trove's ETH collateral from ActivePool to StabilityPool.\\n * Only called by liquidation functions in the TroveManager.\\n * @param _debt debt to cancel\\n * @param _coll collateral to transfer\\n */\\n function offset(uint _debt, uint _coll) external;\\n\\n /**\\n * @return the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`,\\n * to exclude edge cases like ETH received from a self-destruct.\\n */\\n function getETH() external view returns (uint);\\n\\n /**\\n * @return ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\\n */\\n function getTotalZUSDDeposits() external view returns (uint);\\n\\n /**\\n * @notice Calculates the ETH gain earned by the deposit since its last snapshots were taken.\\n * @param _depositor address to calculate ETH gain\\n * @return ETH gain from given depositor\\n */\\n function getDepositorETHGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice Calculate the SOV gain earned by a deposit since its last snapshots were taken.\\n * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned.\\n * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through\\n * which they made their deposit.\\n * @param _depositor address to calculate ETH gain\\n * @return SOV gain from given depositor\\n */\\n function getDepositorSOVGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @param _frontEnd front end address\\n * @return the SOV gain earned by the front end.\\n */\\n function getFrontEndSOVGain(address _frontEnd) external view returns (uint);\\n\\n /**\\n * @param _depositor depositor address\\n * @return the user's compounded deposit.\\n */\\n function getCompoundedZUSDDeposit(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\\n * @param _frontEnd front end address\\n * @return the front end's compounded stake.\\n */\\n function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint);\\n\\n //DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDLLR(\\n uint _dllrAmount,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function provideToSpFromDllrWithPermit2(\\n uint256 _dllrAmount,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /// Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and optionally convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\\n function withdrawFromSpAndConvertToDLLR(uint256 _zusdAmount) external;\\n\\n /**\\n * Fallback function\\n * Only callable by Active Pool, it just accounts for ETH received\\n * receive() external payable;\\n */\\n}\\n\",\"keccak256\":\"0xb35c5ec991dd2b4f8ecb6b28ae29e97313fca6054aa0df14ebdb7336fcea84a6\",\"license\":\"MIT\"},\"contracts/Interfaces/ITroveManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./ILiquityBase.sol\\\";\\nimport \\\"./IStabilityPool.sol\\\";\\nimport \\\"./IZUSDToken.sol\\\";\\nimport \\\"./IZEROToken.sol\\\";\\nimport \\\"./IZEROStaking.sol\\\";\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface ITroveManager is ILiquityBase {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerRedeemOpsAddressChanged(address _troveManagerRedeemOps);\\n event LiquityBaseParamsAddressChanges(address _borrowerOperationsAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZEROTokenAddressChanged(address _zeroTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event Liquidation(\\n uint256 _liquidatedDebt,\\n uint256 _liquidatedColl,\\n uint256 _collGasCompensation,\\n uint256 _ZUSDGasCompensation\\n );\\n event Redemption(\\n uint256 _attemptedZUSDAmount,\\n uint256 _actualZUSDAmount,\\n uint256 _ETHSent,\\n uint256 _ETHFee\\n );\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event TroveLiquidated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint8 operation\\n );\\n event BaseRateUpdated(uint256 _baseRate);\\n event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);\\n event TotalStakesUpdated(uint256 _newTotalStakes);\\n event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);\\n event LTermsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveIndexUpdated(address _borrower, uint256 _newIndex);\\n\\n struct TroveManagerInitAddressesParams {\\n address _feeDistributorAddress;\\n address _troveManagerRedeemOps;\\n address _liquityBaseParamsAddress;\\n address _borrowerOperationsAddress;\\n address _activePoolAddress;\\n address _defaultPoolAddress;\\n address _stabilityPoolAddress;\\n address _gasPoolAddress;\\n address _collSurplusPoolAddress;\\n address _priceFeedAddress;\\n address _zusdTokenAddress;\\n address _sortedTrovesAddress;\\n address _zeroTokenAddress;\\n address _zeroStakingAddress;\\n }\\n\\n // --- Functions ---\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _troveManagerInitAddresses addresses list to intialize TroveManager with _\\n * _feeDistributorAddress feeDistributor contract address\\n * _troveManagerRedeemOps TroveManagerRedeemOps contract address\\n * _liquityBaseParamsAddress LiquityBaseParams contract address\\n * _borrowerOperationsAddress BorrowerOperations contract address\\n * _activePoolAddress ActivePool contract address\\n * _defaultPoolAddress DefaultPool contract address\\n * _stabilityPoolAddress StabilityPool contract address\\n * _gasPoolAddress GasPool contract address\\n * _collSurplusPoolAddress CollSurplusPool contract address\\n * _priceFeedAddress PriceFeed contract address\\n * _zusdTokenAddress ZUSDToken contract address\\n * _sortedTrovesAddress SortedTroves contract address\\n * _zeroTokenAddress ZEROToken contract address\\n * _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n TroveManagerInitAddressesParams memory _troveManagerInitAddresses\\n ) external;\\n\\n function setTroveManagerRedeemOps(address _troveManagerRedeemOps) external;\\n\\n /// @return Trove owners count\\n function getTroveOwnersCount() external view returns (uint256);\\n\\n /// @param _index Trove owner index\\n /// @return Trove from TroveOwners array in given index\\n function getTroveFromTroveOwnersArray(uint256 _index) external view returns (address);\\n\\n /// @param _borrower borrower address\\n /// @return the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getNominalICR(address _borrower) external view returns (uint256);\\n\\n /// @notice computes the user\\u2019s individual collateralization ratio (ICR) based on their total collateral and total ZUSD debt. Returns 2^256 -1 if they have 0 debt.\\n /// @param _borrower borrower address\\n /// @param _price ETH price\\n /// @return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getCurrentICR(address _borrower, uint256 _price) external view returns (uint256);\\n\\n /// @notice Closes the trove if its ICR is lower than the minimum collateral ratio.\\n /// @param _borrower borrower address\\n function liquidate(address _borrower) external;\\n\\n /**\\n * @notice Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves,\\n * starting from the one with the lowest collateral ratio in the system, and moving upwards\\n * @param _n max number of under-collateralized Troves to liquidate\\n */\\n function liquidateTroves(uint256 _n) external;\\n\\n /**\\n * @notice Attempt to liquidate a custom list of troves provided by the caller.\\n * @param _troveArray list of trove addresses\\n */\\n function batchLiquidateTroves(address[] calldata _troveArray) external;\\n\\n /**\\n * @notice Send _ZUSDamount ZUSD to the system and redeem the corresponding amount of collateral from as many Troves as are needed to fill the redemption\\n * request. Applies pending rewards to a Trove before reducing its debt and coll.\\n *\\n * Note that if _amount is very large, this function can run out of gas, specially if traversed troves are small. This can be easily avoided by\\n * splitting the total _amount in appropriate chunks and calling the function multiple times.\\n *\\n * Param `_maxIterations` can also be provided, so the loop through Troves is capped (if it\\u2019s zero, it will be ignored).This makes it easier to\\n * avoid OOG for the frontend, as only knowing approximately the average cost of an iteration is enough, without needing to know the \\u201ctopology\\u201d\\n * of the trove list. It also avoids the need to set the cap in stone in the contract, nor doing gas calculations, as both gas price and opcode\\n * costs can vary.\\n *\\n * All Troves that are redeemed from -- with the likely exception of the last one -- will end up with no debt left, therefore they will be closed.\\n * If the last Trove does have some remaining debt, it has a finite ICR, and the reinsertion could be anywhere in the list, therefore it requires a hint.\\n * A frontend should use getRedemptionHints() to calculate what the ICR of this Trove will be after redemption, and pass a hint for its position\\n * in the sortedTroves list along with the ICR value that the hint was found for.\\n *\\n * If another transaction modifies the list between calling getRedemptionHints() and passing the hints to redeemCollateral(), it\\n * is very likely that the last (partially) redeemed Trove would end up with a different ICR than what the hint is for. In this case the\\n * redemption will stop after the last completely redeemed Trove and the sender will keep the remaining ZUSD amount, which they can attempt\\n * to redeem later.\\n *\\n * @param _ZUSDAmount ZUSD amount to send to the system\\n * @param _firstRedemptionHint calculated ICR hint of first trove after redemption\\n * @param _maxIterations max Troves iterations (can be 0)\\n * @param _maxFee max fee percentage to accept\\n */\\n function redeemCollateral(\\n uint256 _ZUSDAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFee\\n ) external;\\n\\n function redeemCollateralViaDLLR(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function redeemCollateralViaDllrWithPermit2(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n \\n\\n /// @notice Update borrower's stake based on their latest collateral value\\n /// @param _borrower borrower address\\n function updateStakeAndTotalStakes(address _borrower) external returns (uint256);\\n\\n /// @notice Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values\\n /// @param _borrower borrower address\\n function updateTroveRewardSnapshots(address _borrower) external;\\n\\n /// @notice Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct\\n /// @param _borrower borrower address\\n /// @return index where Trove was inserted\\n function addTroveOwnerToArray(address _borrower) external returns (uint256 index);\\n\\n /// @notice Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\\n /// @param _borrower borrower address\\n function applyPendingRewards(address _borrower) external;\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ETH reward, earned by their stake\\n function getPendingETHReward(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ZUSD reward, earned by their stake\\n function getPendingZUSDDebtReward(address _borrower) external view returns (uint256);\\n\\n /*\\n * @notice A Trove has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:\\n * this indicates that rewards have occured since the snapshot was made, and the user therefore has\\n * pending rewards\\n *\\n * @param _borrower borrower address\\n * @return true if has pending rewards\\n */\\n function hasPendingRewards(address _borrower) external view returns (bool);\\n\\n /// @notice returns the Troves entire debt and coll, including pending rewards from redistributions.\\n /// @param _borrower borrower address\\n function getEntireDebtAndColl(\\n address _borrower\\n )\\n external\\n view\\n returns (\\n uint256 debt,\\n uint256 coll,\\n uint256 pendingZUSDDebtReward,\\n uint256 pendingETHReward\\n );\\n\\n /// @notice Close given trove. Called by BorrowerOperations.\\n /// @param _borrower borrower address\\n function closeTrove(address _borrower) external;\\n\\n /// @notice Remove borrower's stake from the totalStakes sum, and set their stake to 0\\n /// @param _borrower borrower address\\n function removeStake(address _borrower) external;\\n\\n /// @return calculated redemption rate using baseRate\\n function getRedemptionRate() external view returns (uint256);\\n\\n /// @return calculated redemption rate using calculated decayed as base rate\\n function getRedemptionRateWithDecay() external view returns (uint256);\\n\\n /// @notice The redemption fee is taken as a cut of the total ETH drawn from the system in a redemption. It is based on the current redemption rate.\\n /// @param _ETHDrawn ETH drawn\\n function getRedemptionFeeWithDecay(uint256 _ETHDrawn) external view returns (uint256);\\n\\n /// @return borrowing rate\\n function getBorrowingRate() external view returns (uint256);\\n\\n /// @return borrowing rate calculated using decayed as base rate\\n function getBorrowingRateWithDecay() external view returns (uint256);\\n\\n /// @param ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate\\n function getBorrowingFee(uint256 ZUSDDebt) external view returns (uint256);\\n\\n /// @param _ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate with decay\\n function getBorrowingFeeWithDecay(uint256 _ZUSDDebt) external view returns (uint256);\\n\\n /// @notice Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation.\\n function decayBaseRateFromBorrowing() external;\\n\\n /// @param _borrower borrower address\\n /// @return Trove status from given trove\\n function getTroveStatus(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove stake from given trove\\n function getTroveStake(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove debt from given trove\\n function getTroveDebt(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove collateral from given trove\\n function getTroveColl(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param num status to set\\n function setTroveStatus(address _borrower, uint256 num) external;\\n\\n /// @param _borrower borrower address\\n /// @param _collIncrease amount of collateral to increase\\n /// @return new trove collateral\\n function increaseTroveColl(\\n address _borrower,\\n uint256 _collIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _collDecrease amount of collateral to decrease\\n /// @return new trove collateral\\n function decreaseTroveColl(\\n address _borrower,\\n uint256 _collDecrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtIncrease amount of debt to increase\\n /// @return new trove debt\\n function increaseTroveDebt(\\n address _borrower,\\n uint256 _debtIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtDecrease amount of debt to decrease\\n /// @return new trove debt\\n function decreaseTroveDebt(\\n address _borrower,\\n uint256 _debtDecrease\\n ) external returns (uint256);\\n\\n /**\\n * @param _price ETH price\\n * @return the total collateralization ratio (TCR) of the system.\\n * The TCR is based on the the entire system debt and collateral (including pending rewards).\\n */\\n function getTCR(uint256 _price) external view returns (uint256);\\n\\n function MCR() external view returns (uint256);\\n\\n function CCR() external view returns (uint256);\\n\\n /// @notice reveals whether or not the system is in Recovery Mode (i.e. whether the Total Collateralization Ratio (TCR) is below the Critical Collateralization Ratio (CCR)).\\n function checkRecoveryMode(uint256 _price) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x396367eb7763c289e419a025532150e2a1d9d99eead359ceb6a081787501a00b\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROStaking.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IZEROStaking {\\n // --- Events --\\n\\n event ZEROTokenAddressSet(address _zeroTokenAddress);\\n event ZUSDTokenAddressSet(address _zusdTokenAddress);\\n event FeeDistributorAddressAddressSet(address _feeDistributorAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event StakeChanged(address indexed staker, uint256 newStake);\\n event StakingGainsWithdrawn(address indexed staker, uint256 ZUSDGain, uint256 ETHGain);\\n event F_ETHUpdated(uint256 _F_ETH);\\n event F_ZUSDUpdated(uint256 _F_ZUSD);\\n event TotalZEROStakedUpdated(uint256 _totalZEROStaked);\\n event EtherSent(address _account, uint256 _amount);\\n event StakerSnapshotsUpdated(address _staker, uint256 _F_ETH, uint256 _F_ZUSD);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _zeroTokenAddress ZEROToken contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _feeDistributorAddress FeeDistributorAddress contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _zeroTokenAddress,\\n address _zusdTokenAddress,\\n address _feeDistributorAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice If caller has a pre-existing stake, send any accumulated ETH and ZUSD gains to them.\\n /// @param _ZEROamount ZERO tokens to stake\\n function stake(uint256 _ZEROamount) external;\\n\\n /**\\n * @notice Unstake the ZERO and send the it back to the caller, along with their accumulated ZUSD & ETH gains.\\n * If requested amount > stake, send their entire stake.\\n * @param _ZEROamount ZERO tokens to unstake\\n */\\n function unstake(uint256 _ZEROamount) external;\\n\\n /// @param _ETHFee ETH fee\\n /// @notice increase ETH fee\\n function increaseF_ETH(uint256 _ETHFee) external;\\n\\n /// @param _ZEROFee ZUSD fee\\n /// @notice increase ZUSD fee\\n function increaseF_ZUSD(uint256 _ZEROFee) external;\\n\\n /// @param _user user address\\n /// @return pending ETH gain of given user\\n function getPendingETHGain(address _user) external view returns (uint256);\\n\\n /// @param _user user address\\n /// @return pending ZUSD gain of given user\\n function getPendingZUSDGain(address _user) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x4c7948ce7dff9ea9b8495054e511eabcf44a91c7db8520ec58ff2a002327e0c5\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZEROToken is IERC20, IERC2612 { \\n\\n // --- Functions ---\\n\\n /// @notice send zero tokens to ZEROStaking contract\\n /// @param _sender sender address\\n /// @param _amount amount to send\\n function sendToZEROStaking(address _sender, uint256 _amount) external;\\n\\n /// @return deployment start time\\n function getDeploymentStartTime() external view returns (uint256);\\n\\n}\\n\",\"keccak256\":\"0xbcc0baabe4c4686563a09cf1486f2d152b70404996676a89d525691f69637f66\",\"license\":\"MIT\"},\"contracts/Interfaces/IZUSDToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZUSDToken is IERC20, IERC2612 { \\n \\n // --- Events ---\\n\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n\\n event ZUSDTokenBalanceUpdated(address _user, uint _amount);\\n\\n // --- Functions ---\\n\\n function mint(address _account, uint256 _amount) external;\\n\\n function burn(address _account, uint256 _amount) external;\\n\\n function sendToPool(address _sender, address poolAddress, uint256 _amount) external;\\n\\n function returnFromPool(address poolAddress, address user, uint256 _amount ) external;\\n}\\n\",\"keccak256\":\"0xe52df063aa08f709640c28888edd27310c820f6d08564855538ae245eb2f5a8c\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60a06040523480156200001157600080fd5b506040516200556638038062005566833981016040819052620000349162000123565b62000048336001600160e01b036200005e16565b60601b6001600160601b031916608052620001b2565b6001600160a01b038116620000905760405162461bcd60e51b8152600401620000879062000170565b60405180910390fd5b6001600160a01b038116620000ad6001600160e01b036200010216565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f29062000153565b6040519081900390209190915550565b600080604051620001139062000153565b6040519081900390205492915050565b60006020828403121562000135578081fd5b81516001600160a01b03811681146200014c578182fd5b9392505050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160601c61538c620001da600039806106a552806110db5280612327525061538c6000f3fe60806040526004361061025c5760003560e01c80637778a3db11610144578063a20baee6116100b6578063c6a6cf201161007a578063c6a6cf2014610601578063e9fc346114610614578063ea9638bf14610629578063ec5472fd1461063c578063ec9f7d4614610651578063f92d3433146106665761025c565b8063a20baee614610414578063a3f4df7e14610595578063ae918754146105b7578063afbc74b5146105cc578063b5c89bab146105ec5761025c565b8063860665b311610108578063860665b314610510578063887105d314610523578063893d20e814610538578063899fe15e1461054d5780638d5c3dc11461056d5780639f070670146105805761025c565b80637778a3db14610486578063795d26c3146104a65780637d4f595d146104bb5780637e3eefdc146104db5780637f7dde4a146104fb5761025c565b8063485f190f116101dd5780636f0b0c1c116101a15780636f0b0c1c146103ff57806372fe25aa14610414578063734f622d14610429578063741bef1a14610449578063759b30341461045e578063763a0ef3146104735761025c565b8063485f190f146103795780634ff814431461038c5780635530273c146103ac57806368647db1146103cc5780636ea56960146103df5761025c565b80631a777717116102245780631a777717146102ed5780631bf435551461030d5780632771510a1461032f5780633cc742251461034f5780633d83908a146103645761025c565b80630d43e8ad146102615780630e704d501461028c5780630ff9a512146102a357806312261ee7146102b857806313af4035146102cd575b600080fd5b34801561026d57600080fd5b5061027661067b565b604051610283919061485c565b60405180910390f35b34801561029857600080fd5b506102a161068a565b005b3480156102af57600080fd5b50610276610694565b3480156102c457600080fd5b506102766106a3565b3480156102d957600080fd5b506102a16102e83660046142d7565b6106c7565b3480156102f957600080fd5b506102a161030836600461455d565b610714565b34801561031957600080fd5b5061032261072b565b60405161028391906152d8565b34801561033b57600080fd5b506102a161034a3660046142d7565b610738565b34801561035b57600080fd5b506102766107c6565b34801561037057600080fd5b506102766107d5565b6102a1610387366004614631565b6107e4565b34801561039857600080fd5b506103226103a7366004614507565b61094e565b3480156103b857600080fd5b506102a16103c7366004614537565b610961565b6102a16103da36600461430f565b610977565b3480156103eb57600080fd5b506102a16103fa366004614631565b61098d565b34801561040b57600080fd5b506102a161099e565b34801561042057600080fd5b506103226109fc565b34801561043557600080fd5b506102a1610444366004614391565b610a08565b34801561045557600080fd5b50610276610dcc565b34801561046a57600080fd5b50610322610ddb565b6102a1610481366004614758565b610de8565b34801561049257600080fd5b506102a16104a136600461449a565b610e04565b3480156104b257600080fd5b50610322610ef5565b3480156104c757600080fd5b506102a16104d63660046144b5565b611014565b3480156104e757600080fd5b506103226104f6366004614631565b61110a565b34801561050757600080fd5b50610276611385565b6102a161051e366004614631565b611394565b34801561052f57600080fd5b506103226113a1565b34801561054457600080fd5b50610276611470565b34801561055957600080fd5b506102a16105683660046145ae565b61148f565b6102a161057b3660046146e0565b6114aa565b34801561058c57600080fd5b506102766114c2565b3480156105a157600080fd5b506105aa6114d1565b6040516102839190614944565b3480156105c357600080fd5b506102766114ff565b3480156105d857600080fd5b506102a16105e7366004614537565b61150e565b3480156105f857600080fd5b50610276611520565b6102a161060f36600461467a565b61152f565b34801561062057600080fd5b5061027661153e565b6102a1610637366004614347565b61154d565b34801561064857600080fd5b50610276611567565b34801561065d57600080fd5b50610276611576565b34801561067257600080fd5b50610322611585565b600d546001600160a01b031681565b610692611607565b565b6009546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6106cf611470565b6001600160a01b0316336001600160a01b0316146107085760405162461bcd60e51b81526004016106ff90614e2d565b60405180910390fd5b610711816119f6565b50565b610725600080866000878787611a81565b50505050565b6809c2007651b250000081565b610740611470565b6001600160a01b0316336001600160a01b0316146107705760405162461bcd60e51b81526004016106ff90614e2d565b600c80546001600160a01b0319166001600160a01b0383161790556040517f6926b3375b54960080b7d8a184061f39a02e8c3bf64aa9df7e75359fdc00d814906107bb90839061485c565b60405180910390a150565b6001546001600160a01b031681565b6004546001600160a01b031681565b600c546001600160a01b031661080c5760405162461bcd60e51b81526004016106ff90615237565b6108198484848430611c37565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b39261084f9291169087906004016148b1565b602060405180830381600087803b15801561086957600080fd5b505af115801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a1919061447e565b6108bd5760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b926108f592911690879033906004016148f5565b602060405180830381600087803b15801561090f57600080fd5b505af1158015610923573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610947919061451f565b5050505050565b600061095982612262565b90505b919050565b61097233846000808686600061227d565b505050565b6109893360008060008686600061227d565b5050565b61072533600085600186868a61227d565b60075460405163b32beb5b60e01b81526001600160a01b039091169063b32beb5b906109ce90339060040161485c565b600060405180830381600087803b1580156109e857600080fd5b505af1158015610725573d6000803e3d6000fd5b670de0b6b3a764000081565b610a10611470565b6001600160a01b0316336001600160a01b031614610a405760405162461bcd60e51b81526004016106ff90614e2d565b610a498c61228d565b610a528b61228d565b610a5b8a61228d565b610a648961228d565b610a6d8861228d565b610a768761228d565b610a7f8661228d565b610a888561228d565b610a918461228d565b610a9a8361228d565b610aa38261228d565b610aac8161228d565b600d80546001600160a01b03199081166001600160a01b038f8116919091179092556003805482168e84161790556004805482168d84161790556000805482168c84161790556001805482168b84161790556005805482168a8416179055600680548216898416179055600780548216888416179055600280548216878416179055600b80548216868416179055600a8054821685841617905560098054821692841692831790556008805490911690911790556040517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db990610b90908e9061485c565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a56788a604051610bc7919061485c565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd88289604051610bfe919061485c565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b88604051610c35919061485c565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f87604051610c6c919061485c565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa086604051610ca3919061485c565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d85604051610cda919061485c565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db26484604051610d11919061485c565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe7880083604051610d48919061485c565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d82604051610d7f919061485c565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd81604051610db6919061485c565b60405180910390a1505050505050505050505050565b6002546001600160a01b031681565b6801158e460913d0000081565b610df98989898989898989896122d2565b505050505050505050565b600c546001600160a01b0316610e2c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a255391610e5e9133910161485c565b60206040518083038186803b158015610e7657600080fd5b505afa158015610e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eae919061451f565b600c54909150610eec906001600160a01b0316610eda836801158e460913d0000063ffffffff6124ab16565b600a546001600160a01b0316856124f6565b50610989611607565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f71919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b505afa158015610fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffb919061451f565b905061100d828263ffffffff6127a716565b9250505090565b600c546001600160a01b031661103c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a25539161106e9133910161485c565b60206040518083038186803b15801561108657600080fd5b505afa15801561109a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110be919061451f565b600c54600a54919250611101916001600160a01b039182169116867f000000000000000000000000000000000000000000000000000000000000000087876127cc565b50610725611607565b600a546040516370a0823160e01b8152600091309183916001600160a01b0316906370a082319061113f90859060040161485c565b60206040518083038186803b15801561115757600080fd5b505afa15801561116b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118f919061451f565b905061119f33838888888c612a19565b6111af818763ffffffff6127a716565b600a546040516370a0823160e01b81526001600160a01b03909116906370a08231906111df90869060040161485c565b60206040518083038186803b1580156111f757600080fd5b505afa15801561120b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122f919061451f565b1461124c5760405162461bcd60e51b81526004016106ff90614ac1565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611282929116908a906004016148b1565b602060405180830381600087803b15801561129c57600080fd5b505af11580156112b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d4919061447e565b6112f05760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611328929116908a9033906004016148f5565b602060405180830381600087803b15801561134257600080fd5b505af1158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a919061451f565b979650505050505050565b6000546001600160a01b031681565b6107258484848433611c37565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b60008060405161147f9061483f565b6040519081900390205492915050565b6114a260008088600089898989896122d2565b505050505050565b6114b987878787878787611a81565b50505050505050565b6003546001600160a01b031681565b60405180604001604052806012815260200171426f72726f7765724f7065726174696f6e7360701b81525081565b600b546001600160a01b031681565b6109723360008560008686600061227d565b600c546001600160a01b031681565b6114a23386868686868c61227d565b600c546001600160a01b031690565b611555612a2b565b6109728360008060008686600061227d565b6008546001600160a01b031681565b600a546001600160a01b031681565b6003546040805163f92d343360e01b815290516000926001600160a01b03169163f92d3433916004808301926020929190829003018186803b1580156115ca57600080fd5b505afa1580156115de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611602919061451f565b905090565b600454600054600a546001600160a01b0392831692918216911661162b8333612a55565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561167157600080fd5b505af1158015611685573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a9919061451f565b90506116b481612af6565b604051630b07655760e01b81526001600160a01b03851690630b076557906116e090339060040161485c565b600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50506040516309019aaf60e31b8152600092506001600160a01b038716915063480cd5789061174190339060040161485c565b60206040518083038186803b15801561175957600080fd5b505afa15801561176d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611791919061451f565b90506000856001600160a01b031663d66a2553336040518263ffffffff1660e01b81526004016117c1919061485c565b60206040518083038186803b1580156117d957600080fd5b505afa1580156117ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611811919061451f565b90506118368433611831846801158e460913d0000063ffffffff6124ab16565b612b1c565b600061184783600084600088612bb8565b905061185281612c43565b604051631fc5750960e31b81526001600160a01b0388169063fe2ba8489061187e90339060040161485c565b600060405180830381600087803b15801561189857600080fd5b505af11580156118ac573d6000803e3d6000fd5b50506040516365e89c5760e11b81526001600160a01b038a16925063cbd138ae91506118dc90339060040161485c565b600060405180830381600087803b1580156118f657600080fd5b505af115801561190a573d6000803e3d6000fd5b50505050336001600160a01b03166000805160206153378339815191526000806000600160405161193e9493929190614918565b60405180910390a261196a868633611965866801158e460913d0000063ffffffff6124ab16565b612ce8565b60065461198d90879087906001600160a01b03166801158e460913d00000612ce8565b6040516364a197f360e01b81526001600160a01b038716906364a197f3906119bb90339087906004016148b1565b600060405180830381600087803b1580156119d557600080fd5b505af11580156119e9573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038116611a1c5760405162461bcd60e51b81526004016106ff90614af8565b806001600160a01b0316611a2e611470565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611a719061483f565b6040519081900390209190915550565b600c546001600160a01b0316611aa95760405162461bcd60e51b81526004016106ff90615237565b83158015611ab75750600085115b15611add57600c54600a54611adb916001600160a01b0390811691889116846124f6565b505b611aed3387878787878d30612da2565b838015611afa5750600085115b156114b957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611b359291169089906004016148b1565b602060405180830381600087803b158015611b4f57600080fd5b505af1158015611b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b87919061447e565b611ba35760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611bdb92911690899033906004016148f5565b602060405180830381600087803b158015611bf557600080fd5b505af1158015611c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2d919061451f565b5050505050505050565b611c3f614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152611c77614131565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611cc757600080fd5b505af1158015611cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cff919061451f565b808252600090611d0e9061337a565b9050611d1a8882613415565b8251611d269033613501565b6040820187905280611d6757611d4683600001518460400151898b6135a3565b602083018190526040830151611d619163ffffffff6127a716565b60408301525b611d74826040015161375c565b611d818260400151612262565b60608301819052611d8e57fe5b611da13483606001518460000151613785565b60808301526060820151611db69034906137c4565b60a08301528015611dd357611dce82608001516137f9565b611e06565b611de0826080015161389e565b6000611df9346001856060015160018760000151612bb8565b9050611e0481612c43565b505b8251604051635d6b480f60e01b81526001600160a01b0390911690635d6b480f90611e389033906001906004016148b1565b600060405180830381600087803b158015611e5257600080fd5b505af1158015611e66573d6000803e3d6000fd5b505084516040516372423c1760e01b81526001600160a01b0390911692506372423c179150611e9b90339034906004016148b1565b602060405180830381600087803b158015611eb557600080fd5b505af1158015611ec9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eed919061451f565b5082516060830151604051639976cf4560e01b81526001600160a01b0390921691639976cf4591611f23913391906004016148b1565b602060405180830381600087803b158015611f3d57600080fd5b505af1158015611f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f75919061451f565b5082516040516382fe3eb960e01b81526001600160a01b03909116906382fe3eb990611fa590339060040161485c565b600060405180830381600087803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b50508451604051630c7940bd60e11b81526001600160a01b0390911692506318f2817a915061200690339060040161485c565b602060405180830381600087803b15801561202057600080fd5b505af1158015612034573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612058919061451f565b60c0830152600b5460a08301516040516346f7cf8760e01b81526001600160a01b03909216916346f7cf8791612097913391908b908b906004016148ca565b600060405180830381600087803b1580156120b157600080fd5b505af11580156120c5573d6000803e3d6000fd5b505084516040516315d549f160e01b81526001600160a01b0390911692506315d549f191506120f890339060040161485c565b602060405180830381600087803b15801561211257600080fd5b505af1158015612126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214a919061451f565b60e0830181905260405133917f59cfd0cd754bc5748b6770e94a4ffa5f678d885cb899dcfadc5734edb97c67ab9161218291906152d8565b60405180910390a2612198836020015134613943565b6121b183602001518460400151868a86604001516139bf565b602083015160408401516006546121dd9291906001600160a01b03166801158e460913d00000806139bf565b606082015160c083015160405133926000805160206153378339815191529261220b92349190600090614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc0022741836020015160405161225091906152d8565b60405180910390a25050505050505050565b6000610959826801158e460913d0000063ffffffff6127a716565b6114b98787878787878733612da2565b6001600160a01b0381166122b35760405162461bcd60e51b81526004016106ff90614c3a565b803b806109895760405162461bcd60e51b81526004016106ff90614fde565b600c546001600160a01b03166122fa5760405162461bcd60e51b81526004016106ff90615237565b851580156123085750600087115b1561234f57600c54600a5461234d916001600160a01b039081169116857f000000000000000000000000000000000000000000000000000000000000000086866127cc565b505b61235f3389898989898f30612da2565b85801561236c5750600087115b15610df957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b3926123a7929116908b906004016148b1565b602060405180830381600087803b1580156123c157600080fd5b505af11580156123d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f9919061447e565b6124155760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b9261244d929116908b9033906004016148f5565b602060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f919061451f565b50505050505050505050565b60006124ed83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a79565b90505b92915050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561253257600080fd5b505afa158015612546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061256a91906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161259a919061485c565b60206040518083038186803b1580156125b257600080fd5b505afa1580156125c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ea919061451f565b9050306001600160a01b03831663605629d633838a893561261160408c0160208d01614803565b8b604001358c606001356040518863ffffffff1660e01b815260040161263d9796959493929190614870565b600060405180830381600087803b15801561265757600080fd5b505af115801561266b573d6000803e3d6000fd5b50505050866126fc83856001600160a01b03166370a08231856040518263ffffffff1660e01b81526004016126a0919061485c565b60206040518083038186803b1580156126b857600080fd5b505afa1580156126cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f0919061451f565b9063ffffffff6124ab16565b146127195760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c9223906127499089908b9033906004016148f5565b602060405180830381600087803b15801561276357600080fd5b505af1158015612777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279b919061451f565b98975050505050505050565b6000828201838110156124ed5760405162461bcd60e51b81526004016106ff90614a8a565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284091906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612870919061485c565b60206040518083038186803b15801561288857600080fd5b505afa15801561289c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c0919061451f565b87516020015190915030906001600160a01b0388166330f28b7a8a6128e58585613aa5565b338b8b6040518663ffffffff1660e01b8152600401612908959493929190615267565b600060405180830381600087803b15801561292257600080fd5b505af1158015612936573d6000803e3d6000fd5b505050508061296b84866001600160a01b03166370a08231866040518263ffffffff1660e01b81526004016126a0919061485c565b146129885760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c9223906129b8908d90859033906004016148f5565b602060405180830381600087803b1580156129d257600080fd5b505af11580156129e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0a919061451f565b9b9a5050505050505050505050565b6114a28660008660018787878c612da2565b6005546001600160a01b031633146106925760405162461bcd60e51b81526004016106ff9061507c565b6040516321e3780160e01b81526000906001600160a01b038416906321e3780190612a8490859060040161485c565b60206040518083038186803b158015612a9c57600080fd5b505afa158015612ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad4919061451f565b9050806001146109725760405162461bcd60e51b81526004016106ff90614ddf565b612aff8161337a565b156107115760405162461bcd60e51b81526004016106ff90614b8a565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190612b4a90869060040161485c565b60206040518083038186803b158015612b6257600080fd5b505afa158015612b76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9a919061451f565b10156109725760405162461bcd60e51b81526004016106ff90614997565b600080612bc36113a1565b90506000612bcf610ef5565b905086612beb57612be6828963ffffffff6124ab16565b612bfb565b612bfb828963ffffffff6127a716565b915084612c1757612c12818763ffffffff6124ab16565b612c27565b612c27818763ffffffff6127a716565b90506000612c36838387613785565b9998505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9157600080fd5b505afa158015612ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc9919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614d70565b60405163121cbc4d60e11b81526001600160a01b03851690632439789a90612d149084906004016152d8565b600060405180830381600087803b158015612d2e57600080fd5b505af1158015612d42573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b0386169250639dc29fac9150612d7490859085906004016148b1565b600060405180830381600087803b158015612d8e57600080fd5b505af1158015611c2d573d6000803e3d6000fd5b612daa614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152612de2614176565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e3257600080fd5b505af1158015612e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6a919061451f565b808252612e769061337a565b15156101c08201528615612e9c57612e9384826101c00151613415565b612e9c88613ad7565b612ea589613af7565b612eaf8989613b1e565b8151612ebb908b612a55565b336001600160a01b038b161480612ef157506005546001600160a01b031633148015612ee75750600034115b8015612ef1575087155b612ef757fe5b8151604051630b07655760e01b81526001600160a01b0390911690630b07655790612f26908d9060040161485c565b600060405180830381600087803b158015612f4057600080fd5b505af1158015612f54573d6000803e3d6000fd5b50505050612f62348a613b51565b15156060830152602082015260408101889052868015612f855750806101c00151155b15612fc057612f9e826000015183604001518a876135a3565b61012082018190526040820151612fba9163ffffffff6127a716565b60408201525b815160405163d66a255360e01b81526001600160a01b039091169063d66a255390612fef908d9060040161485c565b60206040518083038186803b15801561300757600080fd5b505afa15801561301b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303f919061451f565b608082015281516040516309019aaf60e31b81526001600160a01b039091169063480cd57890613073908d9060040161485c565b60206040518083038186803b15801561308b57600080fd5b505afa15801561309f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c3919061451f565b60a08201819052608082015182516130dc929190613785565b8160c001818152505061310c8160a0015182608001518360200151846060015185604001518c8760000151613b70565b60e082015260a081015189111561311f57fe5b613130816101c001518a8984613b94565b8615801561313e5750600088115b156131855761316061315b82604001516126f08460800151613c08565b61375c565b61317281608001518260400151613c23565b61318582604001518b8360400151612b1c565b6131a382600001518b8360200151846060015185604001518c613c5b565b6101408301526101608201528151604051630c7940bd60e11b81526001600160a01b03909116906318f2817a906131de908d9060040161485c565b602060405180830381600087803b1580156131f857600080fd5b505af115801561320c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613230919061451f565b8161018001818152505061325c8160a0015182608001518360200151846060015185604001518c613e89565b6101a08201819052600b5460405163015f109360e51b81526001600160a01b0390911691632be2126091613298918e918b908b906004016148ca565b600060405180830381600087803b1580156132b257600080fd5b505af11580156132c6573d6000803e3d6000fd5b50505050896001600160a01b031660008051602061533783398151915282610140015183610160015184610180015160026040516133079493929190614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc002274182610120015160405161334d91906152d8565b60405180910390a261249f8260200151836040015133846020015185606001518d8d88604001518b613eba565b60008061338683613f5e565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133d657600080fd5b505afa1580156133ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061340e919061451f565b1192915050565b801561344857670de0b6b3a76400008211156134435760405162461bcd60e51b81526004016106ff90614c71565b610989565b600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561349657600080fd5b505afa1580156134aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ce919061451f565b82101580156134e55750670de0b6b3a76400008211155b6109895760405162461bcd60e51b81526004016106ff906150c5565b6040516321e3780160e01b81526000906001600160a01b038416906321e378019061353090859060040161485c565b60206040518083038186803b15801561354857600080fd5b505afa15801561355c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613580919061451f565b905080600114156109725760405162461bcd60e51b81526004016106ff90615115565b6000846001600160a01b0316635dba4c4a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135e057600080fd5b505af11580156135f4573d6000803e3d6000fd5b5050604051630631203b60e41b8152600092506001600160a01b038816915063631203b0906136279087906004016152d8565b60206040518083038186803b15801561363f57600080fd5b505afa158015613653573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613677919061451f565b9050613684818585613f8a565b600d546040516340c10f1960e01b81526001600160a01b03878116926340c10f19926136b8929091169085906004016148b1565b600060405180830381600087803b1580156136d257600080fd5b505af11580156136e6573d6000803e3d6000fd5b50505050600d60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561373a57600080fd5b505af115801561374e573d6000803e3d6000fd5b509298975050505050505050565b6809c2007651b25000008110156107115760405162461bcd60e51b81526004016106ff90614f81565b600082156137b85760006137af846137a3878663ffffffff613fca16565b9063ffffffff61400416565b91506137bd9050565b506000195b9392505050565b600081156137f0576137e9826137a38568056bc75e2d6310000063ffffffff613fca16565b90506124f0565b506000196124f0565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561384757600080fd5b505afa15801561385b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387f919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614be3565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156138ec57600080fd5b505afa158015613900573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613924919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614f12565b6000826001600160a01b03168260405161395c9061483c565b60006040518083038185875af1925050503d8060008114613999576040519150601f19603f3d011682016040523d82523d6000602084013e61399e565b606091505b50509050806109725760405162461bcd60e51b81526004016106ff906149f4565b60405163f2e91d7160e01b81526001600160a01b0386169063f2e91d71906139eb9084906004016152d8565b600060405180830381600087803b158015613a0557600080fd5b505af1158015613a19573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b03871692506340c10f199150613a4b90869086906004016148b1565b600060405180830381600087803b158015613a6557600080fd5b505af1158015610df9573d6000803e3d6000fd5b60008184841115613a9d5760405162461bcd60e51b81526004016106ff9190614944565b505050900390565b613aad6141f0565b613ab56141f0565b5050604080518082019091526001600160a01b03929092168252602082015290565b600081116107115760405162461bcd60e51b81526004016106ff9061514c565b341580613b02575080155b6107115760405162461bcd60e51b81526004016106ff90614b3a565b34151580613b2b57508115155b80613b3557508015155b6109895760405162461bcd60e51b81526004016106ff90614cc3565b6000808315613b6557508290506001613b69565b8291505b9250929050565b6000806000613b838a8a8a8a8a8a614046565b915091506000612a0a838387613785565b8315613bcd57613ba38361409c565b8115613bc857613bb68160e001516137f9565b613bc88160e001518260c001516140ba565b610725565b613bda8160e0015161389e565b613bf7816020015182606001518360400151858560000151612bb8565b610100820181905261072590612c43565b6000610959826801158e460913d0000063ffffffff6124ab16565b613c3c826801158e460913d0000063ffffffff6124ab16565b8111156109895760405162461bcd60e51b81526004016106ff90615013565b600080600085613cea5760405163d3d6f84360e01b81526001600160a01b038a169063d3d6f84390613c93908b908b906004016148b1565b602060405180830381600087803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce5919061451f565b613d6a565b6040516372423c1760e01b81526001600160a01b038a16906372423c1790613d18908b908b906004016148b1565b602060405180830381600087803b158015613d3257600080fd5b505af1158015613d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d6a919061451f565b9050600084613df857604051630930874960e11b81526001600160a01b038b16906312610e9290613da1908c908a906004016148b1565b602060405180830381600087803b158015613dbb57600080fd5b505af1158015613dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df3919061451f565b613e78565b604051639976cf4560e01b81526001600160a01b038b1690639976cf4590613e26908c908a906004016148b1565b602060405180830381600087803b158015613e4057600080fd5b505af1158015613e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e78919061451f565b919a91995090975050505050505050565b6000806000613e9c898989898989614046565b915091506000613eac83836137c4565b9a9950505050505050505050565b8215613ed257613ecd89898387866139bf565b613ede565b613ede89898987612ce8565b8415613ef357613eee8987613943565b610df9565b6040516364a197f360e01b81526001600160a01b038a16906364a197f390613f21908a908a906004016148b1565b600060405180830381600087803b158015613f3b57600080fd5b505af1158015613f4f573d6000803e3d6000fd5b50505050505050505050505050565b600080613f696113a1565b90506000613f75610ef5565b9050613f82828286613785565b949350505050565b6000613fa8836137a386670de0b6b3a764000063ffffffff613fca16565b9050818111156107255760405162461bcd60e51b81526004016106ff90615200565b600082613fd9575060006124f0565b82820282848281613fe657fe5b04146124ed5760405162461bcd60e51b81526004016106ff90614d2f565b60006124ed83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506140da565b600080878786614065576140608a8963ffffffff6124ab16565b614075565b6140758a8963ffffffff6127a716565b91508461408c57613df3898763ffffffff6124ab16565b613e78898763ffffffff6127a716565b80156107115760405162461bcd60e51b81526004016106ff90614e5e565b808210156109895760405162461bcd60e51b81526004016106ff906151a3565b600081836140fb5760405162461bcd60e51b81526004016106ff9190614944565b50600083858161410757fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806101e00160405280600081526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b80356124f081615313565b60008083601f840112614223578182fd5b50813567ffffffffffffffff81111561423a578182fd5b602083019150836020828501011115613b6957600080fd5b600060808284031215614263578081fd5b50919050565b6000818303608081121561427b578182fd5b61428560606152e1565b9150604081121561429557600080fd5b506142a060406152e1565b82356142ab81615313565b808252506020830135602082015280825250604082013560208201526060820135604082015292915050565b6000602082840312156142e8578081fd5b81356124ed81615313565b600060208284031215614304578081fd5b81516124ed81615313565b60008060408385031215614321578081fd5b823561432c81615313565b9150602083013561433c81615313565b809150509250929050565b60008060006060848603121561435b578081fd5b833561436681615313565b9250602084013561437681615313565b9150604084013561438681615313565b809150509250925092565b6000806000806000806000806000806000806101808d8f0312156143b3578788fd5b8c356143be81615313565b9b5060208d01356143ce81615313565b9a5060408d01356143de81615313565b995060608d01356143ee81615313565b985060808d01356143fe81615313565b975060a08d013561440e81615313565b965061441d8e60c08f01614207565b955061442c8e60e08f01614207565b945061443c8e6101008f01614207565b935061444c8e6101208f01614207565b925061445c8e6101408f01614207565b915061446c8e6101608f01614207565b90509295989b509295989b509295989b565b60006020828403121561448f578081fd5b81516124ed81615328565b6000608082840312156144ab578081fd5b6124ed8383614252565b600080600060a084860312156144c9578283fd5b6144d38585614269565b9250608084013567ffffffffffffffff8111156144ee578283fd5b6144fa86828701614212565b9497909650939450505050565b600060208284031215614518578081fd5b5035919050565b600060208284031215614530578081fd5b5051919050565b60008060006060848603121561454b578283fd5b83359250602084013561437681615313565b60008060008060e08587031215614572578182fd5b84359350602085013561458481615313565b9250604085013561459481615313565b91506145a38660608701614252565b905092959194509250565b60008060008060008061010087890312156145c7578384fd5b8635955060208701356145d981615313565b945060408701356145e981615313565b93506145f88860608901614269565b925060e087013567ffffffffffffffff811115614613578283fd5b61461f89828a01614212565b979a9699509497509295939492505050565b60008060008060808587031215614646578182fd5b8435935060208501359250604085013561465f81615313565b9150606085013561466f81615313565b939692955090935050565b60008060008060008060c08789031215614692578384fd5b86359550602087013594506040870135935060608701356146b281615328565b925060808701356146c281615313565b915060a08701356146d281615313565b809150509295509295509295565b6000806000806000806000610140888a0312156146fb578081fd5b873596506020880135955060408801359450606088013561471b81615328565b9350608088013561472b81615313565b925060a088013561473b81615313565b915061474a8960c08a01614252565b905092959891949750929550565b60008060008060008060008060006101608a8c031215614776578283fd5b8935985060208a0135975060408a0135965060608a013561479681615328565b955060808a01356147a681615313565b945060a08a01356147b681615313565b93506147c58b60c08c01614269565b92506101408a013567ffffffffffffffff8111156147e1578283fd5b6147ed8c828d01614212565b8194508093505050509295985092959850929598565b600060208284031215614814578081fd5b813560ff811681146124ed578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b84815260208101849052604081018390526080810161493683615308565b606083015295945050505050565b6000602080835283518082850152825b8181101561497057858101830151858201604001528201614954565b818111156149815783604083870101525b50601f01601f1916929092016040019392505050565b6020808252603d908201527f426f72726f7765724f70733a2043616c6c657220646f65736e7420686176652060408201527f656e6f756768205a55534420746f206d616b652072657061796d656e74000000606082015260800190565b6020808252602d908201527f426f72726f7765724f70733a2053656e64696e672045544820746f204163746960408201526c1d99541bdbdb0819985a5b1959609a1b606082015260800190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f5a555344206973206e6f7420626f72726f77656420636f72726563746c790000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60208082526030908201527f426f72726f7765724f7065726174696f6e733a2043616e6e6f7420776974686460408201526f1c985dc8185b99081859190818dbdb1b60821b606082015260800190565b60208082526039908201527f426f72726f7765724f70733a204f7065726174696f6e206e6f74207065726d696040820152787474656420647572696e67205265636f76657279204d6f646560381b606082015260800190565b60208082526037908201527f426f72726f7765724f70733a204f7065726174696f6e206d757374206c65617660408201527632903a3937bb32903bb4ba341024a1a9101f1e9021a1a960491b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526032908201527f4d6178206665652070657263656e74616765206d757374206c657373207468616040820152716e206f7220657175616c20746f203130302560701b606082015260800190565b60208082526046908201527f426f72726f7765724f70733a205468657265206d75737420626520656974686560408201527f72206120636f6c6c61746572616c206368616e6765206f7220612064656274206060820152656368616e676560d01b608082015260a00190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20544352203c20434352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252602e908201527f426f72726f7765724f70733a2054726f766520646f6573206e6f74206578697360408201526d1d081bdc881a5cc818db1bdcd95960921b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252603e908201527f426f72726f7765724f70733a20436f6c6c61746572616c20776974686472617760408201527f616c206e6f74207065726d6974746564205265636f76657279204d6f64650000606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20494352203c204d4352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252603a908201527f426f72726f7765724f70733a2054726f76652773206e65742064656274206d7560408201527f73742062652067726561746572207468616e206d696e696d756d000000000000606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526043908201527f426f72726f7765724f70733a20416d6f756e7420726570616964206d7573742060408201527f6e6f74206265206c6172676572207468616e207468652054726f76652773206460608201526219589d60ea1b608082015260a00190565b60208082526029908201527f426f72726f7765724f70733a2043616c6c6572206973206e6f742053746162696040820152681b1a5d1e48141bdbdb60ba1b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252601c908201527f426f72726f7765724f70733a2054726f76652069732061637469766500000000604082015260600190565b60208082526037908201527f426f72726f7765724f70733a204465627420696e637265617365207265717569604082015276726573206e6f6e2d7a65726f20646562744368616e676560481b606082015260800190565b6020808252603e908201527f426f72726f7765724f70733a2043616e6e6f7420646563726561736520796f7560408201527f722054726f766527732049435220696e205265636f76657279204d6f64650000606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b60208082526016908201527513585cdcd95d081859191c995cdcc81b9bdd081cd95d60521b604082015260600190565b6000610100615277838951614824565b60208801516040840152604088015160608401526152986080840188614824565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b60405181810167ffffffffffffffff8111828210171561530057600080fd5b604052919050565b806003811061095c57fe5b6001600160a01b038116811461071157600080fd5b801515811461071157600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212209d20681b7b6630050fbad5344b16d370ece553865b2bf0ccb789b394933ed00f64736f6c634300060b0033", + "deployedBytecode": "0x60806040526004361061025c5760003560e01c80637778a3db11610144578063a20baee6116100b6578063c6a6cf201161007a578063c6a6cf2014610601578063e9fc346114610614578063ea9638bf14610629578063ec5472fd1461063c578063ec9f7d4614610651578063f92d3433146106665761025c565b8063a20baee614610414578063a3f4df7e14610595578063ae918754146105b7578063afbc74b5146105cc578063b5c89bab146105ec5761025c565b8063860665b311610108578063860665b314610510578063887105d314610523578063893d20e814610538578063899fe15e1461054d5780638d5c3dc11461056d5780639f070670146105805761025c565b80637778a3db14610486578063795d26c3146104a65780637d4f595d146104bb5780637e3eefdc146104db5780637f7dde4a146104fb5761025c565b8063485f190f116101dd5780636f0b0c1c116101a15780636f0b0c1c146103ff57806372fe25aa14610414578063734f622d14610429578063741bef1a14610449578063759b30341461045e578063763a0ef3146104735761025c565b8063485f190f146103795780634ff814431461038c5780635530273c146103ac57806368647db1146103cc5780636ea56960146103df5761025c565b80631a777717116102245780631a777717146102ed5780631bf435551461030d5780632771510a1461032f5780633cc742251461034f5780633d83908a146103645761025c565b80630d43e8ad146102615780630e704d501461028c5780630ff9a512146102a357806312261ee7146102b857806313af4035146102cd575b600080fd5b34801561026d57600080fd5b5061027661067b565b604051610283919061485c565b60405180910390f35b34801561029857600080fd5b506102a161068a565b005b3480156102af57600080fd5b50610276610694565b3480156102c457600080fd5b506102766106a3565b3480156102d957600080fd5b506102a16102e83660046142d7565b6106c7565b3480156102f957600080fd5b506102a161030836600461455d565b610714565b34801561031957600080fd5b5061032261072b565b60405161028391906152d8565b34801561033b57600080fd5b506102a161034a3660046142d7565b610738565b34801561035b57600080fd5b506102766107c6565b34801561037057600080fd5b506102766107d5565b6102a1610387366004614631565b6107e4565b34801561039857600080fd5b506103226103a7366004614507565b61094e565b3480156103b857600080fd5b506102a16103c7366004614537565b610961565b6102a16103da36600461430f565b610977565b3480156103eb57600080fd5b506102a16103fa366004614631565b61098d565b34801561040b57600080fd5b506102a161099e565b34801561042057600080fd5b506103226109fc565b34801561043557600080fd5b506102a1610444366004614391565b610a08565b34801561045557600080fd5b50610276610dcc565b34801561046a57600080fd5b50610322610ddb565b6102a1610481366004614758565b610de8565b34801561049257600080fd5b506102a16104a136600461449a565b610e04565b3480156104b257600080fd5b50610322610ef5565b3480156104c757600080fd5b506102a16104d63660046144b5565b611014565b3480156104e757600080fd5b506103226104f6366004614631565b61110a565b34801561050757600080fd5b50610276611385565b6102a161051e366004614631565b611394565b34801561052f57600080fd5b506103226113a1565b34801561054457600080fd5b50610276611470565b34801561055957600080fd5b506102a16105683660046145ae565b61148f565b6102a161057b3660046146e0565b6114aa565b34801561058c57600080fd5b506102766114c2565b3480156105a157600080fd5b506105aa6114d1565b6040516102839190614944565b3480156105c357600080fd5b506102766114ff565b3480156105d857600080fd5b506102a16105e7366004614537565b61150e565b3480156105f857600080fd5b50610276611520565b6102a161060f36600461467a565b61152f565b34801561062057600080fd5b5061027661153e565b6102a1610637366004614347565b61154d565b34801561064857600080fd5b50610276611567565b34801561065d57600080fd5b50610276611576565b34801561067257600080fd5b50610322611585565b600d546001600160a01b031681565b610692611607565b565b6009546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6106cf611470565b6001600160a01b0316336001600160a01b0316146107085760405162461bcd60e51b81526004016106ff90614e2d565b60405180910390fd5b610711816119f6565b50565b610725600080866000878787611a81565b50505050565b6809c2007651b250000081565b610740611470565b6001600160a01b0316336001600160a01b0316146107705760405162461bcd60e51b81526004016106ff90614e2d565b600c80546001600160a01b0319166001600160a01b0383161790556040517f6926b3375b54960080b7d8a184061f39a02e8c3bf64aa9df7e75359fdc00d814906107bb90839061485c565b60405180910390a150565b6001546001600160a01b031681565b6004546001600160a01b031681565b600c546001600160a01b031661080c5760405162461bcd60e51b81526004016106ff90615237565b6108198484848430611c37565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b39261084f9291169087906004016148b1565b602060405180830381600087803b15801561086957600080fd5b505af115801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a1919061447e565b6108bd5760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b926108f592911690879033906004016148f5565b602060405180830381600087803b15801561090f57600080fd5b505af1158015610923573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610947919061451f565b5050505050565b600061095982612262565b90505b919050565b61097233846000808686600061227d565b505050565b6109893360008060008686600061227d565b5050565b61072533600085600186868a61227d565b60075460405163b32beb5b60e01b81526001600160a01b039091169063b32beb5b906109ce90339060040161485c565b600060405180830381600087803b1580156109e857600080fd5b505af1158015610725573d6000803e3d6000fd5b670de0b6b3a764000081565b610a10611470565b6001600160a01b0316336001600160a01b031614610a405760405162461bcd60e51b81526004016106ff90614e2d565b610a498c61228d565b610a528b61228d565b610a5b8a61228d565b610a648961228d565b610a6d8861228d565b610a768761228d565b610a7f8661228d565b610a888561228d565b610a918461228d565b610a9a8361228d565b610aa38261228d565b610aac8161228d565b600d80546001600160a01b03199081166001600160a01b038f8116919091179092556003805482168e84161790556004805482168d84161790556000805482168c84161790556001805482168b84161790556005805482168a8416179055600680548216898416179055600780548216888416179055600280548216878416179055600b80548216868416179055600a8054821685841617905560098054821692841692831790556008805490911690911790556040517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db990610b90908e9061485c565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a56788a604051610bc7919061485c565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd88289604051610bfe919061485c565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b88604051610c35919061485c565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f87604051610c6c919061485c565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa086604051610ca3919061485c565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d85604051610cda919061485c565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db26484604051610d11919061485c565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe7880083604051610d48919061485c565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d82604051610d7f919061485c565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd81604051610db6919061485c565b60405180910390a1505050505050505050505050565b6002546001600160a01b031681565b6801158e460913d0000081565b610df98989898989898989896122d2565b505050505050505050565b600c546001600160a01b0316610e2c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a255391610e5e9133910161485c565b60206040518083038186803b158015610e7657600080fd5b505afa158015610e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eae919061451f565b600c54909150610eec906001600160a01b0316610eda836801158e460913d0000063ffffffff6124ab16565b600a546001600160a01b0316856124f6565b50610989611607565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f71919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b505afa158015610fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffb919061451f565b905061100d828263ffffffff6127a716565b9250505090565b600c546001600160a01b031661103c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a25539161106e9133910161485c565b60206040518083038186803b15801561108657600080fd5b505afa15801561109a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110be919061451f565b600c54600a54919250611101916001600160a01b039182169116867f000000000000000000000000000000000000000000000000000000000000000087876127cc565b50610725611607565b600a546040516370a0823160e01b8152600091309183916001600160a01b0316906370a082319061113f90859060040161485c565b60206040518083038186803b15801561115757600080fd5b505afa15801561116b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118f919061451f565b905061119f33838888888c612a19565b6111af818763ffffffff6127a716565b600a546040516370a0823160e01b81526001600160a01b03909116906370a08231906111df90869060040161485c565b60206040518083038186803b1580156111f757600080fd5b505afa15801561120b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122f919061451f565b1461124c5760405162461bcd60e51b81526004016106ff90614ac1565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611282929116908a906004016148b1565b602060405180830381600087803b15801561129c57600080fd5b505af11580156112b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d4919061447e565b6112f05760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611328929116908a9033906004016148f5565b602060405180830381600087803b15801561134257600080fd5b505af1158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a919061451f565b979650505050505050565b6000546001600160a01b031681565b6107258484848433611c37565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b60008060405161147f9061483f565b6040519081900390205492915050565b6114a260008088600089898989896122d2565b505050505050565b6114b987878787878787611a81565b50505050505050565b6003546001600160a01b031681565b60405180604001604052806012815260200171426f72726f7765724f7065726174696f6e7360701b81525081565b600b546001600160a01b031681565b6109723360008560008686600061227d565b600c546001600160a01b031681565b6114a23386868686868c61227d565b600c546001600160a01b031690565b611555612a2b565b6109728360008060008686600061227d565b6008546001600160a01b031681565b600a546001600160a01b031681565b6003546040805163f92d343360e01b815290516000926001600160a01b03169163f92d3433916004808301926020929190829003018186803b1580156115ca57600080fd5b505afa1580156115de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611602919061451f565b905090565b600454600054600a546001600160a01b0392831692918216911661162b8333612a55565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561167157600080fd5b505af1158015611685573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a9919061451f565b90506116b481612af6565b604051630b07655760e01b81526001600160a01b03851690630b076557906116e090339060040161485c565b600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50506040516309019aaf60e31b8152600092506001600160a01b038716915063480cd5789061174190339060040161485c565b60206040518083038186803b15801561175957600080fd5b505afa15801561176d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611791919061451f565b90506000856001600160a01b031663d66a2553336040518263ffffffff1660e01b81526004016117c1919061485c565b60206040518083038186803b1580156117d957600080fd5b505afa1580156117ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611811919061451f565b90506118368433611831846801158e460913d0000063ffffffff6124ab16565b612b1c565b600061184783600084600088612bb8565b905061185281612c43565b604051631fc5750960e31b81526001600160a01b0388169063fe2ba8489061187e90339060040161485c565b600060405180830381600087803b15801561189857600080fd5b505af11580156118ac573d6000803e3d6000fd5b50506040516365e89c5760e11b81526001600160a01b038a16925063cbd138ae91506118dc90339060040161485c565b600060405180830381600087803b1580156118f657600080fd5b505af115801561190a573d6000803e3d6000fd5b50505050336001600160a01b03166000805160206153378339815191526000806000600160405161193e9493929190614918565b60405180910390a261196a868633611965866801158e460913d0000063ffffffff6124ab16565b612ce8565b60065461198d90879087906001600160a01b03166801158e460913d00000612ce8565b6040516364a197f360e01b81526001600160a01b038716906364a197f3906119bb90339087906004016148b1565b600060405180830381600087803b1580156119d557600080fd5b505af11580156119e9573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038116611a1c5760405162461bcd60e51b81526004016106ff90614af8565b806001600160a01b0316611a2e611470565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611a719061483f565b6040519081900390209190915550565b600c546001600160a01b0316611aa95760405162461bcd60e51b81526004016106ff90615237565b83158015611ab75750600085115b15611add57600c54600a54611adb916001600160a01b0390811691889116846124f6565b505b611aed3387878787878d30612da2565b838015611afa5750600085115b156114b957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611b359291169089906004016148b1565b602060405180830381600087803b158015611b4f57600080fd5b505af1158015611b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b87919061447e565b611ba35760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611bdb92911690899033906004016148f5565b602060405180830381600087803b158015611bf557600080fd5b505af1158015611c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2d919061451f565b5050505050505050565b611c3f614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152611c77614131565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611cc757600080fd5b505af1158015611cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cff919061451f565b808252600090611d0e9061337a565b9050611d1a8882613415565b8251611d269033613501565b6040820187905280611d6757611d4683600001518460400151898b6135a3565b602083018190526040830151611d619163ffffffff6127a716565b60408301525b611d74826040015161375c565b611d818260400151612262565b60608301819052611d8e57fe5b611da13483606001518460000151613785565b60808301526060820151611db69034906137c4565b60a08301528015611dd357611dce82608001516137f9565b611e06565b611de0826080015161389e565b6000611df9346001856060015160018760000151612bb8565b9050611e0481612c43565b505b8251604051635d6b480f60e01b81526001600160a01b0390911690635d6b480f90611e389033906001906004016148b1565b600060405180830381600087803b158015611e5257600080fd5b505af1158015611e66573d6000803e3d6000fd5b505084516040516372423c1760e01b81526001600160a01b0390911692506372423c179150611e9b90339034906004016148b1565b602060405180830381600087803b158015611eb557600080fd5b505af1158015611ec9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eed919061451f565b5082516060830151604051639976cf4560e01b81526001600160a01b0390921691639976cf4591611f23913391906004016148b1565b602060405180830381600087803b158015611f3d57600080fd5b505af1158015611f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f75919061451f565b5082516040516382fe3eb960e01b81526001600160a01b03909116906382fe3eb990611fa590339060040161485c565b600060405180830381600087803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b50508451604051630c7940bd60e11b81526001600160a01b0390911692506318f2817a915061200690339060040161485c565b602060405180830381600087803b15801561202057600080fd5b505af1158015612034573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612058919061451f565b60c0830152600b5460a08301516040516346f7cf8760e01b81526001600160a01b03909216916346f7cf8791612097913391908b908b906004016148ca565b600060405180830381600087803b1580156120b157600080fd5b505af11580156120c5573d6000803e3d6000fd5b505084516040516315d549f160e01b81526001600160a01b0390911692506315d549f191506120f890339060040161485c565b602060405180830381600087803b15801561211257600080fd5b505af1158015612126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214a919061451f565b60e0830181905260405133917f59cfd0cd754bc5748b6770e94a4ffa5f678d885cb899dcfadc5734edb97c67ab9161218291906152d8565b60405180910390a2612198836020015134613943565b6121b183602001518460400151868a86604001516139bf565b602083015160408401516006546121dd9291906001600160a01b03166801158e460913d00000806139bf565b606082015160c083015160405133926000805160206153378339815191529261220b92349190600090614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc0022741836020015160405161225091906152d8565b60405180910390a25050505050505050565b6000610959826801158e460913d0000063ffffffff6127a716565b6114b98787878787878733612da2565b6001600160a01b0381166122b35760405162461bcd60e51b81526004016106ff90614c3a565b803b806109895760405162461bcd60e51b81526004016106ff90614fde565b600c546001600160a01b03166122fa5760405162461bcd60e51b81526004016106ff90615237565b851580156123085750600087115b1561234f57600c54600a5461234d916001600160a01b039081169116857f000000000000000000000000000000000000000000000000000000000000000086866127cc565b505b61235f3389898989898f30612da2565b85801561236c5750600087115b15610df957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b3926123a7929116908b906004016148b1565b602060405180830381600087803b1580156123c157600080fd5b505af11580156123d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f9919061447e565b6124155760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b9261244d929116908b9033906004016148f5565b602060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f919061451f565b50505050505050505050565b60006124ed83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a79565b90505b92915050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561253257600080fd5b505afa158015612546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061256a91906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161259a919061485c565b60206040518083038186803b1580156125b257600080fd5b505afa1580156125c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ea919061451f565b9050306001600160a01b03831663605629d633838a893561261160408c0160208d01614803565b8b604001358c606001356040518863ffffffff1660e01b815260040161263d9796959493929190614870565b600060405180830381600087803b15801561265757600080fd5b505af115801561266b573d6000803e3d6000fd5b50505050866126fc83856001600160a01b03166370a08231856040518263ffffffff1660e01b81526004016126a0919061485c565b60206040518083038186803b1580156126b857600080fd5b505afa1580156126cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f0919061451f565b9063ffffffff6124ab16565b146127195760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c9223906127499089908b9033906004016148f5565b602060405180830381600087803b15801561276357600080fd5b505af1158015612777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279b919061451f565b98975050505050505050565b6000828201838110156124ed5760405162461bcd60e51b81526004016106ff90614a8a565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284091906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612870919061485c565b60206040518083038186803b15801561288857600080fd5b505afa15801561289c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c0919061451f565b87516020015190915030906001600160a01b0388166330f28b7a8a6128e58585613aa5565b338b8b6040518663ffffffff1660e01b8152600401612908959493929190615267565b600060405180830381600087803b15801561292257600080fd5b505af1158015612936573d6000803e3d6000fd5b505050508061296b84866001600160a01b03166370a08231866040518263ffffffff1660e01b81526004016126a0919061485c565b146129885760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c9223906129b8908d90859033906004016148f5565b602060405180830381600087803b1580156129d257600080fd5b505af11580156129e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0a919061451f565b9b9a5050505050505050505050565b6114a28660008660018787878c612da2565b6005546001600160a01b031633146106925760405162461bcd60e51b81526004016106ff9061507c565b6040516321e3780160e01b81526000906001600160a01b038416906321e3780190612a8490859060040161485c565b60206040518083038186803b158015612a9c57600080fd5b505afa158015612ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad4919061451f565b9050806001146109725760405162461bcd60e51b81526004016106ff90614ddf565b612aff8161337a565b156107115760405162461bcd60e51b81526004016106ff90614b8a565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190612b4a90869060040161485c565b60206040518083038186803b158015612b6257600080fd5b505afa158015612b76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9a919061451f565b10156109725760405162461bcd60e51b81526004016106ff90614997565b600080612bc36113a1565b90506000612bcf610ef5565b905086612beb57612be6828963ffffffff6124ab16565b612bfb565b612bfb828963ffffffff6127a716565b915084612c1757612c12818763ffffffff6124ab16565b612c27565b612c27818763ffffffff6127a716565b90506000612c36838387613785565b9998505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9157600080fd5b505afa158015612ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc9919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614d70565b60405163121cbc4d60e11b81526001600160a01b03851690632439789a90612d149084906004016152d8565b600060405180830381600087803b158015612d2e57600080fd5b505af1158015612d42573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b0386169250639dc29fac9150612d7490859085906004016148b1565b600060405180830381600087803b158015612d8e57600080fd5b505af1158015611c2d573d6000803e3d6000fd5b612daa614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152612de2614176565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e3257600080fd5b505af1158015612e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6a919061451f565b808252612e769061337a565b15156101c08201528615612e9c57612e9384826101c00151613415565b612e9c88613ad7565b612ea589613af7565b612eaf8989613b1e565b8151612ebb908b612a55565b336001600160a01b038b161480612ef157506005546001600160a01b031633148015612ee75750600034115b8015612ef1575087155b612ef757fe5b8151604051630b07655760e01b81526001600160a01b0390911690630b07655790612f26908d9060040161485c565b600060405180830381600087803b158015612f4057600080fd5b505af1158015612f54573d6000803e3d6000fd5b50505050612f62348a613b51565b15156060830152602082015260408101889052868015612f855750806101c00151155b15612fc057612f9e826000015183604001518a876135a3565b61012082018190526040820151612fba9163ffffffff6127a716565b60408201525b815160405163d66a255360e01b81526001600160a01b039091169063d66a255390612fef908d9060040161485c565b60206040518083038186803b15801561300757600080fd5b505afa15801561301b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303f919061451f565b608082015281516040516309019aaf60e31b81526001600160a01b039091169063480cd57890613073908d9060040161485c565b60206040518083038186803b15801561308b57600080fd5b505afa15801561309f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c3919061451f565b60a08201819052608082015182516130dc929190613785565b8160c001818152505061310c8160a0015182608001518360200151846060015185604001518c8760000151613b70565b60e082015260a081015189111561311f57fe5b613130816101c001518a8984613b94565b8615801561313e5750600088115b156131855761316061315b82604001516126f08460800151613c08565b61375c565b61317281608001518260400151613c23565b61318582604001518b8360400151612b1c565b6131a382600001518b8360200151846060015185604001518c613c5b565b6101408301526101608201528151604051630c7940bd60e11b81526001600160a01b03909116906318f2817a906131de908d9060040161485c565b602060405180830381600087803b1580156131f857600080fd5b505af115801561320c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613230919061451f565b8161018001818152505061325c8160a0015182608001518360200151846060015185604001518c613e89565b6101a08201819052600b5460405163015f109360e51b81526001600160a01b0390911691632be2126091613298918e918b908b906004016148ca565b600060405180830381600087803b1580156132b257600080fd5b505af11580156132c6573d6000803e3d6000fd5b50505050896001600160a01b031660008051602061533783398151915282610140015183610160015184610180015160026040516133079493929190614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc002274182610120015160405161334d91906152d8565b60405180910390a261249f8260200151836040015133846020015185606001518d8d88604001518b613eba565b60008061338683613f5e565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133d657600080fd5b505afa1580156133ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061340e919061451f565b1192915050565b801561344857670de0b6b3a76400008211156134435760405162461bcd60e51b81526004016106ff90614c71565b610989565b600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561349657600080fd5b505afa1580156134aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ce919061451f565b82101580156134e55750670de0b6b3a76400008211155b6109895760405162461bcd60e51b81526004016106ff906150c5565b6040516321e3780160e01b81526000906001600160a01b038416906321e378019061353090859060040161485c565b60206040518083038186803b15801561354857600080fd5b505afa15801561355c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613580919061451f565b905080600114156109725760405162461bcd60e51b81526004016106ff90615115565b6000846001600160a01b0316635dba4c4a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135e057600080fd5b505af11580156135f4573d6000803e3d6000fd5b5050604051630631203b60e41b8152600092506001600160a01b038816915063631203b0906136279087906004016152d8565b60206040518083038186803b15801561363f57600080fd5b505afa158015613653573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613677919061451f565b9050613684818585613f8a565b600d546040516340c10f1960e01b81526001600160a01b03878116926340c10f19926136b8929091169085906004016148b1565b600060405180830381600087803b1580156136d257600080fd5b505af11580156136e6573d6000803e3d6000fd5b50505050600d60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561373a57600080fd5b505af115801561374e573d6000803e3d6000fd5b509298975050505050505050565b6809c2007651b25000008110156107115760405162461bcd60e51b81526004016106ff90614f81565b600082156137b85760006137af846137a3878663ffffffff613fca16565b9063ffffffff61400416565b91506137bd9050565b506000195b9392505050565b600081156137f0576137e9826137a38568056bc75e2d6310000063ffffffff613fca16565b90506124f0565b506000196124f0565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561384757600080fd5b505afa15801561385b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387f919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614be3565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156138ec57600080fd5b505afa158015613900573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613924919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614f12565b6000826001600160a01b03168260405161395c9061483c565b60006040518083038185875af1925050503d8060008114613999576040519150601f19603f3d011682016040523d82523d6000602084013e61399e565b606091505b50509050806109725760405162461bcd60e51b81526004016106ff906149f4565b60405163f2e91d7160e01b81526001600160a01b0386169063f2e91d71906139eb9084906004016152d8565b600060405180830381600087803b158015613a0557600080fd5b505af1158015613a19573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b03871692506340c10f199150613a4b90869086906004016148b1565b600060405180830381600087803b158015613a6557600080fd5b505af1158015610df9573d6000803e3d6000fd5b60008184841115613a9d5760405162461bcd60e51b81526004016106ff9190614944565b505050900390565b613aad6141f0565b613ab56141f0565b5050604080518082019091526001600160a01b03929092168252602082015290565b600081116107115760405162461bcd60e51b81526004016106ff9061514c565b341580613b02575080155b6107115760405162461bcd60e51b81526004016106ff90614b3a565b34151580613b2b57508115155b80613b3557508015155b6109895760405162461bcd60e51b81526004016106ff90614cc3565b6000808315613b6557508290506001613b69565b8291505b9250929050565b6000806000613b838a8a8a8a8a8a614046565b915091506000612a0a838387613785565b8315613bcd57613ba38361409c565b8115613bc857613bb68160e001516137f9565b613bc88160e001518260c001516140ba565b610725565b613bda8160e0015161389e565b613bf7816020015182606001518360400151858560000151612bb8565b610100820181905261072590612c43565b6000610959826801158e460913d0000063ffffffff6124ab16565b613c3c826801158e460913d0000063ffffffff6124ab16565b8111156109895760405162461bcd60e51b81526004016106ff90615013565b600080600085613cea5760405163d3d6f84360e01b81526001600160a01b038a169063d3d6f84390613c93908b908b906004016148b1565b602060405180830381600087803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce5919061451f565b613d6a565b6040516372423c1760e01b81526001600160a01b038a16906372423c1790613d18908b908b906004016148b1565b602060405180830381600087803b158015613d3257600080fd5b505af1158015613d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d6a919061451f565b9050600084613df857604051630930874960e11b81526001600160a01b038b16906312610e9290613da1908c908a906004016148b1565b602060405180830381600087803b158015613dbb57600080fd5b505af1158015613dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df3919061451f565b613e78565b604051639976cf4560e01b81526001600160a01b038b1690639976cf4590613e26908c908a906004016148b1565b602060405180830381600087803b158015613e4057600080fd5b505af1158015613e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e78919061451f565b919a91995090975050505050505050565b6000806000613e9c898989898989614046565b915091506000613eac83836137c4565b9a9950505050505050505050565b8215613ed257613ecd89898387866139bf565b613ede565b613ede89898987612ce8565b8415613ef357613eee8987613943565b610df9565b6040516364a197f360e01b81526001600160a01b038a16906364a197f390613f21908a908a906004016148b1565b600060405180830381600087803b158015613f3b57600080fd5b505af1158015613f4f573d6000803e3d6000fd5b50505050505050505050505050565b600080613f696113a1565b90506000613f75610ef5565b9050613f82828286613785565b949350505050565b6000613fa8836137a386670de0b6b3a764000063ffffffff613fca16565b9050818111156107255760405162461bcd60e51b81526004016106ff90615200565b600082613fd9575060006124f0565b82820282848281613fe657fe5b04146124ed5760405162461bcd60e51b81526004016106ff90614d2f565b60006124ed83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506140da565b600080878786614065576140608a8963ffffffff6124ab16565b614075565b6140758a8963ffffffff6127a716565b91508461408c57613df3898763ffffffff6124ab16565b613e78898763ffffffff6127a716565b80156107115760405162461bcd60e51b81526004016106ff90614e5e565b808210156109895760405162461bcd60e51b81526004016106ff906151a3565b600081836140fb5760405162461bcd60e51b81526004016106ff9190614944565b50600083858161410757fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806101e00160405280600081526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b80356124f081615313565b60008083601f840112614223578182fd5b50813567ffffffffffffffff81111561423a578182fd5b602083019150836020828501011115613b6957600080fd5b600060808284031215614263578081fd5b50919050565b6000818303608081121561427b578182fd5b61428560606152e1565b9150604081121561429557600080fd5b506142a060406152e1565b82356142ab81615313565b808252506020830135602082015280825250604082013560208201526060820135604082015292915050565b6000602082840312156142e8578081fd5b81356124ed81615313565b600060208284031215614304578081fd5b81516124ed81615313565b60008060408385031215614321578081fd5b823561432c81615313565b9150602083013561433c81615313565b809150509250929050565b60008060006060848603121561435b578081fd5b833561436681615313565b9250602084013561437681615313565b9150604084013561438681615313565b809150509250925092565b6000806000806000806000806000806000806101808d8f0312156143b3578788fd5b8c356143be81615313565b9b5060208d01356143ce81615313565b9a5060408d01356143de81615313565b995060608d01356143ee81615313565b985060808d01356143fe81615313565b975060a08d013561440e81615313565b965061441d8e60c08f01614207565b955061442c8e60e08f01614207565b945061443c8e6101008f01614207565b935061444c8e6101208f01614207565b925061445c8e6101408f01614207565b915061446c8e6101608f01614207565b90509295989b509295989b509295989b565b60006020828403121561448f578081fd5b81516124ed81615328565b6000608082840312156144ab578081fd5b6124ed8383614252565b600080600060a084860312156144c9578283fd5b6144d38585614269565b9250608084013567ffffffffffffffff8111156144ee578283fd5b6144fa86828701614212565b9497909650939450505050565b600060208284031215614518578081fd5b5035919050565b600060208284031215614530578081fd5b5051919050565b60008060006060848603121561454b578283fd5b83359250602084013561437681615313565b60008060008060e08587031215614572578182fd5b84359350602085013561458481615313565b9250604085013561459481615313565b91506145a38660608701614252565b905092959194509250565b60008060008060008061010087890312156145c7578384fd5b8635955060208701356145d981615313565b945060408701356145e981615313565b93506145f88860608901614269565b925060e087013567ffffffffffffffff811115614613578283fd5b61461f89828a01614212565b979a9699509497509295939492505050565b60008060008060808587031215614646578182fd5b8435935060208501359250604085013561465f81615313565b9150606085013561466f81615313565b939692955090935050565b60008060008060008060c08789031215614692578384fd5b86359550602087013594506040870135935060608701356146b281615328565b925060808701356146c281615313565b915060a08701356146d281615313565b809150509295509295509295565b6000806000806000806000610140888a0312156146fb578081fd5b873596506020880135955060408801359450606088013561471b81615328565b9350608088013561472b81615313565b925060a088013561473b81615313565b915061474a8960c08a01614252565b905092959891949750929550565b60008060008060008060008060006101608a8c031215614776578283fd5b8935985060208a0135975060408a0135965060608a013561479681615328565b955060808a01356147a681615313565b945060a08a01356147b681615313565b93506147c58b60c08c01614269565b92506101408a013567ffffffffffffffff8111156147e1578283fd5b6147ed8c828d01614212565b8194508093505050509295985092959850929598565b600060208284031215614814578081fd5b813560ff811681146124ed578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b84815260208101849052604081018390526080810161493683615308565b606083015295945050505050565b6000602080835283518082850152825b8181101561497057858101830151858201604001528201614954565b818111156149815783604083870101525b50601f01601f1916929092016040019392505050565b6020808252603d908201527f426f72726f7765724f70733a2043616c6c657220646f65736e7420686176652060408201527f656e6f756768205a55534420746f206d616b652072657061796d656e74000000606082015260800190565b6020808252602d908201527f426f72726f7765724f70733a2053656e64696e672045544820746f204163746960408201526c1d99541bdbdb0819985a5b1959609a1b606082015260800190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f5a555344206973206e6f7420626f72726f77656420636f72726563746c790000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60208082526030908201527f426f72726f7765724f7065726174696f6e733a2043616e6e6f7420776974686460408201526f1c985dc8185b99081859190818dbdb1b60821b606082015260800190565b60208082526039908201527f426f72726f7765724f70733a204f7065726174696f6e206e6f74207065726d696040820152787474656420647572696e67205265636f76657279204d6f646560381b606082015260800190565b60208082526037908201527f426f72726f7765724f70733a204f7065726174696f6e206d757374206c65617660408201527632903a3937bb32903bb4ba341024a1a9101f1e9021a1a960491b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526032908201527f4d6178206665652070657263656e74616765206d757374206c657373207468616040820152716e206f7220657175616c20746f203130302560701b606082015260800190565b60208082526046908201527f426f72726f7765724f70733a205468657265206d75737420626520656974686560408201527f72206120636f6c6c61746572616c206368616e6765206f7220612064656274206060820152656368616e676560d01b608082015260a00190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20544352203c20434352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252602e908201527f426f72726f7765724f70733a2054726f766520646f6573206e6f74206578697360408201526d1d081bdc881a5cc818db1bdcd95960921b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252603e908201527f426f72726f7765724f70733a20436f6c6c61746572616c20776974686472617760408201527f616c206e6f74207065726d6974746564205265636f76657279204d6f64650000606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20494352203c204d4352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252603a908201527f426f72726f7765724f70733a2054726f76652773206e65742064656274206d7560408201527f73742062652067726561746572207468616e206d696e696d756d000000000000606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526043908201527f426f72726f7765724f70733a20416d6f756e7420726570616964206d7573742060408201527f6e6f74206265206c6172676572207468616e207468652054726f76652773206460608201526219589d60ea1b608082015260a00190565b60208082526029908201527f426f72726f7765724f70733a2043616c6c6572206973206e6f742053746162696040820152681b1a5d1e48141bdbdb60ba1b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252601c908201527f426f72726f7765724f70733a2054726f76652069732061637469766500000000604082015260600190565b60208082526037908201527f426f72726f7765724f70733a204465627420696e637265617365207265717569604082015276726573206e6f6e2d7a65726f20646562744368616e676560481b606082015260800190565b6020808252603e908201527f426f72726f7765724f70733a2043616e6e6f7420646563726561736520796f7560408201527f722054726f766527732049435220696e205265636f76657279204d6f64650000606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b60208082526016908201527513585cdcd95d081859191c995cdcc81b9bdd081cd95d60521b604082015260600190565b6000610100615277838951614824565b60208801516040840152604088015160608401526152986080840188614824565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b60405181810167ffffffffffffffff8111828210171561530057600080fd5b604052919050565b806003811061095c57fe5b6001600160a01b038116811461071157600080fd5b801515811461071157600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212209d20681b7b6630050fbad5344b16d370ece553865b2bf0ccb789b394933ed00f64736f6c634300060b0033", + "devdoc": { + "kind": "dev", + "methods": { + "getOwner()": { + "returns": { + "_owner": "Address of the owner. " + } + }, + "setAddresses(address,address,address,address,address,address,address,address,address,address,address,address)": { + "details": "initializer function, checks addresses are contracts", + "params": { + "_activePoolAddress": "ActivePool contract address", + "_collSurplusPoolAddress": "CollSurplusPool contract address", + "_defaultPoolAddress": "DefaultPool contract address", + "_feeDistributorAddress": "feeDistributor contract address", + "_gasPoolAddress": "GasPool contract address", + "_liquityBaseParamsAddress": "LiquidityBaseParams contract address", + "_priceFeedAddress": "PrideFeed contract address", + "_sortedTrovesAddress": "SortedTroves contract address", + "_stabilityPoolAddress": "StabilityPool contract address", + "_troveManagerAddress": "TroveManager contract address", + "_zeroStakingAddress": "ZEROStaking contract address", + "_zusdTokenAddress": "ZUSDToken contract address" + } + }, + "setOwner(address)": { + "params": { + "_owner": "Address of the owner. " + } + }, + "withdrawZusdAndConvertToDLLR(uint256,uint256,address,address)": { + "returns": { + "_0": "DLLR amount minted" + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "MIN_NET_DEBT()": { + "notice": "Minimum amount of net ZUSD debt a trove must have" + }, + "ZUSD_GAS_COMPENSATION()": { + "notice": "Amount of ZUSD to be locked in gas pool on opening troves" + }, + "addColl(address,address)": { + "notice": "Send ETH as collateral to a trove" + }, + "claimCollateral()": { + "notice": "Claim remaining collateral from a redemption or from a liquidation with ICR > MCR in Recovery Mode" + }, + "closeNueTrove((uint256,uint8,bytes32,bytes32))": { + "notice": "allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE. This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD." + }, + "closeNueTroveWithPermit2(((address,uint256),uint256,uint256),bytes)": { + "notice": "allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE. This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD." + }, + "closeTrove()": { + "notice": "allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a ZUSD balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` ZUSD." + }, + "constructor": "Constructor ", + "getOwner()": { + "notice": "Return address of the owner." + }, + "moveETHGainToTrove(address,address,address)": { + "notice": "Send ETH as collateral to a trove. Called by only the Stability Pool." + }, + "permit2()": { + "notice": "CONSTANT / IMMUTABLE VARIABLE ONLY " + }, + "repayZUSD(uint256,address,address)": { + "notice": "Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly" + }, + "repayZusdFromDLLR(uint256,address,address,(uint256,uint8,bytes32,bytes32))": { + "notice": "Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly" + }, + "repayZusdFromDLLRWithPermit2(uint256,address,address,((address,uint256),uint256,uint256),bytes)": { + "notice": "Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly" + }, + "setAddresses(address,address,address,address,address,address,address,address,address,address,address,address)": { + "notice": "Called only once on init, to set addresses of other Zero contracts. Callable only by owner" + }, + "setOwner(address)": { + "notice": "Set address of the owner (only owner can call this function)" + }, + "withdrawColl(uint256,address,address)": { + "notice": "Withdraw ETH collateral from a trove" + }, + "withdrawZUSD(uint256,uint256,address,address)": { + "notice": "Withdraw ZUSD tokens from a trove: mint new ZUSD tokens to the owner, and increase the trove's debt accordingly" + }, + "withdrawZusdAndConvertToDLLR(uint256,uint256,address,address)": { + "notice": "Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction Zero Line of Credit owner can borrow a specified amount of ZUSD and convert it to DLLR via Sovryn Mynt" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 5495, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "activePool", + "offset": 0, + "slot": "0", + "type": "t_contract(IActivePool)19557" + }, + { + "astId": 5497, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "defaultPool", + "offset": 0, + "slot": "1", + "type": "t_contract(IDefaultPool)20229" + }, + { + "astId": 5500, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "priceFeed", + "offset": 0, + "slot": "2", + "type": "t_contract(IPriceFeed)20458" + }, + { + "astId": 5503, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "liquityBaseParams", + "offset": 0, + "slot": "3", + "type": "t_contract(ILiquityBaseParams)20379" + }, + { + "astId": 4622, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "troveManager", + "offset": 0, + "slot": "4", + "type": "t_contract(ITroveManager)21635" + }, + { + "astId": 4624, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "stabilityPoolAddress", + "offset": 0, + "slot": "5", + "type": "t_address" + }, + { + "astId": 4626, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "gasPoolAddress", + "offset": 0, + "slot": "6", + "type": "t_address" + }, + { + "astId": 4628, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "collSurplusPool", + "offset": 0, + "slot": "7", + "type": "t_contract(ICollSurplusPool)20130" + }, + { + "astId": 4630, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "zeroStaking", + "offset": 0, + "slot": "8", + "type": "t_contract(IZEROStaking)21760" + }, + { + "astId": 4632, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "zeroStakingAddress", + "offset": 0, + "slot": "9", + "type": "t_address" + }, + { + "astId": 4634, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "zusdToken", + "offset": 0, + "slot": "10", + "type": "t_contract(IZUSDToken)21842" + }, + { + "astId": 4636, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "sortedTroves", + "offset": 0, + "slot": "11", + "type": "t_contract(ISortedTroves)20817" + }, + { + "astId": 4638, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "massetManager", + "offset": 0, + "slot": "12", + "type": "t_contract(IMassetManager)6083" + }, + { + "astId": 4640, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "feeDistributor", + "offset": 0, + "slot": "13", + "type": "t_contract(IFeeDistributor)20298" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_contract(IActivePool)19557": { + "encoding": "inplace", + "label": "contract IActivePool", + "numberOfBytes": "20" + }, + "t_contract(ICollSurplusPool)20130": { + "encoding": "inplace", + "label": "contract ICollSurplusPool", + "numberOfBytes": "20" + }, + "t_contract(IDefaultPool)20229": { + "encoding": "inplace", + "label": "contract IDefaultPool", + "numberOfBytes": "20" + }, + "t_contract(IFeeDistributor)20298": { + "encoding": "inplace", + "label": "contract IFeeDistributor", + "numberOfBytes": "20" + }, + "t_contract(ILiquityBaseParams)20379": { + "encoding": "inplace", + "label": "contract ILiquityBaseParams", + "numberOfBytes": "20" + }, + "t_contract(IMassetManager)6083": { + "encoding": "inplace", + "label": "contract IMassetManager", + "numberOfBytes": "20" + }, + "t_contract(IPriceFeed)20458": { + "encoding": "inplace", + "label": "contract IPriceFeed", + "numberOfBytes": "20" + }, + "t_contract(ISortedTroves)20817": { + "encoding": "inplace", + "label": "contract ISortedTroves", + "numberOfBytes": "20" + }, + "t_contract(ITroveManager)21635": { + "encoding": "inplace", + "label": "contract ITroveManager", + "numberOfBytes": "20" + }, + "t_contract(IZEROStaking)21760": { + "encoding": "inplace", + "label": "contract IZEROStaking", + "numberOfBytes": "20" + }, + "t_contract(IZUSDToken)21842": { + "encoding": "inplace", + "label": "contract IZUSDToken", + "numberOfBytes": "20" + } + } + } +} diff --git a/external/deployments/rskMainnet/BorrowerOperations_Proxy.json b/external/deployments/rskMainnet/BorrowerOperations_Proxy.json new file mode 100644 index 000000000..4fc96e547 --- /dev/null +++ b/external/deployments/rskMainnet/BorrowerOperations_Proxy.json @@ -0,0 +1,110 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "UpgradableProxy", + "sourceName": "contracts/Proxy/UpgradableProxy.sol", + "address": "0x5B9dB4B8bdeF3e57323187a9AC2639C5DEe5FD39", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_oldImplementation", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_newImplementation", + "type": "address" + } + ], + "name": "ImplementationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610023336001600160e01b0361002816565b610110565b6001600160a01b03811661006d5760405162461bcd60e51b81526004018080602001828103825260228152602001806105e26022913960400191505060405180910390fd5b6001600160a01b0381166100886001600160e01b036100e616565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b6104c38061011f6000396000f3fe6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b00334f776e61626c653a3a7365744f776e65723a20696e76616c69642061646472657373", + "deployedBytecode": "0x6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/external/deployments/rskMainnet/MocIntegration.json b/external/deployments/rskMainnet/MocIntegration.json new file mode 100644 index 000000000..60cfd5a95 --- /dev/null +++ b/external/deployments/rskMainnet/MocIntegration.json @@ -0,0 +1,547 @@ +{ + "address": "0x9363323D9c653a2b89C758f62f5043f0B2c67C71", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_moc", + "type": "address" + }, + { + "internalType": "address", + "name": "_doc", + "type": "address" + }, + { + "internalType": "address", + "name": "_dllr", + "type": "address" + }, + { + "internalType": "address", + "name": "_massetManager", + "type": "address" + }, + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fromDLLR", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "toRBTC", + "type": "uint256" + } + ], + "name": "GetDocFromDllrAndRedeemRBTC", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newMocVendorAccount", + "type": "address" + } + ], + "name": "MocVendorAccountSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "dllr", + "outputs": [ + { + "internalType": "contract IDLLR", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "doc", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "getDocFromDllrAndRedeemRBTC", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "getDocFromDllrAndRedeemRbtcWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getProxyImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_mocVendorAccount", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "massetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "moc", + "outputs": [ + { + "internalType": "contract IMocMintRedeemDoc", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "mocVendorAccount", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "newMocVedorAccount", + "type": "address" + } + ], + "name": "setMocVendorAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "numDeployments": 3, + "bytecode": "0x6101206040523480156200001257600080fd5b50604051620012cd380380620012cd833981016040819052620000359162000140565b6001600160a01b038516158015906200005657506001600160a01b03841615155b80156200006b57506001600160a01b03831615155b80156200008057506001600160a01b03821615155b80156200009557506001600160a01b03811615155b620000f95760405162461bcd60e51b815260206004820152602a60248201527f4d6f63496e746567726174696f6e3a3a206e6f206e756c6c2061646472657373604482015269195cc8185b1b1bddd95960b21b606482015260840160405180910390fd5b6001600160a01b0394851660805292841660a05290831660c052821660e0521661010052620001b0565b80516001600160a01b03811681146200013b57600080fd5b919050565b600080600080600060a086880312156200015957600080fd5b620001648662000123565b9450620001746020870162000123565b9350620001846040870162000123565b9250620001946060870162000123565b9150620001a46080870162000123565b90509295509295909350565b60805160a05160c05160e051610100516110a16200022c6000396000818160ff015261069301526000818161027501528181610435015261074f01526000818161014f01526103220152600081816101ee015281816103fb01526107150152600081816101a5015281816104f7015261080801526110a16000f3fe6080604052600436106100e15760003560e01c806390e4b7201161007f578063c4d66de811610059578063c4d66de814610297578063e5085517146102b7578063f2fde38b146102d7578063fc176819146102f757600080fd5b806390e4b7201461022e5780639b2633ae14610243578063b5c89bab1461026357600080fd5b806353428253116100bb5780635342825314610193578063715018a6146101c75780637a0a3ac5146101dc5780638da5cb5b1461021057600080fd5b806312261ee7146100ed57806333c507ae1461013d578063460f2de11461017157600080fd5b366100e857005b600080fd5b3480156100f957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b34801561014957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561017d57600080fd5b5061019161018c366004610c64565b610317565b005b34801561019f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d357600080fd5b50610191610619565b3480156101e857600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561021c57600080fd5b506033546001600160a01b0316610121565b34801561023a57600080fd5b5061012161062d565b34801561024f57600080fd5b5061019161025e366004610d7d565b610665565b34801561026f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156102a357600080fd5b506101916102b2366004610e40565b61092c565b3480156102c357600080fd5b506101916102d2366004610e40565b610a47565b3480156102e357600080fd5b506101916102f2366004610e40565b610a5b565b34801561030357600080fd5b50609754610121906001600160a01b031681565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663605629d6338386863561035c6040890160208a01610e64565b604080516001600160e01b031960e089901b1681526001600160a01b0396871660048201529590941660248601526044850192909252606484015260ff16608483015285013560a4820152606085013560c482015260e401600060405180830381600087803b1580156103ce57600080fd5b505af11580156103e2573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820187905284811660448301528693507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af115801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a39190610e87565b146104c95760405162461bcd60e51b81526004016104c090610ea0565b60405180910390fd5b60975460405163b7aa53e760e01b8152600481018590526001600160a01b03918216602482015282821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561053b57600080fd5b505af115801561054f573d6000803e3d6000fd5b50505050600081836001600160a01b03163161056b9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146105b0576040519150601f19603f3d011682016040523d82523d6000602084013e6105b5565b606091505b50509050806105d65760405162461bcd60e51b81526004016104c090610f0f565b604080518781526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a2505050505050565b610621610ad1565b61062b6000610b2b565b565b60006106607f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b815160200151309060006106798383610b7d565b60405163187945bd60e11b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906330f28b7a906106ce908890859033908a90600401610f60565b600060405180830381600087803b1580156106e857600080fd5b505af11580156106fc573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820186905286811660448301528593507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af1158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd9190610e87565b146107da5760405162461bcd60e51b81526004016104c090610ea0565b60975460405163b7aa53e760e01b8152600481018490526001600160a01b03918216602482015284821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561084c57600080fd5b505af1158015610860573d6000803e3d6000fd5b50505050600081856001600160a01b03163161087c9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146108c1576040519150601f19603f3d011682016040523d82523d6000602084013e6108c6565b606091505b50509050806108e75760405162461bcd60e51b81526004016104c090610f0f565b604080518681526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a25050505050505050565b600054610100900460ff161580801561094c5750600054600160ff909116105b806109665750303b158015610966575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104c0565b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b6109f4610bb1565b6109fd82610be0565b8015610a43576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b610a4f610ad1565b610a5881610be0565b50565b610a63610ad1565b6001600160a01b038116610ac85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104c0565b610a5881610b2b565b6033546001600160a01b0316331461062b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104c0565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080518082018252600080825260209182015281518083019092526001600160a01b038416825281018290525b92915050565b600054610100900460ff16610bd85760405162461bcd60e51b81526004016104c090611020565b61062b610c34565b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527fc2a1feb9d65ecb31b0e93a520a66d19319929a2bf58046d92d762c04e7dd06c99060200160405180910390a150565b600054610100900460ff16610c5b5760405162461bcd60e51b81526004016104c090611020565b61062b33610b2b565b60008082840360a0811215610c7857600080fd5b833592506080601f1982011215610c8e57600080fd5b506020830190509250929050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610cd557610cd5610c9c565b60405290565b6001600160a01b0381168114610a5857600080fd5b600082601f830112610d0157600080fd5b813567ffffffffffffffff80821115610d1c57610d1c610c9c565b604051601f8301601f19908116603f01168101908282118183101715610d4457610d44610c9c565b81604052838152866020858801011115610d5d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008082840360a0811215610d9157600080fd5b6080811215610d9f57600080fd5b6040516060810167ffffffffffffffff8282108183111715610dc357610dc3610c9c565b816040526040841215610dd557600080fd5b610ddd610cb2565b935086359150610dec82610cdb565b8184526020870135602085015283835260408701356020840152606087013560408401528295506080870135935080841115610e2757600080fd5b505050610e3685828601610cf0565b9150509250929050565b600060208284031215610e5257600080fd5b8135610e5d81610cdb565b9392505050565b600060208284031215610e7657600080fd5b813560ff81168114610e5d57600080fd5b600060208284031215610e9957600080fd5b5051919050565b6020808252602e908201527f4d6f63496e746567726174696f6e3a3a2072656465656d656420696e636f727260408201526d1958dd08111bd0c8185b5bdd5b9d60921b606082015260800190565b81810381811115610bab57634e487b7160e01b600052601160045260246000fd5b60208082526031908201527f4d6f63496e746567726174696f6e3a3a206572726f72207472616e7366657272604082015270696e672072656465656d6564205242544360781b606082015260800190565b6000610100610f8383885180516001600160a01b03168252602090810151910152565b602080880151604085015260408801516060850152610fb8608085018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c085015260e0840182905284519184018290526000915b80831015610ff957858301820151858401610120015291810191610fda565b6101209250600083828701015282601f19601f830116860101935050505095945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220d0fcc7c15da2d0cf8a6f0df865b7535edea2c45483b951fb883a7a57908c9d0764736f6c63430008110033", + "deployedBytecode": "0x6080604052600436106100e15760003560e01c806390e4b7201161007f578063c4d66de811610059578063c4d66de814610297578063e5085517146102b7578063f2fde38b146102d7578063fc176819146102f757600080fd5b806390e4b7201461022e5780639b2633ae14610243578063b5c89bab1461026357600080fd5b806353428253116100bb5780635342825314610193578063715018a6146101c75780637a0a3ac5146101dc5780638da5cb5b1461021057600080fd5b806312261ee7146100ed57806333c507ae1461013d578063460f2de11461017157600080fd5b366100e857005b600080fd5b3480156100f957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b34801561014957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561017d57600080fd5b5061019161018c366004610c64565b610317565b005b34801561019f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d357600080fd5b50610191610619565b3480156101e857600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561021c57600080fd5b506033546001600160a01b0316610121565b34801561023a57600080fd5b5061012161062d565b34801561024f57600080fd5b5061019161025e366004610d7d565b610665565b34801561026f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156102a357600080fd5b506101916102b2366004610e40565b61092c565b3480156102c357600080fd5b506101916102d2366004610e40565b610a47565b3480156102e357600080fd5b506101916102f2366004610e40565b610a5b565b34801561030357600080fd5b50609754610121906001600160a01b031681565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663605629d6338386863561035c6040890160208a01610e64565b604080516001600160e01b031960e089901b1681526001600160a01b0396871660048201529590941660248601526044850192909252606484015260ff16608483015285013560a4820152606085013560c482015260e401600060405180830381600087803b1580156103ce57600080fd5b505af11580156103e2573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820187905284811660448301528693507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af115801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a39190610e87565b146104c95760405162461bcd60e51b81526004016104c090610ea0565b60405180910390fd5b60975460405163b7aa53e760e01b8152600481018590526001600160a01b03918216602482015282821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561053b57600080fd5b505af115801561054f573d6000803e3d6000fd5b50505050600081836001600160a01b03163161056b9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146105b0576040519150601f19603f3d011682016040523d82523d6000602084013e6105b5565b606091505b50509050806105d65760405162461bcd60e51b81526004016104c090610f0f565b604080518781526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a2505050505050565b610621610ad1565b61062b6000610b2b565b565b60006106607f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b815160200151309060006106798383610b7d565b60405163187945bd60e11b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906330f28b7a906106ce908890859033908a90600401610f60565b600060405180830381600087803b1580156106e857600080fd5b505af11580156106fc573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820186905286811660448301528593507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af1158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd9190610e87565b146107da5760405162461bcd60e51b81526004016104c090610ea0565b60975460405163b7aa53e760e01b8152600481018490526001600160a01b03918216602482015284821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561084c57600080fd5b505af1158015610860573d6000803e3d6000fd5b50505050600081856001600160a01b03163161087c9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146108c1576040519150601f19603f3d011682016040523d82523d6000602084013e6108c6565b606091505b50509050806108e75760405162461bcd60e51b81526004016104c090610f0f565b604080518681526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a25050505050505050565b600054610100900460ff161580801561094c5750600054600160ff909116105b806109665750303b158015610966575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104c0565b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b6109f4610bb1565b6109fd82610be0565b8015610a43576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b610a4f610ad1565b610a5881610be0565b50565b610a63610ad1565b6001600160a01b038116610ac85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104c0565b610a5881610b2b565b6033546001600160a01b0316331461062b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104c0565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080518082018252600080825260209182015281518083019092526001600160a01b038416825281018290525b92915050565b600054610100900460ff16610bd85760405162461bcd60e51b81526004016104c090611020565b61062b610c34565b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527fc2a1feb9d65ecb31b0e93a520a66d19319929a2bf58046d92d762c04e7dd06c99060200160405180910390a150565b600054610100900460ff16610c5b5760405162461bcd60e51b81526004016104c090611020565b61062b33610b2b565b60008082840360a0811215610c7857600080fd5b833592506080601f1982011215610c8e57600080fd5b506020830190509250929050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610cd557610cd5610c9c565b60405290565b6001600160a01b0381168114610a5857600080fd5b600082601f830112610d0157600080fd5b813567ffffffffffffffff80821115610d1c57610d1c610c9c565b604051601f8301601f19908116603f01168101908282118183101715610d4457610d44610c9c565b81604052838152866020858801011115610d5d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008082840360a0811215610d9157600080fd5b6080811215610d9f57600080fd5b6040516060810167ffffffffffffffff8282108183111715610dc357610dc3610c9c565b816040526040841215610dd557600080fd5b610ddd610cb2565b935086359150610dec82610cdb565b8184526020870135602085015283835260408701356020840152606087013560408401528295506080870135935080841115610e2757600080fd5b505050610e3685828601610cf0565b9150509250929050565b600060208284031215610e5257600080fd5b8135610e5d81610cdb565b9392505050565b600060208284031215610e7657600080fd5b813560ff81168114610e5d57600080fd5b600060208284031215610e9957600080fd5b5051919050565b6020808252602e908201527f4d6f63496e746567726174696f6e3a3a2072656465656d656420696e636f727260408201526d1958dd08111bd0c8185b5bdd5b9d60921b606082015260800190565b81810381811115610bab57634e487b7160e01b600052601160045260246000fd5b60208082526031908201527f4d6f63496e746567726174696f6e3a3a206572726f72207472616e7366657272604082015270696e672072656465656d6564205242544360781b606082015260800190565b6000610100610f8383885180516001600160a01b03168252602090810151910152565b602080880151604085015260408801516060850152610fb8608085018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c085015260e0840182905284519184018290526000915b80831015610ff957858301820151858401610120015291810191610fda565b6101209250600083828701015282601f19601f830116860101935050505095945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220d0fcc7c15da2d0cf8a6f0df865b7535edea2c45483b951fb883a7a57908c9d0764736f6c63430008110033", + "implementation": "0x454E8deBBf6900036372407a23E1d0284Be3f12A", + "devdoc": { + "kind": "dev", + "methods": { + "constructor": { + "params": { + "_dllr": "DLLR contract address", + "_doc": "DoC contract address", + "_massetManager": "MassetManager contract address", + "_moc": "MoC main contract address" + } + }, + "getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))": { + "params": { + "_dllrAmount": "The amount of the DLLR (mAsset) that will be burned in exchange for _toToken", + "_permitParams": "EIP-2612 permit params: _deadline Expiration time of the signature. _v Last 1 byte of ECDSA signature. _r First 32 bytes of ECDSA signature. _s 32 bytes after _r in ECDSA signature." + } + }, + "getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)": { + "params": { + "permit": "permit data, in form of PermitTransferFrom struct.", + "signature": "of the permit data." + } + }, + "getProxyImplementation()": { + "details": "get the implementation logic address referring to ERC1967 standard.", + "returns": { + "_0": "logic implementation address." + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))": { + "notice": "how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------" + }, + "getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)": { + "notice": "how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------" + }, + "setMocVendorAccount(address)": { + "notice": "Set MoC registered Vendor account to receive markup fees https://docs.moneyonchain.com/main-rbtc-contract/integration-with-moc-platform/vendors" + } + }, + "notice": "This contract provides compound functions with Money On Chain wrapping them in one transaction for convenience and to save on gas", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 534, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8" + }, + { + "astId": 537, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 1021, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 10, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "t_address" + }, + { + "astId": 130, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "52", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 516, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 3845, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "mocVendorAccount", + "offset": 0, + "slot": "151", + "type": "t_address" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)49_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } + } +} diff --git a/external/deployments/rskMainnet/MocIntegration_Implementation.json b/external/deployments/rskMainnet/MocIntegration_Implementation.json new file mode 100644 index 000000000..3d0394f45 --- /dev/null +++ b/external/deployments/rskMainnet/MocIntegration_Implementation.json @@ -0,0 +1,571 @@ +{ + "address": "0x454E8deBBf6900036372407a23E1d0284Be3f12A", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_moc", + "type": "address" + }, + { + "internalType": "address", + "name": "_doc", + "type": "address" + }, + { + "internalType": "address", + "name": "_dllr", + "type": "address" + }, + { + "internalType": "address", + "name": "_massetManager", + "type": "address" + }, + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fromDLLR", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "toRBTC", + "type": "uint256" + } + ], + "name": "GetDocFromDllrAndRedeemRBTC", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newMocVendorAccount", + "type": "address" + } + ], + "name": "MocVendorAccountSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "dllr", + "outputs": [ + { + "internalType": "contract IDLLR", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "doc", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "getDocFromDllrAndRedeemRBTC", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "getDocFromDllrAndRedeemRbtcWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getProxyImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_mocVendorAccount", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "massetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "moc", + "outputs": [ + { + "internalType": "contract IMocMintRedeemDoc", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "mocVendorAccount", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "newMocVedorAccount", + "type": "address" + } + ], + "name": "setMocVendorAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0xbbd13925020d5f3b18a6d00ce298542584f591355a4414da5940ac8b4577f63d", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0x454E8deBBf6900036372407a23E1d0284Be3f12A", + "transactionIndex": 3, + "gasUsed": "1203648", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x93c59f579cf5b1630763e7425c9cba836c45a1b4be82c022451618b488b27c53", + "transactionHash": "0xbbd13925020d5f3b18a6d00ce298542584f591355a4414da5940ac8b4577f63d", + "logs": [], + "blockNumber": 6035993, + "cumulativeGasUsed": "2018846", + "status": 1, + "byzantium": true + }, + "args": [ + "0xf773b590af754d597770937fa8ea7abdf2668370", + "0xe700691da7b9851f2f35f8b8182c69c53ccad9db", + "0xc1411567d2670e24d9C4DaAa7CdA95686e1250AA", + "0x5F777270259E32F79589fe82269DB6209F7b7582", + "0x000000000022d473030f116ddee9f6b43ac78ba3" + ], + "numDeployments": 3, + "solcInputHash": "a479fe3ce562e2144d83ea46d24c05f8", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_moc\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_doc\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_dllr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_massetManager\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_permit2\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"}],\"name\":\"BeaconUpgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fromDLLR\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"toRBTC\",\"type\":\"uint256\"}],\"name\":\"GetDocFromDllrAndRedeemRBTC\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newMocVendorAccount\",\"type\":\"address\"}],\"name\":\"MocVendorAccountSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dllr\",\"outputs\":[{\"internalType\":\"contract IDLLR\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doc\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"getDocFromDllrAndRedeemRBTC\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"getDocFromDllrAndRedeemRbtcWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProxyImplementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_mocVendorAccount\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"massetManager\",\"outputs\":[{\"internalType\":\"contract IMassetManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"moc\",\"outputs\":[{\"internalType\":\"contract IMocMintRedeemDoc\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"mocVendorAccount\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newMocVedorAccount\",\"type\":\"address\"}],\"name\":\"setMocVendorAccount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_dllr\":\"DLLR contract address\",\"_doc\":\"DoC contract address\",\"_massetManager\":\"MassetManager contract address\",\"_moc\":\"MoC main contract address\"}},\"getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))\":{\"params\":{\"_dllrAmount\":\"The amount of the DLLR (mAsset) that will be burned in exchange for _toToken\",\"_permitParams\":\"EIP-2612 permit params: _deadline Expiration time of the signature. _v Last 1 byte of ECDSA signature. _r First 32 bytes of ECDSA signature. _s 32 bytes after _r in ECDSA signature.\"}},\"getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)\":{\"params\":{\"permit\":\"permit data, in form of PermitTransferFrom struct.\",\"signature\":\"of the permit data.\"}},\"getProxyImplementation()\":{\"details\":\"get the implementation logic address referring to ERC1967 standard.\",\"returns\":{\"_0\":\"logic implementation address.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))\":{\"notice\":\"how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------\"},\"getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)\":{\"notice\":\"how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------\"},\"setMocVendorAccount(address)\":{\"notice\":\"Set MoC registered Vendor account to receive markup fees https://docs.moneyonchain.com/main-rbtc-contract/integration-with-moc-platform/vendors\"}},\"notice\":\"This contract provides compound functions with Money On Chain wrapping them in one transaction for convenience and to save on gas\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/integration/MoC/MocIntegration.sol\":\"MocIntegration\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/ContextUpgradeable.sol\\\";\\nimport \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n function __Ownable_init() internal onlyInitializing {\\n __Ownable_init_unchained();\\n }\\n\\n function __Ownable_init_unchained() internal onlyInitializing {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n\\n /**\\n * @dev This empty reserved space is put in place to allow future versions to add new\\n * variables without shifting down storage in the inheritance chain.\\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n */\\n uint256[49] private __gap;\\n}\\n\",\"keccak256\":\"0x247c62047745915c0af6b955470a72d1696ebad4352d7d3011aef1a2463cd888\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/interfaces/IERC1967Upgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.3) (interfaces/IERC1967.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.\\n *\\n * _Available since v4.9._\\n */\\ninterface IERC1967Upgradeable {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Emitted when the admin account has changed.\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @dev Emitted when the beacon is changed.\\n */\\n event BeaconUpgraded(address indexed beacon);\\n}\\n\",\"keccak256\":\"0xb8d68221343ed784c7b76edb6a686cb65e49c476d9e22bb89a5c0c3947ff14db\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/interfaces/draft-IERC1822Upgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\\n * proxy whose upgrades are fully controlled by the current implementation.\\n */\\ninterface IERC1822ProxiableUpgradeable {\\n /**\\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\\n * address.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy.\\n */\\n function proxiableUUID() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x77c89f893e403efc6929ba842b7ccf6534d4ffe03afe31670b4a528c0ad78c0f\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.3) (proxy/ERC1967/ERC1967Upgrade.sol)\\n\\npragma solidity ^0.8.2;\\n\\nimport \\\"../beacon/IBeaconUpgradeable.sol\\\";\\nimport \\\"../../interfaces/IERC1967Upgradeable.sol\\\";\\nimport \\\"../../interfaces/draft-IERC1822Upgradeable.sol\\\";\\nimport \\\"../../utils/AddressUpgradeable.sol\\\";\\nimport \\\"../../utils/StorageSlotUpgradeable.sol\\\";\\nimport \\\"../utils/Initializable.sol\\\";\\n\\n/**\\n * @dev This abstract contract provides getters and event emitting update functions for\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\\n *\\n * _Available since v4.1._\\n *\\n * @custom:oz-upgrades-unsafe-allow delegatecall\\n */\\nabstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable {\\n function __ERC1967Upgrade_init() internal onlyInitializing {\\n }\\n\\n function __ERC1967Upgrade_init_unchained() internal onlyInitializing {\\n }\\n // This is the keccak-256 hash of \\\"eip1967.proxy.rollback\\\" subtracted by 1\\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _getImplementation() internal view returns (address) {\\n return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 implementation slot.\\n */\\n function _setImplementation(address newImplementation) private {\\n require(AddressUpgradeable.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n }\\n\\n /**\\n * @dev Perform implementation upgrade\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCall(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _upgradeTo(newImplementation);\\n if (data.length > 0 || forceCall) {\\n _functionDelegateCall(newImplementation, data);\\n }\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCallUUPS(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n // Upgrades from old implementations will perform a rollback test. This test requires the new\\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\\n // this special case will break upgrade paths from old UUPS implementation to new ones.\\n if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {\\n _setImplementation(newImplementation);\\n } else {\\n try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n require(slot == _IMPLEMENTATION_SLOT, \\\"ERC1967Upgrade: unsupported proxiableUUID\\\");\\n } catch {\\n revert(\\\"ERC1967Upgrade: new implementation is not UUPS\\\");\\n }\\n _upgradeToAndCall(newImplementation, data, forceCall);\\n }\\n }\\n\\n /**\\n * @dev Storage slot with the admin of the contract.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.admin\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _getAdmin() internal view returns (address) {\\n return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 admin slot.\\n */\\n function _setAdmin(address newAdmin) private {\\n require(newAdmin != address(0), \\\"ERC1967: new admin is the zero address\\\");\\n StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n */\\n function _changeAdmin(address newAdmin) internal {\\n emit AdminChanged(_getAdmin(), newAdmin);\\n _setAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\\n */\\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\\n\\n /**\\n * @dev Returns the current beacon.\\n */\\n function _getBeacon() internal view returns (address) {\\n return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new beacon in the EIP1967 beacon slot.\\n */\\n function _setBeacon(address newBeacon) private {\\n require(AddressUpgradeable.isContract(newBeacon), \\\"ERC1967: new beacon is not a contract\\\");\\n require(\\n AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),\\n \\\"ERC1967: beacon implementation is not a contract\\\"\\n );\\n StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;\\n }\\n\\n /**\\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\\n *\\n * Emits a {BeaconUpgraded} event.\\n */\\n function _upgradeBeaconToAndCall(\\n address newBeacon,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _setBeacon(newBeacon);\\n emit BeaconUpgraded(newBeacon);\\n if (data.length > 0 || forceCall) {\\n _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);\\n }\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {\\n require(AddressUpgradeable.isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return AddressUpgradeable.verifyCallResult(success, returndata, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev This empty reserved space is put in place to allow future versions to add new\\n * variables without shifting down storage in the inheritance chain.\\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n */\\n uint256[50] private __gap;\\n}\\n\",\"keccak256\":\"0x1599637b52d20dc3954cea44914b2a4a9a8a5caade58d9da947e0b6c9acc07ba\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\\n */\\ninterface IBeaconUpgradeable {\\n /**\\n * @dev Must return an address that can be used as a delegate call target.\\n *\\n * {BeaconProxy} will check that this address is a contract.\\n */\\n function implementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0x24b86ac8c005b8c654fbf6ac34a5a4f61580d7273541e83e013e89d66fbf0908\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)\\n\\npragma solidity ^0.8.2;\\n\\nimport \\\"../../utils/AddressUpgradeable.sol\\\";\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n * ====\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n * @custom:oz-retyped-from bool\\n */\\n uint8 private _initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private _initializing;\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint8 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\\n * constructor.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n bool isTopLevelCall = !_initializing;\\n require(\\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n _initialized = 1;\\n if (isTopLevelCall) {\\n _initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n _initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: setting the version to 255 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint8 version) {\\n require(!_initializing && _initialized < version, \\\"Initializable: contract is already initialized\\\");\\n _initialized = version;\\n _initializing = true;\\n _;\\n _initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n require(_initializing, \\\"Initializable: contract is not initializing\\\");\\n _;\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n require(!_initializing, \\\"Initializable: contract is initializing\\\");\\n if (_initialized < type(uint8).max) {\\n _initialized = type(uint8).max;\\n emit Initialized(type(uint8).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint8) {\\n return _initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _initializing;\\n }\\n}\\n\",\"keccak256\":\"0x037c334add4b033ad3493038c25be1682d78c00992e1acb0e2795caff3925271\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary AddressUpgradeable {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2edcb41c121abc510932e8d83ff8b82cf9cdde35e7c297622f5c29ef0af25183\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\nimport \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract ContextUpgradeable is Initializable {\\n function __Context_init() internal onlyInitializing {\\n }\\n\\n function __Context_init_unchained() internal onlyInitializing {\\n }\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n\\n /**\\n * @dev This empty reserved space is put in place to allow future versions to add new\\n * variables without shifting down storage in the inheritance chain.\\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n */\\n uint256[50] private __gap;\\n}\\n\",\"keccak256\":\"0x963ea7f0b48b032eef72fe3a7582edf78408d6f834115b9feadd673a4d5bd149\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/StorageSlotUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for reading and writing primitive types to specific storage slots.\\n *\\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\\n * This library helps with reading and writing to such slots without the need for inline assembly.\\n *\\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\\n *\\n * Example usage to set ERC1967 implementation slot:\\n * ```\\n * contract ERC1967 {\\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n *\\n * function _getImplementation() internal view returns (address) {\\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n * }\\n *\\n * function _setImplementation(address newImplementation) internal {\\n * require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n * }\\n * }\\n * ```\\n *\\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\\n */\\nlibrary StorageSlotUpgradeable {\\n struct AddressSlot {\\n address value;\\n }\\n\\n struct BooleanSlot {\\n bool value;\\n }\\n\\n struct Bytes32Slot {\\n bytes32 value;\\n }\\n\\n struct Uint256Slot {\\n uint256 value;\\n }\\n\\n /**\\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\\n */\\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\\n */\\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\\n */\\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\\n */\\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n}\\n\",\"keccak256\":\"0x09864aea84f01e39313375b5610c73a3c1c68abbdc51e5ccdd25ff977fdadf9a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x4ffc0547c02ad22925310c585c0f166f8759e2648a09e9b489100c42f15dd98d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./draft-IERC20Permit.sol\\\";\\nimport \\\"../ERC20.sol\\\";\\nimport \\\"../../../utils/cryptography/ECDSA.sol\\\";\\nimport \\\"../../../utils/cryptography/EIP712.sol\\\";\\nimport \\\"../../../utils/Counters.sol\\\";\\n\\n/**\\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n *\\n * _Available since v3.4._\\n */\\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\\n using Counters for Counters.Counter;\\n\\n mapping(address => Counters.Counter) private _nonces;\\n\\n // solhint-disable-next-line var-name-mixedcase\\n bytes32 private constant _PERMIT_TYPEHASH =\\n keccak256(\\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\");\\n /**\\n * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.\\n * However, to ensure consistency with the upgradeable transpiler, we will continue\\n * to reserve a slot.\\n * @custom:oz-renamed-from _PERMIT_TYPEHASH\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;\\n\\n /**\\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\\\"1\\\"`.\\n *\\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\\n */\\n constructor(string memory name) EIP712(name, \\\"1\\\") {}\\n\\n /**\\n * @dev See {IERC20Permit-permit}.\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public virtual override {\\n require(block.timestamp <= deadline, \\\"ERC20Permit: expired deadline\\\");\\n\\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\\n\\n bytes32 hash = _hashTypedDataV4(structHash);\\n\\n address signer = ECDSA.recover(hash, v, r, s);\\n require(signer == owner, \\\"ERC20Permit: invalid signature\\\");\\n\\n _approve(owner, spender, value);\\n }\\n\\n /**\\n * @dev See {IERC20Permit-nonces}.\\n */\\n function nonces(address owner) public view virtual override returns (uint256) {\\n return _nonces[owner].current();\\n }\\n\\n /**\\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\\n return _domainSeparatorV4();\\n }\\n\\n /**\\n * @dev \\\"Consume a nonce\\\": return the current value and increment.\\n *\\n * _Available since v4.1._\\n */\\n function _useNonce(address owner) internal virtual returns (uint256 current) {\\n Counters.Counter storage nonce = _nonces[owner];\\n current = nonce.current();\\n nonce.increment();\\n }\\n}\\n\",\"keccak256\":\"0xd2dd6003a2dc02ab905fd405938322e510429d19ae6c07c2c683d70f13ab2f36\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Counters.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Counters\\n * @author Matt Condon (@shrugs)\\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\\n *\\n * Include with `using Counters for Counters.Counter;`\\n */\\nlibrary Counters {\\n struct Counter {\\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\\n // this feature: see https://github.com/ethereum/solidity/issues/4637\\n uint256 _value; // default: 0\\n }\\n\\n function current(Counter storage counter) internal view returns (uint256) {\\n return counter._value;\\n }\\n\\n function increment(Counter storage counter) internal {\\n unchecked {\\n counter._value += 1;\\n }\\n }\\n\\n function decrement(Counter storage counter) internal {\\n uint256 value = counter._value;\\n require(value > 0, \\\"Counter: decrement overflow\\\");\\n unchecked {\\n counter._value = value - 1;\\n }\\n }\\n\\n function reset(Counter storage counter) internal {\\n counter._value = 0;\\n }\\n}\\n\",\"keccak256\":\"0xf0018c2440fbe238dd3a8732fa8e17a0f9dce84d31451dc8a32f6d62b349c9f1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./math/Math.sol\\\";\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n uint256 length = Math.log10(value) + 1;\\n string memory buffer = new string(length);\\n uint256 ptr;\\n /// @solidity memory-safe-assembly\\n assembly {\\n ptr := add(buffer, add(32, length))\\n }\\n while (true) {\\n ptr--;\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\\n }\\n value /= 10;\\n if (value == 0) break;\\n }\\n return buffer;\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n return toHexString(value, Math.log256(value) + 1);\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xa4d1d62251f8574deb032a35fc948386a9b4de74b812d4f545a1ac120486b48a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV // Deprecated in v4.8\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xda898fa084aa1ddfdb346e6a40459e00a59d87071cce7c315a46d648dd71d0ba\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/EIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./ECDSA.sol\\\";\\n\\n/**\\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\\n *\\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\\n *\\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\\n * ({_hashTypedDataV4}).\\n *\\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\\n * the chain id to protect against replay attacks on an eventual fork of the chain.\\n *\\n * NOTE: This contract implements the version of the encoding known as \\\"v4\\\", as implemented by the JSON RPC method\\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\\n *\\n * _Available since v3.4._\\n */\\nabstract contract EIP712 {\\n /* solhint-disable var-name-mixedcase */\\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\\n // invalidate the cached domain separator if the chain id changes.\\n bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\\n uint256 private immutable _CACHED_CHAIN_ID;\\n address private immutable _CACHED_THIS;\\n\\n bytes32 private immutable _HASHED_NAME;\\n bytes32 private immutable _HASHED_VERSION;\\n bytes32 private immutable _TYPE_HASH;\\n\\n /* solhint-enable var-name-mixedcase */\\n\\n /**\\n * @dev Initializes the domain separator and parameter caches.\\n *\\n * The meaning of `name` and `version` is specified in\\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\\n *\\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\\n * - `version`: the current major version of the signing domain.\\n *\\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\\n * contract upgrade].\\n */\\n constructor(string memory name, string memory version) {\\n bytes32 hashedName = keccak256(bytes(name));\\n bytes32 hashedVersion = keccak256(bytes(version));\\n bytes32 typeHash = keccak256(\\n \\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"\\n );\\n _HASHED_NAME = hashedName;\\n _HASHED_VERSION = hashedVersion;\\n _CACHED_CHAIN_ID = block.chainid;\\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\\n _CACHED_THIS = address(this);\\n _TYPE_HASH = typeHash;\\n }\\n\\n /**\\n * @dev Returns the domain separator for the current chain.\\n */\\n function _domainSeparatorV4() internal view returns (bytes32) {\\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\\n return _CACHED_DOMAIN_SEPARATOR;\\n } else {\\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\\n }\\n }\\n\\n function _buildDomainSeparator(\\n bytes32 typeHash,\\n bytes32 nameHash,\\n bytes32 versionHash\\n ) private view returns (bytes32) {\\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\\n }\\n\\n /**\\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\\n * function returns the hash of the fully encoded EIP712 message for this domain.\\n *\\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\\n *\\n * ```solidity\\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\\n * keccak256(\\\"Mail(address to,string contents)\\\"),\\n * mailTo,\\n * keccak256(bytes(mailContents))\\n * )));\\n * address signer = ECDSA.recover(digest, signature);\\n * ```\\n */\\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\\n }\\n}\\n\",\"keccak256\":\"0x948d8b2d18f38141ec78c5229d770d950ebc781ed3f44cc9e3ccbb9fded5846a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa1e8e83cd0087785df04ac79fb395d9f3684caeaf973d9e2c71caef723a3a5d6\",\"license\":\"MIT\"},\"contracts/integration/MoC/IMoC.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\n/// Interface to the Money OnChain main contract MoC to mint DoC and redeem RBTC\\ninterface IMocMintRedeemDoc {\\n /**\\n @dev Returns the total amount of Docs in the redeem queue for redeemer\\n @param redeemer address for which ^ is computed\\n @return total amount of Docs in the redeem queue for redeemer\\n */\\n function docAmountToRedeem(address redeemer) external view returns (uint256);\\n\\n /**\\n * @dev Creates or updates the amount of a Doc redeem Request from the msg.sender\\n * @param docAmount Amount of Docs to redeem on settlement [using mocPrecision]\\n */\\n function redeemDocRequest(uint256 docAmount) external;\\n\\n /**\\n @dev Alters the redeem amount position for the redeemer\\n @param isAddition true if adding amount to redeem, false to substract.\\n @param delta the amount to add/substract to current position\\n */\\n function alterRedeemRequestAmount(bool isAddition, uint256 delta) external;\\n\\n /**\\n @dev Mint Doc tokens and pays the commisions of the operation (retrocompatible function).\\n @dev Retrocompatible function.\\n @param btcToMint Amount in RBTC to mint\\n */\\n function mintDoc(uint256 btcToMint) external payable;\\n\\n /**\\n * @dev Mint Doc tokens and pays the commisions of the operation\\n * @param btcToMint Amount in RBTC to mint\\n * @param vendorAccount Vendor address\\n */\\n function mintDocVendors(uint256 btcToMint, address payable vendorAccount) external payable;\\n\\n /**\\n @dev Redeems the requested amount for the msg.sender, or the max amount of free docs possible (retrocompatible function).\\n @dev Retrocompatible function.\\n @param docAmount Amount of Docs to redeem.\\n */\\n function redeemFreeDoc(uint256 docAmount) external;\\n\\n /**\\n @dev Redeems the requested amount for the msg.sender, or the max amount of free docs possible.\\n @param docAmount Amount of Docs to redeem.\\n @param vendorAccount Vendor address\\n */\\n function redeemFreeDocVendors(uint256 docAmount, address payable vendorAccount) external;\\n\\n /**\\n @dev Allow redeem on liquidation state, user DoCs get burned and he receives\\n the equivalent BTCs if can be covered, or the maximum available\\n */\\n function redeemAllDoc() external;\\n}\\n\\n/// An aggregating interface\\ninterface IMoC is IMocMintRedeemDoc {\\n\\n}\\n\",\"keccak256\":\"0xc571f8c743be8c85e8d570ec0378abef85ffc676e58a6fd3861501689721f944\",\"license\":\"MIT\"},\"contracts/integration/MoC/MocIntegration.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\nimport \\\"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\\\";\\nimport \\\"@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol\\\";\\nimport { IMocMintRedeemDoc } from \\\"./IMoC.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Counters.sol\\\";\\nimport \\\"../../meta-asset-token/DLLR.sol\\\";\\nimport \\\"../../interfaces/IMassetManager.sol\\\";\\nimport { IDLLR, PermitParams } from \\\"../../interfaces/IDLLR.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"../../permit2/interfaces/IPermit2.sol\\\";\\n\\n/// @notice This contract provides compound functions with Money On Chain wrapping them in one transaction for convenience and to save on gas\\ncontract MocIntegration is OwnableUpgradeable, ERC1967UpgradeUpgradeable {\\n using Counters for Counters.Counter;\\n // Money On Chain DoC redeem interface at MoC main contract address\\n IMocMintRedeemDoc public immutable moc;\\n // IERC20@[DoC token]\\n IERC20 public immutable doc;\\n IDLLR public immutable dllr;\\n IMassetManager public immutable massetManager;\\n\\n address public mocVendorAccount;\\n\\n IPermit2 public immutable permit2;\\n\\n event GetDocFromDllrAndRedeemRBTC(address indexed from, uint256 fromDLLR, uint256 toRBTC);\\n event MocVendorAccountSet(address newMocVendorAccount);\\n\\n /**\\n * @param _moc MoC main contract address\\n * @param _doc DoC contract address\\n * @param _dllr DLLR contract address\\n * @param _massetManager MassetManager contract address\\n */\\n constructor(\\n address _moc,\\n address _doc,\\n address _dllr,\\n address _massetManager,\\n address _permit2\\n ) {\\n require(\\n _moc != address(0) &&\\n _doc != address(0) &&\\n _dllr != address(0) &&\\n _massetManager != address(0) &&\\n _permit2 != address(0),\\n \\\"MocIntegration:: no null addresses allowed\\\"\\n );\\n moc = IMocMintRedeemDoc(_moc);\\n doc = IERC20(_doc);\\n dllr = IDLLR(_dllr);\\n massetManager = IMassetManager(_massetManager);\\n permit2 = IPermit2(_permit2);\\n }\\n\\n function initialize(address payable _mocVendorAccount) external initializer {\\n __Ownable_init();\\n _setMocVendorAccount(_mocVendorAccount);\\n }\\n\\n ///@dev the contract requires receiving funds temporarily before transferring them to users\\n receive() external payable {}\\n\\n /**\\n * @notice how getDocFromDllrAndRedeemRBTC function works:\\n * -------------------------------------------------------------------------------------------\\n * | Mynt | Money On Chain |\\n * -------------------------------------------------------------------------------------------\\n * | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user |\\n * -------------------------------------------------------------------------------------------\\n *\\n * @param _dllrAmount The amount of the DLLR (mAsset) that will be burned in exchange for _toToken\\n * @param _permitParams EIP-2612 permit params:\\n * _deadline Expiration time of the signature.\\n * _v Last 1 byte of ECDSA signature.\\n * _r First 32 bytes of ECDSA signature.\\n * _s 32 bytes after _r in ECDSA signature.\\n */\\n function getDocFromDllrAndRedeemRBTC(\\n uint256 _dllrAmount,\\n PermitParams calldata _permitParams\\n ) external {\\n // transfer _dllrAmount to this contract by permit (EIP-2612)\\n address thisAddress = address(this);\\n dllr.transferWithPermit(\\n msg.sender,\\n thisAddress,\\n _dllrAmount,\\n _permitParams.deadline,\\n _permitParams.v,\\n _permitParams.r,\\n _permitParams.s\\n );\\n\\n // redeem DoC from DLLR\\n require(\\n massetManager.redeemTo(address(doc), _dllrAmount, thisAddress) == _dllrAmount,\\n \\\"MocIntegration:: redeemed incorrect DoC amount\\\"\\n );\\n\\n // redeem RBTC from DoC using Money On Chain and send to the user\\n uint256 rbtcBalanceBefore = thisAddress.balance;\\n moc.redeemFreeDocVendors(_dllrAmount, payable(mocVendorAccount));\\n uint256 rbtcAmount = thisAddress.balance - rbtcBalanceBefore;\\n (bool success, ) = msg.sender.call{ value: rbtcAmount }(\\\"\\\");\\n require(success, \\\"MocIntegration:: error transferring redeemed RBTC\\\");\\n\\n emit GetDocFromDllrAndRedeemRBTC(msg.sender, _dllrAmount, rbtcAmount);\\n }\\n\\n /**\\n * @notice how getDocFromDllrAndRedeemRBTC function works:\\n * -------------------------------------------------------------------------------------------\\n * | Mynt | Money On Chain |\\n * -------------------------------------------------------------------------------------------\\n * | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user |\\n * -------------------------------------------------------------------------------------------\\n *\\n * @param permit permit data, in form of PermitTransferFrom struct.\\n * @param signature of the permit data.\\n */\\n function getDocFromDllrAndRedeemRbtcWithPermit2(\\n ISignatureTransfer.PermitTransferFrom memory permit,\\n bytes memory signature\\n ) external {\\n address thisAddress = address(this);\\n uint256 _dllrAmount = permit.permitted.amount;\\n\\n ISignatureTransfer.SignatureTransferDetails\\n memory transferDetails = _generateTransferDetails(thisAddress, _dllrAmount);\\n\\n permit2.permitTransferFrom(permit, transferDetails, msg.sender, signature);\\n\\n // redeem DoC from DLLR\\n require(\\n massetManager.redeemTo(address(doc), _dllrAmount, thisAddress) == _dllrAmount,\\n \\\"MocIntegration:: redeemed incorrect DoC amount\\\"\\n );\\n\\n // redeem RBTC from DoC using Money On Chain and send to the user\\n uint256 rbtcBalanceBefore = thisAddress.balance;\\n moc.redeemFreeDocVendors(_dllrAmount, payable(mocVendorAccount));\\n uint256 rbtcAmount = thisAddress.balance - rbtcBalanceBefore;\\n (bool success, ) = msg.sender.call{ value: rbtcAmount }(\\\"\\\");\\n require(success, \\\"MocIntegration:: error transferring redeemed RBTC\\\");\\n\\n emit GetDocFromDllrAndRedeemRBTC(msg.sender, _dllrAmount, rbtcAmount);\\n }\\n\\n /// Set MoC registered Vendor account to receive markup fees https://docs.moneyonchain.com/main-rbtc-contract/integration-with-moc-platform/vendors\\n function setMocVendorAccount(address payable newMocVedorAccount) external onlyOwner {\\n _setMocVendorAccount(newMocVedorAccount);\\n }\\n\\n function _setMocVendorAccount(address newMocVedorAccount) internal {\\n mocVendorAccount = newMocVedorAccount;\\n emit MocVendorAccountSet(mocVendorAccount);\\n }\\n\\n /**\\n * @dev get the implementation logic address referring to ERC1967 standard.\\n *\\n * @return logic implementation address.\\n */\\n function getProxyImplementation() external view returns (address) {\\n return ERC1967UpgradeUpgradeable._getImplementation();\\n }\\n\\n /**\\n * @dev view function to construct SignatureTransferDetails struct to be used by Permit2\\n *\\n * @param _to ultimate recipient\\n * @param _amount amount of transfer\\n *\\n * @return SignatureTransferDetails struct object\\n */\\n function _generateTransferDetails(\\n address _to,\\n uint256 _amount\\n ) private pure returns (ISignatureTransfer.SignatureTransferDetails memory) {\\n ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer\\n .SignatureTransferDetails({ to: _to, requestedAmount: _amount });\\n\\n return transferDetails;\\n }\\n}\\n\",\"keccak256\":\"0x5369b9bbb3e887e5d93413aed76f45df17085f6ee9d8f4826ab35c239f7a5539\",\"license\":\"MIT\"},\"contracts/interfaces/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\n/**\\n * @title Interface for contract governance/ApprovalReceiver.sol\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n */\\ninterface IApproveAndCall {\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _sender The sender of SOV.approveAndCall function.\\n * @param _amount The amount was approved.\\n * @param _token The address of token.\\n * @param _data The data will be used for low level call.\\n * */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x0dd8105c56c42841b136acb14c8058f7802800727d76daf708ec67f614f8f7f3\",\"license\":\"MIT\"},\"contracts/interfaces/IDLLR.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @dev Permit params (EIP-2612) wrapper struct\\n */\\nstruct PermitParams {\\n uint256 deadline;\\n uint8 v;\\n bytes32 r;\\n bytes32 s;\\n}\\n\\n/**\\n * @title DLLR mAsset interface.\\n * @dev mAsset - Meta Asset Token implementation.\\n * Inherits from ERC20.\\n * mint and burn functions.\\n */\\ninterface IDLLR is IERC20 {\\n // events\\n\\n /**\\n * @dev Emitted when MassetManager config is changed.\\n * @param _newMassetManagerProxy Address of new MassetManager proxy.\\n */\\n event MassetManagerProxyChanged(address indexed _newMassetManagerProxy);\\n\\n /**\\n * @dev Emitted when Basket Manager config is changed.\\n * @param _newBasketManagerProxy Address of new Basket Manager proxy.\\n */\\n event BasketManagerProxyChanged(address indexed _newBasketManagerProxy);\\n\\n /**\\n * @dev getter function of MassetManager implementation address\\n *\\n * @return MassetManager implementation address\\n */\\n function massetManagerImplementation() external view returns (address);\\n\\n /**\\n * @dev getter function of basket manager implementation address\\n *\\n * @return basket manager implementation address\\n */\\n function basketManagerImplementation() external view returns (address);\\n\\n /**\\n * @notice setMassetManagerProxy sets the MassetManager proxy address\\n * @param _massetManagerProxy The address of the MassetManager proxy contract\\n */\\n function setMassetManagerProxy(address _massetManagerProxy) external;\\n\\n /**\\n * @notice setBasketManagerConfig sets the Basket Manager proxy address\\n * @param _basketManagerProxy The address of the Basket Manager proxy contract\\n */\\n function setBasketManagerProxy(address _basketManagerProxy) external;\\n\\n /**\\n * @notice Creates new tokens and sends them to the recipient.\\n * @notice Can be minted only by the MassetManager proxy contract.\\n *\\n * @param _account The recipient address to get the minted tokens.\\n * @param _amount The amount of tokens to be minted.\\n */\\n function mint(address _account, uint256 _amount) external;\\n\\n /**\\n * @notice Burns tokens for the given account.\\n * @notice Can be burned only by the MassetManager proxy contract.\\n *\\n * @param _account The recipient address to get the minted tokens.\\n * @param _amount The amount of tokens to be minted.\\n */\\n function burn(address _account, uint256 _amount) external;\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _recipient Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transfer(address _recipient, uint256 _amount) external returns (bool);\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transferFrom(address _from, address _to, uint256 _amount) external returns (bool);\\n\\n /**\\n * @notice transfer utilizing EIP-2612, to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @dev By calling this function, the allowance will be overwritten by the total amount.\\n *\\n * @param _from Owner of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of the token that will be transferred.\\n * @param _deadline Expiration time of the signature.\\n * @param _v Last 1 byte of ECDSA signature.\\n * @param _r First 32 bytes of ECDSA signature.\\n * @param _s 32 bytes after _r in ECDSA signature.\\n */\\n function transferWithPermit(\\n address _from,\\n address _to,\\n uint256 _amount,\\n uint256 _deadline,\\n uint8 _v,\\n bytes32 _r,\\n bytes32 _s\\n ) external;\\n\\n /**\\n * @notice Approves and then calls the receiving contract.\\n * Useful to encapsulate sending tokens to a contract in one call.\\n * Solidity has no native way to send tokens to contracts.\\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\\n * @param _spender The contract address to spend the tokens.\\n * @param _amount The amount of tokens to be sent.\\n * @param _data Parameters for the contract call, such as endpoint signature.\\n */\\n function approveAndCall(address _spender, uint256 _amount, bytes calldata _data) external;\\n\\n /**\\n * @dev to support EIP712, will need the token contract to return the chain id.\\n *\\n * @return chain id.\\n *\\n */\\n function getChainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x34068131b6d47697cdf66239fe8f28b191afe6e13b5d145a39e7c93c8a092a01\",\"license\":\"MIT\"},\"contracts/interfaces/IMassetManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\n/**\\n * @title MassetManager\\n * @dev Contract is responsible for managing mAsset and bAsset.\\n * Used for minting and burning tokens and calculating fees\\n * if transaction based on token from another blockchain.\\n */\\n\\ninterface IMassetManager {\\n // events\\n\\n /**\\n * @dev Emitted when deposit is completed.\\n * @param minter Address of the minter.\\n * @param recipient Address of the recipient.\\n * @param massetQuantity Masset quantity.\\n * @param bAsset Address of the bAsset.\\n * @param bassetQuantity Basset quantity.\\n */\\n event Minted(\\n address indexed minter,\\n address indexed recipient,\\n uint256 massetQuantity,\\n address bAsset,\\n uint256 bassetQuantity\\n );\\n\\n /**\\n * @dev Emitted when withdrawal is completed.\\n * @param redeemer Address of the redeemer.\\n * @param recipient Address of the recipient.\\n * @param massetQuantity Masset quantity.\\n * @param bAsset Address of the bAsset.\\n * @param bassetQuantity Basset quantity.\\n */\\n event Redeemed(\\n address indexed redeemer,\\n address indexed recipient,\\n uint256 massetQuantity,\\n address bAsset,\\n uint256 bassetQuantity\\n );\\n\\n /***************************************\\n MINTING (PUBLIC)\\n ****************************************/\\n\\n /**\\n * @dev Mint a single mAsset, at a 1:1 ratio with the bAsset. This contract\\n * must have approval to spend the senders bAsset.\\n * @param _bAsset Address of the bAsset.\\n * @param _bAssetQuantity Quantity in bAsset units.\\n * @return massetMinted Quantity of newly minted mAsset.\\n */\\n function mint(\\n address _bAsset,\\n uint256 _bAssetQuantity\\n ) external returns (uint256 massetMinted);\\n\\n /**\\n * @dev Mint a single mAsset to recipient address, at a 1:1 ratio with the bAsset.\\n * This contract must have approval to spend the senders bAsset.\\n * @param _bAsset Address of the bAsset.\\n * @param _bAssetQuantity Quantity in bAsset units.\\n * @param _recipient Receipient of the newly minted mAsset tokens.\\n * @return massetMinted Number of newly minted mAssets.\\n */\\n function mintTo(\\n address _bAsset,\\n uint256 _bAssetQuantity,\\n address _recipient\\n ) external returns (uint256 massetMinted);\\n\\n /***************************************\\n REDEMPTION (PUBLIC)\\n ****************************************/\\n\\n /**\\n * @dev Credits the sender with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small mAsset fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeem(\\n address _bAsset,\\n uint256 _massetQuantity\\n ) external returns (uint256 massetRedeemed);\\n\\n /**\\n * @dev Credits a recipient with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @param _recipient Address to credit with withdrawn bAssets.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeemTo(\\n address _bAsset,\\n uint256 _massetQuantity,\\n address _recipient\\n ) external returns (uint256 massetRedeemed);\\n\\n // Getters\\n\\n function getFeesVault() external view returns (address);\\n\\n function getFeesManager() external view returns (address);\\n\\n function getVersion() external view returns (string memory);\\n\\n function getToken() external view returns (address);\\n\\n function getBasketManager() external view returns (address);\\n\\n /**\\n * @dev get the implementation logic address referring to ERC1967 standard.\\n *\\n * @return logic implementation address.\\n */\\n function getProxyImplementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0xa1f03fbed78848636e091cf9558ad018306a099d58dec55738aee06f3dec432a\",\"license\":\"MIT\"},\"contracts/interfaces/IProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.17;\\n\\ninterface IProxy {\\n function getProxyImplementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0x5bf844214dbafb99a41cd0dff86537312cd3f20636dbb8d27cc91496fd808bc5\",\"license\":\"MIT\"},\"contracts/meta-asset-token/DLLR.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\nimport \\\"./MetaAssetToken.sol\\\";\\n\\ncontract DLLR is MetaAssetToken {\\n constructor() MetaAssetToken(\\\"Sovryn Dollar\\\", \\\"DLLR\\\") {}\\n}\\n\",\"keccak256\":\"0x38a864f85b864d9b413c67d789493690aca728ca555ac6d0a345a40ee5b1794f\",\"license\":\"MIT\"},\"contracts/meta-asset-token/MetaAssetToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol\\\";\\nimport \\\"../interfaces/IApproveAndCall.sol\\\";\\nimport \\\"../interfaces/IProxy.sol\\\";\\n\\n/**\\n * @title MetaAssetToken\\n * @dev mAsset - Meta Asset Token implementation.\\n * Inherits from ERC20.\\n * mint and burn functions.\\n */\\n\\ncontract MetaAssetToken is ERC20Permit, Ownable {\\n // events\\n\\n /**\\n * @dev Emitted when MassetManager config is changed.\\n * @param _newMassetManagerProxy Address of new MassetManager proxy.\\n */\\n event MassetManagerProxyChanged(address indexed _newMassetManagerProxy);\\n\\n /**\\n * @dev Emitted when Basket Manager config is changed.\\n * @param _newBasketManagerProxy Address of new Basket Manager proxy.\\n */\\n event BasketManagerProxyChanged(address indexed _newBasketManagerProxy);\\n\\n /**\\n * @dev Emitted when transfer Manager config is changed.\\n */\\n event TransferWithPermit(address _from, address _to, uint256 _amount);\\n\\n // state\\n\\n address public massetManagerProxy;\\n address public basketManagerProxy;\\n\\n // modifiers\\n modifier onlyMassetManagerProxy() {\\n require(msg.sender == massetManagerProxy, \\\"DLLR:unauthorized MassetManager proxy\\\");\\n _;\\n }\\n\\n modifier requireValidRecipient(address _recipient) {\\n require(\\n _recipient != address(0) && _recipient != address(this),\\n \\\"DLLR: Invalid address. Cannot transfer DLLR to the null address.\\\"\\n );\\n _;\\n }\\n\\n /**\\n * @notice Constructor called on deployment, initiates the contract.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _symbol\\n ) ERC20(_tokenName, _symbol) ERC20Permit(_tokenName) {}\\n\\n /**\\n * @dev getter function of MassetManager implementation address\\n *\\n * @return MassetManager implementation address\\n */\\n function massetManagerImplementation() public view virtual returns (address) {\\n return IProxy(massetManagerProxy).getProxyImplementation();\\n }\\n\\n /**\\n * @dev getter function of basket manager implementation address\\n *\\n * @return basket manager implementation address\\n */\\n function basketManagerImplementation() public view virtual returns (address) {\\n return IProxy(basketManagerProxy).getProxyImplementation();\\n }\\n\\n /**\\n * @notice setMassetManagerProxy sets the MassetManager proxy address\\n * @param _massetManagerProxy The address of the MassetManager proxy contract\\n */\\n function setMassetManagerProxy(address _massetManagerProxy) external onlyOwner {\\n require(_massetManagerProxy != address(0), \\\"invalid MassetManager proxy address\\\");\\n massetManagerProxy = _massetManagerProxy;\\n\\n emit MassetManagerProxyChanged(massetManagerProxy);\\n }\\n\\n /**\\n * @notice setBasketManagerConfig sets the Basket Manager proxy address\\n * @param _basketManagerProxy The address of the Basket Manager proxy contract\\n */\\n function setBasketManagerProxy(address _basketManagerProxy) external onlyOwner {\\n require(_basketManagerProxy != address(0), \\\"invalid address\\\");\\n basketManagerProxy = _basketManagerProxy;\\n emit BasketManagerProxyChanged(basketManagerProxy);\\n }\\n\\n /**\\n * @notice Creates new tokens and sends them to the recipient.\\n * @notice Can be minted only by the MassetManager proxy contract.\\n *\\n * @param _account The recipient address to get the minted tokens.\\n * @param _amount The amount of tokens to be minted.\\n */\\n function mint(address _account, uint256 _amount) external onlyMassetManagerProxy {\\n _mint(_account, _amount);\\n }\\n\\n /**\\n * @notice Burns tokens for the given account.\\n * @notice Can be burned only by the MassetManager proxy contract.\\n *\\n * @param _account The recipient address to get the minted tokens.\\n * @param _amount The amount of tokens to be minted.\\n */\\n function burn(address _account, uint256 _amount) external onlyMassetManagerProxy {\\n _burn(_account, _amount);\\n }\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _recipient Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transfer(\\n address _recipient,\\n uint256 _amount\\n ) public override requireValidRecipient(_recipient) returns (bool) {\\n _transfer(_msgSender(), _recipient, _amount);\\n return true;\\n }\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _amount\\n ) public override requireValidRecipient(_to) returns (bool) {\\n _approve(_from, msg.sender, allowance(_from, msg.sender) - _amount);\\n _transfer(_from, _to, _amount);\\n return true;\\n }\\n\\n /**\\n * @notice transfer utilizing EIP-2612, to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @dev By calling this function, the allowance will be overwritten by the total amount.\\n *\\n * @param _from Owner of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of the token that will be transferred.\\n * @param _deadline Expiration time of the signature.\\n * @param _v Last 1 byte of ECDSA signature.\\n * @param _r First 32 bytes of ECDSA signature.\\n * @param _s 32 bytes after _r in ECDSA signature.\\n */\\n function transferWithPermit(\\n address _from,\\n address _to,\\n uint256 _amount,\\n uint256 _deadline,\\n uint8 _v,\\n bytes32 _r,\\n bytes32 _s\\n ) external requireValidRecipient(_to) {\\n permit(_from, msg.sender, _amount, _deadline, _v, _r, _s);\\n require(\\n transferFrom(_from, _to, _amount),\\n \\\"MetaAssetToken::transferWithPermit: transfer failed\\\"\\n );\\n\\n emit TransferWithPermit(_from, _to, _amount);\\n }\\n\\n /**\\n * @notice Approves and then calls the receiving contract.\\n * Useful to encapsulate sending tokens to a contract in one call.\\n * Solidity has no native way to send tokens to contracts.\\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\\n * @param _spender The contract address to spend the tokens.\\n * @param _amount The amount of tokens to be sent.\\n * @param _data Parameters for the contract call, such as endpoint signature.\\n */\\n function approveAndCall(address _spender, uint256 _amount, bytes calldata _data) external {\\n approve(_spender, _amount);\\n IApproveAndCall(_spender).receiveApproval(msg.sender, _amount, address(this), _data);\\n }\\n\\n /**\\n * @dev to support EIP712, will need the token contract to return the chain id.\\n *\\n * @return chain id.\\n *\\n */\\n function getChainId() external view returns (uint256) {\\n return block.chainid;\\n }\\n}\\n\",\"keccak256\":\"0x887c09ca5cf835d67db8389c8f4ab4fc2689444bb5806370431e1a18900b66d7\",\"license\":\"MIT\"},\"contracts/permit2/interfaces/IAllowanceTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title AllowanceTransfer\\n/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface IAllowanceTransfer is IEIP712 {\\n /// @notice Thrown when an allowance on a token has expired.\\n /// @param deadline The timestamp at which the allowed amount is no longer valid\\n error AllowanceExpired(uint256 deadline);\\n\\n /// @notice Thrown when an allowance on a token has been depleted.\\n /// @param amount The maximum amount allowed\\n error InsufficientAllowance(uint256 amount);\\n\\n /// @notice Thrown when too many nonces are invalidated.\\n error ExcessiveInvalidation();\\n\\n /// @notice Emits an event when the owner successfully invalidates an ordered nonce.\\n event NonceInvalidation(\\n address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.\\n event Approval(\\n address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.\\n event Permit(\\n address indexed owner,\\n address indexed token,\\n address indexed spender,\\n uint160 amount,\\n uint48 expiration,\\n uint48 nonce\\n );\\n\\n /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.\\n event Lockdown(address indexed owner, address token, address spender);\\n\\n /// @notice The permit data for a token\\n struct PermitDetails {\\n // ERC20 token address\\n address token;\\n // the maximum amount allowed to spend\\n uint160 amount;\\n // timestamp at which a spender's token allowances become invalid\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice The permit message signed for a single token allowance\\n struct PermitSingle {\\n // the permit data for a single token alownce\\n PermitDetails details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The permit message signed for multiple token allowances\\n struct PermitBatch {\\n // the permit data for multiple token allowances\\n PermitDetails[] details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The saved permissions\\n /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n struct PackedAllowance {\\n // amount allowed\\n uint160 amount;\\n // permission expiry\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice A token spender pair.\\n struct TokenSpenderPair {\\n // the token the spender is approved\\n address token;\\n // the spender address\\n address spender;\\n }\\n\\n /// @notice Details for a token transfer.\\n struct AllowanceTransferDetails {\\n // the owner of the token\\n address from;\\n // the recipient of the token\\n address to;\\n // the amount of the token\\n uint160 amount;\\n // the token to be transferred\\n address token;\\n }\\n\\n /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.\\n /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]\\n /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.\\n function allowance(address user, address token, address spender)\\n external\\n view\\n returns (uint160 amount, uint48 expiration, uint48 nonce);\\n\\n /// @notice Approves the spender to use up to amount of the specified token up until the expiration\\n /// @param token The token to approve\\n /// @param spender The spender address to approve\\n /// @param amount The approved amount of the token\\n /// @param expiration The timestamp at which the approval is no longer valid\\n /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n function approve(address token, address spender, uint160 amount, uint48 expiration) external;\\n\\n /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitSingle Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;\\n\\n /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitBatch Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;\\n\\n /// @notice Transfer approved tokens from one address to another\\n /// @param from The address to transfer from\\n /// @param to The address of the recipient\\n /// @param amount The amount of the token to transfer\\n /// @param token The token address to transfer\\n /// @dev Requires the from address to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(address from, address to, uint160 amount, address token) external;\\n\\n /// @notice Transfer approved tokens in a batch\\n /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers\\n /// @dev Requires the from addresses to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;\\n\\n /// @notice Enables performing a \\\"lockdown\\\" of the sender's Permit2 identity\\n /// by batch revoking approvals\\n /// @param approvals Array of approvals to revoke.\\n function lockdown(TokenSpenderPair[] calldata approvals) external;\\n\\n /// @notice Invalidate nonces for a given (token, spender) pair\\n /// @param token The token to invalidate nonces for\\n /// @param spender The spender to invalidate nonces for\\n /// @param newNonce The new nonce to set. Invalidates all nonces less than it.\\n /// @dev Can't invalidate more than 2**16 nonces per transaction.\\n function invalidateNonces(address token, address spender, uint48 newNonce) external;\\n}\\n\",\"keccak256\":\"0x37f0ac203b6ef605c9533e1a739477e8e9dcea90710b40e645a367f8a21ace29\",\"license\":\"MIT\"},\"contracts/permit2/interfaces/IEIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IEIP712 {\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xfdccf2b9639070803cd0e4198427fb0df3cc452ca59bd3b8a0d957a9a4254138\",\"license\":\"MIT\"},\"contracts/permit2/interfaces/IPermit2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {ISignatureTransfer} from \\\"./ISignatureTransfer.sol\\\";\\nimport {IAllowanceTransfer} from \\\"./IAllowanceTransfer.sol\\\";\\n\\n/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer.\\n/// @dev Users must approve Permit2 before calling any of the transfer functions.\\ninterface IPermit2 is ISignatureTransfer, IAllowanceTransfer {\\n// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval.\\n}\\n\",\"keccak256\":\"0xaa631cc9f53e699301d94233007110a345e6779011def484e8dd97b8fe0af771\",\"license\":\"MIT\"},\"contracts/permit2/interfaces/ISignatureTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title SignatureTransfer\\n/// @notice Handles ERC20 token transfers through signature based actions\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface ISignatureTransfer is IEIP712 {\\n /// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount\\n /// @param maxAmount The maximum amount a spender can request to transfer\\n error InvalidAmount(uint256 maxAmount);\\n\\n /// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred\\n /// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred\\n error LengthMismatch();\\n\\n /// @notice Emits an event when the owner successfully invalidates an unordered nonce.\\n event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);\\n\\n /// @notice The token and amount details for a transfer signed in the permit transfer signature\\n struct TokenPermissions {\\n // ERC20 token address\\n address token;\\n // the maximum amount that can be spent\\n uint256 amount;\\n }\\n\\n /// @notice The signed permit message for a single token transfer\\n struct PermitTransferFrom {\\n TokenPermissions permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice Specifies the recipient address and amount for batched transfers.\\n /// @dev Recipients and amounts correspond to the index of the signed token permissions array.\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount.\\n struct SignatureTransferDetails {\\n // recipient address\\n address to;\\n // spender requested amount\\n uint256 requestedAmount;\\n }\\n\\n /// @notice Used to reconstruct the signed permit message for multiple token transfers\\n /// @dev Do not need to pass in spender address as it is required that it is msg.sender\\n /// @dev Note that a user still signs over a spender address\\n struct PermitBatchTransferFrom {\\n // the tokens and corresponding amounts permitted for a transfer\\n TokenPermissions[] permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection\\n /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order\\n /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce\\n /// @dev It returns a uint256 bitmap\\n /// @dev The index, or wordPosition is capped at type(uint248).max\\n function nonceBitmap(address, uint256) external view returns (uint256);\\n\\n /// @notice Transfers a token using a signed permit message\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails The spender's requested transfer details for the permitted token\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitTransferFrom memory permit,\\n SignatureTransferDetails calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Transfers multiple tokens using a signed permit message\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails Specifies the recipient and requested amount for the token transfer\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitBatchTransferFrom memory permit,\\n SignatureTransferDetails[] calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Invalidates the bits specified in mask for the bitmap at the word position\\n /// @dev The wordPos is maxed at type(uint248).max\\n /// @param wordPos A number to index the nonceBitmap at\\n /// @param mask A bitmap masked against msg.sender's current bitmap at the word position\\n function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;\\n}\\n\",\"keccak256\":\"0xaffef816ae65c11123e5ac0ae0e7bf73506635bf6004d1ae3b4deed8c1bc69bd\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6101206040523480156200001257600080fd5b50604051620012cd380380620012cd833981016040819052620000359162000140565b6001600160a01b038516158015906200005657506001600160a01b03841615155b80156200006b57506001600160a01b03831615155b80156200008057506001600160a01b03821615155b80156200009557506001600160a01b03811615155b620000f95760405162461bcd60e51b815260206004820152602a60248201527f4d6f63496e746567726174696f6e3a3a206e6f206e756c6c2061646472657373604482015269195cc8185b1b1bddd95960b21b606482015260840160405180910390fd5b6001600160a01b0394851660805292841660a05290831660c052821660e0521661010052620001b0565b80516001600160a01b03811681146200013b57600080fd5b919050565b600080600080600060a086880312156200015957600080fd5b620001648662000123565b9450620001746020870162000123565b9350620001846040870162000123565b9250620001946060870162000123565b9150620001a46080870162000123565b90509295509295909350565b60805160a05160c05160e051610100516110a16200022c6000396000818160ff015261069301526000818161027501528181610435015261074f01526000818161014f01526103220152600081816101ee015281816103fb01526107150152600081816101a5015281816104f7015261080801526110a16000f3fe6080604052600436106100e15760003560e01c806390e4b7201161007f578063c4d66de811610059578063c4d66de814610297578063e5085517146102b7578063f2fde38b146102d7578063fc176819146102f757600080fd5b806390e4b7201461022e5780639b2633ae14610243578063b5c89bab1461026357600080fd5b806353428253116100bb5780635342825314610193578063715018a6146101c75780637a0a3ac5146101dc5780638da5cb5b1461021057600080fd5b806312261ee7146100ed57806333c507ae1461013d578063460f2de11461017157600080fd5b366100e857005b600080fd5b3480156100f957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b34801561014957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561017d57600080fd5b5061019161018c366004610c64565b610317565b005b34801561019f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d357600080fd5b50610191610619565b3480156101e857600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561021c57600080fd5b506033546001600160a01b0316610121565b34801561023a57600080fd5b5061012161062d565b34801561024f57600080fd5b5061019161025e366004610d7d565b610665565b34801561026f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156102a357600080fd5b506101916102b2366004610e40565b61092c565b3480156102c357600080fd5b506101916102d2366004610e40565b610a47565b3480156102e357600080fd5b506101916102f2366004610e40565b610a5b565b34801561030357600080fd5b50609754610121906001600160a01b031681565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663605629d6338386863561035c6040890160208a01610e64565b604080516001600160e01b031960e089901b1681526001600160a01b0396871660048201529590941660248601526044850192909252606484015260ff16608483015285013560a4820152606085013560c482015260e401600060405180830381600087803b1580156103ce57600080fd5b505af11580156103e2573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820187905284811660448301528693507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af115801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a39190610e87565b146104c95760405162461bcd60e51b81526004016104c090610ea0565b60405180910390fd5b60975460405163b7aa53e760e01b8152600481018590526001600160a01b03918216602482015282821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561053b57600080fd5b505af115801561054f573d6000803e3d6000fd5b50505050600081836001600160a01b03163161056b9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146105b0576040519150601f19603f3d011682016040523d82523d6000602084013e6105b5565b606091505b50509050806105d65760405162461bcd60e51b81526004016104c090610f0f565b604080518781526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a2505050505050565b610621610ad1565b61062b6000610b2b565b565b60006106607f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b815160200151309060006106798383610b7d565b60405163187945bd60e11b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906330f28b7a906106ce908890859033908a90600401610f60565b600060405180830381600087803b1580156106e857600080fd5b505af11580156106fc573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820186905286811660448301528593507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af1158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd9190610e87565b146107da5760405162461bcd60e51b81526004016104c090610ea0565b60975460405163b7aa53e760e01b8152600481018490526001600160a01b03918216602482015284821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561084c57600080fd5b505af1158015610860573d6000803e3d6000fd5b50505050600081856001600160a01b03163161087c9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146108c1576040519150601f19603f3d011682016040523d82523d6000602084013e6108c6565b606091505b50509050806108e75760405162461bcd60e51b81526004016104c090610f0f565b604080518681526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a25050505050505050565b600054610100900460ff161580801561094c5750600054600160ff909116105b806109665750303b158015610966575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104c0565b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b6109f4610bb1565b6109fd82610be0565b8015610a43576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b610a4f610ad1565b610a5881610be0565b50565b610a63610ad1565b6001600160a01b038116610ac85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104c0565b610a5881610b2b565b6033546001600160a01b0316331461062b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104c0565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080518082018252600080825260209182015281518083019092526001600160a01b038416825281018290525b92915050565b600054610100900460ff16610bd85760405162461bcd60e51b81526004016104c090611020565b61062b610c34565b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527fc2a1feb9d65ecb31b0e93a520a66d19319929a2bf58046d92d762c04e7dd06c99060200160405180910390a150565b600054610100900460ff16610c5b5760405162461bcd60e51b81526004016104c090611020565b61062b33610b2b565b60008082840360a0811215610c7857600080fd5b833592506080601f1982011215610c8e57600080fd5b506020830190509250929050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610cd557610cd5610c9c565b60405290565b6001600160a01b0381168114610a5857600080fd5b600082601f830112610d0157600080fd5b813567ffffffffffffffff80821115610d1c57610d1c610c9c565b604051601f8301601f19908116603f01168101908282118183101715610d4457610d44610c9c565b81604052838152866020858801011115610d5d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008082840360a0811215610d9157600080fd5b6080811215610d9f57600080fd5b6040516060810167ffffffffffffffff8282108183111715610dc357610dc3610c9c565b816040526040841215610dd557600080fd5b610ddd610cb2565b935086359150610dec82610cdb565b8184526020870135602085015283835260408701356020840152606087013560408401528295506080870135935080841115610e2757600080fd5b505050610e3685828601610cf0565b9150509250929050565b600060208284031215610e5257600080fd5b8135610e5d81610cdb565b9392505050565b600060208284031215610e7657600080fd5b813560ff81168114610e5d57600080fd5b600060208284031215610e9957600080fd5b5051919050565b6020808252602e908201527f4d6f63496e746567726174696f6e3a3a2072656465656d656420696e636f727260408201526d1958dd08111bd0c8185b5bdd5b9d60921b606082015260800190565b81810381811115610bab57634e487b7160e01b600052601160045260246000fd5b60208082526031908201527f4d6f63496e746567726174696f6e3a3a206572726f72207472616e7366657272604082015270696e672072656465656d6564205242544360781b606082015260800190565b6000610100610f8383885180516001600160a01b03168252602090810151910152565b602080880151604085015260408801516060850152610fb8608085018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c085015260e0840182905284519184018290526000915b80831015610ff957858301820151858401610120015291810191610fda565b6101209250600083828701015282601f19601f830116860101935050505095945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220d0fcc7c15da2d0cf8a6f0df865b7535edea2c45483b951fb883a7a57908c9d0764736f6c63430008110033", + "deployedBytecode": "0x6080604052600436106100e15760003560e01c806390e4b7201161007f578063c4d66de811610059578063c4d66de814610297578063e5085517146102b7578063f2fde38b146102d7578063fc176819146102f757600080fd5b806390e4b7201461022e5780639b2633ae14610243578063b5c89bab1461026357600080fd5b806353428253116100bb5780635342825314610193578063715018a6146101c75780637a0a3ac5146101dc5780638da5cb5b1461021057600080fd5b806312261ee7146100ed57806333c507ae1461013d578063460f2de11461017157600080fd5b366100e857005b600080fd5b3480156100f957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b34801561014957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561017d57600080fd5b5061019161018c366004610c64565b610317565b005b34801561019f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d357600080fd5b50610191610619565b3480156101e857600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561021c57600080fd5b506033546001600160a01b0316610121565b34801561023a57600080fd5b5061012161062d565b34801561024f57600080fd5b5061019161025e366004610d7d565b610665565b34801561026f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156102a357600080fd5b506101916102b2366004610e40565b61092c565b3480156102c357600080fd5b506101916102d2366004610e40565b610a47565b3480156102e357600080fd5b506101916102f2366004610e40565b610a5b565b34801561030357600080fd5b50609754610121906001600160a01b031681565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663605629d6338386863561035c6040890160208a01610e64565b604080516001600160e01b031960e089901b1681526001600160a01b0396871660048201529590941660248601526044850192909252606484015260ff16608483015285013560a4820152606085013560c482015260e401600060405180830381600087803b1580156103ce57600080fd5b505af11580156103e2573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820187905284811660448301528693507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af115801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a39190610e87565b146104c95760405162461bcd60e51b81526004016104c090610ea0565b60405180910390fd5b60975460405163b7aa53e760e01b8152600481018590526001600160a01b03918216602482015282821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561053b57600080fd5b505af115801561054f573d6000803e3d6000fd5b50505050600081836001600160a01b03163161056b9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146105b0576040519150601f19603f3d011682016040523d82523d6000602084013e6105b5565b606091505b50509050806105d65760405162461bcd60e51b81526004016104c090610f0f565b604080518781526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a2505050505050565b610621610ad1565b61062b6000610b2b565b565b60006106607f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b815160200151309060006106798383610b7d565b60405163187945bd60e11b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906330f28b7a906106ce908890859033908a90600401610f60565b600060405180830381600087803b1580156106e857600080fd5b505af11580156106fc573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820186905286811660448301528593507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af1158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd9190610e87565b146107da5760405162461bcd60e51b81526004016104c090610ea0565b60975460405163b7aa53e760e01b8152600481018490526001600160a01b03918216602482015284821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561084c57600080fd5b505af1158015610860573d6000803e3d6000fd5b50505050600081856001600160a01b03163161087c9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146108c1576040519150601f19603f3d011682016040523d82523d6000602084013e6108c6565b606091505b50509050806108e75760405162461bcd60e51b81526004016104c090610f0f565b604080518681526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a25050505050505050565b600054610100900460ff161580801561094c5750600054600160ff909116105b806109665750303b158015610966575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104c0565b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b6109f4610bb1565b6109fd82610be0565b8015610a43576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b610a4f610ad1565b610a5881610be0565b50565b610a63610ad1565b6001600160a01b038116610ac85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104c0565b610a5881610b2b565b6033546001600160a01b0316331461062b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104c0565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080518082018252600080825260209182015281518083019092526001600160a01b038416825281018290525b92915050565b600054610100900460ff16610bd85760405162461bcd60e51b81526004016104c090611020565b61062b610c34565b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527fc2a1feb9d65ecb31b0e93a520a66d19319929a2bf58046d92d762c04e7dd06c99060200160405180910390a150565b600054610100900460ff16610c5b5760405162461bcd60e51b81526004016104c090611020565b61062b33610b2b565b60008082840360a0811215610c7857600080fd5b833592506080601f1982011215610c8e57600080fd5b506020830190509250929050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610cd557610cd5610c9c565b60405290565b6001600160a01b0381168114610a5857600080fd5b600082601f830112610d0157600080fd5b813567ffffffffffffffff80821115610d1c57610d1c610c9c565b604051601f8301601f19908116603f01168101908282118183101715610d4457610d44610c9c565b81604052838152866020858801011115610d5d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008082840360a0811215610d9157600080fd5b6080811215610d9f57600080fd5b6040516060810167ffffffffffffffff8282108183111715610dc357610dc3610c9c565b816040526040841215610dd557600080fd5b610ddd610cb2565b935086359150610dec82610cdb565b8184526020870135602085015283835260408701356020840152606087013560408401528295506080870135935080841115610e2757600080fd5b505050610e3685828601610cf0565b9150509250929050565b600060208284031215610e5257600080fd5b8135610e5d81610cdb565b9392505050565b600060208284031215610e7657600080fd5b813560ff81168114610e5d57600080fd5b600060208284031215610e9957600080fd5b5051919050565b6020808252602e908201527f4d6f63496e746567726174696f6e3a3a2072656465656d656420696e636f727260408201526d1958dd08111bd0c8185b5bdd5b9d60921b606082015260800190565b81810381811115610bab57634e487b7160e01b600052601160045260246000fd5b60208082526031908201527f4d6f63496e746567726174696f6e3a3a206572726f72207472616e7366657272604082015270696e672072656465656d6564205242544360781b606082015260800190565b6000610100610f8383885180516001600160a01b03168252602090810151910152565b602080880151604085015260408801516060850152610fb8608085018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c085015260e0840182905284519184018290526000915b80831015610ff957858301820151858401610120015291810191610fda565b6101209250600083828701015282601f19601f830116860101935050505095945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220d0fcc7c15da2d0cf8a6f0df865b7535edea2c45483b951fb883a7a57908c9d0764736f6c63430008110033", + "devdoc": { + "kind": "dev", + "methods": { + "constructor": { + "params": { + "_dllr": "DLLR contract address", + "_doc": "DoC contract address", + "_massetManager": "MassetManager contract address", + "_moc": "MoC main contract address" + } + }, + "getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))": { + "params": { + "_dllrAmount": "The amount of the DLLR (mAsset) that will be burned in exchange for _toToken", + "_permitParams": "EIP-2612 permit params: _deadline Expiration time of the signature. _v Last 1 byte of ECDSA signature. _r First 32 bytes of ECDSA signature. _s 32 bytes after _r in ECDSA signature." + } + }, + "getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)": { + "params": { + "permit": "permit data, in form of PermitTransferFrom struct.", + "signature": "of the permit data." + } + }, + "getProxyImplementation()": { + "details": "get the implementation logic address referring to ERC1967 standard.", + "returns": { + "_0": "logic implementation address." + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))": { + "notice": "how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------" + }, + "getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)": { + "notice": "how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------" + }, + "setMocVendorAccount(address)": { + "notice": "Set MoC registered Vendor account to receive markup fees https://docs.moneyonchain.com/main-rbtc-contract/integration-with-moc-platform/vendors" + } + }, + "notice": "This contract provides compound functions with Money On Chain wrapping them in one transaction for convenience and to save on gas", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 534, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8" + }, + { + "astId": 537, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 1021, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 10, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "t_address" + }, + { + "astId": 130, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "52", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 516, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 3845, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "mocVendorAccount", + "offset": 0, + "slot": "151", + "type": "t_address" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)49_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } + } +} diff --git a/external/deployments/rskMainnet/MocIntegration_Proxy.json b/external/deployments/rskMainnet/MocIntegration_Proxy.json new file mode 100644 index 000000000..12f60acb8 --- /dev/null +++ b/external/deployments/rskMainnet/MocIntegration_Proxy.json @@ -0,0 +1,267 @@ +{ + "address": "0x9363323D9c653a2b89C758f62f5043f0B2c67C71", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "admin_", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "admin_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "changeAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "implementation_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x33cbc8cbe0033011eac63d9f342de4abf4a5b3bdc681cdfd0a7f452b88760477", + "receipt": { + "to": null, + "from": "0xFEe171A152C02F336021fb9E79b4fAc2304a9E7E", + "contractAddress": "0x9363323D9c653a2b89C758f62f5043f0B2c67C71", + "transactionIndex": 0, + "gasUsed": "992423", + "logsBloom": "0x00000000000000000000010000100000400000000100000080800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000003000080000000000000000000000000000000020000000000000000000800000000800000000000000000000000400000000000000000000000000000000000000000000080000000000000800000000200000000000000000000000400000000000000000000000000000000000000000020000000000000000010040000000000000400008000000000200020000000000000000000000000000000000000000000000440000000000000000000", + "blockHash": "0x5fc5e4d0ac0fa4b4d1e42046e43691a6b59128568d984ddb4123250102cc4ad8", + "transactionHash": "0x33cbc8cbe0033011eac63d9f342de4abf4a5b3bdc681cdfd0a7f452b88760477", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 5072812, + "transactionHash": "0x33cbc8cbe0033011eac63d9f342de4abf4a5b3bdc681cdfd0a7f452b88760477", + "address": "0x9363323D9c653a2b89C758f62f5043f0B2c67C71", + "topics": [ + "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", + "0x00000000000000000000000068d06009d4dd7c189b9f5df1d53acffc5bf898af" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x5fc5e4d0ac0fa4b4d1e42046e43691a6b59128568d984ddb4123250102cc4ad8" + }, + { + "transactionIndex": 0, + "blockNumber": 5072812, + "transactionHash": "0x33cbc8cbe0033011eac63d9f342de4abf4a5b3bdc681cdfd0a7f452b88760477", + "address": "0x9363323D9c653a2b89C758f62f5043f0B2c67C71", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000fee171a152c02f336021fb9e79b4fac2304a9e7e" + ], + "data": "0x", + "logIndex": 1, + "blockHash": "0x5fc5e4d0ac0fa4b4d1e42046e43691a6b59128568d984ddb4123250102cc4ad8" + }, + { + "transactionIndex": 0, + "blockNumber": 5072812, + "transactionHash": "0x33cbc8cbe0033011eac63d9f342de4abf4a5b3bdc681cdfd0a7f452b88760477", + "address": "0x9363323D9c653a2b89C758f62f5043f0B2c67C71", + "topics": ["0xc2a1feb9d65ecb31b0e93a520a66d19319929a2bf58046d92d762c04e7dd06c9"], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": 2, + "blockHash": "0x5fc5e4d0ac0fa4b4d1e42046e43691a6b59128568d984ddb4123250102cc4ad8" + }, + { + "transactionIndex": 0, + "blockNumber": 5072812, + "transactionHash": "0x33cbc8cbe0033011eac63d9f342de4abf4a5b3bdc681cdfd0a7f452b88760477", + "address": "0x9363323D9c653a2b89C758f62f5043f0B2c67C71", + "topics": ["0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498"], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 3, + "blockHash": "0x5fc5e4d0ac0fa4b4d1e42046e43691a6b59128568d984ddb4123250102cc4ad8" + }, + { + "transactionIndex": 0, + "blockNumber": 5072812, + "transactionHash": "0x33cbc8cbe0033011eac63d9f342de4abf4a5b3bdc681cdfd0a7f452b88760477", + "address": "0x9363323D9c653a2b89C758f62f5043f0B2c67C71", + "topics": ["0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f"], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000466e023ddd08b53385b4763b883ab63820c123df", + "logIndex": 4, + "blockHash": "0x5fc5e4d0ac0fa4b4d1e42046e43691a6b59128568d984ddb4123250102cc4ad8" + } + ], + "blockNumber": 5072812, + "cumulativeGasUsed": "992423", + "status": 1, + "byzantium": true + }, + "args": [ + "0x68D06009d4DD7c189B9f5dF1D53aCffC5bF898aF", + "0x466e023ddd08b53385b4763b883ab63820c123df", + "0xc4d66de80000000000000000000000000000000000000000000000000000000000000000" + ], + "numDeployments": 1, + "solcInputHash": "0e89febeebc7444140de8e67c9067d2c", + "metadata": "{\"compiler\":{\"version\":\"0.8.10+commit.fc410830\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"}],\"name\":\"BeaconUpgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"changeAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"implementation_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"This contract implements a proxy that is upgradeable by an admin. To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector clashing], which can potentially be used in an attack, this contract uses the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two things that go hand in hand: 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if that call matches one of the admin functions exposed by the proxy itself. 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the implementation. If the admin tries to call a function on the implementation it will fail with an error that says \\\"admin cannot fallback to proxy target\\\". These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to call a function from the proxy implementation. Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\",\"kind\":\"dev\",\"methods\":{\"admin()\":{\"details\":\"Returns the current admin. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\"},\"changeAdmin(address)\":{\"details\":\"Changes the admin of the proxy. Emits an {AdminChanged} event. NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.\"},\"constructor\":{\"details\":\"Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\"},\"implementation()\":{\"details\":\"Returns the current implementation. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\"},\"upgradeTo(address)\":{\"details\":\"Upgrade the implementation of the proxy. NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.\"},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the implementation of the proxy, and then call a function from the new implementation as specified by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the proxied contract. NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solc_0.8/openzeppelin/proxy/transparent/TransparentUpgradeableProxy.sol\":\"TransparentUpgradeableProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"solc_0.8/openzeppelin/interfaces/draft-IERC1822.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (interfaces/draft-IERC1822.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\\n * proxy whose upgrades are fully controlled by the current implementation.\\n */\\ninterface IERC1822Proxiable {\\n /**\\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\\n * address.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy.\\n */\\n function proxiableUUID() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x93b4e21c931252739a1ec13ea31d3d35a5c068be3163ccab83e4d70c40355f03\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/proxy/ERC1967/ERC1967Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Proxy.sol\\\";\\nimport \\\"./ERC1967Upgrade.sol\\\";\\n\\n/**\\n * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an\\n * implementation address that can be changed. This address is stored in storage in the location specified by\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the\\n * implementation behind the proxy.\\n */\\ncontract ERC1967Proxy is Proxy, ERC1967Upgrade {\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded\\n * function call, and allows initializating the storage of the proxy like a Solidity constructor.\\n */\\n constructor(address _logic, bytes memory _data) payable {\\n assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256(\\\"eip1967.proxy.implementation\\\")) - 1));\\n _upgradeToAndCall(_logic, _data, false);\\n }\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _implementation() internal view virtual override returns (address impl) {\\n return ERC1967Upgrade._getImplementation();\\n }\\n}\\n\",\"keccak256\":\"0x6309f9f39dc6f4f45a24f296543867aa358e32946cd6b2874627a996d606b3a0\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/proxy/ERC1967/ERC1967Upgrade.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (proxy/ERC1967/ERC1967Upgrade.sol)\\n\\npragma solidity ^0.8.2;\\n\\nimport \\\"../beacon/IBeacon.sol\\\";\\nimport \\\"../../interfaces/draft-IERC1822.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/StorageSlot.sol\\\";\\n\\n/**\\n * @dev This abstract contract provides getters and event emitting update functions for\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\\n *\\n * _Available since v4.1._\\n *\\n * @custom:oz-upgrades-unsafe-allow delegatecall\\n */\\nabstract contract ERC1967Upgrade {\\n // This is the keccak-256 hash of \\\"eip1967.proxy.rollback\\\" subtracted by 1\\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _getImplementation() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 implementation slot.\\n */\\n function _setImplementation(address newImplementation) private {\\n require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n }\\n\\n /**\\n * @dev Perform implementation upgrade\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCall(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _upgradeTo(newImplementation);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(newImplementation, data);\\n }\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCallUUPS(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n // Upgrades from old implementations will perform a rollback test. This test requires the new\\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\\n // this special case will break upgrade paths from old UUPS implementation to new ones.\\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\\n _setImplementation(newImplementation);\\n } else {\\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n require(slot == _IMPLEMENTATION_SLOT, \\\"ERC1967Upgrade: unsupported proxiableUUID\\\");\\n } catch {\\n revert(\\\"ERC1967Upgrade: new implementation is not UUPS\\\");\\n }\\n _upgradeToAndCall(newImplementation, data, forceCall);\\n }\\n }\\n\\n /**\\n * @dev Storage slot with the admin of the contract.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.admin\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n /**\\n * @dev Emitted when the admin account has changed.\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _getAdmin() internal view virtual returns (address) {\\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 admin slot.\\n */\\n function _setAdmin(address newAdmin) private {\\n require(newAdmin != address(0), \\\"ERC1967: new admin is the zero address\\\");\\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n */\\n function _changeAdmin(address newAdmin) internal {\\n emit AdminChanged(_getAdmin(), newAdmin);\\n _setAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\\n */\\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\\n\\n /**\\n * @dev Emitted when the beacon is upgraded.\\n */\\n event BeaconUpgraded(address indexed beacon);\\n\\n /**\\n * @dev Returns the current beacon.\\n */\\n function _getBeacon() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new beacon in the EIP1967 beacon slot.\\n */\\n function _setBeacon(address newBeacon) private {\\n require(Address.isContract(newBeacon), \\\"ERC1967: new beacon is not a contract\\\");\\n require(Address.isContract(IBeacon(newBeacon).implementation()), \\\"ERC1967: beacon implementation is not a contract\\\");\\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\\n }\\n\\n /**\\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\\n *\\n * Emits a {BeaconUpgraded} event.\\n */\\n function _upgradeBeaconToAndCall(\\n address newBeacon,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _setBeacon(newBeacon);\\n emit BeaconUpgraded(newBeacon);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x17668652127feebed0ce8d9431ef95ccc8c4292f03e3b8cf06c6ca16af396633\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/proxy/Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (proxy/Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\\n * be specified by overriding the virtual {_implementation} function.\\n *\\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\\n * different contract through the {_delegate} function.\\n *\\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\\n */\\nabstract contract Proxy {\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal virtual {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n /**\\n * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function\\n * and {_fallback} should delegate.\\n */\\n function _implementation() internal view virtual returns (address);\\n\\n /**\\n * @dev Delegates the current call to the address returned by `_implementation()`.\\n *\\n * This function does not return to its internall call site, it will return directly to the external caller.\\n */\\n function _fallback() internal virtual {\\n _beforeFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\\n * is empty.\\n */\\n receive() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\\n * call, or as part of the Solidity `fallback` or `receive` functions.\\n *\\n * If overriden should call `super._beforeFallback()`.\\n */\\n function _beforeFallback() internal virtual {}\\n}\\n\",\"keccak256\":\"0xd5d1fd16e9faff7fcb3a52e02a8d49156f42a38a03f07b5f1810c21c2149a8ab\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/proxy/beacon/IBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\\n */\\ninterface IBeacon {\\n /**\\n * @dev Must return an address that can be used as a delegate call target.\\n *\\n * {BeaconProxy} will check that this address is a contract.\\n */\\n function implementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0xd50a3421ac379ccb1be435fa646d66a65c986b4924f0849839f08692f39dde61\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/proxy/transparent/TransparentUpgradeableProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../ERC1967/ERC1967Proxy.sol\\\";\\n\\n/**\\n * @dev This contract implements a proxy that is upgradeable by an admin.\\n *\\n * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector\\n * clashing], which can potentially be used in an attack, this contract uses the\\n * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two\\n * things that go hand in hand:\\n *\\n * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if\\n * that call matches one of the admin functions exposed by the proxy itself.\\n * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the\\n * implementation. If the admin tries to call a function on the implementation it will fail with an error that says\\n * \\\"admin cannot fallback to proxy target\\\".\\n *\\n * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing\\n * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due\\n * to sudden errors when trying to call a function from the proxy implementation.\\n *\\n * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,\\n * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\\n */\\ncontract TransparentUpgradeableProxy is ERC1967Proxy {\\n /**\\n * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and\\n * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\\n */\\n constructor(\\n address _logic,\\n address admin_,\\n bytes memory _data\\n ) payable ERC1967Proxy(_logic, _data) {\\n assert(_ADMIN_SLOT == bytes32(uint256(keccak256(\\\"eip1967.proxy.admin\\\")) - 1));\\n _changeAdmin(admin_);\\n }\\n\\n /**\\n * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.\\n */\\n modifier ifAdmin() {\\n if (msg.sender == _getAdmin()) {\\n _;\\n } else {\\n _fallback();\\n }\\n }\\n\\n /**\\n * @dev Returns the current admin.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\\n */\\n function admin() external ifAdmin returns (address admin_) {\\n admin_ = _getAdmin();\\n }\\n\\n /**\\n * @dev Returns the current implementation.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\\n */\\n function implementation() external ifAdmin returns (address implementation_) {\\n implementation_ = _implementation();\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.\\n */\\n function changeAdmin(address newAdmin) external virtual ifAdmin {\\n _changeAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev Upgrade the implementation of the proxy.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.\\n */\\n function upgradeTo(address newImplementation) external ifAdmin {\\n _upgradeToAndCall(newImplementation, bytes(\\\"\\\"), false);\\n }\\n\\n /**\\n * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified\\n * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the\\n * proxied contract.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {\\n _upgradeToAndCall(newImplementation, data, true);\\n }\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _admin() internal view virtual returns (address) {\\n return _getAdmin();\\n }\\n\\n /**\\n * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.\\n */\\n function _beforeFallback() internal virtual override {\\n require(msg.sender != _getAdmin(), \\\"TransparentUpgradeableProxy: admin cannot fallback to proxy target\\\");\\n super._beforeFallback();\\n }\\n}\\n\",\"keccak256\":\"0x140055a64cf579d622e04f5a198595832bf2cb193cd0005f4f2d4d61ca906253\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3777e696b62134e6177440dbe6e6601c0c156a443f57167194b67e75527439de\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/utils/StorageSlot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for reading and writing primitive types to specific storage slots.\\n *\\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\\n * This library helps with reading and writing to such slots without the need for inline assembly.\\n *\\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\\n *\\n * Example usage to set ERC1967 implementation slot:\\n * ```\\n * contract ERC1967 {\\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n *\\n * function _getImplementation() internal view returns (address) {\\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n * }\\n *\\n * function _setImplementation(address newImplementation) internal {\\n * require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n * }\\n * }\\n * ```\\n *\\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\\n */\\nlibrary StorageSlot {\\n struct AddressSlot {\\n address value;\\n }\\n\\n struct BooleanSlot {\\n bool value;\\n }\\n\\n struct Bytes32Slot {\\n bytes32 value;\\n }\\n\\n struct Uint256Slot {\\n uint256 value;\\n }\\n\\n /**\\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\\n */\\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\\n */\\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\\n */\\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\\n */\\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\\n assembly {\\n r.slot := slot\\n }\\n }\\n}\\n\",\"keccak256\":\"0xfe1b7a9aa2a530a9e705b220e26cd584e2fbdc9602a3a1066032b12816b46aca\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6080604052604051620011b2380380620011b2833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b6000805160206200116b833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b6000805160206200114b83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002ff1760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e983836040518060600160405280602781526020016200118b6027913962000381565b9392505050565b60006200021a6000805160206200114b83398151915260001b6200046760201b620002731760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd6000805160206200114b83398151915260001b6200046760201b620002731760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200032b1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd6000805160206200116b83398151915260001b6200046760201b620002731760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b610ab380620006986000396000f3fe60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b61009036600461091f565b610135565b61006b6100a336600461093a565b610196565b3480156100b457600080fd5b506100bd610221565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b61010136600461091f565b610276565b34801561011257600080fd5b506100bd6102ba565b610123610347565b61013361012e610435565b61043f565b565b61013d610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561018e5761018b816040518060200160405280600081525060006104a3565b50565b61018b61011b565b61019e610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610219576102148383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600192506104a3915050565b505050565b61021461011b565b600061022b610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026b57610266610435565b905090565b61027361011b565b90565b61027e610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561018e5761018b816104ce565b60006102c4610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026b57610266610463565b60606103248383604051806060016040528060278152602001610a576027913961052f565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b61034f610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b6000610266610657565b3660008037600080366000845af43d6000803e80801561045e573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b6104ac8361067f565b6000825111806104b95750805b15610214576104c883836102ff565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6104f7610463565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161018b816106cc565b606073ffffffffffffffffffffffffffffffffffffffff84163b6105d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e74726163740000000000000000000000000000000000000000000000000000606482015260840161042c565b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516105fd91906109e9565b600060405180830381855af49150503d8060008114610638576040519150601f19603f3d011682016040523d82523d6000602084013e61063d565b606091505b509150915061064d8282866107d8565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610487565b6106888161082b565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b73ffffffffffffffffffffffffffffffffffffffff811661076f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161042c565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b606083156107e7575081610324565b8251156107f75782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161042c9190610a05565b73ffffffffffffffffffffffffffffffffffffffff81163b6108cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e747261637400000000000000000000000000000000000000606482015260840161042c565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610792565b803573ffffffffffffffffffffffffffffffffffffffff8116811461091a57600080fd5b919050565b60006020828403121561093157600080fd5b610324826108f6565b60008060006040848603121561094f57600080fd5b610958846108f6565b9250602084013567ffffffffffffffff8082111561097557600080fd5b818601915086601f83011261098957600080fd5b81358181111561099857600080fd5b8760208285010111156109aa57600080fd5b6020830194508093505050509250925092565b60005b838110156109d85781810151838201526020016109c0565b838111156104c85750506000910152565b600082516109fb8184602087016109bd565b9190910192915050565b6020815260008251806020840152610a248160408501602087016109bd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220b29caa54336b3ee836679675e9732ec5e526fb3f803cca2fe336cc3555aba62264736f6c634300080a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564", + "deployedBytecode": "0x60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b61009036600461091f565b610135565b61006b6100a336600461093a565b610196565b3480156100b457600080fd5b506100bd610221565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b61010136600461091f565b610276565b34801561011257600080fd5b506100bd6102ba565b610123610347565b61013361012e610435565b61043f565b565b61013d610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561018e5761018b816040518060200160405280600081525060006104a3565b50565b61018b61011b565b61019e610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610219576102148383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600192506104a3915050565b505050565b61021461011b565b600061022b610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026b57610266610435565b905090565b61027361011b565b90565b61027e610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561018e5761018b816104ce565b60006102c4610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026b57610266610463565b60606103248383604051806060016040528060278152602001610a576027913961052f565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b61034f610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b6000610266610657565b3660008037600080366000845af43d6000803e80801561045e573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b6104ac8361067f565b6000825111806104b95750805b15610214576104c883836102ff565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6104f7610463565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161018b816106cc565b606073ffffffffffffffffffffffffffffffffffffffff84163b6105d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e74726163740000000000000000000000000000000000000000000000000000606482015260840161042c565b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516105fd91906109e9565b600060405180830381855af49150503d8060008114610638576040519150601f19603f3d011682016040523d82523d6000602084013e61063d565b606091505b509150915061064d8282866107d8565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610487565b6106888161082b565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b73ffffffffffffffffffffffffffffffffffffffff811661076f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161042c565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b606083156107e7575081610324565b8251156107f75782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161042c9190610a05565b73ffffffffffffffffffffffffffffffffffffffff81163b6108cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e747261637400000000000000000000000000000000000000606482015260840161042c565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610792565b803573ffffffffffffffffffffffffffffffffffffffff8116811461091a57600080fd5b919050565b60006020828403121561093157600080fd5b610324826108f6565b60008060006040848603121561094f57600080fd5b610958846108f6565b9250602084013567ffffffffffffffff8082111561097557600080fd5b818601915086601f83011261098957600080fd5b81358181111561099857600080fd5b8760208285010111156109aa57600080fd5b6020830194508093505050509250925092565b60005b838110156109d85781810151838201526020016109c0565b838111156104c85750506000910152565b600082516109fb8184602087016109bd565b9190910192915050565b6020815260008251806020840152610a248160408501602087016109bd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220b29caa54336b3ee836679675e9732ec5e526fb3f803cca2fe336cc3555aba62264736f6c634300080a0033", + "devdoc": { + "details": "This contract implements a proxy that is upgradeable by an admin. To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector clashing], which can potentially be used in an attack, this contract uses the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two things that go hand in hand: 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if that call matches one of the admin functions exposed by the proxy itself. 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the implementation. If the admin tries to call a function on the implementation it will fail with an error that says \"admin cannot fallback to proxy target\". These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to call a function from the proxy implementation. Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.", + "kind": "dev", + "methods": { + "admin()": { + "details": "Returns the current admin. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`" + }, + "changeAdmin(address)": { + "details": "Changes the admin of the proxy. Emits an {AdminChanged} event. NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}." + }, + "constructor": { + "details": "Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}." + }, + "implementation()": { + "details": "Returns the current implementation. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`" + }, + "upgradeTo(address)": { + "details": "Upgrade the implementation of the proxy. NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}." + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the implementation of the proxy, and then call a function from the new implementation as specified by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the proxied contract. NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} diff --git a/external/deployments/rskMainnet/MyntAdminProxy.json b/external/deployments/rskMainnet/MyntAdminProxy.json new file mode 100644 index 000000000..496625174 --- /dev/null +++ b/external/deployments/rskMainnet/MyntAdminProxy.json @@ -0,0 +1,244 @@ +{ + "address": "0x466e023ddd08b53385b4763b883ab63820c123df", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "contract TransparentUpgradeableProxy", + "name": "proxy", + "type": "address" + }, + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "changeProxyAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract TransparentUpgradeableProxy", + "name": "proxy", + "type": "address" + } + ], + "name": "getProxyAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract TransparentUpgradeableProxy", + "name": "proxy", + "type": "address" + } + ], + "name": "getProxyImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract TransparentUpgradeableProxy", + "name": "proxy", + "type": "address" + }, + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "upgrade", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract TransparentUpgradeableProxy", + "name": "proxy", + "type": "address" + }, + { + "internalType": "address", + "name": "implementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + } + ], + "transactionHash": "0xfc8fe415dc433a2e133631c0d58f062f29c46a73a51ab40818534197abda124b", + "receipt": { + "to": null, + "from": "0xfee171a152c02f336021fb9e79b4fac2304a9e7e", + "contractAddress": "0x466e023ddd08b53385b4763b883ab63820c123df", + "transactionIndex": "0x1", + "gasUsed": "0x8146b", + "logsBloom": "0x00000000000000000001000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000003000080000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020080000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x1b04429f5171c5dad3c2bedf1231709746e2de8857b89b2fc5e7c8d7972d15cb", + "transactionHash": "0xfc8fe415dc433a2e133631c0d58f062f29c46a73a51ab40818534197abda124b", + "logs": [ + { + "logIndex": "0x0", + "blockNumber": "0x4d663e", + "blockHash": "0x1b04429f5171c5dad3c2bedf1231709746e2de8857b89b2fc5e7c8d7972d15cb", + "transactionHash": "0xfc8fe415dc433a2e133631c0d58f062f29c46a73a51ab40818534197abda124b", + "transactionIndex": "0x1", + "address": "0x466e023ddd08b53385b4763b883ab63820c123df", + "data": "0x", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000fee171a152c02f336021fb9e79b4fac2304a9e7e" + ] + } + ], + "blockNumber": "0x4d663e", + "cumulativeGasUsed": "0xe43fd", + "status": "0x1" + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "7c5003da36a05eb84dc264d8ce4448ca", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"contract TransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"changeProxyAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract TransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"getProxyAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract TransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"}],\"name\":\"getProxyImplementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract TransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"upgrade\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract TransparentUpgradeableProxy\",\"name\":\"proxy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"changeProxyAdmin(address,address)\":{\"details\":\"Changes the admin of `proxy` to `newAdmin`. Requirements: - This contract must be the current admin of `proxy`.\"},\"getProxyAdmin(address)\":{\"details\":\"Returns the current admin of `proxy`. Requirements: - This contract must be the admin of `proxy`.\"},\"getProxyImplementation(address)\":{\"details\":\"Returns the current implementation of `proxy`. Requirements: - This contract must be the admin of `proxy`.\"},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"upgrade(address,address)\":{\"details\":\"Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}. Requirements: - This contract must be the admin of `proxy`.\"},\"upgradeAndCall(address,address,bytes)\":{\"details\":\"Upgrades `proxy` to `implementation` and calls a function on the new implementation. See {TransparentUpgradeableProxy-upgradeToAndCall}. Requirements: - This contract must be the admin of `proxy`.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/proxy/MyntAdminProxy.sol\":\"MyntAdminProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/interfaces/draft-IERC1822.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\\n * proxy whose upgrades are fully controlled by the current implementation.\\n */\\ninterface IERC1822Proxiable {\\n /**\\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\\n * address.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy.\\n */\\n function proxiableUUID() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x1d4afe6cb24200cc4545eed814ecf5847277dfe5d613a1707aad5fceecebcfff\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Proxy.sol\\\";\\nimport \\\"./ERC1967Upgrade.sol\\\";\\n\\n/**\\n * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an\\n * implementation address that can be changed. This address is stored in storage in the location specified by\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the\\n * implementation behind the proxy.\\n */\\ncontract ERC1967Proxy is Proxy, ERC1967Upgrade {\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded\\n * function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n */\\n constructor(address _logic, bytes memory _data) payable {\\n _upgradeToAndCall(_logic, _data, false);\\n }\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _implementation() internal view virtual override returns (address impl) {\\n return ERC1967Upgrade._getImplementation();\\n }\\n}\\n\",\"keccak256\":\"0xa2b22da3032e50b55f95ec1d13336102d675f341167aa76db571ef7f8bb7975d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)\\n\\npragma solidity ^0.8.2;\\n\\nimport \\\"../beacon/IBeacon.sol\\\";\\nimport \\\"../../interfaces/draft-IERC1822.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/StorageSlot.sol\\\";\\n\\n/**\\n * @dev This abstract contract provides getters and event emitting update functions for\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\\n *\\n * _Available since v4.1._\\n *\\n * @custom:oz-upgrades-unsafe-allow delegatecall\\n */\\nabstract contract ERC1967Upgrade {\\n // This is the keccak-256 hash of \\\"eip1967.proxy.rollback\\\" subtracted by 1\\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _getImplementation() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 implementation slot.\\n */\\n function _setImplementation(address newImplementation) private {\\n require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n }\\n\\n /**\\n * @dev Perform implementation upgrade\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCall(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _upgradeTo(newImplementation);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(newImplementation, data);\\n }\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCallUUPS(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n // Upgrades from old implementations will perform a rollback test. This test requires the new\\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\\n // this special case will break upgrade paths from old UUPS implementation to new ones.\\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\\n _setImplementation(newImplementation);\\n } else {\\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n require(slot == _IMPLEMENTATION_SLOT, \\\"ERC1967Upgrade: unsupported proxiableUUID\\\");\\n } catch {\\n revert(\\\"ERC1967Upgrade: new implementation is not UUPS\\\");\\n }\\n _upgradeToAndCall(newImplementation, data, forceCall);\\n }\\n }\\n\\n /**\\n * @dev Storage slot with the admin of the contract.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.admin\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n /**\\n * @dev Emitted when the admin account has changed.\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _getAdmin() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 admin slot.\\n */\\n function _setAdmin(address newAdmin) private {\\n require(newAdmin != address(0), \\\"ERC1967: new admin is the zero address\\\");\\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n */\\n function _changeAdmin(address newAdmin) internal {\\n emit AdminChanged(_getAdmin(), newAdmin);\\n _setAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\\n */\\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\\n\\n /**\\n * @dev Emitted when the beacon is upgraded.\\n */\\n event BeaconUpgraded(address indexed beacon);\\n\\n /**\\n * @dev Returns the current beacon.\\n */\\n function _getBeacon() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new beacon in the EIP1967 beacon slot.\\n */\\n function _setBeacon(address newBeacon) private {\\n require(Address.isContract(newBeacon), \\\"ERC1967: new beacon is not a contract\\\");\\n require(\\n Address.isContract(IBeacon(newBeacon).implementation()),\\n \\\"ERC1967: beacon implementation is not a contract\\\"\\n );\\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\\n }\\n\\n /**\\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\\n *\\n * Emits a {BeaconUpgraded} event.\\n */\\n function _upgradeBeaconToAndCall(\\n address newBeacon,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _setBeacon(newBeacon);\\n emit BeaconUpgraded(newBeacon);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xabf3f59bc0e5423eae45e459dbe92e7052c6983628d39008590edc852a62f94a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\\n * be specified by overriding the virtual {_implementation} function.\\n *\\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\\n * different contract through the {_delegate} function.\\n *\\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\\n */\\nabstract contract Proxy {\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal virtual {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n /**\\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\\n * and {_fallback} should delegate.\\n */\\n function _implementation() internal view virtual returns (address);\\n\\n /**\\n * @dev Delegates the current call to the address returned by `_implementation()`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _fallback() internal virtual {\\n _beforeFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\\n * is empty.\\n */\\n receive() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\\n * call, or as part of the Solidity `fallback` or `receive` functions.\\n *\\n * If overridden should call `super._beforeFallback()`.\\n */\\n function _beforeFallback() internal virtual {}\\n}\\n\",\"keccak256\":\"0xc130fe33f1b2132158531a87734153293f6d07bc263ff4ac90e85da9c82c0e27\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/beacon/IBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\\n */\\ninterface IBeacon {\\n /**\\n * @dev Must return an address that can be used as a delegate call target.\\n *\\n * {BeaconProxy} will check that this address is a contract.\\n */\\n function implementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0xd50a3421ac379ccb1be435fa646d66a65c986b4924f0849839f08692f39dde61\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/transparent/ProxyAdmin.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./TransparentUpgradeableProxy.sol\\\";\\nimport \\\"../../access/Ownable.sol\\\";\\n\\n/**\\n * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an\\n * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.\\n */\\ncontract ProxyAdmin is Ownable {\\n /**\\n * @dev Returns the current implementation of `proxy`.\\n *\\n * Requirements:\\n *\\n * - This contract must be the admin of `proxy`.\\n */\\n function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {\\n // We need to manually run the static call since the getter cannot be flagged as view\\n // bytes4(keccak256(\\\"implementation()\\\")) == 0x5c60da1b\\n (bool success, bytes memory returndata) = address(proxy).staticcall(hex\\\"5c60da1b\\\");\\n require(success);\\n return abi.decode(returndata, (address));\\n }\\n\\n /**\\n * @dev Returns the current admin of `proxy`.\\n *\\n * Requirements:\\n *\\n * - This contract must be the admin of `proxy`.\\n */\\n function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {\\n // We need to manually run the static call since the getter cannot be flagged as view\\n // bytes4(keccak256(\\\"admin()\\\")) == 0xf851a440\\n (bool success, bytes memory returndata) = address(proxy).staticcall(hex\\\"f851a440\\\");\\n require(success);\\n return abi.decode(returndata, (address));\\n }\\n\\n /**\\n * @dev Changes the admin of `proxy` to `newAdmin`.\\n *\\n * Requirements:\\n *\\n * - This contract must be the current admin of `proxy`.\\n */\\n function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {\\n proxy.changeAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.\\n *\\n * Requirements:\\n *\\n * - This contract must be the admin of `proxy`.\\n */\\n function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {\\n proxy.upgradeTo(implementation);\\n }\\n\\n /**\\n * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See\\n * {TransparentUpgradeableProxy-upgradeToAndCall}.\\n *\\n * Requirements:\\n *\\n * - This contract must be the admin of `proxy`.\\n */\\n function upgradeAndCall(\\n TransparentUpgradeableProxy proxy,\\n address implementation,\\n bytes memory data\\n ) public payable virtual onlyOwner {\\n proxy.upgradeToAndCall{value: msg.value}(implementation, data);\\n }\\n}\\n\",\"keccak256\":\"0x33b8603bfbef7f33d9308b79c79aa3db7eb19525fd1addd764285e834ca275d7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/transparent/TransparentUpgradeableProxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../ERC1967/ERC1967Proxy.sol\\\";\\n\\n/**\\n * @dev This contract implements a proxy that is upgradeable by an admin.\\n *\\n * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector\\n * clashing], which can potentially be used in an attack, this contract uses the\\n * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two\\n * things that go hand in hand:\\n *\\n * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if\\n * that call matches one of the admin functions exposed by the proxy itself.\\n * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the\\n * implementation. If the admin tries to call a function on the implementation it will fail with an error that says\\n * \\\"admin cannot fallback to proxy target\\\".\\n *\\n * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing\\n * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due\\n * to sudden errors when trying to call a function from the proxy implementation.\\n *\\n * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,\\n * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\\n */\\ncontract TransparentUpgradeableProxy is ERC1967Proxy {\\n /**\\n * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and\\n * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\\n */\\n constructor(\\n address _logic,\\n address admin_,\\n bytes memory _data\\n ) payable ERC1967Proxy(_logic, _data) {\\n _changeAdmin(admin_);\\n }\\n\\n /**\\n * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.\\n */\\n modifier ifAdmin() {\\n if (msg.sender == _getAdmin()) {\\n _;\\n } else {\\n _fallback();\\n }\\n }\\n\\n /**\\n * @dev Returns the current admin.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\\n */\\n function admin() external ifAdmin returns (address admin_) {\\n admin_ = _getAdmin();\\n }\\n\\n /**\\n * @dev Returns the current implementation.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\\n */\\n function implementation() external ifAdmin returns (address implementation_) {\\n implementation_ = _implementation();\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.\\n */\\n function changeAdmin(address newAdmin) external virtual ifAdmin {\\n _changeAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev Upgrade the implementation of the proxy.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.\\n */\\n function upgradeTo(address newImplementation) external ifAdmin {\\n _upgradeToAndCall(newImplementation, bytes(\\\"\\\"), false);\\n }\\n\\n /**\\n * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified\\n * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the\\n * proxied contract.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {\\n _upgradeToAndCall(newImplementation, data, true);\\n }\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _admin() internal view virtual returns (address) {\\n return _getAdmin();\\n }\\n\\n /**\\n * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.\\n */\\n function _beforeFallback() internal virtual override {\\n require(msg.sender != _getAdmin(), \\\"TransparentUpgradeableProxy: admin cannot fallback to proxy target\\\");\\n super._beforeFallback();\\n }\\n}\\n\",\"keccak256\":\"0xa6a787e7a901af6511e19aa53e1a00352db215a011d2c7a438d0582dd5da76f9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf96f969e24029d43d0df89e59d365f277021dac62b48e1c1e3ebe0acdd7f1ca1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/StorageSlot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for reading and writing primitive types to specific storage slots.\\n *\\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\\n * This library helps with reading and writing to such slots without the need for inline assembly.\\n *\\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\\n *\\n * Example usage to set ERC1967 implementation slot:\\n * ```\\n * contract ERC1967 {\\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n *\\n * function _getImplementation() internal view returns (address) {\\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n * }\\n *\\n * function _setImplementation(address newImplementation) internal {\\n * require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n * }\\n * }\\n * ```\\n *\\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\\n */\\nlibrary StorageSlot {\\n struct AddressSlot {\\n address value;\\n }\\n\\n struct BooleanSlot {\\n bool value;\\n }\\n\\n struct Bytes32Slot {\\n bytes32 value;\\n }\\n\\n struct Uint256Slot {\\n uint256 value;\\n }\\n\\n /**\\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\\n */\\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\\n */\\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\\n */\\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\\n */\\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n}\\n\",\"keccak256\":\"0xd5c50c54bf02740ebd122ff06832546cb5fa84486d52695a9ccfd11666e0c81d\",\"license\":\"MIT\"},\"contracts/proxy/MyntAdminProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol\\\";\\n\\ncontract MyntAdminProxy is ProxyAdmin {}\\n\",\"keccak256\":\"0x898be1a999c32e5471dd6a8754bca376918ab0dd4ac7bdd73c5c3dcf80bb4928\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6106938061007e6000396000f3fe60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461011157806399a88ec414610124578063f2fde38b14610144578063f3b7dead1461016457600080fd5b8063204e1c7a14610080578063715018a6146100bc5780637eff275e146100d35780638da5cb5b146100f3575b600080fd5b34801561008c57600080fd5b506100a061009b366004610499565b610184565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c857600080fd5b506100d1610215565b005b3480156100df57600080fd5b506100d16100ee3660046104bd565b610229565b3480156100ff57600080fd5b506000546001600160a01b03166100a0565b6100d161011f36600461050c565b610291565b34801561013057600080fd5b506100d161013f3660046104bd565b610300565b34801561015057600080fd5b506100d161015f366004610499565b610336565b34801561017057600080fd5b506100a061017f366004610499565b6103b4565b6000806000836001600160a01b03166040516101aa90635c60da1b60e01b815260040190565b600060405180830381855afa9150503d80600081146101e5576040519150601f19603f3d011682016040523d82523d6000602084013e6101ea565b606091505b5091509150816101f957600080fd5b8080602001905181019061020d91906105e2565b949350505050565b61021d6103da565b6102276000610434565b565b6102316103da565b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b600060405180830381600087803b15801561027557600080fd5b505af1158015610289573d6000803e3d6000fd5b505050505050565b6102996103da565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906102c990869086906004016105ff565b6000604051808303818588803b1580156102e257600080fd5b505af11580156102f6573d6000803e3d6000fd5b5050505050505050565b6103086103da565b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe69060240161025b565b61033e6103da565b6001600160a01b0381166103a85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6103b181610434565b50565b6000806000836001600160a01b03166040516101aa906303e1469160e61b815260040190565b6000546001600160a01b031633146102275760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161039f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146103b157600080fd5b6000602082840312156104ab57600080fd5b81356104b681610484565b9392505050565b600080604083850312156104d057600080fd5b82356104db81610484565b915060208301356104eb81610484565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561052157600080fd5b833561052c81610484565b9250602084013561053c81610484565b9150604084013567ffffffffffffffff8082111561055957600080fd5b818601915086601f83011261056d57600080fd5b81358181111561057f5761057f6104f6565b604051601f8201601f19908116603f011681019083821181831017156105a7576105a76104f6565b816040528281528960208487010111156105c057600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156105f457600080fd5b81516104b681610484565b60018060a01b038316815260006020604081840152835180604085015260005b8181101561063b5785810183015185820160600152820161061f565b506000606082860101526060601f19601f83011685010192505050939250505056fea2646970667358221220f02722c8e22a262deb56e3967ea2bbf25a4754be057f15ea9e063aa27785266664736f6c63430008110033", + "deployedBytecode": "0x60806040526004361061007b5760003560e01c80639623609d1161004e5780639623609d1461011157806399a88ec414610124578063f2fde38b14610144578063f3b7dead1461016457600080fd5b8063204e1c7a14610080578063715018a6146100bc5780637eff275e146100d35780638da5cb5b146100f3575b600080fd5b34801561008c57600080fd5b506100a061009b366004610499565b610184565b6040516001600160a01b03909116815260200160405180910390f35b3480156100c857600080fd5b506100d1610215565b005b3480156100df57600080fd5b506100d16100ee3660046104bd565b610229565b3480156100ff57600080fd5b506000546001600160a01b03166100a0565b6100d161011f36600461050c565b610291565b34801561013057600080fd5b506100d161013f3660046104bd565b610300565b34801561015057600080fd5b506100d161015f366004610499565b610336565b34801561017057600080fd5b506100a061017f366004610499565b6103b4565b6000806000836001600160a01b03166040516101aa90635c60da1b60e01b815260040190565b600060405180830381855afa9150503d80600081146101e5576040519150601f19603f3d011682016040523d82523d6000602084013e6101ea565b606091505b5091509150816101f957600080fd5b8080602001905181019061020d91906105e2565b949350505050565b61021d6103da565b6102276000610434565b565b6102316103da565b6040516308f2839760e41b81526001600160a01b038281166004830152831690638f283970906024015b600060405180830381600087803b15801561027557600080fd5b505af1158015610289573d6000803e3d6000fd5b505050505050565b6102996103da565b60405163278f794360e11b81526001600160a01b03841690634f1ef2869034906102c990869086906004016105ff565b6000604051808303818588803b1580156102e257600080fd5b505af11580156102f6573d6000803e3d6000fd5b5050505050505050565b6103086103da565b604051631b2ce7f360e11b81526001600160a01b038281166004830152831690633659cfe69060240161025b565b61033e6103da565b6001600160a01b0381166103a85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6103b181610434565b50565b6000806000836001600160a01b03166040516101aa906303e1469160e61b815260040190565b6000546001600160a01b031633146102275760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161039f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146103b157600080fd5b6000602082840312156104ab57600080fd5b81356104b681610484565b9392505050565b600080604083850312156104d057600080fd5b82356104db81610484565b915060208301356104eb81610484565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060006060848603121561052157600080fd5b833561052c81610484565b9250602084013561053c81610484565b9150604084013567ffffffffffffffff8082111561055957600080fd5b818601915086601f83011261056d57600080fd5b81358181111561057f5761057f6104f6565b604051601f8201601f19908116603f011681019083821181831017156105a7576105a76104f6565b816040528281528960208487010111156105c057600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156105f457600080fd5b81516104b681610484565b60018060a01b038316815260006020604081840152835180604085015260005b8181101561063b5785810183015185820160600152820161061f565b506000606082860101526060601f19601f83011685010192505050939250505056fea2646970667358221220f02722c8e22a262deb56e3967ea2bbf25a4754be057f15ea9e063aa27785266664736f6c63430008110033", + "devdoc": { + "kind": "dev", + "methods": { + "changeProxyAdmin(address,address)": { + "details": "Changes the admin of `proxy` to `newAdmin`. Requirements: - This contract must be the current admin of `proxy`." + }, + "getProxyAdmin(address)": { + "details": "Returns the current admin of `proxy`. Requirements: - This contract must be the admin of `proxy`." + }, + "getProxyImplementation(address)": { + "details": "Returns the current implementation of `proxy`. Requirements: - This contract must be the admin of `proxy`." + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + }, + "upgrade(address,address)": { + "details": "Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}. Requirements: - This contract must be the admin of `proxy`." + }, + "upgradeAndCall(address,address,bytes)": { + "details": "Upgrades `proxy` to `implementation` and calls a function on the new implementation. See {TransparentUpgradeableProxy-upgradeToAndCall}. Requirements: - This contract must be the admin of `proxy`." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 1156, + "contract": "contracts/proxy/MyntAdminProxy.sol:MyntAdminProxy", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "t_address" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + } + } + } +} diff --git a/external/deployments/rskMainnet/Permit2.json b/external/deployments/rskMainnet/Permit2.json new file mode 100644 index 000000000..311219e0f --- /dev/null +++ b/external/deployments/rskMainnet/Permit2.json @@ -0,0 +1,904 @@ +{ + "address": "0x000000000022d473030f116ddee9f6b43ac78ba3", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "AllowanceExpired", + "type": "error" + }, + { + "inputs": [], + "name": "ExcessiveInvalidation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "maxAmount", + "type": "uint256" + } + ], + "name": "InvalidAmount", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidContractSignature", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidNonce", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSignature", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSignatureLength", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSigner", + "type": "error" + }, + { + "inputs": [], + "name": "LengthMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "signatureDeadline", + "type": "uint256" + } + ], + "name": "SignatureExpired", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "Lockdown", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "newNonce", + "type": "uint48" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "oldNonce", + "type": "uint48" + } + ], + "name": "NonceInvalidation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "name": "Permit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "word", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "mask", + "type": "uint256" + } + ], + "name": "UnorderedNonceInvalidation", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint48", + "name": "newNonce", + "type": "uint48" + } + ], + "name": "invalidateNonces", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "wordPos", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "mask", + "type": "uint256" + } + ], + "name": "invalidateUnorderedNonces", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "internalType": "struct IAllowanceTransfer.TokenSpenderPair[]", + "name": "approvals", + "type": "tuple[]" + } + ], + "name": "lockdown", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "nonceBitmap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "internalType": "struct IAllowanceTransfer.PermitDetails[]", + "name": "details", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sigDeadline", + "type": "uint256" + } + ], + "internalType": "struct IAllowanceTransfer.PermitBatch", + "name": "permitBatch", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "internalType": "struct IAllowanceTransfer.PermitDetails", + "name": "details", + "type": "tuple" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sigDeadline", + "type": "uint256" + } + ], + "internalType": "struct IAllowanceTransfer.PermitSingle", + "name": "permitSingle", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails", + "name": "transferDetails", + "type": "tuple" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permitTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions[]", + "name": "permitted", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitBatchTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails[]", + "name": "transferDetails", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permitTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails", + "name": "transferDetails", + "type": "tuple" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "witness", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "witnessTypeString", + "type": "string" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permitWitnessTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions[]", + "name": "permitted", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitBatchTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails[]", + "name": "transferDetails", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "witness", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "witnessTypeString", + "type": "string" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permitWitnessTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "internalType": "struct IAllowanceTransfer.AllowanceTransferDetails[]", + "name": "transferDetails", + "type": "tuple[]" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/external/deployments/rskMainnet/StabilityPool.json b/external/deployments/rskMainnet/StabilityPool.json new file mode 100644 index 000000000..6f5cb608d --- /dev/null +++ b/external/deployments/rskMainnet/StabilityPool.json @@ -0,0 +1,1534 @@ +{ + "address": "0xd46C0225D1331B46700d64fF8c906709D15C9202", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_oldImplementation", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_newImplementation", + "type": "address" + } + ], + "name": "ImplementationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newActivePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newBorrowerOperationsAddress", + "type": "address" + } + ], + "name": "BorrowerOperationsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newCommunityIssuanceAddress", + "type": "address" + } + ], + "name": "CommunityIssuanceAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newDefaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_S", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + } + ], + "name": "DepositSnapshotUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDLoss", + "type": "uint256" + } + ], + "name": "ETHGainWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint128", + "name": "_currentEpoch", + "type": "uint128" + } + ], + "name": "EpochUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "EtherSent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_kickbackRate", + "type": "uint256" + } + ], + "name": "FrontEndRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + } + ], + "name": "FrontEndSnapshotUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newFrontEndStake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "FrontEndStakeChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "FrontEndTagSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_epoch", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_scale", + "type": "uint128" + } + ], + "name": "G_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + } + ], + "name": "P_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_SOV", + "type": "uint256" + } + ], + "name": "SOVPaidToDepositor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_SOV", + "type": "uint256" + } + ], + "name": "SOVPaidToFrontEnd", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_S", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_epoch", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_scale", + "type": "uint128" + } + ], + "name": "S_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint128", + "name": "_currentScale", + "type": "uint128" + } + ], + "name": "ScaleUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newSortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newBalance", + "type": "uint256" + } + ], + "name": "StabilityPoolETHBalanceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newBalance", + "type": "uint256" + } + ], + "name": "StabilityPoolZUSDBalanceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newTroveManagerAddress", + "type": "address" + } + ], + "name": "TroveManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newDeposit", + "type": "uint256" + } + ], + "name": "UserDepositChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_zusdAmountRequested", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_dllrAmountReceived", + "type": "uint256" + } + ], + "name": "WithdrawFromSpAndConvertToDLLR", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newZUSDTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "P", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SCALE_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "borrowerOperations", + "outputs": [ + { + "internalType": "contract IBorrowerOperations", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "communityIssuance", + "outputs": [ + { + "internalType": "contract ICommunityIssuance", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentEpoch", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentScale", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "depositSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "S", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "P", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "G", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "scale", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "epoch", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "deposits", + "outputs": [ + { + "internalType": "uint256", + "name": "initialValue", + "type": "uint256" + }, + { + "internalType": "address", + "name": "frontEndTag", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "name": "epochToScaleToG", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "name": "epochToScaleToSum", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEndSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "S", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "P", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "G", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "scale", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "epoch", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEndStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEnds", + "outputs": [ + { + "internalType": "uint256", + "name": "kickbackRate", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "registered", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "getCompoundedFrontEndStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getCompoundedZUSDDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getDepositorETHGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getDepositorSOVGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getETH", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "getFrontEndSOVGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalZUSDDeposits", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastETHError_Offset", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastSOVError", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastZUSDLossError_Offset", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_debtToOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collToAdd", + "type": "uint256" + } + ], + "name": "offset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_frontEndTag", + "type": "address" + } + ], + "name": "provideToSP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "provideToSpFromDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "provideToSpFromDllrWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_kickbackRate", + "type": "uint256" + } + ], + "name": "registerFrontEnd", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_communityIssuanceAddress", + "type": "address" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_communityIssuanceAddress", + "type": "address" + } + ], + "name": "setCommunityIssuanceAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManager", + "outputs": [ + { + "internalType": "contract ITroveManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawETHGainToTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "withdrawFromSP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_zusdAmountRequested", + "type": "uint256" + } + ], + "name": "withdrawFromSpAndConvertToDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0xC959895CE6224dde0BdF7eb84519814dE23f2ee5", + "transactionIndex": 0, + "gasUsed": "5135892", + "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000040000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x26eb0b71917b7e14376847d8f22d8b657ac8a4a9756f9bace883ec60614ed674", + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748945, + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "address": "0xC959895CE6224dde0BdF7eb84519814dE23f2ee5", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x26eb0b71917b7e14376847d8f22d8b657ac8a4a9756f9bace883ec60614ed674" + } + ], + "blockNumber": 4748945, + "cumulativeGasUsed": "5135892", + "status": 1, + "byzantium": true + }, + "numDeployments": 4, + "bytecode": "0x60a06040523480156200001157600080fd5b5060405162004b8c38038062004b8c833981016040819052620000349162000123565b62000048336001600160e01b036200005e16565b60601b6001600160601b031916608052620001b2565b6001600160a01b038116620000905760405162461bcd60e51b8152600401620000879062000170565b60405180910390fd5b6001600160a01b038116620000ad6001600160e01b036200010216565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f29062000153565b6040519081900390209190915550565b600080604051620001139062000153565b6040519081900390205492915050565b60006020828403121562000135578081fd5b81516001600160a01b03811681146200014c578182fd5b9392505050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160601c6149b7620001d560003980610ad0528061189a52506149b76000f3fe6080604052600436106102ad5760003560e01c806382e0a57411610165578063b31ee965116100cc578063de13da3c11610085578063de13da3c14610788578063df9cd84f146107a8578063e49d3667146107c8578063ec9f7d46146107e8578063fc7e286d146107fd578063fce6b7341461082b578063fda0101a1461084b576102f8565b8063b31ee965146106f4578063bdaf37ea14610709578063c3a34a0e1461071e578063ce4b5bbe1461073e578063d733cfd014610753578063d7fb044314610773576102f8565b80639f0706701161011e5780639f07067014610665578063a20baee614610531578063a3f4df7e1461067a578063a4e59ac81461069c578063a7bfff97146106b1578063ae918754146106df576102f8565b806382e0a574146105d157806386da0824146105f1578063887105d314610611578063893d20e8146106265780638b8fbd921461063b57806395fb16bb14610650576102f8565b80633d83908a1161021457806372fe25aa116101cd57806372fe25aa14610531578063741bef1a14610546578063759b30341461055b578063766718081461057057806377553ad414610592578063795d26c3146105a75780637f7dde4a146105bc576102f8565b80633d83908a1461048757806340ed1afd1461049c578063556be101146104bc5780635d2de642146104dc5780635f788d65146104fc57806370f1b5721461051c576102f8565b80632199b66f116102665780632199b66f146103d257806328a0a04d146103f25780632e54bf9514610412578063335525ad14610432578063389e92a5146104525780633cc7422514610472576102f8565b80630fbfe38b146102fd57806312261ee71461031f57806313af40351461034a57806314f6c3be1461036a57806316b9d3c51461038c5780631bf43555146103bd576102f8565b366102f8576102ba61086b565b6009546102cd903463ffffffff6108a016565b6009819055604051600080516020614902833981519152916102ee91614847565b60405180910390a1005b600080fd5b34801561030957600080fd5b5061031d610318366004613d86565b6108ce565b005b34801561032b57600080fd5b50610334610ace565b6040516103419190613f43565b60405180910390f35b34801561035657600080fd5b5061031d610365366004613c1a565b610af2565b34801561037657600080fd5b5061037f610b36565b6040516103419190614847565b34801561039857600080fd5b506103ac6103a7366004613c1a565b610b3c565b604051610341959493929190614896565b3480156103c957600080fd5b5061037f610b77565b3480156103de57600080fd5b5061031d6103ed366004613c1a565b610b84565b3480156103fe57600080fd5b5061037f61040d366004613d52565b610c1b565b34801561041e57600080fd5b5061031d61042d366004613d86565b610c38565b34801561043e57600080fd5b5061031d61044d366004613ec9565b610c46565b34801561045e57600080fd5b5061037f61046d366004613c1a565b610ca9565b34801561047e57600080fd5b50610334610d51565b34801561049357600080fd5b50610334610d60565b3480156104a857600080fd5b5061037f6104b7366004613c1a565b610d6f565b3480156104c857600080fd5b5061031d6104d7366004613d86565b610e0c565b3480156104e857600080fd5b5061037f6104f7366004613c1a565b610e84565b34801561050857600080fd5b5061031d610517366004613db6565b610e96565b34801561052857600080fd5b5061037f610ea0565b34801561053d57600080fd5b5061037f610ea6565b34801561055257600080fd5b50610334610eb2565b34801561056757600080fd5b5061037f610ec1565b34801561057c57600080fd5b50610585610ece565b6040516103419190614833565b34801561059e57600080fd5b50610334610ee4565b3480156105b357600080fd5b5061037f610ef3565b3480156105c857600080fd5b50610334611012565b3480156105dd57600080fd5b5061037f6105ec366004613d52565b611021565b3480156105fd57600080fd5b506103ac61060c366004613c1a565b61103e565b34801561061d57600080fd5b5061037f611079565b34801561063257600080fd5b50610334611148565b34801561064757600080fd5b5061037f611167565b34801561065c57600080fd5b5061033461116d565b34801561067157600080fd5b5061033461117c565b34801561068657600080fd5b5061068f61118b565b6040516103419190614060565b3480156106a857600080fd5b506105856111b4565b3480156106bd57600080fd5b506106d16106cc366004613c1a565b6111c3565b604051610341929190614867565b3480156106eb57600080fd5b506103346111df565b34801561070057600080fd5b5061037f6111ee565b34801561071557600080fd5b5061037f6111f4565b34801561072a57600080fd5b5061031d610739366004613dda565b6111fa565b34801561074a57600080fd5b5061037f61129e565b34801561075f57600080fd5b5061031d61076e366004613c8a565b6112a6565b34801561077f57600080fd5b5061037f611538565b34801561079457600080fd5b5061037f6107a3366004613c1a565b61153e565b3480156107b457600080fd5b5061037f6107c3366004613c1a565b611642565b3480156107d457600080fd5b5061037f6107e3366004613c1a565b6116df565b3480156107f457600080fd5b506103346117dc565b34801561080957600080fd5b5061081d610818366004613c1a565b6117eb565b604051610341929190614850565b34801561083757600080fd5b5061031d610846366004613e10565b61180d565b34801561085757600080fd5b5061031d610866366004613c52565b6118cd565b6000546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614258565b60405180910390fd5b565b6000828201838110156108c55760405162461bcd60e51b815260040161089590614168565b90505b92915050565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561091e57600080fd5b505afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613c36565b905060006109648330611b13565b60065460405163095ea7b360e01b81529192506001600160a01b03169063095ea7b3906109979085908590600401613fdf565b602060405180830381600087803b1580156109b157600080fd5b505af11580156109c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e99190613d32565b610a055760405162461bcd60e51b8152600401610895906145ef565b60065460405163438b1b4b60e01b81526001600160a01b038481169263438b1b4b92610a3b929091169085903390600401614019565b602060405180830381600087803b158015610a5557600080fd5b505af1158015610a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8d9190613d9e565b507f2b0fbec1c4e7e30517f196a714775ffe72770d2348f5d586854bb3c0fdf41df8338483604051610ac193929190613ff8565b60405180910390a1505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b610afa611148565b6001600160a01b0316336001600160a01b031614610b2a5760405162461bcd60e51b81526004016108959061451d565b610b3381611cde565b50565b60095490565b600f602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6809c2007651b250000081565b610b8c611148565b6001600160a01b0316336001600160a01b031614610bbc5760405162461bcd60e51b81526004016108959061451d565b610bc581611d69565b600880546001600160a01b0319166001600160a01b0383161790556040517f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac681190610c10908390613f43565b60405180910390a150565b601260209081526000928352604080842090915290825290205481565b610c428133611b13565b5050565b610c4e611dae565b600a54801580610c5c575082155b15610c675750610c42565b600854610c7c906001600160a01b0316611dd8565b600080610c8a848685611e65565b91509150610c988282611f5e565b610ca2848661225f565b5050505050565b6001600160a01b0381166000908152600b602052604081205480610cd1576000915050610d4c565b610cd9613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612395565b93505050505b919050565b6001546001600160a01b031681565b6005546001600160a01b031681565b6001600160a01b0381166000908152600b602052604081205480610d97576000915050610d4c565b610d9f613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b610e1533612582565b610e1e336125be565b610e27816125f5565b336000818152600d6020526040908190208381556001908101805460ff19169091179055517f19bc932fb9e16a8b5a1e41be9f4c2de59d5ddd7567b8b81405f532ca00a9880e90610e79908490614847565b60405180910390a250565b600e6020526000908152604090205481565b610c42828261261d565b60145481565b670de0b6b3a764000081565b6002546001600160a01b031681565b6801158e460913d0000081565b601154600160801b90046001600160801b031681565b6004546001600160a01b031681565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3757600080fd5b505afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b505afa158015610fd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff99190613d9e565b905061100b828263ffffffff6108a016565b9250505090565b6000546001600160a01b031681565b601360209081526000928352604080842090915290825290205481565b600c602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156110be57600080fd5b505afa1580156110d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f69190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b60008060405161115790613f26565b6040519081900390205492915050565b60105481565b6008546001600160a01b031681565b6003546001600160a01b031681565b6040518060400160405280600d81526020016c14dd18589a5b1a5d1e541bdbdb609a1b81525081565b6011546001600160801b031681565b600d602052600090815260409020805460019091015460ff1682565b6007546001600160a01b031681565b60165481565b600a5490565b600480546040805163e9fc346160e01b8152905160009361128c936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561124057600080fd5b505afa158015611254573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112789190613c36565b60065485906001600160a01b0316856127c0565b905061129981600061261d565b505050565b633b9aca0081565b6112ae611148565b6001600160a01b0316336001600160a01b0316146112de5760405162461bcd60e51b81526004016108959061451d565b6112e788611d69565b6112f087611d69565b6112f986611d69565b61130285611d69565b61130b84611d69565b61131483611d69565b61131d82611d69565b61132681611d69565b670de0b6b3a7640000601055600380546001600160a01b03199081166001600160a01b038b8116919091179092556004805482168a8416179055600580548216898416179055600080548216888416179055600680548216878416179055600780548216868416179055600280548216858416179055600880549091169183169190911790556040517f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed985906113dc908990613f43565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a5678866040516114139190613f43565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828560405161144a9190613f43565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d846040516114819190613f43565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800836040516114b89190613f43565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264826040516114ef9190613f43565b60405180910390a17f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac6811816040516115269190613f43565b60405180910390a15050505050505050565b60155481565b6001600160a01b0381166000908152600e602052604081205480611566576000915050610d4c565b6001600160a01b0383166000908152600d602052604081205490611598670de0b6b3a76400008363ffffffff612a6516565b90506115a2613b64565b506001600160a01b0385166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b869063ffffffff612b3316565b9063ffffffff612b6d16565b979650505050505050565b6001600160a01b0381166000908152600e60205260408120548061166a576000915050610d4c565b611672613b64565b506001600160a01b0383166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b6001600160a01b0381166000908152600b602052604081205480611707576000915050610d4c565b6001600160a01b038084166000908152600b602052604081206001015490911690811561174c576001600160a01b0382166000908152600d6020526040902054611756565b670de0b6b3a76400005b9050611760613b64565b506001600160a01b0385166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b6006546001600160a01b031681565b600b60205260009081526040902080546001909101546001600160a01b031682565b600480546040805163e9fc346160e01b815290516000936118c0936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561185357600080fd5b505afa158015611867573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188b9190613c36565b6006546001600160a01b0316867f00000000000000000000000000000000000000000000000000000000000000008787612baf565b9050610ca281600061261d565b336000908152600b60205260409020546118e681612dfc565b6118ef33612e1c565b6118f833612ebb565b6008546001600160a01b031661190d81611dd8565b600061191833610ca9565b9050600061192533610d6f565b90506000611939858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b039091169061196790869083612ee8565b600061197282611642565b90508061197f838261305d565b826001600160a01b031660008051602061496283398151915282336040516119a8929190614850565b60405180910390a26119ba33866131a5565b336001600160a01b031660008051602061494283398151915287866040516119e392919061403c565b60405180910390a2336001600160a01b031660008051602061492283398151915286604051611a129190614847565b60405180910390a2600954611a2d908763ffffffff612a6516565b600981905560405160008051602061490283398151915291611a4e91614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123387604051611a87929190613fdf565b60405180910390a1600460009054906101000a90046001600160a01b03166001600160a01b031663ea9638bf87338d8d6040518563ffffffff1660e01b8152600401611ad593929190613f57565b6000604051808303818588803b158015611aee57600080fd5b505af1158015611b02573d6000803e3d6000fd5b505050505050505050505050505050565b60006001600160a01b038216611b3b5760405162461bcd60e51b815260040161089590614434565b8215611b4957611b4961331a565b336000908152600b6020526040902054611b6281612dfc565b6008546001600160a01b0316611b7781611dd8565b6000611b8233610ca9565b90506000611b8f33610d6f565b90506000611b9d8883613551565b90506000611bb1868463ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b0390911690611bdf90879083612ee8565b6000611bea82611642565b90506000611bfe828663ffffffff612a6516565b9050611c0a838261305d565b826001600160a01b03166000805160206149628339815191528233604051611c33929190614850565b60405180910390a2611c458b86613567565b6000611c57878763ffffffff612a6516565b9050611c6333826131a5565b336001600160a01b031660008051602061492283398151915282604051611c8a9190614847565b60405180910390a2336001600160a01b03166000805160206149428339815191528987604051611cbb92919061403c565b60405180910390a2611ccd88336135e0565b50939b9a5050505050505050505050565b6001600160a01b038116611d045760405162461bcd60e51b81526004016108959061429f565b806001600160a01b0316611d16611148565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611d5990613f26565b6040519081900390209190915550565b6001600160a01b038116611d8f5760405162461bcd60e51b8152600401610895906142e1565b803b80610c425760405162461bcd60e51b815260040161089590614646565b6005546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614369565b600a54604051636cbdcf4760e01b81526000916001600160a01b03841691636cbdcf4791611e0891600401614847565b602060405180830381600087803b158015611e2257600080fd5b505af1158015611e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5a9190613d9e565b9050610c428161370f565b6000806000611e97601554611e8b670de0b6b3a764000089612b3390919063ffffffff16565b9063ffffffff6108a016565b905083851115611ea357fe5b83851415611ec0576000601655670de0b6b3a76400009150611f20565b601654600090611eee90611ee288670de0b6b3a764000063ffffffff612b3316565b9063ffffffff612a6516565b9050611f056001611e8b838863ffffffff612b6d16565b9250611f1b81611ee2858863ffffffff612b3316565b601655505b611f30818563ffffffff612b6d16565b9250611f52611f45848663ffffffff612b3316565b829063ffffffff612a6516565b60155550935093915050565b6010546000670de0b6b3a7640000831115611f7557fe5b6000611f8f670de0b6b3a76400008563ffffffff612a6516565b6011546001600160801b03600160801b820481166000818152601260209081526040808320949095168083529390529283205493945090929091611fd38988612b33565b90506000611fe7838363ffffffff6108a016565b6001600160801b038086166000908152601260209081526040808320938a168352929052819020829055519091507fe12e2cd2c9afa8069203ca07e7eff1edce4a075686d0736a8e7e0d593597b2079061204690839087908990614877565b60405180910390a18561211f5761206d6001600160801b038516600163ffffffff61382016565b601180546001600160801b03908116600160801b938216840217918290556040517fb50f0f59e7cb5b421dc77581c3a9919e3806e076e5fa78a874c3f120cb7d874d936120be930490911690614833565b60405180910390a1601180546001600160801b03191690556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9061210790600090614833565b60405180910390a1670de0b6b3a7640000965061220c565b633b9aca00612140670de0b6b3a764000061162b8b8a63ffffffff612b3316565b10156121ed57612176670de0b6b3a764000061162b633b9aca0061216a8c8b63ffffffff612b3316565b9063ffffffff612b3316565b96506121926001600160801b038616600163ffffffff61382016565b601180546001600160801b0319166001600160801b0392831617908190556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe926121e0921690614833565b60405180910390a161220c565b612209670de0b6b3a764000061162b8a8963ffffffff612b3316565b96505b6000871161221657fe5b60108790556040517fc1a9618cb59ebca77cbdbc2949f126823c407ff13edb285fd0262519a9c18e8c9061224b908990614847565b60405180910390a150505050505050505050565b60005460405163121cbc4d60e11b81526001600160a01b03909116908190632439789a90612291908590600401614847565b600060405180830381600087803b1580156122ab57600080fd5b505af11580156122bf573d6000803e3d6000fd5b505050506122cc82613851565b600654604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906122fe9030908690600401613fdf565b600060405180830381600087803b15801561231857600080fd5b505af115801561232c573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b03841692506364a197f3915061235e9030908790600401613fdf565b600060405180830381600087803b15801561237857600080fd5b505af115801561238c573d6000803e3d6000fd5b50505050505050565b6080810151606082015182516020808501516001600160801b038086166000908152601284526040808220928716825291909352822054919493929185906123e3908463ffffffff612a6516565b6001600160801b0380871660009081526012602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b6001600160801b031681526020810191909152604001600020549063ffffffff612b6d16565b90506000612478670de0b6b3a764000061162b868161246b888863ffffffff6108a016565b8f9063ffffffff612b3316565b9a9950505050505050505050565b6020810151606082015160808301516011546000939291906001600160801b03600160801b909104811690821610156124c557600093505050506108c8565b60115460009081906124e6906001600160801b03168563ffffffff6138ab16565b90506001600160801b0381166125165761250f8561162b6010548b612b3390919063ffffffff16565b915061254e565b806001600160801b0316600114156125495761250f633b9aca0061162b8761162b6010548d612b3390919063ffffffff16565b600091505b61256288633b9aca0063ffffffff612b6d16565b821015612577576000955050505050506108c8565b509695505050505050565b6001600160a01b0381166000908152600d602052604090206001015460ff1615610b335760405162461bcd60e51b81526004016108959061454e565b6001600160a01b0381166000908152600b60205260409020548015610c425760405162461bcd60e51b8152600401610895906145a7565b670de0b6b3a7640000811115610b335760405162461bcd60e51b815260040161089590614484565b612626816138e5565b61262f33612582565b61263882613932565b336000908152600b60205260409020546008546001600160a01b031661265d81611dd8565b8161266c5761266c3384613952565b600061267733610ca9565b9050600061268433610d6f565b90506000612698858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b03909116906126c690869083612ee8565b60006126d182611642565b905060006126e5828b63ffffffff6108a016565b90506126f1838261305d565b826001600160a01b0316600080516020614962833981519152823360405161271a929190614850565b60405180910390a261272c338b6139ac565b600061273e868c63ffffffff6108a016565b905061274a33826131a5565b336001600160a01b0316600080516020614922833981519152826040516127719190614847565b60405180910390a2336001600160a01b031660008051602061494283398151915288876040516127a292919061403c565b60405180910390a26127b387613a60565b5050505050505050505050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b1580156127fc57600080fd5b505afa158015612810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128349190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016128649190613f43565b60206040518083038186803b15801561287c57600080fd5b505afa158015612890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b49190613d9e565b9050306001600160a01b03831663605629d633838a89356128db60408c0160208d01613eea565b8b604001358c606001356040518863ffffffff1660e01b81526004016129079796959493929190613f9e565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b50505050866129ba83856001600160a01b03166370a08231856040518263ffffffff1660e01b815260040161296a9190613f43565b60206040518083038186803b15801561298257600080fd5b505afa158015612996573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee29190613d9e565b146129d75760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390612a079089908b903390600401614019565b602060405180830381600087803b158015612a2157600080fd5b505af1158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613d9e565b98975050505050505050565b60006108c583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a6a565b608081015160608201516040808401516020808601516001600160801b03808716600090815260138452858120918716815292529281205490949392908590612af6908463ffffffff612a6516565b6001600160801b0380871660009081526013602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b600082612b42575060006108c8565b82820282848281612b4f57fe5b04146108c55760405162461bcd60e51b8152600401610895906143f3565b60006108c583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613a96565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015612beb57600080fd5b505afa158015612bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c239190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612c539190613f43565b60206040518083038186803b158015612c6b57600080fd5b505afa158015612c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca39190613d9e565b87516020015190915030906001600160a01b0388166330f28b7a8a612cc88585613acd565b338b8b6040518663ffffffff1660e01b8152600401612ceb9594939291906147c2565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b5050505080612d4e84866001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161296a9190613f43565b14612d6b5760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390612d9b908d9085903390600401614019565b602060405180830381600087803b158015612db557600080fd5b505af1158015612dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ded9190613d9e565b9b9a5050505050505050505050565b60008111610b335760405162461bcd60e51b81526004016108959061467b565b6005546040516321e3780160e01b81526001600160a01b03909116906321e3780190612e4c908490600401613f43565b60206040518083038186803b158015612e6457600080fd5b505afa158015612e78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9c9190613d9e565b600114610b335760405162461bcd60e51b8152600401610895906140b3565b6000612ec682610ca9565b905060008111610c425760405162461bcd60e51b815260040161089590614318565b6001600160a01b03811615612fa8576000612f028261153e565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612f339085908590600401613fdf565b600060405180830381600087803b158015612f4d57600080fd5b505af1158015612f61573d6000803e3d6000fd5b50505050816001600160a01b03167f732e331072fe280a520929e5f2cc76c223389ff57d32a4e278cfded03e6f1caa82604051612f9e9190614847565b60405180910390a2505b6000612fb3836116df565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612fe49086908590600401613fdf565b600060405180830381600087803b158015612ffe57600080fd5b505af1158015613012573d6000803e3d6000fd5b50505050826001600160a01b03167fe9ac2dcd83e719358f1dc0c5c80491937f67d4ec61ef62c262bbe3b78578f92a8260405161304f9190614847565b60405180910390a250505050565b6001600160a01b0382166000908152600e60205260409020819055806130e8576001600160a01b0382166000818152600f60205260408082208281556001810183905560028101839055600301829055517fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e45916130db91819061403c565b60405180910390a2610c42565b6011546010546001600160801b03600160801b80840482166000818152601360209081526040808320978616808452978252808320546001600160a01b038b16808552600f90935292819020600181018890556002810184905560030180546001600160801b0319168917909616948402949094179094559151909392907fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e4590613195908590859061403c565b60405180910390a2505050505050565b6001600160a01b0382166000908152600b6020526040902081905580613243576001600160a01b0382166000818152600b60209081526040808320600190810180546001600160a01b0319169055600c909252808320838155918201839055600282018390556003909101829055517f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a916130db918190819061404a565b6011546010546001600160801b03600160801b8084048216600081815260126020908152604080832097861680845297825280832054848452601383528184208985528352818420546001600160a01b038c16808652600c90945293829020600181018990558181556002810185905560030180546001600160801b0319168a1790971695850295909517909555935191949390917f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a906133099086908690869061404a565b60405180910390a250505050505050565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561336057600080fd5b505af1158015613374573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133989190613d9e565b90506000600760009054906101000a90046001600160a01b03166001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ea57600080fd5b505afa1580156133fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134229190613c36565b600554604051630d293c7160e41b81529192506000916001600160a01b039091169063d293c7109061345a9085908790600401613fdf565b60206040518083038186803b15801561347257600080fd5b505afa158015613486573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134aa9190613d9e565b9050600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156134fa57600080fd5b505afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135329190613d9e565b8110156112995760405162461bcd60e51b815260040161089590614758565b600081831061356057816108c5565b5090919050565b8061357157610c42565b600654604051631062c15f60e11b81526001600160a01b03909116906320c582be906135a590309086908690600401613f7a565b600060405180830381600087803b1580156135bf57600080fd5b505af11580156135d3573d6000803e3d6000fd5b50505050610c4281613851565b6001600160a01b0381166136065760405162461bcd60e51b81526004016108959061419f565b8161361057610c42565b600954600090613626908463ffffffff612a6516565b9050806009819055506000805160206149028339815191528160405161364c9190614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123384604051613685929190613fdf565b60405180910390a16000336001600160a01b0316846040516136a690613f23565b60006040518083038185875af1925050503d80600081146136e3576040519150601f19603f3d011682016040523d82523d6000602084013e6136e8565b606091505b50509050806137095760405162461bcd60e51b8152600401610895906143b2565b50505050565b600a5480158061371d575081155b156137285750610b33565b60006137348383613aff565b9050600061374d60105483612b3390919063ffffffff16565b6011546001600160801b03600160801b820481166000908152601360209081526040808320939094168252919091522054909150613791908263ffffffff6108a016565b601180546001600160801b03600160801b80830482166000908152601360208181526040808420968616845295815285832097909755945491820483168082529486528381209190921680835294528190205490517f2d6127771b164a9cc8827d24b5955db2a77e7a81dac389107ebb8bce9fb64968936138129391614877565b60405180910390a150505050565b60008282016001600160801b0380851690821610156108c55760405162461bcd60e51b815260040161089590614713565b600a54600090613867908363ffffffff612a6516565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c78160405161389f9190614847565b60405180910390a15050565b6000826001600160801b0316826001600160801b031611156138df5760405162461bcd60e51b8152600401610895906146cb565b50900390565b6001600160a01b0381166000908152600d602052604090206001015460ff168061391657506001600160a01b038116155b610b335760405162461bcd60e51b8152600401610895906141ec565b60008111610b335760405162461bcd60e51b8152600401610895906144d7565b6001600160a01b038281166000818152600b602052604080822060010180546001600160a01b0319169486169485179055517f094c08e96a8890877a8390b4f967180a7507ad8622244d05fcd0f9f8e086564e9190a35050565b600654604051632ee65eeb60e21b81526001600160a01b039091169063bb997bac906139e090859030908690600401613f7a565b600060405180830381600087803b1580156139fa57600080fd5b505af1158015613a0e573d6000803e3d6000fd5b5050600a5460009250613a2891508363ffffffff6108a016565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c781604051610ac19190614847565b610b3381336135e0565b60008184841115613a8e5760405162461bcd60e51b81526004016108959190614060565b505050900390565b60008183613ab75760405162461bcd60e51b81526004016108959190614060565b506000838581613ac357fe5b0495945050505050565b613ad5613ba5565b613add613ba5565b5050604080518082019091526001600160a01b03929092168252602082015290565b600080613b23601454611e8b670de0b6b3a764000087612b3390919063ffffffff16565b90506000613b37828563ffffffff612b6d16565b9050613b59613b4c828663ffffffff612b3316565b839063ffffffff612a6516565b601455949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b604080518082019091526000808252602082015290565b60008083601f840112613bcd578182fd5b50813567ffffffffffffffff811115613be4578182fd5b602083019150836020828501011115613bfc57600080fd5b9250929050565b80356001600160801b03811681146108c857600080fd5b600060208284031215613c2b578081fd5b81356108c5816148ec565b600060208284031215613c47578081fd5b81516108c5816148ec565b60008060408385031215613c64578081fd5b8235613c6f816148ec565b91506020830135613c7f816148ec565b809150509250929050565b600080600080600080600080610100898b031215613ca6578384fd5b8835613cb1816148ec565b97506020890135613cc1816148ec565b96506040890135613cd1816148ec565b95506060890135613ce1816148ec565b94506080890135613cf1816148ec565b935060a0890135613d01816148ec565b925060c0890135613d11816148ec565b915060e0890135613d21816148ec565b809150509295985092959890939650565b600060208284031215613d43578081fd5b815180151581146108c5578182fd5b60008060408385031215613d64578182fd5b613d6e8484613c03565b9150613d7d8460208501613c03565b90509250929050565b600060208284031215613d97578081fd5b5035919050565b600060208284031215613daf578081fd5b5051919050565b60008060408385031215613dc8578182fd5b823591506020830135613c7f816148ec565b60008082840360a0811215613ded578283fd5b833592506080601f1982011215613e02578182fd5b506020830190509250929050565b60008060008084860360c0811215613e26578485fd5b85359450601f1981016080811215613e3c578485fd5b613e4660606148c5565b91506040811215613e55578485fd5b50613e6060406148c5565b6020870135613e6e816148ec565b80825250604087013560208201528082525060608601356020820152608086013560408201528093505060a085013567ffffffffffffffff811115613eb1578283fd5b613ebd87828801613bbc565b95989497509550505050565b60008060408385031215613edb578182fd5b50508035926020909101359150565b600060208284031215613efb578081fd5b813560ff811681146108c5578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b6000602080835283518082850152825b8181101561408c57858101830151858201604001528201614070565b8181111561409d5783604083870101525b50601f01601f1916929092016040019392505050565b60208082526046908201527f53746162696c697479506f6f6c3a2063616c6c6572206d75737420686176652060408201527f616e206163746976652074726f766520746f207769746864726177204554484760608201526561696e20746f60d01b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252602d908201527f53503a3a5f73656e644554484761696e546f3a205f726563656976657220697360408201526c207a65726f206164647265737360981b606082015260800190565b60208082526046908201527f53746162696c697479506f6f6c3a20546167206d75737420626520612072656760408201527f697374657265642066726f6e7420656e642c206f7220746865207a65726f206160608201526564647265737360d01b608082015260a00190565b60208082526027908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f74204163746040820152661a5d99541bdbdb60ca1b606082015260800190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526031908201527f53746162696c697479506f6f6c3a2063616c6c6572206d7573742068617665206040820152703737b716bd32b9379022aa241023b0b4b760791b606082015260800190565b60208082526029908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f742054726f6040820152683b32a6b0b730b3b2b960b91b606082015260800190565b60208082526021908201527f53746162696c697479506f6f6c3a2073656e64696e6720455448206661696c656040820152601960fa1b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526030908201527f53503a3a5f776974686472617746726f6d5370546f3a205f726563656976657260408201526f206973207a65726f206164647265737360801b606082015260800190565b60208082526033908201527f53746162696c697479506f6f6c3a204b69636b6261636b2072617465206d75736040820152727420626520696e2072616e6765205b302c315d60681b606082015260800190565b60208082526026908201527f53746162696c697479506f6f6c3a20416d6f756e74206d757374206265206e6f6040820152656e2d7a65726f60d01b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526039908201527f53746162696c697479506f6f6c3a206d757374206e6f7420616c72656164792060408201527818994818481c9959da5cdd195c995908199c9bdb9d08195b99603a1b606082015260800190565b60208082526028908201527f53746162696c697479506f6f6c3a2055736572206d7573742068617665206e6f6040820152670819195c1bdcda5d60c21b606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526030908201527f53746162696c697479506f6f6c3a2055736572206d757374206861766520612060408201526f1b9bdb8b5e995c9bc819195c1bdcda5d60821b606082015260800190565b60208082526028908201527f4c697175697479536166654d6174683132383a207375627472616374696f6e206040820152676f766572666c6f7760c01b606082015260800190565b60208082526025908201527f4c697175697479536166654d6174683132383a206164646974696f6e206f766560408201526472666c6f7760d81b606082015260800190565b60208082526044908201527f53746162696c697479506f6f6c3a2043616e6e6f74207769746864726177207760408201527f68696c65207468657265206172652074726f766573207769746820494352203c6060820152631026a1a960e11b608082015260a00190565b60006101006147d2838951613f0b565b60208801516040840152604088015160608401526147f36080840188613f0b565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b6001600160801b0391909116815260200190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9182521515602082015260400190565b9283526001600160801b03918216602084015216604082015260600190565b948552602085019390935260408401919091526001600160801b03908116606084015216608082015260a00190565b60405181810167ffffffffffffffff811182821017156148e457600080fd5b604052919050565b6001600160a01b0381168114610b3357600080fdfeceb6d671277d4354fd29977ada70695fbd93a16612abf765d6b0e25c28dc6db3bce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c951457222ebca92c335c9c86e2baa1cc0e40ffaa9084a51452980d5ba8dec2f6399920012339b5a3368d3a04b8606ce412c46ed92b7dcd8602d41fc8862cb8f25a2646970667358221220b12079f570461c3902a02d925635ecefb92e70f4556abddd99509e1ecfffdece64736f6c634300060b0033", + "deployedBytecode": "0x6080604052600436106102ad5760003560e01c806382e0a57411610165578063b31ee965116100cc578063de13da3c11610085578063de13da3c14610788578063df9cd84f146107a8578063e49d3667146107c8578063ec9f7d46146107e8578063fc7e286d146107fd578063fce6b7341461082b578063fda0101a1461084b576102f8565b8063b31ee965146106f4578063bdaf37ea14610709578063c3a34a0e1461071e578063ce4b5bbe1461073e578063d733cfd014610753578063d7fb044314610773576102f8565b80639f0706701161011e5780639f07067014610665578063a20baee614610531578063a3f4df7e1461067a578063a4e59ac81461069c578063a7bfff97146106b1578063ae918754146106df576102f8565b806382e0a574146105d157806386da0824146105f1578063887105d314610611578063893d20e8146106265780638b8fbd921461063b57806395fb16bb14610650576102f8565b80633d83908a1161021457806372fe25aa116101cd57806372fe25aa14610531578063741bef1a14610546578063759b30341461055b578063766718081461057057806377553ad414610592578063795d26c3146105a75780637f7dde4a146105bc576102f8565b80633d83908a1461048757806340ed1afd1461049c578063556be101146104bc5780635d2de642146104dc5780635f788d65146104fc57806370f1b5721461051c576102f8565b80632199b66f116102665780632199b66f146103d257806328a0a04d146103f25780632e54bf9514610412578063335525ad14610432578063389e92a5146104525780633cc7422514610472576102f8565b80630fbfe38b146102fd57806312261ee71461031f57806313af40351461034a57806314f6c3be1461036a57806316b9d3c51461038c5780631bf43555146103bd576102f8565b366102f8576102ba61086b565b6009546102cd903463ffffffff6108a016565b6009819055604051600080516020614902833981519152916102ee91614847565b60405180910390a1005b600080fd5b34801561030957600080fd5b5061031d610318366004613d86565b6108ce565b005b34801561032b57600080fd5b50610334610ace565b6040516103419190613f43565b60405180910390f35b34801561035657600080fd5b5061031d610365366004613c1a565b610af2565b34801561037657600080fd5b5061037f610b36565b6040516103419190614847565b34801561039857600080fd5b506103ac6103a7366004613c1a565b610b3c565b604051610341959493929190614896565b3480156103c957600080fd5b5061037f610b77565b3480156103de57600080fd5b5061031d6103ed366004613c1a565b610b84565b3480156103fe57600080fd5b5061037f61040d366004613d52565b610c1b565b34801561041e57600080fd5b5061031d61042d366004613d86565b610c38565b34801561043e57600080fd5b5061031d61044d366004613ec9565b610c46565b34801561045e57600080fd5b5061037f61046d366004613c1a565b610ca9565b34801561047e57600080fd5b50610334610d51565b34801561049357600080fd5b50610334610d60565b3480156104a857600080fd5b5061037f6104b7366004613c1a565b610d6f565b3480156104c857600080fd5b5061031d6104d7366004613d86565b610e0c565b3480156104e857600080fd5b5061037f6104f7366004613c1a565b610e84565b34801561050857600080fd5b5061031d610517366004613db6565b610e96565b34801561052857600080fd5b5061037f610ea0565b34801561053d57600080fd5b5061037f610ea6565b34801561055257600080fd5b50610334610eb2565b34801561056757600080fd5b5061037f610ec1565b34801561057c57600080fd5b50610585610ece565b6040516103419190614833565b34801561059e57600080fd5b50610334610ee4565b3480156105b357600080fd5b5061037f610ef3565b3480156105c857600080fd5b50610334611012565b3480156105dd57600080fd5b5061037f6105ec366004613d52565b611021565b3480156105fd57600080fd5b506103ac61060c366004613c1a565b61103e565b34801561061d57600080fd5b5061037f611079565b34801561063257600080fd5b50610334611148565b34801561064757600080fd5b5061037f611167565b34801561065c57600080fd5b5061033461116d565b34801561067157600080fd5b5061033461117c565b34801561068657600080fd5b5061068f61118b565b6040516103419190614060565b3480156106a857600080fd5b506105856111b4565b3480156106bd57600080fd5b506106d16106cc366004613c1a565b6111c3565b604051610341929190614867565b3480156106eb57600080fd5b506103346111df565b34801561070057600080fd5b5061037f6111ee565b34801561071557600080fd5b5061037f6111f4565b34801561072a57600080fd5b5061031d610739366004613dda565b6111fa565b34801561074a57600080fd5b5061037f61129e565b34801561075f57600080fd5b5061031d61076e366004613c8a565b6112a6565b34801561077f57600080fd5b5061037f611538565b34801561079457600080fd5b5061037f6107a3366004613c1a565b61153e565b3480156107b457600080fd5b5061037f6107c3366004613c1a565b611642565b3480156107d457600080fd5b5061037f6107e3366004613c1a565b6116df565b3480156107f457600080fd5b506103346117dc565b34801561080957600080fd5b5061081d610818366004613c1a565b6117eb565b604051610341929190614850565b34801561083757600080fd5b5061031d610846366004613e10565b61180d565b34801561085757600080fd5b5061031d610866366004613c52565b6118cd565b6000546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614258565b60405180910390fd5b565b6000828201838110156108c55760405162461bcd60e51b815260040161089590614168565b90505b92915050565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561091e57600080fd5b505afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613c36565b905060006109648330611b13565b60065460405163095ea7b360e01b81529192506001600160a01b03169063095ea7b3906109979085908590600401613fdf565b602060405180830381600087803b1580156109b157600080fd5b505af11580156109c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e99190613d32565b610a055760405162461bcd60e51b8152600401610895906145ef565b60065460405163438b1b4b60e01b81526001600160a01b038481169263438b1b4b92610a3b929091169085903390600401614019565b602060405180830381600087803b158015610a5557600080fd5b505af1158015610a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8d9190613d9e565b507f2b0fbec1c4e7e30517f196a714775ffe72770d2348f5d586854bb3c0fdf41df8338483604051610ac193929190613ff8565b60405180910390a1505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b610afa611148565b6001600160a01b0316336001600160a01b031614610b2a5760405162461bcd60e51b81526004016108959061451d565b610b3381611cde565b50565b60095490565b600f602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6809c2007651b250000081565b610b8c611148565b6001600160a01b0316336001600160a01b031614610bbc5760405162461bcd60e51b81526004016108959061451d565b610bc581611d69565b600880546001600160a01b0319166001600160a01b0383161790556040517f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac681190610c10908390613f43565b60405180910390a150565b601260209081526000928352604080842090915290825290205481565b610c428133611b13565b5050565b610c4e611dae565b600a54801580610c5c575082155b15610c675750610c42565b600854610c7c906001600160a01b0316611dd8565b600080610c8a848685611e65565b91509150610c988282611f5e565b610ca2848661225f565b5050505050565b6001600160a01b0381166000908152600b602052604081205480610cd1576000915050610d4c565b610cd9613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612395565b93505050505b919050565b6001546001600160a01b031681565b6005546001600160a01b031681565b6001600160a01b0381166000908152600b602052604081205480610d97576000915050610d4c565b610d9f613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b610e1533612582565b610e1e336125be565b610e27816125f5565b336000818152600d6020526040908190208381556001908101805460ff19169091179055517f19bc932fb9e16a8b5a1e41be9f4c2de59d5ddd7567b8b81405f532ca00a9880e90610e79908490614847565b60405180910390a250565b600e6020526000908152604090205481565b610c42828261261d565b60145481565b670de0b6b3a764000081565b6002546001600160a01b031681565b6801158e460913d0000081565b601154600160801b90046001600160801b031681565b6004546001600160a01b031681565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3757600080fd5b505afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b505afa158015610fd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff99190613d9e565b905061100b828263ffffffff6108a016565b9250505090565b6000546001600160a01b031681565b601360209081526000928352604080842090915290825290205481565b600c602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156110be57600080fd5b505afa1580156110d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f69190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b60008060405161115790613f26565b6040519081900390205492915050565b60105481565b6008546001600160a01b031681565b6003546001600160a01b031681565b6040518060400160405280600d81526020016c14dd18589a5b1a5d1e541bdbdb609a1b81525081565b6011546001600160801b031681565b600d602052600090815260409020805460019091015460ff1682565b6007546001600160a01b031681565b60165481565b600a5490565b600480546040805163e9fc346160e01b8152905160009361128c936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561124057600080fd5b505afa158015611254573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112789190613c36565b60065485906001600160a01b0316856127c0565b905061129981600061261d565b505050565b633b9aca0081565b6112ae611148565b6001600160a01b0316336001600160a01b0316146112de5760405162461bcd60e51b81526004016108959061451d565b6112e788611d69565b6112f087611d69565b6112f986611d69565b61130285611d69565b61130b84611d69565b61131483611d69565b61131d82611d69565b61132681611d69565b670de0b6b3a7640000601055600380546001600160a01b03199081166001600160a01b038b8116919091179092556004805482168a8416179055600580548216898416179055600080548216888416179055600680548216878416179055600780548216868416179055600280548216858416179055600880549091169183169190911790556040517f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed985906113dc908990613f43565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a5678866040516114139190613f43565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828560405161144a9190613f43565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d846040516114819190613f43565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800836040516114b89190613f43565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264826040516114ef9190613f43565b60405180910390a17f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac6811816040516115269190613f43565b60405180910390a15050505050505050565b60155481565b6001600160a01b0381166000908152600e602052604081205480611566576000915050610d4c565b6001600160a01b0383166000908152600d602052604081205490611598670de0b6b3a76400008363ffffffff612a6516565b90506115a2613b64565b506001600160a01b0385166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b869063ffffffff612b3316565b9063ffffffff612b6d16565b979650505050505050565b6001600160a01b0381166000908152600e60205260408120548061166a576000915050610d4c565b611672613b64565b506001600160a01b0383166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b6001600160a01b0381166000908152600b602052604081205480611707576000915050610d4c565b6001600160a01b038084166000908152600b602052604081206001015490911690811561174c576001600160a01b0382166000908152600d6020526040902054611756565b670de0b6b3a76400005b9050611760613b64565b506001600160a01b0385166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b6006546001600160a01b031681565b600b60205260009081526040902080546001909101546001600160a01b031682565b600480546040805163e9fc346160e01b815290516000936118c0936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561185357600080fd5b505afa158015611867573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188b9190613c36565b6006546001600160a01b0316867f00000000000000000000000000000000000000000000000000000000000000008787612baf565b9050610ca281600061261d565b336000908152600b60205260409020546118e681612dfc565b6118ef33612e1c565b6118f833612ebb565b6008546001600160a01b031661190d81611dd8565b600061191833610ca9565b9050600061192533610d6f565b90506000611939858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b039091169061196790869083612ee8565b600061197282611642565b90508061197f838261305d565b826001600160a01b031660008051602061496283398151915282336040516119a8929190614850565b60405180910390a26119ba33866131a5565b336001600160a01b031660008051602061494283398151915287866040516119e392919061403c565b60405180910390a2336001600160a01b031660008051602061492283398151915286604051611a129190614847565b60405180910390a2600954611a2d908763ffffffff612a6516565b600981905560405160008051602061490283398151915291611a4e91614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123387604051611a87929190613fdf565b60405180910390a1600460009054906101000a90046001600160a01b03166001600160a01b031663ea9638bf87338d8d6040518563ffffffff1660e01b8152600401611ad593929190613f57565b6000604051808303818588803b158015611aee57600080fd5b505af1158015611b02573d6000803e3d6000fd5b505050505050505050505050505050565b60006001600160a01b038216611b3b5760405162461bcd60e51b815260040161089590614434565b8215611b4957611b4961331a565b336000908152600b6020526040902054611b6281612dfc565b6008546001600160a01b0316611b7781611dd8565b6000611b8233610ca9565b90506000611b8f33610d6f565b90506000611b9d8883613551565b90506000611bb1868463ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b0390911690611bdf90879083612ee8565b6000611bea82611642565b90506000611bfe828663ffffffff612a6516565b9050611c0a838261305d565b826001600160a01b03166000805160206149628339815191528233604051611c33929190614850565b60405180910390a2611c458b86613567565b6000611c57878763ffffffff612a6516565b9050611c6333826131a5565b336001600160a01b031660008051602061492283398151915282604051611c8a9190614847565b60405180910390a2336001600160a01b03166000805160206149428339815191528987604051611cbb92919061403c565b60405180910390a2611ccd88336135e0565b50939b9a5050505050505050505050565b6001600160a01b038116611d045760405162461bcd60e51b81526004016108959061429f565b806001600160a01b0316611d16611148565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611d5990613f26565b6040519081900390209190915550565b6001600160a01b038116611d8f5760405162461bcd60e51b8152600401610895906142e1565b803b80610c425760405162461bcd60e51b815260040161089590614646565b6005546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614369565b600a54604051636cbdcf4760e01b81526000916001600160a01b03841691636cbdcf4791611e0891600401614847565b602060405180830381600087803b158015611e2257600080fd5b505af1158015611e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5a9190613d9e565b9050610c428161370f565b6000806000611e97601554611e8b670de0b6b3a764000089612b3390919063ffffffff16565b9063ffffffff6108a016565b905083851115611ea357fe5b83851415611ec0576000601655670de0b6b3a76400009150611f20565b601654600090611eee90611ee288670de0b6b3a764000063ffffffff612b3316565b9063ffffffff612a6516565b9050611f056001611e8b838863ffffffff612b6d16565b9250611f1b81611ee2858863ffffffff612b3316565b601655505b611f30818563ffffffff612b6d16565b9250611f52611f45848663ffffffff612b3316565b829063ffffffff612a6516565b60155550935093915050565b6010546000670de0b6b3a7640000831115611f7557fe5b6000611f8f670de0b6b3a76400008563ffffffff612a6516565b6011546001600160801b03600160801b820481166000818152601260209081526040808320949095168083529390529283205493945090929091611fd38988612b33565b90506000611fe7838363ffffffff6108a016565b6001600160801b038086166000908152601260209081526040808320938a168352929052819020829055519091507fe12e2cd2c9afa8069203ca07e7eff1edce4a075686d0736a8e7e0d593597b2079061204690839087908990614877565b60405180910390a18561211f5761206d6001600160801b038516600163ffffffff61382016565b601180546001600160801b03908116600160801b938216840217918290556040517fb50f0f59e7cb5b421dc77581c3a9919e3806e076e5fa78a874c3f120cb7d874d936120be930490911690614833565b60405180910390a1601180546001600160801b03191690556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9061210790600090614833565b60405180910390a1670de0b6b3a7640000965061220c565b633b9aca00612140670de0b6b3a764000061162b8b8a63ffffffff612b3316565b10156121ed57612176670de0b6b3a764000061162b633b9aca0061216a8c8b63ffffffff612b3316565b9063ffffffff612b3316565b96506121926001600160801b038616600163ffffffff61382016565b601180546001600160801b0319166001600160801b0392831617908190556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe926121e0921690614833565b60405180910390a161220c565b612209670de0b6b3a764000061162b8a8963ffffffff612b3316565b96505b6000871161221657fe5b60108790556040517fc1a9618cb59ebca77cbdbc2949f126823c407ff13edb285fd0262519a9c18e8c9061224b908990614847565b60405180910390a150505050505050505050565b60005460405163121cbc4d60e11b81526001600160a01b03909116908190632439789a90612291908590600401614847565b600060405180830381600087803b1580156122ab57600080fd5b505af11580156122bf573d6000803e3d6000fd5b505050506122cc82613851565b600654604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906122fe9030908690600401613fdf565b600060405180830381600087803b15801561231857600080fd5b505af115801561232c573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b03841692506364a197f3915061235e9030908790600401613fdf565b600060405180830381600087803b15801561237857600080fd5b505af115801561238c573d6000803e3d6000fd5b50505050505050565b6080810151606082015182516020808501516001600160801b038086166000908152601284526040808220928716825291909352822054919493929185906123e3908463ffffffff612a6516565b6001600160801b0380871660009081526012602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b6001600160801b031681526020810191909152604001600020549063ffffffff612b6d16565b90506000612478670de0b6b3a764000061162b868161246b888863ffffffff6108a016565b8f9063ffffffff612b3316565b9a9950505050505050505050565b6020810151606082015160808301516011546000939291906001600160801b03600160801b909104811690821610156124c557600093505050506108c8565b60115460009081906124e6906001600160801b03168563ffffffff6138ab16565b90506001600160801b0381166125165761250f8561162b6010548b612b3390919063ffffffff16565b915061254e565b806001600160801b0316600114156125495761250f633b9aca0061162b8761162b6010548d612b3390919063ffffffff16565b600091505b61256288633b9aca0063ffffffff612b6d16565b821015612577576000955050505050506108c8565b509695505050505050565b6001600160a01b0381166000908152600d602052604090206001015460ff1615610b335760405162461bcd60e51b81526004016108959061454e565b6001600160a01b0381166000908152600b60205260409020548015610c425760405162461bcd60e51b8152600401610895906145a7565b670de0b6b3a7640000811115610b335760405162461bcd60e51b815260040161089590614484565b612626816138e5565b61262f33612582565b61263882613932565b336000908152600b60205260409020546008546001600160a01b031661265d81611dd8565b8161266c5761266c3384613952565b600061267733610ca9565b9050600061268433610d6f565b90506000612698858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b03909116906126c690869083612ee8565b60006126d182611642565b905060006126e5828b63ffffffff6108a016565b90506126f1838261305d565b826001600160a01b0316600080516020614962833981519152823360405161271a929190614850565b60405180910390a261272c338b6139ac565b600061273e868c63ffffffff6108a016565b905061274a33826131a5565b336001600160a01b0316600080516020614922833981519152826040516127719190614847565b60405180910390a2336001600160a01b031660008051602061494283398151915288876040516127a292919061403c565b60405180910390a26127b387613a60565b5050505050505050505050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b1580156127fc57600080fd5b505afa158015612810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128349190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016128649190613f43565b60206040518083038186803b15801561287c57600080fd5b505afa158015612890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b49190613d9e565b9050306001600160a01b03831663605629d633838a89356128db60408c0160208d01613eea565b8b604001358c606001356040518863ffffffff1660e01b81526004016129079796959493929190613f9e565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b50505050866129ba83856001600160a01b03166370a08231856040518263ffffffff1660e01b815260040161296a9190613f43565b60206040518083038186803b15801561298257600080fd5b505afa158015612996573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee29190613d9e565b146129d75760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390612a079089908b903390600401614019565b602060405180830381600087803b158015612a2157600080fd5b505af1158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613d9e565b98975050505050505050565b60006108c583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a6a565b608081015160608201516040808401516020808601516001600160801b03808716600090815260138452858120918716815292529281205490949392908590612af6908463ffffffff612a6516565b6001600160801b0380871660009081526013602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b600082612b42575060006108c8565b82820282848281612b4f57fe5b04146108c55760405162461bcd60e51b8152600401610895906143f3565b60006108c583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613a96565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015612beb57600080fd5b505afa158015612bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c239190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612c539190613f43565b60206040518083038186803b158015612c6b57600080fd5b505afa158015612c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca39190613d9e565b87516020015190915030906001600160a01b0388166330f28b7a8a612cc88585613acd565b338b8b6040518663ffffffff1660e01b8152600401612ceb9594939291906147c2565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b5050505080612d4e84866001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161296a9190613f43565b14612d6b5760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390612d9b908d9085903390600401614019565b602060405180830381600087803b158015612db557600080fd5b505af1158015612dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ded9190613d9e565b9b9a5050505050505050505050565b60008111610b335760405162461bcd60e51b81526004016108959061467b565b6005546040516321e3780160e01b81526001600160a01b03909116906321e3780190612e4c908490600401613f43565b60206040518083038186803b158015612e6457600080fd5b505afa158015612e78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9c9190613d9e565b600114610b335760405162461bcd60e51b8152600401610895906140b3565b6000612ec682610ca9565b905060008111610c425760405162461bcd60e51b815260040161089590614318565b6001600160a01b03811615612fa8576000612f028261153e565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612f339085908590600401613fdf565b600060405180830381600087803b158015612f4d57600080fd5b505af1158015612f61573d6000803e3d6000fd5b50505050816001600160a01b03167f732e331072fe280a520929e5f2cc76c223389ff57d32a4e278cfded03e6f1caa82604051612f9e9190614847565b60405180910390a2505b6000612fb3836116df565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612fe49086908590600401613fdf565b600060405180830381600087803b158015612ffe57600080fd5b505af1158015613012573d6000803e3d6000fd5b50505050826001600160a01b03167fe9ac2dcd83e719358f1dc0c5c80491937f67d4ec61ef62c262bbe3b78578f92a8260405161304f9190614847565b60405180910390a250505050565b6001600160a01b0382166000908152600e60205260409020819055806130e8576001600160a01b0382166000818152600f60205260408082208281556001810183905560028101839055600301829055517fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e45916130db91819061403c565b60405180910390a2610c42565b6011546010546001600160801b03600160801b80840482166000818152601360209081526040808320978616808452978252808320546001600160a01b038b16808552600f90935292819020600181018890556002810184905560030180546001600160801b0319168917909616948402949094179094559151909392907fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e4590613195908590859061403c565b60405180910390a2505050505050565b6001600160a01b0382166000908152600b6020526040902081905580613243576001600160a01b0382166000818152600b60209081526040808320600190810180546001600160a01b0319169055600c909252808320838155918201839055600282018390556003909101829055517f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a916130db918190819061404a565b6011546010546001600160801b03600160801b8084048216600081815260126020908152604080832097861680845297825280832054848452601383528184208985528352818420546001600160a01b038c16808652600c90945293829020600181018990558181556002810185905560030180546001600160801b0319168a1790971695850295909517909555935191949390917f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a906133099086908690869061404a565b60405180910390a250505050505050565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561336057600080fd5b505af1158015613374573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133989190613d9e565b90506000600760009054906101000a90046001600160a01b03166001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ea57600080fd5b505afa1580156133fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134229190613c36565b600554604051630d293c7160e41b81529192506000916001600160a01b039091169063d293c7109061345a9085908790600401613fdf565b60206040518083038186803b15801561347257600080fd5b505afa158015613486573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134aa9190613d9e565b9050600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156134fa57600080fd5b505afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135329190613d9e565b8110156112995760405162461bcd60e51b815260040161089590614758565b600081831061356057816108c5565b5090919050565b8061357157610c42565b600654604051631062c15f60e11b81526001600160a01b03909116906320c582be906135a590309086908690600401613f7a565b600060405180830381600087803b1580156135bf57600080fd5b505af11580156135d3573d6000803e3d6000fd5b50505050610c4281613851565b6001600160a01b0381166136065760405162461bcd60e51b81526004016108959061419f565b8161361057610c42565b600954600090613626908463ffffffff612a6516565b9050806009819055506000805160206149028339815191528160405161364c9190614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123384604051613685929190613fdf565b60405180910390a16000336001600160a01b0316846040516136a690613f23565b60006040518083038185875af1925050503d80600081146136e3576040519150601f19603f3d011682016040523d82523d6000602084013e6136e8565b606091505b50509050806137095760405162461bcd60e51b8152600401610895906143b2565b50505050565b600a5480158061371d575081155b156137285750610b33565b60006137348383613aff565b9050600061374d60105483612b3390919063ffffffff16565b6011546001600160801b03600160801b820481166000908152601360209081526040808320939094168252919091522054909150613791908263ffffffff6108a016565b601180546001600160801b03600160801b80830482166000908152601360208181526040808420968616845295815285832097909755945491820483168082529486528381209190921680835294528190205490517f2d6127771b164a9cc8827d24b5955db2a77e7a81dac389107ebb8bce9fb64968936138129391614877565b60405180910390a150505050565b60008282016001600160801b0380851690821610156108c55760405162461bcd60e51b815260040161089590614713565b600a54600090613867908363ffffffff612a6516565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c78160405161389f9190614847565b60405180910390a15050565b6000826001600160801b0316826001600160801b031611156138df5760405162461bcd60e51b8152600401610895906146cb565b50900390565b6001600160a01b0381166000908152600d602052604090206001015460ff168061391657506001600160a01b038116155b610b335760405162461bcd60e51b8152600401610895906141ec565b60008111610b335760405162461bcd60e51b8152600401610895906144d7565b6001600160a01b038281166000818152600b602052604080822060010180546001600160a01b0319169486169485179055517f094c08e96a8890877a8390b4f967180a7507ad8622244d05fcd0f9f8e086564e9190a35050565b600654604051632ee65eeb60e21b81526001600160a01b039091169063bb997bac906139e090859030908690600401613f7a565b600060405180830381600087803b1580156139fa57600080fd5b505af1158015613a0e573d6000803e3d6000fd5b5050600a5460009250613a2891508363ffffffff6108a016565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c781604051610ac19190614847565b610b3381336135e0565b60008184841115613a8e5760405162461bcd60e51b81526004016108959190614060565b505050900390565b60008183613ab75760405162461bcd60e51b81526004016108959190614060565b506000838581613ac357fe5b0495945050505050565b613ad5613ba5565b613add613ba5565b5050604080518082019091526001600160a01b03929092168252602082015290565b600080613b23601454611e8b670de0b6b3a764000087612b3390919063ffffffff16565b90506000613b37828563ffffffff612b6d16565b9050613b59613b4c828663ffffffff612b3316565b839063ffffffff612a6516565b601455949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b604080518082019091526000808252602082015290565b60008083601f840112613bcd578182fd5b50813567ffffffffffffffff811115613be4578182fd5b602083019150836020828501011115613bfc57600080fd5b9250929050565b80356001600160801b03811681146108c857600080fd5b600060208284031215613c2b578081fd5b81356108c5816148ec565b600060208284031215613c47578081fd5b81516108c5816148ec565b60008060408385031215613c64578081fd5b8235613c6f816148ec565b91506020830135613c7f816148ec565b809150509250929050565b600080600080600080600080610100898b031215613ca6578384fd5b8835613cb1816148ec565b97506020890135613cc1816148ec565b96506040890135613cd1816148ec565b95506060890135613ce1816148ec565b94506080890135613cf1816148ec565b935060a0890135613d01816148ec565b925060c0890135613d11816148ec565b915060e0890135613d21816148ec565b809150509295985092959890939650565b600060208284031215613d43578081fd5b815180151581146108c5578182fd5b60008060408385031215613d64578182fd5b613d6e8484613c03565b9150613d7d8460208501613c03565b90509250929050565b600060208284031215613d97578081fd5b5035919050565b600060208284031215613daf578081fd5b5051919050565b60008060408385031215613dc8578182fd5b823591506020830135613c7f816148ec565b60008082840360a0811215613ded578283fd5b833592506080601f1982011215613e02578182fd5b506020830190509250929050565b60008060008084860360c0811215613e26578485fd5b85359450601f1981016080811215613e3c578485fd5b613e4660606148c5565b91506040811215613e55578485fd5b50613e6060406148c5565b6020870135613e6e816148ec565b80825250604087013560208201528082525060608601356020820152608086013560408201528093505060a085013567ffffffffffffffff811115613eb1578283fd5b613ebd87828801613bbc565b95989497509550505050565b60008060408385031215613edb578182fd5b50508035926020909101359150565b600060208284031215613efb578081fd5b813560ff811681146108c5578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b6000602080835283518082850152825b8181101561408c57858101830151858201604001528201614070565b8181111561409d5783604083870101525b50601f01601f1916929092016040019392505050565b60208082526046908201527f53746162696c697479506f6f6c3a2063616c6c6572206d75737420686176652060408201527f616e206163746976652074726f766520746f207769746864726177204554484760608201526561696e20746f60d01b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252602d908201527f53503a3a5f73656e644554484761696e546f3a205f726563656976657220697360408201526c207a65726f206164647265737360981b606082015260800190565b60208082526046908201527f53746162696c697479506f6f6c3a20546167206d75737420626520612072656760408201527f697374657265642066726f6e7420656e642c206f7220746865207a65726f206160608201526564647265737360d01b608082015260a00190565b60208082526027908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f74204163746040820152661a5d99541bdbdb60ca1b606082015260800190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526031908201527f53746162696c697479506f6f6c3a2063616c6c6572206d7573742068617665206040820152703737b716bd32b9379022aa241023b0b4b760791b606082015260800190565b60208082526029908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f742054726f6040820152683b32a6b0b730b3b2b960b91b606082015260800190565b60208082526021908201527f53746162696c697479506f6f6c3a2073656e64696e6720455448206661696c656040820152601960fa1b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526030908201527f53503a3a5f776974686472617746726f6d5370546f3a205f726563656976657260408201526f206973207a65726f206164647265737360801b606082015260800190565b60208082526033908201527f53746162696c697479506f6f6c3a204b69636b6261636b2072617465206d75736040820152727420626520696e2072616e6765205b302c315d60681b606082015260800190565b60208082526026908201527f53746162696c697479506f6f6c3a20416d6f756e74206d757374206265206e6f6040820152656e2d7a65726f60d01b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526039908201527f53746162696c697479506f6f6c3a206d757374206e6f7420616c72656164792060408201527818994818481c9959da5cdd195c995908199c9bdb9d08195b99603a1b606082015260800190565b60208082526028908201527f53746162696c697479506f6f6c3a2055736572206d7573742068617665206e6f6040820152670819195c1bdcda5d60c21b606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526030908201527f53746162696c697479506f6f6c3a2055736572206d757374206861766520612060408201526f1b9bdb8b5e995c9bc819195c1bdcda5d60821b606082015260800190565b60208082526028908201527f4c697175697479536166654d6174683132383a207375627472616374696f6e206040820152676f766572666c6f7760c01b606082015260800190565b60208082526025908201527f4c697175697479536166654d6174683132383a206164646974696f6e206f766560408201526472666c6f7760d81b606082015260800190565b60208082526044908201527f53746162696c697479506f6f6c3a2043616e6e6f74207769746864726177207760408201527f68696c65207468657265206172652074726f766573207769746820494352203c6060820152631026a1a960e11b608082015260a00190565b60006101006147d2838951613f0b565b60208801516040840152604088015160608401526147f36080840188613f0b565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b6001600160801b0391909116815260200190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9182521515602082015260400190565b9283526001600160801b03918216602084015216604082015260600190565b948552602085019390935260408401919091526001600160801b03908116606084015216608082015260a00190565b60405181810167ffffffffffffffff811182821017156148e457600080fd5b604052919050565b6001600160a01b0381168114610b3357600080fdfeceb6d671277d4354fd29977ada70695fbd93a16612abf765d6b0e25c28dc6db3bce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c951457222ebca92c335c9c86e2baa1cc0e40ffaa9084a51452980d5ba8dec2f6399920012339b5a3368d3a04b8606ce412c46ed92b7dcd8602d41fc8862cb8f25a2646970667358221220b12079f570461c3902a02d925635ecefb92e70f4556abddd99509e1ecfffdece64736f6c634300060b0033", + "implementation": "0xC959895CE6224dde0BdF7eb84519814dE23f2ee5" +} diff --git a/external/deployments/rskMainnet/StabilityPool_Implementation.json b/external/deployments/rskMainnet/StabilityPool_Implementation.json new file mode 100644 index 000000000..57a2363ea --- /dev/null +++ b/external/deployments/rskMainnet/StabilityPool_Implementation.json @@ -0,0 +1,1943 @@ +{ + "address": "0x2a1950a06AD5C5113e44721820305645d671eC4F", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newActivePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newBorrowerOperationsAddress", + "type": "address" + } + ], + "name": "BorrowerOperationsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newCommunityIssuanceAddress", + "type": "address" + } + ], + "name": "CommunityIssuanceAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newDefaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_S", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + } + ], + "name": "DepositSnapshotUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDLoss", + "type": "uint256" + } + ], + "name": "ETHGainWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint128", + "name": "_currentEpoch", + "type": "uint128" + } + ], + "name": "EpochUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "EtherSent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_kickbackRate", + "type": "uint256" + } + ], + "name": "FrontEndRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + } + ], + "name": "FrontEndSnapshotUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newFrontEndStake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "FrontEndStakeChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "FrontEndTagSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_epoch", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_scale", + "type": "uint128" + } + ], + "name": "G_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + } + ], + "name": "P_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_SOV", + "type": "uint256" + } + ], + "name": "SOVPaidToDepositor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_SOV", + "type": "uint256" + } + ], + "name": "SOVPaidToFrontEnd", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_S", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_epoch", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_scale", + "type": "uint128" + } + ], + "name": "S_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint128", + "name": "_currentScale", + "type": "uint128" + } + ], + "name": "ScaleUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newSortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newBalance", + "type": "uint256" + } + ], + "name": "StabilityPoolETHBalanceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newBalance", + "type": "uint256" + } + ], + "name": "StabilityPoolZUSDBalanceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newTroveManagerAddress", + "type": "address" + } + ], + "name": "TroveManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newDeposit", + "type": "uint256" + } + ], + "name": "UserDepositChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_zusdAmountRequested", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_dllrAmountReceived", + "type": "uint256" + } + ], + "name": "WithdrawFromSpAndConvertToDLLR", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newZUSDTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "P", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SCALE_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "borrowerOperations", + "outputs": [ + { + "internalType": "contract IBorrowerOperations", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "communityIssuance", + "outputs": [ + { + "internalType": "contract ICommunityIssuance", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentEpoch", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentScale", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "depositSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "S", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "P", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "G", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "scale", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "epoch", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "deposits", + "outputs": [ + { + "internalType": "uint256", + "name": "initialValue", + "type": "uint256" + }, + { + "internalType": "address", + "name": "frontEndTag", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "name": "epochToScaleToG", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "name": "epochToScaleToSum", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEndSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "S", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "P", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "G", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "scale", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "epoch", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEndStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEnds", + "outputs": [ + { + "internalType": "uint256", + "name": "kickbackRate", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "registered", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "getCompoundedFrontEndStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getCompoundedZUSDDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getDepositorETHGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getDepositorSOVGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getETH", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "getFrontEndSOVGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalZUSDDeposits", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastETHError_Offset", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastSOVError", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastZUSDLossError_Offset", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_debtToOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collToAdd", + "type": "uint256" + } + ], + "name": "offset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_frontEndTag", + "type": "address" + } + ], + "name": "provideToSP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "provideToSpFromDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "provideToSpFromDllrWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_kickbackRate", + "type": "uint256" + } + ], + "name": "registerFrontEnd", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_communityIssuanceAddress", + "type": "address" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_communityIssuanceAddress", + "type": "address" + } + ], + "name": "setCommunityIssuanceAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManager", + "outputs": [ + { + "internalType": "contract ITroveManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawETHGainToTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "withdrawFromSP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_zusdAmountRequested", + "type": "uint256" + } + ], + "name": "withdrawFromSpAndConvertToDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0xC959895CE6224dde0BdF7eb84519814dE23f2ee5", + "transactionIndex": 0, + "gasUsed": "5135892", + "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000040000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x26eb0b71917b7e14376847d8f22d8b657ac8a4a9756f9bace883ec60614ed674", + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748945, + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "address": "0xC959895CE6224dde0BdF7eb84519814dE23f2ee5", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x26eb0b71917b7e14376847d8f22d8b657ac8a4a9756f9bace883ec60614ed674" + } + ], + "blockNumber": 4748945, + "cumulativeGasUsed": "5135892", + "status": 1, + "byzantium": true + }, + "args": ["0x000000000022d473030f116ddee9f6b43ac78ba3"], + "numDeployments": 3, + "solcInputHash": "849fadfa265e27de6fba2f2d99bdf763", + "metadata": "{\"compiler\":{\"version\":\"0.6.11+commit.5ef660b1\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_permit2\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newActivePoolAddress\",\"type\":\"address\"}],\"name\":\"ActivePoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newBorrowerOperationsAddress\",\"type\":\"address\"}],\"name\":\"BorrowerOperationsAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newCommunityIssuanceAddress\",\"type\":\"address\"}],\"name\":\"CommunityIssuanceAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newDefaultPoolAddress\",\"type\":\"address\"}],\"name\":\"DefaultPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_P\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_S\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_G\",\"type\":\"uint256\"}],\"name\":\"DepositSnapshotUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ETH\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ZUSDLoss\",\"type\":\"uint256\"}],\"name\":\"ETHGainWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_currentEpoch\",\"type\":\"uint128\"}],\"name\":\"EpochUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"EtherSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_kickbackRate\",\"type\":\"uint256\"}],\"name\":\"FrontEndRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_P\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_G\",\"type\":\"uint256\"}],\"name\":\"FrontEndSnapshotUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newFrontEndStake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"}],\"name\":\"FrontEndStakeChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"}],\"name\":\"FrontEndTagSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_G\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_epoch\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_scale\",\"type\":\"uint128\"}],\"name\":\"G_Updated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_P\",\"type\":\"uint256\"}],\"name\":\"P_Updated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newPriceFeedAddress\",\"type\":\"address\"}],\"name\":\"PriceFeedAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_SOV\",\"type\":\"uint256\"}],\"name\":\"SOVPaidToDepositor\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_SOV\",\"type\":\"uint256\"}],\"name\":\"SOVPaidToFrontEnd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_S\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_epoch\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_scale\",\"type\":\"uint128\"}],\"name\":\"S_Updated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_currentScale\",\"type\":\"uint128\"}],\"name\":\"ScaleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newSortedTrovesAddress\",\"type\":\"address\"}],\"name\":\"SortedTrovesAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newBalance\",\"type\":\"uint256\"}],\"name\":\"StabilityPoolETHBalanceUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newBalance\",\"type\":\"uint256\"}],\"name\":\"StabilityPoolZUSDBalanceUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newTroveManagerAddress\",\"type\":\"address\"}],\"name\":\"TroveManagerAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newDeposit\",\"type\":\"uint256\"}],\"name\":\"UserDepositChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_zusdAmountRequested\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_dllrAmountReceived\",\"type\":\"uint256\"}],\"name\":\"WithdrawFromSpAndConvertToDLLR\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newZUSDTokenAddress\",\"type\":\"address\"}],\"name\":\"ZUSDTokenAddressChanged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DECIMAL_PRECISION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_NET_DEBT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"P\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SCALE_FACTOR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZUSD_GAS_COMPENSATION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_100pct\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activePool\",\"outputs\":[{\"internalType\":\"contract IActivePool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"borrowerOperations\",\"outputs\":[{\"internalType\":\"contract IBorrowerOperations\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"communityIssuance\",\"outputs\":[{\"internalType\":\"contract ICommunityIssuance\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentEpoch\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentScale\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultPool\",\"outputs\":[{\"internalType\":\"contract IDefaultPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"depositSnapshots\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"S\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"P\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"G\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"scale\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"epoch\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"deposits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"initialValue\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"frontEndTag\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"name\":\"epochToScaleToG\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"name\":\"epochToScaleToSum\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"frontEndSnapshots\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"S\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"P\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"G\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"scale\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"epoch\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"frontEndStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"frontEnds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"kickbackRate\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"registered\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"}],\"name\":\"getCompoundedFrontEndStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"}],\"name\":\"getCompoundedZUSDDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"}],\"name\":\"getDepositorETHGain\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"}],\"name\":\"getDepositorSOVGain\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getETH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemColl\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"}],\"name\":\"getFrontEndSOVGain\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalZUSDDeposits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastETHError_Offset\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastSOVError\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastZUSDLossError_Offset\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquityBaseParams\",\"outputs\":[{\"internalType\":\"contract ILiquityBaseParams\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_debtToOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_collToAdd\",\"type\":\"uint256\"}],\"name\":\"offset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceFeed\",\"outputs\":[{\"internalType\":\"contract IPriceFeed\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_frontEndTag\",\"type\":\"address\"}],\"name\":\"provideToSP\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"provideToSpFromDLLR\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"provideToSpFromDllrWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_kickbackRate\",\"type\":\"uint256\"}],\"name\":\"registerFrontEnd\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_liquityBaseParamsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_borrowerOperationsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_troveManagerAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_activePoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zusdTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_sortedTrovesAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_priceFeedAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_communityIssuanceAddress\",\"type\":\"address\"}],\"name\":\"setAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_communityIssuanceAddress\",\"type\":\"address\"}],\"name\":\"setCommunityIssuanceAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortedTroves\",\"outputs\":[{\"internalType\":\"contract ISortedTroves\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"troveManager\",\"outputs\":[{\"internalType\":\"contract ITroveManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"withdrawETHGainToTrove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdrawFromSP\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_zusdAmountRequested\",\"type\":\"uint256\"}],\"name\":\"withdrawFromSpAndConvertToDLLR\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zusdToken\",\"outputs\":[{\"internalType\":\"contract IZUSDToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getETH()\":{\"returns\":{\"_0\":\"the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`, to exclude edge cases like ETH received from a self-destruct.\"}},\"getOwner()\":{\"returns\":{\"_owner\":\"Address of the owner. \"}},\"getTotalZUSDDeposits()\":{\"returns\":{\"_0\":\"ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\"}},\"setAddresses(address,address,address,address,address,address,address,address)\":{\"details\":\"initializer function, checks addresses are contracts\",\"params\":{\"_activePoolAddress\":\"ActivePool contract address\",\"_borrowerOperationsAddress\":\"BorrowerOperations contract address\",\"_communityIssuanceAddress\":\"CommunityIssuanceAddress\",\"_liquityBaseParamsAddress\":\"LiquidityBaseParams contract address\",\"_priceFeedAddress\":\"PriceFeed contract address\",\"_sortedTrovesAddress\":\"SortedTroves contract address\",\"_troveManagerAddress\":\"TroveManager contract address\",\"_zusdTokenAddress\":\"ZUSDToken contract address\"}},\"setCommunityIssuanceAddress(address)\":{\"details\":\"setter function specific for community issuance contract.\",\"params\":{\"_communityIssuanceAddress\":\"address of new community issuance contract.\"}},\"setOwner(address)\":{\"params\":{\"_owner\":\"Address of the owner. \"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"MIN_NET_DEBT()\":{\"notice\":\"Minimum amount of net ZUSD debt a trove must have\"},\"ZUSD_GAS_COMPENSATION()\":{\"notice\":\"Amount of ZUSD to be locked in gas pool on opening troves\"},\"constructor\":\"Constructor \",\"getCompoundedFrontEndStake(address)\":{\"notice\":\"Return the front end's compounded stake. Given by the formula: D = D0 * P/P(0) where P(0) is the depositor's snapshot of the product P, taken at the last time when one of the front end's tagged deposits updated their deposit. The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\"},\"getCompoundedZUSDDeposit(address)\":{\"notice\":\"Return the user's compounded deposit. Given by the formula: d = d0 * P/P(0) where P(0) is the depositor's snapshot of the product P, taken when they last updated their deposit.\"},\"getDepositorETHGain(address)\":{\"notice\":\"Calculates the ETH gain earned by the deposit since its last snapshots were taken. Given by the formula: E = d0 * (S - S(0))/P(0) where S(0) and P(0) are the depositor's snapshots of the sum S and product P, respectively. d0 is the last recorded deposit value.\"},\"getDepositorSOVGain(address)\":{\"notice\":\"Calculate the SOV gain earned by a deposit since its last snapshots were taken. Given by the formula: SOV = d0 * (G - G(0))/P(0) where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively. d0 is the last recorded deposit value.\"},\"getFrontEndSOVGain(address)\":{\"notice\":\"Return the SOV gain earned by the front end. Given by the formula: E = D0 * (G - G(0))/P(0) where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively. D0 is the last recorded value of the front end's total tagged deposits.\"},\"getOwner()\":{\"notice\":\"Return address of the owner.\"},\"offset(uint256,uint256)\":{\"notice\":\"Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible) and transfers the Trove's ETH collateral from ActivePool to StabilityPool. Only called by liquidation functions in the TroveManager.\"},\"provideToSP(uint256,address)\":{\"notice\":\"provideToSP(): - Triggers a SOV issuance, based on time passed since the last issuance and total amount of deposited ZUSD. The SOV issuance is shared between *all* depositors and front ends - Tags the deposit with the provided front end tag param, if it's a new deposit - Sends depositor's accumulated gains (SOV, ETH) to depositor - Sends the tagged front end's accumulated SOV gains to the tagged front end - Increases deposit and tagged front end's stake, and takes new snapshots for each.\"},\"provideToSpFromDLLR(uint256,(uint256,uint8,bytes32,bytes32))\":{\"notice\":\"DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\"},\"provideToSpFromDllrWithPermit2(uint256,((address,uint256),uint256,uint256),bytes)\":{\"notice\":\"DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\"},\"registerFrontEnd(uint256)\":{\"notice\":\"Front end makes a one-time selection of kickback rate upon registering\"},\"setAddresses(address,address,address,address,address,address,address,address)\":{\"notice\":\"Called only once on init, to set addresses of other Liquity contracts. Callable only by owner\"},\"setOwner(address)\":{\"notice\":\"Set address of the owner (only owner can call this function)\"},\"withdrawETHGainToTrove(address,address)\":{\"notice\":\"withdrawETHGainToTrove: - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends - Sends all depositor's SOV gain to depositor - Sends all tagged front end's SOV gain to the tagged front end - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove - Leaves their compounded deposit in the Stability Pool - Updates snapshots for deposit and tagged front end stake \"},\"withdrawFromSP(uint256)\":{\"notice\":\"withdrawFromSP(): - Triggers a SOV issuance, based on time passed since the last issuance and total amount of ZUSD is deposited. The SOV issuance is shared between *all* depositors and front ends - Removes the deposit's front end tag if it is a full withdrawal - Sends all depositor's accumulated gains (SOV, ETH) to depositor - Sends the tagged front end's accumulated SOV gains to the tagged front end - Decreases deposit and tagged front end's stake, and takes new snapshots for each. If _amount > userDeposit, the user withdraws all of their compounded deposit.\"},\"withdrawFromSpAndConvertToDLLR(uint256)\":{\"notice\":\"Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\"}},\"notice\":\"The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors. When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned. Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits. They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors, in the same proportion. When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40% of the total ZUSD in the Stability Pool, depletes 40% of each deposit. A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit, multiplying it by some factor in range ]0,1[ --- IMPLEMENTATION --- We use a highly scalable method of tracking deposits and ETH gains that has O(1) complexity. When a liquidation occurs, rather than updating each depositor's deposit and ETH gain, we simply update two state variables: a product P, and a sum S. A mathematical manipulation allows us to factor out the initial deposit, and accurately track all depositors' compounded deposits and accumulated ETH gains over time, as liquidations occur, using just these two variables P and S. When depositors join the Stability Pool, they get a snapshot of the latest P and S: P_t and S_t, respectively. The formula for a depositor's accumulated ETH gain is derived here: https://github.com/liquity/dev/blob/main/packages/contracts/mathProofs/Scalable%20Compounding%20Stability%20Pool%20Deposits.pdf For a given deposit d_t, the ratio P/P_t tells us the factor by which a deposit has decreased since it joined the Stability Pool, and the term d_t * (S - S_t)/P_t gives us the deposit's total accumulated ETH gain. Each liquidation updates the product P and sum S. After a series of liquidations, a compounded deposit and corresponding ETH gain can be calculated using the initial deposit, the depositor\\u2019s snapshots of P and S, and the latest values of P and S. Any time a depositor updates their deposit (withdrawal, top-up) their accumulated ETH gain is paid out, their new deposit is recorded (based on their latest compounded deposit and modified by the withdrawal/top-up), and they receive new snapshots of the latest P and S. Essentially, they make a fresh deposit that overwrites the old one. --- SCALE FACTOR --- Since P is a running product in range ]0,1] that is always-decreasing, it should never reach 0 when multiplied by a number in range ]0,1[. Unfortunately, Solidity floor division always reaches 0, sooner or later. A series of liquidations that nearly empty the Pool (and thus each multiply P by a very small number in range ]0,1[ ) may push P to its 18 digit decimal limit, and round it to 0, when in fact the Pool hasn't been emptied: this would break deposit tracking. So, to track P accurately, we use a scale factor: if a liquidation would cause P to decrease to <1e-9 (and be rounded to 0 by Solidity), we first multiply P by 1e9, and increment a currentScale factor by 1. The added benefit of using 1e9 for the scale factor (rather than 1e18) is that it ensures negligible precision loss close to the scale boundary: when P is at its minimum value of 1e9, the relative precision loss in P due to floor division is only on the order of 1e-9. --- EPOCHS --- Whenever a liquidation fully empties the Stability Pool, all deposits should become 0. However, setting P to 0 would make P be 0 forever, and break all future reward calculations. So, every time the Stability Pool is emptied by a liquidation, we reset P = 1 and currentScale = 0, and increment the currentEpoch by 1. --- TRACKING DEPOSIT OVER SCALE CHANGES AND EPOCHS --- When a deposit is made, it gets snapshots of the currentEpoch and the currentScale. When calculating a compounded deposit, we compare the current epoch to the deposit's epoch snapshot. If the current epoch is newer, then the deposit was present during a pool-emptying liquidation, and necessarily has been depleted to 0. Otherwise, we then compare the current scale to the deposit's scale snapshot. If they're equal, the compounded deposit is given by d_t * P/P_t. If it spans one scale change, it is given by d_t * P/(P_t * 1e9). If it spans more than one scale change, we define the compounded deposit as 0, since it is now less than 1e-9'th of its initial value (e.g. a deposit of 1 billion ZUSD has depleted to < 1 ZUSD). --- TRACKING DEPOSITOR'S ETH GAIN OVER SCALE CHANGES AND EPOCHS --- In the current epoch, the latest value of S is stored upon each scale change, and the mapping (scale -> S) is stored for each epoch. This allows us to calculate a deposit's accumulated ETH gain, during the epoch in which the deposit was non-zero and earned ETH. We calculate the depositor's accumulated ETH gain for the scale at which they made the deposit, using the ETH gain formula: e_1 = d_t * (S - S_t) / P_t and also for scale after, taking care to divide the latter by a factor of 1e9: e_2 = d_t * S / (P_t * 1e9) The gain in the second scale will be full, as the starting point was in the previous scale, thus no need to subtract anything. The deposit therefore was present for reward events from the beginning of that second scale. S_i-S_t + S_{i+1} .<--------.------------> . . . S_i . S_{i+1} <--.-------->.<-----------> S_t. . <->. . t . |---+---------|-------------|-----... i i+1 The sum of (e_1 + e_2) captures the depositor's total accumulated ETH gain, handling the case where their deposit spanned one scale change. We only care about gains across one scale change, since the compounded deposit is defined as being 0 once it has spanned more than one scale change. --- UPDATING P WHEN A LIQUIDATION OCCURS --- Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations: https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS --- An SOV issuance event occurs at every deposit operation, and every liquidation. Each deposit is tagged with the address of the front end through which it was made. All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate. Please see the system Readme for an overview: https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers We use the same mathematical product-sum approach to track SOV gains for depositors, where 'G' is the sum corresponding to SOV gains. The product P (and snapshot P_t) is re-used, as the ratio P/P_t tracks a deposit's depletion due to liquidations.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/StabilityPool.sol\":\"StabilityPool\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"contracts/Dependencies/BaseMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\n\\ncontract BaseMath {\\n uint constant public DECIMAL_PRECISION = 1e18;\\n}\\n\",\"keccak256\":\"0x7e1369ca5cb09e818e345a2def19a261401f79c985a6030b55b7311dd6f53be4\",\"license\":\"MIT\"},\"contracts/Dependencies/CheckContract.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n\\ncontract CheckContract {\\n /**\\n * @dev Check that the account is an already deployed non-destroyed contract.\\n * See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L12\\n */\\n function checkContract(address _account) internal view {\\n require(_account != address(0), \\\"Account cannot be zero address\\\");\\n\\n uint256 size;\\n // solhint-disable-next-line no-inline-assembly\\n assembly { size := extcodesize(_account) }\\n require(size > 0, \\\"Account code size cannot be zero\\\");\\n }\\n}\\n\",\"keccak256\":\"0x4c7dc4d0197c27ebc7de671b00458a9ff45f57223aeb520e6ddd2eb6d2d89e5c\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on the OpenZeppelin IER20 interface:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol\\n *\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\\n function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n function name() external view returns (string memory);\\n function symbol() external view returns (string memory);\\n function decimals() external view returns (uint8);\\n \\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\",\"keccak256\":\"0xe0b2473eba89df8d27d7cea2a99fce788c212f3fd393c9508e449e51a3f220fa\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC2612.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * @dev Interface of the ERC2612 standard as defined in the EIP.\\n *\\n * Adds the {permit} method, which can be used to change one's\\n * {IERC20-allowance} without having to send a transaction, by signing a\\n * message. This allows users to spend tokens without having to hold Ether.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2612.\\n * \\n * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/\\n */\\ninterface IERC2612 {\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,\\n * given `owner`'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(address owner, address spender, uint256 amount, \\n uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;\\n \\n /**\\n * @dev Returns the current ERC2612 nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases `owner`'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n *\\n * `owner` can limit the time a Permit is valid for by setting `deadline` to \\n * a value in the near future. The deadline argument can be set to uint(-1) to \\n * create Permits that effectively never expire.\\n */\\n function nonces(address owner) external view returns (uint256);\\n \\n function version() external view returns (string memory);\\n function permitTypeHash() external view returns (bytes32);\\n function domainSeparator() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xd376458452f8b480bfea549637bd71d3f9eb1f12e9d59d1beff373417462d67f\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./BaseMath.sol\\\";\\nimport \\\"./LiquityMath.sol\\\";\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IPriceFeed.sol\\\";\\nimport \\\"../Interfaces/ILiquityBase.sol\\\";\\nimport \\\"../Interfaces/ILiquityBaseParams.sol\\\";\\n\\n/**\\n * Base contract for TroveManager, BorrowerOperations and StabilityPool. Contains global system constants and\\n * common functions.\\n */\\ncontract LiquityBase is BaseMath, ILiquityBase {\\n using SafeMath for uint256;\\n\\n uint256 public constant _100pct = 1000000000000000000; // 1e18 == 100%\\n\\n /// Amount of ZUSD to be locked in gas pool on opening troves\\n uint256 public constant ZUSD_GAS_COMPENSATION = 20e18;\\n\\n /// Minimum amount of net ZUSD debt a trove must have\\n uint256 public constant MIN_NET_DEBT = 180e18;\\n\\n IActivePool public activePool;\\n\\n IDefaultPool public defaultPool;\\n\\n IPriceFeed public override priceFeed;\\n\\n ILiquityBaseParams public override liquityBaseParams;\\n\\n // --- Gas compensation functions ---\\n\\n // Returns the composite debt (drawn debt + gas compensation) of a trove, for the purpose of ICR calculation\\n function _getCompositeDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.add(ZUSD_GAS_COMPENSATION);\\n }\\n\\n function _getNetDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.sub(ZUSD_GAS_COMPENSATION);\\n }\\n\\n /// Return the amount of ETH to be drawn from a trove's collateral and sent as gas compensation.\\n function _getCollGasCompensation(uint256 _entireColl) internal view returns (uint256) {\\n return _entireColl / liquityBaseParams.PERCENT_DIVISOR();\\n }\\n\\n function getEntireSystemColl() public view returns (uint256 entireSystemColl) {\\n uint256 activeColl = activePool.getETH();\\n uint256 liquidatedColl = defaultPool.getETH();\\n\\n return activeColl.add(liquidatedColl);\\n }\\n\\n function getEntireSystemDebt() public view returns (uint256 entireSystemDebt) {\\n uint256 activeDebt = activePool.getZUSDDebt();\\n uint256 closedDebt = defaultPool.getZUSDDebt();\\n\\n return activeDebt.add(closedDebt);\\n }\\n\\n function _getTCR(uint256 _price) internal view returns (uint256 TCR) {\\n uint256 entireSystemColl = getEntireSystemColl();\\n uint256 entireSystemDebt = getEntireSystemDebt();\\n\\n TCR = LiquityMath._computeCR(entireSystemColl, entireSystemDebt, _price);\\n\\n return TCR;\\n }\\n\\n function _checkRecoveryMode(uint256 _price) internal view returns (bool) {\\n uint256 TCR = _getTCR(_price);\\n\\n return TCR < liquityBaseParams.CCR();\\n }\\n\\n function _requireUserAcceptsFee(\\n uint256 _fee,\\n uint256 _amount,\\n uint256 _maxFeePercentage\\n ) internal pure {\\n uint256 feePercentage = _fee.mul(DECIMAL_PRECISION).div(_amount);\\n require(feePercentage <= _maxFeePercentage, \\\"Fee exceeded provided maximum\\\");\\n }\\n}\\n\",\"keccak256\":\"0x100b8a1c17caa95f5c9977e88f9263847a1977a365ca0a795753dd74aa1d6d7c\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./console.sol\\\";\\n\\nlibrary LiquityMath {\\n using SafeMath for uint;\\n\\n uint internal constant DECIMAL_PRECISION = 1e18;\\n\\n /* Precision for Nominal ICR (independent of price). Rationale for the value:\\n *\\n * - Making it \\u201ctoo high\\u201d could lead to overflows.\\n * - Making it \\u201ctoo low\\u201d could lead to an ICR equal to zero, due to truncation from Solidity floor division. \\n *\\n * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH,\\n * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.\\n *\\n */\\n uint internal constant NICR_PRECISION = 1e20;\\n\\n function _min(uint _a, uint _b) internal pure returns (uint) {\\n return (_a < _b) ? _a : _b;\\n }\\n\\n function _max(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a : _b;\\n }\\n\\n /* \\n * Multiply two decimal numbers and use normal rounding rules:\\n * -round product up if 19'th mantissa digit >= 5\\n * -round product down if 19'th mantissa digit < 5\\n *\\n * Used only inside the exponentiation, _decPow().\\n */\\n function decMul(uint x, uint y) internal pure returns (uint decProd) {\\n uint prod_xy = x.mul(y);\\n\\n decProd = prod_xy.add(DECIMAL_PRECISION / 2).div(DECIMAL_PRECISION);\\n }\\n\\n /* \\n * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.\\n * \\n * Uses the efficient \\\"exponentiation by squaring\\\" algorithm. O(log(n)) complexity. \\n * \\n * Called by two functions that represent time in units of minutes:\\n * 1) TroveManager._calcDecayedBaseRate\\n * 2) CommunityIssuance._getCumulativeIssuanceFraction \\n * \\n * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals\\n * \\\"minutes in 1000 years\\\": 60 * 24 * 365 * 1000\\n * \\n * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be\\n * negligibly different from just passing the cap, since: \\n *\\n * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years\\n * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible\\n */\\n function _decPow(uint _base, uint _minutes) internal pure returns (uint) {\\n \\n if (_minutes > 525600000) {_minutes = 525600000;} // cap to avoid overflow\\n \\n if (_minutes == 0) {return DECIMAL_PRECISION;}\\n\\n uint y = DECIMAL_PRECISION;\\n uint x = _base;\\n uint n = _minutes;\\n\\n // Exponentiation-by-squaring\\n while (n > 1) {\\n if (n % 2 == 0) {\\n x = decMul(x, x);\\n n = n.div(2);\\n } else { // if (n % 2 != 0)\\n y = decMul(x, y);\\n x = decMul(x, x);\\n n = (n.sub(1)).div(2);\\n }\\n }\\n\\n return decMul(x, y);\\n }\\n\\n function _getAbsoluteDifference(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a.sub(_b) : _b.sub(_a);\\n }\\n\\n function _computeNominalCR(uint _coll, uint _debt) internal pure returns (uint) {\\n if (_debt > 0) {\\n return _coll.mul(NICR_PRECISION).div(_debt);\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1;\\n }\\n }\\n\\n function _computeCR(uint _coll, uint _debt, uint _price) internal pure returns (uint) {\\n if (_debt > 0) {\\n uint newCollRatio = _coll.mul(_price).div(_debt);\\n\\n return newCollRatio;\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1; \\n }\\n }\\n}\\n\",\"keccak256\":\"0x7a95ed70d8937e0896c054b433ad0dfc87a9cfd028cae1694098e9d5d68127cd\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquitySafeMath128.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// uint128 addition and subtraction, with overflow protection.\\n\\nlibrary LiquitySafeMath128 {\\n function add(uint128 a, uint128 b) internal pure returns (uint128) {\\n uint128 c = a + b;\\n require(c >= a, \\\"LiquitySafeMath128: addition overflow\\\");\\n\\n return c;\\n }\\n \\n function sub(uint128 a, uint128 b) internal pure returns (uint128) {\\n require(b <= a, \\\"LiquitySafeMath128: subtraction overflow\\\");\\n uint128 c = a - b;\\n\\n return c;\\n }\\n}\",\"keccak256\":\"0x6e51d34d6fe3a2afbf5b64d1e14984a170f30247b318f62e04b9f4afdb660fc5\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IDLLR.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\nimport \\\"../IERC20.sol\\\";\\n\\n/// Public interface for Sovryn Dollar DLLR (Meta Asset Token of Sovryn Mynt) exposing specific functions\\ninterface IDLLR is IERC20 {\\n /**\\n * @notice Only owner can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _recipient Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transfer(address _recipient, uint256 _amount) external override returns (bool);\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _amount\\n ) external override returns (bool);\\n\\n /**\\n * @notice transfer utilizing EIP-2612, to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @dev By calling this function, the allowance will be overwritten by the total amount.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of the token that will be transferred.\\n * @param _deadline Expiration time of the signature.\\n * @param _v Last 1 byte of ECDSA signature.\\n * @param _r First 32 bytes of ECDSA signature.\\n * @param _s 32 bytes after _r in ECDSA signature.\\n */\\n function transferWithPermit(\\n address _from,\\n address _to,\\n uint256 _amount,\\n uint256 _deadline,\\n uint8 _v,\\n bytes32 _r,\\n bytes32 _s\\n ) external;\\n\\n /**\\n * @notice Approves and then calls the receiving contract.\\n * Useful to encapsulate sending tokens to a contract in one call.\\n * Solidity has no native way to send tokens to contracts.\\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\\n * @param _spender The contract address to spend the tokens.\\n * @param _amount The amount of tokens to be sent.\\n * @param _data Parameters for the contract call, such as endpoint signature.\\n */\\n function approveAndCall(address _spender, uint256 _amount, bytes calldata _data) external;\\n}\\n\",\"keccak256\":\"0x1fcc09759323769fcaa430bef598cf08a9f5e98ce6a9bdd6faa79d8b7b6ecce2\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IMassetManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IMassetManager {\\n struct PermitParams {\\n uint256 deadline;\\n uint8 v;\\n bytes32 r;\\n bytes32 s;\\n }\\n\\n function mintTo(\\n address _bAsset,\\n uint256 _bAssetQuantity,\\n address _recipient\\n ) external returns (uint256);\\n\\n function getToken() external view returns (address);\\n\\n /**\\n * @dev Credits a recipient with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @param _recipient Address to credit with withdrawn bAssets.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeemTo(\\n address _bAsset,\\n uint256 _massetQuantity,\\n address _recipient\\n ) external returns (uint256 massetRedeemed);\\n}\\n\",\"keccak256\":\"0x3e8de462d45e8f07ef83b6b6e7eb90a5d09f21d3bcbb1225e8f781488ab4a771\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/MyntLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IMassetManager.sol\\\";\\nimport \\\"./IDLLR.sol\\\";\\nimport \\\"../SafeMath.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"../../Interfaces/IPermit2.sol\\\";\\n\\nlibrary MyntLib {\\n using SafeMath for uint256;\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @dev WARNING!! Do not us this lib function on RSK network because there is a griefing attack issue in the DLLR contract.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _dllrAmount The amount of the DLLR (mAsset) token that will be burned in exchange for _toToken\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permitParams EIP-2612 permit params:\\n * _deadline Expiration time of the signature.\\n * _v Last 1 byte of ECDSA signature.\\n * _r First 32 bytes of ECDSA signature.\\n * _s 32 bytes after _r in ECDSA signature.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit(\\n IMassetManager _myntMassetManager,\\n uint256 _dllrAmount,\\n address _toToken,\\n IMassetManager.PermitParams calldata _permitParams\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n dllr.transferWithPermit(\\n msg.sender,\\n thisAddress,\\n _dllrAmount,\\n _permitParams.deadline,\\n _permitParams.v,\\n _permitParams.r,\\n _permitParams.s\\n );\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit via a canonical Permit2 contract\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permit permit data, in form of PermitTransferFrom struct.\\n * @param _permit2 permit2 contract address\\n * @param _signature signatue of the permit data.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit2(\\n IMassetManager _myntMassetManager,\\n address _toToken,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n IPermit2 _permit2,\\n bytes calldata _signature\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n uint256 _dllrAmount = _permit.permitted.amount;\\n\\n _permit2.permitTransferFrom(\\n _permit,\\n _generateTransferDetails(thisAddress, _dllrAmount),\\n msg.sender,\\n _signature\\n );\\n\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @dev view function to construct SignatureTransferDetails struct to be used by Permit2\\n *\\n * @param _to ultimate recipient\\n * @param _amount amount of transfer\\n *\\n * @return SignatureTransferDetails struct object \\n */\\n function _generateTransferDetails(address _to, uint256 _amount) private view returns (ISignatureTransfer.SignatureTransferDetails memory) {\\n ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer.SignatureTransferDetails({\\n to: _to,\\n requestedAmount: _amount\\n });\\n\\n return transferDetails;\\n }\\n}\\n\",\"keccak256\":\"0x6f0c78d8c4ea0b5b5e6bbe8d78374b9d2d367ffc07054dde36b9cbe2061944b6\",\"license\":\"MIT\"},\"contracts/Dependencies/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's Ownable contract:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\\n *\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable {\\n bytes32 private constant KEY_OWNER = keccak256(\\\"key.ownable.owner\\\");\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor () internal {\\n _setOwner(msg.sender);\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(msg.sender == getOwner(), \\\"Ownable:: access denied\\\");\\n _;\\n }\\n\\n /**\\n * @notice Set address of the owner.\\n * @param _owner Address of the owner.\\n * */\\n function _setOwner(address _owner) internal {\\n require(_owner != address(0), \\\"Ownable::setOwner: invalid address\\\");\\n emit OwnershipTransferred(getOwner(), _owner);\\n\\n bytes32 key = KEY_OWNER;\\n assembly {\\n sstore(key, _owner)\\n }\\n }\\n\\n /**\\n * @notice Set address of the owner (only owner can call this function)\\n * @param _owner Address of the owner.\\n * */\\n function setOwner(address _owner) public onlyOwner {\\n _setOwner(_owner);\\n }\\n\\n /**\\n * @notice Return address of the owner.\\n * @return _owner Address of the owner.\\n * */\\n function getOwner() public view returns (address _owner) {\\n bytes32 key = KEY_OWNER;\\n assembly {\\n _owner := sload(key)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xb5fc626e0b227fc0feb1d84440585015a0a5f586547d298534a604dd113efec6\",\"license\":\"MIT\"},\"contracts/Dependencies/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's SafeMath:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol\\n *\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x666b890992a066cc791f36c2975cd595d9761a014c654c385ed36ffaf658f3fd\",\"license\":\"MIT\"},\"contracts/Dependencies/console.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Buidler's helper contract for console logging\\nlibrary console {\\n\\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\\n\\n\\tfunction log() internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log()\\\"));\\n\\t\\tignored;\\n\\t}\\tfunction logInt(int p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(int)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logUint(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logString(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBool(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logAddress(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes(bytes memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logByte(byte p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(byte)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes1(bytes1 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes1)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes2(bytes2 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes2)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes3(bytes3 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes3)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes4(bytes4 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes4)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes5(bytes5 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes5)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes6(bytes6 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes6)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes7(bytes7 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes7)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes8(bytes8 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes8)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes9(bytes9 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes9)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes10(bytes10 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes10)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes11(bytes11 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes11)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes12(bytes12 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes12)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes13(bytes13 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes13)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes14(bytes14 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes14)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes15(bytes15 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes15)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes16(bytes16 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes16)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes17(bytes17 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes17)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes18(bytes18 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes18)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes19(bytes19 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes19)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes20(bytes20 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes20)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes21(bytes21 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes21)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes22(bytes22 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes22)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes23(bytes23 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes23)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes24(bytes24 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes24)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes25(bytes25 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes25)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes26(bytes26 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes26)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes27(bytes27 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes27)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes28(bytes28 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes28)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes29(bytes29 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes29)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes30(bytes30 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes30)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes31(bytes31 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes31)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes32(bytes32 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes32)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n}\\n\",\"keccak256\":\"0x6fa1de4ffe22b8f58b0b64d65db11dd5037be9b9db47b365a72adb489e217000\",\"license\":\"MIT\"},\"contracts/Interfaces/IActivePool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\n/**\\n * The Active Pool holds the ETH collateral and ZUSD debt (but not ZUSD tokens) for all active troves.\\n *\\n * When a trove is liquidated, it's ETH and ZUSD debt are transferred from the Active Pool, to either the\\n * Stability Pool, the Default Pool, or both, depending on the liquidation conditions.\\n *\\n */\\ninterface IActivePool is IPool {\\n // --- Events ---\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolZUSDDebtUpdated(uint _ZUSDDebt);\\n event ActivePoolETHBalanceUpdated(uint _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH amount to given account. Updates ActivePool balance. Only callable by BorrowerOperations, TroveManager or StabilityPool.\\n /// @param _account account to receive the ETH amount\\n /// @param _amount ETH amount to send\\n function sendETH(address _account, uint _amount) external;\\n}\\n\",\"keccak256\":\"0xdd5f1b6fae4050b4c885a85a10c2d0e73b82187a51736d009065aaeea33bf0d0\",\"license\":\"MIT\"},\"contracts/Interfaces/IAllowanceTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title AllowanceTransfer\\n/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface IAllowanceTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an ordered nonce.\\n event NonceInvalidation(\\n address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.\\n event Approval(\\n address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.\\n event Permit(\\n address indexed owner,\\n address indexed token,\\n address indexed spender,\\n uint160 amount,\\n uint48 expiration,\\n uint48 nonce\\n );\\n\\n /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.\\n event Lockdown(address indexed owner, address token, address spender);\\n\\n /// @notice The permit data for a token\\n struct PermitDetails {\\n // ERC20 token address\\n address token;\\n // the maximum amount allowed to spend\\n uint160 amount;\\n // timestamp at which a spender's token allowances become invalid\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice The permit message signed for a single token allowance\\n struct PermitSingle {\\n // the permit data for a single token alownce\\n PermitDetails details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The permit message signed for multiple token allowances\\n struct PermitBatch {\\n // the permit data for multiple token allowances\\n PermitDetails[] details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The saved permissions\\n /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n struct PackedAllowance {\\n // amount allowed\\n uint160 amount;\\n // permission expiry\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice A token spender pair.\\n struct TokenSpenderPair {\\n // the token the spender is approved\\n address token;\\n // the spender address\\n address spender;\\n }\\n\\n /// @notice Details for a token transfer.\\n struct AllowanceTransferDetails {\\n // the owner of the token\\n address from;\\n // the recipient of the token\\n address to;\\n // the amount of the token\\n uint160 amount;\\n // the token to be transferred\\n address token;\\n }\\n\\n /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.\\n /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]\\n /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.\\n function allowance(address user, address token, address spender)\\n external\\n view\\n returns (uint160 amount, uint48 expiration, uint48 nonce);\\n\\n /// @notice Approves the spender to use up to amount of the specified token up until the expiration\\n /// @param token The token to approve\\n /// @param spender The spender address to approve\\n /// @param amount The approved amount of the token\\n /// @param expiration The timestamp at which the approval is no longer valid\\n /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n function approve(address token, address spender, uint160 amount, uint48 expiration) external;\\n\\n /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitSingle Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;\\n\\n /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitBatch Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;\\n\\n /// @notice Transfer approved tokens from one address to another\\n /// @param from The address to transfer from\\n /// @param to The address of the recipient\\n /// @param amount The amount of the token to transfer\\n /// @param token The token address to transfer\\n /// @dev Requires the from address to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(address from, address to, uint160 amount, address token) external;\\n\\n /// @notice Transfer approved tokens in a batch\\n /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers\\n /// @dev Requires the from addresses to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;\\n\\n /// @notice Enables performing a \\\"lockdown\\\" of the sender's Permit2 identity\\n /// by batch revoking approvals\\n /// @param approvals Array of approvals to revoke.\\n function lockdown(TokenSpenderPair[] calldata approvals) external;\\n\\n /// @notice Invalidate nonces for a given (token, spender) pair\\n /// @param token The token to invalidate nonces for\\n /// @param spender The spender to invalidate nonces for\\n /// @param newNonce The new nonce to set. Invalidates all nonces less than it.\\n /// @dev Can't invalidate more than 2**16 nonces per transaction.\\n function invalidateNonces(address token, address spender, uint48 newNonce) external;\\n}\\n\",\"keccak256\":\"0xf15059fb68f89542908f963f22e18c0b0ae9997a6f9aaf6a9fb46aa2424acac9\",\"license\":\"MIT\"},\"contracts/Interfaces/IBorrowerOperations.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface IBorrowerOperations {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event TroveCreated(address indexed _borrower, uint256 arrayIndex);\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event ZUSDBorrowingFeePaid(address indexed _borrower, uint256 _ZUSDFee);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeDistributorAddress feeDistributor contract address\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _defaultPoolAddress DefaultPool contract address\\n * @param _stabilityPoolAddress StabilityPool contract address\\n * @param _gasPoolAddress GasPool contract address\\n * @param _collSurplusPoolAddress CollSurplusPool contract address\\n * @param _priceFeedAddress PrideFeed contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n address _feeDistributorAddress,\\n address _liquityBaseParamsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _defaultPoolAddress,\\n address _stabilityPoolAddress,\\n address _gasPoolAddress,\\n address _collSurplusPoolAddress,\\n address _priceFeedAddress,\\n address _sortedTrovesAddress,\\n address _zusdTokenAddress,\\n address _zeroStakingAddress\\n ) external;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * This method is identical to `openTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openNueTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /// @notice payable function that adds the received Ether to the caller's active Trove.\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function addColl(address _upperHint, address _lowerHint) external payable;\\n\\n /// @notice send ETH as collateral to a trove. Called by only the Stability Pool.\\n /// @param _user user trove address\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function moveETHGainToTrove(\\n address _user,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice withdraws `_amount` of collateral from the caller\\u2019s Trove.\\n * Executes only if the user has an active Trove, the withdrawal would not pull the user\\u2019s Trove below the minimum collateralization ratio,\\n * and the resulting total collateralization ratio of the system is above 150%.\\n * @param _amount collateral amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawColl(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice issues `_amount` of ZUSD from the caller\\u2019s Trove to the caller.\\n * Executes only if the Trove's collateralization ratio would remain above the minimum, and the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _amount ZUSD amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawZUSD(\\n uint256 _maxFee,\\n uint256 _amount,\\n address _upperHint,\\n address _lowerHint\\n ) external;\\n\\n /// Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction\\n function withdrawZusdAndConvertToDLLR(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external returns (uint256);\\n\\n /// @notice repay `_amount` of ZUSD to the caller\\u2019s Trove, subject to leaving 50 debt in the Trove (which corresponds to the 50 ZUSD gas compensation).\\n /// @param _amount ZUSD amount to repay\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function repayZUSD(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLR(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLRWithPermit2(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a ZUSD balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` ZUSD.\\n */\\n function closeTrove() external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTrove(IMassetManager.PermitParams calldata _permitParams) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTroveWithPermit2(ISignatureTransfer.PermitTransferFrom memory _permit, bytes calldata _signature) external;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTroveWithPermit2(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external payable;\\n\\n /**\\n * @notice when a borrower\\u2019s Trove has been fully redeemed from and closed, or liquidated in Recovery Mode with a collateralization ratio above 110%,\\n * this function allows the borrower to claim their ETH collateral surplus that remains in the system (collateral - debt upon redemption; collateral - 110% of the debt upon liquidation).\\n */\\n function claimCollateral() external;\\n\\n function getCompositeDebt(uint256 _debt) external view returns (uint256);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint256);\\n\\n function getMassetManager() external view returns (IMassetManager);\\n}\\n\",\"keccak256\":\"0x75da117f4bc4cca15fc16ca0466c68894f1befed0471ea7a670fa9b466ef2bc5\",\"license\":\"MIT\"},\"contracts/Interfaces/ICommunityIssuance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ICommunityIssuance { \\n \\n // --- Events ---\\n \\n event SOVTokenAddressSet(address _zeroTokenAddress);\\n event ZUSDTokenAddressSet(address _zusdTokenAddress);\\n event StabilityPoolAddressSet(address _stabilityPoolAddress);\\n event PriceFeedAddressSet(address _priceFeed);\\n event RewardManagerAddressSet(address _rewardManagerAddress);\\n event APRSet(uint256 _APR);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other contracts. Callable only by owner.\\n * @dev initializer function, checks addresses are contracts\\n * @param _sovTokenAddress sov token address.\\n * @param _zusdTokenAddress zero token address.\\n * @param _stabilityPoolAddress stability pool address.\\n * @param _priceFeed price feed address.\\n * @param _APR apr in basis points.\\n */\\n function initialize(\\n address _sovTokenAddress,\\n address _zusdTokenAddress,\\n address _stabilityPoolAddress,\\n address _priceFeed,\\n uint256 _APR\\n ) external;\\n\\n /**\\n * @dev setter function to set the APR value in basis points.\\n * can only be called by reward manager.\\n * @param _APR apr value in basis points.\\n */\\n function setAPR(uint256 _APR) external;\\n\\n /**\\n * @dev setter function to set the price feed.\\n * can only be called by the owner.\\n * @param _priceFeedAddress price feed address.\\n */\\n function setPriceFeed(address _priceFeedAddress) external;\\n\\n /**\\n * @dev setter function to set reward manager.\\n * can only be called by the owner.\\n * @param _rewardManagerAddress reward manager address.\\n */\\n function setRewardManager(address _rewardManagerAddress) external;\\n\\n /// @notice issues SOV tokens based on total zusd is deposited.\\n /// @return SOV tokens issuance \\n function issueSOV(uint256 _totalZUSDDeposits) external returns (uint256);\\n\\n /// @notice sends ZERO tokens to given account\\n /// @param _account account to receive the tokens\\n /// @param _ZEROamount amount of tokens to transfer\\n function sendSOV(address _account, uint _ZEROamount) external;\\n}\\n\",\"keccak256\":\"0x39b482323f5bfa1983ab020b5a8dc805116ffceb03f2729ffbe91b164403a96a\",\"license\":\"MIT\"},\"contracts/Interfaces/IDefaultPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\ninterface IDefaultPool is IPool {\\n // --- Events ---\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event DefaultPoolZUSDDebtUpdated(uint256 _ZUSDDebt);\\n event DefaultPoolETHBalanceUpdated(uint256 _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH to Active Pool\\n /// @param _amount ETH to send\\n function sendETHToActivePool(uint256 _amount) external;\\n}\\n\",\"keccak256\":\"0xfb2607676b2eb0f2defd248b4dd32895820048317f29aa6bdb572403a3e3d44e\",\"license\":\"MIT\"},\"contracts/Interfaces/IEIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\ninterface IEIP712 {\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xff52e9168eaa532ebacdad2ab6197f60171e3aa2fa2c1d6397d9da4d7782a543\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPriceFeed.sol\\\";\\nimport \\\"./ILiquityBaseParams.sol\\\";\\n\\ninterface ILiquityBase {\\n /// @return PriceFeed contract\\n function priceFeed() external view returns (IPriceFeed);\\n\\n /// @return LiquityBaseParams contract\\n function liquityBaseParams() external view returns (ILiquityBaseParams);\\n}\\n\",\"keccak256\":\"0xa4a57bd79e64d56a687c28d2a35c55b733fde8dda2a7ba861606eed3211724e1\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBaseParams.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ILiquityBaseParams {\\n\\n /// Minimum collateral ratio for individual troves\\n function MCR() external view returns (uint);\\n\\n /// Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.\\n function CCR() external view returns (uint);\\n\\n function PERCENT_DIVISOR() external view returns (uint);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint);\\n\\n /**\\n * Half-life of 12h. 12h = 720 min\\n * (1/2) = d^720 => d = (1/2)^(1/720)\\n */\\n function REDEMPTION_FEE_FLOOR() external view returns (uint);\\n\\n function MAX_BORROWING_FEE() external view returns (uint);\\n\\n}\",\"keccak256\":\"0xef8c0e8ad5d13d604c11b04983ff5bdd41768b646f2b33f45ddd988adec204e0\",\"license\":\"MIT\"},\"contracts/Interfaces/IPermit2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {ISignatureTransfer} from \\\"./ISignatureTransfer.sol\\\";\\nimport {IAllowanceTransfer} from \\\"./IAllowanceTransfer.sol\\\";\\n\\n/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer.\\n/// @dev Users must approve Permit2 before calling any of the transfer functions.\\ninterface IPermit2 is ISignatureTransfer, IAllowanceTransfer {\\n// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval.\\n}\\n\",\"keccak256\":\"0x3df819f5ca8de7324a676839d72e9f44c0f789c41c13bf0a892f3bb98d72ee86\",\"license\":\"MIT\"},\"contracts/Interfaces/IPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the Pools.\\ninterface IPool {\\n // --- Events ---\\n\\n event ETHBalanceUpdated(uint _newBalance);\\n event ZUSDBalanceUpdated(uint _newBalance);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event EtherSent(address _to, uint _amount);\\n\\n // --- Functions ---\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH pool balance\\n function getETH() external view returns (uint);\\n\\n /// @return ZUSD debt pool balance\\n function getZUSDDebt() external view returns (uint);\\n\\n /// @notice Increases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to add to the pool debt\\n function increaseZUSDDebt(uint _amount) external;\\n\\n /// @notice Decreases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to subtract to the pool debt\\n function decreaseZUSDDebt(uint _amount) external;\\n}\\n\",\"keccak256\":\"0x148e87ab38c6176d74f36c9e8989b99e768a7b18d8a045f1f01d6583b986806d\",\"license\":\"MIT\"},\"contracts/Interfaces/IPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IPriceFeed {\\n // --- Events ---\\n event LastGoodPriceUpdated(uint256 _lastGoodPrice);\\n\\n // --- Function ---\\n\\n /// @notice Returns the latest price obtained from the Oracle. Called by Zero functions that require a current price.\\n /// It uses the main price feed and fallback to the backup one in case of an error. If both fail return the last\\n /// good price seen.\\n /// @dev It's also callable by anyone externally\\n /// @return The price\\n function fetchPrice() external returns (uint256);\\n}\\n\",\"keccak256\":\"0x85fd97219a8156209d2cb5c6ae7c5ead01d893db000bf575023fcef0e62f9591\",\"license\":\"MIT\"},\"contracts/Interfaces/ISignatureTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title SignatureTransfer\\n/// @notice Handles ERC20 token transfers through signature based actions\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface ISignatureTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an unordered nonce.\\n event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);\\n\\n /// @notice The token and amount details for a transfer signed in the permit transfer signature\\n struct TokenPermissions {\\n // ERC20 token address\\n address token;\\n // the maximum amount that can be spent\\n uint256 amount;\\n }\\n\\n /// @notice The signed permit message for a single token transfer\\n struct PermitTransferFrom {\\n TokenPermissions permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice Specifies the recipient address and amount for batched transfers.\\n /// @dev Recipients and amounts correspond to the index of the signed token permissions array.\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount.\\n struct SignatureTransferDetails {\\n // recipient address\\n address to;\\n // spender requested amount\\n uint256 requestedAmount;\\n }\\n\\n /// @notice Used to reconstruct the signed permit message for multiple token transfers\\n /// @dev Do not need to pass in spender address as it is required that it is msg.sender\\n /// @dev Note that a user still signs over a spender address\\n struct PermitBatchTransferFrom {\\n // the tokens and corresponding amounts permitted for a transfer\\n TokenPermissions[] permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection\\n /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order\\n /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce\\n /// @dev It returns a uint256 bitmap\\n /// @dev The index, or wordPosition is capped at type(uint248).max\\n function nonceBitmap(address, uint256) external view returns (uint256);\\n\\n /// @notice Transfers a token using a signed permit message\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails The spender's requested transfer details for the permitted token\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitTransferFrom memory permit,\\n SignatureTransferDetails calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Transfers multiple tokens using a signed permit message\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails Specifies the recipient and requested amount for the token transfer\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitBatchTransferFrom memory permit,\\n SignatureTransferDetails[] calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Invalidates the bits specified in mask for the bitmap at the word position\\n /// @dev The wordPos is maxed at type(uint248).max\\n /// @param wordPos A number to index the nonceBitmap at\\n /// @param mask A bitmap masked against msg.sender's current bitmap at the word position\\n function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;\\n}\\n\",\"keccak256\":\"0x7efc63c119694e23dd76e44a5b125999829026bbc23409de7646a6a45e1ac341\",\"license\":\"MIT\"},\"contracts/Interfaces/ISortedTroves.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the SortedTroves Doubly Linked List.\\ninterface ISortedTroves {\\n // --- Events ---\\n\\n event SortedTrovesAddressChanged(address _sortedDoublyLLAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event NodeAdded(address _id, uint256 _NICR);\\n event NodeRemoved(address _id);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts and size. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _size max size of troves list\\n * @param _TroveManagerAddress TroveManager contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n */\\n function setParams(\\n uint256 _size,\\n address _TroveManagerAddress,\\n address _borrowerOperationsAddress\\n ) external;\\n\\n /**\\n * @dev Add a node to the list\\n * @param _id Node's id\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function insert(\\n address _id,\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Remove a node from the list\\n * @param _id Node's id\\n */\\n function remove(address _id) external;\\n\\n /**\\n * @dev Re-insert the node at a new position, based on its new NICR\\n * @param _id Node's id\\n * @param _newICR Node's new NICR\\n * @param _prevId Id of previous node for the new insert position\\n * @param _nextId Id of next node for the new insert position\\n */\\n function reInsert(\\n address _id,\\n uint256 _newICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Checks if the list contains a node\\n * @param _id Node's id\\n * @return true if list contains a node with given id\\n */\\n function contains(address _id) external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is full\\n * @return true if list is full\\n */\\n function isFull() external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is empty\\n * @return true if list is empty\\n */\\n function isEmpty() external view returns (bool);\\n\\n /**\\n * @return list current size\\n */\\n function getSize() external view returns (uint256);\\n\\n /**\\n * @return list max size\\n */\\n function getMaxSize() external view returns (uint256);\\n\\n /**\\n * @return the first node in the list (node with the largest NICR)\\n */\\n function getFirst() external view returns (address);\\n\\n /**\\n * @return the last node in the list (node with the smallest NICR)\\n */\\n function getLast() external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the next node (with a smaller NICR) in the list for a given node\\n */\\n function getNext(address _id) external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the previous node (with a larger NICR) in the list for a given node\\n */\\n function getPrev(address _id) external view returns (address);\\n\\n /**\\n * @notice Check if a pair of nodes is a valid insertion point for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function validInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (bool);\\n\\n /**\\n * @notice Find the insert position for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function findInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (address, address);\\n}\\n\",\"keccak256\":\"0x7328ad009da6230ddea1559564428464a5c3ace2258fb534dfbba5b5a8c7c60d\",\"license\":\"MIT\"},\"contracts/Interfaces/IStabilityPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/*\\n * The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors.\\n *\\n * When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with\\n * ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned.\\n *\\n * Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits.\\n * They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors,\\n * in the same proportion.\\n *\\n * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40%\\n * of the total ZUSD in the Stability Pool, depletes 40% of each deposit.\\n *\\n * A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit,\\n * multiplying it by some factor in range ]0,1[\\n *\\n * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations:\\n * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf\\n *\\n * --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS ---\\n *\\n * An SOV issuance event occurs at every deposit operation, and every liquidation.\\n *\\n * Each deposit is tagged with the address of the front end through which it was made.\\n *\\n * All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned\\n * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate.\\n *\\n * Please see the system Readme for an overview:\\n * https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers\\n */\\ninterface IStabilityPool {\\n // --- Events ---\\n\\n event StabilityPoolETHBalanceUpdated(uint _newBalance);\\n event StabilityPoolZUSDBalanceUpdated(uint _newBalance);\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event SortedTrovesAddressChanged(address _newSortedTrovesAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);\\n\\n event P_Updated(uint _P);\\n event S_Updated(uint _S, uint128 _epoch, uint128 _scale);\\n event G_Updated(uint _G, uint128 _epoch, uint128 _scale);\\n event EpochUpdated(uint128 _currentEpoch);\\n event ScaleUpdated(uint128 _currentScale);\\n\\n event FrontEndRegistered(address indexed _frontEnd, uint _kickbackRate);\\n event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd);\\n\\n event DepositSnapshotUpdated(address indexed _depositor, uint _P, uint _S, uint _G);\\n event FrontEndSnapshotUpdated(address indexed _frontEnd, uint _P, uint _G);\\n event UserDepositChanged(address indexed _depositor, uint _newDeposit);\\n event FrontEndStakeChanged(\\n address indexed _frontEnd,\\n uint _newFrontEndStake,\\n address _depositor\\n );\\n\\n event ETHGainWithdrawn(address indexed _depositor, uint _ETH, uint _ZUSDLoss);\\n event SOVPaidToDepositor(address indexed _depositor, uint _SOV);\\n event SOVPaidToFrontEnd(address indexed _frontEnd, uint _SOV);\\n event EtherSent(address _to, uint _amount);\\n\\n event WithdrawFromSpAndConvertToDLLR(\\n address _depositor,\\n uint256 _zusdAmountRequested,\\n uint256 _dllrAmountReceived\\n );\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Liquity contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _priceFeedAddress PriceFeed contract address\\n * @param _communityIssuanceAddress CommunityIssuanceAddress\\n */\\n function setAddresses(\\n address _liquityBaseParamsAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _zusdTokenAddress,\\n address _sortedTrovesAddress,\\n address _priceFeedAddress,\\n address _communityIssuanceAddress\\n ) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend is registered or zero address\\n * - Sender is not a registered frontend\\n * - _amount is not zero\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Tags the deposit with the provided front end tag param, if it's a new deposit\\n * - Sends depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Increases deposit and tagged front end's stake, and takes new snapshots for each.\\n * @param _amount amount to provide\\n * @param _frontEndTag frontend address to receive accumulated SOV gains\\n */\\n function provideToSP(uint _amount, address _frontEndTag) external;\\n\\n /**\\n * @notice Initial checks:\\n * - _amount is zero or there are no under collateralized troves left in the system\\n * - User has a non zero deposit\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Removes the deposit's front end tag if it is a full withdrawal\\n * - Sends all depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.\\n *\\n * If _amount > userDeposit, the user withdraws all of their compounded deposit.\\n * @param _amount amount to withdraw\\n */\\n function withdrawFromSP(uint _amount) external;\\n\\n /**\\n * @notice Initial checks:\\n * - User has a non zero deposit\\n * - User has an open trove\\n * - User has some ETH gain\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Sends all depositor's SOV gain to depositor\\n * - Sends all tagged front end's SOV gain to the tagged front end\\n * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove\\n * - Leaves their compounded deposit in the Stability Pool\\n * - Updates snapshots for deposit and tagged front end stake\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend (sender) not already registered\\n * - User (sender) has no deposit\\n * - _kickbackRate is in the range [0, 100%]\\n * ---\\n * Front end makes a one-time selection of kickback rate upon registering\\n * @param _kickbackRate kickback rate selected by frontend\\n */\\n function registerFrontEnd(uint _kickbackRate) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Caller is TroveManager\\n * ---\\n * Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible)\\n * and transfers the Trove's ETH collateral from ActivePool to StabilityPool.\\n * Only called by liquidation functions in the TroveManager.\\n * @param _debt debt to cancel\\n * @param _coll collateral to transfer\\n */\\n function offset(uint _debt, uint _coll) external;\\n\\n /**\\n * @return the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`,\\n * to exclude edge cases like ETH received from a self-destruct.\\n */\\n function getETH() external view returns (uint);\\n\\n /**\\n * @return ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\\n */\\n function getTotalZUSDDeposits() external view returns (uint);\\n\\n /**\\n * @notice Calculates the ETH gain earned by the deposit since its last snapshots were taken.\\n * @param _depositor address to calculate ETH gain\\n * @return ETH gain from given depositor\\n */\\n function getDepositorETHGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice Calculate the SOV gain earned by a deposit since its last snapshots were taken.\\n * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned.\\n * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through\\n * which they made their deposit.\\n * @param _depositor address to calculate ETH gain\\n * @return SOV gain from given depositor\\n */\\n function getDepositorSOVGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @param _frontEnd front end address\\n * @return the SOV gain earned by the front end.\\n */\\n function getFrontEndSOVGain(address _frontEnd) external view returns (uint);\\n\\n /**\\n * @param _depositor depositor address\\n * @return the user's compounded deposit.\\n */\\n function getCompoundedZUSDDeposit(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\\n * @param _frontEnd front end address\\n * @return the front end's compounded stake.\\n */\\n function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint);\\n\\n //DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDLLR(\\n uint _dllrAmount,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function provideToSpFromDllrWithPermit2(\\n uint256 _dllrAmount,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /// Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and optionally convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\\n function withdrawFromSpAndConvertToDLLR(uint256 _zusdAmount) external;\\n\\n /**\\n * Fallback function\\n * Only callable by Active Pool, it just accounts for ETH received\\n * receive() external payable;\\n */\\n}\\n\",\"keccak256\":\"0xb35c5ec991dd2b4f8ecb6b28ae29e97313fca6054aa0df14ebdb7336fcea84a6\",\"license\":\"MIT\"},\"contracts/Interfaces/ITroveManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./ILiquityBase.sol\\\";\\nimport \\\"./IStabilityPool.sol\\\";\\nimport \\\"./IZUSDToken.sol\\\";\\nimport \\\"./IZEROToken.sol\\\";\\nimport \\\"./IZEROStaking.sol\\\";\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface ITroveManager is ILiquityBase {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerRedeemOpsAddressChanged(address _troveManagerRedeemOps);\\n event LiquityBaseParamsAddressChanges(address _borrowerOperationsAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZEROTokenAddressChanged(address _zeroTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event Liquidation(\\n uint256 _liquidatedDebt,\\n uint256 _liquidatedColl,\\n uint256 _collGasCompensation,\\n uint256 _ZUSDGasCompensation\\n );\\n event Redemption(\\n uint256 _attemptedZUSDAmount,\\n uint256 _actualZUSDAmount,\\n uint256 _ETHSent,\\n uint256 _ETHFee\\n );\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event TroveLiquidated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint8 operation\\n );\\n event BaseRateUpdated(uint256 _baseRate);\\n event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);\\n event TotalStakesUpdated(uint256 _newTotalStakes);\\n event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);\\n event LTermsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveIndexUpdated(address _borrower, uint256 _newIndex);\\n\\n struct TroveManagerInitAddressesParams {\\n address _feeDistributorAddress;\\n address _troveManagerRedeemOps;\\n address _liquityBaseParamsAddress;\\n address _borrowerOperationsAddress;\\n address _activePoolAddress;\\n address _defaultPoolAddress;\\n address _stabilityPoolAddress;\\n address _gasPoolAddress;\\n address _collSurplusPoolAddress;\\n address _priceFeedAddress;\\n address _zusdTokenAddress;\\n address _sortedTrovesAddress;\\n address _zeroTokenAddress;\\n address _zeroStakingAddress;\\n }\\n\\n // --- Functions ---\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _troveManagerInitAddresses addresses list to intialize TroveManager with _\\n * _feeDistributorAddress feeDistributor contract address\\n * _troveManagerRedeemOps TroveManagerRedeemOps contract address\\n * _liquityBaseParamsAddress LiquityBaseParams contract address\\n * _borrowerOperationsAddress BorrowerOperations contract address\\n * _activePoolAddress ActivePool contract address\\n * _defaultPoolAddress DefaultPool contract address\\n * _stabilityPoolAddress StabilityPool contract address\\n * _gasPoolAddress GasPool contract address\\n * _collSurplusPoolAddress CollSurplusPool contract address\\n * _priceFeedAddress PriceFeed contract address\\n * _zusdTokenAddress ZUSDToken contract address\\n * _sortedTrovesAddress SortedTroves contract address\\n * _zeroTokenAddress ZEROToken contract address\\n * _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n TroveManagerInitAddressesParams memory _troveManagerInitAddresses\\n ) external;\\n\\n function setTroveManagerRedeemOps(address _troveManagerRedeemOps) external;\\n\\n /// @return Trove owners count\\n function getTroveOwnersCount() external view returns (uint256);\\n\\n /// @param _index Trove owner index\\n /// @return Trove from TroveOwners array in given index\\n function getTroveFromTroveOwnersArray(uint256 _index) external view returns (address);\\n\\n /// @param _borrower borrower address\\n /// @return the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getNominalICR(address _borrower) external view returns (uint256);\\n\\n /// @notice computes the user\\u2019s individual collateralization ratio (ICR) based on their total collateral and total ZUSD debt. Returns 2^256 -1 if they have 0 debt.\\n /// @param _borrower borrower address\\n /// @param _price ETH price\\n /// @return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getCurrentICR(address _borrower, uint256 _price) external view returns (uint256);\\n\\n /// @notice Closes the trove if its ICR is lower than the minimum collateral ratio.\\n /// @param _borrower borrower address\\n function liquidate(address _borrower) external;\\n\\n /**\\n * @notice Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves,\\n * starting from the one with the lowest collateral ratio in the system, and moving upwards\\n * @param _n max number of under-collateralized Troves to liquidate\\n */\\n function liquidateTroves(uint256 _n) external;\\n\\n /**\\n * @notice Attempt to liquidate a custom list of troves provided by the caller.\\n * @param _troveArray list of trove addresses\\n */\\n function batchLiquidateTroves(address[] calldata _troveArray) external;\\n\\n /**\\n * @notice Send _ZUSDamount ZUSD to the system and redeem the corresponding amount of collateral from as many Troves as are needed to fill the redemption\\n * request. Applies pending rewards to a Trove before reducing its debt and coll.\\n *\\n * Note that if _amount is very large, this function can run out of gas, specially if traversed troves are small. This can be easily avoided by\\n * splitting the total _amount in appropriate chunks and calling the function multiple times.\\n *\\n * Param `_maxIterations` can also be provided, so the loop through Troves is capped (if it\\u2019s zero, it will be ignored).This makes it easier to\\n * avoid OOG for the frontend, as only knowing approximately the average cost of an iteration is enough, without needing to know the \\u201ctopology\\u201d\\n * of the trove list. It also avoids the need to set the cap in stone in the contract, nor doing gas calculations, as both gas price and opcode\\n * costs can vary.\\n *\\n * All Troves that are redeemed from -- with the likely exception of the last one -- will end up with no debt left, therefore they will be closed.\\n * If the last Trove does have some remaining debt, it has a finite ICR, and the reinsertion could be anywhere in the list, therefore it requires a hint.\\n * A frontend should use getRedemptionHints() to calculate what the ICR of this Trove will be after redemption, and pass a hint for its position\\n * in the sortedTroves list along with the ICR value that the hint was found for.\\n *\\n * If another transaction modifies the list between calling getRedemptionHints() and passing the hints to redeemCollateral(), it\\n * is very likely that the last (partially) redeemed Trove would end up with a different ICR than what the hint is for. In this case the\\n * redemption will stop after the last completely redeemed Trove and the sender will keep the remaining ZUSD amount, which they can attempt\\n * to redeem later.\\n *\\n * @param _ZUSDAmount ZUSD amount to send to the system\\n * @param _firstRedemptionHint calculated ICR hint of first trove after redemption\\n * @param _maxIterations max Troves iterations (can be 0)\\n * @param _maxFee max fee percentage to accept\\n */\\n function redeemCollateral(\\n uint256 _ZUSDAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFee\\n ) external;\\n\\n function redeemCollateralViaDLLR(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function redeemCollateralViaDllrWithPermit2(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n \\n\\n /// @notice Update borrower's stake based on their latest collateral value\\n /// @param _borrower borrower address\\n function updateStakeAndTotalStakes(address _borrower) external returns (uint256);\\n\\n /// @notice Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values\\n /// @param _borrower borrower address\\n function updateTroveRewardSnapshots(address _borrower) external;\\n\\n /// @notice Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct\\n /// @param _borrower borrower address\\n /// @return index where Trove was inserted\\n function addTroveOwnerToArray(address _borrower) external returns (uint256 index);\\n\\n /// @notice Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\\n /// @param _borrower borrower address\\n function applyPendingRewards(address _borrower) external;\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ETH reward, earned by their stake\\n function getPendingETHReward(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ZUSD reward, earned by their stake\\n function getPendingZUSDDebtReward(address _borrower) external view returns (uint256);\\n\\n /*\\n * @notice A Trove has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:\\n * this indicates that rewards have occured since the snapshot was made, and the user therefore has\\n * pending rewards\\n *\\n * @param _borrower borrower address\\n * @return true if has pending rewards\\n */\\n function hasPendingRewards(address _borrower) external view returns (bool);\\n\\n /// @notice returns the Troves entire debt and coll, including pending rewards from redistributions.\\n /// @param _borrower borrower address\\n function getEntireDebtAndColl(\\n address _borrower\\n )\\n external\\n view\\n returns (\\n uint256 debt,\\n uint256 coll,\\n uint256 pendingZUSDDebtReward,\\n uint256 pendingETHReward\\n );\\n\\n /// @notice Close given trove. Called by BorrowerOperations.\\n /// @param _borrower borrower address\\n function closeTrove(address _borrower) external;\\n\\n /// @notice Remove borrower's stake from the totalStakes sum, and set their stake to 0\\n /// @param _borrower borrower address\\n function removeStake(address _borrower) external;\\n\\n /// @return calculated redemption rate using baseRate\\n function getRedemptionRate() external view returns (uint256);\\n\\n /// @return calculated redemption rate using calculated decayed as base rate\\n function getRedemptionRateWithDecay() external view returns (uint256);\\n\\n /// @notice The redemption fee is taken as a cut of the total ETH drawn from the system in a redemption. It is based on the current redemption rate.\\n /// @param _ETHDrawn ETH drawn\\n function getRedemptionFeeWithDecay(uint256 _ETHDrawn) external view returns (uint256);\\n\\n /// @return borrowing rate\\n function getBorrowingRate() external view returns (uint256);\\n\\n /// @return borrowing rate calculated using decayed as base rate\\n function getBorrowingRateWithDecay() external view returns (uint256);\\n\\n /// @param ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate\\n function getBorrowingFee(uint256 ZUSDDebt) external view returns (uint256);\\n\\n /// @param _ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate with decay\\n function getBorrowingFeeWithDecay(uint256 _ZUSDDebt) external view returns (uint256);\\n\\n /// @notice Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation.\\n function decayBaseRateFromBorrowing() external;\\n\\n /// @param _borrower borrower address\\n /// @return Trove status from given trove\\n function getTroveStatus(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove stake from given trove\\n function getTroveStake(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove debt from given trove\\n function getTroveDebt(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove collateral from given trove\\n function getTroveColl(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param num status to set\\n function setTroveStatus(address _borrower, uint256 num) external;\\n\\n /// @param _borrower borrower address\\n /// @param _collIncrease amount of collateral to increase\\n /// @return new trove collateral\\n function increaseTroveColl(\\n address _borrower,\\n uint256 _collIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _collDecrease amount of collateral to decrease\\n /// @return new trove collateral\\n function decreaseTroveColl(\\n address _borrower,\\n uint256 _collDecrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtIncrease amount of debt to increase\\n /// @return new trove debt\\n function increaseTroveDebt(\\n address _borrower,\\n uint256 _debtIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtDecrease amount of debt to decrease\\n /// @return new trove debt\\n function decreaseTroveDebt(\\n address _borrower,\\n uint256 _debtDecrease\\n ) external returns (uint256);\\n\\n /**\\n * @param _price ETH price\\n * @return the total collateralization ratio (TCR) of the system.\\n * The TCR is based on the the entire system debt and collateral (including pending rewards).\\n */\\n function getTCR(uint256 _price) external view returns (uint256);\\n\\n function MCR() external view returns (uint256);\\n\\n function CCR() external view returns (uint256);\\n\\n /// @notice reveals whether or not the system is in Recovery Mode (i.e. whether the Total Collateralization Ratio (TCR) is below the Critical Collateralization Ratio (CCR)).\\n function checkRecoveryMode(uint256 _price) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x396367eb7763c289e419a025532150e2a1d9d99eead359ceb6a081787501a00b\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROStaking.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IZEROStaking {\\n // --- Events --\\n\\n event ZEROTokenAddressSet(address _zeroTokenAddress);\\n event ZUSDTokenAddressSet(address _zusdTokenAddress);\\n event FeeDistributorAddressAddressSet(address _feeDistributorAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event StakeChanged(address indexed staker, uint256 newStake);\\n event StakingGainsWithdrawn(address indexed staker, uint256 ZUSDGain, uint256 ETHGain);\\n event F_ETHUpdated(uint256 _F_ETH);\\n event F_ZUSDUpdated(uint256 _F_ZUSD);\\n event TotalZEROStakedUpdated(uint256 _totalZEROStaked);\\n event EtherSent(address _account, uint256 _amount);\\n event StakerSnapshotsUpdated(address _staker, uint256 _F_ETH, uint256 _F_ZUSD);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _zeroTokenAddress ZEROToken contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _feeDistributorAddress FeeDistributorAddress contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _zeroTokenAddress,\\n address _zusdTokenAddress,\\n address _feeDistributorAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice If caller has a pre-existing stake, send any accumulated ETH and ZUSD gains to them.\\n /// @param _ZEROamount ZERO tokens to stake\\n function stake(uint256 _ZEROamount) external;\\n\\n /**\\n * @notice Unstake the ZERO and send the it back to the caller, along with their accumulated ZUSD & ETH gains.\\n * If requested amount > stake, send their entire stake.\\n * @param _ZEROamount ZERO tokens to unstake\\n */\\n function unstake(uint256 _ZEROamount) external;\\n\\n /// @param _ETHFee ETH fee\\n /// @notice increase ETH fee\\n function increaseF_ETH(uint256 _ETHFee) external;\\n\\n /// @param _ZEROFee ZUSD fee\\n /// @notice increase ZUSD fee\\n function increaseF_ZUSD(uint256 _ZEROFee) external;\\n\\n /// @param _user user address\\n /// @return pending ETH gain of given user\\n function getPendingETHGain(address _user) external view returns (uint256);\\n\\n /// @param _user user address\\n /// @return pending ZUSD gain of given user\\n function getPendingZUSDGain(address _user) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x4c7948ce7dff9ea9b8495054e511eabcf44a91c7db8520ec58ff2a002327e0c5\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZEROToken is IERC20, IERC2612 { \\n\\n // --- Functions ---\\n\\n /// @notice send zero tokens to ZEROStaking contract\\n /// @param _sender sender address\\n /// @param _amount amount to send\\n function sendToZEROStaking(address _sender, uint256 _amount) external;\\n\\n /// @return deployment start time\\n function getDeploymentStartTime() external view returns (uint256);\\n\\n}\\n\",\"keccak256\":\"0xbcc0baabe4c4686563a09cf1486f2d152b70404996676a89d525691f69637f66\",\"license\":\"MIT\"},\"contracts/Interfaces/IZUSDToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZUSDToken is IERC20, IERC2612 { \\n \\n // --- Events ---\\n\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n\\n event ZUSDTokenBalanceUpdated(address _user, uint _amount);\\n\\n // --- Functions ---\\n\\n function mint(address _account, uint256 _amount) external;\\n\\n function burn(address _account, uint256 _amount) external;\\n\\n function sendToPool(address _sender, address poolAddress, uint256 _amount) external;\\n\\n function returnFromPool(address poolAddress, address user, uint256 _amount ) external;\\n}\\n\",\"keccak256\":\"0xe52df063aa08f709640c28888edd27310c820f6d08564855538ae245eb2f5a8c\",\"license\":\"MIT\"},\"contracts/StabilityPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./Interfaces/IStabilityPool.sol\\\";\\nimport \\\"./Interfaces/ITroveManager.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/ICommunityIssuance.sol\\\";\\nimport \\\"./Dependencies/LiquityBase.sol\\\";\\nimport \\\"./Dependencies/LiquitySafeMath128.sol\\\";\\nimport \\\"./Dependencies/CheckContract.sol\\\";\\nimport \\\"./Dependencies/Mynt/MyntLib.sol\\\";\\nimport \\\"./StabilityPoolStorage.sol\\\";\\nimport \\\"./Interfaces/IPermit2.sol\\\";\\n\\n/**\\n * The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors.\\n *\\n * When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with\\n * ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned.\\n *\\n * Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits.\\n * They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors,\\n * in the same proportion.\\n *\\n * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40%\\n * of the total ZUSD in the Stability Pool, depletes 40% of each deposit.\\n *\\n * A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit,\\n * multiplying it by some factor in range ]0,1[\\n *\\n *\\n * --- IMPLEMENTATION ---\\n *\\n * We use a highly scalable method of tracking deposits and ETH gains that has O(1) complexity.\\n *\\n * When a liquidation occurs, rather than updating each depositor's deposit and ETH gain, we simply update two state variables:\\n * a product P, and a sum S.\\n *\\n * A mathematical manipulation allows us to factor out the initial deposit, and accurately track all depositors' compounded deposits\\n * and accumulated ETH gains over time, as liquidations occur, using just these two variables P and S. When depositors join the\\n * Stability Pool, they get a snapshot of the latest P and S: P_t and S_t, respectively.\\n *\\n * The formula for a depositor's accumulated ETH gain is derived here:\\n * https://github.com/liquity/dev/blob/main/packages/contracts/mathProofs/Scalable%20Compounding%20Stability%20Pool%20Deposits.pdf\\n *\\n * For a given deposit d_t, the ratio P/P_t tells us the factor by which a deposit has decreased since it joined the Stability Pool,\\n * and the term d_t * (S - S_t)/P_t gives us the deposit's total accumulated ETH gain.\\n *\\n * Each liquidation updates the product P and sum S. After a series of liquidations, a compounded deposit and corresponding ETH gain\\n * can be calculated using the initial deposit, the depositor\\u2019s snapshots of P and S, and the latest values of P and S.\\n *\\n * Any time a depositor updates their deposit (withdrawal, top-up) their accumulated ETH gain is paid out, their new deposit is recorded\\n * (based on their latest compounded deposit and modified by the withdrawal/top-up), and they receive new snapshots of the latest P and S.\\n * Essentially, they make a fresh deposit that overwrites the old one.\\n *\\n *\\n * --- SCALE FACTOR ---\\n *\\n * Since P is a running product in range ]0,1] that is always-decreasing, it should never reach 0 when multiplied by a number in range ]0,1[.\\n * Unfortunately, Solidity floor division always reaches 0, sooner or later.\\n *\\n * A series of liquidations that nearly empty the Pool (and thus each multiply P by a very small number in range ]0,1[ ) may push P\\n * to its 18 digit decimal limit, and round it to 0, when in fact the Pool hasn't been emptied: this would break deposit tracking.\\n *\\n * So, to track P accurately, we use a scale factor: if a liquidation would cause P to decrease to <1e-9 (and be rounded to 0 by Solidity),\\n * we first multiply P by 1e9, and increment a currentScale factor by 1.\\n *\\n * The added benefit of using 1e9 for the scale factor (rather than 1e18) is that it ensures negligible precision loss close to the\\n * scale boundary: when P is at its minimum value of 1e9, the relative precision loss in P due to floor division is only on the\\n * order of 1e-9.\\n *\\n * --- EPOCHS ---\\n *\\n * Whenever a liquidation fully empties the Stability Pool, all deposits should become 0. However, setting P to 0 would make P be 0\\n * forever, and break all future reward calculations.\\n *\\n * So, every time the Stability Pool is emptied by a liquidation, we reset P = 1 and currentScale = 0, and increment the currentEpoch by 1.\\n *\\n * --- TRACKING DEPOSIT OVER SCALE CHANGES AND EPOCHS ---\\n *\\n * When a deposit is made, it gets snapshots of the currentEpoch and the currentScale.\\n *\\n * When calculating a compounded deposit, we compare the current epoch to the deposit's epoch snapshot. If the current epoch is newer,\\n * then the deposit was present during a pool-emptying liquidation, and necessarily has been depleted to 0.\\n *\\n * Otherwise, we then compare the current scale to the deposit's scale snapshot. If they're equal, the compounded deposit is given by d_t * P/P_t.\\n * If it spans one scale change, it is given by d_t * P/(P_t * 1e9). If it spans more than one scale change, we define the compounded deposit\\n * as 0, since it is now less than 1e-9'th of its initial value (e.g. a deposit of 1 billion ZUSD has depleted to < 1 ZUSD).\\n *\\n *\\n * --- TRACKING DEPOSITOR'S ETH GAIN OVER SCALE CHANGES AND EPOCHS ---\\n *\\n * In the current epoch, the latest value of S is stored upon each scale change, and the mapping (scale -> S) is stored for each epoch.\\n *\\n * This allows us to calculate a deposit's accumulated ETH gain, during the epoch in which the deposit was non-zero and earned ETH.\\n *\\n * We calculate the depositor's accumulated ETH gain for the scale at which they made the deposit, using the ETH gain formula:\\n * e_1 = d_t * (S - S_t) / P_t\\n *\\n * and also for scale after, taking care to divide the latter by a factor of 1e9:\\n * e_2 = d_t * S / (P_t * 1e9)\\n *\\n * The gain in the second scale will be full, as the starting point was in the previous scale, thus no need to subtract anything.\\n * The deposit therefore was present for reward events from the beginning of that second scale.\\n *\\n * S_i-S_t + S_{i+1}\\n * .<--------.------------>\\n * . .\\n * . S_i . S_{i+1}\\n * <--.-------->.<----------->\\n * S_t. .\\n * <->. .\\n * t .\\n * |---+---------|-------------|-----...\\n * i i+1\\n *\\n * The sum of (e_1 + e_2) captures the depositor's total accumulated ETH gain, handling the case where their\\n * deposit spanned one scale change. We only care about gains across one scale change, since the compounded\\n * deposit is defined as being 0 once it has spanned more than one scale change.\\n *\\n *\\n * --- UPDATING P WHEN A LIQUIDATION OCCURS ---\\n *\\n * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations:\\n * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf\\n *\\n *\\n * --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS ---\\n *\\n * An SOV issuance event occurs at every deposit operation, and every liquidation.\\n *\\n * Each deposit is tagged with the address of the front end through which it was made.\\n *\\n * All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned\\n * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate.\\n *\\n * Please see the system Readme for an overview:\\n * https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers\\n *\\n * We use the same mathematical product-sum approach to track SOV gains for depositors, where 'G' is the sum corresponding to SOV gains.\\n * The product P (and snapshot P_t) is re-used, as the ratio P/P_t tracks a deposit's depletion due to liquidations.\\n *\\n */\\ncontract StabilityPool is LiquityBase, StabilityPoolStorage, CheckContract, IStabilityPool {\\n using LiquitySafeMath128 for uint128;\\n address private constant ADDRESS_ZERO = address(0);\\n IPermit2 public immutable permit2;\\n\\n // --- Events ---\\n\\n event StabilityPoolETHBalanceUpdated(uint256 _newBalance);\\n event StabilityPoolZUSDBalanceUpdated(uint256 _newBalance);\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event SortedTrovesAddressChanged(address _newSortedTrovesAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);\\n\\n event P_Updated(uint256 _P);\\n event S_Updated(uint256 _S, uint128 _epoch, uint128 _scale);\\n event G_Updated(uint256 _G, uint128 _epoch, uint128 _scale);\\n event EpochUpdated(uint128 _currentEpoch);\\n event ScaleUpdated(uint128 _currentScale);\\n\\n event FrontEndRegistered(address indexed _frontEnd, uint256 _kickbackRate);\\n event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd);\\n\\n event DepositSnapshotUpdated(address indexed _depositor, uint256 _P, uint256 _S, uint256 _G);\\n event FrontEndSnapshotUpdated(address indexed _frontEnd, uint256 _P, uint256 _G);\\n event UserDepositChanged(address indexed _depositor, uint256 _newDeposit);\\n event FrontEndStakeChanged(\\n address indexed _frontEnd,\\n uint256 _newFrontEndStake,\\n address _depositor\\n );\\n\\n event ETHGainWithdrawn(address indexed _depositor, uint256 _ETH, uint256 _ZUSDLoss);\\n event SOVPaidToDepositor(address indexed _depositor, uint256 _SOV);\\n event SOVPaidToFrontEnd(address indexed _frontEnd, uint256 _SOV);\\n event EtherSent(address _to, uint256 _amount);\\n\\n /** Constructor */\\n constructor(address _permit2) public {\\n permit2 = IPermit2(_permit2);\\n }\\n\\n // --- Contract setters ---\\n\\n function setAddresses(\\n address _liquityBaseParamsAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _zusdTokenAddress,\\n address _sortedTrovesAddress,\\n address _priceFeedAddress,\\n address _communityIssuanceAddress\\n ) external override onlyOwner {\\n checkContract(_liquityBaseParamsAddress);\\n checkContract(_borrowerOperationsAddress);\\n checkContract(_troveManagerAddress);\\n checkContract(_activePoolAddress);\\n checkContract(_zusdTokenAddress);\\n checkContract(_sortedTrovesAddress);\\n checkContract(_priceFeedAddress);\\n checkContract(_communityIssuanceAddress);\\n\\n P = DECIMAL_PRECISION;\\n\\n liquityBaseParams = ILiquityBaseParams(_liquityBaseParamsAddress);\\n borrowerOperations = IBorrowerOperations(_borrowerOperationsAddress);\\n troveManager = ITroveManager(_troveManagerAddress);\\n activePool = IActivePool(_activePoolAddress);\\n zusdToken = IZUSDToken(_zusdTokenAddress);\\n sortedTroves = ISortedTroves(_sortedTrovesAddress);\\n priceFeed = IPriceFeed(_priceFeedAddress);\\n communityIssuance = ICommunityIssuance(_communityIssuanceAddress);\\n\\n emit BorrowerOperationsAddressChanged(_borrowerOperationsAddress);\\n emit TroveManagerAddressChanged(_troveManagerAddress);\\n emit ActivePoolAddressChanged(_activePoolAddress);\\n emit ZUSDTokenAddressChanged(_zusdTokenAddress);\\n emit SortedTrovesAddressChanged(_sortedTrovesAddress);\\n emit PriceFeedAddressChanged(_priceFeedAddress);\\n emit CommunityIssuanceAddressChanged(_communityIssuanceAddress);\\n }\\n\\n /**\\n * @dev setter function specific for community issuance contract.\\n * @param _communityIssuanceAddress address of new community issuance contract.\\n */\\n function setCommunityIssuanceAddress(address _communityIssuanceAddress) external onlyOwner {\\n checkContract(_communityIssuanceAddress);\\n communityIssuance = ICommunityIssuance(_communityIssuanceAddress);\\n emit CommunityIssuanceAddressChanged(_communityIssuanceAddress);\\n }\\n\\n // --- Getters for public variables. Required by IPool interface ---\\n\\n function getETH() external view override returns (uint256) {\\n return ETH;\\n }\\n\\n function getTotalZUSDDeposits() external view override returns (uint256) {\\n return totalZUSDDeposits;\\n }\\n\\n // --- External Depositor Functions ---\\n\\n /** provideToSP():\\n *\\n * - Triggers a SOV issuance, based on time passed since the last issuance and total amount of deposited ZUSD. The SOV issuance is shared between *all* depositors and front ends\\n * - Tags the deposit with the provided front end tag param, if it's a new deposit\\n * - Sends depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Increases deposit and tagged front end's stake, and takes new snapshots for each.\\n */\\n function provideToSP(uint256 _amount, address _frontEndTag) external override {\\n _provideToSP(_amount, _frontEndTag);\\n }\\n\\n function _provideToSP(uint256 _amount, address _frontEndTag) internal {\\n _requireFrontEndIsRegisteredOrZero(_frontEndTag);\\n _requireFrontEndNotRegistered(msg.sender);\\n _requireNonZeroAmount(_amount);\\n\\n uint256 initialDeposit = deposits[msg.sender].initialValue;\\n\\n ICommunityIssuance communityIssuanceCached = communityIssuance;\\n\\n _triggerSOVIssuance(communityIssuanceCached);\\n\\n if (initialDeposit == 0) {\\n _setFrontEndTag(msg.sender, _frontEndTag);\\n }\\n uint256 depositorETHGain = getDepositorETHGain(msg.sender);\\n uint256 compoundedZUSDDeposit = getCompoundedZUSDDeposit(msg.sender);\\n uint256 ZUSDLoss = initialDeposit.sub(compoundedZUSDDeposit); // Needed only for event log\\n\\n // First pay out any SOV gains\\n address frontEnd = deposits[msg.sender].frontEndTag;\\n _payOutSOVGains(communityIssuanceCached, msg.sender, frontEnd);\\n\\n // Update front end stake\\n uint256 compoundedFrontEndStake = getCompoundedFrontEndStake(frontEnd);\\n uint256 newFrontEndStake = compoundedFrontEndStake.add(_amount);\\n _updateFrontEndStakeAndSnapshots(frontEnd, newFrontEndStake);\\n emit FrontEndStakeChanged(frontEnd, newFrontEndStake, msg.sender);\\n\\n _sendZUSDtoStabilityPool(msg.sender, _amount);\\n\\n uint256 newDeposit = compoundedZUSDDeposit.add(_amount);\\n _updateDepositAndSnapshots(msg.sender, newDeposit);\\n emit UserDepositChanged(msg.sender, newDeposit);\\n\\n emit ETHGainWithdrawn(msg.sender, depositorETHGain, ZUSDLoss); // ZUSD Loss required for event log\\n\\n _sendETHGainToDepositor(depositorETHGain);\\n }\\n\\n ///DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDLLR(\\n uint256 _dllrAmount,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external override {\\n uint256 _ZUSDAmount = MyntLib.redeemZusdFromDllrWithPermit(\\n borrowerOperations.getMassetManager(),\\n _dllrAmount,\\n address(zusdToken),\\n _permitParams\\n );\\n\\n _provideToSP(_ZUSDAmount, ADDRESS_ZERO);\\n }\\n\\n ///DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDllrWithPermit2(\\n uint256 _dllrAmount,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external override {\\n uint256 _ZUSDAmount = MyntLib.redeemZusdFromDllrWithPermit2(\\n borrowerOperations.getMassetManager(),\\n address(zusdToken),\\n _permit,\\n permit2,\\n _signature\\n );\\n\\n _provideToSP(_ZUSDAmount, ADDRESS_ZERO);\\n }\\n\\n /** withdrawFromSP():\\n *\\n * - Triggers a SOV issuance, based on time passed since the last issuance and total amount of ZUSD is deposited. The SOV issuance is shared between *all* depositors and front ends\\n * - Removes the deposit's front end tag if it is a full withdrawal\\n * - Sends all depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.\\n *\\n * If _amount > userDeposit, the user withdraws all of their compounded deposit.\\n */\\n function withdrawFromSP(uint256 _amount) external override {\\n _withdrawFromSpTo(_amount, msg.sender);\\n }\\n\\n ///@return actual ZUSD amount withdrawn\\n function _withdrawFromSpTo(uint256 _amount, address _receiver) internal returns (uint256) {\\n require(_receiver != address(0), \\\"SP::_withdrawFromSpTo: _receiver is zero address\\\");\\n if (_amount != 0) {\\n _requireNoUnderCollateralizedTroves();\\n }\\n uint256 initialDeposit = deposits[msg.sender].initialValue;\\n _requireUserHasDeposit(initialDeposit);\\n\\n ICommunityIssuance communityIssuanceCached = communityIssuance;\\n\\n _triggerSOVIssuance(communityIssuanceCached);\\n\\n uint256 depositorETHGain = getDepositorETHGain(msg.sender);\\n\\n uint256 compoundedZUSDDeposit = getCompoundedZUSDDeposit(msg.sender);\\n uint256 ZUSDtoWithdraw = LiquityMath._min(_amount, compoundedZUSDDeposit);\\n uint256 ZUSDLoss = initialDeposit.sub(compoundedZUSDDeposit); // Needed only for event log\\n\\n // First pay out any SOV gains\\n address frontEnd = deposits[msg.sender].frontEndTag;\\n _payOutSOVGains(communityIssuanceCached, msg.sender, frontEnd);\\n\\n // Update front end stake\\n uint256 compoundedFrontEndStake = getCompoundedFrontEndStake(frontEnd);\\n uint256 newFrontEndStake = compoundedFrontEndStake.sub(ZUSDtoWithdraw);\\n _updateFrontEndStakeAndSnapshots(frontEnd, newFrontEndStake);\\n emit FrontEndStakeChanged(frontEnd, newFrontEndStake, msg.sender);\\n\\n _sendZUSDToDepositor(_receiver, ZUSDtoWithdraw);\\n\\n // Update deposit\\n uint256 newDeposit = compoundedZUSDDeposit.sub(ZUSDtoWithdraw);\\n _updateDepositAndSnapshots(msg.sender, newDeposit);\\n emit UserDepositChanged(msg.sender, newDeposit);\\n\\n emit ETHGainWithdrawn(msg.sender, depositorETHGain, ZUSDLoss); // ZUSD Loss required for event log\\n\\n _sendETHGainTo(depositorETHGain, msg.sender);\\n\\n return ZUSDtoWithdraw;\\n }\\n\\n ///Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\\n function withdrawFromSpAndConvertToDLLR(uint256 _zusdAmountRequested) external override {\\n IMassetManager massetManager = borrowerOperations.getMassetManager();\\n uint256 amountWithdrawn = _withdrawFromSpTo(_zusdAmountRequested, address(this));\\n require(\\n zusdToken.approve(address(massetManager), amountWithdrawn),\\n \\\"Failed to approve ZUSD amount for Mynt mAsset to redeem\\\"\\n );\\n massetManager.mintTo(address(zusdToken), amountWithdrawn, msg.sender);\\n emit WithdrawFromSpAndConvertToDLLR(msg.sender, _zusdAmountRequested, amountWithdrawn);\\n }\\n\\n /** withdrawETHGainToTrove:\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Sends all depositor's SOV gain to depositor\\n * - Sends all tagged front end's SOV gain to the tagged front end\\n * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove\\n * - Leaves their compounded deposit in the Stability Pool\\n * - Updates snapshots for deposit and tagged front end stake */\\n function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external override {\\n uint256 initialDeposit = deposits[msg.sender].initialValue;\\n _requireUserHasDeposit(initialDeposit);\\n _requireUserHasTrove(msg.sender);\\n _requireUserHasETHGain(msg.sender);\\n\\n ICommunityIssuance communityIssuanceCached = communityIssuance;\\n\\n _triggerSOVIssuance(communityIssuanceCached);\\n\\n uint256 depositorETHGain = getDepositorETHGain(msg.sender);\\n\\n uint256 compoundedZUSDDeposit = getCompoundedZUSDDeposit(msg.sender);\\n uint256 ZUSDLoss = initialDeposit.sub(compoundedZUSDDeposit); // Needed only for event log\\n\\n // First pay out any SOV gains\\n address frontEnd = deposits[msg.sender].frontEndTag;\\n _payOutSOVGains(communityIssuanceCached, msg.sender, frontEnd);\\n\\n // Update front end stake\\n uint256 compoundedFrontEndStake = getCompoundedFrontEndStake(frontEnd);\\n uint256 newFrontEndStake = compoundedFrontEndStake;\\n _updateFrontEndStakeAndSnapshots(frontEnd, newFrontEndStake);\\n emit FrontEndStakeChanged(frontEnd, newFrontEndStake, msg.sender);\\n\\n _updateDepositAndSnapshots(msg.sender, compoundedZUSDDeposit);\\n\\n /* Emit events before transferring ETH gain to Trove.\\n This lets the event log make more sense (i.e. so it appears that first the ETH gain is withdrawn\\n and then it is deposited into the Trove, not the other way around). */\\n emit ETHGainWithdrawn(msg.sender, depositorETHGain, ZUSDLoss);\\n emit UserDepositChanged(msg.sender, compoundedZUSDDeposit);\\n\\n ETH = ETH.sub(depositorETHGain);\\n emit StabilityPoolETHBalanceUpdated(ETH);\\n emit EtherSent(msg.sender, depositorETHGain);\\n\\n borrowerOperations.moveETHGainToTrove{ value: depositorETHGain }(\\n msg.sender,\\n _upperHint,\\n _lowerHint\\n );\\n }\\n\\n // --- SOV issuance functions ---\\n\\n function _triggerSOVIssuance(ICommunityIssuance _communityIssuance) internal {\\n uint256 SOVIssuance = _communityIssuance.issueSOV(totalZUSDDeposits);\\n _updateG(SOVIssuance);\\n }\\n\\n function _updateG(uint256 _SOVIssuance) internal {\\n uint256 totalZUSD = totalZUSDDeposits; // cached to save an SLOAD\\n /*\\n * When total deposits is 0, G is not updated. In this case, the SOV issued can not be obtained by later\\n * depositors - it is missed out on, and remains in the balanceof the CommunityIssuance contract.\\n *\\n */\\n if (totalZUSD == 0 || _SOVIssuance == 0) {\\n return;\\n }\\n\\n uint256 SOVPerUnitStaked;\\n SOVPerUnitStaked = _computeSOVPerUnitStaked(_SOVIssuance, totalZUSD);\\n\\n uint256 marginalSOVGain = SOVPerUnitStaked.mul(P);\\n epochToScaleToG[currentEpoch][currentScale] = epochToScaleToG[currentEpoch][currentScale]\\n .add(marginalSOVGain);\\n\\n emit G_Updated(epochToScaleToG[currentEpoch][currentScale], currentEpoch, currentScale);\\n }\\n\\n function _computeSOVPerUnitStaked(uint256 _SOVIssuance, uint256 _totalZUSDDeposits)\\n internal\\n returns (uint256)\\n {\\n /*\\n * Calculate the SOV-per-unit staked. Division uses a \\\"feedback\\\" error correction, to keep the\\n * cumulative error low in the running total G:\\n *\\n * 1) Form a numerator which compensates for the floor division error that occurred the last time this\\n * function was called.\\n * 2) Calculate \\\"per-unit-staked\\\" ratio.\\n * 3) Multiply the ratio back by its denominator, to reveal the current floor division error.\\n * 4) Store this error for use in the next correction when this function is called.\\n * 5) Note: static analysis tools complain about this \\\"division before multiplication\\\", however, it is intended.\\n */\\n uint256 SOVNumerator = _SOVIssuance.mul(DECIMAL_PRECISION).add(lastSOVError);\\n\\n uint256 SOVPerUnitStaked = SOVNumerator.div(_totalZUSDDeposits);\\n lastSOVError = SOVNumerator.sub(SOVPerUnitStaked.mul(_totalZUSDDeposits));\\n\\n return SOVPerUnitStaked;\\n }\\n\\n // --- Liquidation functions ---\\n\\n /**\\n * Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible)\\n * and transfers the Trove's ETH collateral from ActivePool to StabilityPool.\\n * Only called by liquidation functions in the TroveManager.\\n */\\n function offset(uint256 _debtToOffset, uint256 _collToAdd) external override {\\n _requireCallerIsTroveManager();\\n uint256 totalZUSD = totalZUSDDeposits; // cached to save an SLOAD\\n if (totalZUSD == 0 || _debtToOffset == 0) {\\n return;\\n }\\n\\n _triggerSOVIssuance(communityIssuance);\\n\\n (\\n uint256 ETHGainPerUnitStaked,\\n uint256 ZUSDLossPerUnitStaked\\n ) = _computeRewardsPerUnitStaked(_collToAdd, _debtToOffset, totalZUSD);\\n\\n _updateRewardSumAndProduct(ETHGainPerUnitStaked, ZUSDLossPerUnitStaked); // updates S and P\\n\\n _moveOffsetCollAndDebt(_collToAdd, _debtToOffset);\\n }\\n\\n // --- Offset helper functions ---\\n\\n function _computeRewardsPerUnitStaked(\\n uint256 _collToAdd,\\n uint256 _debtToOffset,\\n uint256 _totalZUSDDeposits\\n ) internal returns (uint256 ETHGainPerUnitStaked, uint256 ZUSDLossPerUnitStaked) {\\n /*\\n * Compute the ZUSD and ETH rewards. Uses a \\\"feedback\\\" error correction, to keep\\n * the cumulative error in the P and S state variables low:\\n *\\n * 1) Form numerators which compensate for the floor division errors that occurred the last time this\\n * function was called.\\n * 2) Calculate \\\"per-unit-staked\\\" ratios.\\n * 3) Multiply each ratio back by its denominator, to reveal the current floor division error.\\n * 4) Store these errors for use in the next correction when this function is called.\\n * 5) Note: static analysis tools complain about this \\\"division before multiplication\\\", however, it is intended.\\n */\\n uint256 ETHNumerator = _collToAdd.mul(DECIMAL_PRECISION).add(lastETHError_Offset);\\n\\n assert(_debtToOffset <= _totalZUSDDeposits);\\n if (_debtToOffset == _totalZUSDDeposits) {\\n ZUSDLossPerUnitStaked = DECIMAL_PRECISION; // When the Pool depletes to 0, so does each deposit\\n lastZUSDLossError_Offset = 0;\\n } else {\\n uint256 ZUSDLossNumerator = _debtToOffset.mul(DECIMAL_PRECISION).sub(\\n lastZUSDLossError_Offset\\n );\\n /*\\n * Add 1 to make error in quotient positive. We want \\\"slightly too much\\\" ZUSD loss,\\n * which ensures the error in any given compoundedZUSDDeposit favors the Stability Pool.\\n */\\n ZUSDLossPerUnitStaked = (ZUSDLossNumerator.div(_totalZUSDDeposits)).add(1);\\n lastZUSDLossError_Offset = (ZUSDLossPerUnitStaked.mul(_totalZUSDDeposits)).sub(\\n ZUSDLossNumerator\\n );\\n }\\n\\n ETHGainPerUnitStaked = ETHNumerator.div(_totalZUSDDeposits);\\n lastETHError_Offset = ETHNumerator.sub(ETHGainPerUnitStaked.mul(_totalZUSDDeposits));\\n\\n return (ETHGainPerUnitStaked, ZUSDLossPerUnitStaked);\\n }\\n\\n /// Update the Stability Pool reward sum S and product P\\n function _updateRewardSumAndProduct(\\n uint256 _ETHGainPerUnitStaked,\\n uint256 _ZUSDLossPerUnitStaked\\n ) internal {\\n uint256 currentP = P;\\n uint256 newP;\\n\\n assert(_ZUSDLossPerUnitStaked <= DECIMAL_PRECISION);\\n /*\\n * The newProductFactor is the factor by which to change all deposits, due to the depletion of Stability Pool ZUSD in the liquidation.\\n * We make the product factor 0 if there was a pool-emptying. Otherwise, it is (1 - ZUSDLossPerUnitStaked)\\n */\\n uint256 newProductFactor = uint256(DECIMAL_PRECISION).sub(_ZUSDLossPerUnitStaked);\\n\\n uint128 currentScaleCached = currentScale;\\n uint128 currentEpochCached = currentEpoch;\\n uint256 currentS = epochToScaleToSum[currentEpochCached][currentScaleCached];\\n\\n /*\\n * Calculate the new S first, before we update P.\\n * The ETH gain for any given depositor from a liquidation depends on the value of their deposit\\n * (and the value of totalDeposits) prior to the Stability being depleted by the debt in the liquidation.\\n *\\n * Since S corresponds to ETH gain, and P to deposit loss, we update S first.\\n */\\n uint256 marginalETHGain = _ETHGainPerUnitStaked.mul(currentP);\\n uint256 newS = currentS.add(marginalETHGain);\\n epochToScaleToSum[currentEpochCached][currentScaleCached] = newS;\\n emit S_Updated(newS, currentEpochCached, currentScaleCached);\\n\\n // If the Stability Pool was emptied, increment the epoch, and reset the scale and product P\\n if (newProductFactor == 0) {\\n currentEpoch = currentEpochCached.add(1);\\n emit EpochUpdated(currentEpoch);\\n currentScale = 0;\\n emit ScaleUpdated(currentScale);\\n newP = DECIMAL_PRECISION;\\n\\n // If multiplying P by a non-zero product factor would reduce P below the scale boundary, increment the scale\\n } else if (currentP.mul(newProductFactor).div(DECIMAL_PRECISION) < SCALE_FACTOR) {\\n newP = currentP.mul(newProductFactor).mul(SCALE_FACTOR).div(DECIMAL_PRECISION);\\n currentScale = currentScaleCached.add(1);\\n emit ScaleUpdated(currentScale);\\n } else {\\n newP = currentP.mul(newProductFactor).div(DECIMAL_PRECISION);\\n }\\n\\n assert(newP > 0);\\n P = newP;\\n\\n emit P_Updated(newP);\\n }\\n\\n function _moveOffsetCollAndDebt(uint256 _collToAdd, uint256 _debtToOffset) internal {\\n IActivePool activePoolCached = activePool;\\n\\n // Cancel the liquidated ZUSD debt with the ZUSD in the stability pool\\n activePoolCached.decreaseZUSDDebt(_debtToOffset);\\n _decreaseZUSD(_debtToOffset);\\n\\n // Burn the debt that was successfully offset\\n zusdToken.burn(address(this), _debtToOffset);\\n\\n activePoolCached.sendETH(address(this), _collToAdd);\\n }\\n\\n function _decreaseZUSD(uint256 _amount) internal {\\n uint256 newTotalZUSDDeposits = totalZUSDDeposits.sub(_amount);\\n totalZUSDDeposits = newTotalZUSDDeposits;\\n emit StabilityPoolZUSDBalanceUpdated(newTotalZUSDDeposits);\\n }\\n\\n // --- Reward calculator functions for depositor and front end ---\\n\\n /** Calculates the ETH gain earned by the deposit since its last snapshots were taken.\\n * Given by the formula: E = d0 * (S - S(0))/P(0)\\n * where S(0) and P(0) are the depositor's snapshots of the sum S and product P, respectively.\\n * d0 is the last recorded deposit value.\\n */\\n function getDepositorETHGain(address _depositor) public view override returns (uint256) {\\n uint256 initialDeposit = deposits[_depositor].initialValue;\\n\\n if (initialDeposit == 0) {\\n return 0;\\n }\\n\\n Snapshots memory snapshots = depositSnapshots[_depositor];\\n\\n uint256 ETHGain = _getETHGainFromSnapshots(initialDeposit, snapshots);\\n return ETHGain;\\n }\\n\\n function _getETHGainFromSnapshots(uint256 initialDeposit, Snapshots memory snapshots)\\n internal\\n view\\n returns (uint256)\\n {\\n /*\\n * Grab the sum 'S' from the epoch at which the stake was made. The ETH gain may span up to one scale change.\\n * If it does, the second portion of the ETH gain is scaled by 1e9.\\n * If the gain spans no scale change, the second portion will be 0.\\n */\\n uint128 epochSnapshot = snapshots.epoch;\\n uint128 scaleSnapshot = snapshots.scale;\\n uint256 S_Snapshot = snapshots.S;\\n uint256 P_Snapshot = snapshots.P;\\n\\n uint256 firstPortion = epochToScaleToSum[epochSnapshot][scaleSnapshot].sub(S_Snapshot);\\n uint256 secondPortion = epochToScaleToSum[epochSnapshot][scaleSnapshot.add(1)].div(\\n SCALE_FACTOR\\n );\\n\\n uint256 ETHGain = initialDeposit.mul(firstPortion.add(secondPortion)).div(P_Snapshot).div(\\n DECIMAL_PRECISION\\n );\\n\\n return ETHGain;\\n }\\n\\n /**\\n * Calculate the SOV gain earned by a deposit since its last snapshots were taken.\\n * Given by the formula: SOV = d0 * (G - G(0))/P(0)\\n * where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively.\\n * d0 is the last recorded deposit value.\\n */\\n function getDepositorSOVGain(address _depositor) public view override returns (uint256) {\\n uint256 initialDeposit = deposits[_depositor].initialValue;\\n if (initialDeposit == 0) {\\n return 0;\\n }\\n\\n address frontEndTag = deposits[_depositor].frontEndTag;\\n\\n /*\\n * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned.\\n * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through\\n * which they made their deposit.\\n */\\n uint256 kickbackRate = frontEndTag == ADDRESS_ZERO\\n ? DECIMAL_PRECISION\\n : frontEnds[frontEndTag].kickbackRate;\\n\\n Snapshots memory snapshots = depositSnapshots[_depositor];\\n\\n uint256 SOVGain = kickbackRate\\n .mul(_getSOVGainFromSnapshots(initialDeposit, snapshots))\\n .div(DECIMAL_PRECISION);\\n\\n return SOVGain;\\n }\\n\\n /**\\n * Return the SOV gain earned by the front end. Given by the formula: E = D0 * (G - G(0))/P(0)\\n * where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively.\\n *\\n * D0 is the last recorded value of the front end's total tagged deposits.\\n */\\n function getFrontEndSOVGain(address _frontEnd) public view override returns (uint256) {\\n uint256 frontEndStake = frontEndStakes[_frontEnd];\\n if (frontEndStake == 0) {\\n return 0;\\n }\\n\\n uint256 kickbackRate = frontEnds[_frontEnd].kickbackRate;\\n uint256 frontEndShare = uint256(DECIMAL_PRECISION).sub(kickbackRate);\\n\\n Snapshots memory snapshots = frontEndSnapshots[_frontEnd];\\n\\n uint256 SOVGain = frontEndShare\\n .mul(_getSOVGainFromSnapshots(frontEndStake, snapshots))\\n .div(DECIMAL_PRECISION);\\n return SOVGain;\\n }\\n\\n function _getSOVGainFromSnapshots(uint256 initialStake, Snapshots memory snapshots)\\n internal\\n view\\n returns (uint256)\\n {\\n /*\\n * Grab the sum 'G' from the epoch at which the stake was made. The SOV gain may span up to one scale change.\\n * If it does, the second portion of the SOV gain is scaled by 1e9.\\n * If the gain spans no scale change, the second portion will be 0.\\n */\\n uint128 epochSnapshot = snapshots.epoch;\\n uint128 scaleSnapshot = snapshots.scale;\\n uint256 G_Snapshot = snapshots.G;\\n uint256 P_Snapshot = snapshots.P;\\n\\n uint256 firstPortion = epochToScaleToG[epochSnapshot][scaleSnapshot].sub(G_Snapshot);\\n uint256 secondPortion = epochToScaleToG[epochSnapshot][scaleSnapshot.add(1)].div(\\n SCALE_FACTOR\\n );\\n\\n uint256 SOVGain = initialStake.mul(firstPortion.add(secondPortion)).div(P_Snapshot).div(\\n DECIMAL_PRECISION\\n );\\n\\n return SOVGain;\\n }\\n\\n // --- Compounded deposit and compounded front end stake ---\\n\\n /**\\n * Return the user's compounded deposit. Given by the formula: d = d0 * P/P(0)\\n * where P(0) is the depositor's snapshot of the product P, taken when they last updated their deposit.\\n */\\n function getCompoundedZUSDDeposit(address _depositor) public view override returns (uint256) {\\n uint256 initialDeposit = deposits[_depositor].initialValue;\\n if (initialDeposit == 0) {\\n return 0;\\n }\\n\\n Snapshots memory snapshots = depositSnapshots[_depositor];\\n\\n uint256 compoundedDeposit = _getCompoundedStakeFromSnapshots(initialDeposit, snapshots);\\n return compoundedDeposit;\\n }\\n\\n /**\\n * Return the front end's compounded stake. Given by the formula: D = D0 * P/P(0)\\n * where P(0) is the depositor's snapshot of the product P, taken at the last time\\n * when one of the front end's tagged deposits updated their deposit.\\n *\\n * The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\\n */\\n function getCompoundedFrontEndStake(address _frontEnd) public view override returns (uint256) {\\n uint256 frontEndStake = frontEndStakes[_frontEnd];\\n if (frontEndStake == 0) {\\n return 0;\\n }\\n\\n Snapshots memory snapshots = frontEndSnapshots[_frontEnd];\\n\\n uint256 compoundedFrontEndStake = _getCompoundedStakeFromSnapshots(\\n frontEndStake,\\n snapshots\\n );\\n return compoundedFrontEndStake;\\n }\\n\\n // Internal function, used to calculcate compounded deposits and compounded front end stakes.\\n function _getCompoundedStakeFromSnapshots(uint256 initialStake, Snapshots memory snapshots)\\n internal\\n view\\n returns (uint256)\\n {\\n uint256 snapshot_P = snapshots.P;\\n uint128 scaleSnapshot = snapshots.scale;\\n uint128 epochSnapshot = snapshots.epoch;\\n\\n // If stake was made before a pool-emptying event, then it has been fully cancelled with debt -- so, return 0\\n if (epochSnapshot < currentEpoch) {\\n return 0;\\n }\\n\\n uint256 compoundedStake;\\n uint128 scaleDiff = currentScale.sub(scaleSnapshot);\\n\\n /* Compute the compounded stake. If a scale change in P was made during the stake's lifetime,\\n * account for it. If more than one scale change was made, then the stake has decreased by a factor of\\n * at least 1e-9 -- so return 0.\\n */\\n if (scaleDiff == 0) {\\n compoundedStake = initialStake.mul(P).div(snapshot_P);\\n } else if (scaleDiff == 1) {\\n compoundedStake = initialStake.mul(P).div(snapshot_P).div(SCALE_FACTOR);\\n } else {\\n // if scaleDiff >= 2\\n compoundedStake = 0;\\n }\\n\\n /*\\n * If compounded deposit is less than a billionth of the initial deposit, return 0.\\n *\\n * NOTE: originally, this line was in place to stop rounding errors making the deposit too large. However, the error\\n * corrections should ensure the error in P \\\"favors the Pool\\\", i.e. any given compounded deposit should slightly less\\n * than it's theoretical value.\\n *\\n * Thus it's unclear whether this line is still really needed.\\n */\\n if (compoundedStake < initialStake.div(1e9)) {\\n return 0;\\n }\\n\\n return compoundedStake;\\n }\\n\\n // --- Sender functions for ZUSD deposit, ETH gains and SOV gains ---\\n\\n /// Transfer the ZUSD tokens from the user to the Stability Pool's address, and update its recorded ZUSD\\n function _sendZUSDtoStabilityPool(address _address, uint256 _amount) internal {\\n zusdToken.sendToPool(_address, address(this), _amount);\\n uint256 newTotalZUSDDeposits = totalZUSDDeposits.add(_amount);\\n totalZUSDDeposits = newTotalZUSDDeposits;\\n emit StabilityPoolZUSDBalanceUpdated(newTotalZUSDDeposits);\\n }\\n\\n function _sendETHGainToDepositor(uint256 _amount) internal {\\n _sendETHGainTo(_amount, msg.sender);\\n }\\n\\n function _sendETHGainTo(uint256 _amount, address _receiver) internal {\\n require(_receiver != address(0), \\\"SP::_sendETHGainTo: _receiver is zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n uint256 newETH = ETH.sub(_amount);\\n ETH = newETH;\\n emit StabilityPoolETHBalanceUpdated(newETH);\\n emit EtherSent(msg.sender, _amount);\\n\\n (bool success, ) = msg.sender.call{ value: _amount }(\\\"\\\");\\n require(success, \\\"StabilityPool: sending ETH failed\\\");\\n }\\n\\n /// Send ZUSD to user and decrease ZUSD in Pool\\n function _sendZUSDToDepositor(address _depositor, uint256 ZUSDWithdrawal) internal {\\n if (ZUSDWithdrawal == 0) {\\n return;\\n }\\n\\n zusdToken.returnFromPool(address(this), _depositor, ZUSDWithdrawal);\\n _decreaseZUSD(ZUSDWithdrawal);\\n }\\n\\n // --- External Front End functions ---\\n\\n /// Front end makes a one-time selection of kickback rate upon registering\\n function registerFrontEnd(uint256 _kickbackRate) external override {\\n _requireFrontEndNotRegistered(msg.sender);\\n _requireUserHasNoDeposit(msg.sender);\\n _requireValidKickbackRate(_kickbackRate);\\n\\n frontEnds[msg.sender].kickbackRate = _kickbackRate;\\n frontEnds[msg.sender].registered = true;\\n\\n emit FrontEndRegistered(msg.sender, _kickbackRate);\\n }\\n\\n // --- Stability Pool Deposit Functionality ---\\n\\n function _setFrontEndTag(address _depositor, address _frontEndTag) internal {\\n deposits[_depositor].frontEndTag = _frontEndTag;\\n emit FrontEndTagSet(_depositor, _frontEndTag);\\n }\\n\\n function _updateDepositAndSnapshots(address _depositor, uint256 _newValue) internal {\\n deposits[_depositor].initialValue = _newValue;\\n\\n if (_newValue == 0) {\\n delete deposits[_depositor].frontEndTag;\\n delete depositSnapshots[_depositor];\\n emit DepositSnapshotUpdated(_depositor, 0, 0, 0);\\n return;\\n }\\n uint128 currentScaleCached = currentScale;\\n uint128 currentEpochCached = currentEpoch;\\n uint256 currentP = P;\\n\\n // Get S and G for the current epoch and current scale\\n uint256 currentS = epochToScaleToSum[currentEpochCached][currentScaleCached];\\n uint256 currentG = epochToScaleToG[currentEpochCached][currentScaleCached];\\n\\n // Record new snapshots of the latest running product P, sum S, and sum G, for the depositor\\n depositSnapshots[_depositor].P = currentP;\\n depositSnapshots[_depositor].S = currentS;\\n depositSnapshots[_depositor].G = currentG;\\n depositSnapshots[_depositor].scale = currentScaleCached;\\n depositSnapshots[_depositor].epoch = currentEpochCached;\\n\\n emit DepositSnapshotUpdated(_depositor, currentP, currentS, currentG);\\n }\\n\\n function _updateFrontEndStakeAndSnapshots(address _frontEnd, uint256 _newValue) internal {\\n frontEndStakes[_frontEnd] = _newValue;\\n\\n if (_newValue == 0) {\\n delete frontEndSnapshots[_frontEnd];\\n emit FrontEndSnapshotUpdated(_frontEnd, 0, 0);\\n return;\\n }\\n\\n uint128 currentScaleCached = currentScale;\\n uint128 currentEpochCached = currentEpoch;\\n uint256 currentP = P;\\n\\n // Get G for the current epoch and current scale\\n uint256 currentG = epochToScaleToG[currentEpochCached][currentScaleCached];\\n\\n // Record new snapshots of the latest running product P and sum G for the front end\\n frontEndSnapshots[_frontEnd].P = currentP;\\n frontEndSnapshots[_frontEnd].G = currentG;\\n frontEndSnapshots[_frontEnd].scale = currentScaleCached;\\n frontEndSnapshots[_frontEnd].epoch = currentEpochCached;\\n\\n emit FrontEndSnapshotUpdated(_frontEnd, currentP, currentG);\\n }\\n\\n function _payOutSOVGains(\\n ICommunityIssuance _communityIssuance,\\n address _depositor,\\n address _frontEnd\\n ) internal {\\n // Pay out front end's SOV gain\\n if (_frontEnd != ADDRESS_ZERO) {\\n uint256 frontEndSOVGain = getFrontEndSOVGain(_frontEnd);\\n _communityIssuance.sendSOV(_frontEnd, frontEndSOVGain);\\n emit SOVPaidToFrontEnd(_frontEnd, frontEndSOVGain);\\n }\\n\\n // Pay out depositor's SOV gain\\n uint256 depositorSOVGain = getDepositorSOVGain(_depositor);\\n _communityIssuance.sendSOV(_depositor, depositorSOVGain);\\n emit SOVPaidToDepositor(_depositor, depositorSOVGain);\\n }\\n\\n // --- 'require' functions ---\\n\\n function _requireCallerIsActivePool() internal view {\\n require(msg.sender == address(activePool), \\\"StabilityPool: Caller is not ActivePool\\\");\\n }\\n\\n function _requireCallerIsTroveManager() internal view {\\n require(msg.sender == address(troveManager), \\\"StabilityPool: Caller is not TroveManager\\\");\\n }\\n\\n function _requireNoUnderCollateralizedTroves() internal {\\n uint256 price = priceFeed.fetchPrice();\\n address lowestTrove = sortedTroves.getLast();\\n uint256 ICR = troveManager.getCurrentICR(lowestTrove, price);\\n require(\\n ICR >= liquityBaseParams.MCR(),\\n \\\"StabilityPool: Cannot withdraw while there are troves with ICR < MCR\\\"\\n );\\n }\\n\\n function _requireUserHasDeposit(uint256 _initialDeposit) internal pure {\\n require(_initialDeposit > 0, \\\"StabilityPool: User must have a non-zero deposit\\\");\\n }\\n\\n function _requireUserHasNoDeposit(address _address) internal view {\\n uint256 initialDeposit = deposits[_address].initialValue;\\n require(initialDeposit == 0, \\\"StabilityPool: User must have no deposit\\\");\\n }\\n\\n function _requireNonZeroAmount(uint256 _amount) internal pure {\\n require(_amount > 0, \\\"StabilityPool: Amount must be non-zero\\\");\\n }\\n\\n function _requireUserHasTrove(address _depositor) internal view {\\n require(\\n troveManager.getTroveStatus(_depositor) == 1,\\n \\\"StabilityPool: caller must have an active trove to withdraw ETHGain to\\\"\\n );\\n }\\n\\n function _requireUserHasETHGain(address _depositor) internal view {\\n uint256 ETHGain = getDepositorETHGain(_depositor);\\n require(ETHGain > 0, \\\"StabilityPool: caller must have non-zero ETH Gain\\\");\\n }\\n\\n function _requireFrontEndNotRegistered(address _address) internal view {\\n require(\\n !frontEnds[_address].registered,\\n \\\"StabilityPool: must not already be a registered front end\\\"\\n );\\n }\\n\\n function _requireFrontEndIsRegisteredOrZero(address _address) internal view {\\n require(\\n frontEnds[_address].registered || _address == ADDRESS_ZERO,\\n \\\"StabilityPool: Tag must be a registered front end, or the zero address\\\"\\n );\\n }\\n\\n function _requireValidKickbackRate(uint256 _kickbackRate) internal pure {\\n require(\\n _kickbackRate <= DECIMAL_PRECISION,\\n \\\"StabilityPool: Kickback rate must be in range [0,1]\\\"\\n );\\n }\\n\\n // --- Fallback function ---\\n\\n receive() external payable {\\n _requireCallerIsActivePool();\\n ETH = ETH.add(msg.value);\\n StabilityPoolETHBalanceUpdated(ETH);\\n }\\n}\\n\",\"keccak256\":\"0xba9a1f4ef8bf737262b6aa77fac2247ea1ae68d51267496c46ad817bfc9f7acd\",\"license\":\"MIT\"},\"contracts/StabilityPoolStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./Interfaces/IStabilityPool.sol\\\";\\nimport \\\"./Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./Interfaces/ITroveManager.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/ICommunityIssuance.sol\\\";\\nimport \\\"./Dependencies/Ownable.sol\\\";\\nimport \\\"./Dependencies/BaseMath.sol\\\";\\n\\ncontract StabilityPoolStorage is Ownable, BaseMath {\\n string public constant NAME = \\\"StabilityPool\\\";\\n\\n IBorrowerOperations public borrowerOperations;\\n\\n ITroveManager public troveManager;\\n\\n IZUSDToken public zusdToken;\\n\\n // Needed to check if there are pending liquidations\\n ISortedTroves public sortedTroves;\\n\\n ICommunityIssuance public communityIssuance;\\n\\n uint256 internal ETH; // deposited ether tracker\\n\\n // Tracker for ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\\n uint256 internal totalZUSDDeposits;\\n\\n // --- Data structures ---\\n\\n struct FrontEnd {\\n uint256 kickbackRate;\\n bool registered;\\n }\\n\\n struct Deposit {\\n uint256 initialValue;\\n address frontEndTag;\\n }\\n\\n struct Snapshots {\\n uint256 S;\\n uint256 P;\\n uint256 G;\\n uint128 scale;\\n uint128 epoch;\\n }\\n\\n mapping(address => Deposit) public deposits; // depositor address -> Deposit struct\\n mapping(address => Snapshots) public depositSnapshots; // depositor address -> snapshots struct\\n\\n mapping(address => FrontEnd) public frontEnds; // front end address -> FrontEnd struct\\n mapping(address => uint256) public frontEndStakes; // front end address -> last recorded total deposits, tagged with that front end\\n mapping(address => Snapshots) public frontEndSnapshots; // front end address -> snapshots struct\\n\\n /* Product 'P': Running product by which to multiply an initial deposit, in order to find the current compounded deposit,\\n * after a series of liquidations have occurred, each of which cancel some ZUSD debt with the deposit.\\n *\\n * During its lifetime, a deposit's value evolves from d_t to d_t * P / P_t , where P_t\\n * is the snapshot of P taken at the instant the deposit was made. 18-digit decimal.\\n */\\n uint256 public P;\\n\\n uint256 public constant SCALE_FACTOR = 1e9;\\n\\n // Each time the scale of P shifts by SCALE_FACTOR, the scale is incremented by 1\\n uint128 public currentScale;\\n\\n // With each offset that fully empties the Pool, the epoch is incremented by 1\\n uint128 public currentEpoch;\\n\\n /* ETH Gain sum 'S': During its lifetime, each deposit d_t earns an ETH gain of ( d_t * [S - S_t] )/P_t, where S_t\\n * is the depositor's snapshot of S taken at the time t when the deposit was made.\\n *\\n * The 'S' sums are stored in a nested mapping (epoch => scale => sum):\\n *\\n * - The inner mapping records the sum S at different scales\\n * - The outer mapping records the (scale => sum) mappings, for different epochs.\\n */\\n mapping(uint128 => mapping(uint128 => uint256)) public epochToScaleToSum;\\n\\n /*\\n * Similarly, the sum 'G' is used to calculate SOV gains. During it's lifetime, each deposit d_t earns a SOV gain of\\n * ( d_t * [G - G_t] )/P_t, where G_t is the depositor's snapshot of G taken at time t when the deposit was made.\\n *\\n * SOV reward events occur are triggered by depositor operations (new deposit, topup, withdrawal), and liquidations.\\n * In each case, the SOV reward is issued (i.e. G is updated), before other state changes are made.\\n */\\n mapping(uint128 => mapping(uint128 => uint256)) public epochToScaleToG;\\n\\n // Error tracker for the error correction in the SOV issuance calculation\\n uint256 public lastSOVError;\\n // Error trackers for the error correction in the offset calculation\\n uint256 public lastETHError_Offset;\\n uint256 public lastZUSDLossError_Offset;\\n}\\n\",\"keccak256\":\"0x046ee6c1e461c41f97120bec0380f90c35dfc6042ff10249ab3ed75f2217b7d0\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60a06040523480156200001157600080fd5b5060405162004b8c38038062004b8c833981016040819052620000349162000123565b62000048336001600160e01b036200005e16565b60601b6001600160601b031916608052620001b2565b6001600160a01b038116620000905760405162461bcd60e51b8152600401620000879062000170565b60405180910390fd5b6001600160a01b038116620000ad6001600160e01b036200010216565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f29062000153565b6040519081900390209190915550565b600080604051620001139062000153565b6040519081900390205492915050565b60006020828403121562000135578081fd5b81516001600160a01b03811681146200014c578182fd5b9392505050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160601c6149b7620001d560003980610ad0528061189a52506149b76000f3fe6080604052600436106102ad5760003560e01c806382e0a57411610165578063b31ee965116100cc578063de13da3c11610085578063de13da3c14610788578063df9cd84f146107a8578063e49d3667146107c8578063ec9f7d46146107e8578063fc7e286d146107fd578063fce6b7341461082b578063fda0101a1461084b576102f8565b8063b31ee965146106f4578063bdaf37ea14610709578063c3a34a0e1461071e578063ce4b5bbe1461073e578063d733cfd014610753578063d7fb044314610773576102f8565b80639f0706701161011e5780639f07067014610665578063a20baee614610531578063a3f4df7e1461067a578063a4e59ac81461069c578063a7bfff97146106b1578063ae918754146106df576102f8565b806382e0a574146105d157806386da0824146105f1578063887105d314610611578063893d20e8146106265780638b8fbd921461063b57806395fb16bb14610650576102f8565b80633d83908a1161021457806372fe25aa116101cd57806372fe25aa14610531578063741bef1a14610546578063759b30341461055b578063766718081461057057806377553ad414610592578063795d26c3146105a75780637f7dde4a146105bc576102f8565b80633d83908a1461048757806340ed1afd1461049c578063556be101146104bc5780635d2de642146104dc5780635f788d65146104fc57806370f1b5721461051c576102f8565b80632199b66f116102665780632199b66f146103d257806328a0a04d146103f25780632e54bf9514610412578063335525ad14610432578063389e92a5146104525780633cc7422514610472576102f8565b80630fbfe38b146102fd57806312261ee71461031f57806313af40351461034a57806314f6c3be1461036a57806316b9d3c51461038c5780631bf43555146103bd576102f8565b366102f8576102ba61086b565b6009546102cd903463ffffffff6108a016565b6009819055604051600080516020614902833981519152916102ee91614847565b60405180910390a1005b600080fd5b34801561030957600080fd5b5061031d610318366004613d86565b6108ce565b005b34801561032b57600080fd5b50610334610ace565b6040516103419190613f43565b60405180910390f35b34801561035657600080fd5b5061031d610365366004613c1a565b610af2565b34801561037657600080fd5b5061037f610b36565b6040516103419190614847565b34801561039857600080fd5b506103ac6103a7366004613c1a565b610b3c565b604051610341959493929190614896565b3480156103c957600080fd5b5061037f610b77565b3480156103de57600080fd5b5061031d6103ed366004613c1a565b610b84565b3480156103fe57600080fd5b5061037f61040d366004613d52565b610c1b565b34801561041e57600080fd5b5061031d61042d366004613d86565b610c38565b34801561043e57600080fd5b5061031d61044d366004613ec9565b610c46565b34801561045e57600080fd5b5061037f61046d366004613c1a565b610ca9565b34801561047e57600080fd5b50610334610d51565b34801561049357600080fd5b50610334610d60565b3480156104a857600080fd5b5061037f6104b7366004613c1a565b610d6f565b3480156104c857600080fd5b5061031d6104d7366004613d86565b610e0c565b3480156104e857600080fd5b5061037f6104f7366004613c1a565b610e84565b34801561050857600080fd5b5061031d610517366004613db6565b610e96565b34801561052857600080fd5b5061037f610ea0565b34801561053d57600080fd5b5061037f610ea6565b34801561055257600080fd5b50610334610eb2565b34801561056757600080fd5b5061037f610ec1565b34801561057c57600080fd5b50610585610ece565b6040516103419190614833565b34801561059e57600080fd5b50610334610ee4565b3480156105b357600080fd5b5061037f610ef3565b3480156105c857600080fd5b50610334611012565b3480156105dd57600080fd5b5061037f6105ec366004613d52565b611021565b3480156105fd57600080fd5b506103ac61060c366004613c1a565b61103e565b34801561061d57600080fd5b5061037f611079565b34801561063257600080fd5b50610334611148565b34801561064757600080fd5b5061037f611167565b34801561065c57600080fd5b5061033461116d565b34801561067157600080fd5b5061033461117c565b34801561068657600080fd5b5061068f61118b565b6040516103419190614060565b3480156106a857600080fd5b506105856111b4565b3480156106bd57600080fd5b506106d16106cc366004613c1a565b6111c3565b604051610341929190614867565b3480156106eb57600080fd5b506103346111df565b34801561070057600080fd5b5061037f6111ee565b34801561071557600080fd5b5061037f6111f4565b34801561072a57600080fd5b5061031d610739366004613dda565b6111fa565b34801561074a57600080fd5b5061037f61129e565b34801561075f57600080fd5b5061031d61076e366004613c8a565b6112a6565b34801561077f57600080fd5b5061037f611538565b34801561079457600080fd5b5061037f6107a3366004613c1a565b61153e565b3480156107b457600080fd5b5061037f6107c3366004613c1a565b611642565b3480156107d457600080fd5b5061037f6107e3366004613c1a565b6116df565b3480156107f457600080fd5b506103346117dc565b34801561080957600080fd5b5061081d610818366004613c1a565b6117eb565b604051610341929190614850565b34801561083757600080fd5b5061031d610846366004613e10565b61180d565b34801561085757600080fd5b5061031d610866366004613c52565b6118cd565b6000546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614258565b60405180910390fd5b565b6000828201838110156108c55760405162461bcd60e51b815260040161089590614168565b90505b92915050565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561091e57600080fd5b505afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613c36565b905060006109648330611b13565b60065460405163095ea7b360e01b81529192506001600160a01b03169063095ea7b3906109979085908590600401613fdf565b602060405180830381600087803b1580156109b157600080fd5b505af11580156109c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e99190613d32565b610a055760405162461bcd60e51b8152600401610895906145ef565b60065460405163438b1b4b60e01b81526001600160a01b038481169263438b1b4b92610a3b929091169085903390600401614019565b602060405180830381600087803b158015610a5557600080fd5b505af1158015610a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8d9190613d9e565b507f2b0fbec1c4e7e30517f196a714775ffe72770d2348f5d586854bb3c0fdf41df8338483604051610ac193929190613ff8565b60405180910390a1505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b610afa611148565b6001600160a01b0316336001600160a01b031614610b2a5760405162461bcd60e51b81526004016108959061451d565b610b3381611cde565b50565b60095490565b600f602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6809c2007651b250000081565b610b8c611148565b6001600160a01b0316336001600160a01b031614610bbc5760405162461bcd60e51b81526004016108959061451d565b610bc581611d69565b600880546001600160a01b0319166001600160a01b0383161790556040517f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac681190610c10908390613f43565b60405180910390a150565b601260209081526000928352604080842090915290825290205481565b610c428133611b13565b5050565b610c4e611dae565b600a54801580610c5c575082155b15610c675750610c42565b600854610c7c906001600160a01b0316611dd8565b600080610c8a848685611e65565b91509150610c988282611f5e565b610ca2848661225f565b5050505050565b6001600160a01b0381166000908152600b602052604081205480610cd1576000915050610d4c565b610cd9613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612395565b93505050505b919050565b6001546001600160a01b031681565b6005546001600160a01b031681565b6001600160a01b0381166000908152600b602052604081205480610d97576000915050610d4c565b610d9f613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b610e1533612582565b610e1e336125be565b610e27816125f5565b336000818152600d6020526040908190208381556001908101805460ff19169091179055517f19bc932fb9e16a8b5a1e41be9f4c2de59d5ddd7567b8b81405f532ca00a9880e90610e79908490614847565b60405180910390a250565b600e6020526000908152604090205481565b610c42828261261d565b60145481565b670de0b6b3a764000081565b6002546001600160a01b031681565b6801158e460913d0000081565b601154600160801b90046001600160801b031681565b6004546001600160a01b031681565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3757600080fd5b505afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b505afa158015610fd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff99190613d9e565b905061100b828263ffffffff6108a016565b9250505090565b6000546001600160a01b031681565b601360209081526000928352604080842090915290825290205481565b600c602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156110be57600080fd5b505afa1580156110d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f69190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b60008060405161115790613f26565b6040519081900390205492915050565b60105481565b6008546001600160a01b031681565b6003546001600160a01b031681565b6040518060400160405280600d81526020016c14dd18589a5b1a5d1e541bdbdb609a1b81525081565b6011546001600160801b031681565b600d602052600090815260409020805460019091015460ff1682565b6007546001600160a01b031681565b60165481565b600a5490565b600480546040805163e9fc346160e01b8152905160009361128c936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561124057600080fd5b505afa158015611254573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112789190613c36565b60065485906001600160a01b0316856127c0565b905061129981600061261d565b505050565b633b9aca0081565b6112ae611148565b6001600160a01b0316336001600160a01b0316146112de5760405162461bcd60e51b81526004016108959061451d565b6112e788611d69565b6112f087611d69565b6112f986611d69565b61130285611d69565b61130b84611d69565b61131483611d69565b61131d82611d69565b61132681611d69565b670de0b6b3a7640000601055600380546001600160a01b03199081166001600160a01b038b8116919091179092556004805482168a8416179055600580548216898416179055600080548216888416179055600680548216878416179055600780548216868416179055600280548216858416179055600880549091169183169190911790556040517f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed985906113dc908990613f43565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a5678866040516114139190613f43565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828560405161144a9190613f43565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d846040516114819190613f43565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800836040516114b89190613f43565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264826040516114ef9190613f43565b60405180910390a17f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac6811816040516115269190613f43565b60405180910390a15050505050505050565b60155481565b6001600160a01b0381166000908152600e602052604081205480611566576000915050610d4c565b6001600160a01b0383166000908152600d602052604081205490611598670de0b6b3a76400008363ffffffff612a6516565b90506115a2613b64565b506001600160a01b0385166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b869063ffffffff612b3316565b9063ffffffff612b6d16565b979650505050505050565b6001600160a01b0381166000908152600e60205260408120548061166a576000915050610d4c565b611672613b64565b506001600160a01b0383166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b6001600160a01b0381166000908152600b602052604081205480611707576000915050610d4c565b6001600160a01b038084166000908152600b602052604081206001015490911690811561174c576001600160a01b0382166000908152600d6020526040902054611756565b670de0b6b3a76400005b9050611760613b64565b506001600160a01b0385166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b6006546001600160a01b031681565b600b60205260009081526040902080546001909101546001600160a01b031682565b600480546040805163e9fc346160e01b815290516000936118c0936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561185357600080fd5b505afa158015611867573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188b9190613c36565b6006546001600160a01b0316867f00000000000000000000000000000000000000000000000000000000000000008787612baf565b9050610ca281600061261d565b336000908152600b60205260409020546118e681612dfc565b6118ef33612e1c565b6118f833612ebb565b6008546001600160a01b031661190d81611dd8565b600061191833610ca9565b9050600061192533610d6f565b90506000611939858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b039091169061196790869083612ee8565b600061197282611642565b90508061197f838261305d565b826001600160a01b031660008051602061496283398151915282336040516119a8929190614850565b60405180910390a26119ba33866131a5565b336001600160a01b031660008051602061494283398151915287866040516119e392919061403c565b60405180910390a2336001600160a01b031660008051602061492283398151915286604051611a129190614847565b60405180910390a2600954611a2d908763ffffffff612a6516565b600981905560405160008051602061490283398151915291611a4e91614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123387604051611a87929190613fdf565b60405180910390a1600460009054906101000a90046001600160a01b03166001600160a01b031663ea9638bf87338d8d6040518563ffffffff1660e01b8152600401611ad593929190613f57565b6000604051808303818588803b158015611aee57600080fd5b505af1158015611b02573d6000803e3d6000fd5b505050505050505050505050505050565b60006001600160a01b038216611b3b5760405162461bcd60e51b815260040161089590614434565b8215611b4957611b4961331a565b336000908152600b6020526040902054611b6281612dfc565b6008546001600160a01b0316611b7781611dd8565b6000611b8233610ca9565b90506000611b8f33610d6f565b90506000611b9d8883613551565b90506000611bb1868463ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b0390911690611bdf90879083612ee8565b6000611bea82611642565b90506000611bfe828663ffffffff612a6516565b9050611c0a838261305d565b826001600160a01b03166000805160206149628339815191528233604051611c33929190614850565b60405180910390a2611c458b86613567565b6000611c57878763ffffffff612a6516565b9050611c6333826131a5565b336001600160a01b031660008051602061492283398151915282604051611c8a9190614847565b60405180910390a2336001600160a01b03166000805160206149428339815191528987604051611cbb92919061403c565b60405180910390a2611ccd88336135e0565b50939b9a5050505050505050505050565b6001600160a01b038116611d045760405162461bcd60e51b81526004016108959061429f565b806001600160a01b0316611d16611148565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611d5990613f26565b6040519081900390209190915550565b6001600160a01b038116611d8f5760405162461bcd60e51b8152600401610895906142e1565b803b80610c425760405162461bcd60e51b815260040161089590614646565b6005546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614369565b600a54604051636cbdcf4760e01b81526000916001600160a01b03841691636cbdcf4791611e0891600401614847565b602060405180830381600087803b158015611e2257600080fd5b505af1158015611e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5a9190613d9e565b9050610c428161370f565b6000806000611e97601554611e8b670de0b6b3a764000089612b3390919063ffffffff16565b9063ffffffff6108a016565b905083851115611ea357fe5b83851415611ec0576000601655670de0b6b3a76400009150611f20565b601654600090611eee90611ee288670de0b6b3a764000063ffffffff612b3316565b9063ffffffff612a6516565b9050611f056001611e8b838863ffffffff612b6d16565b9250611f1b81611ee2858863ffffffff612b3316565b601655505b611f30818563ffffffff612b6d16565b9250611f52611f45848663ffffffff612b3316565b829063ffffffff612a6516565b60155550935093915050565b6010546000670de0b6b3a7640000831115611f7557fe5b6000611f8f670de0b6b3a76400008563ffffffff612a6516565b6011546001600160801b03600160801b820481166000818152601260209081526040808320949095168083529390529283205493945090929091611fd38988612b33565b90506000611fe7838363ffffffff6108a016565b6001600160801b038086166000908152601260209081526040808320938a168352929052819020829055519091507fe12e2cd2c9afa8069203ca07e7eff1edce4a075686d0736a8e7e0d593597b2079061204690839087908990614877565b60405180910390a18561211f5761206d6001600160801b038516600163ffffffff61382016565b601180546001600160801b03908116600160801b938216840217918290556040517fb50f0f59e7cb5b421dc77581c3a9919e3806e076e5fa78a874c3f120cb7d874d936120be930490911690614833565b60405180910390a1601180546001600160801b03191690556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9061210790600090614833565b60405180910390a1670de0b6b3a7640000965061220c565b633b9aca00612140670de0b6b3a764000061162b8b8a63ffffffff612b3316565b10156121ed57612176670de0b6b3a764000061162b633b9aca0061216a8c8b63ffffffff612b3316565b9063ffffffff612b3316565b96506121926001600160801b038616600163ffffffff61382016565b601180546001600160801b0319166001600160801b0392831617908190556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe926121e0921690614833565b60405180910390a161220c565b612209670de0b6b3a764000061162b8a8963ffffffff612b3316565b96505b6000871161221657fe5b60108790556040517fc1a9618cb59ebca77cbdbc2949f126823c407ff13edb285fd0262519a9c18e8c9061224b908990614847565b60405180910390a150505050505050505050565b60005460405163121cbc4d60e11b81526001600160a01b03909116908190632439789a90612291908590600401614847565b600060405180830381600087803b1580156122ab57600080fd5b505af11580156122bf573d6000803e3d6000fd5b505050506122cc82613851565b600654604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906122fe9030908690600401613fdf565b600060405180830381600087803b15801561231857600080fd5b505af115801561232c573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b03841692506364a197f3915061235e9030908790600401613fdf565b600060405180830381600087803b15801561237857600080fd5b505af115801561238c573d6000803e3d6000fd5b50505050505050565b6080810151606082015182516020808501516001600160801b038086166000908152601284526040808220928716825291909352822054919493929185906123e3908463ffffffff612a6516565b6001600160801b0380871660009081526012602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b6001600160801b031681526020810191909152604001600020549063ffffffff612b6d16565b90506000612478670de0b6b3a764000061162b868161246b888863ffffffff6108a016565b8f9063ffffffff612b3316565b9a9950505050505050505050565b6020810151606082015160808301516011546000939291906001600160801b03600160801b909104811690821610156124c557600093505050506108c8565b60115460009081906124e6906001600160801b03168563ffffffff6138ab16565b90506001600160801b0381166125165761250f8561162b6010548b612b3390919063ffffffff16565b915061254e565b806001600160801b0316600114156125495761250f633b9aca0061162b8761162b6010548d612b3390919063ffffffff16565b600091505b61256288633b9aca0063ffffffff612b6d16565b821015612577576000955050505050506108c8565b509695505050505050565b6001600160a01b0381166000908152600d602052604090206001015460ff1615610b335760405162461bcd60e51b81526004016108959061454e565b6001600160a01b0381166000908152600b60205260409020548015610c425760405162461bcd60e51b8152600401610895906145a7565b670de0b6b3a7640000811115610b335760405162461bcd60e51b815260040161089590614484565b612626816138e5565b61262f33612582565b61263882613932565b336000908152600b60205260409020546008546001600160a01b031661265d81611dd8565b8161266c5761266c3384613952565b600061267733610ca9565b9050600061268433610d6f565b90506000612698858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b03909116906126c690869083612ee8565b60006126d182611642565b905060006126e5828b63ffffffff6108a016565b90506126f1838261305d565b826001600160a01b0316600080516020614962833981519152823360405161271a929190614850565b60405180910390a261272c338b6139ac565b600061273e868c63ffffffff6108a016565b905061274a33826131a5565b336001600160a01b0316600080516020614922833981519152826040516127719190614847565b60405180910390a2336001600160a01b031660008051602061494283398151915288876040516127a292919061403c565b60405180910390a26127b387613a60565b5050505050505050505050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b1580156127fc57600080fd5b505afa158015612810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128349190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016128649190613f43565b60206040518083038186803b15801561287c57600080fd5b505afa158015612890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b49190613d9e565b9050306001600160a01b03831663605629d633838a89356128db60408c0160208d01613eea565b8b604001358c606001356040518863ffffffff1660e01b81526004016129079796959493929190613f9e565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b50505050866129ba83856001600160a01b03166370a08231856040518263ffffffff1660e01b815260040161296a9190613f43565b60206040518083038186803b15801561298257600080fd5b505afa158015612996573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee29190613d9e565b146129d75760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390612a079089908b903390600401614019565b602060405180830381600087803b158015612a2157600080fd5b505af1158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613d9e565b98975050505050505050565b60006108c583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a6a565b608081015160608201516040808401516020808601516001600160801b03808716600090815260138452858120918716815292529281205490949392908590612af6908463ffffffff612a6516565b6001600160801b0380871660009081526013602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b600082612b42575060006108c8565b82820282848281612b4f57fe5b04146108c55760405162461bcd60e51b8152600401610895906143f3565b60006108c583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613a96565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015612beb57600080fd5b505afa158015612bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c239190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612c539190613f43565b60206040518083038186803b158015612c6b57600080fd5b505afa158015612c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca39190613d9e565b87516020015190915030906001600160a01b0388166330f28b7a8a612cc88585613acd565b338b8b6040518663ffffffff1660e01b8152600401612ceb9594939291906147c2565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b5050505080612d4e84866001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161296a9190613f43565b14612d6b5760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390612d9b908d9085903390600401614019565b602060405180830381600087803b158015612db557600080fd5b505af1158015612dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ded9190613d9e565b9b9a5050505050505050505050565b60008111610b335760405162461bcd60e51b81526004016108959061467b565b6005546040516321e3780160e01b81526001600160a01b03909116906321e3780190612e4c908490600401613f43565b60206040518083038186803b158015612e6457600080fd5b505afa158015612e78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9c9190613d9e565b600114610b335760405162461bcd60e51b8152600401610895906140b3565b6000612ec682610ca9565b905060008111610c425760405162461bcd60e51b815260040161089590614318565b6001600160a01b03811615612fa8576000612f028261153e565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612f339085908590600401613fdf565b600060405180830381600087803b158015612f4d57600080fd5b505af1158015612f61573d6000803e3d6000fd5b50505050816001600160a01b03167f732e331072fe280a520929e5f2cc76c223389ff57d32a4e278cfded03e6f1caa82604051612f9e9190614847565b60405180910390a2505b6000612fb3836116df565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612fe49086908590600401613fdf565b600060405180830381600087803b158015612ffe57600080fd5b505af1158015613012573d6000803e3d6000fd5b50505050826001600160a01b03167fe9ac2dcd83e719358f1dc0c5c80491937f67d4ec61ef62c262bbe3b78578f92a8260405161304f9190614847565b60405180910390a250505050565b6001600160a01b0382166000908152600e60205260409020819055806130e8576001600160a01b0382166000818152600f60205260408082208281556001810183905560028101839055600301829055517fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e45916130db91819061403c565b60405180910390a2610c42565b6011546010546001600160801b03600160801b80840482166000818152601360209081526040808320978616808452978252808320546001600160a01b038b16808552600f90935292819020600181018890556002810184905560030180546001600160801b0319168917909616948402949094179094559151909392907fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e4590613195908590859061403c565b60405180910390a2505050505050565b6001600160a01b0382166000908152600b6020526040902081905580613243576001600160a01b0382166000818152600b60209081526040808320600190810180546001600160a01b0319169055600c909252808320838155918201839055600282018390556003909101829055517f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a916130db918190819061404a565b6011546010546001600160801b03600160801b8084048216600081815260126020908152604080832097861680845297825280832054848452601383528184208985528352818420546001600160a01b038c16808652600c90945293829020600181018990558181556002810185905560030180546001600160801b0319168a1790971695850295909517909555935191949390917f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a906133099086908690869061404a565b60405180910390a250505050505050565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561336057600080fd5b505af1158015613374573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133989190613d9e565b90506000600760009054906101000a90046001600160a01b03166001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ea57600080fd5b505afa1580156133fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134229190613c36565b600554604051630d293c7160e41b81529192506000916001600160a01b039091169063d293c7109061345a9085908790600401613fdf565b60206040518083038186803b15801561347257600080fd5b505afa158015613486573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134aa9190613d9e565b9050600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156134fa57600080fd5b505afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135329190613d9e565b8110156112995760405162461bcd60e51b815260040161089590614758565b600081831061356057816108c5565b5090919050565b8061357157610c42565b600654604051631062c15f60e11b81526001600160a01b03909116906320c582be906135a590309086908690600401613f7a565b600060405180830381600087803b1580156135bf57600080fd5b505af11580156135d3573d6000803e3d6000fd5b50505050610c4281613851565b6001600160a01b0381166136065760405162461bcd60e51b81526004016108959061419f565b8161361057610c42565b600954600090613626908463ffffffff612a6516565b9050806009819055506000805160206149028339815191528160405161364c9190614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123384604051613685929190613fdf565b60405180910390a16000336001600160a01b0316846040516136a690613f23565b60006040518083038185875af1925050503d80600081146136e3576040519150601f19603f3d011682016040523d82523d6000602084013e6136e8565b606091505b50509050806137095760405162461bcd60e51b8152600401610895906143b2565b50505050565b600a5480158061371d575081155b156137285750610b33565b60006137348383613aff565b9050600061374d60105483612b3390919063ffffffff16565b6011546001600160801b03600160801b820481166000908152601360209081526040808320939094168252919091522054909150613791908263ffffffff6108a016565b601180546001600160801b03600160801b80830482166000908152601360208181526040808420968616845295815285832097909755945491820483168082529486528381209190921680835294528190205490517f2d6127771b164a9cc8827d24b5955db2a77e7a81dac389107ebb8bce9fb64968936138129391614877565b60405180910390a150505050565b60008282016001600160801b0380851690821610156108c55760405162461bcd60e51b815260040161089590614713565b600a54600090613867908363ffffffff612a6516565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c78160405161389f9190614847565b60405180910390a15050565b6000826001600160801b0316826001600160801b031611156138df5760405162461bcd60e51b8152600401610895906146cb565b50900390565b6001600160a01b0381166000908152600d602052604090206001015460ff168061391657506001600160a01b038116155b610b335760405162461bcd60e51b8152600401610895906141ec565b60008111610b335760405162461bcd60e51b8152600401610895906144d7565b6001600160a01b038281166000818152600b602052604080822060010180546001600160a01b0319169486169485179055517f094c08e96a8890877a8390b4f967180a7507ad8622244d05fcd0f9f8e086564e9190a35050565b600654604051632ee65eeb60e21b81526001600160a01b039091169063bb997bac906139e090859030908690600401613f7a565b600060405180830381600087803b1580156139fa57600080fd5b505af1158015613a0e573d6000803e3d6000fd5b5050600a5460009250613a2891508363ffffffff6108a016565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c781604051610ac19190614847565b610b3381336135e0565b60008184841115613a8e5760405162461bcd60e51b81526004016108959190614060565b505050900390565b60008183613ab75760405162461bcd60e51b81526004016108959190614060565b506000838581613ac357fe5b0495945050505050565b613ad5613ba5565b613add613ba5565b5050604080518082019091526001600160a01b03929092168252602082015290565b600080613b23601454611e8b670de0b6b3a764000087612b3390919063ffffffff16565b90506000613b37828563ffffffff612b6d16565b9050613b59613b4c828663ffffffff612b3316565b839063ffffffff612a6516565b601455949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b604080518082019091526000808252602082015290565b60008083601f840112613bcd578182fd5b50813567ffffffffffffffff811115613be4578182fd5b602083019150836020828501011115613bfc57600080fd5b9250929050565b80356001600160801b03811681146108c857600080fd5b600060208284031215613c2b578081fd5b81356108c5816148ec565b600060208284031215613c47578081fd5b81516108c5816148ec565b60008060408385031215613c64578081fd5b8235613c6f816148ec565b91506020830135613c7f816148ec565b809150509250929050565b600080600080600080600080610100898b031215613ca6578384fd5b8835613cb1816148ec565b97506020890135613cc1816148ec565b96506040890135613cd1816148ec565b95506060890135613ce1816148ec565b94506080890135613cf1816148ec565b935060a0890135613d01816148ec565b925060c0890135613d11816148ec565b915060e0890135613d21816148ec565b809150509295985092959890939650565b600060208284031215613d43578081fd5b815180151581146108c5578182fd5b60008060408385031215613d64578182fd5b613d6e8484613c03565b9150613d7d8460208501613c03565b90509250929050565b600060208284031215613d97578081fd5b5035919050565b600060208284031215613daf578081fd5b5051919050565b60008060408385031215613dc8578182fd5b823591506020830135613c7f816148ec565b60008082840360a0811215613ded578283fd5b833592506080601f1982011215613e02578182fd5b506020830190509250929050565b60008060008084860360c0811215613e26578485fd5b85359450601f1981016080811215613e3c578485fd5b613e4660606148c5565b91506040811215613e55578485fd5b50613e6060406148c5565b6020870135613e6e816148ec565b80825250604087013560208201528082525060608601356020820152608086013560408201528093505060a085013567ffffffffffffffff811115613eb1578283fd5b613ebd87828801613bbc565b95989497509550505050565b60008060408385031215613edb578182fd5b50508035926020909101359150565b600060208284031215613efb578081fd5b813560ff811681146108c5578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b6000602080835283518082850152825b8181101561408c57858101830151858201604001528201614070565b8181111561409d5783604083870101525b50601f01601f1916929092016040019392505050565b60208082526046908201527f53746162696c697479506f6f6c3a2063616c6c6572206d75737420686176652060408201527f616e206163746976652074726f766520746f207769746864726177204554484760608201526561696e20746f60d01b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252602d908201527f53503a3a5f73656e644554484761696e546f3a205f726563656976657220697360408201526c207a65726f206164647265737360981b606082015260800190565b60208082526046908201527f53746162696c697479506f6f6c3a20546167206d75737420626520612072656760408201527f697374657265642066726f6e7420656e642c206f7220746865207a65726f206160608201526564647265737360d01b608082015260a00190565b60208082526027908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f74204163746040820152661a5d99541bdbdb60ca1b606082015260800190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526031908201527f53746162696c697479506f6f6c3a2063616c6c6572206d7573742068617665206040820152703737b716bd32b9379022aa241023b0b4b760791b606082015260800190565b60208082526029908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f742054726f6040820152683b32a6b0b730b3b2b960b91b606082015260800190565b60208082526021908201527f53746162696c697479506f6f6c3a2073656e64696e6720455448206661696c656040820152601960fa1b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526030908201527f53503a3a5f776974686472617746726f6d5370546f3a205f726563656976657260408201526f206973207a65726f206164647265737360801b606082015260800190565b60208082526033908201527f53746162696c697479506f6f6c3a204b69636b6261636b2072617465206d75736040820152727420626520696e2072616e6765205b302c315d60681b606082015260800190565b60208082526026908201527f53746162696c697479506f6f6c3a20416d6f756e74206d757374206265206e6f6040820152656e2d7a65726f60d01b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526039908201527f53746162696c697479506f6f6c3a206d757374206e6f7420616c72656164792060408201527818994818481c9959da5cdd195c995908199c9bdb9d08195b99603a1b606082015260800190565b60208082526028908201527f53746162696c697479506f6f6c3a2055736572206d7573742068617665206e6f6040820152670819195c1bdcda5d60c21b606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526030908201527f53746162696c697479506f6f6c3a2055736572206d757374206861766520612060408201526f1b9bdb8b5e995c9bc819195c1bdcda5d60821b606082015260800190565b60208082526028908201527f4c697175697479536166654d6174683132383a207375627472616374696f6e206040820152676f766572666c6f7760c01b606082015260800190565b60208082526025908201527f4c697175697479536166654d6174683132383a206164646974696f6e206f766560408201526472666c6f7760d81b606082015260800190565b60208082526044908201527f53746162696c697479506f6f6c3a2043616e6e6f74207769746864726177207760408201527f68696c65207468657265206172652074726f766573207769746820494352203c6060820152631026a1a960e11b608082015260a00190565b60006101006147d2838951613f0b565b60208801516040840152604088015160608401526147f36080840188613f0b565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b6001600160801b0391909116815260200190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9182521515602082015260400190565b9283526001600160801b03918216602084015216604082015260600190565b948552602085019390935260408401919091526001600160801b03908116606084015216608082015260a00190565b60405181810167ffffffffffffffff811182821017156148e457600080fd5b604052919050565b6001600160a01b0381168114610b3357600080fdfeceb6d671277d4354fd29977ada70695fbd93a16612abf765d6b0e25c28dc6db3bce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c951457222ebca92c335c9c86e2baa1cc0e40ffaa9084a51452980d5ba8dec2f6399920012339b5a3368d3a04b8606ce412c46ed92b7dcd8602d41fc8862cb8f25a2646970667358221220b12079f570461c3902a02d925635ecefb92e70f4556abddd99509e1ecfffdece64736f6c634300060b0033", + "deployedBytecode": "0x6080604052600436106102ad5760003560e01c806382e0a57411610165578063b31ee965116100cc578063de13da3c11610085578063de13da3c14610788578063df9cd84f146107a8578063e49d3667146107c8578063ec9f7d46146107e8578063fc7e286d146107fd578063fce6b7341461082b578063fda0101a1461084b576102f8565b8063b31ee965146106f4578063bdaf37ea14610709578063c3a34a0e1461071e578063ce4b5bbe1461073e578063d733cfd014610753578063d7fb044314610773576102f8565b80639f0706701161011e5780639f07067014610665578063a20baee614610531578063a3f4df7e1461067a578063a4e59ac81461069c578063a7bfff97146106b1578063ae918754146106df576102f8565b806382e0a574146105d157806386da0824146105f1578063887105d314610611578063893d20e8146106265780638b8fbd921461063b57806395fb16bb14610650576102f8565b80633d83908a1161021457806372fe25aa116101cd57806372fe25aa14610531578063741bef1a14610546578063759b30341461055b578063766718081461057057806377553ad414610592578063795d26c3146105a75780637f7dde4a146105bc576102f8565b80633d83908a1461048757806340ed1afd1461049c578063556be101146104bc5780635d2de642146104dc5780635f788d65146104fc57806370f1b5721461051c576102f8565b80632199b66f116102665780632199b66f146103d257806328a0a04d146103f25780632e54bf9514610412578063335525ad14610432578063389e92a5146104525780633cc7422514610472576102f8565b80630fbfe38b146102fd57806312261ee71461031f57806313af40351461034a57806314f6c3be1461036a57806316b9d3c51461038c5780631bf43555146103bd576102f8565b366102f8576102ba61086b565b6009546102cd903463ffffffff6108a016565b6009819055604051600080516020614902833981519152916102ee91614847565b60405180910390a1005b600080fd5b34801561030957600080fd5b5061031d610318366004613d86565b6108ce565b005b34801561032b57600080fd5b50610334610ace565b6040516103419190613f43565b60405180910390f35b34801561035657600080fd5b5061031d610365366004613c1a565b610af2565b34801561037657600080fd5b5061037f610b36565b6040516103419190614847565b34801561039857600080fd5b506103ac6103a7366004613c1a565b610b3c565b604051610341959493929190614896565b3480156103c957600080fd5b5061037f610b77565b3480156103de57600080fd5b5061031d6103ed366004613c1a565b610b84565b3480156103fe57600080fd5b5061037f61040d366004613d52565b610c1b565b34801561041e57600080fd5b5061031d61042d366004613d86565b610c38565b34801561043e57600080fd5b5061031d61044d366004613ec9565b610c46565b34801561045e57600080fd5b5061037f61046d366004613c1a565b610ca9565b34801561047e57600080fd5b50610334610d51565b34801561049357600080fd5b50610334610d60565b3480156104a857600080fd5b5061037f6104b7366004613c1a565b610d6f565b3480156104c857600080fd5b5061031d6104d7366004613d86565b610e0c565b3480156104e857600080fd5b5061037f6104f7366004613c1a565b610e84565b34801561050857600080fd5b5061031d610517366004613db6565b610e96565b34801561052857600080fd5b5061037f610ea0565b34801561053d57600080fd5b5061037f610ea6565b34801561055257600080fd5b50610334610eb2565b34801561056757600080fd5b5061037f610ec1565b34801561057c57600080fd5b50610585610ece565b6040516103419190614833565b34801561059e57600080fd5b50610334610ee4565b3480156105b357600080fd5b5061037f610ef3565b3480156105c857600080fd5b50610334611012565b3480156105dd57600080fd5b5061037f6105ec366004613d52565b611021565b3480156105fd57600080fd5b506103ac61060c366004613c1a565b61103e565b34801561061d57600080fd5b5061037f611079565b34801561063257600080fd5b50610334611148565b34801561064757600080fd5b5061037f611167565b34801561065c57600080fd5b5061033461116d565b34801561067157600080fd5b5061033461117c565b34801561068657600080fd5b5061068f61118b565b6040516103419190614060565b3480156106a857600080fd5b506105856111b4565b3480156106bd57600080fd5b506106d16106cc366004613c1a565b6111c3565b604051610341929190614867565b3480156106eb57600080fd5b506103346111df565b34801561070057600080fd5b5061037f6111ee565b34801561071557600080fd5b5061037f6111f4565b34801561072a57600080fd5b5061031d610739366004613dda565b6111fa565b34801561074a57600080fd5b5061037f61129e565b34801561075f57600080fd5b5061031d61076e366004613c8a565b6112a6565b34801561077f57600080fd5b5061037f611538565b34801561079457600080fd5b5061037f6107a3366004613c1a565b61153e565b3480156107b457600080fd5b5061037f6107c3366004613c1a565b611642565b3480156107d457600080fd5b5061037f6107e3366004613c1a565b6116df565b3480156107f457600080fd5b506103346117dc565b34801561080957600080fd5b5061081d610818366004613c1a565b6117eb565b604051610341929190614850565b34801561083757600080fd5b5061031d610846366004613e10565b61180d565b34801561085757600080fd5b5061031d610866366004613c52565b6118cd565b6000546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614258565b60405180910390fd5b565b6000828201838110156108c55760405162461bcd60e51b815260040161089590614168565b90505b92915050565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561091e57600080fd5b505afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613c36565b905060006109648330611b13565b60065460405163095ea7b360e01b81529192506001600160a01b03169063095ea7b3906109979085908590600401613fdf565b602060405180830381600087803b1580156109b157600080fd5b505af11580156109c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e99190613d32565b610a055760405162461bcd60e51b8152600401610895906145ef565b60065460405163438b1b4b60e01b81526001600160a01b038481169263438b1b4b92610a3b929091169085903390600401614019565b602060405180830381600087803b158015610a5557600080fd5b505af1158015610a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8d9190613d9e565b507f2b0fbec1c4e7e30517f196a714775ffe72770d2348f5d586854bb3c0fdf41df8338483604051610ac193929190613ff8565b60405180910390a1505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b610afa611148565b6001600160a01b0316336001600160a01b031614610b2a5760405162461bcd60e51b81526004016108959061451d565b610b3381611cde565b50565b60095490565b600f602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6809c2007651b250000081565b610b8c611148565b6001600160a01b0316336001600160a01b031614610bbc5760405162461bcd60e51b81526004016108959061451d565b610bc581611d69565b600880546001600160a01b0319166001600160a01b0383161790556040517f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac681190610c10908390613f43565b60405180910390a150565b601260209081526000928352604080842090915290825290205481565b610c428133611b13565b5050565b610c4e611dae565b600a54801580610c5c575082155b15610c675750610c42565b600854610c7c906001600160a01b0316611dd8565b600080610c8a848685611e65565b91509150610c988282611f5e565b610ca2848661225f565b5050505050565b6001600160a01b0381166000908152600b602052604081205480610cd1576000915050610d4c565b610cd9613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612395565b93505050505b919050565b6001546001600160a01b031681565b6005546001600160a01b031681565b6001600160a01b0381166000908152600b602052604081205480610d97576000915050610d4c565b610d9f613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b610e1533612582565b610e1e336125be565b610e27816125f5565b336000818152600d6020526040908190208381556001908101805460ff19169091179055517f19bc932fb9e16a8b5a1e41be9f4c2de59d5ddd7567b8b81405f532ca00a9880e90610e79908490614847565b60405180910390a250565b600e6020526000908152604090205481565b610c42828261261d565b60145481565b670de0b6b3a764000081565b6002546001600160a01b031681565b6801158e460913d0000081565b601154600160801b90046001600160801b031681565b6004546001600160a01b031681565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3757600080fd5b505afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b505afa158015610fd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff99190613d9e565b905061100b828263ffffffff6108a016565b9250505090565b6000546001600160a01b031681565b601360209081526000928352604080842090915290825290205481565b600c602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156110be57600080fd5b505afa1580156110d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f69190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b60008060405161115790613f26565b6040519081900390205492915050565b60105481565b6008546001600160a01b031681565b6003546001600160a01b031681565b6040518060400160405280600d81526020016c14dd18589a5b1a5d1e541bdbdb609a1b81525081565b6011546001600160801b031681565b600d602052600090815260409020805460019091015460ff1682565b6007546001600160a01b031681565b60165481565b600a5490565b600480546040805163e9fc346160e01b8152905160009361128c936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561124057600080fd5b505afa158015611254573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112789190613c36565b60065485906001600160a01b0316856127c0565b905061129981600061261d565b505050565b633b9aca0081565b6112ae611148565b6001600160a01b0316336001600160a01b0316146112de5760405162461bcd60e51b81526004016108959061451d565b6112e788611d69565b6112f087611d69565b6112f986611d69565b61130285611d69565b61130b84611d69565b61131483611d69565b61131d82611d69565b61132681611d69565b670de0b6b3a7640000601055600380546001600160a01b03199081166001600160a01b038b8116919091179092556004805482168a8416179055600580548216898416179055600080548216888416179055600680548216878416179055600780548216868416179055600280548216858416179055600880549091169183169190911790556040517f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed985906113dc908990613f43565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a5678866040516114139190613f43565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828560405161144a9190613f43565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d846040516114819190613f43565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800836040516114b89190613f43565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264826040516114ef9190613f43565b60405180910390a17f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac6811816040516115269190613f43565b60405180910390a15050505050505050565b60155481565b6001600160a01b0381166000908152600e602052604081205480611566576000915050610d4c565b6001600160a01b0383166000908152600d602052604081205490611598670de0b6b3a76400008363ffffffff612a6516565b90506115a2613b64565b506001600160a01b0385166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b869063ffffffff612b3316565b9063ffffffff612b6d16565b979650505050505050565b6001600160a01b0381166000908152600e60205260408120548061166a576000915050610d4c565b611672613b64565b506001600160a01b0383166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b6001600160a01b0381166000908152600b602052604081205480611707576000915050610d4c565b6001600160a01b038084166000908152600b602052604081206001015490911690811561174c576001600160a01b0382166000908152600d6020526040902054611756565b670de0b6b3a76400005b9050611760613b64565b506001600160a01b0385166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b6006546001600160a01b031681565b600b60205260009081526040902080546001909101546001600160a01b031682565b600480546040805163e9fc346160e01b815290516000936118c0936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561185357600080fd5b505afa158015611867573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188b9190613c36565b6006546001600160a01b0316867f00000000000000000000000000000000000000000000000000000000000000008787612baf565b9050610ca281600061261d565b336000908152600b60205260409020546118e681612dfc565b6118ef33612e1c565b6118f833612ebb565b6008546001600160a01b031661190d81611dd8565b600061191833610ca9565b9050600061192533610d6f565b90506000611939858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b039091169061196790869083612ee8565b600061197282611642565b90508061197f838261305d565b826001600160a01b031660008051602061496283398151915282336040516119a8929190614850565b60405180910390a26119ba33866131a5565b336001600160a01b031660008051602061494283398151915287866040516119e392919061403c565b60405180910390a2336001600160a01b031660008051602061492283398151915286604051611a129190614847565b60405180910390a2600954611a2d908763ffffffff612a6516565b600981905560405160008051602061490283398151915291611a4e91614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123387604051611a87929190613fdf565b60405180910390a1600460009054906101000a90046001600160a01b03166001600160a01b031663ea9638bf87338d8d6040518563ffffffff1660e01b8152600401611ad593929190613f57565b6000604051808303818588803b158015611aee57600080fd5b505af1158015611b02573d6000803e3d6000fd5b505050505050505050505050505050565b60006001600160a01b038216611b3b5760405162461bcd60e51b815260040161089590614434565b8215611b4957611b4961331a565b336000908152600b6020526040902054611b6281612dfc565b6008546001600160a01b0316611b7781611dd8565b6000611b8233610ca9565b90506000611b8f33610d6f565b90506000611b9d8883613551565b90506000611bb1868463ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b0390911690611bdf90879083612ee8565b6000611bea82611642565b90506000611bfe828663ffffffff612a6516565b9050611c0a838261305d565b826001600160a01b03166000805160206149628339815191528233604051611c33929190614850565b60405180910390a2611c458b86613567565b6000611c57878763ffffffff612a6516565b9050611c6333826131a5565b336001600160a01b031660008051602061492283398151915282604051611c8a9190614847565b60405180910390a2336001600160a01b03166000805160206149428339815191528987604051611cbb92919061403c565b60405180910390a2611ccd88336135e0565b50939b9a5050505050505050505050565b6001600160a01b038116611d045760405162461bcd60e51b81526004016108959061429f565b806001600160a01b0316611d16611148565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611d5990613f26565b6040519081900390209190915550565b6001600160a01b038116611d8f5760405162461bcd60e51b8152600401610895906142e1565b803b80610c425760405162461bcd60e51b815260040161089590614646565b6005546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614369565b600a54604051636cbdcf4760e01b81526000916001600160a01b03841691636cbdcf4791611e0891600401614847565b602060405180830381600087803b158015611e2257600080fd5b505af1158015611e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5a9190613d9e565b9050610c428161370f565b6000806000611e97601554611e8b670de0b6b3a764000089612b3390919063ffffffff16565b9063ffffffff6108a016565b905083851115611ea357fe5b83851415611ec0576000601655670de0b6b3a76400009150611f20565b601654600090611eee90611ee288670de0b6b3a764000063ffffffff612b3316565b9063ffffffff612a6516565b9050611f056001611e8b838863ffffffff612b6d16565b9250611f1b81611ee2858863ffffffff612b3316565b601655505b611f30818563ffffffff612b6d16565b9250611f52611f45848663ffffffff612b3316565b829063ffffffff612a6516565b60155550935093915050565b6010546000670de0b6b3a7640000831115611f7557fe5b6000611f8f670de0b6b3a76400008563ffffffff612a6516565b6011546001600160801b03600160801b820481166000818152601260209081526040808320949095168083529390529283205493945090929091611fd38988612b33565b90506000611fe7838363ffffffff6108a016565b6001600160801b038086166000908152601260209081526040808320938a168352929052819020829055519091507fe12e2cd2c9afa8069203ca07e7eff1edce4a075686d0736a8e7e0d593597b2079061204690839087908990614877565b60405180910390a18561211f5761206d6001600160801b038516600163ffffffff61382016565b601180546001600160801b03908116600160801b938216840217918290556040517fb50f0f59e7cb5b421dc77581c3a9919e3806e076e5fa78a874c3f120cb7d874d936120be930490911690614833565b60405180910390a1601180546001600160801b03191690556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9061210790600090614833565b60405180910390a1670de0b6b3a7640000965061220c565b633b9aca00612140670de0b6b3a764000061162b8b8a63ffffffff612b3316565b10156121ed57612176670de0b6b3a764000061162b633b9aca0061216a8c8b63ffffffff612b3316565b9063ffffffff612b3316565b96506121926001600160801b038616600163ffffffff61382016565b601180546001600160801b0319166001600160801b0392831617908190556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe926121e0921690614833565b60405180910390a161220c565b612209670de0b6b3a764000061162b8a8963ffffffff612b3316565b96505b6000871161221657fe5b60108790556040517fc1a9618cb59ebca77cbdbc2949f126823c407ff13edb285fd0262519a9c18e8c9061224b908990614847565b60405180910390a150505050505050505050565b60005460405163121cbc4d60e11b81526001600160a01b03909116908190632439789a90612291908590600401614847565b600060405180830381600087803b1580156122ab57600080fd5b505af11580156122bf573d6000803e3d6000fd5b505050506122cc82613851565b600654604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906122fe9030908690600401613fdf565b600060405180830381600087803b15801561231857600080fd5b505af115801561232c573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b03841692506364a197f3915061235e9030908790600401613fdf565b600060405180830381600087803b15801561237857600080fd5b505af115801561238c573d6000803e3d6000fd5b50505050505050565b6080810151606082015182516020808501516001600160801b038086166000908152601284526040808220928716825291909352822054919493929185906123e3908463ffffffff612a6516565b6001600160801b0380871660009081526012602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b6001600160801b031681526020810191909152604001600020549063ffffffff612b6d16565b90506000612478670de0b6b3a764000061162b868161246b888863ffffffff6108a016565b8f9063ffffffff612b3316565b9a9950505050505050505050565b6020810151606082015160808301516011546000939291906001600160801b03600160801b909104811690821610156124c557600093505050506108c8565b60115460009081906124e6906001600160801b03168563ffffffff6138ab16565b90506001600160801b0381166125165761250f8561162b6010548b612b3390919063ffffffff16565b915061254e565b806001600160801b0316600114156125495761250f633b9aca0061162b8761162b6010548d612b3390919063ffffffff16565b600091505b61256288633b9aca0063ffffffff612b6d16565b821015612577576000955050505050506108c8565b509695505050505050565b6001600160a01b0381166000908152600d602052604090206001015460ff1615610b335760405162461bcd60e51b81526004016108959061454e565b6001600160a01b0381166000908152600b60205260409020548015610c425760405162461bcd60e51b8152600401610895906145a7565b670de0b6b3a7640000811115610b335760405162461bcd60e51b815260040161089590614484565b612626816138e5565b61262f33612582565b61263882613932565b336000908152600b60205260409020546008546001600160a01b031661265d81611dd8565b8161266c5761266c3384613952565b600061267733610ca9565b9050600061268433610d6f565b90506000612698858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b03909116906126c690869083612ee8565b60006126d182611642565b905060006126e5828b63ffffffff6108a016565b90506126f1838261305d565b826001600160a01b0316600080516020614962833981519152823360405161271a929190614850565b60405180910390a261272c338b6139ac565b600061273e868c63ffffffff6108a016565b905061274a33826131a5565b336001600160a01b0316600080516020614922833981519152826040516127719190614847565b60405180910390a2336001600160a01b031660008051602061494283398151915288876040516127a292919061403c565b60405180910390a26127b387613a60565b5050505050505050505050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b1580156127fc57600080fd5b505afa158015612810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128349190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016128649190613f43565b60206040518083038186803b15801561287c57600080fd5b505afa158015612890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b49190613d9e565b9050306001600160a01b03831663605629d633838a89356128db60408c0160208d01613eea565b8b604001358c606001356040518863ffffffff1660e01b81526004016129079796959493929190613f9e565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b50505050866129ba83856001600160a01b03166370a08231856040518263ffffffff1660e01b815260040161296a9190613f43565b60206040518083038186803b15801561298257600080fd5b505afa158015612996573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee29190613d9e565b146129d75760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390612a079089908b903390600401614019565b602060405180830381600087803b158015612a2157600080fd5b505af1158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613d9e565b98975050505050505050565b60006108c583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a6a565b608081015160608201516040808401516020808601516001600160801b03808716600090815260138452858120918716815292529281205490949392908590612af6908463ffffffff612a6516565b6001600160801b0380871660009081526013602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b600082612b42575060006108c8565b82820282848281612b4f57fe5b04146108c55760405162461bcd60e51b8152600401610895906143f3565b60006108c583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613a96565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015612beb57600080fd5b505afa158015612bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c239190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612c539190613f43565b60206040518083038186803b158015612c6b57600080fd5b505afa158015612c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca39190613d9e565b87516020015190915030906001600160a01b0388166330f28b7a8a612cc88585613acd565b338b8b6040518663ffffffff1660e01b8152600401612ceb9594939291906147c2565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b5050505080612d4e84866001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161296a9190613f43565b14612d6b5760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390612d9b908d9085903390600401614019565b602060405180830381600087803b158015612db557600080fd5b505af1158015612dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ded9190613d9e565b9b9a5050505050505050505050565b60008111610b335760405162461bcd60e51b81526004016108959061467b565b6005546040516321e3780160e01b81526001600160a01b03909116906321e3780190612e4c908490600401613f43565b60206040518083038186803b158015612e6457600080fd5b505afa158015612e78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9c9190613d9e565b600114610b335760405162461bcd60e51b8152600401610895906140b3565b6000612ec682610ca9565b905060008111610c425760405162461bcd60e51b815260040161089590614318565b6001600160a01b03811615612fa8576000612f028261153e565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612f339085908590600401613fdf565b600060405180830381600087803b158015612f4d57600080fd5b505af1158015612f61573d6000803e3d6000fd5b50505050816001600160a01b03167f732e331072fe280a520929e5f2cc76c223389ff57d32a4e278cfded03e6f1caa82604051612f9e9190614847565b60405180910390a2505b6000612fb3836116df565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612fe49086908590600401613fdf565b600060405180830381600087803b158015612ffe57600080fd5b505af1158015613012573d6000803e3d6000fd5b50505050826001600160a01b03167fe9ac2dcd83e719358f1dc0c5c80491937f67d4ec61ef62c262bbe3b78578f92a8260405161304f9190614847565b60405180910390a250505050565b6001600160a01b0382166000908152600e60205260409020819055806130e8576001600160a01b0382166000818152600f60205260408082208281556001810183905560028101839055600301829055517fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e45916130db91819061403c565b60405180910390a2610c42565b6011546010546001600160801b03600160801b80840482166000818152601360209081526040808320978616808452978252808320546001600160a01b038b16808552600f90935292819020600181018890556002810184905560030180546001600160801b0319168917909616948402949094179094559151909392907fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e4590613195908590859061403c565b60405180910390a2505050505050565b6001600160a01b0382166000908152600b6020526040902081905580613243576001600160a01b0382166000818152600b60209081526040808320600190810180546001600160a01b0319169055600c909252808320838155918201839055600282018390556003909101829055517f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a916130db918190819061404a565b6011546010546001600160801b03600160801b8084048216600081815260126020908152604080832097861680845297825280832054848452601383528184208985528352818420546001600160a01b038c16808652600c90945293829020600181018990558181556002810185905560030180546001600160801b0319168a1790971695850295909517909555935191949390917f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a906133099086908690869061404a565b60405180910390a250505050505050565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561336057600080fd5b505af1158015613374573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133989190613d9e565b90506000600760009054906101000a90046001600160a01b03166001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ea57600080fd5b505afa1580156133fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134229190613c36565b600554604051630d293c7160e41b81529192506000916001600160a01b039091169063d293c7109061345a9085908790600401613fdf565b60206040518083038186803b15801561347257600080fd5b505afa158015613486573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134aa9190613d9e565b9050600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156134fa57600080fd5b505afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135329190613d9e565b8110156112995760405162461bcd60e51b815260040161089590614758565b600081831061356057816108c5565b5090919050565b8061357157610c42565b600654604051631062c15f60e11b81526001600160a01b03909116906320c582be906135a590309086908690600401613f7a565b600060405180830381600087803b1580156135bf57600080fd5b505af11580156135d3573d6000803e3d6000fd5b50505050610c4281613851565b6001600160a01b0381166136065760405162461bcd60e51b81526004016108959061419f565b8161361057610c42565b600954600090613626908463ffffffff612a6516565b9050806009819055506000805160206149028339815191528160405161364c9190614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123384604051613685929190613fdf565b60405180910390a16000336001600160a01b0316846040516136a690613f23565b60006040518083038185875af1925050503d80600081146136e3576040519150601f19603f3d011682016040523d82523d6000602084013e6136e8565b606091505b50509050806137095760405162461bcd60e51b8152600401610895906143b2565b50505050565b600a5480158061371d575081155b156137285750610b33565b60006137348383613aff565b9050600061374d60105483612b3390919063ffffffff16565b6011546001600160801b03600160801b820481166000908152601360209081526040808320939094168252919091522054909150613791908263ffffffff6108a016565b601180546001600160801b03600160801b80830482166000908152601360208181526040808420968616845295815285832097909755945491820483168082529486528381209190921680835294528190205490517f2d6127771b164a9cc8827d24b5955db2a77e7a81dac389107ebb8bce9fb64968936138129391614877565b60405180910390a150505050565b60008282016001600160801b0380851690821610156108c55760405162461bcd60e51b815260040161089590614713565b600a54600090613867908363ffffffff612a6516565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c78160405161389f9190614847565b60405180910390a15050565b6000826001600160801b0316826001600160801b031611156138df5760405162461bcd60e51b8152600401610895906146cb565b50900390565b6001600160a01b0381166000908152600d602052604090206001015460ff168061391657506001600160a01b038116155b610b335760405162461bcd60e51b8152600401610895906141ec565b60008111610b335760405162461bcd60e51b8152600401610895906144d7565b6001600160a01b038281166000818152600b602052604080822060010180546001600160a01b0319169486169485179055517f094c08e96a8890877a8390b4f967180a7507ad8622244d05fcd0f9f8e086564e9190a35050565b600654604051632ee65eeb60e21b81526001600160a01b039091169063bb997bac906139e090859030908690600401613f7a565b600060405180830381600087803b1580156139fa57600080fd5b505af1158015613a0e573d6000803e3d6000fd5b5050600a5460009250613a2891508363ffffffff6108a016565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c781604051610ac19190614847565b610b3381336135e0565b60008184841115613a8e5760405162461bcd60e51b81526004016108959190614060565b505050900390565b60008183613ab75760405162461bcd60e51b81526004016108959190614060565b506000838581613ac357fe5b0495945050505050565b613ad5613ba5565b613add613ba5565b5050604080518082019091526001600160a01b03929092168252602082015290565b600080613b23601454611e8b670de0b6b3a764000087612b3390919063ffffffff16565b90506000613b37828563ffffffff612b6d16565b9050613b59613b4c828663ffffffff612b3316565b839063ffffffff612a6516565b601455949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b604080518082019091526000808252602082015290565b60008083601f840112613bcd578182fd5b50813567ffffffffffffffff811115613be4578182fd5b602083019150836020828501011115613bfc57600080fd5b9250929050565b80356001600160801b03811681146108c857600080fd5b600060208284031215613c2b578081fd5b81356108c5816148ec565b600060208284031215613c47578081fd5b81516108c5816148ec565b60008060408385031215613c64578081fd5b8235613c6f816148ec565b91506020830135613c7f816148ec565b809150509250929050565b600080600080600080600080610100898b031215613ca6578384fd5b8835613cb1816148ec565b97506020890135613cc1816148ec565b96506040890135613cd1816148ec565b95506060890135613ce1816148ec565b94506080890135613cf1816148ec565b935060a0890135613d01816148ec565b925060c0890135613d11816148ec565b915060e0890135613d21816148ec565b809150509295985092959890939650565b600060208284031215613d43578081fd5b815180151581146108c5578182fd5b60008060408385031215613d64578182fd5b613d6e8484613c03565b9150613d7d8460208501613c03565b90509250929050565b600060208284031215613d97578081fd5b5035919050565b600060208284031215613daf578081fd5b5051919050565b60008060408385031215613dc8578182fd5b823591506020830135613c7f816148ec565b60008082840360a0811215613ded578283fd5b833592506080601f1982011215613e02578182fd5b506020830190509250929050565b60008060008084860360c0811215613e26578485fd5b85359450601f1981016080811215613e3c578485fd5b613e4660606148c5565b91506040811215613e55578485fd5b50613e6060406148c5565b6020870135613e6e816148ec565b80825250604087013560208201528082525060608601356020820152608086013560408201528093505060a085013567ffffffffffffffff811115613eb1578283fd5b613ebd87828801613bbc565b95989497509550505050565b60008060408385031215613edb578182fd5b50508035926020909101359150565b600060208284031215613efb578081fd5b813560ff811681146108c5578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b6000602080835283518082850152825b8181101561408c57858101830151858201604001528201614070565b8181111561409d5783604083870101525b50601f01601f1916929092016040019392505050565b60208082526046908201527f53746162696c697479506f6f6c3a2063616c6c6572206d75737420686176652060408201527f616e206163746976652074726f766520746f207769746864726177204554484760608201526561696e20746f60d01b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252602d908201527f53503a3a5f73656e644554484761696e546f3a205f726563656976657220697360408201526c207a65726f206164647265737360981b606082015260800190565b60208082526046908201527f53746162696c697479506f6f6c3a20546167206d75737420626520612072656760408201527f697374657265642066726f6e7420656e642c206f7220746865207a65726f206160608201526564647265737360d01b608082015260a00190565b60208082526027908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f74204163746040820152661a5d99541bdbdb60ca1b606082015260800190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526031908201527f53746162696c697479506f6f6c3a2063616c6c6572206d7573742068617665206040820152703737b716bd32b9379022aa241023b0b4b760791b606082015260800190565b60208082526029908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f742054726f6040820152683b32a6b0b730b3b2b960b91b606082015260800190565b60208082526021908201527f53746162696c697479506f6f6c3a2073656e64696e6720455448206661696c656040820152601960fa1b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526030908201527f53503a3a5f776974686472617746726f6d5370546f3a205f726563656976657260408201526f206973207a65726f206164647265737360801b606082015260800190565b60208082526033908201527f53746162696c697479506f6f6c3a204b69636b6261636b2072617465206d75736040820152727420626520696e2072616e6765205b302c315d60681b606082015260800190565b60208082526026908201527f53746162696c697479506f6f6c3a20416d6f756e74206d757374206265206e6f6040820152656e2d7a65726f60d01b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526039908201527f53746162696c697479506f6f6c3a206d757374206e6f7420616c72656164792060408201527818994818481c9959da5cdd195c995908199c9bdb9d08195b99603a1b606082015260800190565b60208082526028908201527f53746162696c697479506f6f6c3a2055736572206d7573742068617665206e6f6040820152670819195c1bdcda5d60c21b606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526030908201527f53746162696c697479506f6f6c3a2055736572206d757374206861766520612060408201526f1b9bdb8b5e995c9bc819195c1bdcda5d60821b606082015260800190565b60208082526028908201527f4c697175697479536166654d6174683132383a207375627472616374696f6e206040820152676f766572666c6f7760c01b606082015260800190565b60208082526025908201527f4c697175697479536166654d6174683132383a206164646974696f6e206f766560408201526472666c6f7760d81b606082015260800190565b60208082526044908201527f53746162696c697479506f6f6c3a2043616e6e6f74207769746864726177207760408201527f68696c65207468657265206172652074726f766573207769746820494352203c6060820152631026a1a960e11b608082015260a00190565b60006101006147d2838951613f0b565b60208801516040840152604088015160608401526147f36080840188613f0b565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b6001600160801b0391909116815260200190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9182521515602082015260400190565b9283526001600160801b03918216602084015216604082015260600190565b948552602085019390935260408401919091526001600160801b03908116606084015216608082015260a00190565b60405181810167ffffffffffffffff811182821017156148e457600080fd5b604052919050565b6001600160a01b0381168114610b3357600080fdfeceb6d671277d4354fd29977ada70695fbd93a16612abf765d6b0e25c28dc6db3bce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c951457222ebca92c335c9c86e2baa1cc0e40ffaa9084a51452980d5ba8dec2f6399920012339b5a3368d3a04b8606ce412c46ed92b7dcd8602d41fc8862cb8f25a2646970667358221220b12079f570461c3902a02d925635ecefb92e70f4556abddd99509e1ecfffdece64736f6c634300060b0033", + "devdoc": { + "kind": "dev", + "methods": { + "getETH()": { + "returns": { + "_0": "the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`, to exclude edge cases like ETH received from a self-destruct." + } + }, + "getOwner()": { + "returns": { + "_owner": "Address of the owner. " + } + }, + "getTotalZUSDDeposits()": { + "returns": { + "_0": "ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset." + } + }, + "setAddresses(address,address,address,address,address,address,address,address)": { + "details": "initializer function, checks addresses are contracts", + "params": { + "_activePoolAddress": "ActivePool contract address", + "_borrowerOperationsAddress": "BorrowerOperations contract address", + "_communityIssuanceAddress": "CommunityIssuanceAddress", + "_liquityBaseParamsAddress": "LiquidityBaseParams contract address", + "_priceFeedAddress": "PriceFeed contract address", + "_sortedTrovesAddress": "SortedTroves contract address", + "_troveManagerAddress": "TroveManager contract address", + "_zusdTokenAddress": "ZUSDToken contract address" + } + }, + "setCommunityIssuanceAddress(address)": { + "details": "setter function specific for community issuance contract.", + "params": { + "_communityIssuanceAddress": "address of new community issuance contract." + } + }, + "setOwner(address)": { + "params": { + "_owner": "Address of the owner. " + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "MIN_NET_DEBT()": { + "notice": "Minimum amount of net ZUSD debt a trove must have" + }, + "ZUSD_GAS_COMPENSATION()": { + "notice": "Amount of ZUSD to be locked in gas pool on opening troves" + }, + "constructor": "Constructor ", + "getCompoundedFrontEndStake(address)": { + "notice": "Return the front end's compounded stake. Given by the formula: D = D0 * P/P(0) where P(0) is the depositor's snapshot of the product P, taken at the last time when one of the front end's tagged deposits updated their deposit. The front end's compounded stake is equal to the sum of its depositors' compounded deposits." + }, + "getCompoundedZUSDDeposit(address)": { + "notice": "Return the user's compounded deposit. Given by the formula: d = d0 * P/P(0) where P(0) is the depositor's snapshot of the product P, taken when they last updated their deposit." + }, + "getDepositorETHGain(address)": { + "notice": "Calculates the ETH gain earned by the deposit since its last snapshots were taken. Given by the formula: E = d0 * (S - S(0))/P(0) where S(0) and P(0) are the depositor's snapshots of the sum S and product P, respectively. d0 is the last recorded deposit value." + }, + "getDepositorSOVGain(address)": { + "notice": "Calculate the SOV gain earned by a deposit since its last snapshots were taken. Given by the formula: SOV = d0 * (G - G(0))/P(0) where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively. d0 is the last recorded deposit value." + }, + "getFrontEndSOVGain(address)": { + "notice": "Return the SOV gain earned by the front end. Given by the formula: E = D0 * (G - G(0))/P(0) where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively. D0 is the last recorded value of the front end's total tagged deposits." + }, + "getOwner()": { + "notice": "Return address of the owner." + }, + "offset(uint256,uint256)": { + "notice": "Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible) and transfers the Trove's ETH collateral from ActivePool to StabilityPool. Only called by liquidation functions in the TroveManager." + }, + "provideToSP(uint256,address)": { + "notice": "provideToSP(): - Triggers a SOV issuance, based on time passed since the last issuance and total amount of deposited ZUSD. The SOV issuance is shared between *all* depositors and front ends - Tags the deposit with the provided front end tag param, if it's a new deposit - Sends depositor's accumulated gains (SOV, ETH) to depositor - Sends the tagged front end's accumulated SOV gains to the tagged front end - Increases deposit and tagged front end's stake, and takes new snapshots for each." + }, + "provideToSpFromDLLR(uint256,(uint256,uint8,bytes32,bytes32))": { + "notice": "DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction" + }, + "provideToSpFromDllrWithPermit2(uint256,((address,uint256),uint256,uint256),bytes)": { + "notice": "DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction" + }, + "registerFrontEnd(uint256)": { + "notice": "Front end makes a one-time selection of kickback rate upon registering" + }, + "setAddresses(address,address,address,address,address,address,address,address)": { + "notice": "Called only once on init, to set addresses of other Liquity contracts. Callable only by owner" + }, + "setOwner(address)": { + "notice": "Set address of the owner (only owner can call this function)" + }, + "withdrawETHGainToTrove(address,address)": { + "notice": "withdrawETHGainToTrove: - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends - Sends all depositor's SOV gain to depositor - Sends all tagged front end's SOV gain to the tagged front end - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove - Leaves their compounded deposit in the Stability Pool - Updates snapshots for deposit and tagged front end stake " + }, + "withdrawFromSP(uint256)": { + "notice": "withdrawFromSP(): - Triggers a SOV issuance, based on time passed since the last issuance and total amount of ZUSD is deposited. The SOV issuance is shared between *all* depositors and front ends - Removes the deposit's front end tag if it is a full withdrawal - Sends all depositor's accumulated gains (SOV, ETH) to depositor - Sends the tagged front end's accumulated SOV gains to the tagged front end - Decreases deposit and tagged front end's stake, and takes new snapshots for each. If _amount > userDeposit, the user withdraws all of their compounded deposit." + }, + "withdrawFromSpAndConvertToDLLR(uint256)": { + "notice": "Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction" + } + }, + "notice": "The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors. When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned. Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits. They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors, in the same proportion. When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40% of the total ZUSD in the Stability Pool, depletes 40% of each deposit. A deposit that has experienced a series of liquidations is termed a \"compounded deposit\": each liquidation depletes the deposit, multiplying it by some factor in range ]0,1[ --- IMPLEMENTATION --- We use a highly scalable method of tracking deposits and ETH gains that has O(1) complexity. When a liquidation occurs, rather than updating each depositor's deposit and ETH gain, we simply update two state variables: a product P, and a sum S. A mathematical manipulation allows us to factor out the initial deposit, and accurately track all depositors' compounded deposits and accumulated ETH gains over time, as liquidations occur, using just these two variables P and S. When depositors join the Stability Pool, they get a snapshot of the latest P and S: P_t and S_t, respectively. The formula for a depositor's accumulated ETH gain is derived here: https://github.com/liquity/dev/blob/main/packages/contracts/mathProofs/Scalable%20Compounding%20Stability%20Pool%20Deposits.pdf For a given deposit d_t, the ratio P/P_t tells us the factor by which a deposit has decreased since it joined the Stability Pool, and the term d_t * (S - S_t)/P_t gives us the deposit's total accumulated ETH gain. Each liquidation updates the product P and sum S. After a series of liquidations, a compounded deposit and corresponding ETH gain can be calculated using the initial deposit, the depositor’s snapshots of P and S, and the latest values of P and S. Any time a depositor updates their deposit (withdrawal, top-up) their accumulated ETH gain is paid out, their new deposit is recorded (based on their latest compounded deposit and modified by the withdrawal/top-up), and they receive new snapshots of the latest P and S. Essentially, they make a fresh deposit that overwrites the old one. --- SCALE FACTOR --- Since P is a running product in range ]0,1] that is always-decreasing, it should never reach 0 when multiplied by a number in range ]0,1[. Unfortunately, Solidity floor division always reaches 0, sooner or later. A series of liquidations that nearly empty the Pool (and thus each multiply P by a very small number in range ]0,1[ ) may push P to its 18 digit decimal limit, and round it to 0, when in fact the Pool hasn't been emptied: this would break deposit tracking. So, to track P accurately, we use a scale factor: if a liquidation would cause P to decrease to <1e-9 (and be rounded to 0 by Solidity), we first multiply P by 1e9, and increment a currentScale factor by 1. The added benefit of using 1e9 for the scale factor (rather than 1e18) is that it ensures negligible precision loss close to the scale boundary: when P is at its minimum value of 1e9, the relative precision loss in P due to floor division is only on the order of 1e-9. --- EPOCHS --- Whenever a liquidation fully empties the Stability Pool, all deposits should become 0. However, setting P to 0 would make P be 0 forever, and break all future reward calculations. So, every time the Stability Pool is emptied by a liquidation, we reset P = 1 and currentScale = 0, and increment the currentEpoch by 1. --- TRACKING DEPOSIT OVER SCALE CHANGES AND EPOCHS --- When a deposit is made, it gets snapshots of the currentEpoch and the currentScale. When calculating a compounded deposit, we compare the current epoch to the deposit's epoch snapshot. If the current epoch is newer, then the deposit was present during a pool-emptying liquidation, and necessarily has been depleted to 0. Otherwise, we then compare the current scale to the deposit's scale snapshot. If they're equal, the compounded deposit is given by d_t * P/P_t. If it spans one scale change, it is given by d_t * P/(P_t * 1e9). If it spans more than one scale change, we define the compounded deposit as 0, since it is now less than 1e-9'th of its initial value (e.g. a deposit of 1 billion ZUSD has depleted to < 1 ZUSD). --- TRACKING DEPOSITOR'S ETH GAIN OVER SCALE CHANGES AND EPOCHS --- In the current epoch, the latest value of S is stored upon each scale change, and the mapping (scale -> S) is stored for each epoch. This allows us to calculate a deposit's accumulated ETH gain, during the epoch in which the deposit was non-zero and earned ETH. We calculate the depositor's accumulated ETH gain for the scale at which they made the deposit, using the ETH gain formula: e_1 = d_t * (S - S_t) / P_t and also for scale after, taking care to divide the latter by a factor of 1e9: e_2 = d_t * S / (P_t * 1e9) The gain in the second scale will be full, as the starting point was in the previous scale, thus no need to subtract anything. The deposit therefore was present for reward events from the beginning of that second scale. S_i-S_t + S_{i+1} .<--------.------------> . . . S_i . S_{i+1} <--.-------->.<-----------> S_t. . <->. . t . |---+---------|-------------|-----... i i+1 The sum of (e_1 + e_2) captures the depositor's total accumulated ETH gain, handling the case where their deposit spanned one scale change. We only care about gains across one scale change, since the compounded deposit is defined as being 0 once it has spanned more than one scale change. --- UPDATING P WHEN A LIQUIDATION OCCURS --- Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations: https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS --- An SOV issuance event occurs at every deposit operation, and every liquidation. Each deposit is tagged with the address of the front end through which it was made. All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate. Please see the system Readme for an overview: https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers We use the same mathematical product-sum approach to track SOV gains for depositors, where 'G' is the sum corresponding to SOV gains. The product P (and snapshot P_t) is re-used, as the ratio P/P_t tracks a deposit's depletion due to liquidations.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 5495, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "activePool", + "offset": 0, + "slot": "0", + "type": "t_contract(IActivePool)19557" + }, + { + "astId": 5497, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "defaultPool", + "offset": 0, + "slot": "1", + "type": "t_contract(IDefaultPool)20229" + }, + { + "astId": 5500, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "priceFeed", + "offset": 0, + "slot": "2", + "type": "t_contract(IPriceFeed)20458" + }, + { + "astId": 5503, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "liquityBaseParams", + "offset": 0, + "slot": "3", + "type": "t_contract(ILiquityBaseParams)20379" + }, + { + "astId": 28084, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "borrowerOperations", + "offset": 0, + "slot": "4", + "type": "t_contract(IBorrowerOperations)20065" + }, + { + "astId": 28086, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "troveManager", + "offset": 0, + "slot": "5", + "type": "t_contract(ITroveManager)21635" + }, + { + "astId": 28088, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "zusdToken", + "offset": 0, + "slot": "6", + "type": "t_contract(IZUSDToken)21842" + }, + { + "astId": 28090, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "sortedTroves", + "offset": 0, + "slot": "7", + "type": "t_contract(ISortedTroves)20817" + }, + { + "astId": 28092, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "communityIssuance", + "offset": 0, + "slot": "8", + "type": "t_contract(ICommunityIssuance)20205" + }, + { + "astId": 28094, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "ETH", + "offset": 0, + "slot": "9", + "type": "t_uint256" + }, + { + "astId": 28096, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "totalZUSDDeposits", + "offset": 0, + "slot": "10", + "type": "t_uint256" + }, + { + "astId": 28121, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "deposits", + "offset": 0, + "slot": "11", + "type": "t_mapping(t_address,t_struct(Deposit)28106_storage)" + }, + { + "astId": 28125, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "depositSnapshots", + "offset": 0, + "slot": "12", + "type": "t_mapping(t_address,t_struct(Snapshots)28117_storage)" + }, + { + "astId": 28129, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "frontEnds", + "offset": 0, + "slot": "13", + "type": "t_mapping(t_address,t_struct(FrontEnd)28101_storage)" + }, + { + "astId": 28133, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "frontEndStakes", + "offset": 0, + "slot": "14", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 28137, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "frontEndSnapshots", + "offset": 0, + "slot": "15", + "type": "t_mapping(t_address,t_struct(Snapshots)28117_storage)" + }, + { + "astId": 28139, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "P", + "offset": 0, + "slot": "16", + "type": "t_uint256" + }, + { + "astId": 28144, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "currentScale", + "offset": 0, + "slot": "17", + "type": "t_uint128" + }, + { + "astId": 28146, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "currentEpoch", + "offset": 16, + "slot": "17", + "type": "t_uint128" + }, + { + "astId": 28152, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "epochToScaleToSum", + "offset": 0, + "slot": "18", + "type": "t_mapping(t_uint128,t_mapping(t_uint128,t_uint256))" + }, + { + "astId": 28158, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "epochToScaleToG", + "offset": 0, + "slot": "19", + "type": "t_mapping(t_uint128,t_mapping(t_uint128,t_uint256))" + }, + { + "astId": 28160, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "lastSOVError", + "offset": 0, + "slot": "20", + "type": "t_uint256" + }, + { + "astId": 28162, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "lastETHError_Offset", + "offset": 0, + "slot": "21", + "type": "t_uint256" + }, + { + "astId": 28164, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "lastZUSDLossError_Offset", + "offset": 0, + "slot": "22", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(IActivePool)19557": { + "encoding": "inplace", + "label": "contract IActivePool", + "numberOfBytes": "20" + }, + "t_contract(IBorrowerOperations)20065": { + "encoding": "inplace", + "label": "contract IBorrowerOperations", + "numberOfBytes": "20" + }, + "t_contract(ICommunityIssuance)20205": { + "encoding": "inplace", + "label": "contract ICommunityIssuance", + "numberOfBytes": "20" + }, + "t_contract(IDefaultPool)20229": { + "encoding": "inplace", + "label": "contract IDefaultPool", + "numberOfBytes": "20" + }, + "t_contract(ILiquityBaseParams)20379": { + "encoding": "inplace", + "label": "contract ILiquityBaseParams", + "numberOfBytes": "20" + }, + "t_contract(IPriceFeed)20458": { + "encoding": "inplace", + "label": "contract IPriceFeed", + "numberOfBytes": "20" + }, + "t_contract(ISortedTroves)20817": { + "encoding": "inplace", + "label": "contract ISortedTroves", + "numberOfBytes": "20" + }, + "t_contract(ITroveManager)21635": { + "encoding": "inplace", + "label": "contract ITroveManager", + "numberOfBytes": "20" + }, + "t_contract(IZUSDToken)21842": { + "encoding": "inplace", + "label": "contract IZUSDToken", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_struct(Deposit)28106_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct StabilityPoolStorage.Deposit)", + "numberOfBytes": "32", + "value": "t_struct(Deposit)28106_storage" + }, + "t_mapping(t_address,t_struct(FrontEnd)28101_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct StabilityPoolStorage.FrontEnd)", + "numberOfBytes": "32", + "value": "t_struct(FrontEnd)28101_storage" + }, + "t_mapping(t_address,t_struct(Snapshots)28117_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct StabilityPoolStorage.Snapshots)", + "numberOfBytes": "32", + "value": "t_struct(Snapshots)28117_storage" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_mapping(t_uint128,t_mapping(t_uint128,t_uint256))": { + "encoding": "mapping", + "key": "t_uint128", + "label": "mapping(uint128 => mapping(uint128 => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint128,t_uint256)" + }, + "t_mapping(t_uint128,t_uint256)": { + "encoding": "mapping", + "key": "t_uint128", + "label": "mapping(uint128 => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_struct(Deposit)28106_storage": { + "encoding": "inplace", + "label": "struct StabilityPoolStorage.Deposit", + "members": [ + { + "astId": 28103, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "initialValue", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 28105, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "frontEndTag", + "offset": 0, + "slot": "1", + "type": "t_address" + } + ], + "numberOfBytes": "64" + }, + "t_struct(FrontEnd)28101_storage": { + "encoding": "inplace", + "label": "struct StabilityPoolStorage.FrontEnd", + "members": [ + { + "astId": 28098, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "kickbackRate", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 28100, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "registered", + "offset": 0, + "slot": "1", + "type": "t_bool" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Snapshots)28117_storage": { + "encoding": "inplace", + "label": "struct StabilityPoolStorage.Snapshots", + "members": [ + { + "astId": 28108, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "S", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 28110, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "P", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 28112, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "G", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 28114, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "scale", + "offset": 0, + "slot": "3", + "type": "t_uint128" + }, + { + "astId": 28116, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "epoch", + "offset": 16, + "slot": "3", + "type": "t_uint128" + } + ], + "numberOfBytes": "128" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/external/deployments/rskMainnet/StabilityPool_Proxy.json b/external/deployments/rskMainnet/StabilityPool_Proxy.json new file mode 100644 index 000000000..b94121f4a --- /dev/null +++ b/external/deployments/rskMainnet/StabilityPool_Proxy.json @@ -0,0 +1,110 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "UpgradableProxy", + "sourceName": "contracts/Proxy/UpgradableProxy.sol", + "address": "0xd46C0225D1331B46700d64fF8c906709D15C9202", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_oldImplementation", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_newImplementation", + "type": "address" + } + ], + "name": "ImplementationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610023336001600160e01b0361002816565b610110565b6001600160a01b03811661006d5760405162461bcd60e51b81526004018080602001828103825260228152602001806105e26022913960400191505060405180910390fd5b6001600160a01b0381166100886001600160e01b036100e616565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b6104c38061011f6000396000f3fe6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b00334f776e61626c653a3a7365744f776e65723a20696e76616c69642061646472657373", + "deployedBytecode": "0x6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/external/deployments/rskMainnet/TroveManager.json b/external/deployments/rskMainnet/TroveManager.json new file mode 100644 index 000000000..f5a9b0b51 --- /dev/null +++ b/external/deployments/rskMainnet/TroveManager.json @@ -0,0 +1,2091 @@ +{ + "address": "0x82B09695ee4F214f3A0803683C4AaEc332E4E0a3", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_bootstrapPeriod", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_baseRate", + "type": "uint256" + } + ], + "name": "BaseRateUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newBorrowerOperationsAddress", + "type": "address" + } + ], + "name": "BorrowerOperationsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + } + ], + "name": "CollSurplusPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + } + ], + "name": "FeeDistributorAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + } + ], + "name": "GasPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "LTermsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_lastFeeOpTime", + "type": "uint256" + } + ], + "name": "LastFeeOpTimeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedDebt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedColl", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_collGasCompensation", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDGasCompensation", + "type": "uint256" + } + ], + "name": "Liquidation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + } + ], + "name": "LiquityBaseParamsAddressChanges", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_attemptedZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_actualZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHSent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHFee", + "type": "uint256" + } + ], + "name": "Redemption", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + } + ], + "name": "StabilityPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_totalStakesSnapshot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalCollateralSnapshot", + "type": "uint256" + } + ], + "name": "SystemSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newTotalStakes", + "type": "uint256" + } + ], + "name": "TotalStakesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newIndex", + "type": "uint256" + } + ], + "name": "TroveIndexUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveLiquidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + } + ], + "name": "TroveManagerRedeemOpsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "TroveSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "ZEROStakingAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroTokenAddress", + "type": "address" + } + ], + "name": "ZEROTokenAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newZUSDTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "BETA", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BOOTSTRAP_PERIOD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "CCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ETH", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ZUSDDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINUTE_DECAY_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SECONDS_IN_ONE_MINUTE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "TroveOwners", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "Troves", + "outputs": [ + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coll", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "internalType": "enum TroveManagerStorage.Status", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "arrayIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "_getCurrentICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingETHReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingZUSDDebtReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_getRedemptionRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_hasPendingRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_stabilityPool", + "outputs": [ + { + "internalType": "contract IStabilityPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroStaking", + "outputs": [ + { + "internalType": "contract IZEROStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroToken", + "outputs": [ + { + "internalType": "contract IZEROToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "addTroveOwnerToArray", + "outputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "applyPendingRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_troveArray", + "type": "address[]" + } + ], + "name": "batchLiquidateTroves", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "borrowerOperationsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "checkRecoveryMode", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "closeTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decayBaseRateFromBorrowing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_collDecrease", + "type": "uint256" + } + ], + "name": "decreaseTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_debtDecrease", + "type": "uint256" + } + ], + "name": "decreaseTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeDistributor", + "outputs": [ + { + "internalType": "contract IFeeDistributor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDDebt", + "type": "uint256" + } + ], + "name": "getBorrowingFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDDebt", + "type": "uint256" + } + ], + "name": "getBorrowingFeeWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBorrowingRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBorrowingRateWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "getCurrentICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getEntireDebtAndColl", + "outputs": [ + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coll", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pendingZUSDDebtReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pendingETHReward", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getNominalICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getPendingETHReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getPendingZUSDDebtReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ETHDrawn", + "type": "uint256" + } + ], + "name": "getRedemptionFeeWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRedemptionRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRedemptionRateWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "getTCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_index", + "type": "uint256" + } + ], + "name": "getTroveFromTroveOwnersArray", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTroveOwnersCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveStatus", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "hasPendingRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_collIncrease", + "type": "uint256" + } + ], + "name": "increaseTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_debtIncrease", + "type": "uint256" + } + ], + "name": "increaseTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lastETHError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFeeOperationTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastZUSDDebtError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "liquidate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_n", + "type": "uint256" + } + ], + "name": "liquidateTroves", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDamount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + } + ], + "name": "redeemCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "redeemCollateralViaDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "redeemCollateralViaDllrWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "removeStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "rewardSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "ETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ZUSDDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + }, + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "internalType": "struct ITroveManager.TroveManagerInitAddressesParams", + "name": "_troveManagerInitAddressesParams", + "type": "tuple" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + } + ], + "name": "setTroveManagerRedeemOps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_num", + "type": "uint256" + } + ], + "name": "setTroveStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalCollateralSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakesSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManagerRedeemOps", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "updateStakeAndTotalStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "updateTroveRewardSnapshots", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0xdC03c72c1730b149E3178624FD4d9Bf51501A6E0", + "transactionIndex": 0, + "gasUsed": "6045491", + "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000080000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000400000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x63ae44ab567d090410beb39dd6c2dad30f27c33679e013ac466adf6afc60e169", + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748962, + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "address": "0xdC03c72c1730b149E3178624FD4d9Bf51501A6E0", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x63ae44ab567d090410beb39dd6c2dad30f27c33679e013ac466adf6afc60e169" + } + ], + "blockNumber": 4748962, + "cumulativeGasUsed": "6045491", + "status": 1, + "byzantium": true + }, + "numDeployments": 5, + "bytecode": "0x60c06040523480156200001157600080fd5b50604051620058f2380380620058f2833981016040819052620000349162000128565b8162000049336001600160e01b036200006316565b60805260601b6001600160601b03191660a05250620001c4565b6001600160a01b038116620000955760405162461bcd60e51b81526004016200008c9062000182565b60405180910390fd5b6001600160a01b038116620000b26001600160e01b036200010716565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f79062000165565b6040519081900390209190915550565b600080604051620001189062000165565b6040519081900390205492915050565b600080604083850312156200013b578182fd5b825160208401519092506001600160a01b03811681146200015a578182fd5b809150509250929050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160a05160601c615707620001eb60003980610ff152508061223252506157076000f3fe608060405234801561001057600080fd5b50600436106104c25760003560e01c8063756b253e11610278578063b0d8e1811161015c578063d293c710116100ce578063d815e8e911610092578063d815e8e91461095a578063d9a7244414610962578063e056e91814610975578063e2ac77b014610988578063f36b24251461099b578063fe2ba848146109a3576104c2565b8063d293c71014610906578063d380a37c14610919578063d3d6f84314610921578063d5b3563514610934578063d66a255314610947576104c2565b8063be4b033411610120578063be4b0334146108cb578063bf9befb1146108d3578063c35bc550146108db578063c52861f2146108e3578063c7b55481146108eb578063cbd138ae146108f3576104c2565b8063b0d8e18114610867578063b7f8cf9b1461087a578063b82f263d14610882578063b91af97c14610895578063bcd37526146108b8576104c2565b8063887105d3116101f55780639dd233d2116101b95780639dd233d2146108325780639f0706701461083a578063a20baee614610773578063a3f4df7e14610842578063ae7bec1914610857578063ae9187541461085f576104c2565b8063887105d3146107f4578063893d20e8146107fc57806396d711ff146108045780639708daf41461080c5780639976cf451461081f576104c2565b80637cf54e401161023c5780637cf54e40146107b65780637f7dde4a146107be578063807d138d146107c657806382fe3eb9146107ce57806387436936146107e1576104c2565b8063756b253e14610783578063759b303414610796578063794e57241461079e578063795d26c3146107a6578063797250e3146107ae576104c2565b80633cc74225116103aa57806361ec893d1161031c5780636b444952116102e05780636b4449521461072c5780636ef6433814610734578063716c47e61461075857806372423c171461076057806372fe25aa14610773578063741bef1a1461077b576104c2565b806361ec893d146106e3578063631203b0146106eb57806364cee260146106fe578063653d46e71461071157806366ca4a2114610724576104c2565b80634a767d681161036e5780634a767d681461067a5780634e443d9e1461068d5780635733d58f146106ad5780635d6b480f146106b55780635d8c9609146106c85780635dba4c4a146106db576104c2565b80633cc742251461063157806342ccf1e414610639578063477d66cf1461064c578063480cd5781461065f57806349eefeee14610672576104c2565b806317c62b17116104435780631f68f20a116104075780631f68f20a146105eb57806321e37801146105f35780632b11551a146106065780632f8655681461060e57806331c903b0146106215780633a12859514610629576104c2565b806317c62b171461059757806318f2817a146105aa5780631a59a50e146105bd5780631bf43555146105d05780631e8b1c2b146105d8576104c2565b806312261ee71161048a57806312261ee71461053557806312610e921461053d57806313af40351461055057806315d549f1146105635780631673c79a14610576576104c2565b806301f16e18146104c757806305b6f5ca146104dc578063071a7541146104ef5780630b0765571461050d5780630d43e8ad14610520575b600080fd5b6104da6104d5366004614d96565b6109b6565b005b6104da6104ea366004614f61565b610f1c565b6104f7610fb3565b6040516105049190615568565b60405180910390f35b6104da61051b366004614c9f565b610fb8565b610528610fe0565b604051610504919061512e565b610528610fef565b6104f761054b366004614cd7565b611013565b6104da61055e366004614c9f565b61106b565b6104f7610571366004614c9f565b6110ac565b610589610584366004614c9f565b6110d0565b604051610504929190615571565b6104f76105a5366004614c9f565b6110e9565b6104f76105b8366004614c9f565b6110f4565b6104f76105cb366004614c9f565b611107565b6104f76111cd565b6104da6105e6366004614d02565b6111da565b6104f761153b565b6104f7610601366004614c9f565b611541565b6104f761156b565b6104da61061c366004614c9f565b61157a565b6104f76115e0565b6105286115ed565b6105286115fc565b6104f7610647366004614c9f565b61160b565b6104f761065a366004614ec4565b61163c565b6104f761066d366004614c9f565b61164f565b6104f761166d565b6104f7610688366004614cd7565b611673565b6106a061069b366004614ec4565b611692565b60405161050491906151a1565b6104f761169d565b6104da6106c3366004614cd7565b61171a565b6104f76106d6366004614c9f565b611766565b6104da611771565b6104f76117dc565b6104f76106f9366004614ec4565b6117e1565b6104f761070c366004614c9f565b6117ee565b6104da61071f366004614ec4565b61180c565b6104f7611b96565b6104f7611ba8565b610747610742366004614c9f565b611bae565b6040516105049594939291906155a3565b610528611be8565b6104f761076e366004614cd7565b611bf7565b6104f7611c54565b610528611c60565b610528610791366004614ec4565b611c6f565b6104f7611c96565b6104f7611ca3565b6104f7611ce8565b6104f7611e07565b610528611e0d565b610528611e1c565b6104f7611e2b565b6104da6107dc366004614c9f565b611e31565b6104da6107ef366004614c9f565b611e42565b6104f7611ece565b610528611f9d565b6104f7611fbc565b6104da61081a366004614feb565b611fc2565b6104f761082d366004614cd7565b61205b565b6104f761208e565b610528612094565b61084a6120a3565b60405161050491906151da565b6105286120cb565b6105286120da565b6104f7610875366004614c9f565b6120e9565b610528612110565b6104f7610890366004614ec4565b61211f565b6108a86108a3366004614c9f565b61212a565b604051610504949392919061560f565b6104da6108c6366004614ef4565b61218e565b6104f7612224565b6104f761222a565b6104f7612230565b6104f7612254565b6104f7612266565b6104da610901366004614c9f565b612272565b6104f7610914366004614cd7565b612285565b6104f7612298565b6104f761092f366004614cd7565b61229e565b6104f7610942366004614ec4565b6122d4565b6104f7610955366004614c9f565b6122e7565b610528612302565b610528610970366004614ec4565b612311565b6106a0610983366004614c9f565b61233b565b6106a0610996366004614c9f565b612399565b6104f76123a4565b6104da6109b1366004614c9f565b6123b1565b6109be611f9d565b6001600160a01b0316336001600160a01b0316146109f75760405162461bcd60e51b81526004016109ee906153c5565b60405180910390fd5b8051610a02906123c2565b610a0f81602001516123c2565b610a1c81604001516123c2565b610a2981606001516123c2565b610a3681608001516123c2565b610a438160a001516123c2565b610a508160c001516123c2565b610a5d8160e001516123c2565b610a6b8161010001516123c2565b610a798161012001516123c2565b610a878161014001516123c2565b610a958161016001516123c2565b610aa38161018001516123c2565b610ab1816101a001516123c2565b8051600c80546001600160a01b03199081166001600160a01b038085169190911790925560208401516004805483169184169190911790556040808501516003805484169185169190911790556060850151600580548416918516919091179055608085015160008054841691851691909117905560a085015160018054841691851691909117905560c085015160068054841691851691909117905560e0850151600780548416918516919091179055610100850151600880548416918516919091179055610120850151600280548416918516919091179055610140850151600980548416918516919091179055610160850151600d80548416918516919091179055610180850151600a805484169185169190911790556101a0850151600b80549093169316929092179055517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db991610c0c9161512e565b60405180910390a17f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b18160200151604051610c47919061512e565b60405180910390a17fbf65195e6d5213f6fcbce65b1454c925197a45e616dabd2e243542b039b050928160600151604051610c82919061512e565b60405180910390a17f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed9858160600151604051610cbd919061512e565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828160800151604051610cf8919061512e565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b8160a00151604051610d33919061512e565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f8160c00151604051610d6e919061512e565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa08160e00151604051610da9919061512e565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d816101000151604051610de5919061512e565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264816101200151604051610e21919061512e565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d816101400151604051610e5d919061512e565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800816101600151604051610e99919061512e565b60405180910390a17f61e0c29d5028a9e4facaa476a46e78912e99f1ba945c9560b86b82ebe36ee52d816101800151604051610ed5919061512e565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd816101a00151604051610f11919061512e565b60405180910390a150565b6004546040516000916060916001600160a01b0390911690610f419084903690615101565b600060405180830381855af49150503d8060008114610f7c576040519150601f19603f3d011682016040523d82523d6000602084013e610f81565b606091505b5091509150818190610fa65760405162461bcd60e51b81526004016109ee91906151da565b5050505050505050505050565b600281565b610fc0612407565b600054600154610fdd916001600160a01b03908116911683612433565b50565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061101d612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff61254516565b6001600160a01b03851660009081526010602052604090208190559150505b92915050565b611073611f9d565b6001600160a01b0316336001600160a01b0316146110a35760405162461bcd60e51b81526004016109ee906153c5565b610fdd81612587565b60006110b6612407565b6110bf82612612565b6001600160801b031690505b919050565b6016602052600090815260409020805460019091015482565b60006110658261160b565b60006110fe612407565b611065826126ac565b6001600160a01b0381166000908152601660205260408120546014548290611135908363ffffffff61254516565b905080158061116e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561116b57fe5b14155b1561117e576000925050506110cb565b6001600160a01b038416600090815260106020526040812060020154906111c3670de0b6b3a76400006111b7848663ffffffff61275f16565b9063ffffffff61279916565b9695505050505050565b6809c2007651b250000081565b80516111f85760405162461bcd60e51b81526004016109ee906153f6565b6000546001546006546001600160a01b0392831692918216911661121a614b2b565b611222614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ec57600080fd5b505afa158015611300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113249190614edc565b60208301528151611334906127db565b158015604084015261135c576113558585846000015185602001518a612876565b9050611374565b6113718585846000015185602001518a612b8b565b90505b60008160200151116113985760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad926113cc92600401615571565b600060405180830381600087803b1580156113e657600080fd5b505af11580156113fa573d6000803e3d6000fd5b5050505061141285858360c001518460e00151612ccb565b61010081015115611489576008546101008201516040516364a197f360e01b81526001600160a01b03888116936364a197f393611456939290911691600401615188565b600060405180830381600087803b15801561147057600080fd5b505af1158015611484573d6000803e3d6000fd5b505050505b611497858260400151612f2f565b60208101516060830152610100810151604082015182516114cf92916114c3919063ffffffff61254516565b9063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611517949092909161560f565b60405180910390a1611533853383606001518460400151613090565b505050505050565b600e5481565b6001600160a01b03811660009081526010602052604081206003015460ff16600481111561106557fe5b60006115756115e0565b905090565b6115838161316d565b6040805160018082528183019092526060916020808301908036833701905050905081816000815181106115b357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506115dc816111da565b5050565b6000611575600e546131b6565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290611135908363ffffffff61254516565b6000611065611649611b96565b83613253565b6001600160a01b031660009081526010602052604090206001015490565b60175490565b600080600061168185613271565b9150915060006111c38383876132f7565b6000611065826127db565b60035460408051635733d58f60e01b815290516000926001600160a01b031691635733d58f916004808301926020929190829003018186803b1580156116e257600080fd5b505afa1580156116f6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115759190614edc565b611722612407565b80600481111561172e57fe5b6001600160a01b0383166000908152601060205260409020600301805460ff1916600183600481111561175d57fe5b02179055505050565b600061106582611107565b611779612407565b6000611783613329565b9050670de0b6b3a764000081111561179757fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c906117cc908390615568565b60405180910390a1610fdd61336d565b603c81565b60006110656116496123a4565b6001600160a01b031660009081526010602052604090206002015490565b611814614ba8565b506040805160e081018252600080546001600160a01b0390811683526001548116602084015292820181905260608201819052600d548316608083015260a0820181905260c082015260065490911661186b614b2b565b611873614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fb9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b15801561193d57600080fd5b505afa158015611951573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119759190614edc565b60208301528151611985906127db565b15801560408401526119ac576119a58483600001518460200151886133c2565b90506119cc565b6119c9846000015185602001518460000151856020015189613869565b90505b60008160200151116119f05760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad92611a2492600401615571565b600060405180830381600087803b158015611a3e57600080fd5b505af1158015611a52573d6000803e3d6000fd5b50505050611a72846000015185602001518360c001518460e00151612ccb565b61010081015115611ae95783516008546101008301516040516364a197f360e01b81526001600160a01b03938416936364a197f393611ab693911691600401615188565b600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050505b611afb84600001518260400151612f2f565b6020810151606083015261010081015160408201518251611b2792916114c3919063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611b6f949092909161560f565b60405180910390a1611b8f84600001513383606001518460400151613090565b5050505050565b6000611575611ba3613329565b613a1f565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b6000611c01612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff613b0116565b6001600160a01b038516600090815260106020526040902060010181905591505092915050565b670de0b6b3a764000081565b6002546001600160a01b031681565b60178181548110611c7c57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60035460408051631e5395c960e21b815290516000926001600160a01b03169163794e5724916004808301926020929190829003018186803b1580156116e257600080fd5b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015611d2c57600080fd5b505afa158015611d40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d649190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b505afa158015611dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dee9190614edc565b9050611e00828263ffffffff613b0116565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b611e39612407565b610fdd81613b26565b611e4a611f9d565b6001600160a01b0316336001600160a01b031614611e7a5760405162461bcd60e51b81526004016109ee906153c5565b611e83816123c2565b600480546001600160a01b0319166001600160a01b0383161790556040517f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b190610f1190839061512e565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b158015611f1357600080fd5b505afa158015611f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4b9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b600080604051611fac90615111565b6040519081900390205492915050565b60135481565b6004546040516000916060916001600160a01b0390911690611fe79084903690615101565b600060405180830381855af49150503d8060008114612022576040519150601f19603f3d011682016040523d82523d6000602084013e612027565b606091505b509150915081819061204c5760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050505050565b6000612065612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff613b0116565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b60008060006120f784613271565b9150915060006121078383613b83565b95945050505050565b6005546001600160a01b031681565b600061106582613bb8565b6001600160a01b03811660009081526010602052604081208054600190910154909180612156856110e9565b915061216185611766565b9050612173848363ffffffff613b0116565b9350612185838263ffffffff613b0116565b92509193509193565b6004546040516000916060916001600160a01b03909116906121b39084903690615101565b600060405180830381855af49150503d80600081146121ee576040519150601f19603f3d011682016040523d82523d6000602084013e6121f3565b606091505b50915091508181906122185760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000611575612261613329565b6131b6565b670ddd4b8c6c7d70d881565b61227a612407565b610fdd816002613be4565b60006122918383611673565b9392505050565b600f5481565b60006122a8612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff61254516565b60006110656122e1612254565b83613cf9565b6001600160a01b031660009081526010602052604090205490565b6009546001600160a01b031681565b60006017828154811061232057fe5b6000918252602090912001546001600160a01b031692915050565b600060016001600160a01b03831660009081526010602052604090206003015460ff16600481111561236957fe5b14612376575060006110cb565b506014546001600160a01b03821660009081526016602052604090205410919050565b60006110658261233b565b6000611575600e54613a1f565b6123b9612407565b610fdd81613d39565b6001600160a01b0381166123e85760405162461bcd60e51b81526004016109ee906152a6565b803b806115dc5760405162461bcd60e51b81526004016109ee9061544c565b6005546001600160a01b031633146124315760405162461bcd60e51b81526004016109ee90615368565b565b61243c8161233b565b156125405761244a8161316d565b600061245582611107565b905060006124628361160b565b6001600160a01b038416600090815260106020526040902060010154909150612491908363ffffffff613b0116565b6001600160a01b03841660009081526010602052604090206001810191909155546124c2908263ffffffff613b0116565b6001600160a01b0384166000908152601060205260409020556124e483613b26565b6124f085858385613d89565b6001600160a01b0383166000818152601060205260408082208054600182015460029092015492516000805160206156b28339815191529461253594929392916155e3565b60405180910390a250505b505050565b600061229183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613e71565b6001600160a01b0381166125ad5760405162461bcd60e51b81526004016109ee90615264565b806001600160a01b03166125bf611f9d565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600060405161260290615111565b6040519081900390209190915550565b601780546001808201835560008381527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1590920180546001600160a01b0319166001600160a01b0386161790559154909161266d9190612545565b6001600160a01b039290921660009081526010602052604090206003018054610100600160881b0319166101006001600160801b038516021790555090565b6001600160a01b03811660009081526010602052604081206001015481906126d390613e9d565b6001600160a01b03841660009081526010602052604090206002018054908290556011549192509061271d908390612711908463ffffffff61254516565b9063ffffffff613b0116565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829161275091615568565b60405180910390a15092915050565b60008261276e57506000611065565b8282028284828161277b57fe5b04146122915760405162461bcd60e51b81526004016109ee90615327565b600061229183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ed9565b6000806127e783613bb8565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561283757600080fd5b505afa15801561284b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286f9190614edc565b1192915050565b61287e614b5c565b612886614be4565b61288e614b5c565b848252600060808301526128a0611ce8565b60a08301526128ad611ece565b60c0830152600060208301525b835182602001511015612b8057838260200151815181106128d757fe5b6020908102919091018101516001600160a01b03166060840181905260009081526010909152604090206003015460019060ff16600481111561291657fe5b1461292057612b70565b61292e826060015187611673565b60408301526080820151612a9557600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561298a57600080fd5b505afa15801561299e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c29190614edc565b8260400151101580156129d457508151155b156129de57612b70565b60006129f38360c001518460a00151896132f7565b9050612a108989856060015186604001518760000151868d613f10565b60808101518451919350612a2a919063ffffffff61254516565b8352608082015160a0840151612a459163ffffffff61254516565b60a08085019190915282015160c0840151612a659163ffffffff61254516565b60c0840152612a7484836142e6565b9350612a898360c001518460a00151896143fd565b15608084015250612b70565b81608001518015612b2e5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015612aef57600080fd5b505afa158015612b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b279190614edc565b8260400151105b15612b7057612b4788888460600151856000015161449c565b60808101518351919250612b61919063ffffffff61254516565b8252612b6d83826142e6565b92505b60208201805160010190526128ba565b505095945050505050565b612b93614b5c565b612b9b614be4565b612ba3614b5c565b848252600060208301525b835182602001511015612b805783826020015181518110612bcb57fe5b60209081029190910101516001600160a01b031660608301819052612bf09087611673565b6040808401919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c739190614edc565b82604001511015612cbb57612c9288888460600151856000015161449c565b60808101518351919250612cac919063ffffffff61254516565b8252612cb883826142e6565b92505b6020820180516001019052612bae565b81612cd557612f29565b601854600090612cf79061271184670de0b6b3a764000063ffffffff61275f16565b90506000612d1c601954612711670de0b6b3a76400008761275f90919063ffffffff16565b90506000612d356011548461279990919063ffffffff16565b90506000612d4e6011548461279990919063ffffffff16565b9050612d75612d686011548461275f90919063ffffffff16565b859063ffffffff61254516565b601855601154612d9d90612d9090839063ffffffff61275f16565b849063ffffffff61254516565b601955601454612db3908363ffffffff613b0116565b601455601554612dc9908263ffffffff613b0116565b60158190556014546040517f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e392612e009291615571565b60405180910390a160405163121cbc4d60e11b81526001600160a01b03891690632439789a90612e34908990600401615568565b600060405180830381600087803b158015612e4e57600080fd5b505af1158015612e62573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038a16925063f2e91d719150612e92908990600401615568565b600060405180830381600087803b158015612eac57600080fd5b505af1158015612ec0573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b038b1692506364a197f39150612ef2908a908990600401615188565b600060405180830381600087803b158015612f0c57600080fd5b505af1158015612f20573d6000803e3d6000fd5b50505050505050505b50505050565b6011546012819055506000826001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7357600080fd5b505afa158015612f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fab9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ffd57600080fd5b505afa158015613011573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130359190614edc565b905061304b81612711848663ffffffff61254516565b60138190556012546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf60926130829291615571565b60405180910390a150505050565b811561310157600954600754604051631062c15f60e11b81526001600160a01b03928316926320c582be926130ce9291169087908790600401615142565b600060405180830381600087803b1580156130e857600080fd5b505af11580156130fc573d6000803e3d6000fd5b505050505b8015612f29576040516364a197f360e01b81526001600160a01b038516906364a197f3906131359086908590600401615188565b600060405180830381600087803b15801561314f57600080fd5b505af1158015613163573d6000803e3d6000fd5b5050505050505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561319957fe5b14610fdd5760405162461bcd60e51b81526004016109ee90615519565b600061106561324583600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b505afa158015613221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127119190614edc565b670de0b6b3a76400006145ce565b6000612291670de0b6b3a76400006111b7858563ffffffff61275f16565b600080600061327f84611107565b9050600061328c8561160b565b6001600160a01b038616600090815260106020526040812060010154919250906132bc908463ffffffff613b0116565b6001600160a01b038716600090815260106020526040812054919250906132e9908463ffffffff613b0116565b919550909350505050915091565b6000821561331e576000613315846111b7878663ffffffff61275f16565b91506122919050565b506000199392505050565b6000806133346145e4565b9050600061334a670ddd4b8c6c7d70d883614600565b9050611e00670de0b6b3a76400006111b783600e5461275f90919063ffffffff16565b6000613384600f544261254590919063ffffffff16565b9050603c8110610fdd5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc91610f1191615568565b6133ca614b5c565b6133d2614be4565b6133da614b5c565b848252600060808301526133ec611ce8565b60a08301526133f9611ece565b8260c001818152505086608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561343f57600080fd5b505afa158015613453573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134779190614cbb565b82606001906001600160a01b031690816001600160a01b031681525050600087608001516001600160a01b0316631e2231436040518163ffffffff1660e01b815260040160206040518083038186803b1580156134d357600080fd5b505afa1580156134e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350b9190614cbb565b6000602085015290505b84836020015110801561353e5750806001600160a01b031683606001516001600160a01b031614155b1561385e5760808801516060840151604051632dc9c0eb60e21b81526000926001600160a01b03169163b72703ac9161357a919060040161512e565b60206040518083038186803b15801561359257600080fd5b505afa1580156135a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ca9190614cbb565b90506135da846060015189611673565b6040850152608084015161375357600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561363657600080fd5b505afa15801561364a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061366e9190614edc565b84604001511015801561368057508351155b1561368b575061385e565b60006136a08560c001518660a001518b6132f7565b8a5160208c01516060880151604089015189519495506136c194868f613f10565b608081015186519195506136db919063ffffffff61254516565b8552608084015160a08601516136f69163ffffffff61254516565b8560a00181815250506137238461010001516114c38660a001518860c0015161254590919063ffffffff16565b60c086015261373286856142e6565b95506137478560c001518660a001518b6143fd565b15608086015250613840565b836080015180156137ec5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156137ad57600080fd5b505afa1580156137c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e59190614edc565b8460400151105b1561383a5761380d89600001518a602001518660600151876000015161449c565b60808101518551919450613827919063ffffffff61254516565b845261383385846142e6565b9450613840565b5061385e565b6001600160a01b031660608401526020830180516001019052613515565b505050949350505050565b613871614b5c565b613879614be4565b613881614b5c565b600d54858352600060208401526001600160a01b03165b8483602001511015613a1357806001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156138dd57600080fd5b505afa1580156138f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139159190614cbb565b6001600160a01b03166060840181905261392f9088611673565b6040808501919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b15801561397a57600080fd5b505afa15801561398e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b29190614edc565b836040015110156139fe576139d189898560600151866000015161449c565b608081015184519193506139eb919063ffffffff61254516565b83526139f784836142e6565b9350613a03565b613a13565b6020830180516001019052613898565b50505095945050505050565b6000611065613a7683600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b031663240926696040518163ffffffff1660e01b815260040160206040518083038186803b158015613ac457600080fd5b505afa158015613ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613afc9190614edc565b6145ce565b6000828201838110156122915760405162461bcd60e51b81526004016109ee9061522d565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92610f11929091615571565b60008115613baf57613ba8826111b78568056bc75e2d6310000063ffffffff61275f16565b9050611065565b50600019611065565b600080613bc3611ece565b90506000613bcf611ce8565b9050613bdc8282866132f7565b949350505050565b6000816004811115613bf257fe5b14158015613c0c57506001816004811115613c0957fe5b14155b613c1257fe5b601754613c1e816146ab565b6001600160a01b0383166000908152601060205260409020600301805483919060ff19166001836004811115613c5057fe5b02179055506001600160a01b0383166000908152601060209081526040808320600180820185905590849055601690925282208281550155613c928382614751565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e90613cc290869060040161512e565b600060405180830381600087803b158015613cdc57600080fd5b505af1158015613cf0573d6000803e3d6000fd5b50505050505050565b600080613d18670de0b6b3a76400006111b7868663ffffffff61275f16565b90508281106122915760405162461bcd60e51b81526004016109ee90615481565b6001600160a01b038116600090815260106020526040902060020154601154613d68908263ffffffff61254516565b601155506001600160a01b0316600090815260106020526040812060020155565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a90613db5908590600401615568565b600060405180830381600087803b158015613dcf57600080fd5b505af1158015613de3573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150613e13908590600401615568565b600060405180830381600087803b158015613e2d57600080fd5b505af1158015613e41573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150613135908490600401615568565b60008184841115613e955760405162461bcd60e51b81526004016109ee91906151da565b505050900390565b60008060135460001415613eb2575081611065565b600060125411613ebe57fe5b6122916013546111b76012548661275f90919063ffffffff16565b60008183613efa5760405162461bcd60e51b81526004016109ee91906151da565b506000838581613f0657fe5b0495945050505050565b613f18614b5c565b613f20614c2c565b601754600110613f3057506142db565b613f398761212a565b60408501526020848101919091528401819052908352613f58906148f2565b604083018190526801158e460913d0000060608401526020830151613f829163ffffffff61254516565b8152670de0b6b3a7640000861161404d57613fa7898983602001518460400151613d89565b613fb087613d39565b60006080830181905260a0830152815160c0830152805160e0830152613fd7876003613be4565b815160208301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b60405180910390a2866001600160a01b03166000805160206156b28339815191526000806000600260405161404094939291906151ac565b60405180910390a26142d9565b670de0b6b3a7640000861180156140e85750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156140ad57600080fd5b505afa1580156140c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e59190614edc565b86105b1561413857614101898983602001518460400151613d89565b61410a87613d39565b8151815161411991908761497e565b60e086015260c085015260a08401526080830152613fd7876003613be4565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561418657600080fd5b505afa15801561419a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141be9190614edc565b86101580156141cc57508386105b80156141d9575081518510155b156142c8576141f2898983602001518460400151613d89565b846141f957fe5b61420287613d39565b61421582600001518360200151856149ea565b9150614222876003613be4565b6101008201511561429757600854610100830151604051633f10abab60e01b81526001600160a01b0390921691633f10abab91614264918b9190600401615188565b600060405180830381600087803b15801561427e57600080fd5b505af1158015614292573d6000803e3d6000fd5b505050505b815160a08301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b6142d0614b5c565b91506142db9050565b505b979650505050505050565b6142ee614b5c565b604080830151908401516143079163ffffffff613b0116565b6040820152606080830151908401516143259163ffffffff613b0116565b6060820152815160208401516143409163ffffffff613b0116565b602080830191909152820151835161435d9163ffffffff613b0116565b8152608080830151908401516143789163ffffffff613b0116565b608082015260a080830151908401516143969163ffffffff613b0116565b60a082015260c080830151908401516143b49163ffffffff613b0116565b60c082015260e080830151908401516143d29163ffffffff613b0116565b60e082015261010080830151908401516143f19163ffffffff613b0116565b61010082015292915050565b60008061440b8585856132f7565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561445b57600080fd5b505afa15801561446f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144939190614edc565b11949350505050565b6144a4614b5c565b6144ac614c2c565b6144b58461212a565b604085019081526020858101928352860192909252918452905190516144df918891889190613d89565b6144e884613d39565b6144f582602001516148f2565b604083018190526801158e460913d0000060608401526020830151600091614523919063ffffffff61254516565b90506145348360000151828661497e565b60e087015260c086015260a08501526080840152614553856003613be4565b825160208401516040516001600160a01b03881692600080516020615692833981519152926145849260019061557f565b60405180910390a2846001600160a01b03166000805160206156b2833981519152600080600060016040516145bc94939291906151ac565b60405180910390a25050949350505050565b60008183106145dd5781612291565b5090919050565b6000611575603c6111b7600f544261254590919063ffffffff16565b6000631f54050082111561461657631f54050091505b8161462a5750670de0b6b3a7640000611065565b670de0b6b3a764000083835b60018111156146a1576002810661466b576146518283614af8565b915061466481600263ffffffff61279916565b905061469c565b6146758284614af8565b92506146818283614af8565b915061469960026111b783600163ffffffff61254516565b90505b614636565b6111c38284614af8565b6001811180156147355750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b1580156146fb57600080fd5b505afa15801561470f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147339190614edc565b115b610fdd5760405162461bcd60e51b81526004016109ee906152dd565b6001600160a01b03821660009081526010602052604081206003015460ff169081600481111561477d57fe5b141580156147975750600181600481111561479457fe5b14155b61479d57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b03169083906147d5826001612545565b905080836001600160801b031611156147ea57fe5b6000601782815481106147f957fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b03871690811061482b57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a906148b49083908790615166565b60405180910390a160178054806148c757fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b600354604080516324386ecd60e11b815290516000926001600160a01b031691634870dd9a916004808301926020929190829003018186803b15801561493757600080fd5b505afa15801561494b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496f9190614edc565b828161497757fe5b0492915050565b600080808084156149d45761499387866145ce565b93506149a9876111b7888763ffffffff61275f16565b92506149bb878563ffffffff61254516565b91506149cd868463ffffffff61254516565b90506149e1565b5060009250829150859050845b93509350935093565b6149f2614b5c565b838152602080820184905260035460408051631e5395c960e21b81529051600093614a8e9387936111b7936001600160a01b039092169263794e572492600480840193829003018186803b158015614a4957600080fd5b505afa158015614a5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a819190614edc565b889063ffffffff61275f16565b9050614a99816148f2565b604083018190526801158e460913d00000606084015260808301869052614ac790829063ffffffff61254516565b60a0830152614adc848263ffffffff61254516565b61010083015250600060c0820181905260e08201529392505050565b600080614b0b848463ffffffff61275f16565b9050613bdc670de0b6b3a76400006111b7836706f05b59d3b20000613b01565b6040518060a00160405280600081526020016000815260200160001515815260200160008152602001600081525090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040518060e0016040528060008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b80356110658161567c565b60008083601f840112614c69578081fd5b50813567ffffffffffffffff811115614c80578182fd5b602083019150836020828501011115614c9857600080fd5b9250929050565b600060208284031215614cb0578081fd5b81356122918161567c565b600060208284031215614ccc578081fd5b81516122918161567c565b60008060408385031215614ce9578081fd5b8235614cf48161567c565b946020939093013593505050565b60006020808385031215614d14578182fd5b823567ffffffffffffffff811115614d2a578283fd5b80840185601f820112614d3b578384fd5b80359150614d50614d4b83615651565b61562a565b8281528381019082850185850284018601891015614d6c578687fd5b8693505b848410156142d957614d828982614c4d565b835260019390930192918501918501614d70565b60006101c0808385031215614da9578182fd5b614db28161562a565b614dbc8585614c4d565b8152614dcb8560208601614c4d565b6020820152614ddd8560408601614c4d565b6040820152614def8560608601614c4d565b6060820152614e018560808601614c4d565b6080820152614e138560a08601614c4d565b60a0820152614e258560c08601614c4d565b60c0820152614e378560e08601614c4d565b60e08201526101009150614e4d85838601614c4d565b828201526101209150614e6285838601614c4d565b828201526101409150614e7785838601614c4d565b828201526101609150614e8c85838601614c4d565b828201526101809150614ea185838601614c4d565b828201526101a09150614eb685838601614c4d565b918101919091529392505050565b600060208284031215614ed5578081fd5b5035919050565b600060208284031215614eed578081fd5b5051919050565b600080600080600080600060e0888a031215614f0e578283fd5b873596506020880135614f208161567c565b95506040880135614f308161567c565b94506060880135614f408161567c565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a03610160811215614f7e578182fd5b8935985060208a0135614f908161567c565b975060408a0135614fa08161567c565b965060608a0135614fb08161567c565b955060808a810135955060a08b0135945060c08b0135935060df1982011215614fd7578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c0361018081121561500b578485fd5b8b359a5060208c013561501d8161567c565b995060408c013561502d8161567c565b985060608c013561503d8161567c565b975060808c810135975060a08d0135965060c08d0135955060df19820190811215615066578384fd5b615070606061562a565b9150604081121561507f578384fd5b5061508a604061562a565b60e08d01356150988161567c565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff8111156150dd578283fd5b6150e98d828e01614c58565b8194508093505050509295989b9194979a5092959850565b6000828483379101908152919050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b848152602081018490526040810183905260808101600483106151cb57fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015615206578581018301518582016040015282016151ea565b818111156152175783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252603b908201527f54726f76654d616e616765723a2043616c6c6572206973206e6f74207468652060408201527f426f72726f7765724f7065726174696f6e7320636f6e74726163740000000000606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2043616c6c646174612061646472657373206160408201527572726179206d757374206e6f7420626520656d70747960501b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526022908201527f54726f76654d616e616765723a206e6f7468696e6720746f206c697175696461604082015261746560f01b606082015260800190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b90815260200190565b918252602082015260400190565b838152602081018390526060810161559683615671565b6040830152949350505050565b858152602081018590526040810184905260a08101600584106155c257fe5b60608201939093526001600160801b03919091166080909101529392505050565b84815260208101849052604081018390526080810161560183615671565b606083015295945050505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff8111828210171561564957600080fd5b604052919050565b600067ffffffffffffffff821115615667578081fd5b5060209081020190565b80600481106110cb57fe5b6001600160a01b0381168114610fdd57600080fdfeea67486ed7ebe3eea8ab3390efd4a3c8aae48be5bea27df104a8af786c408434c3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba2646970667358221220a4c2a9a9ec603c1ba14143d02dd4e890d8f91d610315ce69bf8078c0892e8c2464736f6c634300060b0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106104c25760003560e01c8063756b253e11610278578063b0d8e1811161015c578063d293c710116100ce578063d815e8e911610092578063d815e8e91461095a578063d9a7244414610962578063e056e91814610975578063e2ac77b014610988578063f36b24251461099b578063fe2ba848146109a3576104c2565b8063d293c71014610906578063d380a37c14610919578063d3d6f84314610921578063d5b3563514610934578063d66a255314610947576104c2565b8063be4b033411610120578063be4b0334146108cb578063bf9befb1146108d3578063c35bc550146108db578063c52861f2146108e3578063c7b55481146108eb578063cbd138ae146108f3576104c2565b8063b0d8e18114610867578063b7f8cf9b1461087a578063b82f263d14610882578063b91af97c14610895578063bcd37526146108b8576104c2565b8063887105d3116101f55780639dd233d2116101b95780639dd233d2146108325780639f0706701461083a578063a20baee614610773578063a3f4df7e14610842578063ae7bec1914610857578063ae9187541461085f576104c2565b8063887105d3146107f4578063893d20e8146107fc57806396d711ff146108045780639708daf41461080c5780639976cf451461081f576104c2565b80637cf54e401161023c5780637cf54e40146107b65780637f7dde4a146107be578063807d138d146107c657806382fe3eb9146107ce57806387436936146107e1576104c2565b8063756b253e14610783578063759b303414610796578063794e57241461079e578063795d26c3146107a6578063797250e3146107ae576104c2565b80633cc74225116103aa57806361ec893d1161031c5780636b444952116102e05780636b4449521461072c5780636ef6433814610734578063716c47e61461075857806372423c171461076057806372fe25aa14610773578063741bef1a1461077b576104c2565b806361ec893d146106e3578063631203b0146106eb57806364cee260146106fe578063653d46e71461071157806366ca4a2114610724576104c2565b80634a767d681161036e5780634a767d681461067a5780634e443d9e1461068d5780635733d58f146106ad5780635d6b480f146106b55780635d8c9609146106c85780635dba4c4a146106db576104c2565b80633cc742251461063157806342ccf1e414610639578063477d66cf1461064c578063480cd5781461065f57806349eefeee14610672576104c2565b806317c62b17116104435780631f68f20a116104075780631f68f20a146105eb57806321e37801146105f35780632b11551a146106065780632f8655681461060e57806331c903b0146106215780633a12859514610629576104c2565b806317c62b171461059757806318f2817a146105aa5780631a59a50e146105bd5780631bf43555146105d05780631e8b1c2b146105d8576104c2565b806312261ee71161048a57806312261ee71461053557806312610e921461053d57806313af40351461055057806315d549f1146105635780631673c79a14610576576104c2565b806301f16e18146104c757806305b6f5ca146104dc578063071a7541146104ef5780630b0765571461050d5780630d43e8ad14610520575b600080fd5b6104da6104d5366004614d96565b6109b6565b005b6104da6104ea366004614f61565b610f1c565b6104f7610fb3565b6040516105049190615568565b60405180910390f35b6104da61051b366004614c9f565b610fb8565b610528610fe0565b604051610504919061512e565b610528610fef565b6104f761054b366004614cd7565b611013565b6104da61055e366004614c9f565b61106b565b6104f7610571366004614c9f565b6110ac565b610589610584366004614c9f565b6110d0565b604051610504929190615571565b6104f76105a5366004614c9f565b6110e9565b6104f76105b8366004614c9f565b6110f4565b6104f76105cb366004614c9f565b611107565b6104f76111cd565b6104da6105e6366004614d02565b6111da565b6104f761153b565b6104f7610601366004614c9f565b611541565b6104f761156b565b6104da61061c366004614c9f565b61157a565b6104f76115e0565b6105286115ed565b6105286115fc565b6104f7610647366004614c9f565b61160b565b6104f761065a366004614ec4565b61163c565b6104f761066d366004614c9f565b61164f565b6104f761166d565b6104f7610688366004614cd7565b611673565b6106a061069b366004614ec4565b611692565b60405161050491906151a1565b6104f761169d565b6104da6106c3366004614cd7565b61171a565b6104f76106d6366004614c9f565b611766565b6104da611771565b6104f76117dc565b6104f76106f9366004614ec4565b6117e1565b6104f761070c366004614c9f565b6117ee565b6104da61071f366004614ec4565b61180c565b6104f7611b96565b6104f7611ba8565b610747610742366004614c9f565b611bae565b6040516105049594939291906155a3565b610528611be8565b6104f761076e366004614cd7565b611bf7565b6104f7611c54565b610528611c60565b610528610791366004614ec4565b611c6f565b6104f7611c96565b6104f7611ca3565b6104f7611ce8565b6104f7611e07565b610528611e0d565b610528611e1c565b6104f7611e2b565b6104da6107dc366004614c9f565b611e31565b6104da6107ef366004614c9f565b611e42565b6104f7611ece565b610528611f9d565b6104f7611fbc565b6104da61081a366004614feb565b611fc2565b6104f761082d366004614cd7565b61205b565b6104f761208e565b610528612094565b61084a6120a3565b60405161050491906151da565b6105286120cb565b6105286120da565b6104f7610875366004614c9f565b6120e9565b610528612110565b6104f7610890366004614ec4565b61211f565b6108a86108a3366004614c9f565b61212a565b604051610504949392919061560f565b6104da6108c6366004614ef4565b61218e565b6104f7612224565b6104f761222a565b6104f7612230565b6104f7612254565b6104f7612266565b6104da610901366004614c9f565b612272565b6104f7610914366004614cd7565b612285565b6104f7612298565b6104f761092f366004614cd7565b61229e565b6104f7610942366004614ec4565b6122d4565b6104f7610955366004614c9f565b6122e7565b610528612302565b610528610970366004614ec4565b612311565b6106a0610983366004614c9f565b61233b565b6106a0610996366004614c9f565b612399565b6104f76123a4565b6104da6109b1366004614c9f565b6123b1565b6109be611f9d565b6001600160a01b0316336001600160a01b0316146109f75760405162461bcd60e51b81526004016109ee906153c5565b60405180910390fd5b8051610a02906123c2565b610a0f81602001516123c2565b610a1c81604001516123c2565b610a2981606001516123c2565b610a3681608001516123c2565b610a438160a001516123c2565b610a508160c001516123c2565b610a5d8160e001516123c2565b610a6b8161010001516123c2565b610a798161012001516123c2565b610a878161014001516123c2565b610a958161016001516123c2565b610aa38161018001516123c2565b610ab1816101a001516123c2565b8051600c80546001600160a01b03199081166001600160a01b038085169190911790925560208401516004805483169184169190911790556040808501516003805484169185169190911790556060850151600580548416918516919091179055608085015160008054841691851691909117905560a085015160018054841691851691909117905560c085015160068054841691851691909117905560e0850151600780548416918516919091179055610100850151600880548416918516919091179055610120850151600280548416918516919091179055610140850151600980548416918516919091179055610160850151600d80548416918516919091179055610180850151600a805484169185169190911790556101a0850151600b80549093169316929092179055517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db991610c0c9161512e565b60405180910390a17f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b18160200151604051610c47919061512e565b60405180910390a17fbf65195e6d5213f6fcbce65b1454c925197a45e616dabd2e243542b039b050928160600151604051610c82919061512e565b60405180910390a17f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed9858160600151604051610cbd919061512e565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828160800151604051610cf8919061512e565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b8160a00151604051610d33919061512e565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f8160c00151604051610d6e919061512e565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa08160e00151604051610da9919061512e565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d816101000151604051610de5919061512e565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264816101200151604051610e21919061512e565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d816101400151604051610e5d919061512e565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800816101600151604051610e99919061512e565b60405180910390a17f61e0c29d5028a9e4facaa476a46e78912e99f1ba945c9560b86b82ebe36ee52d816101800151604051610ed5919061512e565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd816101a00151604051610f11919061512e565b60405180910390a150565b6004546040516000916060916001600160a01b0390911690610f419084903690615101565b600060405180830381855af49150503d8060008114610f7c576040519150601f19603f3d011682016040523d82523d6000602084013e610f81565b606091505b5091509150818190610fa65760405162461bcd60e51b81526004016109ee91906151da565b5050505050505050505050565b600281565b610fc0612407565b600054600154610fdd916001600160a01b03908116911683612433565b50565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061101d612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff61254516565b6001600160a01b03851660009081526010602052604090208190559150505b92915050565b611073611f9d565b6001600160a01b0316336001600160a01b0316146110a35760405162461bcd60e51b81526004016109ee906153c5565b610fdd81612587565b60006110b6612407565b6110bf82612612565b6001600160801b031690505b919050565b6016602052600090815260409020805460019091015482565b60006110658261160b565b60006110fe612407565b611065826126ac565b6001600160a01b0381166000908152601660205260408120546014548290611135908363ffffffff61254516565b905080158061116e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561116b57fe5b14155b1561117e576000925050506110cb565b6001600160a01b038416600090815260106020526040812060020154906111c3670de0b6b3a76400006111b7848663ffffffff61275f16565b9063ffffffff61279916565b9695505050505050565b6809c2007651b250000081565b80516111f85760405162461bcd60e51b81526004016109ee906153f6565b6000546001546006546001600160a01b0392831692918216911661121a614b2b565b611222614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ec57600080fd5b505afa158015611300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113249190614edc565b60208301528151611334906127db565b158015604084015261135c576113558585846000015185602001518a612876565b9050611374565b6113718585846000015185602001518a612b8b565b90505b60008160200151116113985760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad926113cc92600401615571565b600060405180830381600087803b1580156113e657600080fd5b505af11580156113fa573d6000803e3d6000fd5b5050505061141285858360c001518460e00151612ccb565b61010081015115611489576008546101008201516040516364a197f360e01b81526001600160a01b03888116936364a197f393611456939290911691600401615188565b600060405180830381600087803b15801561147057600080fd5b505af1158015611484573d6000803e3d6000fd5b505050505b611497858260400151612f2f565b60208101516060830152610100810151604082015182516114cf92916114c3919063ffffffff61254516565b9063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611517949092909161560f565b60405180910390a1611533853383606001518460400151613090565b505050505050565b600e5481565b6001600160a01b03811660009081526010602052604081206003015460ff16600481111561106557fe5b60006115756115e0565b905090565b6115838161316d565b6040805160018082528183019092526060916020808301908036833701905050905081816000815181106115b357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506115dc816111da565b5050565b6000611575600e546131b6565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290611135908363ffffffff61254516565b6000611065611649611b96565b83613253565b6001600160a01b031660009081526010602052604090206001015490565b60175490565b600080600061168185613271565b9150915060006111c38383876132f7565b6000611065826127db565b60035460408051635733d58f60e01b815290516000926001600160a01b031691635733d58f916004808301926020929190829003018186803b1580156116e257600080fd5b505afa1580156116f6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115759190614edc565b611722612407565b80600481111561172e57fe5b6001600160a01b0383166000908152601060205260409020600301805460ff1916600183600481111561175d57fe5b02179055505050565b600061106582611107565b611779612407565b6000611783613329565b9050670de0b6b3a764000081111561179757fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c906117cc908390615568565b60405180910390a1610fdd61336d565b603c81565b60006110656116496123a4565b6001600160a01b031660009081526010602052604090206002015490565b611814614ba8565b506040805160e081018252600080546001600160a01b0390811683526001548116602084015292820181905260608201819052600d548316608083015260a0820181905260c082015260065490911661186b614b2b565b611873614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fb9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b15801561193d57600080fd5b505afa158015611951573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119759190614edc565b60208301528151611985906127db565b15801560408401526119ac576119a58483600001518460200151886133c2565b90506119cc565b6119c9846000015185602001518460000151856020015189613869565b90505b60008160200151116119f05760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad92611a2492600401615571565b600060405180830381600087803b158015611a3e57600080fd5b505af1158015611a52573d6000803e3d6000fd5b50505050611a72846000015185602001518360c001518460e00151612ccb565b61010081015115611ae95783516008546101008301516040516364a197f360e01b81526001600160a01b03938416936364a197f393611ab693911691600401615188565b600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050505b611afb84600001518260400151612f2f565b6020810151606083015261010081015160408201518251611b2792916114c3919063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611b6f949092909161560f565b60405180910390a1611b8f84600001513383606001518460400151613090565b5050505050565b6000611575611ba3613329565b613a1f565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b6000611c01612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff613b0116565b6001600160a01b038516600090815260106020526040902060010181905591505092915050565b670de0b6b3a764000081565b6002546001600160a01b031681565b60178181548110611c7c57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60035460408051631e5395c960e21b815290516000926001600160a01b03169163794e5724916004808301926020929190829003018186803b1580156116e257600080fd5b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015611d2c57600080fd5b505afa158015611d40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d649190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b505afa158015611dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dee9190614edc565b9050611e00828263ffffffff613b0116565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b611e39612407565b610fdd81613b26565b611e4a611f9d565b6001600160a01b0316336001600160a01b031614611e7a5760405162461bcd60e51b81526004016109ee906153c5565b611e83816123c2565b600480546001600160a01b0319166001600160a01b0383161790556040517f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b190610f1190839061512e565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b158015611f1357600080fd5b505afa158015611f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4b9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b600080604051611fac90615111565b6040519081900390205492915050565b60135481565b6004546040516000916060916001600160a01b0390911690611fe79084903690615101565b600060405180830381855af49150503d8060008114612022576040519150601f19603f3d011682016040523d82523d6000602084013e612027565b606091505b509150915081819061204c5760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050505050565b6000612065612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff613b0116565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b60008060006120f784613271565b9150915060006121078383613b83565b95945050505050565b6005546001600160a01b031681565b600061106582613bb8565b6001600160a01b03811660009081526010602052604081208054600190910154909180612156856110e9565b915061216185611766565b9050612173848363ffffffff613b0116565b9350612185838263ffffffff613b0116565b92509193509193565b6004546040516000916060916001600160a01b03909116906121b39084903690615101565b600060405180830381855af49150503d80600081146121ee576040519150601f19603f3d011682016040523d82523d6000602084013e6121f3565b606091505b50915091508181906122185760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000611575612261613329565b6131b6565b670ddd4b8c6c7d70d881565b61227a612407565b610fdd816002613be4565b60006122918383611673565b9392505050565b600f5481565b60006122a8612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff61254516565b60006110656122e1612254565b83613cf9565b6001600160a01b031660009081526010602052604090205490565b6009546001600160a01b031681565b60006017828154811061232057fe5b6000918252602090912001546001600160a01b031692915050565b600060016001600160a01b03831660009081526010602052604090206003015460ff16600481111561236957fe5b14612376575060006110cb565b506014546001600160a01b03821660009081526016602052604090205410919050565b60006110658261233b565b6000611575600e54613a1f565b6123b9612407565b610fdd81613d39565b6001600160a01b0381166123e85760405162461bcd60e51b81526004016109ee906152a6565b803b806115dc5760405162461bcd60e51b81526004016109ee9061544c565b6005546001600160a01b031633146124315760405162461bcd60e51b81526004016109ee90615368565b565b61243c8161233b565b156125405761244a8161316d565b600061245582611107565b905060006124628361160b565b6001600160a01b038416600090815260106020526040902060010154909150612491908363ffffffff613b0116565b6001600160a01b03841660009081526010602052604090206001810191909155546124c2908263ffffffff613b0116565b6001600160a01b0384166000908152601060205260409020556124e483613b26565b6124f085858385613d89565b6001600160a01b0383166000818152601060205260408082208054600182015460029092015492516000805160206156b28339815191529461253594929392916155e3565b60405180910390a250505b505050565b600061229183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613e71565b6001600160a01b0381166125ad5760405162461bcd60e51b81526004016109ee90615264565b806001600160a01b03166125bf611f9d565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600060405161260290615111565b6040519081900390209190915550565b601780546001808201835560008381527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1590920180546001600160a01b0319166001600160a01b0386161790559154909161266d9190612545565b6001600160a01b039290921660009081526010602052604090206003018054610100600160881b0319166101006001600160801b038516021790555090565b6001600160a01b03811660009081526010602052604081206001015481906126d390613e9d565b6001600160a01b03841660009081526010602052604090206002018054908290556011549192509061271d908390612711908463ffffffff61254516565b9063ffffffff613b0116565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829161275091615568565b60405180910390a15092915050565b60008261276e57506000611065565b8282028284828161277b57fe5b04146122915760405162461bcd60e51b81526004016109ee90615327565b600061229183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ed9565b6000806127e783613bb8565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561283757600080fd5b505afa15801561284b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286f9190614edc565b1192915050565b61287e614b5c565b612886614be4565b61288e614b5c565b848252600060808301526128a0611ce8565b60a08301526128ad611ece565b60c0830152600060208301525b835182602001511015612b8057838260200151815181106128d757fe5b6020908102919091018101516001600160a01b03166060840181905260009081526010909152604090206003015460019060ff16600481111561291657fe5b1461292057612b70565b61292e826060015187611673565b60408301526080820151612a9557600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561298a57600080fd5b505afa15801561299e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c29190614edc565b8260400151101580156129d457508151155b156129de57612b70565b60006129f38360c001518460a00151896132f7565b9050612a108989856060015186604001518760000151868d613f10565b60808101518451919350612a2a919063ffffffff61254516565b8352608082015160a0840151612a459163ffffffff61254516565b60a08085019190915282015160c0840151612a659163ffffffff61254516565b60c0840152612a7484836142e6565b9350612a898360c001518460a00151896143fd565b15608084015250612b70565b81608001518015612b2e5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015612aef57600080fd5b505afa158015612b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b279190614edc565b8260400151105b15612b7057612b4788888460600151856000015161449c565b60808101518351919250612b61919063ffffffff61254516565b8252612b6d83826142e6565b92505b60208201805160010190526128ba565b505095945050505050565b612b93614b5c565b612b9b614be4565b612ba3614b5c565b848252600060208301525b835182602001511015612b805783826020015181518110612bcb57fe5b60209081029190910101516001600160a01b031660608301819052612bf09087611673565b6040808401919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c739190614edc565b82604001511015612cbb57612c9288888460600151856000015161449c565b60808101518351919250612cac919063ffffffff61254516565b8252612cb883826142e6565b92505b6020820180516001019052612bae565b81612cd557612f29565b601854600090612cf79061271184670de0b6b3a764000063ffffffff61275f16565b90506000612d1c601954612711670de0b6b3a76400008761275f90919063ffffffff16565b90506000612d356011548461279990919063ffffffff16565b90506000612d4e6011548461279990919063ffffffff16565b9050612d75612d686011548461275f90919063ffffffff16565b859063ffffffff61254516565b601855601154612d9d90612d9090839063ffffffff61275f16565b849063ffffffff61254516565b601955601454612db3908363ffffffff613b0116565b601455601554612dc9908263ffffffff613b0116565b60158190556014546040517f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e392612e009291615571565b60405180910390a160405163121cbc4d60e11b81526001600160a01b03891690632439789a90612e34908990600401615568565b600060405180830381600087803b158015612e4e57600080fd5b505af1158015612e62573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038a16925063f2e91d719150612e92908990600401615568565b600060405180830381600087803b158015612eac57600080fd5b505af1158015612ec0573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b038b1692506364a197f39150612ef2908a908990600401615188565b600060405180830381600087803b158015612f0c57600080fd5b505af1158015612f20573d6000803e3d6000fd5b50505050505050505b50505050565b6011546012819055506000826001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7357600080fd5b505afa158015612f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fab9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ffd57600080fd5b505afa158015613011573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130359190614edc565b905061304b81612711848663ffffffff61254516565b60138190556012546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf60926130829291615571565b60405180910390a150505050565b811561310157600954600754604051631062c15f60e11b81526001600160a01b03928316926320c582be926130ce9291169087908790600401615142565b600060405180830381600087803b1580156130e857600080fd5b505af11580156130fc573d6000803e3d6000fd5b505050505b8015612f29576040516364a197f360e01b81526001600160a01b038516906364a197f3906131359086908590600401615188565b600060405180830381600087803b15801561314f57600080fd5b505af1158015613163573d6000803e3d6000fd5b5050505050505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561319957fe5b14610fdd5760405162461bcd60e51b81526004016109ee90615519565b600061106561324583600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b505afa158015613221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127119190614edc565b670de0b6b3a76400006145ce565b6000612291670de0b6b3a76400006111b7858563ffffffff61275f16565b600080600061327f84611107565b9050600061328c8561160b565b6001600160a01b038616600090815260106020526040812060010154919250906132bc908463ffffffff613b0116565b6001600160a01b038716600090815260106020526040812054919250906132e9908463ffffffff613b0116565b919550909350505050915091565b6000821561331e576000613315846111b7878663ffffffff61275f16565b91506122919050565b506000199392505050565b6000806133346145e4565b9050600061334a670ddd4b8c6c7d70d883614600565b9050611e00670de0b6b3a76400006111b783600e5461275f90919063ffffffff16565b6000613384600f544261254590919063ffffffff16565b9050603c8110610fdd5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc91610f1191615568565b6133ca614b5c565b6133d2614be4565b6133da614b5c565b848252600060808301526133ec611ce8565b60a08301526133f9611ece565b8260c001818152505086608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561343f57600080fd5b505afa158015613453573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134779190614cbb565b82606001906001600160a01b031690816001600160a01b031681525050600087608001516001600160a01b0316631e2231436040518163ffffffff1660e01b815260040160206040518083038186803b1580156134d357600080fd5b505afa1580156134e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350b9190614cbb565b6000602085015290505b84836020015110801561353e5750806001600160a01b031683606001516001600160a01b031614155b1561385e5760808801516060840151604051632dc9c0eb60e21b81526000926001600160a01b03169163b72703ac9161357a919060040161512e565b60206040518083038186803b15801561359257600080fd5b505afa1580156135a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ca9190614cbb565b90506135da846060015189611673565b6040850152608084015161375357600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561363657600080fd5b505afa15801561364a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061366e9190614edc565b84604001511015801561368057508351155b1561368b575061385e565b60006136a08560c001518660a001518b6132f7565b8a5160208c01516060880151604089015189519495506136c194868f613f10565b608081015186519195506136db919063ffffffff61254516565b8552608084015160a08601516136f69163ffffffff61254516565b8560a00181815250506137238461010001516114c38660a001518860c0015161254590919063ffffffff16565b60c086015261373286856142e6565b95506137478560c001518660a001518b6143fd565b15608086015250613840565b836080015180156137ec5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156137ad57600080fd5b505afa1580156137c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e59190614edc565b8460400151105b1561383a5761380d89600001518a602001518660600151876000015161449c565b60808101518551919450613827919063ffffffff61254516565b845261383385846142e6565b9450613840565b5061385e565b6001600160a01b031660608401526020830180516001019052613515565b505050949350505050565b613871614b5c565b613879614be4565b613881614b5c565b600d54858352600060208401526001600160a01b03165b8483602001511015613a1357806001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156138dd57600080fd5b505afa1580156138f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139159190614cbb565b6001600160a01b03166060840181905261392f9088611673565b6040808501919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b15801561397a57600080fd5b505afa15801561398e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b29190614edc565b836040015110156139fe576139d189898560600151866000015161449c565b608081015184519193506139eb919063ffffffff61254516565b83526139f784836142e6565b9350613a03565b613a13565b6020830180516001019052613898565b50505095945050505050565b6000611065613a7683600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b031663240926696040518163ffffffff1660e01b815260040160206040518083038186803b158015613ac457600080fd5b505afa158015613ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613afc9190614edc565b6145ce565b6000828201838110156122915760405162461bcd60e51b81526004016109ee9061522d565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92610f11929091615571565b60008115613baf57613ba8826111b78568056bc75e2d6310000063ffffffff61275f16565b9050611065565b50600019611065565b600080613bc3611ece565b90506000613bcf611ce8565b9050613bdc8282866132f7565b949350505050565b6000816004811115613bf257fe5b14158015613c0c57506001816004811115613c0957fe5b14155b613c1257fe5b601754613c1e816146ab565b6001600160a01b0383166000908152601060205260409020600301805483919060ff19166001836004811115613c5057fe5b02179055506001600160a01b0383166000908152601060209081526040808320600180820185905590849055601690925282208281550155613c928382614751565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e90613cc290869060040161512e565b600060405180830381600087803b158015613cdc57600080fd5b505af1158015613cf0573d6000803e3d6000fd5b50505050505050565b600080613d18670de0b6b3a76400006111b7868663ffffffff61275f16565b90508281106122915760405162461bcd60e51b81526004016109ee90615481565b6001600160a01b038116600090815260106020526040902060020154601154613d68908263ffffffff61254516565b601155506001600160a01b0316600090815260106020526040812060020155565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a90613db5908590600401615568565b600060405180830381600087803b158015613dcf57600080fd5b505af1158015613de3573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150613e13908590600401615568565b600060405180830381600087803b158015613e2d57600080fd5b505af1158015613e41573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150613135908490600401615568565b60008184841115613e955760405162461bcd60e51b81526004016109ee91906151da565b505050900390565b60008060135460001415613eb2575081611065565b600060125411613ebe57fe5b6122916013546111b76012548661275f90919063ffffffff16565b60008183613efa5760405162461bcd60e51b81526004016109ee91906151da565b506000838581613f0657fe5b0495945050505050565b613f18614b5c565b613f20614c2c565b601754600110613f3057506142db565b613f398761212a565b60408501526020848101919091528401819052908352613f58906148f2565b604083018190526801158e460913d0000060608401526020830151613f829163ffffffff61254516565b8152670de0b6b3a7640000861161404d57613fa7898983602001518460400151613d89565b613fb087613d39565b60006080830181905260a0830152815160c0830152805160e0830152613fd7876003613be4565b815160208301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b60405180910390a2866001600160a01b03166000805160206156b28339815191526000806000600260405161404094939291906151ac565b60405180910390a26142d9565b670de0b6b3a7640000861180156140e85750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156140ad57600080fd5b505afa1580156140c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e59190614edc565b86105b1561413857614101898983602001518460400151613d89565b61410a87613d39565b8151815161411991908761497e565b60e086015260c085015260a08401526080830152613fd7876003613be4565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561418657600080fd5b505afa15801561419a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141be9190614edc565b86101580156141cc57508386105b80156141d9575081518510155b156142c8576141f2898983602001518460400151613d89565b846141f957fe5b61420287613d39565b61421582600001518360200151856149ea565b9150614222876003613be4565b6101008201511561429757600854610100830151604051633f10abab60e01b81526001600160a01b0390921691633f10abab91614264918b9190600401615188565b600060405180830381600087803b15801561427e57600080fd5b505af1158015614292573d6000803e3d6000fd5b505050505b815160a08301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b6142d0614b5c565b91506142db9050565b505b979650505050505050565b6142ee614b5c565b604080830151908401516143079163ffffffff613b0116565b6040820152606080830151908401516143259163ffffffff613b0116565b6060820152815160208401516143409163ffffffff613b0116565b602080830191909152820151835161435d9163ffffffff613b0116565b8152608080830151908401516143789163ffffffff613b0116565b608082015260a080830151908401516143969163ffffffff613b0116565b60a082015260c080830151908401516143b49163ffffffff613b0116565b60c082015260e080830151908401516143d29163ffffffff613b0116565b60e082015261010080830151908401516143f19163ffffffff613b0116565b61010082015292915050565b60008061440b8585856132f7565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561445b57600080fd5b505afa15801561446f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144939190614edc565b11949350505050565b6144a4614b5c565b6144ac614c2c565b6144b58461212a565b604085019081526020858101928352860192909252918452905190516144df918891889190613d89565b6144e884613d39565b6144f582602001516148f2565b604083018190526801158e460913d0000060608401526020830151600091614523919063ffffffff61254516565b90506145348360000151828661497e565b60e087015260c086015260a08501526080840152614553856003613be4565b825160208401516040516001600160a01b03881692600080516020615692833981519152926145849260019061557f565b60405180910390a2846001600160a01b03166000805160206156b2833981519152600080600060016040516145bc94939291906151ac565b60405180910390a25050949350505050565b60008183106145dd5781612291565b5090919050565b6000611575603c6111b7600f544261254590919063ffffffff16565b6000631f54050082111561461657631f54050091505b8161462a5750670de0b6b3a7640000611065565b670de0b6b3a764000083835b60018111156146a1576002810661466b576146518283614af8565b915061466481600263ffffffff61279916565b905061469c565b6146758284614af8565b92506146818283614af8565b915061469960026111b783600163ffffffff61254516565b90505b614636565b6111c38284614af8565b6001811180156147355750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b1580156146fb57600080fd5b505afa15801561470f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147339190614edc565b115b610fdd5760405162461bcd60e51b81526004016109ee906152dd565b6001600160a01b03821660009081526010602052604081206003015460ff169081600481111561477d57fe5b141580156147975750600181600481111561479457fe5b14155b61479d57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b03169083906147d5826001612545565b905080836001600160801b031611156147ea57fe5b6000601782815481106147f957fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b03871690811061482b57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a906148b49083908790615166565b60405180910390a160178054806148c757fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b600354604080516324386ecd60e11b815290516000926001600160a01b031691634870dd9a916004808301926020929190829003018186803b15801561493757600080fd5b505afa15801561494b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496f9190614edc565b828161497757fe5b0492915050565b600080808084156149d45761499387866145ce565b93506149a9876111b7888763ffffffff61275f16565b92506149bb878563ffffffff61254516565b91506149cd868463ffffffff61254516565b90506149e1565b5060009250829150859050845b93509350935093565b6149f2614b5c565b838152602080820184905260035460408051631e5395c960e21b81529051600093614a8e9387936111b7936001600160a01b039092169263794e572492600480840193829003018186803b158015614a4957600080fd5b505afa158015614a5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a819190614edc565b889063ffffffff61275f16565b9050614a99816148f2565b604083018190526801158e460913d00000606084015260808301869052614ac790829063ffffffff61254516565b60a0830152614adc848263ffffffff61254516565b61010083015250600060c0820181905260e08201529392505050565b600080614b0b848463ffffffff61275f16565b9050613bdc670de0b6b3a76400006111b7836706f05b59d3b20000613b01565b6040518060a00160405280600081526020016000815260200160001515815260200160008152602001600081525090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040518060e0016040528060008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b80356110658161567c565b60008083601f840112614c69578081fd5b50813567ffffffffffffffff811115614c80578182fd5b602083019150836020828501011115614c9857600080fd5b9250929050565b600060208284031215614cb0578081fd5b81356122918161567c565b600060208284031215614ccc578081fd5b81516122918161567c565b60008060408385031215614ce9578081fd5b8235614cf48161567c565b946020939093013593505050565b60006020808385031215614d14578182fd5b823567ffffffffffffffff811115614d2a578283fd5b80840185601f820112614d3b578384fd5b80359150614d50614d4b83615651565b61562a565b8281528381019082850185850284018601891015614d6c578687fd5b8693505b848410156142d957614d828982614c4d565b835260019390930192918501918501614d70565b60006101c0808385031215614da9578182fd5b614db28161562a565b614dbc8585614c4d565b8152614dcb8560208601614c4d565b6020820152614ddd8560408601614c4d565b6040820152614def8560608601614c4d565b6060820152614e018560808601614c4d565b6080820152614e138560a08601614c4d565b60a0820152614e258560c08601614c4d565b60c0820152614e378560e08601614c4d565b60e08201526101009150614e4d85838601614c4d565b828201526101209150614e6285838601614c4d565b828201526101409150614e7785838601614c4d565b828201526101609150614e8c85838601614c4d565b828201526101809150614ea185838601614c4d565b828201526101a09150614eb685838601614c4d565b918101919091529392505050565b600060208284031215614ed5578081fd5b5035919050565b600060208284031215614eed578081fd5b5051919050565b600080600080600080600060e0888a031215614f0e578283fd5b873596506020880135614f208161567c565b95506040880135614f308161567c565b94506060880135614f408161567c565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a03610160811215614f7e578182fd5b8935985060208a0135614f908161567c565b975060408a0135614fa08161567c565b965060608a0135614fb08161567c565b955060808a810135955060a08b0135945060c08b0135935060df1982011215614fd7578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c0361018081121561500b578485fd5b8b359a5060208c013561501d8161567c565b995060408c013561502d8161567c565b985060608c013561503d8161567c565b975060808c810135975060a08d0135965060c08d0135955060df19820190811215615066578384fd5b615070606061562a565b9150604081121561507f578384fd5b5061508a604061562a565b60e08d01356150988161567c565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff8111156150dd578283fd5b6150e98d828e01614c58565b8194508093505050509295989b9194979a5092959850565b6000828483379101908152919050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b848152602081018490526040810183905260808101600483106151cb57fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015615206578581018301518582016040015282016151ea565b818111156152175783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252603b908201527f54726f76654d616e616765723a2043616c6c6572206973206e6f74207468652060408201527f426f72726f7765724f7065726174696f6e7320636f6e74726163740000000000606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2043616c6c646174612061646472657373206160408201527572726179206d757374206e6f7420626520656d70747960501b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526022908201527f54726f76654d616e616765723a206e6f7468696e6720746f206c697175696461604082015261746560f01b606082015260800190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b90815260200190565b918252602082015260400190565b838152602081018390526060810161559683615671565b6040830152949350505050565b858152602081018590526040810184905260a08101600584106155c257fe5b60608201939093526001600160801b03919091166080909101529392505050565b84815260208101849052604081018390526080810161560183615671565b606083015295945050505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff8111828210171561564957600080fd5b604052919050565b600067ffffffffffffffff821115615667578081fd5b5060209081020190565b80600481106110cb57fe5b6001600160a01b0381168114610fdd57600080fdfeea67486ed7ebe3eea8ab3390efd4a3c8aae48be5bea27df104a8af786c408434c3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba2646970667358221220a4c2a9a9ec603c1ba14143d02dd4e890d8f91d610315ce69bf8078c0892e8c2464736f6c634300060b0033", + "implementation": "0xdC03c72c1730b149E3178624FD4d9Bf51501A6E0" +} diff --git a/external/deployments/rskMainnet/TroveManagerRedeemOps.json b/external/deployments/rskMainnet/TroveManagerRedeemOps.json new file mode 100644 index 000000000..678703ef4 --- /dev/null +++ b/external/deployments/rskMainnet/TroveManagerRedeemOps.json @@ -0,0 +1,1587 @@ +{ + "address": "0xa4161D23002e110b3d5C430EfAfF299415074c67", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_bootstrapPeriod", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_baseRate", + "type": "uint256" + } + ], + "name": "BaseRateUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "LTermsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_lastFeeOpTime", + "type": "uint256" + } + ], + "name": "LastFeeOpTimeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedDebt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedColl", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_collGasCompensation", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDGasCompensation", + "type": "uint256" + } + ], + "name": "Liquidation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_attemptedZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_actualZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHSent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHFee", + "type": "uint256" + } + ], + "name": "Redemption", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_totalStakesSnapshot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalCollateralSnapshot", + "type": "uint256" + } + ], + "name": "SystemSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newTotalStakes", + "type": "uint256" + } + ], + "name": "TotalStakesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newIndex", + "type": "uint256" + } + ], + "name": "TroveIndexUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum TroveManagerBase.TroveManagerOperation", + "name": "_operation", + "type": "uint8" + } + ], + "name": "TroveLiquidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "TroveSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_stake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum TroveManagerBase.TroveManagerOperation", + "name": "_operation", + "type": "uint8" + } + ], + "name": "TroveUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "BETA", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BOOTSTRAP_PERIOD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ETH", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ZUSDDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINUTE_DECAY_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SECONDS_IN_ONE_MINUTE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "TroveOwners", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "Troves", + "outputs": [ + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coll", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "internalType": "enum TroveManagerStorage.Status", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "arrayIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "_getCurrentICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingETHReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingZUSDDebtReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_getRedemptionRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_hasPendingRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_stabilityPool", + "outputs": [ + { + "internalType": "contract IStabilityPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroStaking", + "outputs": [ + { + "internalType": "contract IZEROStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroToken", + "outputs": [ + { + "internalType": "contract IZEROToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "borrowerOperationsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeDistributor", + "outputs": [ + { + "internalType": "contract IFeeDistributor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastETHError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFeeOperationTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastZUSDDebtError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDamount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + } + ], + "name": "redeemCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "redeemCollateralViaDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "redeemCollateralViaDllrWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "rewardSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "ETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ZUSDDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalCollateralSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakesSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManagerRedeemOps", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xa204ada1c6efe89dd25c0bcafa2150b377068ec91f2be2124ca46bade37b35fb", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0x5835205e52C6e23c2E7D74F2117538fA8bC3Fc0B", + "transactionIndex": 0, + "gasUsed": "4195652", + "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000001010000000000000000000000000000008000020000000000000000001800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xac4b5fe40db4d9eed4c31111782207da277eb3022a8d4c3252f9a4906681a64c", + "transactionHash": "0xa204ada1c6efe89dd25c0bcafa2150b377068ec91f2be2124ca46bade37b35fb", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748983, + "transactionHash": "0xa204ada1c6efe89dd25c0bcafa2150b377068ec91f2be2124ca46bade37b35fb", + "address": "0x5835205e52C6e23c2E7D74F2117538fA8bC3Fc0B", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0xac4b5fe40db4d9eed4c31111782207da277eb3022a8d4c3252f9a4906681a64c" + } + ], + "blockNumber": 4748983, + "cumulativeGasUsed": "4195652", + "status": 1, + "byzantium": true + }, + "args": ["1209600", "0x000000000022d473030f116ddee9f6b43ac78ba3"], + "numDeployments": 3, + "solcInputHash": "849fadfa265e27de6fba2f2d99bdf763", + "metadata": "{\"compiler\":{\"version\":\"0.6.11+commit.5ef660b1\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_bootstrapPeriod\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_permit2\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_baseRate\",\"type\":\"uint256\"}],\"name\":\"BaseRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ETH\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"LTermsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_lastFeeOpTime\",\"type\":\"uint256\"}],\"name\":\"LastFeeOpTimeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_liquidatedDebt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_liquidatedColl\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_collGasCompensation\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ZUSDGasCompensation\",\"type\":\"uint256\"}],\"name\":\"Liquidation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_attemptedZUSDAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_actualZUSDAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ETHSent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ETHFee\",\"type\":\"uint256\"}],\"name\":\"Redemption\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalStakesSnapshot\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalCollateralSnapshot\",\"type\":\"uint256\"}],\"name\":\"SystemSnapshotsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newTotalStakes\",\"type\":\"uint256\"}],\"name\":\"TotalStakesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newIndex\",\"type\":\"uint256\"}],\"name\":\"TroveIndexUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_coll\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"enum TroveManagerBase.TroveManagerOperation\",\"name\":\"_operation\",\"type\":\"uint8\"}],\"name\":\"TroveLiquidated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ETH\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"TroveSnapshotsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_coll\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_stake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"enum TroveManagerBase.TroveManagerOperation\",\"name\":\"_operation\",\"type\":\"uint8\"}],\"name\":\"TroveUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BETA\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"BOOTSTRAP_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DECIMAL_PRECISION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L_ETH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L_ZUSDDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MINUTE_DECAY_FACTOR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_NET_DEBT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SECONDS_IN_ONE_MINUTE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"TroveOwners\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"Troves\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"debt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"coll\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"enum TroveManagerStorage.Status\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint128\",\"name\":\"arrayIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZUSD_GAS_COMPENSATION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_100pct\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_price\",\"type\":\"uint256\"}],\"name\":\"_getCurrentICR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_getPendingETHReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_getPendingZUSDDebtReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_getRedemptionRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_hasPendingRewards\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_stabilityPool\",\"outputs\":[{\"internalType\":\"contract IStabilityPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zeroStaking\",\"outputs\":[{\"internalType\":\"contract IZEROStaking\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zeroToken\",\"outputs\":[{\"internalType\":\"contract IZEROToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zusdToken\",\"outputs\":[{\"internalType\":\"contract IZUSDToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activePool\",\"outputs\":[{\"internalType\":\"contract IActivePool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"borrowerOperationsAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultPool\",\"outputs\":[{\"internalType\":\"contract IDefaultPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeDistributor\",\"outputs\":[{\"internalType\":\"contract IFeeDistributor\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemColl\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastETHError_Redistribution\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFeeOperationTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastZUSDDebtError_Redistribution\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquityBaseParams\",\"outputs\":[{\"internalType\":\"contract ILiquityBaseParams\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceFeed\",\"outputs\":[{\"internalType\":\"contract IPriceFeed\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ZUSDamount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"}],\"name\":\"redeemCollateral\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"redeemCollateralViaDLLR\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"redeemCollateralViaDllrWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"rewardSnapshots\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"ETH\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"ZUSDDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortedTroves\",\"outputs\":[{\"internalType\":\"contract ISortedTroves\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalCollateralSnapshot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalStakesSnapshot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"troveManagerRedeemOps\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getOwner()\":{\"returns\":{\"_owner\":\"Address of the owner. \"}},\"setOwner(address)\":{\"params\":{\"_owner\":\"Address of the owner. \"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BETA()\":{\"notice\":\"BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption. Corresponds to (1 / ALPHA) in the white paper.\"},\"BOOTSTRAP_PERIOD()\":{\"notice\":\"During bootsrap period redemptions are not allowed\"},\"MIN_NET_DEBT()\":{\"notice\":\"Minimum amount of net ZUSD debt a trove must have\"},\"ZUSD_GAS_COMPENSATION()\":{\"notice\":\"Amount of ZUSD to be locked in gas pool on opening troves\"},\"_getCurrentICR(address,uint256)\":{\"notice\":\"Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\"},\"_getPendingETHReward(address)\":{\"notice\":\"Get the borrower's pending accumulated ETH reward, earned by their stake\"},\"_getPendingZUSDDebtReward(address)\":{\"notice\":\"Get the borrower's pending accumulated ZUSD reward, earned by their stake\"},\"constructor\":\"Constructor \",\"getOwner()\":{\"notice\":\"Return address of the owner.\"},\"permit2()\":{\"notice\":\"CONSTANT / IMMUTABLE VARIABLE ONLY \"},\"redeemCollateralViaDLLR(uint256,address,address,address,uint256,uint256,uint256,(uint256,uint8,bytes32,bytes32))\":{\"notice\":\"DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\"},\"redeemCollateralViaDllrWithPermit2(uint256,address,address,address,uint256,uint256,uint256,((address,uint256),uint256,uint256),bytes)\":{\"notice\":\"DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\"},\"setOwner(address)\":{\"notice\":\"Set address of the owner (only owner can call this function)\"}},\"notice\":\"This contract is designed to be used via delegatecall from the TroveManager contract TroveManagerBase constructor param is bootsrap period when redemptions are not allowed\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Dependencies/TroveManagerRedeemOps.sol\":\"TroveManagerRedeemOps\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"contracts/Dependencies/BaseMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\n\\ncontract BaseMath {\\n uint constant public DECIMAL_PRECISION = 1e18;\\n}\\n\",\"keccak256\":\"0x7e1369ca5cb09e818e345a2def19a261401f79c985a6030b55b7311dd6f53be4\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on the OpenZeppelin IER20 interface:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol\\n *\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\\n function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n function name() external view returns (string memory);\\n function symbol() external view returns (string memory);\\n function decimals() external view returns (uint8);\\n \\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\",\"keccak256\":\"0xe0b2473eba89df8d27d7cea2a99fce788c212f3fd393c9508e449e51a3f220fa\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC2612.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * @dev Interface of the ERC2612 standard as defined in the EIP.\\n *\\n * Adds the {permit} method, which can be used to change one's\\n * {IERC20-allowance} without having to send a transaction, by signing a\\n * message. This allows users to spend tokens without having to hold Ether.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2612.\\n * \\n * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/\\n */\\ninterface IERC2612 {\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,\\n * given `owner`'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(address owner, address spender, uint256 amount, \\n uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;\\n \\n /**\\n * @dev Returns the current ERC2612 nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases `owner`'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n *\\n * `owner` can limit the time a Permit is valid for by setting `deadline` to \\n * a value in the near future. The deadline argument can be set to uint(-1) to \\n * create Permits that effectively never expire.\\n */\\n function nonces(address owner) external view returns (uint256);\\n \\n function version() external view returns (string memory);\\n function permitTypeHash() external view returns (bytes32);\\n function domainSeparator() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xd376458452f8b480bfea549637bd71d3f9eb1f12e9d59d1beff373417462d67f\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./BaseMath.sol\\\";\\nimport \\\"./LiquityMath.sol\\\";\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IPriceFeed.sol\\\";\\nimport \\\"../Interfaces/ILiquityBase.sol\\\";\\nimport \\\"../Interfaces/ILiquityBaseParams.sol\\\";\\n\\n/**\\n * Base contract for TroveManager, BorrowerOperations and StabilityPool. Contains global system constants and\\n * common functions.\\n */\\ncontract LiquityBase is BaseMath, ILiquityBase {\\n using SafeMath for uint256;\\n\\n uint256 public constant _100pct = 1000000000000000000; // 1e18 == 100%\\n\\n /// Amount of ZUSD to be locked in gas pool on opening troves\\n uint256 public constant ZUSD_GAS_COMPENSATION = 20e18;\\n\\n /// Minimum amount of net ZUSD debt a trove must have\\n uint256 public constant MIN_NET_DEBT = 180e18;\\n\\n IActivePool public activePool;\\n\\n IDefaultPool public defaultPool;\\n\\n IPriceFeed public override priceFeed;\\n\\n ILiquityBaseParams public override liquityBaseParams;\\n\\n // --- Gas compensation functions ---\\n\\n // Returns the composite debt (drawn debt + gas compensation) of a trove, for the purpose of ICR calculation\\n function _getCompositeDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.add(ZUSD_GAS_COMPENSATION);\\n }\\n\\n function _getNetDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.sub(ZUSD_GAS_COMPENSATION);\\n }\\n\\n /// Return the amount of ETH to be drawn from a trove's collateral and sent as gas compensation.\\n function _getCollGasCompensation(uint256 _entireColl) internal view returns (uint256) {\\n return _entireColl / liquityBaseParams.PERCENT_DIVISOR();\\n }\\n\\n function getEntireSystemColl() public view returns (uint256 entireSystemColl) {\\n uint256 activeColl = activePool.getETH();\\n uint256 liquidatedColl = defaultPool.getETH();\\n\\n return activeColl.add(liquidatedColl);\\n }\\n\\n function getEntireSystemDebt() public view returns (uint256 entireSystemDebt) {\\n uint256 activeDebt = activePool.getZUSDDebt();\\n uint256 closedDebt = defaultPool.getZUSDDebt();\\n\\n return activeDebt.add(closedDebt);\\n }\\n\\n function _getTCR(uint256 _price) internal view returns (uint256 TCR) {\\n uint256 entireSystemColl = getEntireSystemColl();\\n uint256 entireSystemDebt = getEntireSystemDebt();\\n\\n TCR = LiquityMath._computeCR(entireSystemColl, entireSystemDebt, _price);\\n\\n return TCR;\\n }\\n\\n function _checkRecoveryMode(uint256 _price) internal view returns (bool) {\\n uint256 TCR = _getTCR(_price);\\n\\n return TCR < liquityBaseParams.CCR();\\n }\\n\\n function _requireUserAcceptsFee(\\n uint256 _fee,\\n uint256 _amount,\\n uint256 _maxFeePercentage\\n ) internal pure {\\n uint256 feePercentage = _fee.mul(DECIMAL_PRECISION).div(_amount);\\n require(feePercentage <= _maxFeePercentage, \\\"Fee exceeded provided maximum\\\");\\n }\\n}\\n\",\"keccak256\":\"0x100b8a1c17caa95f5c9977e88f9263847a1977a365ca0a795753dd74aa1d6d7c\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./console.sol\\\";\\n\\nlibrary LiquityMath {\\n using SafeMath for uint;\\n\\n uint internal constant DECIMAL_PRECISION = 1e18;\\n\\n /* Precision for Nominal ICR (independent of price). Rationale for the value:\\n *\\n * - Making it \\u201ctoo high\\u201d could lead to overflows.\\n * - Making it \\u201ctoo low\\u201d could lead to an ICR equal to zero, due to truncation from Solidity floor division. \\n *\\n * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH,\\n * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.\\n *\\n */\\n uint internal constant NICR_PRECISION = 1e20;\\n\\n function _min(uint _a, uint _b) internal pure returns (uint) {\\n return (_a < _b) ? _a : _b;\\n }\\n\\n function _max(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a : _b;\\n }\\n\\n /* \\n * Multiply two decimal numbers and use normal rounding rules:\\n * -round product up if 19'th mantissa digit >= 5\\n * -round product down if 19'th mantissa digit < 5\\n *\\n * Used only inside the exponentiation, _decPow().\\n */\\n function decMul(uint x, uint y) internal pure returns (uint decProd) {\\n uint prod_xy = x.mul(y);\\n\\n decProd = prod_xy.add(DECIMAL_PRECISION / 2).div(DECIMAL_PRECISION);\\n }\\n\\n /* \\n * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.\\n * \\n * Uses the efficient \\\"exponentiation by squaring\\\" algorithm. O(log(n)) complexity. \\n * \\n * Called by two functions that represent time in units of minutes:\\n * 1) TroveManager._calcDecayedBaseRate\\n * 2) CommunityIssuance._getCumulativeIssuanceFraction \\n * \\n * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals\\n * \\\"minutes in 1000 years\\\": 60 * 24 * 365 * 1000\\n * \\n * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be\\n * negligibly different from just passing the cap, since: \\n *\\n * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years\\n * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible\\n */\\n function _decPow(uint _base, uint _minutes) internal pure returns (uint) {\\n \\n if (_minutes > 525600000) {_minutes = 525600000;} // cap to avoid overflow\\n \\n if (_minutes == 0) {return DECIMAL_PRECISION;}\\n\\n uint y = DECIMAL_PRECISION;\\n uint x = _base;\\n uint n = _minutes;\\n\\n // Exponentiation-by-squaring\\n while (n > 1) {\\n if (n % 2 == 0) {\\n x = decMul(x, x);\\n n = n.div(2);\\n } else { // if (n % 2 != 0)\\n y = decMul(x, y);\\n x = decMul(x, x);\\n n = (n.sub(1)).div(2);\\n }\\n }\\n\\n return decMul(x, y);\\n }\\n\\n function _getAbsoluteDifference(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a.sub(_b) : _b.sub(_a);\\n }\\n\\n function _computeNominalCR(uint _coll, uint _debt) internal pure returns (uint) {\\n if (_debt > 0) {\\n return _coll.mul(NICR_PRECISION).div(_debt);\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1;\\n }\\n }\\n\\n function _computeCR(uint _coll, uint _debt, uint _price) internal pure returns (uint) {\\n if (_debt > 0) {\\n uint newCollRatio = _coll.mul(_price).div(_debt);\\n\\n return newCollRatio;\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1; \\n }\\n }\\n}\\n\",\"keccak256\":\"0x7a95ed70d8937e0896c054b433ad0dfc87a9cfd028cae1694098e9d5d68127cd\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IDLLR.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\nimport \\\"../IERC20.sol\\\";\\n\\n/// Public interface for Sovryn Dollar DLLR (Meta Asset Token of Sovryn Mynt) exposing specific functions\\ninterface IDLLR is IERC20 {\\n /**\\n * @notice Only owner can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _recipient Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transfer(address _recipient, uint256 _amount) external override returns (bool);\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _amount\\n ) external override returns (bool);\\n\\n /**\\n * @notice transfer utilizing EIP-2612, to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @dev By calling this function, the allowance will be overwritten by the total amount.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of the token that will be transferred.\\n * @param _deadline Expiration time of the signature.\\n * @param _v Last 1 byte of ECDSA signature.\\n * @param _r First 32 bytes of ECDSA signature.\\n * @param _s 32 bytes after _r in ECDSA signature.\\n */\\n function transferWithPermit(\\n address _from,\\n address _to,\\n uint256 _amount,\\n uint256 _deadline,\\n uint8 _v,\\n bytes32 _r,\\n bytes32 _s\\n ) external;\\n\\n /**\\n * @notice Approves and then calls the receiving contract.\\n * Useful to encapsulate sending tokens to a contract in one call.\\n * Solidity has no native way to send tokens to contracts.\\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\\n * @param _spender The contract address to spend the tokens.\\n * @param _amount The amount of tokens to be sent.\\n * @param _data Parameters for the contract call, such as endpoint signature.\\n */\\n function approveAndCall(address _spender, uint256 _amount, bytes calldata _data) external;\\n}\\n\",\"keccak256\":\"0x1fcc09759323769fcaa430bef598cf08a9f5e98ce6a9bdd6faa79d8b7b6ecce2\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IMassetManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IMassetManager {\\n struct PermitParams {\\n uint256 deadline;\\n uint8 v;\\n bytes32 r;\\n bytes32 s;\\n }\\n\\n function mintTo(\\n address _bAsset,\\n uint256 _bAssetQuantity,\\n address _recipient\\n ) external returns (uint256);\\n\\n function getToken() external view returns (address);\\n\\n /**\\n * @dev Credits a recipient with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @param _recipient Address to credit with withdrawn bAssets.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeemTo(\\n address _bAsset,\\n uint256 _massetQuantity,\\n address _recipient\\n ) external returns (uint256 massetRedeemed);\\n}\\n\",\"keccak256\":\"0x3e8de462d45e8f07ef83b6b6e7eb90a5d09f21d3bcbb1225e8f781488ab4a771\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/MyntLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IMassetManager.sol\\\";\\nimport \\\"./IDLLR.sol\\\";\\nimport \\\"../SafeMath.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"../../Interfaces/IPermit2.sol\\\";\\n\\nlibrary MyntLib {\\n using SafeMath for uint256;\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @dev WARNING!! Do not us this lib function on RSK network because there is a griefing attack issue in the DLLR contract.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _dllrAmount The amount of the DLLR (mAsset) token that will be burned in exchange for _toToken\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permitParams EIP-2612 permit params:\\n * _deadline Expiration time of the signature.\\n * _v Last 1 byte of ECDSA signature.\\n * _r First 32 bytes of ECDSA signature.\\n * _s 32 bytes after _r in ECDSA signature.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit(\\n IMassetManager _myntMassetManager,\\n uint256 _dllrAmount,\\n address _toToken,\\n IMassetManager.PermitParams calldata _permitParams\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n dllr.transferWithPermit(\\n msg.sender,\\n thisAddress,\\n _dllrAmount,\\n _permitParams.deadline,\\n _permitParams.v,\\n _permitParams.r,\\n _permitParams.s\\n );\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit via a canonical Permit2 contract\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permit permit data, in form of PermitTransferFrom struct.\\n * @param _permit2 permit2 contract address\\n * @param _signature signatue of the permit data.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit2(\\n IMassetManager _myntMassetManager,\\n address _toToken,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n IPermit2 _permit2,\\n bytes calldata _signature\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n uint256 _dllrAmount = _permit.permitted.amount;\\n\\n _permit2.permitTransferFrom(\\n _permit,\\n _generateTransferDetails(thisAddress, _dllrAmount),\\n msg.sender,\\n _signature\\n );\\n\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @dev view function to construct SignatureTransferDetails struct to be used by Permit2\\n *\\n * @param _to ultimate recipient\\n * @param _amount amount of transfer\\n *\\n * @return SignatureTransferDetails struct object \\n */\\n function _generateTransferDetails(address _to, uint256 _amount) private view returns (ISignatureTransfer.SignatureTransferDetails memory) {\\n ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer.SignatureTransferDetails({\\n to: _to,\\n requestedAmount: _amount\\n });\\n\\n return transferDetails;\\n }\\n}\\n\",\"keccak256\":\"0x6f0c78d8c4ea0b5b5e6bbe8d78374b9d2d367ffc07054dde36b9cbe2061944b6\",\"license\":\"MIT\"},\"contracts/Dependencies/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's Ownable contract:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\\n *\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable {\\n bytes32 private constant KEY_OWNER = keccak256(\\\"key.ownable.owner\\\");\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor () internal {\\n _setOwner(msg.sender);\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(msg.sender == getOwner(), \\\"Ownable:: access denied\\\");\\n _;\\n }\\n\\n /**\\n * @notice Set address of the owner.\\n * @param _owner Address of the owner.\\n * */\\n function _setOwner(address _owner) internal {\\n require(_owner != address(0), \\\"Ownable::setOwner: invalid address\\\");\\n emit OwnershipTransferred(getOwner(), _owner);\\n\\n bytes32 key = KEY_OWNER;\\n assembly {\\n sstore(key, _owner)\\n }\\n }\\n\\n /**\\n * @notice Set address of the owner (only owner can call this function)\\n * @param _owner Address of the owner.\\n * */\\n function setOwner(address _owner) public onlyOwner {\\n _setOwner(_owner);\\n }\\n\\n /**\\n * @notice Return address of the owner.\\n * @return _owner Address of the owner.\\n * */\\n function getOwner() public view returns (address _owner) {\\n bytes32 key = KEY_OWNER;\\n assembly {\\n _owner := sload(key)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xb5fc626e0b227fc0feb1d84440585015a0a5f586547d298534a604dd113efec6\",\"license\":\"MIT\"},\"contracts/Dependencies/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's SafeMath:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol\\n *\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x666b890992a066cc791f36c2975cd595d9761a014c654c385ed36ffaf658f3fd\",\"license\":\"MIT\"},\"contracts/Dependencies/TroveManagerBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IZUSDToken.sol\\\";\\nimport \\\"../Interfaces/IZEROStaking.sol\\\";\\nimport \\\"../Interfaces/ISortedTroves.sol\\\";\\nimport \\\"../Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"../TroveManagerStorage.sol\\\";\\nimport \\\"./LiquityBase.sol\\\";\\n\\ncontract TroveManagerBase is LiquityBase, TroveManagerStorage {\\n uint256 public constant SECONDS_IN_ONE_MINUTE = 60;\\n\\n uint256 public constant MINUTE_DECAY_FACTOR = 999037758833783000;\\n\\n /// During bootsrap period redemptions are not allowed\\n uint256 public immutable BOOTSTRAP_PERIOD;\\n\\n /**\\n BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption.\\n Corresponds to (1 / ALPHA) in the white paper.\\n */\\n uint256 public constant BETA = 2;\\n\\n /**\\n --- Variable container structs for liquidations ---\\n \\n These structs are used to hold, return and assign variables inside the liquidation functions,\\n in order to avoid the error: \\\"CompilerError: Stack too deep\\\".\\n */\\n\\n struct LocalVariables_OuterLiquidationFunction {\\n uint256 price;\\n uint256 ZUSDInStabPool;\\n bool recoveryModeAtStart;\\n uint256 liquidatedDebt;\\n uint256 liquidatedColl;\\n }\\n\\n struct LocalVariables_InnerSingleLiquidateFunction {\\n uint256 collToLiquidate;\\n uint256 pendingDebtReward;\\n uint256 pendingCollReward;\\n }\\n\\n struct LocalVariables_LiquidationSequence {\\n uint256 remainingZUSDInStabPool;\\n uint256 i;\\n uint256 ICR;\\n address user;\\n bool backToNormalMode;\\n uint256 entireSystemDebt;\\n uint256 entireSystemColl;\\n }\\n\\n struct LiquidationValues {\\n uint256 entireTroveDebt;\\n uint256 entireTroveColl;\\n uint256 collGasCompensation;\\n uint256 ZUSDGasCompensation;\\n uint256 debtToOffset;\\n uint256 collToSendToSP;\\n uint256 debtToRedistribute;\\n uint256 collToRedistribute;\\n uint256 collSurplus;\\n }\\n\\n struct LiquidationTotals {\\n uint256 totalCollInSequence;\\n uint256 totalDebtInSequence;\\n uint256 totalCollGasCompensation;\\n uint256 totalZUSDGasCompensation;\\n uint256 totalDebtToOffset;\\n uint256 totalCollToSendToSP;\\n uint256 totalDebtToRedistribute;\\n uint256 totalCollToRedistribute;\\n uint256 totalCollSurplus;\\n }\\n\\n struct ContractsCache {\\n IActivePool activePool;\\n IDefaultPool defaultPool;\\n IZUSDToken zusdToken;\\n IZEROStaking zeroStaking;\\n ISortedTroves sortedTroves;\\n ICollSurplusPool collSurplusPool;\\n address gasPoolAddress;\\n }\\n // --- Variable container structs for redemptions ---\\n\\n struct RedemptionTotals {\\n uint256 remainingZUSD;\\n uint256 totalZUSDToRedeem;\\n uint256 totalETHDrawn;\\n uint256 ETHFee;\\n uint256 ETHToSendToRedeemer;\\n uint256 decayedBaseRate;\\n uint256 price;\\n uint256 totalZUSDSupplyAtStart;\\n }\\n\\n struct SingleRedemptionValues {\\n uint256 ZUSDLot;\\n uint256 ETHLot;\\n bool cancelledPartial;\\n }\\n\\n // --- Events ---\\n\\n event Liquidation(\\n uint256 _liquidatedDebt,\\n uint256 _liquidatedColl,\\n uint256 _collGasCompensation,\\n uint256 _ZUSDGasCompensation\\n );\\n event Redemption(\\n uint256 _attemptedZUSDAmount,\\n uint256 _actualZUSDAmount,\\n uint256 _ETHSent,\\n uint256 _ETHFee\\n );\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 _stake,\\n TroveManagerOperation _operation\\n );\\n event TroveLiquidated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n TroveManagerOperation _operation\\n );\\n event BaseRateUpdated(uint256 _baseRate);\\n event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);\\n event TotalStakesUpdated(uint256 _newTotalStakes);\\n event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);\\n event LTermsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveIndexUpdated(address _borrower, uint256 _newIndex);\\n\\n enum TroveManagerOperation {\\n applyPendingRewards,\\n liquidateInNormalMode,\\n liquidateInRecoveryMode,\\n redeemCollateral\\n }\\n\\n constructor(uint256 _bootstrapPeriod) public {\\n BOOTSTRAP_PERIOD = _bootstrapPeriod;\\n }\\n\\n /// Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function _getCurrentICR(address _borrower, uint256 _price) public view returns (uint256) {\\n (uint256 currentETH, uint256 currentZUSDDebt) = _getCurrentTroveAmounts(_borrower);\\n\\n uint256 ICR = LiquityMath._computeCR(currentETH, currentZUSDDebt, _price);\\n return ICR;\\n }\\n\\n function _getCurrentTroveAmounts(address _borrower) internal view returns (uint256, uint256) {\\n uint256 pendingETHReward = _getPendingETHReward(_borrower);\\n uint256 pendingZUSDDebtReward = _getPendingZUSDDebtReward(_borrower);\\n\\n uint256 currentETH = Troves[_borrower].coll.add(pendingETHReward);\\n uint256 currentZUSDDebt = Troves[_borrower].debt.add(pendingZUSDDebtReward);\\n\\n return (currentETH, currentZUSDDebt);\\n }\\n\\n /// Get the borrower's pending accumulated ETH reward, earned by their stake\\n function _getPendingETHReward(address _borrower) public view returns (uint256) {\\n uint256 snapshotETH = rewardSnapshots[_borrower].ETH;\\n uint256 rewardPerUnitStaked = L_ETH.sub(snapshotETH);\\n\\n if (rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) {\\n return 0;\\n }\\n\\n uint256 stake = Troves[_borrower].stake;\\n\\n uint256 pendingETHReward = stake.mul(rewardPerUnitStaked).div(DECIMAL_PRECISION);\\n\\n return pendingETHReward;\\n }\\n\\n /// Get the borrower's pending accumulated ZUSD reward, earned by their stake\\n function _getPendingZUSDDebtReward(address _borrower) public view returns (uint256) {\\n uint256 snapshotZUSDDebt = rewardSnapshots[_borrower].ZUSDDebt;\\n uint256 rewardPerUnitStaked = L_ZUSDDebt.sub(snapshotZUSDDebt);\\n\\n if (rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) {\\n return 0;\\n }\\n\\n uint256 stake = Troves[_borrower].stake;\\n\\n uint256 pendingZUSDDebtReward = stake.mul(rewardPerUnitStaked).div(DECIMAL_PRECISION);\\n\\n return pendingZUSDDebtReward;\\n }\\n\\n /// Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\\n function _applyPendingRewards(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n address _borrower\\n ) internal {\\n if (_hasPendingRewards(_borrower)) {\\n _requireTroveIsActive(_borrower);\\n\\n // Compute pending rewards\\n uint256 pendingETHReward = _getPendingETHReward(_borrower);\\n uint256 pendingZUSDDebtReward = _getPendingZUSDDebtReward(_borrower);\\n\\n // Apply pending rewards to trove's state\\n Troves[_borrower].coll = Troves[_borrower].coll.add(pendingETHReward);\\n Troves[_borrower].debt = Troves[_borrower].debt.add(pendingZUSDDebtReward);\\n\\n _updateTroveRewardSnapshots(_borrower);\\n\\n // Transfer from DefaultPool to ActivePool\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n pendingZUSDDebtReward,\\n pendingETHReward\\n );\\n\\n emit TroveUpdated(\\n _borrower,\\n Troves[_borrower].debt,\\n Troves[_borrower].coll,\\n Troves[_borrower].stake,\\n TroveManagerOperation.applyPendingRewards\\n );\\n }\\n }\\n\\n function _hasPendingRewards(address _borrower) public view returns (bool) {\\n /*\\n * A Trove has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:\\n * this indicates that rewards have occured since the snapshot was made, and the user therefore has\\n * pending rewards\\n */\\n if (Troves[_borrower].status != Status.active) {\\n return false;\\n }\\n\\n return (rewardSnapshots[_borrower].ETH < L_ETH);\\n }\\n\\n function _updateTroveRewardSnapshots(address _borrower) internal {\\n rewardSnapshots[_borrower].ETH = L_ETH;\\n rewardSnapshots[_borrower].ZUSDDebt = L_ZUSDDebt;\\n emit TroveSnapshotsUpdated(L_ETH, L_ZUSDDebt);\\n }\\n\\n /// Move a Trove's pending debt and collateral rewards from distributions, from the Default Pool to the Active Pool\\n function _movePendingTroveRewardsToActivePool(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _ZUSD,\\n uint256 _ETH\\n ) internal {\\n _defaultPool.decreaseZUSDDebt(_ZUSD);\\n _activePool.increaseZUSDDebt(_ZUSD);\\n _defaultPool.sendETHToActivePool(_ETH);\\n }\\n\\n /// Remove borrower's stake from the totalStakes sum, and set their stake to 0\\n function _removeStake(address _borrower) internal {\\n uint256 stake = Troves[_borrower].stake;\\n totalStakes = totalStakes.sub(stake);\\n Troves[_borrower].stake = 0;\\n }\\n\\n function _closeTrove(address _borrower, Status closedStatus) internal {\\n assert(closedStatus != Status.nonExistent && closedStatus != Status.active);\\n\\n uint256 TroveOwnersArrayLength = TroveOwners.length;\\n _requireMoreThanOneTroveInSystem(TroveOwnersArrayLength);\\n\\n Troves[_borrower].status = closedStatus;\\n Troves[_borrower].coll = 0;\\n Troves[_borrower].debt = 0;\\n\\n rewardSnapshots[_borrower].ETH = 0;\\n rewardSnapshots[_borrower].ZUSDDebt = 0;\\n\\n _removeTroveOwner(_borrower, TroveOwnersArrayLength);\\n sortedTroves.remove(_borrower);\\n }\\n\\n /// Update borrower's stake based on their latest collateral value\\n function _updateStakeAndTotalStakes(address _borrower) internal returns (uint256) {\\n uint256 newStake = _computeNewStake(Troves[_borrower].coll);\\n uint256 oldStake = Troves[_borrower].stake;\\n Troves[_borrower].stake = newStake;\\n\\n totalStakes = totalStakes.sub(oldStake).add(newStake);\\n emit TotalStakesUpdated(totalStakes);\\n\\n return newStake;\\n }\\n\\n // Calculate a new stake based on the snapshots of the totalStakes and totalCollateral taken at the last liquidation\\n function _computeNewStake(uint256 _coll) internal view returns (uint256) {\\n uint256 stake;\\n if (totalCollateralSnapshot == 0) {\\n stake = _coll;\\n } else {\\n /*\\n * The following assert() holds true because:\\n * - The system always contains >= 1 trove\\n * - When we close or liquidate a trove, we redistribute the pending rewards, so if all troves were closed/liquidated,\\n * rewards would\\u2019ve been emptied and totalCollateralSnapshot would be zero too.\\n */\\n assert(totalStakesSnapshot > 0);\\n stake = _coll.mul(totalStakesSnapshot).div(totalCollateralSnapshot);\\n }\\n return stake;\\n }\\n\\n function _calcDecayedBaseRate() internal view returns (uint256) {\\n uint256 minutesPassed = _minutesPassedSinceLastFeeOp();\\n uint256 decayFactor = LiquityMath._decPow(MINUTE_DECAY_FACTOR, minutesPassed);\\n\\n return baseRate.mul(decayFactor).div(DECIMAL_PRECISION);\\n }\\n\\n function _minutesPassedSinceLastFeeOp() internal view returns (uint256) {\\n return (block.timestamp.sub(lastFeeOperationTime)).div(SECONDS_IN_ONE_MINUTE);\\n }\\n\\n // Update the last fee operation time only if time passed >= decay interval. This prevents base rate griefing.\\n function _updateLastFeeOpTime() internal {\\n uint256 timePassed = block.timestamp.sub(lastFeeOperationTime);\\n\\n if (timePassed >= SECONDS_IN_ONE_MINUTE) {\\n lastFeeOperationTime = block.timestamp;\\n emit LastFeeOpTimeUpdated(block.timestamp);\\n }\\n }\\n\\n function _calcRedemptionFee(\\n uint256 _redemptionRate,\\n uint256 _ETHDrawn\\n ) internal pure returns (uint256) {\\n uint256 redemptionFee = _redemptionRate.mul(_ETHDrawn).div(DECIMAL_PRECISION);\\n require(\\n redemptionFee < _ETHDrawn,\\n \\\"TroveManager: Fee would eat up all returned collateral\\\"\\n );\\n return redemptionFee;\\n }\\n\\n function _getRedemptionRate() public view returns (uint256) {\\n return _calcRedemptionRate(baseRate);\\n }\\n\\n function _getRedemptionFee(uint256 _ETHDrawn) internal view returns (uint256) {\\n return _calcRedemptionFee(_getRedemptionRate(), _ETHDrawn);\\n }\\n\\n function _calcRedemptionRate(uint256 _baseRate) internal view returns (uint256) {\\n return\\n LiquityMath._min(\\n liquityBaseParams.REDEMPTION_FEE_FLOOR().add(_baseRate),\\n DECIMAL_PRECISION // cap at a maximum of 100%\\n );\\n }\\n\\n /**\\n Remove a Trove owner from the TroveOwners array, not preserving array order. Removing owner 'B' does the following:\\n [A B C D E] => [A E C D], and updates E's Trove struct to point to its new array index.\\n */\\n function _removeTroveOwner(address _borrower, uint256 TroveOwnersArrayLength) internal {\\n Status troveStatus = Troves[_borrower].status;\\n // It\\u2019s set in caller function `_closeTrove`\\n assert(troveStatus != Status.nonExistent && troveStatus != Status.active);\\n\\n uint128 index = Troves[_borrower].arrayIndex;\\n uint256 length = TroveOwnersArrayLength;\\n uint256 idxLast = length.sub(1);\\n\\n assert(index <= idxLast);\\n\\n address addressToMove = TroveOwners[idxLast];\\n\\n TroveOwners[index] = addressToMove;\\n Troves[addressToMove].arrayIndex = index;\\n emit TroveIndexUpdated(addressToMove, index);\\n\\n TroveOwners.pop();\\n }\\n\\n // --- 'require' wrapper functions ---\\n\\n function _requireCallerIsBorrowerOperations() internal view {\\n require(\\n msg.sender == borrowerOperationsAddress,\\n \\\"TroveManager: Caller is not the BorrowerOperations contract\\\"\\n );\\n }\\n\\n function _requireTroveIsActive(address _borrower) internal view {\\n require(\\n Troves[_borrower].status == Status.active,\\n \\\"TroveManager: Trove does not exist or is closed\\\"\\n );\\n }\\n\\n function _requireZUSDBalanceCoversRedemption(\\n IZUSDToken _zusdToken,\\n address _redeemer,\\n uint256 _amount\\n ) internal view {\\n require(\\n _zusdToken.balanceOf(_redeemer) >= _amount,\\n \\\"TroveManager: Requested redemption amount must be <= user's ZUSD token balance\\\"\\n );\\n }\\n\\n function _requireMoreThanOneTroveInSystem(uint256 TroveOwnersArrayLength) internal view {\\n require(\\n TroveOwnersArrayLength > 1 && sortedTroves.getSize() > 1,\\n \\\"TroveManager: Only one trove in the system\\\"\\n );\\n }\\n\\n function _requireAmountGreaterThanZero(uint256 _amount) internal pure {\\n require(_amount > 0, \\\"TroveManager: Amount must be greater than zero\\\");\\n }\\n\\n function _requireTCRoverMCR(uint256 _price) internal view {\\n require(\\n _getTCR(_price) >= liquityBaseParams.MCR(),\\n \\\"TroveManager: Cannot redeem when TCR < MCR\\\"\\n );\\n }\\n\\n function _requireAfterBootstrapPeriod() internal view {\\n uint256 systemDeploymentTime = _zeroToken.getDeploymentStartTime();\\n require(\\n block.timestamp >= systemDeploymentTime.add(BOOTSTRAP_PERIOD),\\n \\\"TroveManager: Redemptions are not allowed during bootstrap phase\\\"\\n );\\n }\\n\\n function _requireValidMaxFeePercentage(uint256 _maxFeePercentage) internal view {\\n require(\\n _maxFeePercentage >= liquityBaseParams.REDEMPTION_FEE_FLOOR() &&\\n _maxFeePercentage <= DECIMAL_PRECISION,\\n \\\"Max fee percentage must be between 0.5% and 100%\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x83e1bfaa93cf973052c41df1cc0741a93f737659cd664f207c0d42256f78617b\",\"license\":\"MIT\"},\"contracts/Dependencies/TroveManagerRedeemOps.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/MyntLib.sol\\\";\\nimport \\\"../Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./TroveManagerBase.sol\\\";\\nimport \\\"../Interfaces/IPermit2.sol\\\";\\n\\n/// This contract is designed to be used via delegatecall from the TroveManager contract\\n/// TroveManagerBase constructor param is bootsrap period when redemptions are not allowed\\ncontract TroveManagerRedeemOps is TroveManagerBase {\\n /** CONSTANT / IMMUTABLE VARIABLE ONLY */\\n IPermit2 public immutable permit2;\\n\\n /** Send _ZUSDamount ZUSD to the system and redeem the corresponding amount of collateral from as many Troves as are needed to fill the redemption\\n request. Applies pending rewards to a Trove before reducing its debt and coll.\\n \\n Note that if _amount is very large, this function can run out of gas, specially if traversed troves are small. This can be easily avoided by\\n splitting the total _amount in appropriate chunks and calling the function multiple times.\\n \\n Param `_maxIterations` can also be provided, so the loop through Troves is capped (if it\\u2019s zero, it will be ignored).This makes it easier to\\n avoid OOG for the frontend, as only knowing approximately the average cost of an iteration is enough, without needing to know the \\u201ctopology\\u201d\\n of the trove list. It also avoids the need to set the cap in stone in the contract, nor doing gas calculations, as both gas price and opcode\\n costs can vary.\\n \\n All Troves that are redeemed from -- with the likely exception of the last one -- will end up with no debt left, therefore they will be closed.\\n If the last Trove does have some remaining debt, it has a finite ICR, and the reinsertion could be anywhere in the list, therefore it requires a hint.\\n A frontend should use getRedemptionHints() to calculate what the ICR of this Trove will be after redemption, and pass a hint for its position\\n in the sortedTroves list along with the ICR value that the hint was found for.\\n \\n If another transaction modifies the list between calling getRedemptionHints() and passing the hints to redeemCollateral(), it\\n is very likely that the last (partially) redeemed Trove would end up with a different ICR than what the hint is for. In this case the\\n redemption will stop after the last completely redeemed Trove and the sender will keep the remaining ZUSD amount, which they can attempt\\n to redeem later.\\n */\\n\\n /** Constructor */\\n constructor(uint256 _bootstrapPeriod, address _permit2) public TroveManagerBase(_bootstrapPeriod) {\\n permit2 = IPermit2(_permit2);\\n }\\n\\n function redeemCollateral(\\n uint256 _ZUSDamount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage\\n ) external {\\n _redeemCollateral(\\n _ZUSDamount,\\n _firstRedemptionHint,\\n _upperPartialRedemptionHint,\\n _lowerPartialRedemptionHint,\\n _partialRedemptionHintNICR,\\n _maxIterations,\\n _maxFeePercentage\\n );\\n }\\n\\n function _redeemCollateral(\\n uint256 _ZUSDamount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage\\n ) internal {\\n ContractsCache memory contractsCache = ContractsCache(\\n activePool,\\n defaultPool,\\n _zusdToken,\\n _zeroStaking,\\n sortedTroves,\\n collSurplusPool,\\n gasPoolAddress\\n );\\n RedemptionTotals memory totals;\\n\\n _requireValidMaxFeePercentage(_maxFeePercentage);\\n _requireAfterBootstrapPeriod();\\n totals.price = priceFeed.fetchPrice();\\n _requireTCRoverMCR(totals.price);\\n _requireAmountGreaterThanZero(_ZUSDamount);\\n _requireZUSDBalanceCoversRedemption(contractsCache.zusdToken, msg.sender, _ZUSDamount);\\n\\n totals.totalZUSDSupplyAtStart = getEntireSystemDebt();\\n // Confirm redeemer's balance is less than total ZUSD supply\\n assert(contractsCache.zusdToken.balanceOf(msg.sender) <= totals.totalZUSDSupplyAtStart);\\n\\n totals.remainingZUSD = _ZUSDamount;\\n address currentBorrower;\\n\\n if (\\n _isValidFirstRedemptionHint(\\n contractsCache.sortedTroves,\\n _firstRedemptionHint,\\n totals.price\\n )\\n ) {\\n currentBorrower = _firstRedemptionHint;\\n } else {\\n currentBorrower = contractsCache.sortedTroves.getLast();\\n // Find the first trove with ICR >= MCR\\n while (\\n currentBorrower != address(0) &&\\n _getCurrentICR(currentBorrower, totals.price) < liquityBaseParams.MCR()\\n ) {\\n currentBorrower = contractsCache.sortedTroves.getPrev(currentBorrower);\\n }\\n }\\n\\n // Loop through the Troves starting from the one with lowest collateral ratio until _amount of ZUSD is exchanged for collateral\\n if (_maxIterations == 0) {\\n _maxIterations = uint256(-1);\\n }\\n while (currentBorrower != address(0) && totals.remainingZUSD > 0 && _maxIterations > 0) {\\n _maxIterations--;\\n // Save the address of the Trove preceding the current one, before potentially modifying the list\\n address nextUserToCheck = contractsCache.sortedTroves.getPrev(currentBorrower);\\n\\n _applyPendingRewards(\\n contractsCache.activePool,\\n contractsCache.defaultPool,\\n currentBorrower\\n );\\n\\n SingleRedemptionValues memory singleRedemption = _redeemCollateralFromTrove(\\n contractsCache,\\n currentBorrower,\\n totals.remainingZUSD,\\n totals.price,\\n _upperPartialRedemptionHint,\\n _lowerPartialRedemptionHint,\\n _partialRedemptionHintNICR\\n );\\n\\n if (singleRedemption.cancelledPartial) break; // Partial redemption was cancelled (out-of-date hint, or new net debt < minimum), therefore we could not redeem from the last Trove\\n\\n totals.totalZUSDToRedeem = totals.totalZUSDToRedeem.add(singleRedemption.ZUSDLot);\\n totals.totalETHDrawn = totals.totalETHDrawn.add(singleRedemption.ETHLot);\\n\\n totals.remainingZUSD = totals.remainingZUSD.sub(singleRedemption.ZUSDLot);\\n currentBorrower = nextUserToCheck;\\n }\\n require(totals.totalETHDrawn > 0, \\\"TroveManager: Unable to redeem any amount\\\");\\n\\n // Decay the baseRate due to time passed, and then increase it according to the size of this redemption.\\n // Use the saved total ZUSD supply value, from before it was reduced by the redemption.\\n _updateBaseRateFromRedemption(\\n totals.totalETHDrawn,\\n totals.price,\\n totals.totalZUSDSupplyAtStart\\n );\\n\\n // Calculate the ETH fee\\n totals.ETHFee = _getRedemptionFee(totals.totalETHDrawn);\\n\\n _requireUserAcceptsFee(totals.ETHFee, totals.totalETHDrawn, _maxFeePercentage);\\n\\n // Send the ETH fee to the feeDistributorContract address\\n contractsCache.activePool.sendETH(address(feeDistributor), totals.ETHFee);\\n feeDistributor.distributeFees();\\n\\n totals.ETHToSendToRedeemer = totals.totalETHDrawn.sub(totals.ETHFee);\\n\\n emit Redemption(\\n _ZUSDamount,\\n totals.totalZUSDToRedeem,\\n totals.totalETHDrawn,\\n totals.ETHFee\\n );\\n\\n // Burn the total ZUSD that is cancelled with debt, and send the redeemed ETH to msg.sender\\n contractsCache.zusdToken.burn(msg.sender, totals.totalZUSDToRedeem);\\n // Update Active Pool ZUSD, and send ETH to account\\n contractsCache.activePool.decreaseZUSDDebt(totals.totalZUSDToRedeem);\\n contractsCache.activePool.sendETH(msg.sender, totals.ETHToSendToRedeemer);\\n }\\n\\n ///DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\\n function redeemCollateralViaDLLR(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external {\\n uint256 _zusdAmount = MyntLib.redeemZusdFromDllrWithPermit(\\n IBorrowerOperations(borrowerOperationsAddress).getMassetManager(),\\n _dllrAmount,\\n address(_zusdToken),\\n _permitParams\\n );\\n _redeemCollateral(\\n _zusdAmount,\\n _firstRedemptionHint,\\n _upperPartialRedemptionHint,\\n _lowerPartialRedemptionHint,\\n _partialRedemptionHintNICR,\\n _maxIterations,\\n _maxFeePercentage\\n );\\n }\\n\\n ///DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\\n function redeemCollateralViaDllrWithPermit2(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external {\\n uint256 _zusdAmount = MyntLib.redeemZusdFromDllrWithPermit2(\\n IBorrowerOperations(borrowerOperationsAddress).getMassetManager(),\\n address(_zusdToken),\\n _permit,\\n permit2,\\n _signature\\n );\\n\\n _redeemCollateral(\\n _zusdAmount,\\n _firstRedemptionHint,\\n _upperPartialRedemptionHint,\\n _lowerPartialRedemptionHint,\\n _partialRedemptionHintNICR,\\n _maxIterations,\\n _maxFeePercentage\\n );\\n }\\n\\n function _isValidFirstRedemptionHint(\\n ISortedTroves _sortedTroves,\\n address _firstRedemptionHint,\\n uint256 _price\\n ) internal view returns (bool) {\\n if (\\n _firstRedemptionHint == address(0) ||\\n !_sortedTroves.contains(_firstRedemptionHint) ||\\n _getCurrentICR(_firstRedemptionHint, _price) < liquityBaseParams.MCR()\\n ) {\\n return false;\\n }\\n\\n address nextTrove = _sortedTroves.getNext(_firstRedemptionHint);\\n return\\n nextTrove == address(0) || _getCurrentICR(nextTrove, _price) < liquityBaseParams.MCR();\\n }\\n\\n /// Redeem as much collateral as possible from _borrower's Trove in exchange for ZUSD up to _maxZUSDamount\\n function _redeemCollateralFromTrove(\\n ContractsCache memory _contractsCache,\\n address _borrower,\\n uint256 _maxZUSDamount,\\n uint256 _price,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR\\n ) internal returns (SingleRedemptionValues memory singleRedemption) {\\n // Determine the remaining amount (lot) to be redeemed, capped by the entire debt of the Trove minus the liquidation reserve\\n singleRedemption.ZUSDLot = LiquityMath._min(\\n _maxZUSDamount,\\n Troves[_borrower].debt.sub(ZUSD_GAS_COMPENSATION)\\n );\\n\\n // Get the ETHLot of equivalent value in USD\\n singleRedemption.ETHLot = singleRedemption.ZUSDLot.mul(DECIMAL_PRECISION).div(_price);\\n\\n // Decrease the debt and collateral of the current Trove according to the ZUSD lot and corresponding ETH to send\\n uint256 newDebt = (Troves[_borrower].debt).sub(singleRedemption.ZUSDLot);\\n uint256 newColl = (Troves[_borrower].coll).sub(singleRedemption.ETHLot);\\n\\n if (newDebt == ZUSD_GAS_COMPENSATION) {\\n // No debt left in the Trove (except for the liquidation reserve), therefore the trove gets closed\\n _removeStake(_borrower);\\n _closeTrove(_borrower, Status.closedByRedemption);\\n _redeemCloseTrove(_contractsCache, _borrower, ZUSD_GAS_COMPENSATION, newColl);\\n emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.redeemCollateral);\\n } else {\\n uint256 newNICR = LiquityMath._computeNominalCR(newColl, newDebt);\\n\\n /*\\n * If the provided hint is out of date, we bail since trying to reinsert without a good hint will almost\\n * certainly result in running out of gas.\\n *\\n * If the resultant net debt of the partial is less than the minimum, net debt we bail.\\n */\\n if (newNICR != _partialRedemptionHintNICR || _getNetDebt(newDebt) < MIN_NET_DEBT) {\\n singleRedemption.cancelledPartial = true;\\n return singleRedemption;\\n }\\n\\n _contractsCache.sortedTroves.reInsert(\\n _borrower,\\n newNICR,\\n _upperPartialRedemptionHint,\\n _lowerPartialRedemptionHint\\n );\\n\\n Troves[_borrower].debt = newDebt;\\n Troves[_borrower].coll = newColl;\\n _updateStakeAndTotalStakes(_borrower);\\n\\n emit TroveUpdated(\\n _borrower,\\n newDebt,\\n newColl,\\n Troves[_borrower].stake,\\n TroveManagerOperation.redeemCollateral\\n );\\n }\\n\\n return singleRedemption;\\n }\\n\\n /**\\n This function has two impacts on the baseRate state variable:\\n 1) decays the baseRate based on time passed since last redemption or ZUSD borrowing operation.\\n then,\\n 2) increases the baseRate based on the amount redeemed, as a proportion of total supply\\n */\\n function _updateBaseRateFromRedemption(\\n uint256 _ETHDrawn,\\n uint256 _price,\\n uint256 _totalZUSDSupply\\n ) internal returns (uint256) {\\n uint256 decayedBaseRate = _calcDecayedBaseRate();\\n\\n /* Convert the drawn ETH back to ZUSD at face value rate (1 ZUSD:1 USD), in order to get\\n * the fraction of total supply that was redeemed at face value. */\\n uint256 redeemedZUSDFraction = _ETHDrawn.mul(_price).div(_totalZUSDSupply);\\n\\n uint256 newBaseRate = decayedBaseRate.add(redeemedZUSDFraction.div(BETA));\\n newBaseRate = LiquityMath._min(newBaseRate, DECIMAL_PRECISION); // cap baseRate at a maximum of 100%\\n //assert(newBaseRate <= DECIMAL_PRECISION); // This is already enforced in the line above\\n assert(newBaseRate > 0); // Base rate is always non-zero after redemption\\n\\n // Update the baseRate state variable\\n baseRate = newBaseRate;\\n emit BaseRateUpdated(newBaseRate);\\n\\n _updateLastFeeOpTime();\\n\\n return newBaseRate;\\n }\\n\\n /**\\n Called when a full redemption occurs, and closes the trove.\\n The redeemer swaps (debt - liquidation reserve) ZUSD for (debt - liquidation reserve) worth of ETH, so the ZUSD liquidation reserve left corresponds to the remaining debt.\\n In order to close the trove, the ZUSD liquidation reserve is burned, and the corresponding debt is removed from the active pool.\\n The debt recorded on the trove's struct is zero'd elswhere, in _closeTrove.\\n Any surplus ETH left in the trove, is sent to the Coll surplus pool, and can be later claimed by the borrower.\\n */\\n function _redeemCloseTrove(\\n ContractsCache memory _contractsCache,\\n address _borrower,\\n uint256 _ZUSD,\\n uint256 _ETH\\n ) internal {\\n _contractsCache.zusdToken.burn(gasPoolAddress, _ZUSD);\\n // Update Active Pool ZUSD, and send ETH to account\\n _contractsCache.activePool.decreaseZUSDDebt(_ZUSD);\\n\\n // send ETH from Active Pool to CollSurplus Pool\\n _contractsCache.collSurplusPool.accountSurplus(_borrower, _ETH);\\n _contractsCache.activePool.sendETH(address(_contractsCache.collSurplusPool), _ETH);\\n }\\n}\\n\",\"keccak256\":\"0xb88be6ccc4fb307fbbb8b599be53d96f1dc17c749effb9e97b88a030590101e3\",\"license\":\"MIT\"},\"contracts/Dependencies/console.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Buidler's helper contract for console logging\\nlibrary console {\\n\\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\\n\\n\\tfunction log() internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log()\\\"));\\n\\t\\tignored;\\n\\t}\\tfunction logInt(int p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(int)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logUint(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logString(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBool(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logAddress(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes(bytes memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logByte(byte p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(byte)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes1(bytes1 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes1)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes2(bytes2 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes2)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes3(bytes3 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes3)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes4(bytes4 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes4)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes5(bytes5 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes5)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes6(bytes6 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes6)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes7(bytes7 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes7)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes8(bytes8 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes8)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes9(bytes9 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes9)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes10(bytes10 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes10)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes11(bytes11 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes11)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes12(bytes12 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes12)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes13(bytes13 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes13)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes14(bytes14 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes14)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes15(bytes15 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes15)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes16(bytes16 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes16)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes17(bytes17 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes17)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes18(bytes18 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes18)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes19(bytes19 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes19)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes20(bytes20 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes20)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes21(bytes21 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes21)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes22(bytes22 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes22)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes23(bytes23 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes23)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes24(bytes24 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes24)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes25(bytes25 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes25)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes26(bytes26 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes26)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes27(bytes27 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes27)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes28(bytes28 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes28)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes29(bytes29 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes29)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes30(bytes30 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes30)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes31(bytes31 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes31)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes32(bytes32 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes32)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n}\\n\",\"keccak256\":\"0x6fa1de4ffe22b8f58b0b64d65db11dd5037be9b9db47b365a72adb489e217000\",\"license\":\"MIT\"},\"contracts/Interfaces/IActivePool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\n/**\\n * The Active Pool holds the ETH collateral and ZUSD debt (but not ZUSD tokens) for all active troves.\\n *\\n * When a trove is liquidated, it's ETH and ZUSD debt are transferred from the Active Pool, to either the\\n * Stability Pool, the Default Pool, or both, depending on the liquidation conditions.\\n *\\n */\\ninterface IActivePool is IPool {\\n // --- Events ---\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolZUSDDebtUpdated(uint _ZUSDDebt);\\n event ActivePoolETHBalanceUpdated(uint _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH amount to given account. Updates ActivePool balance. Only callable by BorrowerOperations, TroveManager or StabilityPool.\\n /// @param _account account to receive the ETH amount\\n /// @param _amount ETH amount to send\\n function sendETH(address _account, uint _amount) external;\\n}\\n\",\"keccak256\":\"0xdd5f1b6fae4050b4c885a85a10c2d0e73b82187a51736d009065aaeea33bf0d0\",\"license\":\"MIT\"},\"contracts/Interfaces/IAllowanceTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title AllowanceTransfer\\n/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface IAllowanceTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an ordered nonce.\\n event NonceInvalidation(\\n address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.\\n event Approval(\\n address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.\\n event Permit(\\n address indexed owner,\\n address indexed token,\\n address indexed spender,\\n uint160 amount,\\n uint48 expiration,\\n uint48 nonce\\n );\\n\\n /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.\\n event Lockdown(address indexed owner, address token, address spender);\\n\\n /// @notice The permit data for a token\\n struct PermitDetails {\\n // ERC20 token address\\n address token;\\n // the maximum amount allowed to spend\\n uint160 amount;\\n // timestamp at which a spender's token allowances become invalid\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice The permit message signed for a single token allowance\\n struct PermitSingle {\\n // the permit data for a single token alownce\\n PermitDetails details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The permit message signed for multiple token allowances\\n struct PermitBatch {\\n // the permit data for multiple token allowances\\n PermitDetails[] details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The saved permissions\\n /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n struct PackedAllowance {\\n // amount allowed\\n uint160 amount;\\n // permission expiry\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice A token spender pair.\\n struct TokenSpenderPair {\\n // the token the spender is approved\\n address token;\\n // the spender address\\n address spender;\\n }\\n\\n /// @notice Details for a token transfer.\\n struct AllowanceTransferDetails {\\n // the owner of the token\\n address from;\\n // the recipient of the token\\n address to;\\n // the amount of the token\\n uint160 amount;\\n // the token to be transferred\\n address token;\\n }\\n\\n /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.\\n /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]\\n /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.\\n function allowance(address user, address token, address spender)\\n external\\n view\\n returns (uint160 amount, uint48 expiration, uint48 nonce);\\n\\n /// @notice Approves the spender to use up to amount of the specified token up until the expiration\\n /// @param token The token to approve\\n /// @param spender The spender address to approve\\n /// @param amount The approved amount of the token\\n /// @param expiration The timestamp at which the approval is no longer valid\\n /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n function approve(address token, address spender, uint160 amount, uint48 expiration) external;\\n\\n /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitSingle Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;\\n\\n /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitBatch Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;\\n\\n /// @notice Transfer approved tokens from one address to another\\n /// @param from The address to transfer from\\n /// @param to The address of the recipient\\n /// @param amount The amount of the token to transfer\\n /// @param token The token address to transfer\\n /// @dev Requires the from address to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(address from, address to, uint160 amount, address token) external;\\n\\n /// @notice Transfer approved tokens in a batch\\n /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers\\n /// @dev Requires the from addresses to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;\\n\\n /// @notice Enables performing a \\\"lockdown\\\" of the sender's Permit2 identity\\n /// by batch revoking approvals\\n /// @param approvals Array of approvals to revoke.\\n function lockdown(TokenSpenderPair[] calldata approvals) external;\\n\\n /// @notice Invalidate nonces for a given (token, spender) pair\\n /// @param token The token to invalidate nonces for\\n /// @param spender The spender to invalidate nonces for\\n /// @param newNonce The new nonce to set. Invalidates all nonces less than it.\\n /// @dev Can't invalidate more than 2**16 nonces per transaction.\\n function invalidateNonces(address token, address spender, uint48 newNonce) external;\\n}\\n\",\"keccak256\":\"0xf15059fb68f89542908f963f22e18c0b0ae9997a6f9aaf6a9fb46aa2424acac9\",\"license\":\"MIT\"},\"contracts/Interfaces/IBorrowerOperations.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface IBorrowerOperations {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event TroveCreated(address indexed _borrower, uint256 arrayIndex);\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event ZUSDBorrowingFeePaid(address indexed _borrower, uint256 _ZUSDFee);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeDistributorAddress feeDistributor contract address\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _defaultPoolAddress DefaultPool contract address\\n * @param _stabilityPoolAddress StabilityPool contract address\\n * @param _gasPoolAddress GasPool contract address\\n * @param _collSurplusPoolAddress CollSurplusPool contract address\\n * @param _priceFeedAddress PrideFeed contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n address _feeDistributorAddress,\\n address _liquityBaseParamsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _defaultPoolAddress,\\n address _stabilityPoolAddress,\\n address _gasPoolAddress,\\n address _collSurplusPoolAddress,\\n address _priceFeedAddress,\\n address _sortedTrovesAddress,\\n address _zusdTokenAddress,\\n address _zeroStakingAddress\\n ) external;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * This method is identical to `openTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openNueTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /// @notice payable function that adds the received Ether to the caller's active Trove.\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function addColl(address _upperHint, address _lowerHint) external payable;\\n\\n /// @notice send ETH as collateral to a trove. Called by only the Stability Pool.\\n /// @param _user user trove address\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function moveETHGainToTrove(\\n address _user,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice withdraws `_amount` of collateral from the caller\\u2019s Trove.\\n * Executes only if the user has an active Trove, the withdrawal would not pull the user\\u2019s Trove below the minimum collateralization ratio,\\n * and the resulting total collateralization ratio of the system is above 150%.\\n * @param _amount collateral amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawColl(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice issues `_amount` of ZUSD from the caller\\u2019s Trove to the caller.\\n * Executes only if the Trove's collateralization ratio would remain above the minimum, and the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _amount ZUSD amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawZUSD(\\n uint256 _maxFee,\\n uint256 _amount,\\n address _upperHint,\\n address _lowerHint\\n ) external;\\n\\n /// Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction\\n function withdrawZusdAndConvertToDLLR(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external returns (uint256);\\n\\n /// @notice repay `_amount` of ZUSD to the caller\\u2019s Trove, subject to leaving 50 debt in the Trove (which corresponds to the 50 ZUSD gas compensation).\\n /// @param _amount ZUSD amount to repay\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function repayZUSD(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLR(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLRWithPermit2(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a ZUSD balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` ZUSD.\\n */\\n function closeTrove() external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTrove(IMassetManager.PermitParams calldata _permitParams) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTroveWithPermit2(ISignatureTransfer.PermitTransferFrom memory _permit, bytes calldata _signature) external;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTroveWithPermit2(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external payable;\\n\\n /**\\n * @notice when a borrower\\u2019s Trove has been fully redeemed from and closed, or liquidated in Recovery Mode with a collateralization ratio above 110%,\\n * this function allows the borrower to claim their ETH collateral surplus that remains in the system (collateral - debt upon redemption; collateral - 110% of the debt upon liquidation).\\n */\\n function claimCollateral() external;\\n\\n function getCompositeDebt(uint256 _debt) external view returns (uint256);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint256);\\n\\n function getMassetManager() external view returns (IMassetManager);\\n}\\n\",\"keccak256\":\"0x75da117f4bc4cca15fc16ca0466c68894f1befed0471ea7a670fa9b466ef2bc5\",\"license\":\"MIT\"},\"contracts/Interfaces/ICollSurplusPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ICollSurplusPool {\\n // --- Events ---\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n\\n event CollBalanceUpdated(address indexed _account, uint256 _newBalance);\\n event EtherSent(address _to, uint256 _amount);\\n\\n // --- Contract setters ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH state variable\\n function getETH() external view returns (uint256);\\n\\n /// @param _account account to retrieve collateral\\n /// @return collateral\\n function getCollateral(address _account) external view returns (uint256);\\n\\n /// @notice adds amount to current account balance. Only callable by TroveManager.\\n /// @param _account account to add amount\\n /// @param _amount amount to add\\n function accountSurplus(address _account, uint256 _amount) external;\\n\\n /// @notice claims collateral for given account. Only callable by BorrowerOperations.\\n /// @param _account account to send claimable collateral\\n function claimColl(address _account) external;\\n}\\n\",\"keccak256\":\"0xac983936efe70d19205bff65a18b4e6000d489d4e4d1e2e92f951873cee91048\",\"license\":\"MIT\"},\"contracts/Interfaces/IDefaultPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\ninterface IDefaultPool is IPool {\\n // --- Events ---\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event DefaultPoolZUSDDebtUpdated(uint256 _ZUSDDebt);\\n event DefaultPoolETHBalanceUpdated(uint256 _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH to Active Pool\\n /// @param _amount ETH to send\\n function sendETHToActivePool(uint256 _amount) external;\\n}\\n\",\"keccak256\":\"0xfb2607676b2eb0f2defd248b4dd32895820048317f29aa6bdb572403a3e3d44e\",\"license\":\"MIT\"},\"contracts/Interfaces/IEIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\ninterface IEIP712 {\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xff52e9168eaa532ebacdad2ab6197f60171e3aa2fa2c1d6397d9da4d7782a543\",\"license\":\"MIT\"},\"contracts/Interfaces/IFeeDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/// Common interface for Fee Distributor.\\ninterface IFeeDistributor {\\n // --- Events ---\\n\\n event FeeSharingCollectorAddressChanged(address _feeSharingCollectorAddress);\\n event ZeroStakingAddressChanged(address _zeroStakingAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event WrbtcAddressChanged(address _wrbtcAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event ZUSDDistributed(uint256 _zusdDistributedAmount);\\n event RBTCistributed(uint256 _rbtcDistributedAmount);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeSharingCollectorAddress FeeSharingCollector address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n * @param _borrowerOperationsAddress borrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _wrbtcAddress wrbtc ERC20 contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _feeSharingCollectorAddress,\\n address _zeroStakingAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _wrbtcAddress,\\n address _zusdTokenAddress,\\n address _activePoolAddress\\n ) external;\\n\\n function distributeFees() external;\\n}\\n\",\"keccak256\":\"0x4b9bc6eaa8a9ea5e0570ffd84c0af2a92e74b001ae1ee1c8518d76382691a07f\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPriceFeed.sol\\\";\\nimport \\\"./ILiquityBaseParams.sol\\\";\\n\\ninterface ILiquityBase {\\n /// @return PriceFeed contract\\n function priceFeed() external view returns (IPriceFeed);\\n\\n /// @return LiquityBaseParams contract\\n function liquityBaseParams() external view returns (ILiquityBaseParams);\\n}\\n\",\"keccak256\":\"0xa4a57bd79e64d56a687c28d2a35c55b733fde8dda2a7ba861606eed3211724e1\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBaseParams.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ILiquityBaseParams {\\n\\n /// Minimum collateral ratio for individual troves\\n function MCR() external view returns (uint);\\n\\n /// Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.\\n function CCR() external view returns (uint);\\n\\n function PERCENT_DIVISOR() external view returns (uint);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint);\\n\\n /**\\n * Half-life of 12h. 12h = 720 min\\n * (1/2) = d^720 => d = (1/2)^(1/720)\\n */\\n function REDEMPTION_FEE_FLOOR() external view returns (uint);\\n\\n function MAX_BORROWING_FEE() external view returns (uint);\\n\\n}\",\"keccak256\":\"0xef8c0e8ad5d13d604c11b04983ff5bdd41768b646f2b33f45ddd988adec204e0\",\"license\":\"MIT\"},\"contracts/Interfaces/IPermit2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {ISignatureTransfer} from \\\"./ISignatureTransfer.sol\\\";\\nimport {IAllowanceTransfer} from \\\"./IAllowanceTransfer.sol\\\";\\n\\n/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer.\\n/// @dev Users must approve Permit2 before calling any of the transfer functions.\\ninterface IPermit2 is ISignatureTransfer, IAllowanceTransfer {\\n// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval.\\n}\\n\",\"keccak256\":\"0x3df819f5ca8de7324a676839d72e9f44c0f789c41c13bf0a892f3bb98d72ee86\",\"license\":\"MIT\"},\"contracts/Interfaces/IPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the Pools.\\ninterface IPool {\\n // --- Events ---\\n\\n event ETHBalanceUpdated(uint _newBalance);\\n event ZUSDBalanceUpdated(uint _newBalance);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event EtherSent(address _to, uint _amount);\\n\\n // --- Functions ---\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH pool balance\\n function getETH() external view returns (uint);\\n\\n /// @return ZUSD debt pool balance\\n function getZUSDDebt() external view returns (uint);\\n\\n /// @notice Increases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to add to the pool debt\\n function increaseZUSDDebt(uint _amount) external;\\n\\n /// @notice Decreases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to subtract to the pool debt\\n function decreaseZUSDDebt(uint _amount) external;\\n}\\n\",\"keccak256\":\"0x148e87ab38c6176d74f36c9e8989b99e768a7b18d8a045f1f01d6583b986806d\",\"license\":\"MIT\"},\"contracts/Interfaces/IPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IPriceFeed {\\n // --- Events ---\\n event LastGoodPriceUpdated(uint256 _lastGoodPrice);\\n\\n // --- Function ---\\n\\n /// @notice Returns the latest price obtained from the Oracle. Called by Zero functions that require a current price.\\n /// It uses the main price feed and fallback to the backup one in case of an error. If both fail return the last\\n /// good price seen.\\n /// @dev It's also callable by anyone externally\\n /// @return The price\\n function fetchPrice() external returns (uint256);\\n}\\n\",\"keccak256\":\"0x85fd97219a8156209d2cb5c6ae7c5ead01d893db000bf575023fcef0e62f9591\",\"license\":\"MIT\"},\"contracts/Interfaces/ISignatureTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title SignatureTransfer\\n/// @notice Handles ERC20 token transfers through signature based actions\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface ISignatureTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an unordered nonce.\\n event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);\\n\\n /// @notice The token and amount details for a transfer signed in the permit transfer signature\\n struct TokenPermissions {\\n // ERC20 token address\\n address token;\\n // the maximum amount that can be spent\\n uint256 amount;\\n }\\n\\n /// @notice The signed permit message for a single token transfer\\n struct PermitTransferFrom {\\n TokenPermissions permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice Specifies the recipient address and amount for batched transfers.\\n /// @dev Recipients and amounts correspond to the index of the signed token permissions array.\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount.\\n struct SignatureTransferDetails {\\n // recipient address\\n address to;\\n // spender requested amount\\n uint256 requestedAmount;\\n }\\n\\n /// @notice Used to reconstruct the signed permit message for multiple token transfers\\n /// @dev Do not need to pass in spender address as it is required that it is msg.sender\\n /// @dev Note that a user still signs over a spender address\\n struct PermitBatchTransferFrom {\\n // the tokens and corresponding amounts permitted for a transfer\\n TokenPermissions[] permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection\\n /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order\\n /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce\\n /// @dev It returns a uint256 bitmap\\n /// @dev The index, or wordPosition is capped at type(uint248).max\\n function nonceBitmap(address, uint256) external view returns (uint256);\\n\\n /// @notice Transfers a token using a signed permit message\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails The spender's requested transfer details for the permitted token\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitTransferFrom memory permit,\\n SignatureTransferDetails calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Transfers multiple tokens using a signed permit message\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails Specifies the recipient and requested amount for the token transfer\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitBatchTransferFrom memory permit,\\n SignatureTransferDetails[] calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Invalidates the bits specified in mask for the bitmap at the word position\\n /// @dev The wordPos is maxed at type(uint248).max\\n /// @param wordPos A number to index the nonceBitmap at\\n /// @param mask A bitmap masked against msg.sender's current bitmap at the word position\\n function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;\\n}\\n\",\"keccak256\":\"0x7efc63c119694e23dd76e44a5b125999829026bbc23409de7646a6a45e1ac341\",\"license\":\"MIT\"},\"contracts/Interfaces/ISortedTroves.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the SortedTroves Doubly Linked List.\\ninterface ISortedTroves {\\n // --- Events ---\\n\\n event SortedTrovesAddressChanged(address _sortedDoublyLLAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event NodeAdded(address _id, uint256 _NICR);\\n event NodeRemoved(address _id);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts and size. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _size max size of troves list\\n * @param _TroveManagerAddress TroveManager contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n */\\n function setParams(\\n uint256 _size,\\n address _TroveManagerAddress,\\n address _borrowerOperationsAddress\\n ) external;\\n\\n /**\\n * @dev Add a node to the list\\n * @param _id Node's id\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function insert(\\n address _id,\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Remove a node from the list\\n * @param _id Node's id\\n */\\n function remove(address _id) external;\\n\\n /**\\n * @dev Re-insert the node at a new position, based on its new NICR\\n * @param _id Node's id\\n * @param _newICR Node's new NICR\\n * @param _prevId Id of previous node for the new insert position\\n * @param _nextId Id of next node for the new insert position\\n */\\n function reInsert(\\n address _id,\\n uint256 _newICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Checks if the list contains a node\\n * @param _id Node's id\\n * @return true if list contains a node with given id\\n */\\n function contains(address _id) external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is full\\n * @return true if list is full\\n */\\n function isFull() external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is empty\\n * @return true if list is empty\\n */\\n function isEmpty() external view returns (bool);\\n\\n /**\\n * @return list current size\\n */\\n function getSize() external view returns (uint256);\\n\\n /**\\n * @return list max size\\n */\\n function getMaxSize() external view returns (uint256);\\n\\n /**\\n * @return the first node in the list (node with the largest NICR)\\n */\\n function getFirst() external view returns (address);\\n\\n /**\\n * @return the last node in the list (node with the smallest NICR)\\n */\\n function getLast() external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the next node (with a smaller NICR) in the list for a given node\\n */\\n function getNext(address _id) external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the previous node (with a larger NICR) in the list for a given node\\n */\\n function getPrev(address _id) external view returns (address);\\n\\n /**\\n * @notice Check if a pair of nodes is a valid insertion point for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function validInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (bool);\\n\\n /**\\n * @notice Find the insert position for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function findInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (address, address);\\n}\\n\",\"keccak256\":\"0x7328ad009da6230ddea1559564428464a5c3ace2258fb534dfbba5b5a8c7c60d\",\"license\":\"MIT\"},\"contracts/Interfaces/IStabilityPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/*\\n * The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors.\\n *\\n * When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with\\n * ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned.\\n *\\n * Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits.\\n * They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors,\\n * in the same proportion.\\n *\\n * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40%\\n * of the total ZUSD in the Stability Pool, depletes 40% of each deposit.\\n *\\n * A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit,\\n * multiplying it by some factor in range ]0,1[\\n *\\n * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations:\\n * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf\\n *\\n * --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS ---\\n *\\n * An SOV issuance event occurs at every deposit operation, and every liquidation.\\n *\\n * Each deposit is tagged with the address of the front end through which it was made.\\n *\\n * All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned\\n * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate.\\n *\\n * Please see the system Readme for an overview:\\n * https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers\\n */\\ninterface IStabilityPool {\\n // --- Events ---\\n\\n event StabilityPoolETHBalanceUpdated(uint _newBalance);\\n event StabilityPoolZUSDBalanceUpdated(uint _newBalance);\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event SortedTrovesAddressChanged(address _newSortedTrovesAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);\\n\\n event P_Updated(uint _P);\\n event S_Updated(uint _S, uint128 _epoch, uint128 _scale);\\n event G_Updated(uint _G, uint128 _epoch, uint128 _scale);\\n event EpochUpdated(uint128 _currentEpoch);\\n event ScaleUpdated(uint128 _currentScale);\\n\\n event FrontEndRegistered(address indexed _frontEnd, uint _kickbackRate);\\n event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd);\\n\\n event DepositSnapshotUpdated(address indexed _depositor, uint _P, uint _S, uint _G);\\n event FrontEndSnapshotUpdated(address indexed _frontEnd, uint _P, uint _G);\\n event UserDepositChanged(address indexed _depositor, uint _newDeposit);\\n event FrontEndStakeChanged(\\n address indexed _frontEnd,\\n uint _newFrontEndStake,\\n address _depositor\\n );\\n\\n event ETHGainWithdrawn(address indexed _depositor, uint _ETH, uint _ZUSDLoss);\\n event SOVPaidToDepositor(address indexed _depositor, uint _SOV);\\n event SOVPaidToFrontEnd(address indexed _frontEnd, uint _SOV);\\n event EtherSent(address _to, uint _amount);\\n\\n event WithdrawFromSpAndConvertToDLLR(\\n address _depositor,\\n uint256 _zusdAmountRequested,\\n uint256 _dllrAmountReceived\\n );\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Liquity contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _priceFeedAddress PriceFeed contract address\\n * @param _communityIssuanceAddress CommunityIssuanceAddress\\n */\\n function setAddresses(\\n address _liquityBaseParamsAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _zusdTokenAddress,\\n address _sortedTrovesAddress,\\n address _priceFeedAddress,\\n address _communityIssuanceAddress\\n ) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend is registered or zero address\\n * - Sender is not a registered frontend\\n * - _amount is not zero\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Tags the deposit with the provided front end tag param, if it's a new deposit\\n * - Sends depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Increases deposit and tagged front end's stake, and takes new snapshots for each.\\n * @param _amount amount to provide\\n * @param _frontEndTag frontend address to receive accumulated SOV gains\\n */\\n function provideToSP(uint _amount, address _frontEndTag) external;\\n\\n /**\\n * @notice Initial checks:\\n * - _amount is zero or there are no under collateralized troves left in the system\\n * - User has a non zero deposit\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Removes the deposit's front end tag if it is a full withdrawal\\n * - Sends all depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.\\n *\\n * If _amount > userDeposit, the user withdraws all of their compounded deposit.\\n * @param _amount amount to withdraw\\n */\\n function withdrawFromSP(uint _amount) external;\\n\\n /**\\n * @notice Initial checks:\\n * - User has a non zero deposit\\n * - User has an open trove\\n * - User has some ETH gain\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Sends all depositor's SOV gain to depositor\\n * - Sends all tagged front end's SOV gain to the tagged front end\\n * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove\\n * - Leaves their compounded deposit in the Stability Pool\\n * - Updates snapshots for deposit and tagged front end stake\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend (sender) not already registered\\n * - User (sender) has no deposit\\n * - _kickbackRate is in the range [0, 100%]\\n * ---\\n * Front end makes a one-time selection of kickback rate upon registering\\n * @param _kickbackRate kickback rate selected by frontend\\n */\\n function registerFrontEnd(uint _kickbackRate) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Caller is TroveManager\\n * ---\\n * Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible)\\n * and transfers the Trove's ETH collateral from ActivePool to StabilityPool.\\n * Only called by liquidation functions in the TroveManager.\\n * @param _debt debt to cancel\\n * @param _coll collateral to transfer\\n */\\n function offset(uint _debt, uint _coll) external;\\n\\n /**\\n * @return the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`,\\n * to exclude edge cases like ETH received from a self-destruct.\\n */\\n function getETH() external view returns (uint);\\n\\n /**\\n * @return ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\\n */\\n function getTotalZUSDDeposits() external view returns (uint);\\n\\n /**\\n * @notice Calculates the ETH gain earned by the deposit since its last snapshots were taken.\\n * @param _depositor address to calculate ETH gain\\n * @return ETH gain from given depositor\\n */\\n function getDepositorETHGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice Calculate the SOV gain earned by a deposit since its last snapshots were taken.\\n * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned.\\n * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through\\n * which they made their deposit.\\n * @param _depositor address to calculate ETH gain\\n * @return SOV gain from given depositor\\n */\\n function getDepositorSOVGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @param _frontEnd front end address\\n * @return the SOV gain earned by the front end.\\n */\\n function getFrontEndSOVGain(address _frontEnd) external view returns (uint);\\n\\n /**\\n * @param _depositor depositor address\\n * @return the user's compounded deposit.\\n */\\n function getCompoundedZUSDDeposit(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\\n * @param _frontEnd front end address\\n * @return the front end's compounded stake.\\n */\\n function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint);\\n\\n //DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDLLR(\\n uint _dllrAmount,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function provideToSpFromDllrWithPermit2(\\n uint256 _dllrAmount,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /// Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and optionally convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\\n function withdrawFromSpAndConvertToDLLR(uint256 _zusdAmount) external;\\n\\n /**\\n * Fallback function\\n * Only callable by Active Pool, it just accounts for ETH received\\n * receive() external payable;\\n */\\n}\\n\",\"keccak256\":\"0xb35c5ec991dd2b4f8ecb6b28ae29e97313fca6054aa0df14ebdb7336fcea84a6\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROStaking.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IZEROStaking {\\n // --- Events --\\n\\n event ZEROTokenAddressSet(address _zeroTokenAddress);\\n event ZUSDTokenAddressSet(address _zusdTokenAddress);\\n event FeeDistributorAddressAddressSet(address _feeDistributorAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event StakeChanged(address indexed staker, uint256 newStake);\\n event StakingGainsWithdrawn(address indexed staker, uint256 ZUSDGain, uint256 ETHGain);\\n event F_ETHUpdated(uint256 _F_ETH);\\n event F_ZUSDUpdated(uint256 _F_ZUSD);\\n event TotalZEROStakedUpdated(uint256 _totalZEROStaked);\\n event EtherSent(address _account, uint256 _amount);\\n event StakerSnapshotsUpdated(address _staker, uint256 _F_ETH, uint256 _F_ZUSD);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _zeroTokenAddress ZEROToken contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _feeDistributorAddress FeeDistributorAddress contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _zeroTokenAddress,\\n address _zusdTokenAddress,\\n address _feeDistributorAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice If caller has a pre-existing stake, send any accumulated ETH and ZUSD gains to them.\\n /// @param _ZEROamount ZERO tokens to stake\\n function stake(uint256 _ZEROamount) external;\\n\\n /**\\n * @notice Unstake the ZERO and send the it back to the caller, along with their accumulated ZUSD & ETH gains.\\n * If requested amount > stake, send their entire stake.\\n * @param _ZEROamount ZERO tokens to unstake\\n */\\n function unstake(uint256 _ZEROamount) external;\\n\\n /// @param _ETHFee ETH fee\\n /// @notice increase ETH fee\\n function increaseF_ETH(uint256 _ETHFee) external;\\n\\n /// @param _ZEROFee ZUSD fee\\n /// @notice increase ZUSD fee\\n function increaseF_ZUSD(uint256 _ZEROFee) external;\\n\\n /// @param _user user address\\n /// @return pending ETH gain of given user\\n function getPendingETHGain(address _user) external view returns (uint256);\\n\\n /// @param _user user address\\n /// @return pending ZUSD gain of given user\\n function getPendingZUSDGain(address _user) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x4c7948ce7dff9ea9b8495054e511eabcf44a91c7db8520ec58ff2a002327e0c5\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZEROToken is IERC20, IERC2612 { \\n\\n // --- Functions ---\\n\\n /// @notice send zero tokens to ZEROStaking contract\\n /// @param _sender sender address\\n /// @param _amount amount to send\\n function sendToZEROStaking(address _sender, uint256 _amount) external;\\n\\n /// @return deployment start time\\n function getDeploymentStartTime() external view returns (uint256);\\n\\n}\\n\",\"keccak256\":\"0xbcc0baabe4c4686563a09cf1486f2d152b70404996676a89d525691f69637f66\",\"license\":\"MIT\"},\"contracts/Interfaces/IZUSDToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZUSDToken is IERC20, IERC2612 { \\n \\n // --- Events ---\\n\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n\\n event ZUSDTokenBalanceUpdated(address _user, uint _amount);\\n\\n // --- Functions ---\\n\\n function mint(address _account, uint256 _amount) external;\\n\\n function burn(address _account, uint256 _amount) external;\\n\\n function sendToPool(address _sender, address poolAddress, uint256 _amount) external;\\n\\n function returnFromPool(address poolAddress, address user, uint256 _amount ) external;\\n}\\n\",\"keccak256\":\"0xe52df063aa08f709640c28888edd27310c820f6d08564855538ae245eb2f5a8c\",\"license\":\"MIT\"},\"contracts/TroveManagerStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./Interfaces/IStabilityPool.sol\\\";\\nimport \\\"./Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/IZEROToken.sol\\\";\\nimport \\\"./Interfaces/IZEROStaking.sol\\\";\\nimport \\\"./Interfaces/IFeeDistributor.sol\\\";\\nimport \\\"./Dependencies/Ownable.sol\\\";\\nimport \\\"./Dependencies/BaseMath.sol\\\";\\nimport \\\"./Dependencies/console.sol\\\";\\n\\ncontract TroveManagerStorage is Ownable, BaseMath {\\n string public constant NAME = \\\"TroveManager\\\";\\n\\n // --- Connected contract declarations ---\\n\\n address public troveManagerRedeemOps;\\n\\n address public borrowerOperationsAddress;\\n\\n IStabilityPool public _stabilityPool;\\n\\n address gasPoolAddress;\\n\\n ICollSurplusPool collSurplusPool;\\n\\n IZUSDToken public _zusdToken;\\n\\n IZEROToken public _zeroToken;\\n\\n IZEROStaking public _zeroStaking;\\n\\n IFeeDistributor public feeDistributor;\\n\\n // A doubly linked list of Troves, sorted by their sorted by their collateral ratios\\n ISortedTroves public sortedTroves;\\n\\n // --- Data structures ---\\n\\n uint256 public baseRate;\\n\\n // The timestamp of the latest fee operation (redemption or new ZUSD issuance)\\n uint256 public lastFeeOperationTime;\\n\\n enum Status {\\n nonExistent,\\n active,\\n closedByOwner,\\n closedByLiquidation,\\n closedByRedemption\\n }\\n\\n // Store the necessary data for a trove\\n struct Trove {\\n uint256 debt;\\n uint256 coll;\\n uint256 stake;\\n Status status;\\n uint128 arrayIndex;\\n }\\n\\n mapping(address => Trove) public Troves;\\n\\n uint256 public totalStakes;\\n\\n // Snapshot of the value of totalStakes, taken immediately after the latest liquidation\\n uint256 public totalStakesSnapshot;\\n\\n // Snapshot of the total collateral across the ActivePool and DefaultPool, immediately after the latest liquidation.\\n uint256 public totalCollateralSnapshot;\\n\\n /*\\n * L_ETH and L_ZUSDDebt track the sums of accumulated liquidation rewards per unit staked. During its lifetime, each stake earns:\\n *\\n * An ETH gain of ( stake * [L_ETH - L_ETH(0)] )\\n * A ZUSDDebt increase of ( stake * [L_ZUSDDebt - L_ZUSDDebt(0)] )\\n *\\n * Where L_ETH(0) and L_ZUSDDebt(0) are snapshots of L_ETH and L_ZUSDDebt for the active Trove taken at the instant the stake was made\\n */\\n uint256 public L_ETH;\\n uint256 public L_ZUSDDebt;\\n\\n // Map addresses with active troves to their RewardSnapshot\\n mapping(address => RewardSnapshot) public rewardSnapshots;\\n\\n // Object containing the ETH and ZUSD snapshots for a given active trove\\n struct RewardSnapshot {\\n uint256 ETH;\\n uint256 ZUSDDebt;\\n }\\n\\n // Array of all active trove addresses - used to to compute an approximate hint off-chain, for the sorted list insertion\\n address[] public TroveOwners;\\n\\n // Error trackers for the trove redistribution calculation\\n uint256 public lastETHError_Redistribution;\\n uint256 public lastZUSDDebtError_Redistribution;\\n}\\n\",\"keccak256\":\"0x979836e7db9988074cd7cbbaaa94d67a297a078a8f93ceb14430ffe548545145\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60c06040523480156200001157600080fd5b5060405162003dfe38038062003dfe833981016040819052620000349162000128565b8162000049336001600160e01b036200006316565b60805260601b6001600160601b03191660a05250620001c4565b6001600160a01b038116620000955760405162461bcd60e51b81526004016200008c9062000182565b60405180910390fd5b6001600160a01b038116620000b26001600160e01b036200010716565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f79062000165565b6040519081900390209190915550565b600080604051620001189062000165565b6040519081900390205492915050565b600080604083850312156200013b578182fd5b825160208401519092506001600160a01b03811681146200015a578182fd5b809150509250929050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160a05160601c613c09620001f56000398061059f5280610b08525080610bdc5280611d565250613c096000f3fe608060405234801561001057600080fd5b506004361061028a5760003560e01c8063797250e31161015c578063a3f4df7e116100ce578063bf9befb111610087578063bf9befb114610486578063c35bc5501461048e578063c7b5548114610496578063d380a37c1461049e578063d815e8e9146104a6578063e056e918146104ae5761028a565b8063a3f4df7e1461043e578063ae7bec1914610453578063ae9187541461045b578063b7f8cf9b14610463578063bcd375261461046b578063be4b03341461047e5761028a565b8063893d20e811610120578063893d20e81461040b57806396d711ff146104135780639708daf41461041b5780639dd233d21461042e5780639f07067014610436578063a20baee6146103b05761028a565b8063797250e3146103e35780637cf54e40146103eb5780637f7dde4a146103f3578063807d138d146103fb578063887105d3146104035761028a565b80633cc7422511610200578063716c47e6116101b9578063716c47e6146103a857806372fe25aa146103b0578063741bef1a146103b8578063756b253e146103c0578063759b3034146103d3578063795d26c3146103db5761028a565b80633cc742251461034657806342ccf1e41461034e5780634a767d681461036157806361ec893d146103745780636b4449521461037c5780636ef64338146103845761028a565b80631673c79a116102525780631673c79a146102f25780631a59a50e146103135780631bf43555146103265780631f68f20a1461032e57806331c903b0146103365780633a1285951461033e5761028a565b806305b6f5ca1461028f578063071a7541146102a45780630d43e8ad146102c257806312261ee7146102d757806313af4035146102df575b600080fd5b6102a261029d3660046132d7565b6104ce565b005b6102ac610589565b6040516102b99190613b05565b60405180910390f35b6102ca61058e565b6040516102b991906134cd565b6102ca61059d565b6102a26102ed3660046131b7565b6105c1565b6103056103003660046131b7565b61060e565b6040516102b9929190613b0e565b6102ac6103213660046131b7565b610627565b6102ac6106ef565b6102ac6106fc565b6102ac610702565b6102ca610714565b6102ca610723565b6102ac61035c3660046131b7565b610732565b6102ac61036f3660046131ef565b610763565b6102ac61078e565b6102ac610793565b6103976103923660046131b7565b610799565b6040516102b9959493929190613b1c565b6102ca6107d3565b6102ac6107e2565b6102ca6107ee565b6102ca6103ce36600461323a565b6107fd565b6102ac610824565b6102ac610831565b6102ac610950565b6102ca610956565b6102ca610965565b6102ac610974565b6102ac61097a565b6102ca610a49565b6102ac610a68565b6102a2610429366004613361565b610a6e565b6102ac610b4c565b6102ca610b52565b610446610b61565b6040516102b991906135e4565b6102ca610b89565b6102ca610b98565b6102ca610ba7565b6102a261047936600461326a565b610bb6565b6102ac610bce565b6102ac610bd4565b6102ac610bda565b6102ac610bfe565b6102ac610c0a565b6102ca610c10565b6104c16104bc3660046131b7565b610c1f565b6040516102b991906135ab565b600061056d600560009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561052157600080fd5b505afa158015610535573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055991906131d3565b6009548b906001600160a01b031685610c7d565b905061057e81898989898989610f2e565b505050505050505050565b600281565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6105c9610a49565b6001600160a01b0316336001600160a01b0316146106025760405162461bcd60e51b81526004016105f99061389f565b60405180910390fd5b61060b816116f5565b50565b6016602052600090815260409020805460019091015482565b6001600160a01b0381166000908152601660205260408120546014548290610655908363ffffffff61178016565b905080158061068e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561068b57fe5b14155b1561069e576000925050506106ea565b6001600160a01b038416600090815260106020526040812060020154906106e3670de0b6b3a76400006106d7848663ffffffff6117c916565b9063ffffffff61180316565b9450505050505b919050565b6809c2007651b250000081565b600e5481565b600061070f600e54611845565b905090565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290610655908363ffffffff61178016565b6000806000610771856118ee565b915091506000610782838387611974565b93505050505b92915050565b603c81565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b670de0b6b3a764000081565b6002546001600160a01b031681565b6017818154811061080a57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b15801561087557600080fd5b505afa158015610889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ad9190613252565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ff57600080fd5b505afa158015610913573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109379190613252565b9050610949828263ffffffff6119a616565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156109bf57600080fd5b505afa1580156109d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f79190613252565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ff57600080fd5b600080604051610a58906134b0565b6040519081900390205492915050565b60135481565b6000610b2e600560009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b158015610ac157600080fd5b505afa158015610ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af991906131d3565b6009546001600160a01b0316867f000000000000000000000000000000000000000000000000000000000000000087876119cb565b9050610b3f818b8b8b8b8b8b610f2e565b5050505050505050505050565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b6005546001600160a01b031681565b610bc587878787878787610f2e565b50505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b670ddd4b8c6c7d70d881565b600f5481565b6009546001600160a01b031681565b600060016001600160a01b03831660009081526010602052604090206003015460ff166004811115610c4d57fe5b14610c5a575060006106ea565b506014546001600160a01b03821660009081526016602052604090205410919050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015610cb957600080fd5b505afa158015610ccd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf191906131d3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610d2191906134cd565b60206040518083038186803b158015610d3957600080fd5b505afa158015610d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d719190613252565b9050306001600160a01b03831663605629d633838a8935610d9860408c0160208d01613477565b8b604001358c606001356040518863ffffffff1660e01b8152600401610dc497969594939291906134e1565b600060405180830381600087803b158015610dde57600080fd5b505af1158015610df2573d6000803e3d6000fd5b5050505086610e8383856001600160a01b03166370a08231856040518263ffffffff1660e01b8152600401610e2791906134cd565b60206040518083038186803b158015610e3f57600080fd5b505afa158015610e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e779190613252565b9063ffffffff61178016565b14610ea05760405162461bcd60e51b81526004016105f9906136ab565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390610ed09089908b90339060040161355d565b602060405180830381600087803b158015610eea57600080fd5b505af1158015610efe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f229190613252565b98975050505050505050565b610f366130b5565b506040805160e0810182526000546001600160a01b03908116825260015481166020830152600954811692820192909252600b5482166060820152600d5482166080820152600854821660a082015260075490911660c0820152610f986130f1565b610fa183611c18565b610fa9611cd1565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610ff957600080fd5b505af115801561100d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110319190613252565b60c0820181905261104190611d9f565b61104a89611e4c565b6110598260400151338b611e6c565b611061610831565b60e0820181905260408084015190516370a0823160e01b81526001600160a01b03909116906370a082319061109a9033906004016134cd565b60206040518083038186803b1580156110b257600080fd5b505afa1580156110c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ea9190613252565b11156110f257fe5b888152608082015160c082015160009161110d918b90611f0d565b156111195750876112c6565b82608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561115657600080fd5b505afa15801561116a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118e91906131d3565b90505b6001600160a01b0381161580159061123a5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156111f257600080fd5b505afa158015611206573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122a9190613252565b611238828460c00151610763565b105b156112c65782608001516001600160a01b031663b72703ac826040518263ffffffff1660e01b815260040161126f91906134cd565b60206040518083038186803b15801561128757600080fd5b505afa15801561129b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bf91906131d3565b9050611191565b846112d15760001994505b6001600160a01b038116158015906112e95750815115155b80156112f55750600085115b15611423576080830151604051632dc9c0eb60e21b8152600019909601956000916001600160a01b03169063b72703ac906113349085906004016134cd565b60206040518083038186803b15801561134c57600080fd5b505afa158015611360573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138491906131d3565b90506113998460000151856020015184612170565b6113a1613136565b6113b8858486600001518760c001518e8e8e612281565b90508060400151156113cb575050611423565b805160208501516113e19163ffffffff6119a616565b60208086019190915281015160408501516114019163ffffffff6119a616565b6040850152805184516114199163ffffffff61178016565b84525090506112d1565b60008260400151116114475760405162461bcd60e51b81526004016105f9906136f4565b61145e82604001518360c001518460e001516124f5565b5061146c82604001516125ac565b6060830181905260408301516114839190866125bf565b8251600c5460608401516040516364a197f360e01b81526001600160a01b03938416936364a197f3936114bb93911691600401613522565b600060405180830381600087803b1580156114d557600080fd5b505af11580156114e9573d6000803e3d6000fd5b50505050600c60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561153d57600080fd5b505af1158015611551573d6000803e3d6000fd5b505050506060820151604083015161156891611780565b60808301526020820151604080840151606085015191517f43a3f4082a4dbc33d78e317d2497d3a730bc7fc3574159dcea1056e62e5d9ad8936115ae938f939192613b5c565b60405180910390a182604001516001600160a01b0316639dc29fac3384602001516040518363ffffffff1660e01b81526004016115ec929190613522565b600060405180830381600087803b15801561160657600080fd5b505af115801561161a573d6000803e3d6000fd5b50508451602085015160405163121cbc4d60e11b81526001600160a01b039092169350632439789a925061165091600401613b05565b600060405180830381600087803b15801561166a57600080fd5b505af115801561167e573d6000803e3d6000fd5b5050845160808501516040516364a197f360e01b81526001600160a01b0390921693506364a197f392506116b791339190600401613522565b600060405180830381600087803b1580156116d157600080fd5b505af11580156116e5573d6000803e3d6000fd5b5050505050505050505050505050565b6001600160a01b03811661171b5760405162461bcd60e51b81526004016105f990613774565b806001600160a01b031661172d610a49565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611770906134b0565b6040519081900390209190915550565b60006117c283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612605565b9392505050565b6000826117d857506000610788565b828202828482816117e557fe5b04146117c25760405162461bcd60e51b81526004016105f99061385e565b60006117c283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612631565b60006107886118e083600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561189c57600080fd5b505afa1580156118b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d49190613252565b9063ffffffff6119a616565b670de0b6b3a7640000612668565b60008060006118fc84610627565b9050600061190985610732565b6001600160a01b03861660009081526010602052604081206001015491925090611939908463ffffffff6119a616565b6001600160a01b03871660009081526010602052604081205491925090611966908463ffffffff6119a616565b919550909350505050915091565b6000821561199b576000611992846106d7878663ffffffff6117c916565b91506117c29050565b506000199392505050565b6000828201838110156117c25760405162461bcd60e51b81526004016105f99061373d565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015611a0757600080fd5b505afa158015611a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3f91906131d3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611a6f91906134cd565b60206040518083038186803b158015611a8757600080fd5b505afa158015611a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abf9190613252565b87516020015190915030906001600160a01b0388166330f28b7a8a611ae4858561267e565b338b8b6040518663ffffffff1660e01b8152600401611b07959493929190613a94565b600060405180830381600087803b158015611b2157600080fd5b505af1158015611b35573d6000803e3d6000fd5b5050505080611b6a84866001600160a01b03166370a08231866040518263ffffffff1660e01b8152600401610e2791906134cd565b14611b875760405162461bcd60e51b81526004016105f9906136ab565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390611bb7908d908590339060040161355d565b602060405180830381600087803b158015611bd157600080fd5b505af1158015611be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c099190613252565b9b9a5050505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c6657600080fd5b505afa158015611c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9e9190613252565b8110158015611cb55750670de0b6b3a76400008111155b61060b5760405162461bcd60e51b81526004016105f990613974565b600a5460408051631e425be160e11b815290516000926001600160a01b031691633c84b7c2916004808301926020929190829003018186803b158015611d1657600080fd5b505afa158015611d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d4e9190613252565b9050611d80817f000000000000000000000000000000000000000000000000000000000000000063ffffffff6119a616565b42101561060b5760405162461bcd60e51b81526004016105f990613800565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015611ded57600080fd5b505afa158015611e01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e259190613252565b611e2e826126b0565b101561060b5760405162461bcd60e51b81526004016105f9906139c4565b6000811161060b5760405162461bcd60e51b81526004016105f9906138d0565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190611e9a9086906004016134cd565b60206040518083038186803b158015611eb257600080fd5b505afa158015611ec6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eea9190613252565b1015611f085760405162461bcd60e51b81526004016105f990613637565b505050565b60006001600160a01b0383161580611f9e5750604051630bb7c8fd60e31b81526001600160a01b03851690635dbe47e890611f4c9086906004016134cd565b60206040518083038186803b158015611f6457600080fd5b505afa158015611f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9c919061321a565b155b806120365750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015611ff257600080fd5b505afa158015612006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202a9190613252565b6120348484610763565b105b15612043575060006117c2565b60405163765e015960e01b81526000906001600160a01b0386169063765e0159906120729087906004016134cd565b60206040518083038186803b15801561208a57600080fd5b505afa15801561209e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c291906131d3565b90506001600160a01b03811615806121675750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561212357600080fd5b505afa158015612137573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215b9190613252565b6121658285610763565b105b95945050505050565b61217981610c1f565b15611f0857612187816126dc565b600061219282610627565b9050600061219f83610732565b6001600160a01b0384166000908152601060205260409020600101549091506121ce908363ffffffff6119a616565b6001600160a01b03841660009081526010602052604090206001810191909155546121ff908263ffffffff6119a616565b6001600160a01b03841660009081526010602052604090205561222183612725565b61222d8585838561278d565b6001600160a01b038316600081815260106020526040808220805460018201546002909201549251600080516020613bb48339815191529461227294929392916135b6565b60405180910390a25050505050565b612289613136565b6001600160a01b0387166000908152601060205260409020546122c69087906122c1906801158e460913d0000063ffffffff61178016565b612668565b8082526122e79086906106d790670de0b6b3a764000063ffffffff6117c916565b60208083019190915281516001600160a01b03891660009081526010909252604082205461231a9163ffffffff61178016565b6020808401516001600160a01b038b1660009081526010909252604082206001015492935090916123509163ffffffff61178016565b90506801158e460913d000008214156123c95761236c896128ad565b6123778960046128fd565b61238c8a8a6801158e460913d0000084612a09565b886001600160a01b0316600080516020613bb4833981519152600080600060036040516123bc94939291906135b6565b60405180910390a26124e7565b60006123d58284612b6c565b905084811415806123f657506809c2007651b25000006123f484612ba1565b105b1561240a57505060016040830152506124ea565b8a608001516001600160a01b0316632be212608b838a8a6040518563ffffffff1660e01b81526004016124409493929190613580565b600060405180830381600087803b15801561245a57600080fd5b505af115801561246e573d6000803e3d6000fd5b5050506001600160a01b038b1660009081526010602052604090208481556001018390555061249c8a612bbc565b506001600160a01b038a1660008181526010602052604090819020600201549051600080516020613bb4833981519152916124dd91879187916003906135b6565b60405180910390a2505b50505b979650505050505050565b600080612500612c63565b90506000612518846106d7888863ffffffff6117c916565b9050600061253d61253083600263ffffffff61180316565b849063ffffffff6119a616565b905061255181670de0b6b3a7640000612668565b90506000811161255d57fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c90612592908390613b05565b60405180910390a16125a2612ca7565b9695505050505050565b60006107886125b9610702565b83612cfc565b60006125dd836106d786670de0b6b3a764000063ffffffff6117c916565b9050818111156125ff5760405162461bcd60e51b81526004016105f990613a0e565b50505050565b600081848411156126295760405162461bcd60e51b81526004016105f991906135e4565b505050900390565b600081836126525760405162461bcd60e51b81526004016105f991906135e4565b50600083858161265e57fe5b0495945050505050565b600081831061267757816117c2565b5090919050565b612686613159565b61268e613159565b5050604080518082019091526001600160a01b03929092168252602082015290565b6000806126bb61097a565b905060006126c7610831565b90506126d4828286611974565b949350505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561270857fe5b1461060b5760405162461bcd60e51b81526004016105f990613a45565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92612782929091613b0e565b60405180910390a150565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a906127b9908590600401613b05565b600060405180830381600087803b1580156127d357600080fd5b505af11580156127e7573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150612817908590600401613b05565b600060405180830381600087803b15801561283157600080fd5b505af1158015612845573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150612875908490600401613b05565b600060405180830381600087803b15801561288f57600080fd5b505af11580156128a3573d6000803e3d6000fd5b5050505050505050565b6001600160a01b0381166000908152601060205260409020600201546011546128dc908263ffffffff61178016565b601155506001600160a01b0316600090815260106020526040812060020155565b600081600481111561290b57fe5b141580156129255750600181600481111561292257fe5b14155b61292b57fe5b60175461293781612d3c565b6001600160a01b0383166000908152601060205260409020600301805483919060ff1916600183600481111561296957fe5b02179055506001600160a01b03831660009081526010602090815260408083206001808201859055908490556016909252822082815501556129ab8382612de2565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e906129db9086906004016134cd565b600060405180830381600087803b1580156129f557600080fd5b505af1158015610bc5573d6000803e3d6000fd5b6040808501516007549151632770a7eb60e21b81526001600160a01b0391821692639dc29fac92612a41929116908690600401613522565b600060405180830381600087803b158015612a5b57600080fd5b505af1158015612a6f573d6000803e3d6000fd5b5050855160405163121cbc4d60e11b81526001600160a01b039091169250632439789a9150612aa2908590600401613b05565b600060405180830381600087803b158015612abc57600080fd5b505af1158015612ad0573d6000803e3d6000fd5b505050508360a001516001600160a01b0316633f10abab84836040518363ffffffff1660e01b8152600401612b06929190613522565b600060405180830381600087803b158015612b2057600080fd5b505af1158015612b34573d6000803e3d6000fd5b5050855160a08701516040516364a197f360e01b81526001600160a01b0390921693506364a197f39250612875918590600401613522565b60008115612b9857612b91826106d78568056bc75e2d6310000063ffffffff6117c916565b9050610788565b50600019610788565b6000610788826801158e460913d0000063ffffffff61178016565b6001600160a01b0381166000908152601060205260408120600101548190612be390612f83565b6001600160a01b038416600090815260106020526040902060020180549082905560115491925090612c219083906118d4908463ffffffff61178016565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae52038291612c5491613b05565b60405180910390a15092915050565b600080612c6e612fbf565b90506000612c84670ddd4b8c6c7d70d883612fdb565b9050610949670de0b6b3a76400006106d783600e546117c990919063ffffffff16565b6000612cbe600f544261178090919063ffffffff16565b9050603c811061060b5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc9161278291613b05565b600080612d1b670de0b6b3a76400006106d7868663ffffffff6117c916565b90508281106117c25760405162461bcd60e51b81526004016105f99061391e565b600181118015612dc65750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b158015612d8c57600080fd5b505afa158015612da0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc49190613252565b115b61060b5760405162461bcd60e51b81526004016105f9906137b6565b6001600160a01b03821660009081526010602052604081206003015460ff1690816004811115612e0e57fe5b14158015612e2857506001816004811115612e2557fe5b14155b612e2e57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b0316908390612e66826001611780565b905080836001600160801b03161115612e7b57fe5b600060178281548110612e8a57fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b038716908110612ebc57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a90612f45908390879061353b565b60405180910390a16017805480612f5857fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b60008060135460001415612f98575081610788565b600060125411612fa457fe5b6117c26013546106d7601254866117c990919063ffffffff16565b600061070f603c6106d7600f544261178090919063ffffffff16565b6000631f540500821115612ff157631f54050091505b816130055750670de0b6b3a7640000610788565b670de0b6b3a764000083835b600181111561307c57600281066130465761302c8283613082565b915061303f81600263ffffffff61180316565b9050613077565b6130508284613082565b925061305c8283613082565b915061307460026106d783600163ffffffff61178016565b90505b613011565b61078282845b600080613095848463ffffffff6117c916565b90506126d4670de0b6b3a76400006106d7836706f05b59d3b200006119a6565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806060016040528060008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b60008083601f840112613181578182fd5b50813567ffffffffffffffff811115613198578182fd5b6020830191508360208285010111156131b057600080fd5b9250929050565b6000602082840312156131c8578081fd5b81356117c281613b9e565b6000602082840312156131e4578081fd5b81516117c281613b9e565b60008060408385031215613201578081fd5b823561320c81613b9e565b946020939093013593505050565b60006020828403121561322b578081fd5b815180151581146117c2578182fd5b60006020828403121561324b578081fd5b5035919050565b600060208284031215613263578081fd5b5051919050565b600080600080600080600060e0888a031215613284578283fd5b87359650602088013561329681613b9e565b955060408801356132a681613b9e565b945060608801356132b681613b9e565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a036101608112156132f4578182fd5b8935985060208a013561330681613b9e565b975060408a013561331681613b9e565b965060608a013561332681613b9e565b955060808a810135955060a08b0135945060c08b0135935060df198201121561334d578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c03610180811215613381578283fd5b8b359a5060208c013561339381613b9e565b995060408c01356133a381613b9e565b985060608c01356133b381613b9e565b975060808c810135975060a08d0135965060c08d0135955060df198201908112156133dc578384fd5b6133e66060613b77565b915060408112156133f5578384fd5b506134006040613b77565b60e08d013561340e81613b9e565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff811115613453578283fd5b61345f8d828e01613170565b8194508093505050509295989b9194979a5092959850565b600060208284031215613488578081fd5b813560ff811681146117c2578182fd5b80516001600160a01b03168252602090810151910152565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b901515815260200190565b848152602081018490526040810183905260808101600483106135d557fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015613610578581018301518582016040015282016135f4565b818111156136215783604083870101525b50601f01601f1916929092016040019392505050565b6020808252604e908201527f54726f76654d616e616765723a2052657175657374656420726564656d70746960408201527f6f6e20616d6f756e74206d757374206265203c3d20757365722773205a55534460608201526d20746f6b656e2062616c616e636560901b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b60208082526029908201527f54726f76654d616e616765723a20556e61626c6520746f2072656465656d20616040820152681b9e48185b5bdd5b9d60ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b602080825260409082018190527f54726f76654d616e616765723a20526564656d7074696f6e7320617265206e6f908201527f7420616c6c6f77656420647572696e6720626f6f747374726170207068617365606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252602e908201527f54726f76654d616e616765723a20416d6f756e74206d7573742062652067726560408201526d61746572207468616e207a65726f60901b606082015260800190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252602a908201527f54726f76654d616e616765723a2043616e6e6f742072656465656d207768656e604082015269102a21a9101e1026a1a960b11b606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b6000610100613aa4838951613498565b6020880151604084015260408801516060840152613ac56080840188613498565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b918252602082015260400190565b858152602081018590526040810184905260a0810160058410613b3b57fe5b60608201939093526001600160801b03919091166080909101529392505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff81118282101715613b9657600080fd5b604052919050565b6001600160a01b038116811461060b57600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212207c16913f9245b09fe846c28a2b84344e3caf87f082e47e49ca0ae21a08915c2b64736f6c634300060b0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061028a5760003560e01c8063797250e31161015c578063a3f4df7e116100ce578063bf9befb111610087578063bf9befb114610486578063c35bc5501461048e578063c7b5548114610496578063d380a37c1461049e578063d815e8e9146104a6578063e056e918146104ae5761028a565b8063a3f4df7e1461043e578063ae7bec1914610453578063ae9187541461045b578063b7f8cf9b14610463578063bcd375261461046b578063be4b03341461047e5761028a565b8063893d20e811610120578063893d20e81461040b57806396d711ff146104135780639708daf41461041b5780639dd233d21461042e5780639f07067014610436578063a20baee6146103b05761028a565b8063797250e3146103e35780637cf54e40146103eb5780637f7dde4a146103f3578063807d138d146103fb578063887105d3146104035761028a565b80633cc7422511610200578063716c47e6116101b9578063716c47e6146103a857806372fe25aa146103b0578063741bef1a146103b8578063756b253e146103c0578063759b3034146103d3578063795d26c3146103db5761028a565b80633cc742251461034657806342ccf1e41461034e5780634a767d681461036157806361ec893d146103745780636b4449521461037c5780636ef64338146103845761028a565b80631673c79a116102525780631673c79a146102f25780631a59a50e146103135780631bf43555146103265780631f68f20a1461032e57806331c903b0146103365780633a1285951461033e5761028a565b806305b6f5ca1461028f578063071a7541146102a45780630d43e8ad146102c257806312261ee7146102d757806313af4035146102df575b600080fd5b6102a261029d3660046132d7565b6104ce565b005b6102ac610589565b6040516102b99190613b05565b60405180910390f35b6102ca61058e565b6040516102b991906134cd565b6102ca61059d565b6102a26102ed3660046131b7565b6105c1565b6103056103003660046131b7565b61060e565b6040516102b9929190613b0e565b6102ac6103213660046131b7565b610627565b6102ac6106ef565b6102ac6106fc565b6102ac610702565b6102ca610714565b6102ca610723565b6102ac61035c3660046131b7565b610732565b6102ac61036f3660046131ef565b610763565b6102ac61078e565b6102ac610793565b6103976103923660046131b7565b610799565b6040516102b9959493929190613b1c565b6102ca6107d3565b6102ac6107e2565b6102ca6107ee565b6102ca6103ce36600461323a565b6107fd565b6102ac610824565b6102ac610831565b6102ac610950565b6102ca610956565b6102ca610965565b6102ac610974565b6102ac61097a565b6102ca610a49565b6102ac610a68565b6102a2610429366004613361565b610a6e565b6102ac610b4c565b6102ca610b52565b610446610b61565b6040516102b991906135e4565b6102ca610b89565b6102ca610b98565b6102ca610ba7565b6102a261047936600461326a565b610bb6565b6102ac610bce565b6102ac610bd4565b6102ac610bda565b6102ac610bfe565b6102ac610c0a565b6102ca610c10565b6104c16104bc3660046131b7565b610c1f565b6040516102b991906135ab565b600061056d600560009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561052157600080fd5b505afa158015610535573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055991906131d3565b6009548b906001600160a01b031685610c7d565b905061057e81898989898989610f2e565b505050505050505050565b600281565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6105c9610a49565b6001600160a01b0316336001600160a01b0316146106025760405162461bcd60e51b81526004016105f99061389f565b60405180910390fd5b61060b816116f5565b50565b6016602052600090815260409020805460019091015482565b6001600160a01b0381166000908152601660205260408120546014548290610655908363ffffffff61178016565b905080158061068e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561068b57fe5b14155b1561069e576000925050506106ea565b6001600160a01b038416600090815260106020526040812060020154906106e3670de0b6b3a76400006106d7848663ffffffff6117c916565b9063ffffffff61180316565b9450505050505b919050565b6809c2007651b250000081565b600e5481565b600061070f600e54611845565b905090565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290610655908363ffffffff61178016565b6000806000610771856118ee565b915091506000610782838387611974565b93505050505b92915050565b603c81565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b670de0b6b3a764000081565b6002546001600160a01b031681565b6017818154811061080a57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b15801561087557600080fd5b505afa158015610889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ad9190613252565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ff57600080fd5b505afa158015610913573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109379190613252565b9050610949828263ffffffff6119a616565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156109bf57600080fd5b505afa1580156109d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f79190613252565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ff57600080fd5b600080604051610a58906134b0565b6040519081900390205492915050565b60135481565b6000610b2e600560009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b158015610ac157600080fd5b505afa158015610ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af991906131d3565b6009546001600160a01b0316867f000000000000000000000000000000000000000000000000000000000000000087876119cb565b9050610b3f818b8b8b8b8b8b610f2e565b5050505050505050505050565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b6005546001600160a01b031681565b610bc587878787878787610f2e565b50505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b670ddd4b8c6c7d70d881565b600f5481565b6009546001600160a01b031681565b600060016001600160a01b03831660009081526010602052604090206003015460ff166004811115610c4d57fe5b14610c5a575060006106ea565b506014546001600160a01b03821660009081526016602052604090205410919050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015610cb957600080fd5b505afa158015610ccd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf191906131d3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610d2191906134cd565b60206040518083038186803b158015610d3957600080fd5b505afa158015610d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d719190613252565b9050306001600160a01b03831663605629d633838a8935610d9860408c0160208d01613477565b8b604001358c606001356040518863ffffffff1660e01b8152600401610dc497969594939291906134e1565b600060405180830381600087803b158015610dde57600080fd5b505af1158015610df2573d6000803e3d6000fd5b5050505086610e8383856001600160a01b03166370a08231856040518263ffffffff1660e01b8152600401610e2791906134cd565b60206040518083038186803b158015610e3f57600080fd5b505afa158015610e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e779190613252565b9063ffffffff61178016565b14610ea05760405162461bcd60e51b81526004016105f9906136ab565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390610ed09089908b90339060040161355d565b602060405180830381600087803b158015610eea57600080fd5b505af1158015610efe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f229190613252565b98975050505050505050565b610f366130b5565b506040805160e0810182526000546001600160a01b03908116825260015481166020830152600954811692820192909252600b5482166060820152600d5482166080820152600854821660a082015260075490911660c0820152610f986130f1565b610fa183611c18565b610fa9611cd1565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610ff957600080fd5b505af115801561100d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110319190613252565b60c0820181905261104190611d9f565b61104a89611e4c565b6110598260400151338b611e6c565b611061610831565b60e0820181905260408084015190516370a0823160e01b81526001600160a01b03909116906370a082319061109a9033906004016134cd565b60206040518083038186803b1580156110b257600080fd5b505afa1580156110c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ea9190613252565b11156110f257fe5b888152608082015160c082015160009161110d918b90611f0d565b156111195750876112c6565b82608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561115657600080fd5b505afa15801561116a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118e91906131d3565b90505b6001600160a01b0381161580159061123a5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156111f257600080fd5b505afa158015611206573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122a9190613252565b611238828460c00151610763565b105b156112c65782608001516001600160a01b031663b72703ac826040518263ffffffff1660e01b815260040161126f91906134cd565b60206040518083038186803b15801561128757600080fd5b505afa15801561129b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bf91906131d3565b9050611191565b846112d15760001994505b6001600160a01b038116158015906112e95750815115155b80156112f55750600085115b15611423576080830151604051632dc9c0eb60e21b8152600019909601956000916001600160a01b03169063b72703ac906113349085906004016134cd565b60206040518083038186803b15801561134c57600080fd5b505afa158015611360573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138491906131d3565b90506113998460000151856020015184612170565b6113a1613136565b6113b8858486600001518760c001518e8e8e612281565b90508060400151156113cb575050611423565b805160208501516113e19163ffffffff6119a616565b60208086019190915281015160408501516114019163ffffffff6119a616565b6040850152805184516114199163ffffffff61178016565b84525090506112d1565b60008260400151116114475760405162461bcd60e51b81526004016105f9906136f4565b61145e82604001518360c001518460e001516124f5565b5061146c82604001516125ac565b6060830181905260408301516114839190866125bf565b8251600c5460608401516040516364a197f360e01b81526001600160a01b03938416936364a197f3936114bb93911691600401613522565b600060405180830381600087803b1580156114d557600080fd5b505af11580156114e9573d6000803e3d6000fd5b50505050600c60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561153d57600080fd5b505af1158015611551573d6000803e3d6000fd5b505050506060820151604083015161156891611780565b60808301526020820151604080840151606085015191517f43a3f4082a4dbc33d78e317d2497d3a730bc7fc3574159dcea1056e62e5d9ad8936115ae938f939192613b5c565b60405180910390a182604001516001600160a01b0316639dc29fac3384602001516040518363ffffffff1660e01b81526004016115ec929190613522565b600060405180830381600087803b15801561160657600080fd5b505af115801561161a573d6000803e3d6000fd5b50508451602085015160405163121cbc4d60e11b81526001600160a01b039092169350632439789a925061165091600401613b05565b600060405180830381600087803b15801561166a57600080fd5b505af115801561167e573d6000803e3d6000fd5b5050845160808501516040516364a197f360e01b81526001600160a01b0390921693506364a197f392506116b791339190600401613522565b600060405180830381600087803b1580156116d157600080fd5b505af11580156116e5573d6000803e3d6000fd5b5050505050505050505050505050565b6001600160a01b03811661171b5760405162461bcd60e51b81526004016105f990613774565b806001600160a01b031661172d610a49565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611770906134b0565b6040519081900390209190915550565b60006117c283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612605565b9392505050565b6000826117d857506000610788565b828202828482816117e557fe5b04146117c25760405162461bcd60e51b81526004016105f99061385e565b60006117c283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612631565b60006107886118e083600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561189c57600080fd5b505afa1580156118b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d49190613252565b9063ffffffff6119a616565b670de0b6b3a7640000612668565b60008060006118fc84610627565b9050600061190985610732565b6001600160a01b03861660009081526010602052604081206001015491925090611939908463ffffffff6119a616565b6001600160a01b03871660009081526010602052604081205491925090611966908463ffffffff6119a616565b919550909350505050915091565b6000821561199b576000611992846106d7878663ffffffff6117c916565b91506117c29050565b506000199392505050565b6000828201838110156117c25760405162461bcd60e51b81526004016105f99061373d565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015611a0757600080fd5b505afa158015611a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3f91906131d3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611a6f91906134cd565b60206040518083038186803b158015611a8757600080fd5b505afa158015611a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abf9190613252565b87516020015190915030906001600160a01b0388166330f28b7a8a611ae4858561267e565b338b8b6040518663ffffffff1660e01b8152600401611b07959493929190613a94565b600060405180830381600087803b158015611b2157600080fd5b505af1158015611b35573d6000803e3d6000fd5b5050505080611b6a84866001600160a01b03166370a08231866040518263ffffffff1660e01b8152600401610e2791906134cd565b14611b875760405162461bcd60e51b81526004016105f9906136ab565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390611bb7908d908590339060040161355d565b602060405180830381600087803b158015611bd157600080fd5b505af1158015611be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c099190613252565b9b9a5050505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c6657600080fd5b505afa158015611c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9e9190613252565b8110158015611cb55750670de0b6b3a76400008111155b61060b5760405162461bcd60e51b81526004016105f990613974565b600a5460408051631e425be160e11b815290516000926001600160a01b031691633c84b7c2916004808301926020929190829003018186803b158015611d1657600080fd5b505afa158015611d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d4e9190613252565b9050611d80817f000000000000000000000000000000000000000000000000000000000000000063ffffffff6119a616565b42101561060b5760405162461bcd60e51b81526004016105f990613800565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015611ded57600080fd5b505afa158015611e01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e259190613252565b611e2e826126b0565b101561060b5760405162461bcd60e51b81526004016105f9906139c4565b6000811161060b5760405162461bcd60e51b81526004016105f9906138d0565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190611e9a9086906004016134cd565b60206040518083038186803b158015611eb257600080fd5b505afa158015611ec6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eea9190613252565b1015611f085760405162461bcd60e51b81526004016105f990613637565b505050565b60006001600160a01b0383161580611f9e5750604051630bb7c8fd60e31b81526001600160a01b03851690635dbe47e890611f4c9086906004016134cd565b60206040518083038186803b158015611f6457600080fd5b505afa158015611f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9c919061321a565b155b806120365750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015611ff257600080fd5b505afa158015612006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202a9190613252565b6120348484610763565b105b15612043575060006117c2565b60405163765e015960e01b81526000906001600160a01b0386169063765e0159906120729087906004016134cd565b60206040518083038186803b15801561208a57600080fd5b505afa15801561209e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c291906131d3565b90506001600160a01b03811615806121675750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561212357600080fd5b505afa158015612137573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215b9190613252565b6121658285610763565b105b95945050505050565b61217981610c1f565b15611f0857612187816126dc565b600061219282610627565b9050600061219f83610732565b6001600160a01b0384166000908152601060205260409020600101549091506121ce908363ffffffff6119a616565b6001600160a01b03841660009081526010602052604090206001810191909155546121ff908263ffffffff6119a616565b6001600160a01b03841660009081526010602052604090205561222183612725565b61222d8585838561278d565b6001600160a01b038316600081815260106020526040808220805460018201546002909201549251600080516020613bb48339815191529461227294929392916135b6565b60405180910390a25050505050565b612289613136565b6001600160a01b0387166000908152601060205260409020546122c69087906122c1906801158e460913d0000063ffffffff61178016565b612668565b8082526122e79086906106d790670de0b6b3a764000063ffffffff6117c916565b60208083019190915281516001600160a01b03891660009081526010909252604082205461231a9163ffffffff61178016565b6020808401516001600160a01b038b1660009081526010909252604082206001015492935090916123509163ffffffff61178016565b90506801158e460913d000008214156123c95761236c896128ad565b6123778960046128fd565b61238c8a8a6801158e460913d0000084612a09565b886001600160a01b0316600080516020613bb4833981519152600080600060036040516123bc94939291906135b6565b60405180910390a26124e7565b60006123d58284612b6c565b905084811415806123f657506809c2007651b25000006123f484612ba1565b105b1561240a57505060016040830152506124ea565b8a608001516001600160a01b0316632be212608b838a8a6040518563ffffffff1660e01b81526004016124409493929190613580565b600060405180830381600087803b15801561245a57600080fd5b505af115801561246e573d6000803e3d6000fd5b5050506001600160a01b038b1660009081526010602052604090208481556001018390555061249c8a612bbc565b506001600160a01b038a1660008181526010602052604090819020600201549051600080516020613bb4833981519152916124dd91879187916003906135b6565b60405180910390a2505b50505b979650505050505050565b600080612500612c63565b90506000612518846106d7888863ffffffff6117c916565b9050600061253d61253083600263ffffffff61180316565b849063ffffffff6119a616565b905061255181670de0b6b3a7640000612668565b90506000811161255d57fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c90612592908390613b05565b60405180910390a16125a2612ca7565b9695505050505050565b60006107886125b9610702565b83612cfc565b60006125dd836106d786670de0b6b3a764000063ffffffff6117c916565b9050818111156125ff5760405162461bcd60e51b81526004016105f990613a0e565b50505050565b600081848411156126295760405162461bcd60e51b81526004016105f991906135e4565b505050900390565b600081836126525760405162461bcd60e51b81526004016105f991906135e4565b50600083858161265e57fe5b0495945050505050565b600081831061267757816117c2565b5090919050565b612686613159565b61268e613159565b5050604080518082019091526001600160a01b03929092168252602082015290565b6000806126bb61097a565b905060006126c7610831565b90506126d4828286611974565b949350505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561270857fe5b1461060b5760405162461bcd60e51b81526004016105f990613a45565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92612782929091613b0e565b60405180910390a150565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a906127b9908590600401613b05565b600060405180830381600087803b1580156127d357600080fd5b505af11580156127e7573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150612817908590600401613b05565b600060405180830381600087803b15801561283157600080fd5b505af1158015612845573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150612875908490600401613b05565b600060405180830381600087803b15801561288f57600080fd5b505af11580156128a3573d6000803e3d6000fd5b5050505050505050565b6001600160a01b0381166000908152601060205260409020600201546011546128dc908263ffffffff61178016565b601155506001600160a01b0316600090815260106020526040812060020155565b600081600481111561290b57fe5b141580156129255750600181600481111561292257fe5b14155b61292b57fe5b60175461293781612d3c565b6001600160a01b0383166000908152601060205260409020600301805483919060ff1916600183600481111561296957fe5b02179055506001600160a01b03831660009081526010602090815260408083206001808201859055908490556016909252822082815501556129ab8382612de2565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e906129db9086906004016134cd565b600060405180830381600087803b1580156129f557600080fd5b505af1158015610bc5573d6000803e3d6000fd5b6040808501516007549151632770a7eb60e21b81526001600160a01b0391821692639dc29fac92612a41929116908690600401613522565b600060405180830381600087803b158015612a5b57600080fd5b505af1158015612a6f573d6000803e3d6000fd5b5050855160405163121cbc4d60e11b81526001600160a01b039091169250632439789a9150612aa2908590600401613b05565b600060405180830381600087803b158015612abc57600080fd5b505af1158015612ad0573d6000803e3d6000fd5b505050508360a001516001600160a01b0316633f10abab84836040518363ffffffff1660e01b8152600401612b06929190613522565b600060405180830381600087803b158015612b2057600080fd5b505af1158015612b34573d6000803e3d6000fd5b5050855160a08701516040516364a197f360e01b81526001600160a01b0390921693506364a197f39250612875918590600401613522565b60008115612b9857612b91826106d78568056bc75e2d6310000063ffffffff6117c916565b9050610788565b50600019610788565b6000610788826801158e460913d0000063ffffffff61178016565b6001600160a01b0381166000908152601060205260408120600101548190612be390612f83565b6001600160a01b038416600090815260106020526040902060020180549082905560115491925090612c219083906118d4908463ffffffff61178016565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae52038291612c5491613b05565b60405180910390a15092915050565b600080612c6e612fbf565b90506000612c84670ddd4b8c6c7d70d883612fdb565b9050610949670de0b6b3a76400006106d783600e546117c990919063ffffffff16565b6000612cbe600f544261178090919063ffffffff16565b9050603c811061060b5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc9161278291613b05565b600080612d1b670de0b6b3a76400006106d7868663ffffffff6117c916565b90508281106117c25760405162461bcd60e51b81526004016105f99061391e565b600181118015612dc65750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b158015612d8c57600080fd5b505afa158015612da0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc49190613252565b115b61060b5760405162461bcd60e51b81526004016105f9906137b6565b6001600160a01b03821660009081526010602052604081206003015460ff1690816004811115612e0e57fe5b14158015612e2857506001816004811115612e2557fe5b14155b612e2e57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b0316908390612e66826001611780565b905080836001600160801b03161115612e7b57fe5b600060178281548110612e8a57fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b038716908110612ebc57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a90612f45908390879061353b565b60405180910390a16017805480612f5857fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b60008060135460001415612f98575081610788565b600060125411612fa457fe5b6117c26013546106d7601254866117c990919063ffffffff16565b600061070f603c6106d7600f544261178090919063ffffffff16565b6000631f540500821115612ff157631f54050091505b816130055750670de0b6b3a7640000610788565b670de0b6b3a764000083835b600181111561307c57600281066130465761302c8283613082565b915061303f81600263ffffffff61180316565b9050613077565b6130508284613082565b925061305c8283613082565b915061307460026106d783600163ffffffff61178016565b90505b613011565b61078282845b600080613095848463ffffffff6117c916565b90506126d4670de0b6b3a76400006106d7836706f05b59d3b200006119a6565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806060016040528060008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b60008083601f840112613181578182fd5b50813567ffffffffffffffff811115613198578182fd5b6020830191508360208285010111156131b057600080fd5b9250929050565b6000602082840312156131c8578081fd5b81356117c281613b9e565b6000602082840312156131e4578081fd5b81516117c281613b9e565b60008060408385031215613201578081fd5b823561320c81613b9e565b946020939093013593505050565b60006020828403121561322b578081fd5b815180151581146117c2578182fd5b60006020828403121561324b578081fd5b5035919050565b600060208284031215613263578081fd5b5051919050565b600080600080600080600060e0888a031215613284578283fd5b87359650602088013561329681613b9e565b955060408801356132a681613b9e565b945060608801356132b681613b9e565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a036101608112156132f4578182fd5b8935985060208a013561330681613b9e565b975060408a013561331681613b9e565b965060608a013561332681613b9e565b955060808a810135955060a08b0135945060c08b0135935060df198201121561334d578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c03610180811215613381578283fd5b8b359a5060208c013561339381613b9e565b995060408c01356133a381613b9e565b985060608c01356133b381613b9e565b975060808c810135975060a08d0135965060c08d0135955060df198201908112156133dc578384fd5b6133e66060613b77565b915060408112156133f5578384fd5b506134006040613b77565b60e08d013561340e81613b9e565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff811115613453578283fd5b61345f8d828e01613170565b8194508093505050509295989b9194979a5092959850565b600060208284031215613488578081fd5b813560ff811681146117c2578182fd5b80516001600160a01b03168252602090810151910152565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b901515815260200190565b848152602081018490526040810183905260808101600483106135d557fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015613610578581018301518582016040015282016135f4565b818111156136215783604083870101525b50601f01601f1916929092016040019392505050565b6020808252604e908201527f54726f76654d616e616765723a2052657175657374656420726564656d70746960408201527f6f6e20616d6f756e74206d757374206265203c3d20757365722773205a55534460608201526d20746f6b656e2062616c616e636560901b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b60208082526029908201527f54726f76654d616e616765723a20556e61626c6520746f2072656465656d20616040820152681b9e48185b5bdd5b9d60ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b602080825260409082018190527f54726f76654d616e616765723a20526564656d7074696f6e7320617265206e6f908201527f7420616c6c6f77656420647572696e6720626f6f747374726170207068617365606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252602e908201527f54726f76654d616e616765723a20416d6f756e74206d7573742062652067726560408201526d61746572207468616e207a65726f60901b606082015260800190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252602a908201527f54726f76654d616e616765723a2043616e6e6f742072656465656d207768656e604082015269102a21a9101e1026a1a960b11b606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b6000610100613aa4838951613498565b6020880151604084015260408801516060840152613ac56080840188613498565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b918252602082015260400190565b858152602081018590526040810184905260a0810160058410613b3b57fe5b60608201939093526001600160801b03919091166080909101529392505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff81118282101715613b9657600080fd5b604052919050565b6001600160a01b038116811461060b57600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212207c16913f9245b09fe846c28a2b84344e3caf87f082e47e49ca0ae21a08915c2b64736f6c634300060b0033", + "devdoc": { + "kind": "dev", + "methods": { + "getOwner()": { + "returns": { + "_owner": "Address of the owner. " + } + }, + "setOwner(address)": { + "params": { + "_owner": "Address of the owner. " + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "BETA()": { + "notice": "BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption. Corresponds to (1 / ALPHA) in the white paper." + }, + "BOOTSTRAP_PERIOD()": { + "notice": "During bootsrap period redemptions are not allowed" + }, + "MIN_NET_DEBT()": { + "notice": "Minimum amount of net ZUSD debt a trove must have" + }, + "ZUSD_GAS_COMPENSATION()": { + "notice": "Amount of ZUSD to be locked in gas pool on opening troves" + }, + "_getCurrentICR(address,uint256)": { + "notice": "Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account." + }, + "_getPendingETHReward(address)": { + "notice": "Get the borrower's pending accumulated ETH reward, earned by their stake" + }, + "_getPendingZUSDDebtReward(address)": { + "notice": "Get the borrower's pending accumulated ZUSD reward, earned by their stake" + }, + "constructor": "Constructor ", + "getOwner()": { + "notice": "Return address of the owner." + }, + "permit2()": { + "notice": "CONSTANT / IMMUTABLE VARIABLE ONLY " + }, + "redeemCollateralViaDLLR(uint256,address,address,address,uint256,uint256,uint256,(uint256,uint8,bytes32,bytes32))": { + "notice": "DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction" + }, + "redeemCollateralViaDllrWithPermit2(uint256,address,address,address,uint256,uint256,uint256,((address,uint256),uint256,uint256),bytes)": { + "notice": "DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction" + }, + "setOwner(address)": { + "notice": "Set address of the owner (only owner can call this function)" + } + }, + "notice": "This contract is designed to be used via delegatecall from the TroveManager contract TroveManagerBase constructor param is bootsrap period when redemptions are not allowed", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 5495, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "activePool", + "offset": 0, + "slot": "0", + "type": "t_contract(IActivePool)19557" + }, + { + "astId": 5497, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "defaultPool", + "offset": 0, + "slot": "1", + "type": "t_contract(IDefaultPool)20229" + }, + { + "astId": 5500, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "priceFeed", + "offset": 0, + "slot": "2", + "type": "t_contract(IPriceFeed)20458" + }, + { + "astId": 5503, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "liquityBaseParams", + "offset": 0, + "slot": "3", + "type": "t_contract(ILiquityBaseParams)20379" + }, + { + "astId": 35227, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "troveManagerRedeemOps", + "offset": 0, + "slot": "4", + "type": "t_address" + }, + { + "astId": 35229, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "borrowerOperationsAddress", + "offset": 0, + "slot": "5", + "type": "t_address" + }, + { + "astId": 35231, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "_stabilityPool", + "offset": 0, + "slot": "6", + "type": "t_contract(IStabilityPool)21101" + }, + { + "astId": 35233, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "gasPoolAddress", + "offset": 0, + "slot": "7", + "type": "t_address" + }, + { + "astId": 35235, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "collSurplusPool", + "offset": 0, + "slot": "8", + "type": "t_contract(ICollSurplusPool)20130" + }, + { + "astId": 35237, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "_zusdToken", + "offset": 0, + "slot": "9", + "type": "t_contract(IZUSDToken)21842" + }, + { + "astId": 35239, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "_zeroToken", + "offset": 0, + "slot": "10", + "type": "t_contract(IZEROToken)21783" + }, + { + "astId": 35241, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "_zeroStaking", + "offset": 0, + "slot": "11", + "type": "t_contract(IZEROStaking)21760" + }, + { + "astId": 35243, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "feeDistributor", + "offset": 0, + "slot": "12", + "type": "t_contract(IFeeDistributor)20298" + }, + { + "astId": 35245, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "sortedTroves", + "offset": 0, + "slot": "13", + "type": "t_contract(ISortedTroves)20817" + }, + { + "astId": 35247, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "baseRate", + "offset": 0, + "slot": "14", + "type": "t_uint256" + }, + { + "astId": 35249, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "lastFeeOperationTime", + "offset": 0, + "slot": "15", + "type": "t_uint256" + }, + { + "astId": 35270, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "Troves", + "offset": 0, + "slot": "16", + "type": "t_mapping(t_address,t_struct(Trove)35266_storage)" + }, + { + "astId": 35272, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "totalStakes", + "offset": 0, + "slot": "17", + "type": "t_uint256" + }, + { + "astId": 35274, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "totalStakesSnapshot", + "offset": 0, + "slot": "18", + "type": "t_uint256" + }, + { + "astId": 35276, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "totalCollateralSnapshot", + "offset": 0, + "slot": "19", + "type": "t_uint256" + }, + { + "astId": 35278, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "L_ETH", + "offset": 0, + "slot": "20", + "type": "t_uint256" + }, + { + "astId": 35280, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "L_ZUSDDebt", + "offset": 0, + "slot": "21", + "type": "t_uint256" + }, + { + "astId": 35284, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "rewardSnapshots", + "offset": 0, + "slot": "22", + "type": "t_mapping(t_address,t_struct(RewardSnapshot)35289_storage)" + }, + { + "astId": 35292, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "TroveOwners", + "offset": 0, + "slot": "23", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 35294, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "lastETHError_Redistribution", + "offset": 0, + "slot": "24", + "type": "t_uint256" + }, + { + "astId": 35296, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "lastZUSDDebtError_Redistribution", + "offset": 0, + "slot": "25", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_contract(IActivePool)19557": { + "encoding": "inplace", + "label": "contract IActivePool", + "numberOfBytes": "20" + }, + "t_contract(ICollSurplusPool)20130": { + "encoding": "inplace", + "label": "contract ICollSurplusPool", + "numberOfBytes": "20" + }, + "t_contract(IDefaultPool)20229": { + "encoding": "inplace", + "label": "contract IDefaultPool", + "numberOfBytes": "20" + }, + "t_contract(IFeeDistributor)20298": { + "encoding": "inplace", + "label": "contract IFeeDistributor", + "numberOfBytes": "20" + }, + "t_contract(ILiquityBaseParams)20379": { + "encoding": "inplace", + "label": "contract ILiquityBaseParams", + "numberOfBytes": "20" + }, + "t_contract(IPriceFeed)20458": { + "encoding": "inplace", + "label": "contract IPriceFeed", + "numberOfBytes": "20" + }, + "t_contract(ISortedTroves)20817": { + "encoding": "inplace", + "label": "contract ISortedTroves", + "numberOfBytes": "20" + }, + "t_contract(IStabilityPool)21101": { + "encoding": "inplace", + "label": "contract IStabilityPool", + "numberOfBytes": "20" + }, + "t_contract(IZEROStaking)21760": { + "encoding": "inplace", + "label": "contract IZEROStaking", + "numberOfBytes": "20" + }, + "t_contract(IZEROToken)21783": { + "encoding": "inplace", + "label": "contract IZEROToken", + "numberOfBytes": "20" + }, + "t_contract(IZUSDToken)21842": { + "encoding": "inplace", + "label": "contract IZUSDToken", + "numberOfBytes": "20" + }, + "t_enum(Status)35255": { + "encoding": "inplace", + "label": "enum TroveManagerStorage.Status", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_struct(RewardSnapshot)35289_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct TroveManagerStorage.RewardSnapshot)", + "numberOfBytes": "32", + "value": "t_struct(RewardSnapshot)35289_storage" + }, + "t_mapping(t_address,t_struct(Trove)35266_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct TroveManagerStorage.Trove)", + "numberOfBytes": "32", + "value": "t_struct(Trove)35266_storage" + }, + "t_struct(RewardSnapshot)35289_storage": { + "encoding": "inplace", + "label": "struct TroveManagerStorage.RewardSnapshot", + "members": [ + { + "astId": 35286, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "ETH", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 35288, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "ZUSDDebt", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Trove)35266_storage": { + "encoding": "inplace", + "label": "struct TroveManagerStorage.Trove", + "members": [ + { + "astId": 35257, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "debt", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 35259, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "coll", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 35261, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "stake", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 35263, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "status", + "offset": 0, + "slot": "3", + "type": "t_enum(Status)35255" + }, + { + "astId": 35265, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "arrayIndex", + "offset": 1, + "slot": "3", + "type": "t_uint128" + } + ], + "numberOfBytes": "128" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/external/deployments/rskMainnet/TroveManager_Implementation.json b/external/deployments/rskMainnet/TroveManager_Implementation.json new file mode 100644 index 000000000..aa4f644be --- /dev/null +++ b/external/deployments/rskMainnet/TroveManager_Implementation.json @@ -0,0 +1,2752 @@ +{ + "address": "0x3d841398AcA5794b9da2f2573F473075417a0117", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_bootstrapPeriod", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_baseRate", + "type": "uint256" + } + ], + "name": "BaseRateUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newBorrowerOperationsAddress", + "type": "address" + } + ], + "name": "BorrowerOperationsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + } + ], + "name": "CollSurplusPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + } + ], + "name": "FeeDistributorAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + } + ], + "name": "GasPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "LTermsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_lastFeeOpTime", + "type": "uint256" + } + ], + "name": "LastFeeOpTimeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedDebt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedColl", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_collGasCompensation", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDGasCompensation", + "type": "uint256" + } + ], + "name": "Liquidation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + } + ], + "name": "LiquityBaseParamsAddressChanges", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_attemptedZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_actualZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHSent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHFee", + "type": "uint256" + } + ], + "name": "Redemption", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + } + ], + "name": "StabilityPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_totalStakesSnapshot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalCollateralSnapshot", + "type": "uint256" + } + ], + "name": "SystemSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newTotalStakes", + "type": "uint256" + } + ], + "name": "TotalStakesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newIndex", + "type": "uint256" + } + ], + "name": "TroveIndexUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveLiquidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + } + ], + "name": "TroveManagerRedeemOpsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "TroveSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "ZEROStakingAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroTokenAddress", + "type": "address" + } + ], + "name": "ZEROTokenAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newZUSDTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "BETA", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BOOTSTRAP_PERIOD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "CCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ETH", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ZUSDDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINUTE_DECAY_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SECONDS_IN_ONE_MINUTE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "TroveOwners", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "Troves", + "outputs": [ + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coll", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "internalType": "enum TroveManagerStorage.Status", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "arrayIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "_getCurrentICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingETHReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingZUSDDebtReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_getRedemptionRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_hasPendingRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_stabilityPool", + "outputs": [ + { + "internalType": "contract IStabilityPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroStaking", + "outputs": [ + { + "internalType": "contract IZEROStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroToken", + "outputs": [ + { + "internalType": "contract IZEROToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "addTroveOwnerToArray", + "outputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "applyPendingRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_troveArray", + "type": "address[]" + } + ], + "name": "batchLiquidateTroves", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "borrowerOperationsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "checkRecoveryMode", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "closeTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decayBaseRateFromBorrowing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_collDecrease", + "type": "uint256" + } + ], + "name": "decreaseTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_debtDecrease", + "type": "uint256" + } + ], + "name": "decreaseTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeDistributor", + "outputs": [ + { + "internalType": "contract IFeeDistributor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDDebt", + "type": "uint256" + } + ], + "name": "getBorrowingFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDDebt", + "type": "uint256" + } + ], + "name": "getBorrowingFeeWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBorrowingRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBorrowingRateWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "getCurrentICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getEntireDebtAndColl", + "outputs": [ + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coll", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pendingZUSDDebtReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pendingETHReward", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getNominalICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getPendingETHReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getPendingZUSDDebtReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ETHDrawn", + "type": "uint256" + } + ], + "name": "getRedemptionFeeWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRedemptionRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRedemptionRateWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "getTCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_index", + "type": "uint256" + } + ], + "name": "getTroveFromTroveOwnersArray", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTroveOwnersCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveStatus", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "hasPendingRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_collIncrease", + "type": "uint256" + } + ], + "name": "increaseTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_debtIncrease", + "type": "uint256" + } + ], + "name": "increaseTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lastETHError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFeeOperationTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastZUSDDebtError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "liquidate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_n", + "type": "uint256" + } + ], + "name": "liquidateTroves", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDamount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + } + ], + "name": "redeemCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "redeemCollateralViaDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "redeemCollateralViaDllrWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "removeStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "rewardSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "ETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ZUSDDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + }, + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "internalType": "struct ITroveManager.TroveManagerInitAddressesParams", + "name": "_troveManagerInitAddressesParams", + "type": "tuple" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + } + ], + "name": "setTroveManagerRedeemOps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_num", + "type": "uint256" + } + ], + "name": "setTroveStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalCollateralSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakesSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManagerRedeemOps", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "updateStakeAndTotalStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "updateTroveRewardSnapshots", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0xdC03c72c1730b149E3178624FD4d9Bf51501A6E0", + "transactionIndex": 0, + "gasUsed": "6045491", + "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000080000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000400000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x63ae44ab567d090410beb39dd6c2dad30f27c33679e013ac466adf6afc60e169", + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748962, + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "address": "0xdC03c72c1730b149E3178624FD4d9Bf51501A6E0", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x63ae44ab567d090410beb39dd6c2dad30f27c33679e013ac466adf6afc60e169" + } + ], + "blockNumber": 4748962, + "cumulativeGasUsed": "6045491", + "status": 1, + "byzantium": true + }, + "args": ["1209600", "0x000000000022d473030f116ddee9f6b43ac78ba3"], + "numDeployments": 2, + "solcInputHash": "849fadfa265e27de6fba2f2d99bdf763", + "metadata": "{\"compiler\":{\"version\":\"0.6.11+commit.5ef660b1\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_bootstrapPeriod\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_permit2\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_activePoolAddress\",\"type\":\"address\"}],\"name\":\"ActivePoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_baseRate\",\"type\":\"uint256\"}],\"name\":\"BaseRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newBorrowerOperationsAddress\",\"type\":\"address\"}],\"name\":\"BorrowerOperationsAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_collSurplusPoolAddress\",\"type\":\"address\"}],\"name\":\"CollSurplusPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_defaultPoolAddress\",\"type\":\"address\"}],\"name\":\"DefaultPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_feeDistributorAddress\",\"type\":\"address\"}],\"name\":\"FeeDistributorAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_gasPoolAddress\",\"type\":\"address\"}],\"name\":\"GasPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ETH\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"LTermsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_lastFeeOpTime\",\"type\":\"uint256\"}],\"name\":\"LastFeeOpTimeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_liquidatedDebt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_liquidatedColl\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_collGasCompensation\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ZUSDGasCompensation\",\"type\":\"uint256\"}],\"name\":\"Liquidation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_borrowerOperationsAddress\",\"type\":\"address\"}],\"name\":\"LiquityBaseParamsAddressChanges\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newPriceFeedAddress\",\"type\":\"address\"}],\"name\":\"PriceFeedAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_attemptedZUSDAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_actualZUSDAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ETHSent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ETHFee\",\"type\":\"uint256\"}],\"name\":\"Redemption\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_sortedTrovesAddress\",\"type\":\"address\"}],\"name\":\"SortedTrovesAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_stabilityPoolAddress\",\"type\":\"address\"}],\"name\":\"StabilityPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalStakesSnapshot\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalCollateralSnapshot\",\"type\":\"uint256\"}],\"name\":\"SystemSnapshotsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newTotalStakes\",\"type\":\"uint256\"}],\"name\":\"TotalStakesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newIndex\",\"type\":\"uint256\"}],\"name\":\"TroveIndexUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_coll\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"operation\",\"type\":\"uint8\"}],\"name\":\"TroveLiquidated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_troveManagerRedeemOps\",\"type\":\"address\"}],\"name\":\"TroveManagerRedeemOpsAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ETH\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"TroveSnapshotsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_coll\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"operation\",\"type\":\"uint8\"}],\"name\":\"TroveUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_zeroStakingAddress\",\"type\":\"address\"}],\"name\":\"ZEROStakingAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_zeroTokenAddress\",\"type\":\"address\"}],\"name\":\"ZEROTokenAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newZUSDTokenAddress\",\"type\":\"address\"}],\"name\":\"ZUSDTokenAddressChanged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BETA\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"BOOTSTRAP_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"CCR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DECIMAL_PRECISION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L_ETH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L_ZUSDDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MCR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MINUTE_DECAY_FACTOR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_NET_DEBT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SECONDS_IN_ONE_MINUTE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"TroveOwners\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"Troves\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"debt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"coll\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"enum TroveManagerStorage.Status\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint128\",\"name\":\"arrayIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZUSD_GAS_COMPENSATION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_100pct\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_price\",\"type\":\"uint256\"}],\"name\":\"_getCurrentICR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_getPendingETHReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_getPendingZUSDDebtReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_getRedemptionRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_hasPendingRewards\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_stabilityPool\",\"outputs\":[{\"internalType\":\"contract IStabilityPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zeroStaking\",\"outputs\":[{\"internalType\":\"contract IZEROStaking\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zeroToken\",\"outputs\":[{\"internalType\":\"contract IZEROToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zusdToken\",\"outputs\":[{\"internalType\":\"contract IZUSDToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activePool\",\"outputs\":[{\"internalType\":\"contract IActivePool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"addTroveOwnerToArray\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"applyPendingRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_troveArray\",\"type\":\"address[]\"}],\"name\":\"batchLiquidateTroves\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"borrowerOperationsAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_price\",\"type\":\"uint256\"}],\"name\":\"checkRecoveryMode\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"closeTrove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decayBaseRateFromBorrowing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_collDecrease\",\"type\":\"uint256\"}],\"name\":\"decreaseTroveColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_debtDecrease\",\"type\":\"uint256\"}],\"name\":\"decreaseTroveDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultPool\",\"outputs\":[{\"internalType\":\"contract IDefaultPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeDistributor\",\"outputs\":[{\"internalType\":\"contract IFeeDistributor\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"getBorrowingFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"getBorrowingFeeWithDecay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBorrowingRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBorrowingRateWithDecay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_price\",\"type\":\"uint256\"}],\"name\":\"getCurrentICR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getEntireDebtAndColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"debt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"coll\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pendingZUSDDebtReward\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pendingETHReward\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemColl\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getNominalICR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getPendingETHReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getPendingZUSDDebtReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ETHDrawn\",\"type\":\"uint256\"}],\"name\":\"getRedemptionFeeWithDecay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRedemptionRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRedemptionRateWithDecay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_price\",\"type\":\"uint256\"}],\"name\":\"getTCR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getTroveColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getTroveDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getTroveFromTroveOwnersArray\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTroveOwnersCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getTroveStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getTroveStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"hasPendingRewards\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_collIncrease\",\"type\":\"uint256\"}],\"name\":\"increaseTroveColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_debtIncrease\",\"type\":\"uint256\"}],\"name\":\"increaseTroveDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastETHError_Redistribution\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFeeOperationTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastZUSDDebtError_Redistribution\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"liquidate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_n\",\"type\":\"uint256\"}],\"name\":\"liquidateTroves\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquityBaseParams\",\"outputs\":[{\"internalType\":\"contract ILiquityBaseParams\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceFeed\",\"outputs\":[{\"internalType\":\"contract IPriceFeed\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ZUSDamount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"}],\"name\":\"redeemCollateral\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"redeemCollateralViaDLLR\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"redeemCollateralViaDllrWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"removeStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"rewardSnapshots\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"ETH\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"ZUSDDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"_feeDistributorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_troveManagerRedeemOps\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_liquityBaseParamsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_borrowerOperationsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_activePoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_defaultPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_stabilityPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_gasPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_collSurplusPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_priceFeedAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zusdTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_sortedTrovesAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zeroTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zeroStakingAddress\",\"type\":\"address\"}],\"internalType\":\"struct ITroveManager.TroveManagerInitAddressesParams\",\"name\":\"_troveManagerInitAddressesParams\",\"type\":\"tuple\"}],\"name\":\"setAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_troveManagerRedeemOps\",\"type\":\"address\"}],\"name\":\"setTroveManagerRedeemOps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_num\",\"type\":\"uint256\"}],\"name\":\"setTroveStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortedTroves\",\"outputs\":[{\"internalType\":\"contract ISortedTroves\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalCollateralSnapshot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalStakesSnapshot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"troveManagerRedeemOps\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"updateStakeAndTotalStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"updateTroveRewardSnapshots\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"applyPendingRewards(address)\":{\"params\":{\"_borrower\":\"borrower address\"}},\"closeTrove(address)\":{\"params\":{\"_borrower\":\"borrower address\"}},\"constructor\":{\"params\":{\"_bootstrapPeriod\":\"During bootsrap period redemptions are not allowed\"}},\"decreaseTroveColl(address,uint256)\":{\"params\":{\"_borrower\":\"borrower address\",\"_collDecrease\":\"amount of collateral to decrease\"},\"returns\":{\"_0\":\"new trove collateral\"}},\"decreaseTroveDebt(address,uint256)\":{\"params\":{\"_borrower\":\"borrower address\",\"_debtDecrease\":\"amount of debt to decrease\"},\"returns\":{\"_0\":\"new trove debt\"}},\"getBorrowingFeeWithDecay(uint256)\":{\"params\":{\"_ZUSDDebt\":\"ZUSD debt amount to calculate fee\"},\"returns\":{\"_0\":\"borrowing fee using borrowing rate with decay\"}},\"getBorrowingRate()\":{\"returns\":{\"_0\":\"borrowing rate\"}},\"getBorrowingRateWithDecay()\":{\"returns\":{\"_0\":\"borrowing rate calculated using decayed as base rate\"}},\"getCurrentICR(address,uint256)\":{\"params\":{\"_borrower\":\"borrower address\",\"_price\":\"ETH price\"},\"returns\":{\"_0\":\"the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\"}},\"getNominalICR(address)\":{\"returns\":{\"_0\":\"the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account.\"}},\"getOwner()\":{\"returns\":{\"_owner\":\"Address of the owner. \"}},\"getPendingETHReward(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"the borrower's pending accumulated ETH reward, earned by their stake\"}},\"getPendingZUSDDebtReward(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"the borrower's pending accumulated ZUSD reward, earned by their stake\"}},\"getRedemptionFeeWithDecay(uint256)\":{\"params\":{\"_ETHDrawn\":\"ETH drawn\"}},\"getRedemptionRate()\":{\"returns\":{\"_0\":\"calculated redemption rate using baseRate\"}},\"getRedemptionRateWithDecay()\":{\"returns\":{\"_0\":\"calculated redemption rate using calculated decayed as base rate\"}},\"getTCR(uint256)\":{\"params\":{\"_price\":\"ETH price\"},\"returns\":{\"_0\":\"the total collateralization ratio (TCR) of the system. The TCR is based on the the entire system debt and collateral (including pending rewards).\"}},\"getTroveColl(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"Trove collateral from given trove\"}},\"getTroveDebt(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"Trove debt from given trove\"}},\"getTroveFromTroveOwnersArray(uint256)\":{\"params\":{\"_index\":\"Trove owner index\"},\"returns\":{\"_0\":\"Trove from TroveOwners array in given index\"}},\"getTroveOwnersCount()\":{\"returns\":{\"_0\":\"Trove owners count\"}},\"getTroveStake(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"Trove stake from given trove\"}},\"getTroveStatus(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"Trove status from given trove\"}},\"increaseTroveColl(address,uint256)\":{\"params\":{\"_borrower\":\"borrower address\",\"_collIncrease\":\"amount of collateral to increase\"},\"returns\":{\"_0\":\"new trove collateral\"}},\"increaseTroveDebt(address,uint256)\":{\"params\":{\"_borrower\":\"borrower address\",\"_debtIncrease\":\"amount of debt to increase\"},\"returns\":{\"_0\":\"new trove debt\"}},\"redeemCollateral(uint256,address,address,address,uint256,uint256,uint256)\":{\"details\":\"this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed\"},\"redeemCollateralViaDLLR(uint256,address,address,address,uint256,uint256,uint256,(uint256,uint8,bytes32,bytes32))\":{\"details\":\"this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\"},\"redeemCollateralViaDllrWithPermit2(uint256,address,address,address,uint256,uint256,uint256,((address,uint256),uint256,uint256),bytes)\":{\"details\":\"this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\"},\"removeStake(address)\":{\"params\":{\"_borrower\":\"borrower address\"}},\"setOwner(address)\":{\"params\":{\"_owner\":\"Address of the owner. \"}},\"updateStakeAndTotalStakes(address)\":{\"params\":{\"_borrower\":\"borrower address\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BETA()\":{\"notice\":\"BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption. Corresponds to (1 / ALPHA) in the white paper.\"},\"BOOTSTRAP_PERIOD()\":{\"notice\":\"During bootsrap period redemptions are not allowed\"},\"MIN_NET_DEBT()\":{\"notice\":\"Minimum amount of net ZUSD debt a trove must have\"},\"ZUSD_GAS_COMPENSATION()\":{\"notice\":\"Amount of ZUSD to be locked in gas pool on opening troves\"},\"_getCurrentICR(address,uint256)\":{\"notice\":\"Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\"},\"_getPendingETHReward(address)\":{\"notice\":\"Get the borrower's pending accumulated ETH reward, earned by their stake\"},\"_getPendingZUSDDebtReward(address)\":{\"notice\":\"Get the borrower's pending accumulated ZUSD reward, earned by their stake\"},\"addTroveOwnerToArray(address)\":{\"notice\":\"Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct\"},\"applyPendingRewards(address)\":{\"notice\":\"Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\"},\"batchLiquidateTroves(address[])\":{\"notice\":\"Attempt to liquidate a custom list of troves provided by the caller.\"},\"checkRecoveryMode(uint256)\":{\"notice\":\"reveals whether or not the system is in Recovery Mode (i.e. whether the Total Collateralization Ratio (TCR) is below the Critical Collateralization Ratio (CCR)).\"},\"closeTrove(address)\":{\"notice\":\"Close given trove. Called by BorrowerOperations.\"},\"decayBaseRateFromBorrowing()\":{\"notice\":\"Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation.\"},\"getCurrentICR(address,uint256)\":{\"notice\":\"computes the user\\u2019s individual collateralization ratio (ICR) based on their total collateral and total ZUSD debt. Returns 2^256 -1 if they have 0 debt.\"},\"getEntireDebtAndColl(address)\":{\"notice\":\"Return the Troves entire debt and coll, including pending rewards from redistributions.\"},\"getOwner()\":{\"notice\":\"Return address of the owner.\"},\"getRedemptionFeeWithDecay(uint256)\":{\"notice\":\"The redemption fee is taken as a cut of the total ETH drawn from the system in a redemption. It is based on the current redemption rate.\"},\"liquidate(address)\":{\"notice\":\"Single liquidation function. Closes the trove if its ICR is lower than the minimum collateral ratio.\"},\"liquidateTroves(uint256)\":{\"notice\":\"Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves, starting from the one with the lowest collateral ratio in the system, and moving upwards\"},\"permit2()\":{\"notice\":\"CONSTANT / IMMUTABLE VARIABLE ONLY \"},\"removeStake(address)\":{\"notice\":\"Remove borrower's stake from the totalStakes sum, and set their stake to 0\"},\"setOwner(address)\":{\"notice\":\"Set address of the owner (only owner can call this function)\"},\"updateStakeAndTotalStakes(address)\":{\"notice\":\"Update borrower's stake based on their latest collateral value\"},\"updateTroveRewardSnapshots(address)\":{\"notice\":\"Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/TroveManager.sol\":\"TroveManager\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"contracts/Dependencies/BaseMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\n\\ncontract BaseMath {\\n uint constant public DECIMAL_PRECISION = 1e18;\\n}\\n\",\"keccak256\":\"0x7e1369ca5cb09e818e345a2def19a261401f79c985a6030b55b7311dd6f53be4\",\"license\":\"MIT\"},\"contracts/Dependencies/CheckContract.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n\\ncontract CheckContract {\\n /**\\n * @dev Check that the account is an already deployed non-destroyed contract.\\n * See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L12\\n */\\n function checkContract(address _account) internal view {\\n require(_account != address(0), \\\"Account cannot be zero address\\\");\\n\\n uint256 size;\\n // solhint-disable-next-line no-inline-assembly\\n assembly { size := extcodesize(_account) }\\n require(size > 0, \\\"Account code size cannot be zero\\\");\\n }\\n}\\n\",\"keccak256\":\"0x4c7dc4d0197c27ebc7de671b00458a9ff45f57223aeb520e6ddd2eb6d2d89e5c\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on the OpenZeppelin IER20 interface:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol\\n *\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\\n function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n function name() external view returns (string memory);\\n function symbol() external view returns (string memory);\\n function decimals() external view returns (uint8);\\n \\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\",\"keccak256\":\"0xe0b2473eba89df8d27d7cea2a99fce788c212f3fd393c9508e449e51a3f220fa\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC2612.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * @dev Interface of the ERC2612 standard as defined in the EIP.\\n *\\n * Adds the {permit} method, which can be used to change one's\\n * {IERC20-allowance} without having to send a transaction, by signing a\\n * message. This allows users to spend tokens without having to hold Ether.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2612.\\n * \\n * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/\\n */\\ninterface IERC2612 {\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,\\n * given `owner`'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(address owner, address spender, uint256 amount, \\n uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;\\n \\n /**\\n * @dev Returns the current ERC2612 nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases `owner`'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n *\\n * `owner` can limit the time a Permit is valid for by setting `deadline` to \\n * a value in the near future. The deadline argument can be set to uint(-1) to \\n * create Permits that effectively never expire.\\n */\\n function nonces(address owner) external view returns (uint256);\\n \\n function version() external view returns (string memory);\\n function permitTypeHash() external view returns (bytes32);\\n function domainSeparator() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xd376458452f8b480bfea549637bd71d3f9eb1f12e9d59d1beff373417462d67f\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./BaseMath.sol\\\";\\nimport \\\"./LiquityMath.sol\\\";\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IPriceFeed.sol\\\";\\nimport \\\"../Interfaces/ILiquityBase.sol\\\";\\nimport \\\"../Interfaces/ILiquityBaseParams.sol\\\";\\n\\n/**\\n * Base contract for TroveManager, BorrowerOperations and StabilityPool. Contains global system constants and\\n * common functions.\\n */\\ncontract LiquityBase is BaseMath, ILiquityBase {\\n using SafeMath for uint256;\\n\\n uint256 public constant _100pct = 1000000000000000000; // 1e18 == 100%\\n\\n /// Amount of ZUSD to be locked in gas pool on opening troves\\n uint256 public constant ZUSD_GAS_COMPENSATION = 20e18;\\n\\n /// Minimum amount of net ZUSD debt a trove must have\\n uint256 public constant MIN_NET_DEBT = 180e18;\\n\\n IActivePool public activePool;\\n\\n IDefaultPool public defaultPool;\\n\\n IPriceFeed public override priceFeed;\\n\\n ILiquityBaseParams public override liquityBaseParams;\\n\\n // --- Gas compensation functions ---\\n\\n // Returns the composite debt (drawn debt + gas compensation) of a trove, for the purpose of ICR calculation\\n function _getCompositeDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.add(ZUSD_GAS_COMPENSATION);\\n }\\n\\n function _getNetDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.sub(ZUSD_GAS_COMPENSATION);\\n }\\n\\n /// Return the amount of ETH to be drawn from a trove's collateral and sent as gas compensation.\\n function _getCollGasCompensation(uint256 _entireColl) internal view returns (uint256) {\\n return _entireColl / liquityBaseParams.PERCENT_DIVISOR();\\n }\\n\\n function getEntireSystemColl() public view returns (uint256 entireSystemColl) {\\n uint256 activeColl = activePool.getETH();\\n uint256 liquidatedColl = defaultPool.getETH();\\n\\n return activeColl.add(liquidatedColl);\\n }\\n\\n function getEntireSystemDebt() public view returns (uint256 entireSystemDebt) {\\n uint256 activeDebt = activePool.getZUSDDebt();\\n uint256 closedDebt = defaultPool.getZUSDDebt();\\n\\n return activeDebt.add(closedDebt);\\n }\\n\\n function _getTCR(uint256 _price) internal view returns (uint256 TCR) {\\n uint256 entireSystemColl = getEntireSystemColl();\\n uint256 entireSystemDebt = getEntireSystemDebt();\\n\\n TCR = LiquityMath._computeCR(entireSystemColl, entireSystemDebt, _price);\\n\\n return TCR;\\n }\\n\\n function _checkRecoveryMode(uint256 _price) internal view returns (bool) {\\n uint256 TCR = _getTCR(_price);\\n\\n return TCR < liquityBaseParams.CCR();\\n }\\n\\n function _requireUserAcceptsFee(\\n uint256 _fee,\\n uint256 _amount,\\n uint256 _maxFeePercentage\\n ) internal pure {\\n uint256 feePercentage = _fee.mul(DECIMAL_PRECISION).div(_amount);\\n require(feePercentage <= _maxFeePercentage, \\\"Fee exceeded provided maximum\\\");\\n }\\n}\\n\",\"keccak256\":\"0x100b8a1c17caa95f5c9977e88f9263847a1977a365ca0a795753dd74aa1d6d7c\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./console.sol\\\";\\n\\nlibrary LiquityMath {\\n using SafeMath for uint;\\n\\n uint internal constant DECIMAL_PRECISION = 1e18;\\n\\n /* Precision for Nominal ICR (independent of price). Rationale for the value:\\n *\\n * - Making it \\u201ctoo high\\u201d could lead to overflows.\\n * - Making it \\u201ctoo low\\u201d could lead to an ICR equal to zero, due to truncation from Solidity floor division. \\n *\\n * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH,\\n * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.\\n *\\n */\\n uint internal constant NICR_PRECISION = 1e20;\\n\\n function _min(uint _a, uint _b) internal pure returns (uint) {\\n return (_a < _b) ? _a : _b;\\n }\\n\\n function _max(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a : _b;\\n }\\n\\n /* \\n * Multiply two decimal numbers and use normal rounding rules:\\n * -round product up if 19'th mantissa digit >= 5\\n * -round product down if 19'th mantissa digit < 5\\n *\\n * Used only inside the exponentiation, _decPow().\\n */\\n function decMul(uint x, uint y) internal pure returns (uint decProd) {\\n uint prod_xy = x.mul(y);\\n\\n decProd = prod_xy.add(DECIMAL_PRECISION / 2).div(DECIMAL_PRECISION);\\n }\\n\\n /* \\n * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.\\n * \\n * Uses the efficient \\\"exponentiation by squaring\\\" algorithm. O(log(n)) complexity. \\n * \\n * Called by two functions that represent time in units of minutes:\\n * 1) TroveManager._calcDecayedBaseRate\\n * 2) CommunityIssuance._getCumulativeIssuanceFraction \\n * \\n * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals\\n * \\\"minutes in 1000 years\\\": 60 * 24 * 365 * 1000\\n * \\n * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be\\n * negligibly different from just passing the cap, since: \\n *\\n * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years\\n * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible\\n */\\n function _decPow(uint _base, uint _minutes) internal pure returns (uint) {\\n \\n if (_minutes > 525600000) {_minutes = 525600000;} // cap to avoid overflow\\n \\n if (_minutes == 0) {return DECIMAL_PRECISION;}\\n\\n uint y = DECIMAL_PRECISION;\\n uint x = _base;\\n uint n = _minutes;\\n\\n // Exponentiation-by-squaring\\n while (n > 1) {\\n if (n % 2 == 0) {\\n x = decMul(x, x);\\n n = n.div(2);\\n } else { // if (n % 2 != 0)\\n y = decMul(x, y);\\n x = decMul(x, x);\\n n = (n.sub(1)).div(2);\\n }\\n }\\n\\n return decMul(x, y);\\n }\\n\\n function _getAbsoluteDifference(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a.sub(_b) : _b.sub(_a);\\n }\\n\\n function _computeNominalCR(uint _coll, uint _debt) internal pure returns (uint) {\\n if (_debt > 0) {\\n return _coll.mul(NICR_PRECISION).div(_debt);\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1;\\n }\\n }\\n\\n function _computeCR(uint _coll, uint _debt, uint _price) internal pure returns (uint) {\\n if (_debt > 0) {\\n uint newCollRatio = _coll.mul(_price).div(_debt);\\n\\n return newCollRatio;\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1; \\n }\\n }\\n}\\n\",\"keccak256\":\"0x7a95ed70d8937e0896c054b433ad0dfc87a9cfd028cae1694098e9d5d68127cd\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IMassetManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IMassetManager {\\n struct PermitParams {\\n uint256 deadline;\\n uint8 v;\\n bytes32 r;\\n bytes32 s;\\n }\\n\\n function mintTo(\\n address _bAsset,\\n uint256 _bAssetQuantity,\\n address _recipient\\n ) external returns (uint256);\\n\\n function getToken() external view returns (address);\\n\\n /**\\n * @dev Credits a recipient with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @param _recipient Address to credit with withdrawn bAssets.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeemTo(\\n address _bAsset,\\n uint256 _massetQuantity,\\n address _recipient\\n ) external returns (uint256 massetRedeemed);\\n}\\n\",\"keccak256\":\"0x3e8de462d45e8f07ef83b6b6e7eb90a5d09f21d3bcbb1225e8f781488ab4a771\",\"license\":\"MIT\"},\"contracts/Dependencies/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's Ownable contract:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\\n *\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable {\\n bytes32 private constant KEY_OWNER = keccak256(\\\"key.ownable.owner\\\");\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor () internal {\\n _setOwner(msg.sender);\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(msg.sender == getOwner(), \\\"Ownable:: access denied\\\");\\n _;\\n }\\n\\n /**\\n * @notice Set address of the owner.\\n * @param _owner Address of the owner.\\n * */\\n function _setOwner(address _owner) internal {\\n require(_owner != address(0), \\\"Ownable::setOwner: invalid address\\\");\\n emit OwnershipTransferred(getOwner(), _owner);\\n\\n bytes32 key = KEY_OWNER;\\n assembly {\\n sstore(key, _owner)\\n }\\n }\\n\\n /**\\n * @notice Set address of the owner (only owner can call this function)\\n * @param _owner Address of the owner.\\n * */\\n function setOwner(address _owner) public onlyOwner {\\n _setOwner(_owner);\\n }\\n\\n /**\\n * @notice Return address of the owner.\\n * @return _owner Address of the owner.\\n * */\\n function getOwner() public view returns (address _owner) {\\n bytes32 key = KEY_OWNER;\\n assembly {\\n _owner := sload(key)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xb5fc626e0b227fc0feb1d84440585015a0a5f586547d298534a604dd113efec6\",\"license\":\"MIT\"},\"contracts/Dependencies/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's SafeMath:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol\\n *\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x666b890992a066cc791f36c2975cd595d9761a014c654c385ed36ffaf658f3fd\",\"license\":\"MIT\"},\"contracts/Dependencies/TroveManagerBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IZUSDToken.sol\\\";\\nimport \\\"../Interfaces/IZEROStaking.sol\\\";\\nimport \\\"../Interfaces/ISortedTroves.sol\\\";\\nimport \\\"../Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"../TroveManagerStorage.sol\\\";\\nimport \\\"./LiquityBase.sol\\\";\\n\\ncontract TroveManagerBase is LiquityBase, TroveManagerStorage {\\n uint256 public constant SECONDS_IN_ONE_MINUTE = 60;\\n\\n uint256 public constant MINUTE_DECAY_FACTOR = 999037758833783000;\\n\\n /// During bootsrap period redemptions are not allowed\\n uint256 public immutable BOOTSTRAP_PERIOD;\\n\\n /**\\n BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption.\\n Corresponds to (1 / ALPHA) in the white paper.\\n */\\n uint256 public constant BETA = 2;\\n\\n /**\\n --- Variable container structs for liquidations ---\\n \\n These structs are used to hold, return and assign variables inside the liquidation functions,\\n in order to avoid the error: \\\"CompilerError: Stack too deep\\\".\\n */\\n\\n struct LocalVariables_OuterLiquidationFunction {\\n uint256 price;\\n uint256 ZUSDInStabPool;\\n bool recoveryModeAtStart;\\n uint256 liquidatedDebt;\\n uint256 liquidatedColl;\\n }\\n\\n struct LocalVariables_InnerSingleLiquidateFunction {\\n uint256 collToLiquidate;\\n uint256 pendingDebtReward;\\n uint256 pendingCollReward;\\n }\\n\\n struct LocalVariables_LiquidationSequence {\\n uint256 remainingZUSDInStabPool;\\n uint256 i;\\n uint256 ICR;\\n address user;\\n bool backToNormalMode;\\n uint256 entireSystemDebt;\\n uint256 entireSystemColl;\\n }\\n\\n struct LiquidationValues {\\n uint256 entireTroveDebt;\\n uint256 entireTroveColl;\\n uint256 collGasCompensation;\\n uint256 ZUSDGasCompensation;\\n uint256 debtToOffset;\\n uint256 collToSendToSP;\\n uint256 debtToRedistribute;\\n uint256 collToRedistribute;\\n uint256 collSurplus;\\n }\\n\\n struct LiquidationTotals {\\n uint256 totalCollInSequence;\\n uint256 totalDebtInSequence;\\n uint256 totalCollGasCompensation;\\n uint256 totalZUSDGasCompensation;\\n uint256 totalDebtToOffset;\\n uint256 totalCollToSendToSP;\\n uint256 totalDebtToRedistribute;\\n uint256 totalCollToRedistribute;\\n uint256 totalCollSurplus;\\n }\\n\\n struct ContractsCache {\\n IActivePool activePool;\\n IDefaultPool defaultPool;\\n IZUSDToken zusdToken;\\n IZEROStaking zeroStaking;\\n ISortedTroves sortedTroves;\\n ICollSurplusPool collSurplusPool;\\n address gasPoolAddress;\\n }\\n // --- Variable container structs for redemptions ---\\n\\n struct RedemptionTotals {\\n uint256 remainingZUSD;\\n uint256 totalZUSDToRedeem;\\n uint256 totalETHDrawn;\\n uint256 ETHFee;\\n uint256 ETHToSendToRedeemer;\\n uint256 decayedBaseRate;\\n uint256 price;\\n uint256 totalZUSDSupplyAtStart;\\n }\\n\\n struct SingleRedemptionValues {\\n uint256 ZUSDLot;\\n uint256 ETHLot;\\n bool cancelledPartial;\\n }\\n\\n // --- Events ---\\n\\n event Liquidation(\\n uint256 _liquidatedDebt,\\n uint256 _liquidatedColl,\\n uint256 _collGasCompensation,\\n uint256 _ZUSDGasCompensation\\n );\\n event Redemption(\\n uint256 _attemptedZUSDAmount,\\n uint256 _actualZUSDAmount,\\n uint256 _ETHSent,\\n uint256 _ETHFee\\n );\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 _stake,\\n TroveManagerOperation _operation\\n );\\n event TroveLiquidated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n TroveManagerOperation _operation\\n );\\n event BaseRateUpdated(uint256 _baseRate);\\n event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);\\n event TotalStakesUpdated(uint256 _newTotalStakes);\\n event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);\\n event LTermsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveIndexUpdated(address _borrower, uint256 _newIndex);\\n\\n enum TroveManagerOperation {\\n applyPendingRewards,\\n liquidateInNormalMode,\\n liquidateInRecoveryMode,\\n redeemCollateral\\n }\\n\\n constructor(uint256 _bootstrapPeriod) public {\\n BOOTSTRAP_PERIOD = _bootstrapPeriod;\\n }\\n\\n /// Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function _getCurrentICR(address _borrower, uint256 _price) public view returns (uint256) {\\n (uint256 currentETH, uint256 currentZUSDDebt) = _getCurrentTroveAmounts(_borrower);\\n\\n uint256 ICR = LiquityMath._computeCR(currentETH, currentZUSDDebt, _price);\\n return ICR;\\n }\\n\\n function _getCurrentTroveAmounts(address _borrower) internal view returns (uint256, uint256) {\\n uint256 pendingETHReward = _getPendingETHReward(_borrower);\\n uint256 pendingZUSDDebtReward = _getPendingZUSDDebtReward(_borrower);\\n\\n uint256 currentETH = Troves[_borrower].coll.add(pendingETHReward);\\n uint256 currentZUSDDebt = Troves[_borrower].debt.add(pendingZUSDDebtReward);\\n\\n return (currentETH, currentZUSDDebt);\\n }\\n\\n /// Get the borrower's pending accumulated ETH reward, earned by their stake\\n function _getPendingETHReward(address _borrower) public view returns (uint256) {\\n uint256 snapshotETH = rewardSnapshots[_borrower].ETH;\\n uint256 rewardPerUnitStaked = L_ETH.sub(snapshotETH);\\n\\n if (rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) {\\n return 0;\\n }\\n\\n uint256 stake = Troves[_borrower].stake;\\n\\n uint256 pendingETHReward = stake.mul(rewardPerUnitStaked).div(DECIMAL_PRECISION);\\n\\n return pendingETHReward;\\n }\\n\\n /// Get the borrower's pending accumulated ZUSD reward, earned by their stake\\n function _getPendingZUSDDebtReward(address _borrower) public view returns (uint256) {\\n uint256 snapshotZUSDDebt = rewardSnapshots[_borrower].ZUSDDebt;\\n uint256 rewardPerUnitStaked = L_ZUSDDebt.sub(snapshotZUSDDebt);\\n\\n if (rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) {\\n return 0;\\n }\\n\\n uint256 stake = Troves[_borrower].stake;\\n\\n uint256 pendingZUSDDebtReward = stake.mul(rewardPerUnitStaked).div(DECIMAL_PRECISION);\\n\\n return pendingZUSDDebtReward;\\n }\\n\\n /// Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\\n function _applyPendingRewards(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n address _borrower\\n ) internal {\\n if (_hasPendingRewards(_borrower)) {\\n _requireTroveIsActive(_borrower);\\n\\n // Compute pending rewards\\n uint256 pendingETHReward = _getPendingETHReward(_borrower);\\n uint256 pendingZUSDDebtReward = _getPendingZUSDDebtReward(_borrower);\\n\\n // Apply pending rewards to trove's state\\n Troves[_borrower].coll = Troves[_borrower].coll.add(pendingETHReward);\\n Troves[_borrower].debt = Troves[_borrower].debt.add(pendingZUSDDebtReward);\\n\\n _updateTroveRewardSnapshots(_borrower);\\n\\n // Transfer from DefaultPool to ActivePool\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n pendingZUSDDebtReward,\\n pendingETHReward\\n );\\n\\n emit TroveUpdated(\\n _borrower,\\n Troves[_borrower].debt,\\n Troves[_borrower].coll,\\n Troves[_borrower].stake,\\n TroveManagerOperation.applyPendingRewards\\n );\\n }\\n }\\n\\n function _hasPendingRewards(address _borrower) public view returns (bool) {\\n /*\\n * A Trove has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:\\n * this indicates that rewards have occured since the snapshot was made, and the user therefore has\\n * pending rewards\\n */\\n if (Troves[_borrower].status != Status.active) {\\n return false;\\n }\\n\\n return (rewardSnapshots[_borrower].ETH < L_ETH);\\n }\\n\\n function _updateTroveRewardSnapshots(address _borrower) internal {\\n rewardSnapshots[_borrower].ETH = L_ETH;\\n rewardSnapshots[_borrower].ZUSDDebt = L_ZUSDDebt;\\n emit TroveSnapshotsUpdated(L_ETH, L_ZUSDDebt);\\n }\\n\\n /// Move a Trove's pending debt and collateral rewards from distributions, from the Default Pool to the Active Pool\\n function _movePendingTroveRewardsToActivePool(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _ZUSD,\\n uint256 _ETH\\n ) internal {\\n _defaultPool.decreaseZUSDDebt(_ZUSD);\\n _activePool.increaseZUSDDebt(_ZUSD);\\n _defaultPool.sendETHToActivePool(_ETH);\\n }\\n\\n /// Remove borrower's stake from the totalStakes sum, and set their stake to 0\\n function _removeStake(address _borrower) internal {\\n uint256 stake = Troves[_borrower].stake;\\n totalStakes = totalStakes.sub(stake);\\n Troves[_borrower].stake = 0;\\n }\\n\\n function _closeTrove(address _borrower, Status closedStatus) internal {\\n assert(closedStatus != Status.nonExistent && closedStatus != Status.active);\\n\\n uint256 TroveOwnersArrayLength = TroveOwners.length;\\n _requireMoreThanOneTroveInSystem(TroveOwnersArrayLength);\\n\\n Troves[_borrower].status = closedStatus;\\n Troves[_borrower].coll = 0;\\n Troves[_borrower].debt = 0;\\n\\n rewardSnapshots[_borrower].ETH = 0;\\n rewardSnapshots[_borrower].ZUSDDebt = 0;\\n\\n _removeTroveOwner(_borrower, TroveOwnersArrayLength);\\n sortedTroves.remove(_borrower);\\n }\\n\\n /// Update borrower's stake based on their latest collateral value\\n function _updateStakeAndTotalStakes(address _borrower) internal returns (uint256) {\\n uint256 newStake = _computeNewStake(Troves[_borrower].coll);\\n uint256 oldStake = Troves[_borrower].stake;\\n Troves[_borrower].stake = newStake;\\n\\n totalStakes = totalStakes.sub(oldStake).add(newStake);\\n emit TotalStakesUpdated(totalStakes);\\n\\n return newStake;\\n }\\n\\n // Calculate a new stake based on the snapshots of the totalStakes and totalCollateral taken at the last liquidation\\n function _computeNewStake(uint256 _coll) internal view returns (uint256) {\\n uint256 stake;\\n if (totalCollateralSnapshot == 0) {\\n stake = _coll;\\n } else {\\n /*\\n * The following assert() holds true because:\\n * - The system always contains >= 1 trove\\n * - When we close or liquidate a trove, we redistribute the pending rewards, so if all troves were closed/liquidated,\\n * rewards would\\u2019ve been emptied and totalCollateralSnapshot would be zero too.\\n */\\n assert(totalStakesSnapshot > 0);\\n stake = _coll.mul(totalStakesSnapshot).div(totalCollateralSnapshot);\\n }\\n return stake;\\n }\\n\\n function _calcDecayedBaseRate() internal view returns (uint256) {\\n uint256 minutesPassed = _minutesPassedSinceLastFeeOp();\\n uint256 decayFactor = LiquityMath._decPow(MINUTE_DECAY_FACTOR, minutesPassed);\\n\\n return baseRate.mul(decayFactor).div(DECIMAL_PRECISION);\\n }\\n\\n function _minutesPassedSinceLastFeeOp() internal view returns (uint256) {\\n return (block.timestamp.sub(lastFeeOperationTime)).div(SECONDS_IN_ONE_MINUTE);\\n }\\n\\n // Update the last fee operation time only if time passed >= decay interval. This prevents base rate griefing.\\n function _updateLastFeeOpTime() internal {\\n uint256 timePassed = block.timestamp.sub(lastFeeOperationTime);\\n\\n if (timePassed >= SECONDS_IN_ONE_MINUTE) {\\n lastFeeOperationTime = block.timestamp;\\n emit LastFeeOpTimeUpdated(block.timestamp);\\n }\\n }\\n\\n function _calcRedemptionFee(\\n uint256 _redemptionRate,\\n uint256 _ETHDrawn\\n ) internal pure returns (uint256) {\\n uint256 redemptionFee = _redemptionRate.mul(_ETHDrawn).div(DECIMAL_PRECISION);\\n require(\\n redemptionFee < _ETHDrawn,\\n \\\"TroveManager: Fee would eat up all returned collateral\\\"\\n );\\n return redemptionFee;\\n }\\n\\n function _getRedemptionRate() public view returns (uint256) {\\n return _calcRedemptionRate(baseRate);\\n }\\n\\n function _getRedemptionFee(uint256 _ETHDrawn) internal view returns (uint256) {\\n return _calcRedemptionFee(_getRedemptionRate(), _ETHDrawn);\\n }\\n\\n function _calcRedemptionRate(uint256 _baseRate) internal view returns (uint256) {\\n return\\n LiquityMath._min(\\n liquityBaseParams.REDEMPTION_FEE_FLOOR().add(_baseRate),\\n DECIMAL_PRECISION // cap at a maximum of 100%\\n );\\n }\\n\\n /**\\n Remove a Trove owner from the TroveOwners array, not preserving array order. Removing owner 'B' does the following:\\n [A B C D E] => [A E C D], and updates E's Trove struct to point to its new array index.\\n */\\n function _removeTroveOwner(address _borrower, uint256 TroveOwnersArrayLength) internal {\\n Status troveStatus = Troves[_borrower].status;\\n // It\\u2019s set in caller function `_closeTrove`\\n assert(troveStatus != Status.nonExistent && troveStatus != Status.active);\\n\\n uint128 index = Troves[_borrower].arrayIndex;\\n uint256 length = TroveOwnersArrayLength;\\n uint256 idxLast = length.sub(1);\\n\\n assert(index <= idxLast);\\n\\n address addressToMove = TroveOwners[idxLast];\\n\\n TroveOwners[index] = addressToMove;\\n Troves[addressToMove].arrayIndex = index;\\n emit TroveIndexUpdated(addressToMove, index);\\n\\n TroveOwners.pop();\\n }\\n\\n // --- 'require' wrapper functions ---\\n\\n function _requireCallerIsBorrowerOperations() internal view {\\n require(\\n msg.sender == borrowerOperationsAddress,\\n \\\"TroveManager: Caller is not the BorrowerOperations contract\\\"\\n );\\n }\\n\\n function _requireTroveIsActive(address _borrower) internal view {\\n require(\\n Troves[_borrower].status == Status.active,\\n \\\"TroveManager: Trove does not exist or is closed\\\"\\n );\\n }\\n\\n function _requireZUSDBalanceCoversRedemption(\\n IZUSDToken _zusdToken,\\n address _redeemer,\\n uint256 _amount\\n ) internal view {\\n require(\\n _zusdToken.balanceOf(_redeemer) >= _amount,\\n \\\"TroveManager: Requested redemption amount must be <= user's ZUSD token balance\\\"\\n );\\n }\\n\\n function _requireMoreThanOneTroveInSystem(uint256 TroveOwnersArrayLength) internal view {\\n require(\\n TroveOwnersArrayLength > 1 && sortedTroves.getSize() > 1,\\n \\\"TroveManager: Only one trove in the system\\\"\\n );\\n }\\n\\n function _requireAmountGreaterThanZero(uint256 _amount) internal pure {\\n require(_amount > 0, \\\"TroveManager: Amount must be greater than zero\\\");\\n }\\n\\n function _requireTCRoverMCR(uint256 _price) internal view {\\n require(\\n _getTCR(_price) >= liquityBaseParams.MCR(),\\n \\\"TroveManager: Cannot redeem when TCR < MCR\\\"\\n );\\n }\\n\\n function _requireAfterBootstrapPeriod() internal view {\\n uint256 systemDeploymentTime = _zeroToken.getDeploymentStartTime();\\n require(\\n block.timestamp >= systemDeploymentTime.add(BOOTSTRAP_PERIOD),\\n \\\"TroveManager: Redemptions are not allowed during bootstrap phase\\\"\\n );\\n }\\n\\n function _requireValidMaxFeePercentage(uint256 _maxFeePercentage) internal view {\\n require(\\n _maxFeePercentage >= liquityBaseParams.REDEMPTION_FEE_FLOOR() &&\\n _maxFeePercentage <= DECIMAL_PRECISION,\\n \\\"Max fee percentage must be between 0.5% and 100%\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x83e1bfaa93cf973052c41df1cc0741a93f737659cd664f207c0d42256f78617b\",\"license\":\"MIT\"},\"contracts/Dependencies/console.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Buidler's helper contract for console logging\\nlibrary console {\\n\\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\\n\\n\\tfunction log() internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log()\\\"));\\n\\t\\tignored;\\n\\t}\\tfunction logInt(int p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(int)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logUint(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logString(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBool(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logAddress(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes(bytes memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logByte(byte p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(byte)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes1(bytes1 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes1)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes2(bytes2 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes2)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes3(bytes3 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes3)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes4(bytes4 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes4)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes5(bytes5 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes5)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes6(bytes6 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes6)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes7(bytes7 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes7)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes8(bytes8 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes8)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes9(bytes9 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes9)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes10(bytes10 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes10)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes11(bytes11 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes11)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes12(bytes12 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes12)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes13(bytes13 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes13)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes14(bytes14 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes14)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes15(bytes15 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes15)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes16(bytes16 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes16)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes17(bytes17 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes17)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes18(bytes18 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes18)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes19(bytes19 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes19)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes20(bytes20 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes20)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes21(bytes21 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes21)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes22(bytes22 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes22)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes23(bytes23 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes23)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes24(bytes24 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes24)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes25(bytes25 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes25)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes26(bytes26 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes26)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes27(bytes27 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes27)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes28(bytes28 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes28)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes29(bytes29 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes29)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes30(bytes30 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes30)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes31(bytes31 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes31)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes32(bytes32 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes32)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n}\\n\",\"keccak256\":\"0x6fa1de4ffe22b8f58b0b64d65db11dd5037be9b9db47b365a72adb489e217000\",\"license\":\"MIT\"},\"contracts/Interfaces/IActivePool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\n/**\\n * The Active Pool holds the ETH collateral and ZUSD debt (but not ZUSD tokens) for all active troves.\\n *\\n * When a trove is liquidated, it's ETH and ZUSD debt are transferred from the Active Pool, to either the\\n * Stability Pool, the Default Pool, or both, depending on the liquidation conditions.\\n *\\n */\\ninterface IActivePool is IPool {\\n // --- Events ---\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolZUSDDebtUpdated(uint _ZUSDDebt);\\n event ActivePoolETHBalanceUpdated(uint _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH amount to given account. Updates ActivePool balance. Only callable by BorrowerOperations, TroveManager or StabilityPool.\\n /// @param _account account to receive the ETH amount\\n /// @param _amount ETH amount to send\\n function sendETH(address _account, uint _amount) external;\\n}\\n\",\"keccak256\":\"0xdd5f1b6fae4050b4c885a85a10c2d0e73b82187a51736d009065aaeea33bf0d0\",\"license\":\"MIT\"},\"contracts/Interfaces/IAllowanceTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title AllowanceTransfer\\n/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface IAllowanceTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an ordered nonce.\\n event NonceInvalidation(\\n address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.\\n event Approval(\\n address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.\\n event Permit(\\n address indexed owner,\\n address indexed token,\\n address indexed spender,\\n uint160 amount,\\n uint48 expiration,\\n uint48 nonce\\n );\\n\\n /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.\\n event Lockdown(address indexed owner, address token, address spender);\\n\\n /// @notice The permit data for a token\\n struct PermitDetails {\\n // ERC20 token address\\n address token;\\n // the maximum amount allowed to spend\\n uint160 amount;\\n // timestamp at which a spender's token allowances become invalid\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice The permit message signed for a single token allowance\\n struct PermitSingle {\\n // the permit data for a single token alownce\\n PermitDetails details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The permit message signed for multiple token allowances\\n struct PermitBatch {\\n // the permit data for multiple token allowances\\n PermitDetails[] details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The saved permissions\\n /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n struct PackedAllowance {\\n // amount allowed\\n uint160 amount;\\n // permission expiry\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice A token spender pair.\\n struct TokenSpenderPair {\\n // the token the spender is approved\\n address token;\\n // the spender address\\n address spender;\\n }\\n\\n /// @notice Details for a token transfer.\\n struct AllowanceTransferDetails {\\n // the owner of the token\\n address from;\\n // the recipient of the token\\n address to;\\n // the amount of the token\\n uint160 amount;\\n // the token to be transferred\\n address token;\\n }\\n\\n /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.\\n /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]\\n /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.\\n function allowance(address user, address token, address spender)\\n external\\n view\\n returns (uint160 amount, uint48 expiration, uint48 nonce);\\n\\n /// @notice Approves the spender to use up to amount of the specified token up until the expiration\\n /// @param token The token to approve\\n /// @param spender The spender address to approve\\n /// @param amount The approved amount of the token\\n /// @param expiration The timestamp at which the approval is no longer valid\\n /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n function approve(address token, address spender, uint160 amount, uint48 expiration) external;\\n\\n /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitSingle Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;\\n\\n /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitBatch Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;\\n\\n /// @notice Transfer approved tokens from one address to another\\n /// @param from The address to transfer from\\n /// @param to The address of the recipient\\n /// @param amount The amount of the token to transfer\\n /// @param token The token address to transfer\\n /// @dev Requires the from address to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(address from, address to, uint160 amount, address token) external;\\n\\n /// @notice Transfer approved tokens in a batch\\n /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers\\n /// @dev Requires the from addresses to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;\\n\\n /// @notice Enables performing a \\\"lockdown\\\" of the sender's Permit2 identity\\n /// by batch revoking approvals\\n /// @param approvals Array of approvals to revoke.\\n function lockdown(TokenSpenderPair[] calldata approvals) external;\\n\\n /// @notice Invalidate nonces for a given (token, spender) pair\\n /// @param token The token to invalidate nonces for\\n /// @param spender The spender to invalidate nonces for\\n /// @param newNonce The new nonce to set. Invalidates all nonces less than it.\\n /// @dev Can't invalidate more than 2**16 nonces per transaction.\\n function invalidateNonces(address token, address spender, uint48 newNonce) external;\\n}\\n\",\"keccak256\":\"0xf15059fb68f89542908f963f22e18c0b0ae9997a6f9aaf6a9fb46aa2424acac9\",\"license\":\"MIT\"},\"contracts/Interfaces/ICollSurplusPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ICollSurplusPool {\\n // --- Events ---\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n\\n event CollBalanceUpdated(address indexed _account, uint256 _newBalance);\\n event EtherSent(address _to, uint256 _amount);\\n\\n // --- Contract setters ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH state variable\\n function getETH() external view returns (uint256);\\n\\n /// @param _account account to retrieve collateral\\n /// @return collateral\\n function getCollateral(address _account) external view returns (uint256);\\n\\n /// @notice adds amount to current account balance. Only callable by TroveManager.\\n /// @param _account account to add amount\\n /// @param _amount amount to add\\n function accountSurplus(address _account, uint256 _amount) external;\\n\\n /// @notice claims collateral for given account. Only callable by BorrowerOperations.\\n /// @param _account account to send claimable collateral\\n function claimColl(address _account) external;\\n}\\n\",\"keccak256\":\"0xac983936efe70d19205bff65a18b4e6000d489d4e4d1e2e92f951873cee91048\",\"license\":\"MIT\"},\"contracts/Interfaces/IDefaultPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\ninterface IDefaultPool is IPool {\\n // --- Events ---\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event DefaultPoolZUSDDebtUpdated(uint256 _ZUSDDebt);\\n event DefaultPoolETHBalanceUpdated(uint256 _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH to Active Pool\\n /// @param _amount ETH to send\\n function sendETHToActivePool(uint256 _amount) external;\\n}\\n\",\"keccak256\":\"0xfb2607676b2eb0f2defd248b4dd32895820048317f29aa6bdb572403a3e3d44e\",\"license\":\"MIT\"},\"contracts/Interfaces/IEIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\ninterface IEIP712 {\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xff52e9168eaa532ebacdad2ab6197f60171e3aa2fa2c1d6397d9da4d7782a543\",\"license\":\"MIT\"},\"contracts/Interfaces/IFeeDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/// Common interface for Fee Distributor.\\ninterface IFeeDistributor {\\n // --- Events ---\\n\\n event FeeSharingCollectorAddressChanged(address _feeSharingCollectorAddress);\\n event ZeroStakingAddressChanged(address _zeroStakingAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event WrbtcAddressChanged(address _wrbtcAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event ZUSDDistributed(uint256 _zusdDistributedAmount);\\n event RBTCistributed(uint256 _rbtcDistributedAmount);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeSharingCollectorAddress FeeSharingCollector address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n * @param _borrowerOperationsAddress borrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _wrbtcAddress wrbtc ERC20 contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _feeSharingCollectorAddress,\\n address _zeroStakingAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _wrbtcAddress,\\n address _zusdTokenAddress,\\n address _activePoolAddress\\n ) external;\\n\\n function distributeFees() external;\\n}\\n\",\"keccak256\":\"0x4b9bc6eaa8a9ea5e0570ffd84c0af2a92e74b001ae1ee1c8518d76382691a07f\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPriceFeed.sol\\\";\\nimport \\\"./ILiquityBaseParams.sol\\\";\\n\\ninterface ILiquityBase {\\n /// @return PriceFeed contract\\n function priceFeed() external view returns (IPriceFeed);\\n\\n /// @return LiquityBaseParams contract\\n function liquityBaseParams() external view returns (ILiquityBaseParams);\\n}\\n\",\"keccak256\":\"0xa4a57bd79e64d56a687c28d2a35c55b733fde8dda2a7ba861606eed3211724e1\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBaseParams.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ILiquityBaseParams {\\n\\n /// Minimum collateral ratio for individual troves\\n function MCR() external view returns (uint);\\n\\n /// Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.\\n function CCR() external view returns (uint);\\n\\n function PERCENT_DIVISOR() external view returns (uint);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint);\\n\\n /**\\n * Half-life of 12h. 12h = 720 min\\n * (1/2) = d^720 => d = (1/2)^(1/720)\\n */\\n function REDEMPTION_FEE_FLOOR() external view returns (uint);\\n\\n function MAX_BORROWING_FEE() external view returns (uint);\\n\\n}\",\"keccak256\":\"0xef8c0e8ad5d13d604c11b04983ff5bdd41768b646f2b33f45ddd988adec204e0\",\"license\":\"MIT\"},\"contracts/Interfaces/IPermit2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {ISignatureTransfer} from \\\"./ISignatureTransfer.sol\\\";\\nimport {IAllowanceTransfer} from \\\"./IAllowanceTransfer.sol\\\";\\n\\n/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer.\\n/// @dev Users must approve Permit2 before calling any of the transfer functions.\\ninterface IPermit2 is ISignatureTransfer, IAllowanceTransfer {\\n// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval.\\n}\\n\",\"keccak256\":\"0x3df819f5ca8de7324a676839d72e9f44c0f789c41c13bf0a892f3bb98d72ee86\",\"license\":\"MIT\"},\"contracts/Interfaces/IPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the Pools.\\ninterface IPool {\\n // --- Events ---\\n\\n event ETHBalanceUpdated(uint _newBalance);\\n event ZUSDBalanceUpdated(uint _newBalance);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event EtherSent(address _to, uint _amount);\\n\\n // --- Functions ---\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH pool balance\\n function getETH() external view returns (uint);\\n\\n /// @return ZUSD debt pool balance\\n function getZUSDDebt() external view returns (uint);\\n\\n /// @notice Increases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to add to the pool debt\\n function increaseZUSDDebt(uint _amount) external;\\n\\n /// @notice Decreases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to subtract to the pool debt\\n function decreaseZUSDDebt(uint _amount) external;\\n}\\n\",\"keccak256\":\"0x148e87ab38c6176d74f36c9e8989b99e768a7b18d8a045f1f01d6583b986806d\",\"license\":\"MIT\"},\"contracts/Interfaces/IPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IPriceFeed {\\n // --- Events ---\\n event LastGoodPriceUpdated(uint256 _lastGoodPrice);\\n\\n // --- Function ---\\n\\n /// @notice Returns the latest price obtained from the Oracle. Called by Zero functions that require a current price.\\n /// It uses the main price feed and fallback to the backup one in case of an error. If both fail return the last\\n /// good price seen.\\n /// @dev It's also callable by anyone externally\\n /// @return The price\\n function fetchPrice() external returns (uint256);\\n}\\n\",\"keccak256\":\"0x85fd97219a8156209d2cb5c6ae7c5ead01d893db000bf575023fcef0e62f9591\",\"license\":\"MIT\"},\"contracts/Interfaces/ISignatureTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title SignatureTransfer\\n/// @notice Handles ERC20 token transfers through signature based actions\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface ISignatureTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an unordered nonce.\\n event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);\\n\\n /// @notice The token and amount details for a transfer signed in the permit transfer signature\\n struct TokenPermissions {\\n // ERC20 token address\\n address token;\\n // the maximum amount that can be spent\\n uint256 amount;\\n }\\n\\n /// @notice The signed permit message for a single token transfer\\n struct PermitTransferFrom {\\n TokenPermissions permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice Specifies the recipient address and amount for batched transfers.\\n /// @dev Recipients and amounts correspond to the index of the signed token permissions array.\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount.\\n struct SignatureTransferDetails {\\n // recipient address\\n address to;\\n // spender requested amount\\n uint256 requestedAmount;\\n }\\n\\n /// @notice Used to reconstruct the signed permit message for multiple token transfers\\n /// @dev Do not need to pass in spender address as it is required that it is msg.sender\\n /// @dev Note that a user still signs over a spender address\\n struct PermitBatchTransferFrom {\\n // the tokens and corresponding amounts permitted for a transfer\\n TokenPermissions[] permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection\\n /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order\\n /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce\\n /// @dev It returns a uint256 bitmap\\n /// @dev The index, or wordPosition is capped at type(uint248).max\\n function nonceBitmap(address, uint256) external view returns (uint256);\\n\\n /// @notice Transfers a token using a signed permit message\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails The spender's requested transfer details for the permitted token\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitTransferFrom memory permit,\\n SignatureTransferDetails calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Transfers multiple tokens using a signed permit message\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails Specifies the recipient and requested amount for the token transfer\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitBatchTransferFrom memory permit,\\n SignatureTransferDetails[] calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Invalidates the bits specified in mask for the bitmap at the word position\\n /// @dev The wordPos is maxed at type(uint248).max\\n /// @param wordPos A number to index the nonceBitmap at\\n /// @param mask A bitmap masked against msg.sender's current bitmap at the word position\\n function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;\\n}\\n\",\"keccak256\":\"0x7efc63c119694e23dd76e44a5b125999829026bbc23409de7646a6a45e1ac341\",\"license\":\"MIT\"},\"contracts/Interfaces/ISortedTroves.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the SortedTroves Doubly Linked List.\\ninterface ISortedTroves {\\n // --- Events ---\\n\\n event SortedTrovesAddressChanged(address _sortedDoublyLLAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event NodeAdded(address _id, uint256 _NICR);\\n event NodeRemoved(address _id);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts and size. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _size max size of troves list\\n * @param _TroveManagerAddress TroveManager contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n */\\n function setParams(\\n uint256 _size,\\n address _TroveManagerAddress,\\n address _borrowerOperationsAddress\\n ) external;\\n\\n /**\\n * @dev Add a node to the list\\n * @param _id Node's id\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function insert(\\n address _id,\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Remove a node from the list\\n * @param _id Node's id\\n */\\n function remove(address _id) external;\\n\\n /**\\n * @dev Re-insert the node at a new position, based on its new NICR\\n * @param _id Node's id\\n * @param _newICR Node's new NICR\\n * @param _prevId Id of previous node for the new insert position\\n * @param _nextId Id of next node for the new insert position\\n */\\n function reInsert(\\n address _id,\\n uint256 _newICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Checks if the list contains a node\\n * @param _id Node's id\\n * @return true if list contains a node with given id\\n */\\n function contains(address _id) external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is full\\n * @return true if list is full\\n */\\n function isFull() external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is empty\\n * @return true if list is empty\\n */\\n function isEmpty() external view returns (bool);\\n\\n /**\\n * @return list current size\\n */\\n function getSize() external view returns (uint256);\\n\\n /**\\n * @return list max size\\n */\\n function getMaxSize() external view returns (uint256);\\n\\n /**\\n * @return the first node in the list (node with the largest NICR)\\n */\\n function getFirst() external view returns (address);\\n\\n /**\\n * @return the last node in the list (node with the smallest NICR)\\n */\\n function getLast() external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the next node (with a smaller NICR) in the list for a given node\\n */\\n function getNext(address _id) external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the previous node (with a larger NICR) in the list for a given node\\n */\\n function getPrev(address _id) external view returns (address);\\n\\n /**\\n * @notice Check if a pair of nodes is a valid insertion point for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function validInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (bool);\\n\\n /**\\n * @notice Find the insert position for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function findInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (address, address);\\n}\\n\",\"keccak256\":\"0x7328ad009da6230ddea1559564428464a5c3ace2258fb534dfbba5b5a8c7c60d\",\"license\":\"MIT\"},\"contracts/Interfaces/IStabilityPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/*\\n * The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors.\\n *\\n * When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with\\n * ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned.\\n *\\n * Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits.\\n * They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors,\\n * in the same proportion.\\n *\\n * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40%\\n * of the total ZUSD in the Stability Pool, depletes 40% of each deposit.\\n *\\n * A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit,\\n * multiplying it by some factor in range ]0,1[\\n *\\n * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations:\\n * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf\\n *\\n * --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS ---\\n *\\n * An SOV issuance event occurs at every deposit operation, and every liquidation.\\n *\\n * Each deposit is tagged with the address of the front end through which it was made.\\n *\\n * All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned\\n * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate.\\n *\\n * Please see the system Readme for an overview:\\n * https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers\\n */\\ninterface IStabilityPool {\\n // --- Events ---\\n\\n event StabilityPoolETHBalanceUpdated(uint _newBalance);\\n event StabilityPoolZUSDBalanceUpdated(uint _newBalance);\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event SortedTrovesAddressChanged(address _newSortedTrovesAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);\\n\\n event P_Updated(uint _P);\\n event S_Updated(uint _S, uint128 _epoch, uint128 _scale);\\n event G_Updated(uint _G, uint128 _epoch, uint128 _scale);\\n event EpochUpdated(uint128 _currentEpoch);\\n event ScaleUpdated(uint128 _currentScale);\\n\\n event FrontEndRegistered(address indexed _frontEnd, uint _kickbackRate);\\n event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd);\\n\\n event DepositSnapshotUpdated(address indexed _depositor, uint _P, uint _S, uint _G);\\n event FrontEndSnapshotUpdated(address indexed _frontEnd, uint _P, uint _G);\\n event UserDepositChanged(address indexed _depositor, uint _newDeposit);\\n event FrontEndStakeChanged(\\n address indexed _frontEnd,\\n uint _newFrontEndStake,\\n address _depositor\\n );\\n\\n event ETHGainWithdrawn(address indexed _depositor, uint _ETH, uint _ZUSDLoss);\\n event SOVPaidToDepositor(address indexed _depositor, uint _SOV);\\n event SOVPaidToFrontEnd(address indexed _frontEnd, uint _SOV);\\n event EtherSent(address _to, uint _amount);\\n\\n event WithdrawFromSpAndConvertToDLLR(\\n address _depositor,\\n uint256 _zusdAmountRequested,\\n uint256 _dllrAmountReceived\\n );\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Liquity contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _priceFeedAddress PriceFeed contract address\\n * @param _communityIssuanceAddress CommunityIssuanceAddress\\n */\\n function setAddresses(\\n address _liquityBaseParamsAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _zusdTokenAddress,\\n address _sortedTrovesAddress,\\n address _priceFeedAddress,\\n address _communityIssuanceAddress\\n ) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend is registered or zero address\\n * - Sender is not a registered frontend\\n * - _amount is not zero\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Tags the deposit with the provided front end tag param, if it's a new deposit\\n * - Sends depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Increases deposit and tagged front end's stake, and takes new snapshots for each.\\n * @param _amount amount to provide\\n * @param _frontEndTag frontend address to receive accumulated SOV gains\\n */\\n function provideToSP(uint _amount, address _frontEndTag) external;\\n\\n /**\\n * @notice Initial checks:\\n * - _amount is zero or there are no under collateralized troves left in the system\\n * - User has a non zero deposit\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Removes the deposit's front end tag if it is a full withdrawal\\n * - Sends all depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.\\n *\\n * If _amount > userDeposit, the user withdraws all of their compounded deposit.\\n * @param _amount amount to withdraw\\n */\\n function withdrawFromSP(uint _amount) external;\\n\\n /**\\n * @notice Initial checks:\\n * - User has a non zero deposit\\n * - User has an open trove\\n * - User has some ETH gain\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Sends all depositor's SOV gain to depositor\\n * - Sends all tagged front end's SOV gain to the tagged front end\\n * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove\\n * - Leaves their compounded deposit in the Stability Pool\\n * - Updates snapshots for deposit and tagged front end stake\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend (sender) not already registered\\n * - User (sender) has no deposit\\n * - _kickbackRate is in the range [0, 100%]\\n * ---\\n * Front end makes a one-time selection of kickback rate upon registering\\n * @param _kickbackRate kickback rate selected by frontend\\n */\\n function registerFrontEnd(uint _kickbackRate) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Caller is TroveManager\\n * ---\\n * Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible)\\n * and transfers the Trove's ETH collateral from ActivePool to StabilityPool.\\n * Only called by liquidation functions in the TroveManager.\\n * @param _debt debt to cancel\\n * @param _coll collateral to transfer\\n */\\n function offset(uint _debt, uint _coll) external;\\n\\n /**\\n * @return the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`,\\n * to exclude edge cases like ETH received from a self-destruct.\\n */\\n function getETH() external view returns (uint);\\n\\n /**\\n * @return ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\\n */\\n function getTotalZUSDDeposits() external view returns (uint);\\n\\n /**\\n * @notice Calculates the ETH gain earned by the deposit since its last snapshots were taken.\\n * @param _depositor address to calculate ETH gain\\n * @return ETH gain from given depositor\\n */\\n function getDepositorETHGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice Calculate the SOV gain earned by a deposit since its last snapshots were taken.\\n * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned.\\n * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through\\n * which they made their deposit.\\n * @param _depositor address to calculate ETH gain\\n * @return SOV gain from given depositor\\n */\\n function getDepositorSOVGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @param _frontEnd front end address\\n * @return the SOV gain earned by the front end.\\n */\\n function getFrontEndSOVGain(address _frontEnd) external view returns (uint);\\n\\n /**\\n * @param _depositor depositor address\\n * @return the user's compounded deposit.\\n */\\n function getCompoundedZUSDDeposit(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\\n * @param _frontEnd front end address\\n * @return the front end's compounded stake.\\n */\\n function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint);\\n\\n //DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDLLR(\\n uint _dllrAmount,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function provideToSpFromDllrWithPermit2(\\n uint256 _dllrAmount,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /// Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and optionally convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\\n function withdrawFromSpAndConvertToDLLR(uint256 _zusdAmount) external;\\n\\n /**\\n * Fallback function\\n * Only callable by Active Pool, it just accounts for ETH received\\n * receive() external payable;\\n */\\n}\\n\",\"keccak256\":\"0xb35c5ec991dd2b4f8ecb6b28ae29e97313fca6054aa0df14ebdb7336fcea84a6\",\"license\":\"MIT\"},\"contracts/Interfaces/ITroveManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./ILiquityBase.sol\\\";\\nimport \\\"./IStabilityPool.sol\\\";\\nimport \\\"./IZUSDToken.sol\\\";\\nimport \\\"./IZEROToken.sol\\\";\\nimport \\\"./IZEROStaking.sol\\\";\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface ITroveManager is ILiquityBase {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerRedeemOpsAddressChanged(address _troveManagerRedeemOps);\\n event LiquityBaseParamsAddressChanges(address _borrowerOperationsAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZEROTokenAddressChanged(address _zeroTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event Liquidation(\\n uint256 _liquidatedDebt,\\n uint256 _liquidatedColl,\\n uint256 _collGasCompensation,\\n uint256 _ZUSDGasCompensation\\n );\\n event Redemption(\\n uint256 _attemptedZUSDAmount,\\n uint256 _actualZUSDAmount,\\n uint256 _ETHSent,\\n uint256 _ETHFee\\n );\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event TroveLiquidated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint8 operation\\n );\\n event BaseRateUpdated(uint256 _baseRate);\\n event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);\\n event TotalStakesUpdated(uint256 _newTotalStakes);\\n event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);\\n event LTermsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveIndexUpdated(address _borrower, uint256 _newIndex);\\n\\n struct TroveManagerInitAddressesParams {\\n address _feeDistributorAddress;\\n address _troveManagerRedeemOps;\\n address _liquityBaseParamsAddress;\\n address _borrowerOperationsAddress;\\n address _activePoolAddress;\\n address _defaultPoolAddress;\\n address _stabilityPoolAddress;\\n address _gasPoolAddress;\\n address _collSurplusPoolAddress;\\n address _priceFeedAddress;\\n address _zusdTokenAddress;\\n address _sortedTrovesAddress;\\n address _zeroTokenAddress;\\n address _zeroStakingAddress;\\n }\\n\\n // --- Functions ---\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _troveManagerInitAddresses addresses list to intialize TroveManager with _\\n * _feeDistributorAddress feeDistributor contract address\\n * _troveManagerRedeemOps TroveManagerRedeemOps contract address\\n * _liquityBaseParamsAddress LiquityBaseParams contract address\\n * _borrowerOperationsAddress BorrowerOperations contract address\\n * _activePoolAddress ActivePool contract address\\n * _defaultPoolAddress DefaultPool contract address\\n * _stabilityPoolAddress StabilityPool contract address\\n * _gasPoolAddress GasPool contract address\\n * _collSurplusPoolAddress CollSurplusPool contract address\\n * _priceFeedAddress PriceFeed contract address\\n * _zusdTokenAddress ZUSDToken contract address\\n * _sortedTrovesAddress SortedTroves contract address\\n * _zeroTokenAddress ZEROToken contract address\\n * _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n TroveManagerInitAddressesParams memory _troveManagerInitAddresses\\n ) external;\\n\\n function setTroveManagerRedeemOps(address _troveManagerRedeemOps) external;\\n\\n /// @return Trove owners count\\n function getTroveOwnersCount() external view returns (uint256);\\n\\n /// @param _index Trove owner index\\n /// @return Trove from TroveOwners array in given index\\n function getTroveFromTroveOwnersArray(uint256 _index) external view returns (address);\\n\\n /// @param _borrower borrower address\\n /// @return the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getNominalICR(address _borrower) external view returns (uint256);\\n\\n /// @notice computes the user\\u2019s individual collateralization ratio (ICR) based on their total collateral and total ZUSD debt. Returns 2^256 -1 if they have 0 debt.\\n /// @param _borrower borrower address\\n /// @param _price ETH price\\n /// @return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getCurrentICR(address _borrower, uint256 _price) external view returns (uint256);\\n\\n /// @notice Closes the trove if its ICR is lower than the minimum collateral ratio.\\n /// @param _borrower borrower address\\n function liquidate(address _borrower) external;\\n\\n /**\\n * @notice Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves,\\n * starting from the one with the lowest collateral ratio in the system, and moving upwards\\n * @param _n max number of under-collateralized Troves to liquidate\\n */\\n function liquidateTroves(uint256 _n) external;\\n\\n /**\\n * @notice Attempt to liquidate a custom list of troves provided by the caller.\\n * @param _troveArray list of trove addresses\\n */\\n function batchLiquidateTroves(address[] calldata _troveArray) external;\\n\\n /**\\n * @notice Send _ZUSDamount ZUSD to the system and redeem the corresponding amount of collateral from as many Troves as are needed to fill the redemption\\n * request. Applies pending rewards to a Trove before reducing its debt and coll.\\n *\\n * Note that if _amount is very large, this function can run out of gas, specially if traversed troves are small. This can be easily avoided by\\n * splitting the total _amount in appropriate chunks and calling the function multiple times.\\n *\\n * Param `_maxIterations` can also be provided, so the loop through Troves is capped (if it\\u2019s zero, it will be ignored).This makes it easier to\\n * avoid OOG for the frontend, as only knowing approximately the average cost of an iteration is enough, without needing to know the \\u201ctopology\\u201d\\n * of the trove list. It also avoids the need to set the cap in stone in the contract, nor doing gas calculations, as both gas price and opcode\\n * costs can vary.\\n *\\n * All Troves that are redeemed from -- with the likely exception of the last one -- will end up with no debt left, therefore they will be closed.\\n * If the last Trove does have some remaining debt, it has a finite ICR, and the reinsertion could be anywhere in the list, therefore it requires a hint.\\n * A frontend should use getRedemptionHints() to calculate what the ICR of this Trove will be after redemption, and pass a hint for its position\\n * in the sortedTroves list along with the ICR value that the hint was found for.\\n *\\n * If another transaction modifies the list between calling getRedemptionHints() and passing the hints to redeemCollateral(), it\\n * is very likely that the last (partially) redeemed Trove would end up with a different ICR than what the hint is for. In this case the\\n * redemption will stop after the last completely redeemed Trove and the sender will keep the remaining ZUSD amount, which they can attempt\\n * to redeem later.\\n *\\n * @param _ZUSDAmount ZUSD amount to send to the system\\n * @param _firstRedemptionHint calculated ICR hint of first trove after redemption\\n * @param _maxIterations max Troves iterations (can be 0)\\n * @param _maxFee max fee percentage to accept\\n */\\n function redeemCollateral(\\n uint256 _ZUSDAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFee\\n ) external;\\n\\n function redeemCollateralViaDLLR(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function redeemCollateralViaDllrWithPermit2(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n \\n\\n /// @notice Update borrower's stake based on their latest collateral value\\n /// @param _borrower borrower address\\n function updateStakeAndTotalStakes(address _borrower) external returns (uint256);\\n\\n /// @notice Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values\\n /// @param _borrower borrower address\\n function updateTroveRewardSnapshots(address _borrower) external;\\n\\n /// @notice Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct\\n /// @param _borrower borrower address\\n /// @return index where Trove was inserted\\n function addTroveOwnerToArray(address _borrower) external returns (uint256 index);\\n\\n /// @notice Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\\n /// @param _borrower borrower address\\n function applyPendingRewards(address _borrower) external;\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ETH reward, earned by their stake\\n function getPendingETHReward(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ZUSD reward, earned by their stake\\n function getPendingZUSDDebtReward(address _borrower) external view returns (uint256);\\n\\n /*\\n * @notice A Trove has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:\\n * this indicates that rewards have occured since the snapshot was made, and the user therefore has\\n * pending rewards\\n *\\n * @param _borrower borrower address\\n * @return true if has pending rewards\\n */\\n function hasPendingRewards(address _borrower) external view returns (bool);\\n\\n /// @notice returns the Troves entire debt and coll, including pending rewards from redistributions.\\n /// @param _borrower borrower address\\n function getEntireDebtAndColl(\\n address _borrower\\n )\\n external\\n view\\n returns (\\n uint256 debt,\\n uint256 coll,\\n uint256 pendingZUSDDebtReward,\\n uint256 pendingETHReward\\n );\\n\\n /// @notice Close given trove. Called by BorrowerOperations.\\n /// @param _borrower borrower address\\n function closeTrove(address _borrower) external;\\n\\n /// @notice Remove borrower's stake from the totalStakes sum, and set their stake to 0\\n /// @param _borrower borrower address\\n function removeStake(address _borrower) external;\\n\\n /// @return calculated redemption rate using baseRate\\n function getRedemptionRate() external view returns (uint256);\\n\\n /// @return calculated redemption rate using calculated decayed as base rate\\n function getRedemptionRateWithDecay() external view returns (uint256);\\n\\n /// @notice The redemption fee is taken as a cut of the total ETH drawn from the system in a redemption. It is based on the current redemption rate.\\n /// @param _ETHDrawn ETH drawn\\n function getRedemptionFeeWithDecay(uint256 _ETHDrawn) external view returns (uint256);\\n\\n /// @return borrowing rate\\n function getBorrowingRate() external view returns (uint256);\\n\\n /// @return borrowing rate calculated using decayed as base rate\\n function getBorrowingRateWithDecay() external view returns (uint256);\\n\\n /// @param ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate\\n function getBorrowingFee(uint256 ZUSDDebt) external view returns (uint256);\\n\\n /// @param _ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate with decay\\n function getBorrowingFeeWithDecay(uint256 _ZUSDDebt) external view returns (uint256);\\n\\n /// @notice Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation.\\n function decayBaseRateFromBorrowing() external;\\n\\n /// @param _borrower borrower address\\n /// @return Trove status from given trove\\n function getTroveStatus(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove stake from given trove\\n function getTroveStake(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove debt from given trove\\n function getTroveDebt(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove collateral from given trove\\n function getTroveColl(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param num status to set\\n function setTroveStatus(address _borrower, uint256 num) external;\\n\\n /// @param _borrower borrower address\\n /// @param _collIncrease amount of collateral to increase\\n /// @return new trove collateral\\n function increaseTroveColl(\\n address _borrower,\\n uint256 _collIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _collDecrease amount of collateral to decrease\\n /// @return new trove collateral\\n function decreaseTroveColl(\\n address _borrower,\\n uint256 _collDecrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtIncrease amount of debt to increase\\n /// @return new trove debt\\n function increaseTroveDebt(\\n address _borrower,\\n uint256 _debtIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtDecrease amount of debt to decrease\\n /// @return new trove debt\\n function decreaseTroveDebt(\\n address _borrower,\\n uint256 _debtDecrease\\n ) external returns (uint256);\\n\\n /**\\n * @param _price ETH price\\n * @return the total collateralization ratio (TCR) of the system.\\n * The TCR is based on the the entire system debt and collateral (including pending rewards).\\n */\\n function getTCR(uint256 _price) external view returns (uint256);\\n\\n function MCR() external view returns (uint256);\\n\\n function CCR() external view returns (uint256);\\n\\n /// @notice reveals whether or not the system is in Recovery Mode (i.e. whether the Total Collateralization Ratio (TCR) is below the Critical Collateralization Ratio (CCR)).\\n function checkRecoveryMode(uint256 _price) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x396367eb7763c289e419a025532150e2a1d9d99eead359ceb6a081787501a00b\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROStaking.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IZEROStaking {\\n // --- Events --\\n\\n event ZEROTokenAddressSet(address _zeroTokenAddress);\\n event ZUSDTokenAddressSet(address _zusdTokenAddress);\\n event FeeDistributorAddressAddressSet(address _feeDistributorAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event StakeChanged(address indexed staker, uint256 newStake);\\n event StakingGainsWithdrawn(address indexed staker, uint256 ZUSDGain, uint256 ETHGain);\\n event F_ETHUpdated(uint256 _F_ETH);\\n event F_ZUSDUpdated(uint256 _F_ZUSD);\\n event TotalZEROStakedUpdated(uint256 _totalZEROStaked);\\n event EtherSent(address _account, uint256 _amount);\\n event StakerSnapshotsUpdated(address _staker, uint256 _F_ETH, uint256 _F_ZUSD);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _zeroTokenAddress ZEROToken contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _feeDistributorAddress FeeDistributorAddress contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _zeroTokenAddress,\\n address _zusdTokenAddress,\\n address _feeDistributorAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice If caller has a pre-existing stake, send any accumulated ETH and ZUSD gains to them.\\n /// @param _ZEROamount ZERO tokens to stake\\n function stake(uint256 _ZEROamount) external;\\n\\n /**\\n * @notice Unstake the ZERO and send the it back to the caller, along with their accumulated ZUSD & ETH gains.\\n * If requested amount > stake, send their entire stake.\\n * @param _ZEROamount ZERO tokens to unstake\\n */\\n function unstake(uint256 _ZEROamount) external;\\n\\n /// @param _ETHFee ETH fee\\n /// @notice increase ETH fee\\n function increaseF_ETH(uint256 _ETHFee) external;\\n\\n /// @param _ZEROFee ZUSD fee\\n /// @notice increase ZUSD fee\\n function increaseF_ZUSD(uint256 _ZEROFee) external;\\n\\n /// @param _user user address\\n /// @return pending ETH gain of given user\\n function getPendingETHGain(address _user) external view returns (uint256);\\n\\n /// @param _user user address\\n /// @return pending ZUSD gain of given user\\n function getPendingZUSDGain(address _user) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x4c7948ce7dff9ea9b8495054e511eabcf44a91c7db8520ec58ff2a002327e0c5\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZEROToken is IERC20, IERC2612 { \\n\\n // --- Functions ---\\n\\n /// @notice send zero tokens to ZEROStaking contract\\n /// @param _sender sender address\\n /// @param _amount amount to send\\n function sendToZEROStaking(address _sender, uint256 _amount) external;\\n\\n /// @return deployment start time\\n function getDeploymentStartTime() external view returns (uint256);\\n\\n}\\n\",\"keccak256\":\"0xbcc0baabe4c4686563a09cf1486f2d152b70404996676a89d525691f69637f66\",\"license\":\"MIT\"},\"contracts/Interfaces/IZUSDToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZUSDToken is IERC20, IERC2612 { \\n \\n // --- Events ---\\n\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n\\n event ZUSDTokenBalanceUpdated(address _user, uint _amount);\\n\\n // --- Functions ---\\n\\n function mint(address _account, uint256 _amount) external;\\n\\n function burn(address _account, uint256 _amount) external;\\n\\n function sendToPool(address _sender, address poolAddress, uint256 _amount) external;\\n\\n function returnFromPool(address poolAddress, address user, uint256 _amount ) external;\\n}\\n\",\"keccak256\":\"0xe52df063aa08f709640c28888edd27310c820f6d08564855538ae245eb2f5a8c\",\"license\":\"MIT\"},\"contracts/TroveManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./Interfaces/ITroveManager.sol\\\";\\nimport \\\"./Interfaces/IStabilityPool.sol\\\";\\nimport \\\"./Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/IZEROToken.sol\\\";\\nimport \\\"./Interfaces/IZEROStaking.sol\\\";\\nimport \\\"./Interfaces/IFeeDistributor.sol\\\";\\nimport \\\"./Dependencies/LiquityBase.sol\\\";\\nimport \\\"./Dependencies/CheckContract.sol\\\";\\nimport \\\"./Dependencies/console.sol\\\";\\nimport \\\"./Dependencies/TroveManagerBase.sol\\\";\\nimport \\\"./TroveManagerStorage.sol\\\";\\nimport \\\"./Interfaces/IPermit2.sol\\\";\\n\\ncontract TroveManager is TroveManagerBase, CheckContract, ITroveManager {\\n /** CONSTANT / IMMUTABLE VARIABLE ONLY */\\n IPermit2 public immutable permit2;\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerRedeemOpsAddressChanged(address _troveManagerRedeemOps);\\n event LiquityBaseParamsAddressChanges(address _borrowerOperationsAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZEROTokenAddressChanged(address _zeroTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n ///@param _bootstrapPeriod During bootsrap period redemptions are not allowed\\n constructor(uint256 _bootstrapPeriod, address _permit2) public TroveManagerBase(_bootstrapPeriod) {\\n permit2 = IPermit2(_permit2);\\n }\\n\\n // --- Dependency setter ---\\n function setAddresses(\\n TroveManagerInitAddressesParams memory _troveManagerInitAddressesParams\\n ) external override onlyOwner {\\n {\\n checkContract(_troveManagerInitAddressesParams._feeDistributorAddress);\\n checkContract(_troveManagerInitAddressesParams._troveManagerRedeemOps);\\n checkContract(_troveManagerInitAddressesParams._liquityBaseParamsAddress);\\n checkContract(_troveManagerInitAddressesParams._borrowerOperationsAddress);\\n checkContract(_troveManagerInitAddressesParams._activePoolAddress);\\n checkContract(_troveManagerInitAddressesParams._defaultPoolAddress);\\n checkContract(_troveManagerInitAddressesParams._stabilityPoolAddress);\\n checkContract(_troveManagerInitAddressesParams._gasPoolAddress);\\n checkContract(_troveManagerInitAddressesParams._collSurplusPoolAddress);\\n checkContract(_troveManagerInitAddressesParams._priceFeedAddress);\\n checkContract(_troveManagerInitAddressesParams._zusdTokenAddress);\\n checkContract(_troveManagerInitAddressesParams._sortedTrovesAddress);\\n checkContract(_troveManagerInitAddressesParams._zeroTokenAddress);\\n checkContract(_troveManagerInitAddressesParams._zeroStakingAddress);\\n }\\n\\n feeDistributor = IFeeDistributor(_troveManagerInitAddressesParams._feeDistributorAddress);\\n troveManagerRedeemOps = _troveManagerInitAddressesParams._troveManagerRedeemOps;\\n liquityBaseParams = ILiquityBaseParams(\\n _troveManagerInitAddressesParams._liquityBaseParamsAddress\\n );\\n {\\n borrowerOperationsAddress = _troveManagerInitAddressesParams\\n ._borrowerOperationsAddress;\\n activePool = IActivePool(_troveManagerInitAddressesParams._activePoolAddress);\\n defaultPool = IDefaultPool(_troveManagerInitAddressesParams._defaultPoolAddress);\\n _stabilityPool = IStabilityPool(\\n _troveManagerInitAddressesParams._stabilityPoolAddress\\n );\\n gasPoolAddress = _troveManagerInitAddressesParams._gasPoolAddress;\\n collSurplusPool = ICollSurplusPool(\\n _troveManagerInitAddressesParams._collSurplusPoolAddress\\n );\\n priceFeed = IPriceFeed(_troveManagerInitAddressesParams._priceFeedAddress);\\n _zusdToken = IZUSDToken(_troveManagerInitAddressesParams._zusdTokenAddress);\\n sortedTroves = ISortedTroves(_troveManagerInitAddressesParams._sortedTrovesAddress);\\n _zeroToken = IZEROToken(_troveManagerInitAddressesParams._zeroTokenAddress);\\n _zeroStaking = IZEROStaking(_troveManagerInitAddressesParams._zeroStakingAddress);\\n }\\n\\n emit FeeDistributorAddressChanged(_troveManagerInitAddressesParams._feeDistributorAddress);\\n emit TroveManagerRedeemOpsAddressChanged(\\n _troveManagerInitAddressesParams._troveManagerRedeemOps\\n );\\n emit LiquityBaseParamsAddressChanges(\\n _troveManagerInitAddressesParams._borrowerOperationsAddress\\n );\\n emit BorrowerOperationsAddressChanged(\\n _troveManagerInitAddressesParams._borrowerOperationsAddress\\n );\\n emit ActivePoolAddressChanged(_troveManagerInitAddressesParams._activePoolAddress);\\n emit DefaultPoolAddressChanged(_troveManagerInitAddressesParams._defaultPoolAddress);\\n emit StabilityPoolAddressChanged(_troveManagerInitAddressesParams._stabilityPoolAddress);\\n emit GasPoolAddressChanged(_troveManagerInitAddressesParams._gasPoolAddress);\\n emit CollSurplusPoolAddressChanged(\\n _troveManagerInitAddressesParams._collSurplusPoolAddress\\n );\\n emit PriceFeedAddressChanged(_troveManagerInitAddressesParams._priceFeedAddress);\\n emit ZUSDTokenAddressChanged(_troveManagerInitAddressesParams._zusdTokenAddress);\\n emit SortedTrovesAddressChanged(_troveManagerInitAddressesParams._sortedTrovesAddress);\\n emit ZEROTokenAddressChanged(_troveManagerInitAddressesParams._zeroTokenAddress);\\n emit ZEROStakingAddressChanged(_troveManagerInitAddressesParams._zeroStakingAddress);\\n }\\n\\n function setTroveManagerRedeemOps(address _troveManagerRedeemOps) external override onlyOwner {\\n checkContract(_troveManagerRedeemOps);\\n troveManagerRedeemOps = _troveManagerRedeemOps;\\n emit TroveManagerRedeemOpsAddressChanged(_troveManagerRedeemOps);\\n }\\n\\n // --- Getters ---\\n\\n function getTroveOwnersCount() external view override returns (uint256) {\\n return TroveOwners.length;\\n }\\n\\n function getTroveFromTroveOwnersArray(\\n uint256 _index\\n ) external view override returns (address) {\\n return TroveOwners[_index];\\n }\\n\\n // --- Trove Liquidation functions ---\\n\\n /// Single liquidation function. Closes the trove if its ICR is lower than the minimum collateral ratio.\\n function liquidate(address _borrower) external override {\\n _requireTroveIsActive(_borrower);\\n\\n address[] memory borrowers = new address[](1);\\n borrowers[0] = _borrower;\\n batchLiquidateTroves(borrowers);\\n }\\n\\n // --- Inner single liquidation functions ---\\n\\n /// Liquidate one trove, in Normal Mode.\\n function _liquidateNormalMode(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n address _borrower,\\n uint256 _ZUSDInStabPool\\n ) internal returns (LiquidationValues memory singleLiquidation) {\\n LocalVariables_InnerSingleLiquidateFunction memory vars;\\n\\n (\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n ) = getEntireDebtAndColl(_borrower);\\n\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n );\\n _removeStake(_borrower);\\n\\n singleLiquidation.collGasCompensation = _getCollGasCompensation(\\n singleLiquidation.entireTroveColl\\n );\\n singleLiquidation.ZUSDGasCompensation = ZUSD_GAS_COMPENSATION;\\n uint256 collToLiquidate = singleLiquidation.entireTroveColl.sub(\\n singleLiquidation.collGasCompensation\\n );\\n\\n (\\n singleLiquidation.debtToOffset,\\n singleLiquidation.collToSendToSP,\\n singleLiquidation.debtToRedistribute,\\n singleLiquidation.collToRedistribute\\n ) = _getOffsetAndRedistributionVals(\\n singleLiquidation.entireTroveDebt,\\n collToLiquidate,\\n _ZUSDInStabPool\\n );\\n\\n _closeTrove(_borrower, Status.closedByLiquidation);\\n emit TroveLiquidated(\\n _borrower,\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n TroveManagerOperation.liquidateInNormalMode\\n );\\n emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInNormalMode);\\n return singleLiquidation;\\n }\\n\\n /// Liquidate one trove, in Recovery Mode.\\n function _liquidateRecoveryMode(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n address _borrower,\\n uint256 _ICR,\\n uint256 _ZUSDInStabPool,\\n uint256 _TCR,\\n uint256 _price\\n ) internal returns (LiquidationValues memory singleLiquidation) {\\n LocalVariables_InnerSingleLiquidateFunction memory vars;\\n if (TroveOwners.length <= 1) {\\n return singleLiquidation;\\n } // don't liquidate if last trove\\n (\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n ) = getEntireDebtAndColl(_borrower);\\n\\n singleLiquidation.collGasCompensation = _getCollGasCompensation(\\n singleLiquidation.entireTroveColl\\n );\\n singleLiquidation.ZUSDGasCompensation = ZUSD_GAS_COMPENSATION;\\n vars.collToLiquidate = singleLiquidation.entireTroveColl.sub(\\n singleLiquidation.collGasCompensation\\n );\\n\\n // If ICR <= 100%, purely redistribute the Trove across all active Troves\\n if (_ICR <= _100pct) {\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n );\\n _removeStake(_borrower);\\n\\n singleLiquidation.debtToOffset = 0;\\n singleLiquidation.collToSendToSP = 0;\\n singleLiquidation.debtToRedistribute = singleLiquidation.entireTroveDebt;\\n singleLiquidation.collToRedistribute = vars.collToLiquidate;\\n\\n _closeTrove(_borrower, Status.closedByLiquidation);\\n emit TroveLiquidated(\\n _borrower,\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n TroveManagerOperation.liquidateInRecoveryMode\\n );\\n emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode);\\n\\n // If 100% < ICR < MCR, offset as much as possible, and redistribute the remainder\\n } else if ((_ICR > _100pct) && (_ICR < liquityBaseParams.MCR())) {\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n );\\n _removeStake(_borrower);\\n\\n (\\n singleLiquidation.debtToOffset,\\n singleLiquidation.collToSendToSP,\\n singleLiquidation.debtToRedistribute,\\n singleLiquidation.collToRedistribute\\n ) = _getOffsetAndRedistributionVals(\\n singleLiquidation.entireTroveDebt,\\n vars.collToLiquidate,\\n _ZUSDInStabPool\\n );\\n\\n _closeTrove(_borrower, Status.closedByLiquidation);\\n emit TroveLiquidated(\\n _borrower,\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n TroveManagerOperation.liquidateInRecoveryMode\\n );\\n emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode);\\n /*\\n * If 110% <= ICR < current TCR (accounting for the preceding liquidations in the current sequence)\\n * and there is ZUSD in the Stability Pool, only offset, with no redistribution,\\n * but at a capped rate of 1.1 and only if the whole debt can be liquidated.\\n * The remainder due to the capped rate will be claimable as collateral surplus.\\n */\\n } else if (\\n (_ICR >= liquityBaseParams.MCR()) &&\\n (_ICR < _TCR) &&\\n (singleLiquidation.entireTroveDebt <= _ZUSDInStabPool)\\n ) {\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n );\\n assert(_ZUSDInStabPool != 0);\\n\\n _removeStake(_borrower);\\n singleLiquidation = _getCappedOffsetVals(\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n _price\\n );\\n\\n _closeTrove(_borrower, Status.closedByLiquidation);\\n if (singleLiquidation.collSurplus > 0) {\\n collSurplusPool.accountSurplus(_borrower, singleLiquidation.collSurplus);\\n }\\n\\n emit TroveLiquidated(\\n _borrower,\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.collToSendToSP,\\n TroveManagerOperation.liquidateInRecoveryMode\\n );\\n emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode);\\n } else {\\n // if (_ICR >= liquityBaseParams.MCR() && ( _ICR >= _TCR || singleLiquidation.entireTroveDebt > _ZUSDInStabPool))\\n LiquidationValues memory zeroVals;\\n return zeroVals;\\n }\\n\\n return singleLiquidation;\\n }\\n\\n /** In a full liquidation, returns the values for a trove's coll and debt to be offset, and coll and debt to be\\n * redistributed to active troves.\\n */\\n function _getOffsetAndRedistributionVals(\\n uint256 _debt,\\n uint256 _coll,\\n uint256 _ZUSDInStabPool\\n )\\n internal\\n pure\\n returns (\\n uint256 debtToOffset,\\n uint256 collToSendToSP,\\n uint256 debtToRedistribute,\\n uint256 collToRedistribute\\n )\\n {\\n if (_ZUSDInStabPool > 0) {\\n /*\\n * Offset as much debt & collateral as possible against the Stability Pool, and redistribute the remainder\\n * between all active troves.\\n *\\n * If the trove's debt is larger than the deposited ZUSD in the Stability Pool:\\n *\\n * - Offset an amount of the trove's debt equal to the ZUSD in the Stability Pool\\n * - Send a fraction of the trove's collateral to the Stability Pool, equal to the fraction of its offset debt\\n *\\n */\\n debtToOffset = LiquityMath._min(_debt, _ZUSDInStabPool);\\n collToSendToSP = _coll.mul(debtToOffset).div(_debt);\\n debtToRedistribute = _debt.sub(debtToOffset);\\n collToRedistribute = _coll.sub(collToSendToSP);\\n } else {\\n debtToOffset = 0;\\n collToSendToSP = 0;\\n debtToRedistribute = _debt;\\n collToRedistribute = _coll;\\n }\\n }\\n\\n /**\\n * Get its offset coll/debt and ETH gas comp, and close the trove.\\n */\\n function _getCappedOffsetVals(\\n uint256 _entireTroveDebt,\\n uint256 _entireTroveColl,\\n uint256 _price\\n ) internal view returns (LiquidationValues memory singleLiquidation) {\\n singleLiquidation.entireTroveDebt = _entireTroveDebt;\\n singleLiquidation.entireTroveColl = _entireTroveColl;\\n uint256 collToOffset = _entireTroveDebt.mul(liquityBaseParams.MCR()).div(_price);\\n\\n singleLiquidation.collGasCompensation = _getCollGasCompensation(collToOffset);\\n singleLiquidation.ZUSDGasCompensation = ZUSD_GAS_COMPENSATION;\\n\\n singleLiquidation.debtToOffset = _entireTroveDebt;\\n singleLiquidation.collToSendToSP = collToOffset.sub(singleLiquidation.collGasCompensation);\\n singleLiquidation.collSurplus = _entireTroveColl.sub(collToOffset);\\n singleLiquidation.debtToRedistribute = 0;\\n singleLiquidation.collToRedistribute = 0;\\n }\\n\\n /**\\n * Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves,\\n * starting from the one with the lowest collateral ratio in the system, and moving upwards\\n */\\n function liquidateTroves(uint256 _n) external override {\\n ContractsCache memory contractsCache = ContractsCache(\\n activePool,\\n defaultPool,\\n IZUSDToken(address(0)),\\n IZEROStaking(address(0)),\\n sortedTroves,\\n ICollSurplusPool(address(0)),\\n address(0)\\n );\\n IStabilityPool stabilityPoolCached = _stabilityPool;\\n\\n LocalVariables_OuterLiquidationFunction memory vars;\\n\\n LiquidationTotals memory totals;\\n\\n vars.price = priceFeed.fetchPrice();\\n vars.ZUSDInStabPool = stabilityPoolCached.getTotalZUSDDeposits();\\n vars.recoveryModeAtStart = _checkRecoveryMode(vars.price);\\n\\n // Perform the appropriate liquidation sequence - tally the values, and obtain their totals\\n if (vars.recoveryModeAtStart) {\\n totals = _getTotalsFromLiquidateTrovesSequence_RecoveryMode(\\n contractsCache,\\n vars.price,\\n vars.ZUSDInStabPool,\\n _n\\n );\\n } else {\\n // if !vars.recoveryModeAtStart\\n totals = _getTotalsFromLiquidateTrovesSequence_NormalMode(\\n contractsCache.activePool,\\n contractsCache.defaultPool,\\n vars.price,\\n vars.ZUSDInStabPool,\\n _n\\n );\\n }\\n\\n require(totals.totalDebtInSequence > 0, \\\"TroveManager: nothing to liquidate\\\");\\n\\n // Move liquidated ETH and ZUSD to the appropriate pools\\n stabilityPoolCached.offset(totals.totalDebtToOffset, totals.totalCollToSendToSP);\\n _redistributeDebtAndColl(\\n contractsCache.activePool,\\n contractsCache.defaultPool,\\n totals.totalDebtToRedistribute,\\n totals.totalCollToRedistribute\\n );\\n if (totals.totalCollSurplus > 0) {\\n contractsCache.activePool.sendETH(address(collSurplusPool), totals.totalCollSurplus);\\n }\\n\\n // Update system snapshots\\n _updateSystemSnapshots_excludeCollRemainder(\\n contractsCache.activePool,\\n totals.totalCollGasCompensation\\n );\\n\\n vars.liquidatedDebt = totals.totalDebtInSequence;\\n vars.liquidatedColl = totals.totalCollInSequence.sub(totals.totalCollGasCompensation).sub(\\n totals.totalCollSurplus\\n );\\n emit Liquidation(\\n vars.liquidatedDebt,\\n vars.liquidatedColl,\\n totals.totalCollGasCompensation,\\n totals.totalZUSDGasCompensation\\n );\\n\\n // Send gas compensation to caller\\n _sendGasCompensation(\\n contractsCache.activePool,\\n msg.sender,\\n totals.totalZUSDGasCompensation,\\n totals.totalCollGasCompensation\\n );\\n }\\n\\n /**\\n * This function is used when the liquidateTroves sequence starts during Recovery Mode. However, it\\n * handle the case where the system *leaves* Recovery Mode, part way through the liquidation sequence\\n */\\n function _getTotalsFromLiquidateTrovesSequence_RecoveryMode(\\n ContractsCache memory _contractsCache,\\n uint256 _price,\\n uint256 _ZUSDInStabPool,\\n uint256 _n\\n ) internal returns (LiquidationTotals memory totals) {\\n LocalVariables_LiquidationSequence memory vars;\\n LiquidationValues memory singleLiquidation;\\n\\n vars.remainingZUSDInStabPool = _ZUSDInStabPool;\\n vars.backToNormalMode = false;\\n vars.entireSystemDebt = getEntireSystemDebt();\\n vars.entireSystemColl = getEntireSystemColl();\\n\\n vars.user = _contractsCache.sortedTroves.getLast();\\n address firstUser = _contractsCache.sortedTroves.getFirst();\\n for (vars.i = 0; vars.i < _n && vars.user != firstUser; vars.i++) {\\n // we need to cache it, because current user is likely going to be deleted\\n address nextUser = _contractsCache.sortedTroves.getPrev(vars.user);\\n\\n vars.ICR = _getCurrentICR(vars.user, _price);\\n\\n if (!vars.backToNormalMode) {\\n // Break the loop if ICR is greater than liquityBaseParams.MCR() and Stability Pool is empty\\n if (vars.ICR >= liquityBaseParams.MCR() && vars.remainingZUSDInStabPool == 0) {\\n break;\\n }\\n\\n uint256 TCR = LiquityMath._computeCR(\\n vars.entireSystemColl,\\n vars.entireSystemDebt,\\n _price\\n );\\n\\n singleLiquidation = _liquidateRecoveryMode(\\n _contractsCache.activePool,\\n _contractsCache.defaultPool,\\n vars.user,\\n vars.ICR,\\n vars.remainingZUSDInStabPool,\\n TCR,\\n _price\\n );\\n\\n // Update aggregate trackers\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n vars.entireSystemDebt = vars.entireSystemDebt.sub(singleLiquidation.debtToOffset);\\n vars.entireSystemColl = vars\\n .entireSystemColl\\n .sub(singleLiquidation.collToSendToSP)\\n .sub(singleLiquidation.collSurplus);\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n\\n vars.backToNormalMode = !_checkPotentialRecoveryMode(\\n vars.entireSystemColl,\\n vars.entireSystemDebt,\\n _price\\n );\\n } else if (vars.backToNormalMode && vars.ICR < liquityBaseParams.MCR()) {\\n singleLiquidation = _liquidateNormalMode(\\n _contractsCache.activePool,\\n _contractsCache.defaultPool,\\n vars.user,\\n vars.remainingZUSDInStabPool\\n );\\n\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n } else break; // break if the loop reaches a Trove with ICR >= MCR\\n\\n vars.user = nextUser;\\n }\\n }\\n\\n function _getTotalsFromLiquidateTrovesSequence_NormalMode(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _price,\\n uint256 _ZUSDInStabPool,\\n uint256 _n\\n ) internal returns (LiquidationTotals memory totals) {\\n LocalVariables_LiquidationSequence memory vars;\\n LiquidationValues memory singleLiquidation;\\n ISortedTroves sortedTrovesCached = sortedTroves;\\n\\n vars.remainingZUSDInStabPool = _ZUSDInStabPool;\\n\\n for (vars.i = 0; vars.i < _n; vars.i++) {\\n vars.user = sortedTrovesCached.getLast();\\n vars.ICR = _getCurrentICR(vars.user, _price);\\n\\n if (vars.ICR < liquityBaseParams.MCR()) {\\n singleLiquidation = _liquidateNormalMode(\\n _activePool,\\n _defaultPool,\\n vars.user,\\n vars.remainingZUSDInStabPool\\n );\\n\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n } else break; // break if the loop reaches a Trove with ICR >= MCR\\n }\\n }\\n\\n /**\\n * Attempt to liquidate a custom list of troves provided by the caller.\\n */\\n function batchLiquidateTroves(address[] memory _troveArray) public override {\\n require(_troveArray.length != 0, \\\"TroveManager: Calldata address array must not be empty\\\");\\n\\n IActivePool activePoolCached = activePool;\\n IDefaultPool defaultPoolCached = defaultPool;\\n IStabilityPool stabilityPoolCached = _stabilityPool;\\n\\n LocalVariables_OuterLiquidationFunction memory vars;\\n LiquidationTotals memory totals;\\n\\n vars.price = priceFeed.fetchPrice();\\n vars.ZUSDInStabPool = stabilityPoolCached.getTotalZUSDDeposits();\\n vars.recoveryModeAtStart = _checkRecoveryMode(vars.price);\\n\\n // Perform the appropriate liquidation sequence - tally values and obtain their totals.\\n if (vars.recoveryModeAtStart) {\\n totals = _getTotalFromBatchLiquidate_RecoveryMode(\\n activePoolCached,\\n defaultPoolCached,\\n vars.price,\\n vars.ZUSDInStabPool,\\n _troveArray\\n );\\n } else {\\n // if !vars.recoveryModeAtStart\\n totals = _getTotalsFromBatchLiquidate_NormalMode(\\n activePoolCached,\\n defaultPoolCached,\\n vars.price,\\n vars.ZUSDInStabPool,\\n _troveArray\\n );\\n }\\n\\n require(totals.totalDebtInSequence > 0, \\\"TroveManager: nothing to liquidate\\\");\\n\\n // Move liquidated ETH and ZUSD to the appropriate pools\\n stabilityPoolCached.offset(totals.totalDebtToOffset, totals.totalCollToSendToSP);\\n _redistributeDebtAndColl(\\n activePoolCached,\\n defaultPoolCached,\\n totals.totalDebtToRedistribute,\\n totals.totalCollToRedistribute\\n );\\n if (totals.totalCollSurplus > 0) {\\n activePoolCached.sendETH(address(collSurplusPool), totals.totalCollSurplus);\\n }\\n\\n // Update system snapshots\\n _updateSystemSnapshots_excludeCollRemainder(\\n activePoolCached,\\n totals.totalCollGasCompensation\\n );\\n\\n vars.liquidatedDebt = totals.totalDebtInSequence;\\n vars.liquidatedColl = totals.totalCollInSequence.sub(totals.totalCollGasCompensation).sub(\\n totals.totalCollSurplus\\n );\\n emit Liquidation(\\n vars.liquidatedDebt,\\n vars.liquidatedColl,\\n totals.totalCollGasCompensation,\\n totals.totalZUSDGasCompensation\\n );\\n\\n // Send gas compensation to caller\\n _sendGasCompensation(\\n activePoolCached,\\n msg.sender,\\n totals.totalZUSDGasCompensation,\\n totals.totalCollGasCompensation\\n );\\n }\\n\\n /**\\n * This function is used when the batch liquidation sequence starts during Recovery Mode. However, it\\n * handle the case where the system *leaves* Recovery Mode, part way through the liquidation sequence\\n */\\n function _getTotalFromBatchLiquidate_RecoveryMode(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _price,\\n uint256 _ZUSDInStabPool,\\n address[] memory _troveArray\\n ) internal returns (LiquidationTotals memory totals) {\\n LocalVariables_LiquidationSequence memory vars;\\n LiquidationValues memory singleLiquidation;\\n\\n vars.remainingZUSDInStabPool = _ZUSDInStabPool;\\n vars.backToNormalMode = false;\\n vars.entireSystemDebt = getEntireSystemDebt();\\n vars.entireSystemColl = getEntireSystemColl();\\n\\n for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {\\n vars.user = _troveArray[vars.i];\\n // Skip non-active troves\\n if (Troves[vars.user].status != Status.active) {\\n continue;\\n }\\n vars.ICR = _getCurrentICR(vars.user, _price);\\n\\n if (!vars.backToNormalMode) {\\n // Skip this trove if ICR is greater than liquityBaseParams.MCR() and Stability Pool is empty\\n if (vars.ICR >= liquityBaseParams.MCR() && vars.remainingZUSDInStabPool == 0) {\\n continue;\\n }\\n\\n uint256 TCR = LiquityMath._computeCR(\\n vars.entireSystemColl,\\n vars.entireSystemDebt,\\n _price\\n );\\n\\n singleLiquidation = _liquidateRecoveryMode(\\n _activePool,\\n _defaultPool,\\n vars.user,\\n vars.ICR,\\n vars.remainingZUSDInStabPool,\\n TCR,\\n _price\\n );\\n\\n // Update aggregate trackers\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n vars.entireSystemDebt = vars.entireSystemDebt.sub(singleLiquidation.debtToOffset);\\n vars.entireSystemColl = vars.entireSystemColl.sub(\\n singleLiquidation.collToSendToSP\\n );\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n\\n vars.backToNormalMode = !_checkPotentialRecoveryMode(\\n vars.entireSystemColl,\\n vars.entireSystemDebt,\\n _price\\n );\\n } else if (vars.backToNormalMode && vars.ICR < liquityBaseParams.MCR()) {\\n singleLiquidation = _liquidateNormalMode(\\n _activePool,\\n _defaultPool,\\n vars.user,\\n vars.remainingZUSDInStabPool\\n );\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n } else continue; // In Normal Mode skip troves with ICR >= MCR\\n }\\n }\\n\\n function _getTotalsFromBatchLiquidate_NormalMode(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _price,\\n uint256 _ZUSDInStabPool,\\n address[] memory _troveArray\\n ) internal returns (LiquidationTotals memory totals) {\\n LocalVariables_LiquidationSequence memory vars;\\n LiquidationValues memory singleLiquidation;\\n\\n vars.remainingZUSDInStabPool = _ZUSDInStabPool;\\n\\n for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {\\n vars.user = _troveArray[vars.i];\\n vars.ICR = _getCurrentICR(vars.user, _price);\\n\\n if (vars.ICR < liquityBaseParams.MCR()) {\\n singleLiquidation = _liquidateNormalMode(\\n _activePool,\\n _defaultPool,\\n vars.user,\\n vars.remainingZUSDInStabPool\\n );\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n }\\n }\\n }\\n\\n // --- Liquidation helper functions ---\\n\\n function _addLiquidationValuesToTotals(\\n LiquidationTotals memory oldTotals,\\n LiquidationValues memory singleLiquidation\\n ) internal pure returns (LiquidationTotals memory newTotals) {\\n // Tally all the values with their respective running totals\\n newTotals.totalCollGasCompensation = oldTotals.totalCollGasCompensation.add(\\n singleLiquidation.collGasCompensation\\n );\\n newTotals.totalZUSDGasCompensation = oldTotals.totalZUSDGasCompensation.add(\\n singleLiquidation.ZUSDGasCompensation\\n );\\n newTotals.totalDebtInSequence = oldTotals.totalDebtInSequence.add(\\n singleLiquidation.entireTroveDebt\\n );\\n newTotals.totalCollInSequence = oldTotals.totalCollInSequence.add(\\n singleLiquidation.entireTroveColl\\n );\\n newTotals.totalDebtToOffset = oldTotals.totalDebtToOffset.add(\\n singleLiquidation.debtToOffset\\n );\\n newTotals.totalCollToSendToSP = oldTotals.totalCollToSendToSP.add(\\n singleLiquidation.collToSendToSP\\n );\\n newTotals.totalDebtToRedistribute = oldTotals.totalDebtToRedistribute.add(\\n singleLiquidation.debtToRedistribute\\n );\\n newTotals.totalCollToRedistribute = oldTotals.totalCollToRedistribute.add(\\n singleLiquidation.collToRedistribute\\n );\\n newTotals.totalCollSurplus = oldTotals.totalCollSurplus.add(singleLiquidation.collSurplus);\\n\\n return newTotals;\\n }\\n\\n function _sendGasCompensation(\\n IActivePool _activePool,\\n address _liquidator,\\n uint256 _ZUSD,\\n uint256 _ETH\\n ) internal {\\n if (_ZUSD > 0) {\\n _zusdToken.returnFromPool(gasPoolAddress, _liquidator, _ZUSD);\\n }\\n\\n if (_ETH > 0) {\\n _activePool.sendETH(_liquidator, _ETH);\\n }\\n }\\n\\n // --- Helper functions ---\\n\\n /// @return the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getNominalICR(address _borrower) public view override returns (uint256) {\\n (uint256 currentETH, uint256 currentZUSDDebt) = _getCurrentTroveAmounts(_borrower);\\n\\n uint256 NICR = LiquityMath._computeNominalCR(currentETH, currentZUSDDebt);\\n return NICR;\\n }\\n\\n function applyPendingRewards(address _borrower) external override {\\n _requireCallerIsBorrowerOperations();\\n return _applyPendingRewards(activePool, defaultPool, _borrower);\\n }\\n\\n /// Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values\\n function updateTroveRewardSnapshots(address _borrower) external override {\\n _requireCallerIsBorrowerOperations();\\n return _updateTroveRewardSnapshots(_borrower);\\n }\\n\\n /// Return the Troves entire debt and coll, including pending rewards from redistributions.\\n function getEntireDebtAndColl(\\n address _borrower\\n )\\n public\\n view\\n override\\n returns (\\n uint256 debt,\\n uint256 coll,\\n uint256 pendingZUSDDebtReward,\\n uint256 pendingETHReward\\n )\\n {\\n debt = Troves[_borrower].debt;\\n coll = Troves[_borrower].coll;\\n\\n pendingZUSDDebtReward = getPendingZUSDDebtReward(_borrower);\\n pendingETHReward = getPendingETHReward(_borrower);\\n\\n debt = debt.add(pendingZUSDDebtReward);\\n coll = coll.add(pendingETHReward);\\n }\\n\\n function removeStake(address _borrower) external override {\\n _requireCallerIsBorrowerOperations();\\n return _removeStake(_borrower);\\n }\\n\\n function updateStakeAndTotalStakes(address _borrower) external override returns (uint256) {\\n _requireCallerIsBorrowerOperations();\\n return _updateStakeAndTotalStakes(_borrower);\\n }\\n\\n function _redistributeDebtAndColl(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _debt,\\n uint256 _coll\\n ) internal {\\n if (_debt == 0) {\\n return;\\n }\\n\\n /*\\n * Add distributed coll and debt rewards-per-unit-staked to the running totals. Division uses a \\\"feedback\\\"\\n * error correction, to keep the cumulative error low in the running totals L_ETH and L_ZUSDDebt:\\n *\\n * 1) Form numerators which compensate for the floor division errors that occurred the last time this\\n * function was called.\\n * 2) Calculate \\\"per-unit-staked\\\" ratios.\\n * 3) Multiply each ratio back by its denominator, to reveal the current floor division error.\\n * 4) Store these errors for use in the next correction when this function is called.\\n * 5) Note: static analysis tools complain about this \\\"division before multiplication\\\", however, it is intended.\\n */\\n uint256 ETHNumerator = _coll.mul(DECIMAL_PRECISION).add(lastETHError_Redistribution);\\n uint256 ZUSDDebtNumerator = _debt.mul(DECIMAL_PRECISION).add(\\n lastZUSDDebtError_Redistribution\\n );\\n\\n // Get the per-unit-staked terms\\n uint256 ETHRewardPerUnitStaked = ETHNumerator.div(totalStakes);\\n uint256 ZUSDDebtRewardPerUnitStaked = ZUSDDebtNumerator.div(totalStakes);\\n\\n lastETHError_Redistribution = ETHNumerator.sub(ETHRewardPerUnitStaked.mul(totalStakes));\\n lastZUSDDebtError_Redistribution = ZUSDDebtNumerator.sub(\\n ZUSDDebtRewardPerUnitStaked.mul(totalStakes)\\n );\\n\\n // Add per-unit-staked terms to the running totals\\n L_ETH = L_ETH.add(ETHRewardPerUnitStaked);\\n L_ZUSDDebt = L_ZUSDDebt.add(ZUSDDebtRewardPerUnitStaked);\\n\\n emit LTermsUpdated(L_ETH, L_ZUSDDebt);\\n\\n // Transfer coll and debt from ActivePool to DefaultPool\\n _activePool.decreaseZUSDDebt(_debt);\\n _defaultPool.increaseZUSDDebt(_debt);\\n _activePool.sendETH(address(_defaultPool), _coll);\\n }\\n\\n function closeTrove(address _borrower) external override {\\n _requireCallerIsBorrowerOperations();\\n return _closeTrove(_borrower, Status.closedByOwner);\\n }\\n\\n /**\\n * Updates snapshots of system total stakes and total collateral, excluding a given collateral remainder from the calculation.\\n * Used in a liquidation sequence.\\n *\\n * The calculation excludes a portion of collateral that is in the ActivePool:\\n *\\n * the total ETH gas compensation from the liquidation sequence\\n *\\n * The ETH as compensation must be excluded as it is always sent out at the very end of the liquidation sequence.\\n */\\n function _updateSystemSnapshots_excludeCollRemainder(\\n IActivePool _activePool,\\n uint256 _collRemainder\\n ) internal {\\n totalStakesSnapshot = totalStakes;\\n\\n uint256 activeColl = _activePool.getETH();\\n uint256 liquidatedColl = defaultPool.getETH();\\n totalCollateralSnapshot = activeColl.sub(_collRemainder).add(liquidatedColl);\\n\\n emit SystemSnapshotsUpdated(totalStakesSnapshot, totalCollateralSnapshot);\\n }\\n\\n /// Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct\\n function addTroveOwnerToArray(address _borrower) external override returns (uint256 index) {\\n _requireCallerIsBorrowerOperations();\\n return _addTroveOwnerToArray(_borrower);\\n }\\n\\n function _addTroveOwnerToArray(address _borrower) internal returns (uint128 index) {\\n /* Max array size is 2**128 - 1, i.e. ~3e30 troves. No risk of overflow, since troves have minimum ZUSD\\n debt of liquidation reserve plus MIN_NET_DEBT. 3e30 ZUSD dwarfs the value of all wealth in the world ( which is < 1e15 USD). */\\n\\n // Push the Troveowner to the array\\n TroveOwners.push(_borrower);\\n\\n // Record the index of the new Troveowner on their Trove struct\\n index = uint128(TroveOwners.length.sub(1));\\n Troves[_borrower].arrayIndex = index;\\n\\n return index;\\n }\\n\\n // --- Recovery Mode and TCR functions ---\\n\\n function getTCR(uint256 _price) external view override returns (uint256) {\\n return _getTCR(_price);\\n }\\n\\n function MCR() external view override returns (uint256) {\\n return liquityBaseParams.MCR();\\n }\\n\\n function CCR() external view override returns (uint256) {\\n return liquityBaseParams.CCR();\\n }\\n\\n function checkRecoveryMode(uint256 _price) external view override returns (bool) {\\n return _checkRecoveryMode(_price);\\n }\\n\\n // Check whether or not the system *would be* in Recovery Mode, given an ETH:USD price, and the entire system coll and debt.\\n function _checkPotentialRecoveryMode(\\n uint256 _entireSystemColl,\\n uint256 _entireSystemDebt,\\n uint256 _price\\n ) internal view returns (bool) {\\n uint256 TCR = LiquityMath._computeCR(_entireSystemColl, _entireSystemDebt, _price);\\n\\n return TCR < liquityBaseParams.CCR();\\n }\\n\\n function getRedemptionRateWithDecay() public view override returns (uint256) {\\n return _calcRedemptionRate(_calcDecayedBaseRate());\\n }\\n\\n function getRedemptionFeeWithDecay(\\n uint256 _ETHDrawn\\n ) external view override returns (uint256) {\\n return _calcRedemptionFee(getRedemptionRateWithDecay(), _ETHDrawn);\\n }\\n\\n // --- Borrowing fee functions ---\\n\\n function getBorrowingRate() public view override returns (uint256) {\\n return _calcBorrowingRate(baseRate);\\n }\\n\\n function getBorrowingRateWithDecay() public view override returns (uint256) {\\n return _calcBorrowingRate(_calcDecayedBaseRate());\\n }\\n\\n function _calcBorrowingRate(uint256 _baseRate) internal view returns (uint256) {\\n return\\n LiquityMath._min(\\n liquityBaseParams.BORROWING_FEE_FLOOR().add(_baseRate),\\n liquityBaseParams.MAX_BORROWING_FEE()\\n );\\n }\\n\\n function getBorrowingFee(uint256 _ZUSDDebt) external view override returns (uint256) {\\n return _calcBorrowingFee(getBorrowingRate(), _ZUSDDebt);\\n }\\n\\n function getBorrowingFeeWithDecay(uint256 _ZUSDDebt) external view override returns (uint256) {\\n return _calcBorrowingFee(getBorrowingRateWithDecay(), _ZUSDDebt);\\n }\\n\\n function _calcBorrowingFee(\\n uint256 _borrowingRate,\\n uint256 _ZUSDDebt\\n ) internal pure returns (uint256) {\\n return _borrowingRate.mul(_ZUSDDebt).div(DECIMAL_PRECISION);\\n }\\n\\n /// Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation.\\n function decayBaseRateFromBorrowing() external override {\\n _requireCallerIsBorrowerOperations();\\n\\n uint256 decayedBaseRate = _calcDecayedBaseRate();\\n assert(decayedBaseRate <= DECIMAL_PRECISION); // The baseRate can decay to 0\\n\\n baseRate = decayedBaseRate;\\n emit BaseRateUpdated(decayedBaseRate);\\n\\n _updateLastFeeOpTime();\\n }\\n\\n // --- Internal fee functions ---\\n\\n // --- Trove property getters ---\\n\\n function getTroveStatus(address _borrower) external view override returns (uint256) {\\n return uint256(Troves[_borrower].status);\\n }\\n\\n function getTroveStake(address _borrower) external view override returns (uint256) {\\n return Troves[_borrower].stake;\\n }\\n\\n function getTroveDebt(address _borrower) external view override returns (uint256) {\\n return Troves[_borrower].debt;\\n }\\n\\n function getTroveColl(address _borrower) external view override returns (uint256) {\\n return Troves[_borrower].coll;\\n }\\n\\n // --- Trove property setters, called by BorrowerOperations ---\\n\\n function setTroveStatus(address _borrower, uint256 _num) external override {\\n _requireCallerIsBorrowerOperations();\\n Troves[_borrower].status = Status(_num);\\n }\\n\\n function increaseTroveColl(\\n address _borrower,\\n uint256 _collIncrease\\n ) external override returns (uint256) {\\n _requireCallerIsBorrowerOperations();\\n uint256 newColl = Troves[_borrower].coll.add(_collIncrease);\\n Troves[_borrower].coll = newColl;\\n return newColl;\\n }\\n\\n function decreaseTroveColl(\\n address _borrower,\\n uint256 _collDecrease\\n ) external override returns (uint256) {\\n _requireCallerIsBorrowerOperations();\\n uint256 newColl = Troves[_borrower].coll.sub(_collDecrease);\\n Troves[_borrower].coll = newColl;\\n return newColl;\\n }\\n\\n function increaseTroveDebt(\\n address _borrower,\\n uint256 _debtIncrease\\n ) external override returns (uint256) {\\n _requireCallerIsBorrowerOperations();\\n uint256 newDebt = Troves[_borrower].debt.add(_debtIncrease);\\n Troves[_borrower].debt = newDebt;\\n return newDebt;\\n }\\n\\n function decreaseTroveDebt(\\n address _borrower,\\n uint256 _debtDecrease\\n ) external override returns (uint256) {\\n _requireCallerIsBorrowerOperations();\\n uint256 newDebt = Troves[_borrower].debt.sub(_debtDecrease);\\n Troves[_borrower].debt = newDebt;\\n return newDebt;\\n }\\n\\n function getCurrentICR(\\n address _borrower,\\n uint256 _price\\n ) external view override returns (uint256) {\\n return _getCurrentICR(_borrower, _price);\\n }\\n\\n function getPendingETHReward(address _borrower) public view override returns (uint256) {\\n return _getPendingETHReward(_borrower);\\n }\\n\\n function getPendingZUSDDebtReward(address _borrower) public view override returns (uint256) {\\n return _getPendingZUSDDebtReward(_borrower);\\n }\\n\\n function hasPendingRewards(address _borrower) public view override returns (bool) {\\n return _hasPendingRewards(_borrower);\\n }\\n\\n function getRedemptionRate() public view override returns (uint256) {\\n return _getRedemptionRate();\\n }\\n\\n /// @dev this function forwards the call to the troveManagerRedeemOps in a delegate call fashion\\n /// so the parameters are not needed\\n function redeemCollateral(\\n uint256 _ZUSDamount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage\\n ) external override {\\n (bool success, bytes memory returndata) = troveManagerRedeemOps.delegatecall(msg.data);\\n require(success, string(returndata));\\n }\\n\\n /// @dev this function forwards the call to the troveManagerRedeemOps in a delegate call fashion\\n /// so the parameters are not needed\\n ///DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\\n function redeemCollateralViaDLLR(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external override {\\n (bool success, bytes memory returndata) = troveManagerRedeemOps.delegatecall(msg.data);\\n require(success, string(returndata));\\n }\\n\\n /// @dev this function forwards the call to the troveManagerRedeemOps in a delegate call fashion\\n /// so the parameters are not needed\\n ///DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\\n function redeemCollateralViaDllrWithPermit2(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external override {\\n (bool success, bytes memory returndata) = troveManagerRedeemOps.delegatecall(msg.data);\\n require(success, string(returndata));\\n }\\n}\\n\",\"keccak256\":\"0xbe8cf91ac61c6634335c692e9d285827666fbee79db0032cd1bd0bc49762cfc0\",\"license\":\"MIT\"},\"contracts/TroveManagerStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./Interfaces/IStabilityPool.sol\\\";\\nimport \\\"./Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/IZEROToken.sol\\\";\\nimport \\\"./Interfaces/IZEROStaking.sol\\\";\\nimport \\\"./Interfaces/IFeeDistributor.sol\\\";\\nimport \\\"./Dependencies/Ownable.sol\\\";\\nimport \\\"./Dependencies/BaseMath.sol\\\";\\nimport \\\"./Dependencies/console.sol\\\";\\n\\ncontract TroveManagerStorage is Ownable, BaseMath {\\n string public constant NAME = \\\"TroveManager\\\";\\n\\n // --- Connected contract declarations ---\\n\\n address public troveManagerRedeemOps;\\n\\n address public borrowerOperationsAddress;\\n\\n IStabilityPool public _stabilityPool;\\n\\n address gasPoolAddress;\\n\\n ICollSurplusPool collSurplusPool;\\n\\n IZUSDToken public _zusdToken;\\n\\n IZEROToken public _zeroToken;\\n\\n IZEROStaking public _zeroStaking;\\n\\n IFeeDistributor public feeDistributor;\\n\\n // A doubly linked list of Troves, sorted by their sorted by their collateral ratios\\n ISortedTroves public sortedTroves;\\n\\n // --- Data structures ---\\n\\n uint256 public baseRate;\\n\\n // The timestamp of the latest fee operation (redemption or new ZUSD issuance)\\n uint256 public lastFeeOperationTime;\\n\\n enum Status {\\n nonExistent,\\n active,\\n closedByOwner,\\n closedByLiquidation,\\n closedByRedemption\\n }\\n\\n // Store the necessary data for a trove\\n struct Trove {\\n uint256 debt;\\n uint256 coll;\\n uint256 stake;\\n Status status;\\n uint128 arrayIndex;\\n }\\n\\n mapping(address => Trove) public Troves;\\n\\n uint256 public totalStakes;\\n\\n // Snapshot of the value of totalStakes, taken immediately after the latest liquidation\\n uint256 public totalStakesSnapshot;\\n\\n // Snapshot of the total collateral across the ActivePool and DefaultPool, immediately after the latest liquidation.\\n uint256 public totalCollateralSnapshot;\\n\\n /*\\n * L_ETH and L_ZUSDDebt track the sums of accumulated liquidation rewards per unit staked. During its lifetime, each stake earns:\\n *\\n * An ETH gain of ( stake * [L_ETH - L_ETH(0)] )\\n * A ZUSDDebt increase of ( stake * [L_ZUSDDebt - L_ZUSDDebt(0)] )\\n *\\n * Where L_ETH(0) and L_ZUSDDebt(0) are snapshots of L_ETH and L_ZUSDDebt for the active Trove taken at the instant the stake was made\\n */\\n uint256 public L_ETH;\\n uint256 public L_ZUSDDebt;\\n\\n // Map addresses with active troves to their RewardSnapshot\\n mapping(address => RewardSnapshot) public rewardSnapshots;\\n\\n // Object containing the ETH and ZUSD snapshots for a given active trove\\n struct RewardSnapshot {\\n uint256 ETH;\\n uint256 ZUSDDebt;\\n }\\n\\n // Array of all active trove addresses - used to to compute an approximate hint off-chain, for the sorted list insertion\\n address[] public TroveOwners;\\n\\n // Error trackers for the trove redistribution calculation\\n uint256 public lastETHError_Redistribution;\\n uint256 public lastZUSDDebtError_Redistribution;\\n}\\n\",\"keccak256\":\"0x979836e7db9988074cd7cbbaaa94d67a297a078a8f93ceb14430ffe548545145\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60c06040523480156200001157600080fd5b50604051620058f2380380620058f2833981016040819052620000349162000128565b8162000049336001600160e01b036200006316565b60805260601b6001600160601b03191660a05250620001c4565b6001600160a01b038116620000955760405162461bcd60e51b81526004016200008c9062000182565b60405180910390fd5b6001600160a01b038116620000b26001600160e01b036200010716565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f79062000165565b6040519081900390209190915550565b600080604051620001189062000165565b6040519081900390205492915050565b600080604083850312156200013b578182fd5b825160208401519092506001600160a01b03811681146200015a578182fd5b809150509250929050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160a05160601c615707620001eb60003980610ff152508061223252506157076000f3fe608060405234801561001057600080fd5b50600436106104c25760003560e01c8063756b253e11610278578063b0d8e1811161015c578063d293c710116100ce578063d815e8e911610092578063d815e8e91461095a578063d9a7244414610962578063e056e91814610975578063e2ac77b014610988578063f36b24251461099b578063fe2ba848146109a3576104c2565b8063d293c71014610906578063d380a37c14610919578063d3d6f84314610921578063d5b3563514610934578063d66a255314610947576104c2565b8063be4b033411610120578063be4b0334146108cb578063bf9befb1146108d3578063c35bc550146108db578063c52861f2146108e3578063c7b55481146108eb578063cbd138ae146108f3576104c2565b8063b0d8e18114610867578063b7f8cf9b1461087a578063b82f263d14610882578063b91af97c14610895578063bcd37526146108b8576104c2565b8063887105d3116101f55780639dd233d2116101b95780639dd233d2146108325780639f0706701461083a578063a20baee614610773578063a3f4df7e14610842578063ae7bec1914610857578063ae9187541461085f576104c2565b8063887105d3146107f4578063893d20e8146107fc57806396d711ff146108045780639708daf41461080c5780639976cf451461081f576104c2565b80637cf54e401161023c5780637cf54e40146107b65780637f7dde4a146107be578063807d138d146107c657806382fe3eb9146107ce57806387436936146107e1576104c2565b8063756b253e14610783578063759b303414610796578063794e57241461079e578063795d26c3146107a6578063797250e3146107ae576104c2565b80633cc74225116103aa57806361ec893d1161031c5780636b444952116102e05780636b4449521461072c5780636ef6433814610734578063716c47e61461075857806372423c171461076057806372fe25aa14610773578063741bef1a1461077b576104c2565b806361ec893d146106e3578063631203b0146106eb57806364cee260146106fe578063653d46e71461071157806366ca4a2114610724576104c2565b80634a767d681161036e5780634a767d681461067a5780634e443d9e1461068d5780635733d58f146106ad5780635d6b480f146106b55780635d8c9609146106c85780635dba4c4a146106db576104c2565b80633cc742251461063157806342ccf1e414610639578063477d66cf1461064c578063480cd5781461065f57806349eefeee14610672576104c2565b806317c62b17116104435780631f68f20a116104075780631f68f20a146105eb57806321e37801146105f35780632b11551a146106065780632f8655681461060e57806331c903b0146106215780633a12859514610629576104c2565b806317c62b171461059757806318f2817a146105aa5780631a59a50e146105bd5780631bf43555146105d05780631e8b1c2b146105d8576104c2565b806312261ee71161048a57806312261ee71461053557806312610e921461053d57806313af40351461055057806315d549f1146105635780631673c79a14610576576104c2565b806301f16e18146104c757806305b6f5ca146104dc578063071a7541146104ef5780630b0765571461050d5780630d43e8ad14610520575b600080fd5b6104da6104d5366004614d96565b6109b6565b005b6104da6104ea366004614f61565b610f1c565b6104f7610fb3565b6040516105049190615568565b60405180910390f35b6104da61051b366004614c9f565b610fb8565b610528610fe0565b604051610504919061512e565b610528610fef565b6104f761054b366004614cd7565b611013565b6104da61055e366004614c9f565b61106b565b6104f7610571366004614c9f565b6110ac565b610589610584366004614c9f565b6110d0565b604051610504929190615571565b6104f76105a5366004614c9f565b6110e9565b6104f76105b8366004614c9f565b6110f4565b6104f76105cb366004614c9f565b611107565b6104f76111cd565b6104da6105e6366004614d02565b6111da565b6104f761153b565b6104f7610601366004614c9f565b611541565b6104f761156b565b6104da61061c366004614c9f565b61157a565b6104f76115e0565b6105286115ed565b6105286115fc565b6104f7610647366004614c9f565b61160b565b6104f761065a366004614ec4565b61163c565b6104f761066d366004614c9f565b61164f565b6104f761166d565b6104f7610688366004614cd7565b611673565b6106a061069b366004614ec4565b611692565b60405161050491906151a1565b6104f761169d565b6104da6106c3366004614cd7565b61171a565b6104f76106d6366004614c9f565b611766565b6104da611771565b6104f76117dc565b6104f76106f9366004614ec4565b6117e1565b6104f761070c366004614c9f565b6117ee565b6104da61071f366004614ec4565b61180c565b6104f7611b96565b6104f7611ba8565b610747610742366004614c9f565b611bae565b6040516105049594939291906155a3565b610528611be8565b6104f761076e366004614cd7565b611bf7565b6104f7611c54565b610528611c60565b610528610791366004614ec4565b611c6f565b6104f7611c96565b6104f7611ca3565b6104f7611ce8565b6104f7611e07565b610528611e0d565b610528611e1c565b6104f7611e2b565b6104da6107dc366004614c9f565b611e31565b6104da6107ef366004614c9f565b611e42565b6104f7611ece565b610528611f9d565b6104f7611fbc565b6104da61081a366004614feb565b611fc2565b6104f761082d366004614cd7565b61205b565b6104f761208e565b610528612094565b61084a6120a3565b60405161050491906151da565b6105286120cb565b6105286120da565b6104f7610875366004614c9f565b6120e9565b610528612110565b6104f7610890366004614ec4565b61211f565b6108a86108a3366004614c9f565b61212a565b604051610504949392919061560f565b6104da6108c6366004614ef4565b61218e565b6104f7612224565b6104f761222a565b6104f7612230565b6104f7612254565b6104f7612266565b6104da610901366004614c9f565b612272565b6104f7610914366004614cd7565b612285565b6104f7612298565b6104f761092f366004614cd7565b61229e565b6104f7610942366004614ec4565b6122d4565b6104f7610955366004614c9f565b6122e7565b610528612302565b610528610970366004614ec4565b612311565b6106a0610983366004614c9f565b61233b565b6106a0610996366004614c9f565b612399565b6104f76123a4565b6104da6109b1366004614c9f565b6123b1565b6109be611f9d565b6001600160a01b0316336001600160a01b0316146109f75760405162461bcd60e51b81526004016109ee906153c5565b60405180910390fd5b8051610a02906123c2565b610a0f81602001516123c2565b610a1c81604001516123c2565b610a2981606001516123c2565b610a3681608001516123c2565b610a438160a001516123c2565b610a508160c001516123c2565b610a5d8160e001516123c2565b610a6b8161010001516123c2565b610a798161012001516123c2565b610a878161014001516123c2565b610a958161016001516123c2565b610aa38161018001516123c2565b610ab1816101a001516123c2565b8051600c80546001600160a01b03199081166001600160a01b038085169190911790925560208401516004805483169184169190911790556040808501516003805484169185169190911790556060850151600580548416918516919091179055608085015160008054841691851691909117905560a085015160018054841691851691909117905560c085015160068054841691851691909117905560e0850151600780548416918516919091179055610100850151600880548416918516919091179055610120850151600280548416918516919091179055610140850151600980548416918516919091179055610160850151600d80548416918516919091179055610180850151600a805484169185169190911790556101a0850151600b80549093169316929092179055517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db991610c0c9161512e565b60405180910390a17f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b18160200151604051610c47919061512e565b60405180910390a17fbf65195e6d5213f6fcbce65b1454c925197a45e616dabd2e243542b039b050928160600151604051610c82919061512e565b60405180910390a17f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed9858160600151604051610cbd919061512e565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828160800151604051610cf8919061512e565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b8160a00151604051610d33919061512e565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f8160c00151604051610d6e919061512e565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa08160e00151604051610da9919061512e565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d816101000151604051610de5919061512e565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264816101200151604051610e21919061512e565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d816101400151604051610e5d919061512e565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800816101600151604051610e99919061512e565b60405180910390a17f61e0c29d5028a9e4facaa476a46e78912e99f1ba945c9560b86b82ebe36ee52d816101800151604051610ed5919061512e565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd816101a00151604051610f11919061512e565b60405180910390a150565b6004546040516000916060916001600160a01b0390911690610f419084903690615101565b600060405180830381855af49150503d8060008114610f7c576040519150601f19603f3d011682016040523d82523d6000602084013e610f81565b606091505b5091509150818190610fa65760405162461bcd60e51b81526004016109ee91906151da565b5050505050505050505050565b600281565b610fc0612407565b600054600154610fdd916001600160a01b03908116911683612433565b50565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061101d612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff61254516565b6001600160a01b03851660009081526010602052604090208190559150505b92915050565b611073611f9d565b6001600160a01b0316336001600160a01b0316146110a35760405162461bcd60e51b81526004016109ee906153c5565b610fdd81612587565b60006110b6612407565b6110bf82612612565b6001600160801b031690505b919050565b6016602052600090815260409020805460019091015482565b60006110658261160b565b60006110fe612407565b611065826126ac565b6001600160a01b0381166000908152601660205260408120546014548290611135908363ffffffff61254516565b905080158061116e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561116b57fe5b14155b1561117e576000925050506110cb565b6001600160a01b038416600090815260106020526040812060020154906111c3670de0b6b3a76400006111b7848663ffffffff61275f16565b9063ffffffff61279916565b9695505050505050565b6809c2007651b250000081565b80516111f85760405162461bcd60e51b81526004016109ee906153f6565b6000546001546006546001600160a01b0392831692918216911661121a614b2b565b611222614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ec57600080fd5b505afa158015611300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113249190614edc565b60208301528151611334906127db565b158015604084015261135c576113558585846000015185602001518a612876565b9050611374565b6113718585846000015185602001518a612b8b565b90505b60008160200151116113985760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad926113cc92600401615571565b600060405180830381600087803b1580156113e657600080fd5b505af11580156113fa573d6000803e3d6000fd5b5050505061141285858360c001518460e00151612ccb565b61010081015115611489576008546101008201516040516364a197f360e01b81526001600160a01b03888116936364a197f393611456939290911691600401615188565b600060405180830381600087803b15801561147057600080fd5b505af1158015611484573d6000803e3d6000fd5b505050505b611497858260400151612f2f565b60208101516060830152610100810151604082015182516114cf92916114c3919063ffffffff61254516565b9063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611517949092909161560f565b60405180910390a1611533853383606001518460400151613090565b505050505050565b600e5481565b6001600160a01b03811660009081526010602052604081206003015460ff16600481111561106557fe5b60006115756115e0565b905090565b6115838161316d565b6040805160018082528183019092526060916020808301908036833701905050905081816000815181106115b357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506115dc816111da565b5050565b6000611575600e546131b6565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290611135908363ffffffff61254516565b6000611065611649611b96565b83613253565b6001600160a01b031660009081526010602052604090206001015490565b60175490565b600080600061168185613271565b9150915060006111c38383876132f7565b6000611065826127db565b60035460408051635733d58f60e01b815290516000926001600160a01b031691635733d58f916004808301926020929190829003018186803b1580156116e257600080fd5b505afa1580156116f6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115759190614edc565b611722612407565b80600481111561172e57fe5b6001600160a01b0383166000908152601060205260409020600301805460ff1916600183600481111561175d57fe5b02179055505050565b600061106582611107565b611779612407565b6000611783613329565b9050670de0b6b3a764000081111561179757fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c906117cc908390615568565b60405180910390a1610fdd61336d565b603c81565b60006110656116496123a4565b6001600160a01b031660009081526010602052604090206002015490565b611814614ba8565b506040805160e081018252600080546001600160a01b0390811683526001548116602084015292820181905260608201819052600d548316608083015260a0820181905260c082015260065490911661186b614b2b565b611873614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fb9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b15801561193d57600080fd5b505afa158015611951573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119759190614edc565b60208301528151611985906127db565b15801560408401526119ac576119a58483600001518460200151886133c2565b90506119cc565b6119c9846000015185602001518460000151856020015189613869565b90505b60008160200151116119f05760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad92611a2492600401615571565b600060405180830381600087803b158015611a3e57600080fd5b505af1158015611a52573d6000803e3d6000fd5b50505050611a72846000015185602001518360c001518460e00151612ccb565b61010081015115611ae95783516008546101008301516040516364a197f360e01b81526001600160a01b03938416936364a197f393611ab693911691600401615188565b600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050505b611afb84600001518260400151612f2f565b6020810151606083015261010081015160408201518251611b2792916114c3919063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611b6f949092909161560f565b60405180910390a1611b8f84600001513383606001518460400151613090565b5050505050565b6000611575611ba3613329565b613a1f565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b6000611c01612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff613b0116565b6001600160a01b038516600090815260106020526040902060010181905591505092915050565b670de0b6b3a764000081565b6002546001600160a01b031681565b60178181548110611c7c57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60035460408051631e5395c960e21b815290516000926001600160a01b03169163794e5724916004808301926020929190829003018186803b1580156116e257600080fd5b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015611d2c57600080fd5b505afa158015611d40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d649190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b505afa158015611dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dee9190614edc565b9050611e00828263ffffffff613b0116565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b611e39612407565b610fdd81613b26565b611e4a611f9d565b6001600160a01b0316336001600160a01b031614611e7a5760405162461bcd60e51b81526004016109ee906153c5565b611e83816123c2565b600480546001600160a01b0319166001600160a01b0383161790556040517f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b190610f1190839061512e565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b158015611f1357600080fd5b505afa158015611f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4b9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b600080604051611fac90615111565b6040519081900390205492915050565b60135481565b6004546040516000916060916001600160a01b0390911690611fe79084903690615101565b600060405180830381855af49150503d8060008114612022576040519150601f19603f3d011682016040523d82523d6000602084013e612027565b606091505b509150915081819061204c5760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050505050565b6000612065612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff613b0116565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b60008060006120f784613271565b9150915060006121078383613b83565b95945050505050565b6005546001600160a01b031681565b600061106582613bb8565b6001600160a01b03811660009081526010602052604081208054600190910154909180612156856110e9565b915061216185611766565b9050612173848363ffffffff613b0116565b9350612185838263ffffffff613b0116565b92509193509193565b6004546040516000916060916001600160a01b03909116906121b39084903690615101565b600060405180830381855af49150503d80600081146121ee576040519150601f19603f3d011682016040523d82523d6000602084013e6121f3565b606091505b50915091508181906122185760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000611575612261613329565b6131b6565b670ddd4b8c6c7d70d881565b61227a612407565b610fdd816002613be4565b60006122918383611673565b9392505050565b600f5481565b60006122a8612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff61254516565b60006110656122e1612254565b83613cf9565b6001600160a01b031660009081526010602052604090205490565b6009546001600160a01b031681565b60006017828154811061232057fe5b6000918252602090912001546001600160a01b031692915050565b600060016001600160a01b03831660009081526010602052604090206003015460ff16600481111561236957fe5b14612376575060006110cb565b506014546001600160a01b03821660009081526016602052604090205410919050565b60006110658261233b565b6000611575600e54613a1f565b6123b9612407565b610fdd81613d39565b6001600160a01b0381166123e85760405162461bcd60e51b81526004016109ee906152a6565b803b806115dc5760405162461bcd60e51b81526004016109ee9061544c565b6005546001600160a01b031633146124315760405162461bcd60e51b81526004016109ee90615368565b565b61243c8161233b565b156125405761244a8161316d565b600061245582611107565b905060006124628361160b565b6001600160a01b038416600090815260106020526040902060010154909150612491908363ffffffff613b0116565b6001600160a01b03841660009081526010602052604090206001810191909155546124c2908263ffffffff613b0116565b6001600160a01b0384166000908152601060205260409020556124e483613b26565b6124f085858385613d89565b6001600160a01b0383166000818152601060205260408082208054600182015460029092015492516000805160206156b28339815191529461253594929392916155e3565b60405180910390a250505b505050565b600061229183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613e71565b6001600160a01b0381166125ad5760405162461bcd60e51b81526004016109ee90615264565b806001600160a01b03166125bf611f9d565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600060405161260290615111565b6040519081900390209190915550565b601780546001808201835560008381527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1590920180546001600160a01b0319166001600160a01b0386161790559154909161266d9190612545565b6001600160a01b039290921660009081526010602052604090206003018054610100600160881b0319166101006001600160801b038516021790555090565b6001600160a01b03811660009081526010602052604081206001015481906126d390613e9d565b6001600160a01b03841660009081526010602052604090206002018054908290556011549192509061271d908390612711908463ffffffff61254516565b9063ffffffff613b0116565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829161275091615568565b60405180910390a15092915050565b60008261276e57506000611065565b8282028284828161277b57fe5b04146122915760405162461bcd60e51b81526004016109ee90615327565b600061229183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ed9565b6000806127e783613bb8565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561283757600080fd5b505afa15801561284b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286f9190614edc565b1192915050565b61287e614b5c565b612886614be4565b61288e614b5c565b848252600060808301526128a0611ce8565b60a08301526128ad611ece565b60c0830152600060208301525b835182602001511015612b8057838260200151815181106128d757fe5b6020908102919091018101516001600160a01b03166060840181905260009081526010909152604090206003015460019060ff16600481111561291657fe5b1461292057612b70565b61292e826060015187611673565b60408301526080820151612a9557600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561298a57600080fd5b505afa15801561299e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c29190614edc565b8260400151101580156129d457508151155b156129de57612b70565b60006129f38360c001518460a00151896132f7565b9050612a108989856060015186604001518760000151868d613f10565b60808101518451919350612a2a919063ffffffff61254516565b8352608082015160a0840151612a459163ffffffff61254516565b60a08085019190915282015160c0840151612a659163ffffffff61254516565b60c0840152612a7484836142e6565b9350612a898360c001518460a00151896143fd565b15608084015250612b70565b81608001518015612b2e5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015612aef57600080fd5b505afa158015612b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b279190614edc565b8260400151105b15612b7057612b4788888460600151856000015161449c565b60808101518351919250612b61919063ffffffff61254516565b8252612b6d83826142e6565b92505b60208201805160010190526128ba565b505095945050505050565b612b93614b5c565b612b9b614be4565b612ba3614b5c565b848252600060208301525b835182602001511015612b805783826020015181518110612bcb57fe5b60209081029190910101516001600160a01b031660608301819052612bf09087611673565b6040808401919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c739190614edc565b82604001511015612cbb57612c9288888460600151856000015161449c565b60808101518351919250612cac919063ffffffff61254516565b8252612cb883826142e6565b92505b6020820180516001019052612bae565b81612cd557612f29565b601854600090612cf79061271184670de0b6b3a764000063ffffffff61275f16565b90506000612d1c601954612711670de0b6b3a76400008761275f90919063ffffffff16565b90506000612d356011548461279990919063ffffffff16565b90506000612d4e6011548461279990919063ffffffff16565b9050612d75612d686011548461275f90919063ffffffff16565b859063ffffffff61254516565b601855601154612d9d90612d9090839063ffffffff61275f16565b849063ffffffff61254516565b601955601454612db3908363ffffffff613b0116565b601455601554612dc9908263ffffffff613b0116565b60158190556014546040517f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e392612e009291615571565b60405180910390a160405163121cbc4d60e11b81526001600160a01b03891690632439789a90612e34908990600401615568565b600060405180830381600087803b158015612e4e57600080fd5b505af1158015612e62573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038a16925063f2e91d719150612e92908990600401615568565b600060405180830381600087803b158015612eac57600080fd5b505af1158015612ec0573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b038b1692506364a197f39150612ef2908a908990600401615188565b600060405180830381600087803b158015612f0c57600080fd5b505af1158015612f20573d6000803e3d6000fd5b50505050505050505b50505050565b6011546012819055506000826001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7357600080fd5b505afa158015612f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fab9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ffd57600080fd5b505afa158015613011573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130359190614edc565b905061304b81612711848663ffffffff61254516565b60138190556012546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf60926130829291615571565b60405180910390a150505050565b811561310157600954600754604051631062c15f60e11b81526001600160a01b03928316926320c582be926130ce9291169087908790600401615142565b600060405180830381600087803b1580156130e857600080fd5b505af11580156130fc573d6000803e3d6000fd5b505050505b8015612f29576040516364a197f360e01b81526001600160a01b038516906364a197f3906131359086908590600401615188565b600060405180830381600087803b15801561314f57600080fd5b505af1158015613163573d6000803e3d6000fd5b5050505050505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561319957fe5b14610fdd5760405162461bcd60e51b81526004016109ee90615519565b600061106561324583600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b505afa158015613221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127119190614edc565b670de0b6b3a76400006145ce565b6000612291670de0b6b3a76400006111b7858563ffffffff61275f16565b600080600061327f84611107565b9050600061328c8561160b565b6001600160a01b038616600090815260106020526040812060010154919250906132bc908463ffffffff613b0116565b6001600160a01b038716600090815260106020526040812054919250906132e9908463ffffffff613b0116565b919550909350505050915091565b6000821561331e576000613315846111b7878663ffffffff61275f16565b91506122919050565b506000199392505050565b6000806133346145e4565b9050600061334a670ddd4b8c6c7d70d883614600565b9050611e00670de0b6b3a76400006111b783600e5461275f90919063ffffffff16565b6000613384600f544261254590919063ffffffff16565b9050603c8110610fdd5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc91610f1191615568565b6133ca614b5c565b6133d2614be4565b6133da614b5c565b848252600060808301526133ec611ce8565b60a08301526133f9611ece565b8260c001818152505086608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561343f57600080fd5b505afa158015613453573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134779190614cbb565b82606001906001600160a01b031690816001600160a01b031681525050600087608001516001600160a01b0316631e2231436040518163ffffffff1660e01b815260040160206040518083038186803b1580156134d357600080fd5b505afa1580156134e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350b9190614cbb565b6000602085015290505b84836020015110801561353e5750806001600160a01b031683606001516001600160a01b031614155b1561385e5760808801516060840151604051632dc9c0eb60e21b81526000926001600160a01b03169163b72703ac9161357a919060040161512e565b60206040518083038186803b15801561359257600080fd5b505afa1580156135a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ca9190614cbb565b90506135da846060015189611673565b6040850152608084015161375357600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561363657600080fd5b505afa15801561364a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061366e9190614edc565b84604001511015801561368057508351155b1561368b575061385e565b60006136a08560c001518660a001518b6132f7565b8a5160208c01516060880151604089015189519495506136c194868f613f10565b608081015186519195506136db919063ffffffff61254516565b8552608084015160a08601516136f69163ffffffff61254516565b8560a00181815250506137238461010001516114c38660a001518860c0015161254590919063ffffffff16565b60c086015261373286856142e6565b95506137478560c001518660a001518b6143fd565b15608086015250613840565b836080015180156137ec5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156137ad57600080fd5b505afa1580156137c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e59190614edc565b8460400151105b1561383a5761380d89600001518a602001518660600151876000015161449c565b60808101518551919450613827919063ffffffff61254516565b845261383385846142e6565b9450613840565b5061385e565b6001600160a01b031660608401526020830180516001019052613515565b505050949350505050565b613871614b5c565b613879614be4565b613881614b5c565b600d54858352600060208401526001600160a01b03165b8483602001511015613a1357806001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156138dd57600080fd5b505afa1580156138f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139159190614cbb565b6001600160a01b03166060840181905261392f9088611673565b6040808501919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b15801561397a57600080fd5b505afa15801561398e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b29190614edc565b836040015110156139fe576139d189898560600151866000015161449c565b608081015184519193506139eb919063ffffffff61254516565b83526139f784836142e6565b9350613a03565b613a13565b6020830180516001019052613898565b50505095945050505050565b6000611065613a7683600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b031663240926696040518163ffffffff1660e01b815260040160206040518083038186803b158015613ac457600080fd5b505afa158015613ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613afc9190614edc565b6145ce565b6000828201838110156122915760405162461bcd60e51b81526004016109ee9061522d565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92610f11929091615571565b60008115613baf57613ba8826111b78568056bc75e2d6310000063ffffffff61275f16565b9050611065565b50600019611065565b600080613bc3611ece565b90506000613bcf611ce8565b9050613bdc8282866132f7565b949350505050565b6000816004811115613bf257fe5b14158015613c0c57506001816004811115613c0957fe5b14155b613c1257fe5b601754613c1e816146ab565b6001600160a01b0383166000908152601060205260409020600301805483919060ff19166001836004811115613c5057fe5b02179055506001600160a01b0383166000908152601060209081526040808320600180820185905590849055601690925282208281550155613c928382614751565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e90613cc290869060040161512e565b600060405180830381600087803b158015613cdc57600080fd5b505af1158015613cf0573d6000803e3d6000fd5b50505050505050565b600080613d18670de0b6b3a76400006111b7868663ffffffff61275f16565b90508281106122915760405162461bcd60e51b81526004016109ee90615481565b6001600160a01b038116600090815260106020526040902060020154601154613d68908263ffffffff61254516565b601155506001600160a01b0316600090815260106020526040812060020155565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a90613db5908590600401615568565b600060405180830381600087803b158015613dcf57600080fd5b505af1158015613de3573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150613e13908590600401615568565b600060405180830381600087803b158015613e2d57600080fd5b505af1158015613e41573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150613135908490600401615568565b60008184841115613e955760405162461bcd60e51b81526004016109ee91906151da565b505050900390565b60008060135460001415613eb2575081611065565b600060125411613ebe57fe5b6122916013546111b76012548661275f90919063ffffffff16565b60008183613efa5760405162461bcd60e51b81526004016109ee91906151da565b506000838581613f0657fe5b0495945050505050565b613f18614b5c565b613f20614c2c565b601754600110613f3057506142db565b613f398761212a565b60408501526020848101919091528401819052908352613f58906148f2565b604083018190526801158e460913d0000060608401526020830151613f829163ffffffff61254516565b8152670de0b6b3a7640000861161404d57613fa7898983602001518460400151613d89565b613fb087613d39565b60006080830181905260a0830152815160c0830152805160e0830152613fd7876003613be4565b815160208301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b60405180910390a2866001600160a01b03166000805160206156b28339815191526000806000600260405161404094939291906151ac565b60405180910390a26142d9565b670de0b6b3a7640000861180156140e85750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156140ad57600080fd5b505afa1580156140c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e59190614edc565b86105b1561413857614101898983602001518460400151613d89565b61410a87613d39565b8151815161411991908761497e565b60e086015260c085015260a08401526080830152613fd7876003613be4565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561418657600080fd5b505afa15801561419a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141be9190614edc565b86101580156141cc57508386105b80156141d9575081518510155b156142c8576141f2898983602001518460400151613d89565b846141f957fe5b61420287613d39565b61421582600001518360200151856149ea565b9150614222876003613be4565b6101008201511561429757600854610100830151604051633f10abab60e01b81526001600160a01b0390921691633f10abab91614264918b9190600401615188565b600060405180830381600087803b15801561427e57600080fd5b505af1158015614292573d6000803e3d6000fd5b505050505b815160a08301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b6142d0614b5c565b91506142db9050565b505b979650505050505050565b6142ee614b5c565b604080830151908401516143079163ffffffff613b0116565b6040820152606080830151908401516143259163ffffffff613b0116565b6060820152815160208401516143409163ffffffff613b0116565b602080830191909152820151835161435d9163ffffffff613b0116565b8152608080830151908401516143789163ffffffff613b0116565b608082015260a080830151908401516143969163ffffffff613b0116565b60a082015260c080830151908401516143b49163ffffffff613b0116565b60c082015260e080830151908401516143d29163ffffffff613b0116565b60e082015261010080830151908401516143f19163ffffffff613b0116565b61010082015292915050565b60008061440b8585856132f7565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561445b57600080fd5b505afa15801561446f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144939190614edc565b11949350505050565b6144a4614b5c565b6144ac614c2c565b6144b58461212a565b604085019081526020858101928352860192909252918452905190516144df918891889190613d89565b6144e884613d39565b6144f582602001516148f2565b604083018190526801158e460913d0000060608401526020830151600091614523919063ffffffff61254516565b90506145348360000151828661497e565b60e087015260c086015260a08501526080840152614553856003613be4565b825160208401516040516001600160a01b03881692600080516020615692833981519152926145849260019061557f565b60405180910390a2846001600160a01b03166000805160206156b2833981519152600080600060016040516145bc94939291906151ac565b60405180910390a25050949350505050565b60008183106145dd5781612291565b5090919050565b6000611575603c6111b7600f544261254590919063ffffffff16565b6000631f54050082111561461657631f54050091505b8161462a5750670de0b6b3a7640000611065565b670de0b6b3a764000083835b60018111156146a1576002810661466b576146518283614af8565b915061466481600263ffffffff61279916565b905061469c565b6146758284614af8565b92506146818283614af8565b915061469960026111b783600163ffffffff61254516565b90505b614636565b6111c38284614af8565b6001811180156147355750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b1580156146fb57600080fd5b505afa15801561470f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147339190614edc565b115b610fdd5760405162461bcd60e51b81526004016109ee906152dd565b6001600160a01b03821660009081526010602052604081206003015460ff169081600481111561477d57fe5b141580156147975750600181600481111561479457fe5b14155b61479d57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b03169083906147d5826001612545565b905080836001600160801b031611156147ea57fe5b6000601782815481106147f957fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b03871690811061482b57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a906148b49083908790615166565b60405180910390a160178054806148c757fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b600354604080516324386ecd60e11b815290516000926001600160a01b031691634870dd9a916004808301926020929190829003018186803b15801561493757600080fd5b505afa15801561494b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496f9190614edc565b828161497757fe5b0492915050565b600080808084156149d45761499387866145ce565b93506149a9876111b7888763ffffffff61275f16565b92506149bb878563ffffffff61254516565b91506149cd868463ffffffff61254516565b90506149e1565b5060009250829150859050845b93509350935093565b6149f2614b5c565b838152602080820184905260035460408051631e5395c960e21b81529051600093614a8e9387936111b7936001600160a01b039092169263794e572492600480840193829003018186803b158015614a4957600080fd5b505afa158015614a5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a819190614edc565b889063ffffffff61275f16565b9050614a99816148f2565b604083018190526801158e460913d00000606084015260808301869052614ac790829063ffffffff61254516565b60a0830152614adc848263ffffffff61254516565b61010083015250600060c0820181905260e08201529392505050565b600080614b0b848463ffffffff61275f16565b9050613bdc670de0b6b3a76400006111b7836706f05b59d3b20000613b01565b6040518060a00160405280600081526020016000815260200160001515815260200160008152602001600081525090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040518060e0016040528060008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b80356110658161567c565b60008083601f840112614c69578081fd5b50813567ffffffffffffffff811115614c80578182fd5b602083019150836020828501011115614c9857600080fd5b9250929050565b600060208284031215614cb0578081fd5b81356122918161567c565b600060208284031215614ccc578081fd5b81516122918161567c565b60008060408385031215614ce9578081fd5b8235614cf48161567c565b946020939093013593505050565b60006020808385031215614d14578182fd5b823567ffffffffffffffff811115614d2a578283fd5b80840185601f820112614d3b578384fd5b80359150614d50614d4b83615651565b61562a565b8281528381019082850185850284018601891015614d6c578687fd5b8693505b848410156142d957614d828982614c4d565b835260019390930192918501918501614d70565b60006101c0808385031215614da9578182fd5b614db28161562a565b614dbc8585614c4d565b8152614dcb8560208601614c4d565b6020820152614ddd8560408601614c4d565b6040820152614def8560608601614c4d565b6060820152614e018560808601614c4d565b6080820152614e138560a08601614c4d565b60a0820152614e258560c08601614c4d565b60c0820152614e378560e08601614c4d565b60e08201526101009150614e4d85838601614c4d565b828201526101209150614e6285838601614c4d565b828201526101409150614e7785838601614c4d565b828201526101609150614e8c85838601614c4d565b828201526101809150614ea185838601614c4d565b828201526101a09150614eb685838601614c4d565b918101919091529392505050565b600060208284031215614ed5578081fd5b5035919050565b600060208284031215614eed578081fd5b5051919050565b600080600080600080600060e0888a031215614f0e578283fd5b873596506020880135614f208161567c565b95506040880135614f308161567c565b94506060880135614f408161567c565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a03610160811215614f7e578182fd5b8935985060208a0135614f908161567c565b975060408a0135614fa08161567c565b965060608a0135614fb08161567c565b955060808a810135955060a08b0135945060c08b0135935060df1982011215614fd7578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c0361018081121561500b578485fd5b8b359a5060208c013561501d8161567c565b995060408c013561502d8161567c565b985060608c013561503d8161567c565b975060808c810135975060a08d0135965060c08d0135955060df19820190811215615066578384fd5b615070606061562a565b9150604081121561507f578384fd5b5061508a604061562a565b60e08d01356150988161567c565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff8111156150dd578283fd5b6150e98d828e01614c58565b8194508093505050509295989b9194979a5092959850565b6000828483379101908152919050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b848152602081018490526040810183905260808101600483106151cb57fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015615206578581018301518582016040015282016151ea565b818111156152175783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252603b908201527f54726f76654d616e616765723a2043616c6c6572206973206e6f74207468652060408201527f426f72726f7765724f7065726174696f6e7320636f6e74726163740000000000606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2043616c6c646174612061646472657373206160408201527572726179206d757374206e6f7420626520656d70747960501b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526022908201527f54726f76654d616e616765723a206e6f7468696e6720746f206c697175696461604082015261746560f01b606082015260800190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b90815260200190565b918252602082015260400190565b838152602081018390526060810161559683615671565b6040830152949350505050565b858152602081018590526040810184905260a08101600584106155c257fe5b60608201939093526001600160801b03919091166080909101529392505050565b84815260208101849052604081018390526080810161560183615671565b606083015295945050505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff8111828210171561564957600080fd5b604052919050565b600067ffffffffffffffff821115615667578081fd5b5060209081020190565b80600481106110cb57fe5b6001600160a01b0381168114610fdd57600080fdfeea67486ed7ebe3eea8ab3390efd4a3c8aae48be5bea27df104a8af786c408434c3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba2646970667358221220a4c2a9a9ec603c1ba14143d02dd4e890d8f91d610315ce69bf8078c0892e8c2464736f6c634300060b0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106104c25760003560e01c8063756b253e11610278578063b0d8e1811161015c578063d293c710116100ce578063d815e8e911610092578063d815e8e91461095a578063d9a7244414610962578063e056e91814610975578063e2ac77b014610988578063f36b24251461099b578063fe2ba848146109a3576104c2565b8063d293c71014610906578063d380a37c14610919578063d3d6f84314610921578063d5b3563514610934578063d66a255314610947576104c2565b8063be4b033411610120578063be4b0334146108cb578063bf9befb1146108d3578063c35bc550146108db578063c52861f2146108e3578063c7b55481146108eb578063cbd138ae146108f3576104c2565b8063b0d8e18114610867578063b7f8cf9b1461087a578063b82f263d14610882578063b91af97c14610895578063bcd37526146108b8576104c2565b8063887105d3116101f55780639dd233d2116101b95780639dd233d2146108325780639f0706701461083a578063a20baee614610773578063a3f4df7e14610842578063ae7bec1914610857578063ae9187541461085f576104c2565b8063887105d3146107f4578063893d20e8146107fc57806396d711ff146108045780639708daf41461080c5780639976cf451461081f576104c2565b80637cf54e401161023c5780637cf54e40146107b65780637f7dde4a146107be578063807d138d146107c657806382fe3eb9146107ce57806387436936146107e1576104c2565b8063756b253e14610783578063759b303414610796578063794e57241461079e578063795d26c3146107a6578063797250e3146107ae576104c2565b80633cc74225116103aa57806361ec893d1161031c5780636b444952116102e05780636b4449521461072c5780636ef6433814610734578063716c47e61461075857806372423c171461076057806372fe25aa14610773578063741bef1a1461077b576104c2565b806361ec893d146106e3578063631203b0146106eb57806364cee260146106fe578063653d46e71461071157806366ca4a2114610724576104c2565b80634a767d681161036e5780634a767d681461067a5780634e443d9e1461068d5780635733d58f146106ad5780635d6b480f146106b55780635d8c9609146106c85780635dba4c4a146106db576104c2565b80633cc742251461063157806342ccf1e414610639578063477d66cf1461064c578063480cd5781461065f57806349eefeee14610672576104c2565b806317c62b17116104435780631f68f20a116104075780631f68f20a146105eb57806321e37801146105f35780632b11551a146106065780632f8655681461060e57806331c903b0146106215780633a12859514610629576104c2565b806317c62b171461059757806318f2817a146105aa5780631a59a50e146105bd5780631bf43555146105d05780631e8b1c2b146105d8576104c2565b806312261ee71161048a57806312261ee71461053557806312610e921461053d57806313af40351461055057806315d549f1146105635780631673c79a14610576576104c2565b806301f16e18146104c757806305b6f5ca146104dc578063071a7541146104ef5780630b0765571461050d5780630d43e8ad14610520575b600080fd5b6104da6104d5366004614d96565b6109b6565b005b6104da6104ea366004614f61565b610f1c565b6104f7610fb3565b6040516105049190615568565b60405180910390f35b6104da61051b366004614c9f565b610fb8565b610528610fe0565b604051610504919061512e565b610528610fef565b6104f761054b366004614cd7565b611013565b6104da61055e366004614c9f565b61106b565b6104f7610571366004614c9f565b6110ac565b610589610584366004614c9f565b6110d0565b604051610504929190615571565b6104f76105a5366004614c9f565b6110e9565b6104f76105b8366004614c9f565b6110f4565b6104f76105cb366004614c9f565b611107565b6104f76111cd565b6104da6105e6366004614d02565b6111da565b6104f761153b565b6104f7610601366004614c9f565b611541565b6104f761156b565b6104da61061c366004614c9f565b61157a565b6104f76115e0565b6105286115ed565b6105286115fc565b6104f7610647366004614c9f565b61160b565b6104f761065a366004614ec4565b61163c565b6104f761066d366004614c9f565b61164f565b6104f761166d565b6104f7610688366004614cd7565b611673565b6106a061069b366004614ec4565b611692565b60405161050491906151a1565b6104f761169d565b6104da6106c3366004614cd7565b61171a565b6104f76106d6366004614c9f565b611766565b6104da611771565b6104f76117dc565b6104f76106f9366004614ec4565b6117e1565b6104f761070c366004614c9f565b6117ee565b6104da61071f366004614ec4565b61180c565b6104f7611b96565b6104f7611ba8565b610747610742366004614c9f565b611bae565b6040516105049594939291906155a3565b610528611be8565b6104f761076e366004614cd7565b611bf7565b6104f7611c54565b610528611c60565b610528610791366004614ec4565b611c6f565b6104f7611c96565b6104f7611ca3565b6104f7611ce8565b6104f7611e07565b610528611e0d565b610528611e1c565b6104f7611e2b565b6104da6107dc366004614c9f565b611e31565b6104da6107ef366004614c9f565b611e42565b6104f7611ece565b610528611f9d565b6104f7611fbc565b6104da61081a366004614feb565b611fc2565b6104f761082d366004614cd7565b61205b565b6104f761208e565b610528612094565b61084a6120a3565b60405161050491906151da565b6105286120cb565b6105286120da565b6104f7610875366004614c9f565b6120e9565b610528612110565b6104f7610890366004614ec4565b61211f565b6108a86108a3366004614c9f565b61212a565b604051610504949392919061560f565b6104da6108c6366004614ef4565b61218e565b6104f7612224565b6104f761222a565b6104f7612230565b6104f7612254565b6104f7612266565b6104da610901366004614c9f565b612272565b6104f7610914366004614cd7565b612285565b6104f7612298565b6104f761092f366004614cd7565b61229e565b6104f7610942366004614ec4565b6122d4565b6104f7610955366004614c9f565b6122e7565b610528612302565b610528610970366004614ec4565b612311565b6106a0610983366004614c9f565b61233b565b6106a0610996366004614c9f565b612399565b6104f76123a4565b6104da6109b1366004614c9f565b6123b1565b6109be611f9d565b6001600160a01b0316336001600160a01b0316146109f75760405162461bcd60e51b81526004016109ee906153c5565b60405180910390fd5b8051610a02906123c2565b610a0f81602001516123c2565b610a1c81604001516123c2565b610a2981606001516123c2565b610a3681608001516123c2565b610a438160a001516123c2565b610a508160c001516123c2565b610a5d8160e001516123c2565b610a6b8161010001516123c2565b610a798161012001516123c2565b610a878161014001516123c2565b610a958161016001516123c2565b610aa38161018001516123c2565b610ab1816101a001516123c2565b8051600c80546001600160a01b03199081166001600160a01b038085169190911790925560208401516004805483169184169190911790556040808501516003805484169185169190911790556060850151600580548416918516919091179055608085015160008054841691851691909117905560a085015160018054841691851691909117905560c085015160068054841691851691909117905560e0850151600780548416918516919091179055610100850151600880548416918516919091179055610120850151600280548416918516919091179055610140850151600980548416918516919091179055610160850151600d80548416918516919091179055610180850151600a805484169185169190911790556101a0850151600b80549093169316929092179055517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db991610c0c9161512e565b60405180910390a17f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b18160200151604051610c47919061512e565b60405180910390a17fbf65195e6d5213f6fcbce65b1454c925197a45e616dabd2e243542b039b050928160600151604051610c82919061512e565b60405180910390a17f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed9858160600151604051610cbd919061512e565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828160800151604051610cf8919061512e565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b8160a00151604051610d33919061512e565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f8160c00151604051610d6e919061512e565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa08160e00151604051610da9919061512e565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d816101000151604051610de5919061512e565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264816101200151604051610e21919061512e565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d816101400151604051610e5d919061512e565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800816101600151604051610e99919061512e565b60405180910390a17f61e0c29d5028a9e4facaa476a46e78912e99f1ba945c9560b86b82ebe36ee52d816101800151604051610ed5919061512e565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd816101a00151604051610f11919061512e565b60405180910390a150565b6004546040516000916060916001600160a01b0390911690610f419084903690615101565b600060405180830381855af49150503d8060008114610f7c576040519150601f19603f3d011682016040523d82523d6000602084013e610f81565b606091505b5091509150818190610fa65760405162461bcd60e51b81526004016109ee91906151da565b5050505050505050505050565b600281565b610fc0612407565b600054600154610fdd916001600160a01b03908116911683612433565b50565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061101d612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff61254516565b6001600160a01b03851660009081526010602052604090208190559150505b92915050565b611073611f9d565b6001600160a01b0316336001600160a01b0316146110a35760405162461bcd60e51b81526004016109ee906153c5565b610fdd81612587565b60006110b6612407565b6110bf82612612565b6001600160801b031690505b919050565b6016602052600090815260409020805460019091015482565b60006110658261160b565b60006110fe612407565b611065826126ac565b6001600160a01b0381166000908152601660205260408120546014548290611135908363ffffffff61254516565b905080158061116e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561116b57fe5b14155b1561117e576000925050506110cb565b6001600160a01b038416600090815260106020526040812060020154906111c3670de0b6b3a76400006111b7848663ffffffff61275f16565b9063ffffffff61279916565b9695505050505050565b6809c2007651b250000081565b80516111f85760405162461bcd60e51b81526004016109ee906153f6565b6000546001546006546001600160a01b0392831692918216911661121a614b2b565b611222614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ec57600080fd5b505afa158015611300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113249190614edc565b60208301528151611334906127db565b158015604084015261135c576113558585846000015185602001518a612876565b9050611374565b6113718585846000015185602001518a612b8b565b90505b60008160200151116113985760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad926113cc92600401615571565b600060405180830381600087803b1580156113e657600080fd5b505af11580156113fa573d6000803e3d6000fd5b5050505061141285858360c001518460e00151612ccb565b61010081015115611489576008546101008201516040516364a197f360e01b81526001600160a01b03888116936364a197f393611456939290911691600401615188565b600060405180830381600087803b15801561147057600080fd5b505af1158015611484573d6000803e3d6000fd5b505050505b611497858260400151612f2f565b60208101516060830152610100810151604082015182516114cf92916114c3919063ffffffff61254516565b9063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611517949092909161560f565b60405180910390a1611533853383606001518460400151613090565b505050505050565b600e5481565b6001600160a01b03811660009081526010602052604081206003015460ff16600481111561106557fe5b60006115756115e0565b905090565b6115838161316d565b6040805160018082528183019092526060916020808301908036833701905050905081816000815181106115b357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506115dc816111da565b5050565b6000611575600e546131b6565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290611135908363ffffffff61254516565b6000611065611649611b96565b83613253565b6001600160a01b031660009081526010602052604090206001015490565b60175490565b600080600061168185613271565b9150915060006111c38383876132f7565b6000611065826127db565b60035460408051635733d58f60e01b815290516000926001600160a01b031691635733d58f916004808301926020929190829003018186803b1580156116e257600080fd5b505afa1580156116f6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115759190614edc565b611722612407565b80600481111561172e57fe5b6001600160a01b0383166000908152601060205260409020600301805460ff1916600183600481111561175d57fe5b02179055505050565b600061106582611107565b611779612407565b6000611783613329565b9050670de0b6b3a764000081111561179757fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c906117cc908390615568565b60405180910390a1610fdd61336d565b603c81565b60006110656116496123a4565b6001600160a01b031660009081526010602052604090206002015490565b611814614ba8565b506040805160e081018252600080546001600160a01b0390811683526001548116602084015292820181905260608201819052600d548316608083015260a0820181905260c082015260065490911661186b614b2b565b611873614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fb9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b15801561193d57600080fd5b505afa158015611951573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119759190614edc565b60208301528151611985906127db565b15801560408401526119ac576119a58483600001518460200151886133c2565b90506119cc565b6119c9846000015185602001518460000151856020015189613869565b90505b60008160200151116119f05760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad92611a2492600401615571565b600060405180830381600087803b158015611a3e57600080fd5b505af1158015611a52573d6000803e3d6000fd5b50505050611a72846000015185602001518360c001518460e00151612ccb565b61010081015115611ae95783516008546101008301516040516364a197f360e01b81526001600160a01b03938416936364a197f393611ab693911691600401615188565b600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050505b611afb84600001518260400151612f2f565b6020810151606083015261010081015160408201518251611b2792916114c3919063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611b6f949092909161560f565b60405180910390a1611b8f84600001513383606001518460400151613090565b5050505050565b6000611575611ba3613329565b613a1f565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b6000611c01612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff613b0116565b6001600160a01b038516600090815260106020526040902060010181905591505092915050565b670de0b6b3a764000081565b6002546001600160a01b031681565b60178181548110611c7c57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60035460408051631e5395c960e21b815290516000926001600160a01b03169163794e5724916004808301926020929190829003018186803b1580156116e257600080fd5b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015611d2c57600080fd5b505afa158015611d40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d649190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b505afa158015611dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dee9190614edc565b9050611e00828263ffffffff613b0116565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b611e39612407565b610fdd81613b26565b611e4a611f9d565b6001600160a01b0316336001600160a01b031614611e7a5760405162461bcd60e51b81526004016109ee906153c5565b611e83816123c2565b600480546001600160a01b0319166001600160a01b0383161790556040517f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b190610f1190839061512e565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b158015611f1357600080fd5b505afa158015611f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4b9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b600080604051611fac90615111565b6040519081900390205492915050565b60135481565b6004546040516000916060916001600160a01b0390911690611fe79084903690615101565b600060405180830381855af49150503d8060008114612022576040519150601f19603f3d011682016040523d82523d6000602084013e612027565b606091505b509150915081819061204c5760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050505050565b6000612065612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff613b0116565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b60008060006120f784613271565b9150915060006121078383613b83565b95945050505050565b6005546001600160a01b031681565b600061106582613bb8565b6001600160a01b03811660009081526010602052604081208054600190910154909180612156856110e9565b915061216185611766565b9050612173848363ffffffff613b0116565b9350612185838263ffffffff613b0116565b92509193509193565b6004546040516000916060916001600160a01b03909116906121b39084903690615101565b600060405180830381855af49150503d80600081146121ee576040519150601f19603f3d011682016040523d82523d6000602084013e6121f3565b606091505b50915091508181906122185760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000611575612261613329565b6131b6565b670ddd4b8c6c7d70d881565b61227a612407565b610fdd816002613be4565b60006122918383611673565b9392505050565b600f5481565b60006122a8612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff61254516565b60006110656122e1612254565b83613cf9565b6001600160a01b031660009081526010602052604090205490565b6009546001600160a01b031681565b60006017828154811061232057fe5b6000918252602090912001546001600160a01b031692915050565b600060016001600160a01b03831660009081526010602052604090206003015460ff16600481111561236957fe5b14612376575060006110cb565b506014546001600160a01b03821660009081526016602052604090205410919050565b60006110658261233b565b6000611575600e54613a1f565b6123b9612407565b610fdd81613d39565b6001600160a01b0381166123e85760405162461bcd60e51b81526004016109ee906152a6565b803b806115dc5760405162461bcd60e51b81526004016109ee9061544c565b6005546001600160a01b031633146124315760405162461bcd60e51b81526004016109ee90615368565b565b61243c8161233b565b156125405761244a8161316d565b600061245582611107565b905060006124628361160b565b6001600160a01b038416600090815260106020526040902060010154909150612491908363ffffffff613b0116565b6001600160a01b03841660009081526010602052604090206001810191909155546124c2908263ffffffff613b0116565b6001600160a01b0384166000908152601060205260409020556124e483613b26565b6124f085858385613d89565b6001600160a01b0383166000818152601060205260408082208054600182015460029092015492516000805160206156b28339815191529461253594929392916155e3565b60405180910390a250505b505050565b600061229183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613e71565b6001600160a01b0381166125ad5760405162461bcd60e51b81526004016109ee90615264565b806001600160a01b03166125bf611f9d565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600060405161260290615111565b6040519081900390209190915550565b601780546001808201835560008381527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1590920180546001600160a01b0319166001600160a01b0386161790559154909161266d9190612545565b6001600160a01b039290921660009081526010602052604090206003018054610100600160881b0319166101006001600160801b038516021790555090565b6001600160a01b03811660009081526010602052604081206001015481906126d390613e9d565b6001600160a01b03841660009081526010602052604090206002018054908290556011549192509061271d908390612711908463ffffffff61254516565b9063ffffffff613b0116565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829161275091615568565b60405180910390a15092915050565b60008261276e57506000611065565b8282028284828161277b57fe5b04146122915760405162461bcd60e51b81526004016109ee90615327565b600061229183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ed9565b6000806127e783613bb8565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561283757600080fd5b505afa15801561284b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286f9190614edc565b1192915050565b61287e614b5c565b612886614be4565b61288e614b5c565b848252600060808301526128a0611ce8565b60a08301526128ad611ece565b60c0830152600060208301525b835182602001511015612b8057838260200151815181106128d757fe5b6020908102919091018101516001600160a01b03166060840181905260009081526010909152604090206003015460019060ff16600481111561291657fe5b1461292057612b70565b61292e826060015187611673565b60408301526080820151612a9557600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561298a57600080fd5b505afa15801561299e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c29190614edc565b8260400151101580156129d457508151155b156129de57612b70565b60006129f38360c001518460a00151896132f7565b9050612a108989856060015186604001518760000151868d613f10565b60808101518451919350612a2a919063ffffffff61254516565b8352608082015160a0840151612a459163ffffffff61254516565b60a08085019190915282015160c0840151612a659163ffffffff61254516565b60c0840152612a7484836142e6565b9350612a898360c001518460a00151896143fd565b15608084015250612b70565b81608001518015612b2e5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015612aef57600080fd5b505afa158015612b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b279190614edc565b8260400151105b15612b7057612b4788888460600151856000015161449c565b60808101518351919250612b61919063ffffffff61254516565b8252612b6d83826142e6565b92505b60208201805160010190526128ba565b505095945050505050565b612b93614b5c565b612b9b614be4565b612ba3614b5c565b848252600060208301525b835182602001511015612b805783826020015181518110612bcb57fe5b60209081029190910101516001600160a01b031660608301819052612bf09087611673565b6040808401919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c739190614edc565b82604001511015612cbb57612c9288888460600151856000015161449c565b60808101518351919250612cac919063ffffffff61254516565b8252612cb883826142e6565b92505b6020820180516001019052612bae565b81612cd557612f29565b601854600090612cf79061271184670de0b6b3a764000063ffffffff61275f16565b90506000612d1c601954612711670de0b6b3a76400008761275f90919063ffffffff16565b90506000612d356011548461279990919063ffffffff16565b90506000612d4e6011548461279990919063ffffffff16565b9050612d75612d686011548461275f90919063ffffffff16565b859063ffffffff61254516565b601855601154612d9d90612d9090839063ffffffff61275f16565b849063ffffffff61254516565b601955601454612db3908363ffffffff613b0116565b601455601554612dc9908263ffffffff613b0116565b60158190556014546040517f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e392612e009291615571565b60405180910390a160405163121cbc4d60e11b81526001600160a01b03891690632439789a90612e34908990600401615568565b600060405180830381600087803b158015612e4e57600080fd5b505af1158015612e62573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038a16925063f2e91d719150612e92908990600401615568565b600060405180830381600087803b158015612eac57600080fd5b505af1158015612ec0573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b038b1692506364a197f39150612ef2908a908990600401615188565b600060405180830381600087803b158015612f0c57600080fd5b505af1158015612f20573d6000803e3d6000fd5b50505050505050505b50505050565b6011546012819055506000826001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7357600080fd5b505afa158015612f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fab9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ffd57600080fd5b505afa158015613011573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130359190614edc565b905061304b81612711848663ffffffff61254516565b60138190556012546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf60926130829291615571565b60405180910390a150505050565b811561310157600954600754604051631062c15f60e11b81526001600160a01b03928316926320c582be926130ce9291169087908790600401615142565b600060405180830381600087803b1580156130e857600080fd5b505af11580156130fc573d6000803e3d6000fd5b505050505b8015612f29576040516364a197f360e01b81526001600160a01b038516906364a197f3906131359086908590600401615188565b600060405180830381600087803b15801561314f57600080fd5b505af1158015613163573d6000803e3d6000fd5b5050505050505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561319957fe5b14610fdd5760405162461bcd60e51b81526004016109ee90615519565b600061106561324583600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b505afa158015613221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127119190614edc565b670de0b6b3a76400006145ce565b6000612291670de0b6b3a76400006111b7858563ffffffff61275f16565b600080600061327f84611107565b9050600061328c8561160b565b6001600160a01b038616600090815260106020526040812060010154919250906132bc908463ffffffff613b0116565b6001600160a01b038716600090815260106020526040812054919250906132e9908463ffffffff613b0116565b919550909350505050915091565b6000821561331e576000613315846111b7878663ffffffff61275f16565b91506122919050565b506000199392505050565b6000806133346145e4565b9050600061334a670ddd4b8c6c7d70d883614600565b9050611e00670de0b6b3a76400006111b783600e5461275f90919063ffffffff16565b6000613384600f544261254590919063ffffffff16565b9050603c8110610fdd5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc91610f1191615568565b6133ca614b5c565b6133d2614be4565b6133da614b5c565b848252600060808301526133ec611ce8565b60a08301526133f9611ece565b8260c001818152505086608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561343f57600080fd5b505afa158015613453573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134779190614cbb565b82606001906001600160a01b031690816001600160a01b031681525050600087608001516001600160a01b0316631e2231436040518163ffffffff1660e01b815260040160206040518083038186803b1580156134d357600080fd5b505afa1580156134e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350b9190614cbb565b6000602085015290505b84836020015110801561353e5750806001600160a01b031683606001516001600160a01b031614155b1561385e5760808801516060840151604051632dc9c0eb60e21b81526000926001600160a01b03169163b72703ac9161357a919060040161512e565b60206040518083038186803b15801561359257600080fd5b505afa1580156135a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ca9190614cbb565b90506135da846060015189611673565b6040850152608084015161375357600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561363657600080fd5b505afa15801561364a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061366e9190614edc565b84604001511015801561368057508351155b1561368b575061385e565b60006136a08560c001518660a001518b6132f7565b8a5160208c01516060880151604089015189519495506136c194868f613f10565b608081015186519195506136db919063ffffffff61254516565b8552608084015160a08601516136f69163ffffffff61254516565b8560a00181815250506137238461010001516114c38660a001518860c0015161254590919063ffffffff16565b60c086015261373286856142e6565b95506137478560c001518660a001518b6143fd565b15608086015250613840565b836080015180156137ec5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156137ad57600080fd5b505afa1580156137c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e59190614edc565b8460400151105b1561383a5761380d89600001518a602001518660600151876000015161449c565b60808101518551919450613827919063ffffffff61254516565b845261383385846142e6565b9450613840565b5061385e565b6001600160a01b031660608401526020830180516001019052613515565b505050949350505050565b613871614b5c565b613879614be4565b613881614b5c565b600d54858352600060208401526001600160a01b03165b8483602001511015613a1357806001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156138dd57600080fd5b505afa1580156138f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139159190614cbb565b6001600160a01b03166060840181905261392f9088611673565b6040808501919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b15801561397a57600080fd5b505afa15801561398e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b29190614edc565b836040015110156139fe576139d189898560600151866000015161449c565b608081015184519193506139eb919063ffffffff61254516565b83526139f784836142e6565b9350613a03565b613a13565b6020830180516001019052613898565b50505095945050505050565b6000611065613a7683600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b031663240926696040518163ffffffff1660e01b815260040160206040518083038186803b158015613ac457600080fd5b505afa158015613ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613afc9190614edc565b6145ce565b6000828201838110156122915760405162461bcd60e51b81526004016109ee9061522d565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92610f11929091615571565b60008115613baf57613ba8826111b78568056bc75e2d6310000063ffffffff61275f16565b9050611065565b50600019611065565b600080613bc3611ece565b90506000613bcf611ce8565b9050613bdc8282866132f7565b949350505050565b6000816004811115613bf257fe5b14158015613c0c57506001816004811115613c0957fe5b14155b613c1257fe5b601754613c1e816146ab565b6001600160a01b0383166000908152601060205260409020600301805483919060ff19166001836004811115613c5057fe5b02179055506001600160a01b0383166000908152601060209081526040808320600180820185905590849055601690925282208281550155613c928382614751565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e90613cc290869060040161512e565b600060405180830381600087803b158015613cdc57600080fd5b505af1158015613cf0573d6000803e3d6000fd5b50505050505050565b600080613d18670de0b6b3a76400006111b7868663ffffffff61275f16565b90508281106122915760405162461bcd60e51b81526004016109ee90615481565b6001600160a01b038116600090815260106020526040902060020154601154613d68908263ffffffff61254516565b601155506001600160a01b0316600090815260106020526040812060020155565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a90613db5908590600401615568565b600060405180830381600087803b158015613dcf57600080fd5b505af1158015613de3573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150613e13908590600401615568565b600060405180830381600087803b158015613e2d57600080fd5b505af1158015613e41573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150613135908490600401615568565b60008184841115613e955760405162461bcd60e51b81526004016109ee91906151da565b505050900390565b60008060135460001415613eb2575081611065565b600060125411613ebe57fe5b6122916013546111b76012548661275f90919063ffffffff16565b60008183613efa5760405162461bcd60e51b81526004016109ee91906151da565b506000838581613f0657fe5b0495945050505050565b613f18614b5c565b613f20614c2c565b601754600110613f3057506142db565b613f398761212a565b60408501526020848101919091528401819052908352613f58906148f2565b604083018190526801158e460913d0000060608401526020830151613f829163ffffffff61254516565b8152670de0b6b3a7640000861161404d57613fa7898983602001518460400151613d89565b613fb087613d39565b60006080830181905260a0830152815160c0830152805160e0830152613fd7876003613be4565b815160208301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b60405180910390a2866001600160a01b03166000805160206156b28339815191526000806000600260405161404094939291906151ac565b60405180910390a26142d9565b670de0b6b3a7640000861180156140e85750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156140ad57600080fd5b505afa1580156140c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e59190614edc565b86105b1561413857614101898983602001518460400151613d89565b61410a87613d39565b8151815161411991908761497e565b60e086015260c085015260a08401526080830152613fd7876003613be4565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561418657600080fd5b505afa15801561419a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141be9190614edc565b86101580156141cc57508386105b80156141d9575081518510155b156142c8576141f2898983602001518460400151613d89565b846141f957fe5b61420287613d39565b61421582600001518360200151856149ea565b9150614222876003613be4565b6101008201511561429757600854610100830151604051633f10abab60e01b81526001600160a01b0390921691633f10abab91614264918b9190600401615188565b600060405180830381600087803b15801561427e57600080fd5b505af1158015614292573d6000803e3d6000fd5b505050505b815160a08301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b6142d0614b5c565b91506142db9050565b505b979650505050505050565b6142ee614b5c565b604080830151908401516143079163ffffffff613b0116565b6040820152606080830151908401516143259163ffffffff613b0116565b6060820152815160208401516143409163ffffffff613b0116565b602080830191909152820151835161435d9163ffffffff613b0116565b8152608080830151908401516143789163ffffffff613b0116565b608082015260a080830151908401516143969163ffffffff613b0116565b60a082015260c080830151908401516143b49163ffffffff613b0116565b60c082015260e080830151908401516143d29163ffffffff613b0116565b60e082015261010080830151908401516143f19163ffffffff613b0116565b61010082015292915050565b60008061440b8585856132f7565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561445b57600080fd5b505afa15801561446f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144939190614edc565b11949350505050565b6144a4614b5c565b6144ac614c2c565b6144b58461212a565b604085019081526020858101928352860192909252918452905190516144df918891889190613d89565b6144e884613d39565b6144f582602001516148f2565b604083018190526801158e460913d0000060608401526020830151600091614523919063ffffffff61254516565b90506145348360000151828661497e565b60e087015260c086015260a08501526080840152614553856003613be4565b825160208401516040516001600160a01b03881692600080516020615692833981519152926145849260019061557f565b60405180910390a2846001600160a01b03166000805160206156b2833981519152600080600060016040516145bc94939291906151ac565b60405180910390a25050949350505050565b60008183106145dd5781612291565b5090919050565b6000611575603c6111b7600f544261254590919063ffffffff16565b6000631f54050082111561461657631f54050091505b8161462a5750670de0b6b3a7640000611065565b670de0b6b3a764000083835b60018111156146a1576002810661466b576146518283614af8565b915061466481600263ffffffff61279916565b905061469c565b6146758284614af8565b92506146818283614af8565b915061469960026111b783600163ffffffff61254516565b90505b614636565b6111c38284614af8565b6001811180156147355750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b1580156146fb57600080fd5b505afa15801561470f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147339190614edc565b115b610fdd5760405162461bcd60e51b81526004016109ee906152dd565b6001600160a01b03821660009081526010602052604081206003015460ff169081600481111561477d57fe5b141580156147975750600181600481111561479457fe5b14155b61479d57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b03169083906147d5826001612545565b905080836001600160801b031611156147ea57fe5b6000601782815481106147f957fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b03871690811061482b57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a906148b49083908790615166565b60405180910390a160178054806148c757fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b600354604080516324386ecd60e11b815290516000926001600160a01b031691634870dd9a916004808301926020929190829003018186803b15801561493757600080fd5b505afa15801561494b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496f9190614edc565b828161497757fe5b0492915050565b600080808084156149d45761499387866145ce565b93506149a9876111b7888763ffffffff61275f16565b92506149bb878563ffffffff61254516565b91506149cd868463ffffffff61254516565b90506149e1565b5060009250829150859050845b93509350935093565b6149f2614b5c565b838152602080820184905260035460408051631e5395c960e21b81529051600093614a8e9387936111b7936001600160a01b039092169263794e572492600480840193829003018186803b158015614a4957600080fd5b505afa158015614a5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a819190614edc565b889063ffffffff61275f16565b9050614a99816148f2565b604083018190526801158e460913d00000606084015260808301869052614ac790829063ffffffff61254516565b60a0830152614adc848263ffffffff61254516565b61010083015250600060c0820181905260e08201529392505050565b600080614b0b848463ffffffff61275f16565b9050613bdc670de0b6b3a76400006111b7836706f05b59d3b20000613b01565b6040518060a00160405280600081526020016000815260200160001515815260200160008152602001600081525090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040518060e0016040528060008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b80356110658161567c565b60008083601f840112614c69578081fd5b50813567ffffffffffffffff811115614c80578182fd5b602083019150836020828501011115614c9857600080fd5b9250929050565b600060208284031215614cb0578081fd5b81356122918161567c565b600060208284031215614ccc578081fd5b81516122918161567c565b60008060408385031215614ce9578081fd5b8235614cf48161567c565b946020939093013593505050565b60006020808385031215614d14578182fd5b823567ffffffffffffffff811115614d2a578283fd5b80840185601f820112614d3b578384fd5b80359150614d50614d4b83615651565b61562a565b8281528381019082850185850284018601891015614d6c578687fd5b8693505b848410156142d957614d828982614c4d565b835260019390930192918501918501614d70565b60006101c0808385031215614da9578182fd5b614db28161562a565b614dbc8585614c4d565b8152614dcb8560208601614c4d565b6020820152614ddd8560408601614c4d565b6040820152614def8560608601614c4d565b6060820152614e018560808601614c4d565b6080820152614e138560a08601614c4d565b60a0820152614e258560c08601614c4d565b60c0820152614e378560e08601614c4d565b60e08201526101009150614e4d85838601614c4d565b828201526101209150614e6285838601614c4d565b828201526101409150614e7785838601614c4d565b828201526101609150614e8c85838601614c4d565b828201526101809150614ea185838601614c4d565b828201526101a09150614eb685838601614c4d565b918101919091529392505050565b600060208284031215614ed5578081fd5b5035919050565b600060208284031215614eed578081fd5b5051919050565b600080600080600080600060e0888a031215614f0e578283fd5b873596506020880135614f208161567c565b95506040880135614f308161567c565b94506060880135614f408161567c565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a03610160811215614f7e578182fd5b8935985060208a0135614f908161567c565b975060408a0135614fa08161567c565b965060608a0135614fb08161567c565b955060808a810135955060a08b0135945060c08b0135935060df1982011215614fd7578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c0361018081121561500b578485fd5b8b359a5060208c013561501d8161567c565b995060408c013561502d8161567c565b985060608c013561503d8161567c565b975060808c810135975060a08d0135965060c08d0135955060df19820190811215615066578384fd5b615070606061562a565b9150604081121561507f578384fd5b5061508a604061562a565b60e08d01356150988161567c565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff8111156150dd578283fd5b6150e98d828e01614c58565b8194508093505050509295989b9194979a5092959850565b6000828483379101908152919050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b848152602081018490526040810183905260808101600483106151cb57fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015615206578581018301518582016040015282016151ea565b818111156152175783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252603b908201527f54726f76654d616e616765723a2043616c6c6572206973206e6f74207468652060408201527f426f72726f7765724f7065726174696f6e7320636f6e74726163740000000000606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2043616c6c646174612061646472657373206160408201527572726179206d757374206e6f7420626520656d70747960501b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526022908201527f54726f76654d616e616765723a206e6f7468696e6720746f206c697175696461604082015261746560f01b606082015260800190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b90815260200190565b918252602082015260400190565b838152602081018390526060810161559683615671565b6040830152949350505050565b858152602081018590526040810184905260a08101600584106155c257fe5b60608201939093526001600160801b03919091166080909101529392505050565b84815260208101849052604081018390526080810161560183615671565b606083015295945050505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff8111828210171561564957600080fd5b604052919050565b600067ffffffffffffffff821115615667578081fd5b5060209081020190565b80600481106110cb57fe5b6001600160a01b0381168114610fdd57600080fdfeea67486ed7ebe3eea8ab3390efd4a3c8aae48be5bea27df104a8af786c408434c3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba2646970667358221220a4c2a9a9ec603c1ba14143d02dd4e890d8f91d610315ce69bf8078c0892e8c2464736f6c634300060b0033", + "devdoc": { + "kind": "dev", + "methods": { + "applyPendingRewards(address)": { + "params": { + "_borrower": "borrower address" + } + }, + "closeTrove(address)": { + "params": { + "_borrower": "borrower address" + } + }, + "constructor": { + "params": { + "_bootstrapPeriod": "During bootsrap period redemptions are not allowed" + } + }, + "decreaseTroveColl(address,uint256)": { + "params": { + "_borrower": "borrower address", + "_collDecrease": "amount of collateral to decrease" + }, + "returns": { + "_0": "new trove collateral" + } + }, + "decreaseTroveDebt(address,uint256)": { + "params": { + "_borrower": "borrower address", + "_debtDecrease": "amount of debt to decrease" + }, + "returns": { + "_0": "new trove debt" + } + }, + "getBorrowingFeeWithDecay(uint256)": { + "params": { + "_ZUSDDebt": "ZUSD debt amount to calculate fee" + }, + "returns": { + "_0": "borrowing fee using borrowing rate with decay" + } + }, + "getBorrowingRate()": { + "returns": { + "_0": "borrowing rate" + } + }, + "getBorrowingRateWithDecay()": { + "returns": { + "_0": "borrowing rate calculated using decayed as base rate" + } + }, + "getCurrentICR(address,uint256)": { + "params": { + "_borrower": "borrower address", + "_price": "ETH price" + }, + "returns": { + "_0": "the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account." + } + }, + "getNominalICR(address)": { + "returns": { + "_0": "the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account." + } + }, + "getOwner()": { + "returns": { + "_owner": "Address of the owner. " + } + }, + "getPendingETHReward(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "the borrower's pending accumulated ETH reward, earned by their stake" + } + }, + "getPendingZUSDDebtReward(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "the borrower's pending accumulated ZUSD reward, earned by their stake" + } + }, + "getRedemptionFeeWithDecay(uint256)": { + "params": { + "_ETHDrawn": "ETH drawn" + } + }, + "getRedemptionRate()": { + "returns": { + "_0": "calculated redemption rate using baseRate" + } + }, + "getRedemptionRateWithDecay()": { + "returns": { + "_0": "calculated redemption rate using calculated decayed as base rate" + } + }, + "getTCR(uint256)": { + "params": { + "_price": "ETH price" + }, + "returns": { + "_0": "the total collateralization ratio (TCR) of the system. The TCR is based on the the entire system debt and collateral (including pending rewards)." + } + }, + "getTroveColl(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "Trove collateral from given trove" + } + }, + "getTroveDebt(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "Trove debt from given trove" + } + }, + "getTroveFromTroveOwnersArray(uint256)": { + "params": { + "_index": "Trove owner index" + }, + "returns": { + "_0": "Trove from TroveOwners array in given index" + } + }, + "getTroveOwnersCount()": { + "returns": { + "_0": "Trove owners count" + } + }, + "getTroveStake(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "Trove stake from given trove" + } + }, + "getTroveStatus(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "Trove status from given trove" + } + }, + "increaseTroveColl(address,uint256)": { + "params": { + "_borrower": "borrower address", + "_collIncrease": "amount of collateral to increase" + }, + "returns": { + "_0": "new trove collateral" + } + }, + "increaseTroveDebt(address,uint256)": { + "params": { + "_borrower": "borrower address", + "_debtIncrease": "amount of debt to increase" + }, + "returns": { + "_0": "new trove debt" + } + }, + "redeemCollateral(uint256,address,address,address,uint256,uint256,uint256)": { + "details": "this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed" + }, + "redeemCollateralViaDLLR(uint256,address,address,address,uint256,uint256,uint256,(uint256,uint8,bytes32,bytes32))": { + "details": "this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction" + }, + "redeemCollateralViaDllrWithPermit2(uint256,address,address,address,uint256,uint256,uint256,((address,uint256),uint256,uint256),bytes)": { + "details": "this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction" + }, + "removeStake(address)": { + "params": { + "_borrower": "borrower address" + } + }, + "setOwner(address)": { + "params": { + "_owner": "Address of the owner. " + } + }, + "updateStakeAndTotalStakes(address)": { + "params": { + "_borrower": "borrower address" + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "BETA()": { + "notice": "BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption. Corresponds to (1 / ALPHA) in the white paper." + }, + "BOOTSTRAP_PERIOD()": { + "notice": "During bootsrap period redemptions are not allowed" + }, + "MIN_NET_DEBT()": { + "notice": "Minimum amount of net ZUSD debt a trove must have" + }, + "ZUSD_GAS_COMPENSATION()": { + "notice": "Amount of ZUSD to be locked in gas pool on opening troves" + }, + "_getCurrentICR(address,uint256)": { + "notice": "Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account." + }, + "_getPendingETHReward(address)": { + "notice": "Get the borrower's pending accumulated ETH reward, earned by their stake" + }, + "_getPendingZUSDDebtReward(address)": { + "notice": "Get the borrower's pending accumulated ZUSD reward, earned by their stake" + }, + "addTroveOwnerToArray(address)": { + "notice": "Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct" + }, + "applyPendingRewards(address)": { + "notice": "Add the borrowers's coll and debt rewards earned from redistributions, to their Trove" + }, + "batchLiquidateTroves(address[])": { + "notice": "Attempt to liquidate a custom list of troves provided by the caller." + }, + "checkRecoveryMode(uint256)": { + "notice": "reveals whether or not the system is in Recovery Mode (i.e. whether the Total Collateralization Ratio (TCR) is below the Critical Collateralization Ratio (CCR))." + }, + "closeTrove(address)": { + "notice": "Close given trove. Called by BorrowerOperations." + }, + "decayBaseRateFromBorrowing()": { + "notice": "Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation." + }, + "getCurrentICR(address,uint256)": { + "notice": "computes the user’s individual collateralization ratio (ICR) based on their total collateral and total ZUSD debt. Returns 2^256 -1 if they have 0 debt." + }, + "getEntireDebtAndColl(address)": { + "notice": "Return the Troves entire debt and coll, including pending rewards from redistributions." + }, + "getOwner()": { + "notice": "Return address of the owner." + }, + "getRedemptionFeeWithDecay(uint256)": { + "notice": "The redemption fee is taken as a cut of the total ETH drawn from the system in a redemption. It is based on the current redemption rate." + }, + "liquidate(address)": { + "notice": "Single liquidation function. Closes the trove if its ICR is lower than the minimum collateral ratio." + }, + "liquidateTroves(uint256)": { + "notice": "Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves, starting from the one with the lowest collateral ratio in the system, and moving upwards" + }, + "permit2()": { + "notice": "CONSTANT / IMMUTABLE VARIABLE ONLY " + }, + "removeStake(address)": { + "notice": "Remove borrower's stake from the totalStakes sum, and set their stake to 0" + }, + "setOwner(address)": { + "notice": "Set address of the owner (only owner can call this function)" + }, + "updateStakeAndTotalStakes(address)": { + "notice": "Update borrower's stake based on their latest collateral value" + }, + "updateTroveRewardSnapshots(address)": { + "notice": "Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 5495, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "activePool", + "offset": 0, + "slot": "0", + "type": "t_contract(IActivePool)19557" + }, + { + "astId": 5497, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "defaultPool", + "offset": 0, + "slot": "1", + "type": "t_contract(IDefaultPool)20229" + }, + { + "astId": 5500, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "priceFeed", + "offset": 0, + "slot": "2", + "type": "t_contract(IPriceFeed)20458" + }, + { + "astId": 5503, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "liquityBaseParams", + "offset": 0, + "slot": "3", + "type": "t_contract(ILiquityBaseParams)20379" + }, + { + "astId": 35227, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "troveManagerRedeemOps", + "offset": 0, + "slot": "4", + "type": "t_address" + }, + { + "astId": 35229, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "borrowerOperationsAddress", + "offset": 0, + "slot": "5", + "type": "t_address" + }, + { + "astId": 35231, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "_stabilityPool", + "offset": 0, + "slot": "6", + "type": "t_contract(IStabilityPool)21101" + }, + { + "astId": 35233, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "gasPoolAddress", + "offset": 0, + "slot": "7", + "type": "t_address" + }, + { + "astId": 35235, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "collSurplusPool", + "offset": 0, + "slot": "8", + "type": "t_contract(ICollSurplusPool)20130" + }, + { + "astId": 35237, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "_zusdToken", + "offset": 0, + "slot": "9", + "type": "t_contract(IZUSDToken)21842" + }, + { + "astId": 35239, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "_zeroToken", + "offset": 0, + "slot": "10", + "type": "t_contract(IZEROToken)21783" + }, + { + "astId": 35241, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "_zeroStaking", + "offset": 0, + "slot": "11", + "type": "t_contract(IZEROStaking)21760" + }, + { + "astId": 35243, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "feeDistributor", + "offset": 0, + "slot": "12", + "type": "t_contract(IFeeDistributor)20298" + }, + { + "astId": 35245, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "sortedTroves", + "offset": 0, + "slot": "13", + "type": "t_contract(ISortedTroves)20817" + }, + { + "astId": 35247, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "baseRate", + "offset": 0, + "slot": "14", + "type": "t_uint256" + }, + { + "astId": 35249, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "lastFeeOperationTime", + "offset": 0, + "slot": "15", + "type": "t_uint256" + }, + { + "astId": 35270, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "Troves", + "offset": 0, + "slot": "16", + "type": "t_mapping(t_address,t_struct(Trove)35266_storage)" + }, + { + "astId": 35272, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "totalStakes", + "offset": 0, + "slot": "17", + "type": "t_uint256" + }, + { + "astId": 35274, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "totalStakesSnapshot", + "offset": 0, + "slot": "18", + "type": "t_uint256" + }, + { + "astId": 35276, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "totalCollateralSnapshot", + "offset": 0, + "slot": "19", + "type": "t_uint256" + }, + { + "astId": 35278, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "L_ETH", + "offset": 0, + "slot": "20", + "type": "t_uint256" + }, + { + "astId": 35280, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "L_ZUSDDebt", + "offset": 0, + "slot": "21", + "type": "t_uint256" + }, + { + "astId": 35284, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "rewardSnapshots", + "offset": 0, + "slot": "22", + "type": "t_mapping(t_address,t_struct(RewardSnapshot)35289_storage)" + }, + { + "astId": 35292, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "TroveOwners", + "offset": 0, + "slot": "23", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 35294, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "lastETHError_Redistribution", + "offset": 0, + "slot": "24", + "type": "t_uint256" + }, + { + "astId": 35296, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "lastZUSDDebtError_Redistribution", + "offset": 0, + "slot": "25", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_contract(IActivePool)19557": { + "encoding": "inplace", + "label": "contract IActivePool", + "numberOfBytes": "20" + }, + "t_contract(ICollSurplusPool)20130": { + "encoding": "inplace", + "label": "contract ICollSurplusPool", + "numberOfBytes": "20" + }, + "t_contract(IDefaultPool)20229": { + "encoding": "inplace", + "label": "contract IDefaultPool", + "numberOfBytes": "20" + }, + "t_contract(IFeeDistributor)20298": { + "encoding": "inplace", + "label": "contract IFeeDistributor", + "numberOfBytes": "20" + }, + "t_contract(ILiquityBaseParams)20379": { + "encoding": "inplace", + "label": "contract ILiquityBaseParams", + "numberOfBytes": "20" + }, + "t_contract(IPriceFeed)20458": { + "encoding": "inplace", + "label": "contract IPriceFeed", + "numberOfBytes": "20" + }, + "t_contract(ISortedTroves)20817": { + "encoding": "inplace", + "label": "contract ISortedTroves", + "numberOfBytes": "20" + }, + "t_contract(IStabilityPool)21101": { + "encoding": "inplace", + "label": "contract IStabilityPool", + "numberOfBytes": "20" + }, + "t_contract(IZEROStaking)21760": { + "encoding": "inplace", + "label": "contract IZEROStaking", + "numberOfBytes": "20" + }, + "t_contract(IZEROToken)21783": { + "encoding": "inplace", + "label": "contract IZEROToken", + "numberOfBytes": "20" + }, + "t_contract(IZUSDToken)21842": { + "encoding": "inplace", + "label": "contract IZUSDToken", + "numberOfBytes": "20" + }, + "t_enum(Status)35255": { + "encoding": "inplace", + "label": "enum TroveManagerStorage.Status", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_struct(RewardSnapshot)35289_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct TroveManagerStorage.RewardSnapshot)", + "numberOfBytes": "32", + "value": "t_struct(RewardSnapshot)35289_storage" + }, + "t_mapping(t_address,t_struct(Trove)35266_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct TroveManagerStorage.Trove)", + "numberOfBytes": "32", + "value": "t_struct(Trove)35266_storage" + }, + "t_struct(RewardSnapshot)35289_storage": { + "encoding": "inplace", + "label": "struct TroveManagerStorage.RewardSnapshot", + "members": [ + { + "astId": 35286, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "ETH", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 35288, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "ZUSDDebt", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Trove)35266_storage": { + "encoding": "inplace", + "label": "struct TroveManagerStorage.Trove", + "members": [ + { + "astId": 35257, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "debt", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 35259, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "coll", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 35261, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "stake", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 35263, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "status", + "offset": 0, + "slot": "3", + "type": "t_enum(Status)35255" + }, + { + "astId": 35265, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "arrayIndex", + "offset": 1, + "slot": "3", + "type": "t_uint128" + } + ], + "numberOfBytes": "128" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/external/deployments/rskMainnet/TroveManager_Proxy.json b/external/deployments/rskMainnet/TroveManager_Proxy.json new file mode 100644 index 000000000..6993e65ef --- /dev/null +++ b/external/deployments/rskMainnet/TroveManager_Proxy.json @@ -0,0 +1,110 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "UpgradableProxy", + "sourceName": "contracts/Proxy/UpgradableProxy.sol", + "address": "0x82B09695ee4F214f3A0803683C4AaEc332E4E0a3", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_oldImplementation", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_newImplementation", + "type": "address" + } + ], + "name": "ImplementationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610023336001600160e01b0361002816565b610110565b6001600160a01b03811661006d5760405162461bcd60e51b81526004018080602001828103825260228152602001806105e26022913960400191505060405180910390fd5b6001600160a01b0381166100886001600160e01b036100e616565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b6104c38061011f6000396000f3fe6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b00334f776e61626c653a3a7365744f776e65723a20696e76616c69642061646472657373", + "deployedBytecode": "0x6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/external/deployments/rskTestnet/BorrowerOperations.json b/external/deployments/rskTestnet/BorrowerOperations.json new file mode 100644 index 000000000..fbe931864 --- /dev/null +++ b/external/deployments/rskTestnet/BorrowerOperations.json @@ -0,0 +1,1391 @@ +{ + "address": "0xba8d7B80bcb3A01A5e713c356fD18EeD299B70D0", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_oldImplementation", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_newImplementation", + "type": "address" + } + ], + "name": "ImplementationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + } + ], + "name": "CollSurplusPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + } + ], + "name": "FeeDistributorAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + } + ], + "name": "GasPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_massetManagerAddress", + "type": "address" + } + ], + "name": "MassetManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + } + ], + "name": "StabilityPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "arrayIndex", + "type": "uint256" + } + ], + "name": "TroveCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newTroveManagerAddress", + "type": "address" + } + ], + "name": "TroveManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum BorrowerOperations.BorrowerOperation", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "ZEROStakingAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDFee", + "type": "uint256" + } + ], + "name": "ZUSDBorrowingFeePaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "BORROWING_FEE_FLOOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "addColl", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "adjustNueTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "adjustNueTroveWithPermit2", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "adjustTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "claimCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "closeNueTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "closeNueTroveWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "closeTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeDistributor", + "outputs": [ + { + "internalType": "contract IFeeDistributor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + } + ], + "name": "getCompositeDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMassetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "massetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "moveETHGainToTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "openNueTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "openTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "repayZUSD", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "repayZusdFromDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "repayZusdFromDLLRWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_massetManagerAddress", + "type": "address" + } + ], + "name": "setMassetManagerAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManager", + "outputs": [ + { + "internalType": "contract ITroveManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawColl", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawZUSD", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawZusdAndConvertToDLLR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "zeroStaking", + "outputs": [ + { + "internalType": "contract IZEROStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zeroStakingAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0x330ad35d02b52b6f132C3C31730Dd8F79Cb58b7E", + "transactionIndex": 0, + "gasUsed": "5799498", + "logsBloom": "0x00000800000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000001000000000000000000000000000000000000000", + "blockHash": "0x7de331c1815635488605d3e00b15a43084f7a6002e2ddf43d01f2c61ae10f888", + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748936, + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "address": "0x330ad35d02b52b6f132C3C31730Dd8F79Cb58b7E", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x7de331c1815635488605d3e00b15a43084f7a6002e2ddf43d01f2c61ae10f888" + } + ], + "blockNumber": 4748936, + "cumulativeGasUsed": "5799498", + "status": 1, + "byzantium": true + }, + "numDeployments": 10, + "bytecode": "0x60a06040523480156200001157600080fd5b506040516200556638038062005566833981016040819052620000349162000123565b62000048336001600160e01b036200005e16565b60601b6001600160601b031916608052620001b2565b6001600160a01b038116620000905760405162461bcd60e51b8152600401620000879062000170565b60405180910390fd5b6001600160a01b038116620000ad6001600160e01b036200010216565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f29062000153565b6040519081900390209190915550565b600080604051620001139062000153565b6040519081900390205492915050565b60006020828403121562000135578081fd5b81516001600160a01b03811681146200014c578182fd5b9392505050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160601c61538c620001da600039806106a552806110db5280612327525061538c6000f3fe60806040526004361061025c5760003560e01c80637778a3db11610144578063a20baee6116100b6578063c6a6cf201161007a578063c6a6cf2014610601578063e9fc346114610614578063ea9638bf14610629578063ec5472fd1461063c578063ec9f7d4614610651578063f92d3433146106665761025c565b8063a20baee614610414578063a3f4df7e14610595578063ae918754146105b7578063afbc74b5146105cc578063b5c89bab146105ec5761025c565b8063860665b311610108578063860665b314610510578063887105d314610523578063893d20e814610538578063899fe15e1461054d5780638d5c3dc11461056d5780639f070670146105805761025c565b80637778a3db14610486578063795d26c3146104a65780637d4f595d146104bb5780637e3eefdc146104db5780637f7dde4a146104fb5761025c565b8063485f190f116101dd5780636f0b0c1c116101a15780636f0b0c1c146103ff57806372fe25aa14610414578063734f622d14610429578063741bef1a14610449578063759b30341461045e578063763a0ef3146104735761025c565b8063485f190f146103795780634ff814431461038c5780635530273c146103ac57806368647db1146103cc5780636ea56960146103df5761025c565b80631a777717116102245780631a777717146102ed5780631bf435551461030d5780632771510a1461032f5780633cc742251461034f5780633d83908a146103645761025c565b80630d43e8ad146102615780630e704d501461028c5780630ff9a512146102a357806312261ee7146102b857806313af4035146102cd575b600080fd5b34801561026d57600080fd5b5061027661067b565b604051610283919061485c565b60405180910390f35b34801561029857600080fd5b506102a161068a565b005b3480156102af57600080fd5b50610276610694565b3480156102c457600080fd5b506102766106a3565b3480156102d957600080fd5b506102a16102e83660046142d7565b6106c7565b3480156102f957600080fd5b506102a161030836600461455d565b610714565b34801561031957600080fd5b5061032261072b565b60405161028391906152d8565b34801561033b57600080fd5b506102a161034a3660046142d7565b610738565b34801561035b57600080fd5b506102766107c6565b34801561037057600080fd5b506102766107d5565b6102a1610387366004614631565b6107e4565b34801561039857600080fd5b506103226103a7366004614507565b61094e565b3480156103b857600080fd5b506102a16103c7366004614537565b610961565b6102a16103da36600461430f565b610977565b3480156103eb57600080fd5b506102a16103fa366004614631565b61098d565b34801561040b57600080fd5b506102a161099e565b34801561042057600080fd5b506103226109fc565b34801561043557600080fd5b506102a1610444366004614391565b610a08565b34801561045557600080fd5b50610276610dcc565b34801561046a57600080fd5b50610322610ddb565b6102a1610481366004614758565b610de8565b34801561049257600080fd5b506102a16104a136600461449a565b610e04565b3480156104b257600080fd5b50610322610ef5565b3480156104c757600080fd5b506102a16104d63660046144b5565b611014565b3480156104e757600080fd5b506103226104f6366004614631565b61110a565b34801561050757600080fd5b50610276611385565b6102a161051e366004614631565b611394565b34801561052f57600080fd5b506103226113a1565b34801561054457600080fd5b50610276611470565b34801561055957600080fd5b506102a16105683660046145ae565b61148f565b6102a161057b3660046146e0565b6114aa565b34801561058c57600080fd5b506102766114c2565b3480156105a157600080fd5b506105aa6114d1565b6040516102839190614944565b3480156105c357600080fd5b506102766114ff565b3480156105d857600080fd5b506102a16105e7366004614537565b61150e565b3480156105f857600080fd5b50610276611520565b6102a161060f36600461467a565b61152f565b34801561062057600080fd5b5061027661153e565b6102a1610637366004614347565b61154d565b34801561064857600080fd5b50610276611567565b34801561065d57600080fd5b50610276611576565b34801561067257600080fd5b50610322611585565b600d546001600160a01b031681565b610692611607565b565b6009546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6106cf611470565b6001600160a01b0316336001600160a01b0316146107085760405162461bcd60e51b81526004016106ff90614e2d565b60405180910390fd5b610711816119f6565b50565b610725600080866000878787611a81565b50505050565b6809c2007651b250000081565b610740611470565b6001600160a01b0316336001600160a01b0316146107705760405162461bcd60e51b81526004016106ff90614e2d565b600c80546001600160a01b0319166001600160a01b0383161790556040517f6926b3375b54960080b7d8a184061f39a02e8c3bf64aa9df7e75359fdc00d814906107bb90839061485c565b60405180910390a150565b6001546001600160a01b031681565b6004546001600160a01b031681565b600c546001600160a01b031661080c5760405162461bcd60e51b81526004016106ff90615237565b6108198484848430611c37565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b39261084f9291169087906004016148b1565b602060405180830381600087803b15801561086957600080fd5b505af115801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a1919061447e565b6108bd5760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b926108f592911690879033906004016148f5565b602060405180830381600087803b15801561090f57600080fd5b505af1158015610923573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610947919061451f565b5050505050565b600061095982612262565b90505b919050565b61097233846000808686600061227d565b505050565b6109893360008060008686600061227d565b5050565b61072533600085600186868a61227d565b60075460405163b32beb5b60e01b81526001600160a01b039091169063b32beb5b906109ce90339060040161485c565b600060405180830381600087803b1580156109e857600080fd5b505af1158015610725573d6000803e3d6000fd5b670de0b6b3a764000081565b610a10611470565b6001600160a01b0316336001600160a01b031614610a405760405162461bcd60e51b81526004016106ff90614e2d565b610a498c61228d565b610a528b61228d565b610a5b8a61228d565b610a648961228d565b610a6d8861228d565b610a768761228d565b610a7f8661228d565b610a888561228d565b610a918461228d565b610a9a8361228d565b610aa38261228d565b610aac8161228d565b600d80546001600160a01b03199081166001600160a01b038f8116919091179092556003805482168e84161790556004805482168d84161790556000805482168c84161790556001805482168b84161790556005805482168a8416179055600680548216898416179055600780548216888416179055600280548216878416179055600b80548216868416179055600a8054821685841617905560098054821692841692831790556008805490911690911790556040517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db990610b90908e9061485c565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a56788a604051610bc7919061485c565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd88289604051610bfe919061485c565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b88604051610c35919061485c565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f87604051610c6c919061485c565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa086604051610ca3919061485c565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d85604051610cda919061485c565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db26484604051610d11919061485c565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe7880083604051610d48919061485c565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d82604051610d7f919061485c565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd81604051610db6919061485c565b60405180910390a1505050505050505050505050565b6002546001600160a01b031681565b6801158e460913d0000081565b610df98989898989898989896122d2565b505050505050505050565b600c546001600160a01b0316610e2c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a255391610e5e9133910161485c565b60206040518083038186803b158015610e7657600080fd5b505afa158015610e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eae919061451f565b600c54909150610eec906001600160a01b0316610eda836801158e460913d0000063ffffffff6124ab16565b600a546001600160a01b0316856124f6565b50610989611607565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f71919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b505afa158015610fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffb919061451f565b905061100d828263ffffffff6127a716565b9250505090565b600c546001600160a01b031661103c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a25539161106e9133910161485c565b60206040518083038186803b15801561108657600080fd5b505afa15801561109a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110be919061451f565b600c54600a54919250611101916001600160a01b039182169116867f000000000000000000000000000000000000000000000000000000000000000087876127cc565b50610725611607565b600a546040516370a0823160e01b8152600091309183916001600160a01b0316906370a082319061113f90859060040161485c565b60206040518083038186803b15801561115757600080fd5b505afa15801561116b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118f919061451f565b905061119f33838888888c612a19565b6111af818763ffffffff6127a716565b600a546040516370a0823160e01b81526001600160a01b03909116906370a08231906111df90869060040161485c565b60206040518083038186803b1580156111f757600080fd5b505afa15801561120b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122f919061451f565b1461124c5760405162461bcd60e51b81526004016106ff90614ac1565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611282929116908a906004016148b1565b602060405180830381600087803b15801561129c57600080fd5b505af11580156112b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d4919061447e565b6112f05760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611328929116908a9033906004016148f5565b602060405180830381600087803b15801561134257600080fd5b505af1158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a919061451f565b979650505050505050565b6000546001600160a01b031681565b6107258484848433611c37565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b60008060405161147f9061483f565b6040519081900390205492915050565b6114a260008088600089898989896122d2565b505050505050565b6114b987878787878787611a81565b50505050505050565b6003546001600160a01b031681565b60405180604001604052806012815260200171426f72726f7765724f7065726174696f6e7360701b81525081565b600b546001600160a01b031681565b6109723360008560008686600061227d565b600c546001600160a01b031681565b6114a23386868686868c61227d565b600c546001600160a01b031690565b611555612a2b565b6109728360008060008686600061227d565b6008546001600160a01b031681565b600a546001600160a01b031681565b6003546040805163f92d343360e01b815290516000926001600160a01b03169163f92d3433916004808301926020929190829003018186803b1580156115ca57600080fd5b505afa1580156115de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611602919061451f565b905090565b600454600054600a546001600160a01b0392831692918216911661162b8333612a55565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561167157600080fd5b505af1158015611685573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a9919061451f565b90506116b481612af6565b604051630b07655760e01b81526001600160a01b03851690630b076557906116e090339060040161485c565b600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50506040516309019aaf60e31b8152600092506001600160a01b038716915063480cd5789061174190339060040161485c565b60206040518083038186803b15801561175957600080fd5b505afa15801561176d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611791919061451f565b90506000856001600160a01b031663d66a2553336040518263ffffffff1660e01b81526004016117c1919061485c565b60206040518083038186803b1580156117d957600080fd5b505afa1580156117ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611811919061451f565b90506118368433611831846801158e460913d0000063ffffffff6124ab16565b612b1c565b600061184783600084600088612bb8565b905061185281612c43565b604051631fc5750960e31b81526001600160a01b0388169063fe2ba8489061187e90339060040161485c565b600060405180830381600087803b15801561189857600080fd5b505af11580156118ac573d6000803e3d6000fd5b50506040516365e89c5760e11b81526001600160a01b038a16925063cbd138ae91506118dc90339060040161485c565b600060405180830381600087803b1580156118f657600080fd5b505af115801561190a573d6000803e3d6000fd5b50505050336001600160a01b03166000805160206153378339815191526000806000600160405161193e9493929190614918565b60405180910390a261196a868633611965866801158e460913d0000063ffffffff6124ab16565b612ce8565b60065461198d90879087906001600160a01b03166801158e460913d00000612ce8565b6040516364a197f360e01b81526001600160a01b038716906364a197f3906119bb90339087906004016148b1565b600060405180830381600087803b1580156119d557600080fd5b505af11580156119e9573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038116611a1c5760405162461bcd60e51b81526004016106ff90614af8565b806001600160a01b0316611a2e611470565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611a719061483f565b6040519081900390209190915550565b600c546001600160a01b0316611aa95760405162461bcd60e51b81526004016106ff90615237565b83158015611ab75750600085115b15611add57600c54600a54611adb916001600160a01b0390811691889116846124f6565b505b611aed3387878787878d30612da2565b838015611afa5750600085115b156114b957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611b359291169089906004016148b1565b602060405180830381600087803b158015611b4f57600080fd5b505af1158015611b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b87919061447e565b611ba35760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611bdb92911690899033906004016148f5565b602060405180830381600087803b158015611bf557600080fd5b505af1158015611c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2d919061451f565b5050505050505050565b611c3f614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152611c77614131565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611cc757600080fd5b505af1158015611cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cff919061451f565b808252600090611d0e9061337a565b9050611d1a8882613415565b8251611d269033613501565b6040820187905280611d6757611d4683600001518460400151898b6135a3565b602083018190526040830151611d619163ffffffff6127a716565b60408301525b611d74826040015161375c565b611d818260400151612262565b60608301819052611d8e57fe5b611da13483606001518460000151613785565b60808301526060820151611db69034906137c4565b60a08301528015611dd357611dce82608001516137f9565b611e06565b611de0826080015161389e565b6000611df9346001856060015160018760000151612bb8565b9050611e0481612c43565b505b8251604051635d6b480f60e01b81526001600160a01b0390911690635d6b480f90611e389033906001906004016148b1565b600060405180830381600087803b158015611e5257600080fd5b505af1158015611e66573d6000803e3d6000fd5b505084516040516372423c1760e01b81526001600160a01b0390911692506372423c179150611e9b90339034906004016148b1565b602060405180830381600087803b158015611eb557600080fd5b505af1158015611ec9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eed919061451f565b5082516060830151604051639976cf4560e01b81526001600160a01b0390921691639976cf4591611f23913391906004016148b1565b602060405180830381600087803b158015611f3d57600080fd5b505af1158015611f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f75919061451f565b5082516040516382fe3eb960e01b81526001600160a01b03909116906382fe3eb990611fa590339060040161485c565b600060405180830381600087803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b50508451604051630c7940bd60e11b81526001600160a01b0390911692506318f2817a915061200690339060040161485c565b602060405180830381600087803b15801561202057600080fd5b505af1158015612034573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612058919061451f565b60c0830152600b5460a08301516040516346f7cf8760e01b81526001600160a01b03909216916346f7cf8791612097913391908b908b906004016148ca565b600060405180830381600087803b1580156120b157600080fd5b505af11580156120c5573d6000803e3d6000fd5b505084516040516315d549f160e01b81526001600160a01b0390911692506315d549f191506120f890339060040161485c565b602060405180830381600087803b15801561211257600080fd5b505af1158015612126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214a919061451f565b60e0830181905260405133917f59cfd0cd754bc5748b6770e94a4ffa5f678d885cb899dcfadc5734edb97c67ab9161218291906152d8565b60405180910390a2612198836020015134613943565b6121b183602001518460400151868a86604001516139bf565b602083015160408401516006546121dd9291906001600160a01b03166801158e460913d00000806139bf565b606082015160c083015160405133926000805160206153378339815191529261220b92349190600090614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc0022741836020015160405161225091906152d8565b60405180910390a25050505050505050565b6000610959826801158e460913d0000063ffffffff6127a716565b6114b98787878787878733612da2565b6001600160a01b0381166122b35760405162461bcd60e51b81526004016106ff90614c3a565b803b806109895760405162461bcd60e51b81526004016106ff90614fde565b600c546001600160a01b03166122fa5760405162461bcd60e51b81526004016106ff90615237565b851580156123085750600087115b1561234f57600c54600a5461234d916001600160a01b039081169116857f000000000000000000000000000000000000000000000000000000000000000086866127cc565b505b61235f3389898989898f30612da2565b85801561236c5750600087115b15610df957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b3926123a7929116908b906004016148b1565b602060405180830381600087803b1580156123c157600080fd5b505af11580156123d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f9919061447e565b6124155760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b9261244d929116908b9033906004016148f5565b602060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f919061451f565b50505050505050505050565b60006124ed83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a79565b90505b92915050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561253257600080fd5b505afa158015612546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061256a91906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161259a919061485c565b60206040518083038186803b1580156125b257600080fd5b505afa1580156125c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ea919061451f565b9050306001600160a01b03831663605629d633838a893561261160408c0160208d01614803565b8b604001358c606001356040518863ffffffff1660e01b815260040161263d9796959493929190614870565b600060405180830381600087803b15801561265757600080fd5b505af115801561266b573d6000803e3d6000fd5b50505050866126fc83856001600160a01b03166370a08231856040518263ffffffff1660e01b81526004016126a0919061485c565b60206040518083038186803b1580156126b857600080fd5b505afa1580156126cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f0919061451f565b9063ffffffff6124ab16565b146127195760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c9223906127499089908b9033906004016148f5565b602060405180830381600087803b15801561276357600080fd5b505af1158015612777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279b919061451f565b98975050505050505050565b6000828201838110156124ed5760405162461bcd60e51b81526004016106ff90614a8a565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284091906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612870919061485c565b60206040518083038186803b15801561288857600080fd5b505afa15801561289c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c0919061451f565b87516020015190915030906001600160a01b0388166330f28b7a8a6128e58585613aa5565b338b8b6040518663ffffffff1660e01b8152600401612908959493929190615267565b600060405180830381600087803b15801561292257600080fd5b505af1158015612936573d6000803e3d6000fd5b505050508061296b84866001600160a01b03166370a08231866040518263ffffffff1660e01b81526004016126a0919061485c565b146129885760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c9223906129b8908d90859033906004016148f5565b602060405180830381600087803b1580156129d257600080fd5b505af11580156129e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0a919061451f565b9b9a5050505050505050505050565b6114a28660008660018787878c612da2565b6005546001600160a01b031633146106925760405162461bcd60e51b81526004016106ff9061507c565b6040516321e3780160e01b81526000906001600160a01b038416906321e3780190612a8490859060040161485c565b60206040518083038186803b158015612a9c57600080fd5b505afa158015612ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad4919061451f565b9050806001146109725760405162461bcd60e51b81526004016106ff90614ddf565b612aff8161337a565b156107115760405162461bcd60e51b81526004016106ff90614b8a565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190612b4a90869060040161485c565b60206040518083038186803b158015612b6257600080fd5b505afa158015612b76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9a919061451f565b10156109725760405162461bcd60e51b81526004016106ff90614997565b600080612bc36113a1565b90506000612bcf610ef5565b905086612beb57612be6828963ffffffff6124ab16565b612bfb565b612bfb828963ffffffff6127a716565b915084612c1757612c12818763ffffffff6124ab16565b612c27565b612c27818763ffffffff6127a716565b90506000612c36838387613785565b9998505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9157600080fd5b505afa158015612ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc9919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614d70565b60405163121cbc4d60e11b81526001600160a01b03851690632439789a90612d149084906004016152d8565b600060405180830381600087803b158015612d2e57600080fd5b505af1158015612d42573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b0386169250639dc29fac9150612d7490859085906004016148b1565b600060405180830381600087803b158015612d8e57600080fd5b505af1158015611c2d573d6000803e3d6000fd5b612daa614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152612de2614176565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e3257600080fd5b505af1158015612e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6a919061451f565b808252612e769061337a565b15156101c08201528615612e9c57612e9384826101c00151613415565b612e9c88613ad7565b612ea589613af7565b612eaf8989613b1e565b8151612ebb908b612a55565b336001600160a01b038b161480612ef157506005546001600160a01b031633148015612ee75750600034115b8015612ef1575087155b612ef757fe5b8151604051630b07655760e01b81526001600160a01b0390911690630b07655790612f26908d9060040161485c565b600060405180830381600087803b158015612f4057600080fd5b505af1158015612f54573d6000803e3d6000fd5b50505050612f62348a613b51565b15156060830152602082015260408101889052868015612f855750806101c00151155b15612fc057612f9e826000015183604001518a876135a3565b61012082018190526040820151612fba9163ffffffff6127a716565b60408201525b815160405163d66a255360e01b81526001600160a01b039091169063d66a255390612fef908d9060040161485c565b60206040518083038186803b15801561300757600080fd5b505afa15801561301b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303f919061451f565b608082015281516040516309019aaf60e31b81526001600160a01b039091169063480cd57890613073908d9060040161485c565b60206040518083038186803b15801561308b57600080fd5b505afa15801561309f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c3919061451f565b60a08201819052608082015182516130dc929190613785565b8160c001818152505061310c8160a0015182608001518360200151846060015185604001518c8760000151613b70565b60e082015260a081015189111561311f57fe5b613130816101c001518a8984613b94565b8615801561313e5750600088115b156131855761316061315b82604001516126f08460800151613c08565b61375c565b61317281608001518260400151613c23565b61318582604001518b8360400151612b1c565b6131a382600001518b8360200151846060015185604001518c613c5b565b6101408301526101608201528151604051630c7940bd60e11b81526001600160a01b03909116906318f2817a906131de908d9060040161485c565b602060405180830381600087803b1580156131f857600080fd5b505af115801561320c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613230919061451f565b8161018001818152505061325c8160a0015182608001518360200151846060015185604001518c613e89565b6101a08201819052600b5460405163015f109360e51b81526001600160a01b0390911691632be2126091613298918e918b908b906004016148ca565b600060405180830381600087803b1580156132b257600080fd5b505af11580156132c6573d6000803e3d6000fd5b50505050896001600160a01b031660008051602061533783398151915282610140015183610160015184610180015160026040516133079493929190614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc002274182610120015160405161334d91906152d8565b60405180910390a261249f8260200151836040015133846020015185606001518d8d88604001518b613eba565b60008061338683613f5e565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133d657600080fd5b505afa1580156133ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061340e919061451f565b1192915050565b801561344857670de0b6b3a76400008211156134435760405162461bcd60e51b81526004016106ff90614c71565b610989565b600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561349657600080fd5b505afa1580156134aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ce919061451f565b82101580156134e55750670de0b6b3a76400008211155b6109895760405162461bcd60e51b81526004016106ff906150c5565b6040516321e3780160e01b81526000906001600160a01b038416906321e378019061353090859060040161485c565b60206040518083038186803b15801561354857600080fd5b505afa15801561355c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613580919061451f565b905080600114156109725760405162461bcd60e51b81526004016106ff90615115565b6000846001600160a01b0316635dba4c4a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135e057600080fd5b505af11580156135f4573d6000803e3d6000fd5b5050604051630631203b60e41b8152600092506001600160a01b038816915063631203b0906136279087906004016152d8565b60206040518083038186803b15801561363f57600080fd5b505afa158015613653573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613677919061451f565b9050613684818585613f8a565b600d546040516340c10f1960e01b81526001600160a01b03878116926340c10f19926136b8929091169085906004016148b1565b600060405180830381600087803b1580156136d257600080fd5b505af11580156136e6573d6000803e3d6000fd5b50505050600d60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561373a57600080fd5b505af115801561374e573d6000803e3d6000fd5b509298975050505050505050565b6809c2007651b25000008110156107115760405162461bcd60e51b81526004016106ff90614f81565b600082156137b85760006137af846137a3878663ffffffff613fca16565b9063ffffffff61400416565b91506137bd9050565b506000195b9392505050565b600081156137f0576137e9826137a38568056bc75e2d6310000063ffffffff613fca16565b90506124f0565b506000196124f0565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561384757600080fd5b505afa15801561385b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387f919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614be3565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156138ec57600080fd5b505afa158015613900573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613924919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614f12565b6000826001600160a01b03168260405161395c9061483c565b60006040518083038185875af1925050503d8060008114613999576040519150601f19603f3d011682016040523d82523d6000602084013e61399e565b606091505b50509050806109725760405162461bcd60e51b81526004016106ff906149f4565b60405163f2e91d7160e01b81526001600160a01b0386169063f2e91d71906139eb9084906004016152d8565b600060405180830381600087803b158015613a0557600080fd5b505af1158015613a19573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b03871692506340c10f199150613a4b90869086906004016148b1565b600060405180830381600087803b158015613a6557600080fd5b505af1158015610df9573d6000803e3d6000fd5b60008184841115613a9d5760405162461bcd60e51b81526004016106ff9190614944565b505050900390565b613aad6141f0565b613ab56141f0565b5050604080518082019091526001600160a01b03929092168252602082015290565b600081116107115760405162461bcd60e51b81526004016106ff9061514c565b341580613b02575080155b6107115760405162461bcd60e51b81526004016106ff90614b3a565b34151580613b2b57508115155b80613b3557508015155b6109895760405162461bcd60e51b81526004016106ff90614cc3565b6000808315613b6557508290506001613b69565b8291505b9250929050565b6000806000613b838a8a8a8a8a8a614046565b915091506000612a0a838387613785565b8315613bcd57613ba38361409c565b8115613bc857613bb68160e001516137f9565b613bc88160e001518260c001516140ba565b610725565b613bda8160e0015161389e565b613bf7816020015182606001518360400151858560000151612bb8565b610100820181905261072590612c43565b6000610959826801158e460913d0000063ffffffff6124ab16565b613c3c826801158e460913d0000063ffffffff6124ab16565b8111156109895760405162461bcd60e51b81526004016106ff90615013565b600080600085613cea5760405163d3d6f84360e01b81526001600160a01b038a169063d3d6f84390613c93908b908b906004016148b1565b602060405180830381600087803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce5919061451f565b613d6a565b6040516372423c1760e01b81526001600160a01b038a16906372423c1790613d18908b908b906004016148b1565b602060405180830381600087803b158015613d3257600080fd5b505af1158015613d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d6a919061451f565b9050600084613df857604051630930874960e11b81526001600160a01b038b16906312610e9290613da1908c908a906004016148b1565b602060405180830381600087803b158015613dbb57600080fd5b505af1158015613dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df3919061451f565b613e78565b604051639976cf4560e01b81526001600160a01b038b1690639976cf4590613e26908c908a906004016148b1565b602060405180830381600087803b158015613e4057600080fd5b505af1158015613e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e78919061451f565b919a91995090975050505050505050565b6000806000613e9c898989898989614046565b915091506000613eac83836137c4565b9a9950505050505050505050565b8215613ed257613ecd89898387866139bf565b613ede565b613ede89898987612ce8565b8415613ef357613eee8987613943565b610df9565b6040516364a197f360e01b81526001600160a01b038a16906364a197f390613f21908a908a906004016148b1565b600060405180830381600087803b158015613f3b57600080fd5b505af1158015613f4f573d6000803e3d6000fd5b50505050505050505050505050565b600080613f696113a1565b90506000613f75610ef5565b9050613f82828286613785565b949350505050565b6000613fa8836137a386670de0b6b3a764000063ffffffff613fca16565b9050818111156107255760405162461bcd60e51b81526004016106ff90615200565b600082613fd9575060006124f0565b82820282848281613fe657fe5b04146124ed5760405162461bcd60e51b81526004016106ff90614d2f565b60006124ed83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506140da565b600080878786614065576140608a8963ffffffff6124ab16565b614075565b6140758a8963ffffffff6127a716565b91508461408c57613df3898763ffffffff6124ab16565b613e78898763ffffffff6127a716565b80156107115760405162461bcd60e51b81526004016106ff90614e5e565b808210156109895760405162461bcd60e51b81526004016106ff906151a3565b600081836140fb5760405162461bcd60e51b81526004016106ff9190614944565b50600083858161410757fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806101e00160405280600081526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b80356124f081615313565b60008083601f840112614223578182fd5b50813567ffffffffffffffff81111561423a578182fd5b602083019150836020828501011115613b6957600080fd5b600060808284031215614263578081fd5b50919050565b6000818303608081121561427b578182fd5b61428560606152e1565b9150604081121561429557600080fd5b506142a060406152e1565b82356142ab81615313565b808252506020830135602082015280825250604082013560208201526060820135604082015292915050565b6000602082840312156142e8578081fd5b81356124ed81615313565b600060208284031215614304578081fd5b81516124ed81615313565b60008060408385031215614321578081fd5b823561432c81615313565b9150602083013561433c81615313565b809150509250929050565b60008060006060848603121561435b578081fd5b833561436681615313565b9250602084013561437681615313565b9150604084013561438681615313565b809150509250925092565b6000806000806000806000806000806000806101808d8f0312156143b3578788fd5b8c356143be81615313565b9b5060208d01356143ce81615313565b9a5060408d01356143de81615313565b995060608d01356143ee81615313565b985060808d01356143fe81615313565b975060a08d013561440e81615313565b965061441d8e60c08f01614207565b955061442c8e60e08f01614207565b945061443c8e6101008f01614207565b935061444c8e6101208f01614207565b925061445c8e6101408f01614207565b915061446c8e6101608f01614207565b90509295989b509295989b509295989b565b60006020828403121561448f578081fd5b81516124ed81615328565b6000608082840312156144ab578081fd5b6124ed8383614252565b600080600060a084860312156144c9578283fd5b6144d38585614269565b9250608084013567ffffffffffffffff8111156144ee578283fd5b6144fa86828701614212565b9497909650939450505050565b600060208284031215614518578081fd5b5035919050565b600060208284031215614530578081fd5b5051919050565b60008060006060848603121561454b578283fd5b83359250602084013561437681615313565b60008060008060e08587031215614572578182fd5b84359350602085013561458481615313565b9250604085013561459481615313565b91506145a38660608701614252565b905092959194509250565b60008060008060008061010087890312156145c7578384fd5b8635955060208701356145d981615313565b945060408701356145e981615313565b93506145f88860608901614269565b925060e087013567ffffffffffffffff811115614613578283fd5b61461f89828a01614212565b979a9699509497509295939492505050565b60008060008060808587031215614646578182fd5b8435935060208501359250604085013561465f81615313565b9150606085013561466f81615313565b939692955090935050565b60008060008060008060c08789031215614692578384fd5b86359550602087013594506040870135935060608701356146b281615328565b925060808701356146c281615313565b915060a08701356146d281615313565b809150509295509295509295565b6000806000806000806000610140888a0312156146fb578081fd5b873596506020880135955060408801359450606088013561471b81615328565b9350608088013561472b81615313565b925060a088013561473b81615313565b915061474a8960c08a01614252565b905092959891949750929550565b60008060008060008060008060006101608a8c031215614776578283fd5b8935985060208a0135975060408a0135965060608a013561479681615328565b955060808a01356147a681615313565b945060a08a01356147b681615313565b93506147c58b60c08c01614269565b92506101408a013567ffffffffffffffff8111156147e1578283fd5b6147ed8c828d01614212565b8194508093505050509295985092959850929598565b600060208284031215614814578081fd5b813560ff811681146124ed578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b84815260208101849052604081018390526080810161493683615308565b606083015295945050505050565b6000602080835283518082850152825b8181101561497057858101830151858201604001528201614954565b818111156149815783604083870101525b50601f01601f1916929092016040019392505050565b6020808252603d908201527f426f72726f7765724f70733a2043616c6c657220646f65736e7420686176652060408201527f656e6f756768205a55534420746f206d616b652072657061796d656e74000000606082015260800190565b6020808252602d908201527f426f72726f7765724f70733a2053656e64696e672045544820746f204163746960408201526c1d99541bdbdb0819985a5b1959609a1b606082015260800190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f5a555344206973206e6f7420626f72726f77656420636f72726563746c790000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60208082526030908201527f426f72726f7765724f7065726174696f6e733a2043616e6e6f7420776974686460408201526f1c985dc8185b99081859190818dbdb1b60821b606082015260800190565b60208082526039908201527f426f72726f7765724f70733a204f7065726174696f6e206e6f74207065726d696040820152787474656420647572696e67205265636f76657279204d6f646560381b606082015260800190565b60208082526037908201527f426f72726f7765724f70733a204f7065726174696f6e206d757374206c65617660408201527632903a3937bb32903bb4ba341024a1a9101f1e9021a1a960491b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526032908201527f4d6178206665652070657263656e74616765206d757374206c657373207468616040820152716e206f7220657175616c20746f203130302560701b606082015260800190565b60208082526046908201527f426f72726f7765724f70733a205468657265206d75737420626520656974686560408201527f72206120636f6c6c61746572616c206368616e6765206f7220612064656274206060820152656368616e676560d01b608082015260a00190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20544352203c20434352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252602e908201527f426f72726f7765724f70733a2054726f766520646f6573206e6f74206578697360408201526d1d081bdc881a5cc818db1bdcd95960921b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252603e908201527f426f72726f7765724f70733a20436f6c6c61746572616c20776974686472617760408201527f616c206e6f74207065726d6974746564205265636f76657279204d6f64650000606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20494352203c204d4352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252603a908201527f426f72726f7765724f70733a2054726f76652773206e65742064656274206d7560408201527f73742062652067726561746572207468616e206d696e696d756d000000000000606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526043908201527f426f72726f7765724f70733a20416d6f756e7420726570616964206d7573742060408201527f6e6f74206265206c6172676572207468616e207468652054726f76652773206460608201526219589d60ea1b608082015260a00190565b60208082526029908201527f426f72726f7765724f70733a2043616c6c6572206973206e6f742053746162696040820152681b1a5d1e48141bdbdb60ba1b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252601c908201527f426f72726f7765724f70733a2054726f76652069732061637469766500000000604082015260600190565b60208082526037908201527f426f72726f7765724f70733a204465627420696e637265617365207265717569604082015276726573206e6f6e2d7a65726f20646562744368616e676560481b606082015260800190565b6020808252603e908201527f426f72726f7765724f70733a2043616e6e6f7420646563726561736520796f7560408201527f722054726f766527732049435220696e205265636f76657279204d6f64650000606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b60208082526016908201527513585cdcd95d081859191c995cdcc81b9bdd081cd95d60521b604082015260600190565b6000610100615277838951614824565b60208801516040840152604088015160608401526152986080840188614824565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b60405181810167ffffffffffffffff8111828210171561530057600080fd5b604052919050565b806003811061095c57fe5b6001600160a01b038116811461071157600080fd5b801515811461071157600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212209d20681b7b6630050fbad5344b16d370ece553865b2bf0ccb789b394933ed00f64736f6c634300060b0033", + "deployedBytecode": "0x60806040526004361061025c5760003560e01c80637778a3db11610144578063a20baee6116100b6578063c6a6cf201161007a578063c6a6cf2014610601578063e9fc346114610614578063ea9638bf14610629578063ec5472fd1461063c578063ec9f7d4614610651578063f92d3433146106665761025c565b8063a20baee614610414578063a3f4df7e14610595578063ae918754146105b7578063afbc74b5146105cc578063b5c89bab146105ec5761025c565b8063860665b311610108578063860665b314610510578063887105d314610523578063893d20e814610538578063899fe15e1461054d5780638d5c3dc11461056d5780639f070670146105805761025c565b80637778a3db14610486578063795d26c3146104a65780637d4f595d146104bb5780637e3eefdc146104db5780637f7dde4a146104fb5761025c565b8063485f190f116101dd5780636f0b0c1c116101a15780636f0b0c1c146103ff57806372fe25aa14610414578063734f622d14610429578063741bef1a14610449578063759b30341461045e578063763a0ef3146104735761025c565b8063485f190f146103795780634ff814431461038c5780635530273c146103ac57806368647db1146103cc5780636ea56960146103df5761025c565b80631a777717116102245780631a777717146102ed5780631bf435551461030d5780632771510a1461032f5780633cc742251461034f5780633d83908a146103645761025c565b80630d43e8ad146102615780630e704d501461028c5780630ff9a512146102a357806312261ee7146102b857806313af4035146102cd575b600080fd5b34801561026d57600080fd5b5061027661067b565b604051610283919061485c565b60405180910390f35b34801561029857600080fd5b506102a161068a565b005b3480156102af57600080fd5b50610276610694565b3480156102c457600080fd5b506102766106a3565b3480156102d957600080fd5b506102a16102e83660046142d7565b6106c7565b3480156102f957600080fd5b506102a161030836600461455d565b610714565b34801561031957600080fd5b5061032261072b565b60405161028391906152d8565b34801561033b57600080fd5b506102a161034a3660046142d7565b610738565b34801561035b57600080fd5b506102766107c6565b34801561037057600080fd5b506102766107d5565b6102a1610387366004614631565b6107e4565b34801561039857600080fd5b506103226103a7366004614507565b61094e565b3480156103b857600080fd5b506102a16103c7366004614537565b610961565b6102a16103da36600461430f565b610977565b3480156103eb57600080fd5b506102a16103fa366004614631565b61098d565b34801561040b57600080fd5b506102a161099e565b34801561042057600080fd5b506103226109fc565b34801561043557600080fd5b506102a1610444366004614391565b610a08565b34801561045557600080fd5b50610276610dcc565b34801561046a57600080fd5b50610322610ddb565b6102a1610481366004614758565b610de8565b34801561049257600080fd5b506102a16104a136600461449a565b610e04565b3480156104b257600080fd5b50610322610ef5565b3480156104c757600080fd5b506102a16104d63660046144b5565b611014565b3480156104e757600080fd5b506103226104f6366004614631565b61110a565b34801561050757600080fd5b50610276611385565b6102a161051e366004614631565b611394565b34801561052f57600080fd5b506103226113a1565b34801561054457600080fd5b50610276611470565b34801561055957600080fd5b506102a16105683660046145ae565b61148f565b6102a161057b3660046146e0565b6114aa565b34801561058c57600080fd5b506102766114c2565b3480156105a157600080fd5b506105aa6114d1565b6040516102839190614944565b3480156105c357600080fd5b506102766114ff565b3480156105d857600080fd5b506102a16105e7366004614537565b61150e565b3480156105f857600080fd5b50610276611520565b6102a161060f36600461467a565b61152f565b34801561062057600080fd5b5061027661153e565b6102a1610637366004614347565b61154d565b34801561064857600080fd5b50610276611567565b34801561065d57600080fd5b50610276611576565b34801561067257600080fd5b50610322611585565b600d546001600160a01b031681565b610692611607565b565b6009546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6106cf611470565b6001600160a01b0316336001600160a01b0316146107085760405162461bcd60e51b81526004016106ff90614e2d565b60405180910390fd5b610711816119f6565b50565b610725600080866000878787611a81565b50505050565b6809c2007651b250000081565b610740611470565b6001600160a01b0316336001600160a01b0316146107705760405162461bcd60e51b81526004016106ff90614e2d565b600c80546001600160a01b0319166001600160a01b0383161790556040517f6926b3375b54960080b7d8a184061f39a02e8c3bf64aa9df7e75359fdc00d814906107bb90839061485c565b60405180910390a150565b6001546001600160a01b031681565b6004546001600160a01b031681565b600c546001600160a01b031661080c5760405162461bcd60e51b81526004016106ff90615237565b6108198484848430611c37565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b39261084f9291169087906004016148b1565b602060405180830381600087803b15801561086957600080fd5b505af115801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a1919061447e565b6108bd5760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b926108f592911690879033906004016148f5565b602060405180830381600087803b15801561090f57600080fd5b505af1158015610923573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610947919061451f565b5050505050565b600061095982612262565b90505b919050565b61097233846000808686600061227d565b505050565b6109893360008060008686600061227d565b5050565b61072533600085600186868a61227d565b60075460405163b32beb5b60e01b81526001600160a01b039091169063b32beb5b906109ce90339060040161485c565b600060405180830381600087803b1580156109e857600080fd5b505af1158015610725573d6000803e3d6000fd5b670de0b6b3a764000081565b610a10611470565b6001600160a01b0316336001600160a01b031614610a405760405162461bcd60e51b81526004016106ff90614e2d565b610a498c61228d565b610a528b61228d565b610a5b8a61228d565b610a648961228d565b610a6d8861228d565b610a768761228d565b610a7f8661228d565b610a888561228d565b610a918461228d565b610a9a8361228d565b610aa38261228d565b610aac8161228d565b600d80546001600160a01b03199081166001600160a01b038f8116919091179092556003805482168e84161790556004805482168d84161790556000805482168c84161790556001805482168b84161790556005805482168a8416179055600680548216898416179055600780548216888416179055600280548216878416179055600b80548216868416179055600a8054821685841617905560098054821692841692831790556008805490911690911790556040517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db990610b90908e9061485c565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a56788a604051610bc7919061485c565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd88289604051610bfe919061485c565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b88604051610c35919061485c565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f87604051610c6c919061485c565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa086604051610ca3919061485c565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d85604051610cda919061485c565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db26484604051610d11919061485c565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe7880083604051610d48919061485c565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d82604051610d7f919061485c565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd81604051610db6919061485c565b60405180910390a1505050505050505050505050565b6002546001600160a01b031681565b6801158e460913d0000081565b610df98989898989898989896122d2565b505050505050505050565b600c546001600160a01b0316610e2c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a255391610e5e9133910161485c565b60206040518083038186803b158015610e7657600080fd5b505afa158015610e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eae919061451f565b600c54909150610eec906001600160a01b0316610eda836801158e460913d0000063ffffffff6124ab16565b600a546001600160a01b0316856124f6565b50610989611607565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f71919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b505afa158015610fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffb919061451f565b905061100d828263ffffffff6127a716565b9250505090565b600c546001600160a01b031661103c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a25539161106e9133910161485c565b60206040518083038186803b15801561108657600080fd5b505afa15801561109a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110be919061451f565b600c54600a54919250611101916001600160a01b039182169116867f000000000000000000000000000000000000000000000000000000000000000087876127cc565b50610725611607565b600a546040516370a0823160e01b8152600091309183916001600160a01b0316906370a082319061113f90859060040161485c565b60206040518083038186803b15801561115757600080fd5b505afa15801561116b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118f919061451f565b905061119f33838888888c612a19565b6111af818763ffffffff6127a716565b600a546040516370a0823160e01b81526001600160a01b03909116906370a08231906111df90869060040161485c565b60206040518083038186803b1580156111f757600080fd5b505afa15801561120b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122f919061451f565b1461124c5760405162461bcd60e51b81526004016106ff90614ac1565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611282929116908a906004016148b1565b602060405180830381600087803b15801561129c57600080fd5b505af11580156112b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d4919061447e565b6112f05760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611328929116908a9033906004016148f5565b602060405180830381600087803b15801561134257600080fd5b505af1158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a919061451f565b979650505050505050565b6000546001600160a01b031681565b6107258484848433611c37565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b60008060405161147f9061483f565b6040519081900390205492915050565b6114a260008088600089898989896122d2565b505050505050565b6114b987878787878787611a81565b50505050505050565b6003546001600160a01b031681565b60405180604001604052806012815260200171426f72726f7765724f7065726174696f6e7360701b81525081565b600b546001600160a01b031681565b6109723360008560008686600061227d565b600c546001600160a01b031681565b6114a23386868686868c61227d565b600c546001600160a01b031690565b611555612a2b565b6109728360008060008686600061227d565b6008546001600160a01b031681565b600a546001600160a01b031681565b6003546040805163f92d343360e01b815290516000926001600160a01b03169163f92d3433916004808301926020929190829003018186803b1580156115ca57600080fd5b505afa1580156115de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611602919061451f565b905090565b600454600054600a546001600160a01b0392831692918216911661162b8333612a55565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561167157600080fd5b505af1158015611685573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a9919061451f565b90506116b481612af6565b604051630b07655760e01b81526001600160a01b03851690630b076557906116e090339060040161485c565b600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50506040516309019aaf60e31b8152600092506001600160a01b038716915063480cd5789061174190339060040161485c565b60206040518083038186803b15801561175957600080fd5b505afa15801561176d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611791919061451f565b90506000856001600160a01b031663d66a2553336040518263ffffffff1660e01b81526004016117c1919061485c565b60206040518083038186803b1580156117d957600080fd5b505afa1580156117ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611811919061451f565b90506118368433611831846801158e460913d0000063ffffffff6124ab16565b612b1c565b600061184783600084600088612bb8565b905061185281612c43565b604051631fc5750960e31b81526001600160a01b0388169063fe2ba8489061187e90339060040161485c565b600060405180830381600087803b15801561189857600080fd5b505af11580156118ac573d6000803e3d6000fd5b50506040516365e89c5760e11b81526001600160a01b038a16925063cbd138ae91506118dc90339060040161485c565b600060405180830381600087803b1580156118f657600080fd5b505af115801561190a573d6000803e3d6000fd5b50505050336001600160a01b03166000805160206153378339815191526000806000600160405161193e9493929190614918565b60405180910390a261196a868633611965866801158e460913d0000063ffffffff6124ab16565b612ce8565b60065461198d90879087906001600160a01b03166801158e460913d00000612ce8565b6040516364a197f360e01b81526001600160a01b038716906364a197f3906119bb90339087906004016148b1565b600060405180830381600087803b1580156119d557600080fd5b505af11580156119e9573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038116611a1c5760405162461bcd60e51b81526004016106ff90614af8565b806001600160a01b0316611a2e611470565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611a719061483f565b6040519081900390209190915550565b600c546001600160a01b0316611aa95760405162461bcd60e51b81526004016106ff90615237565b83158015611ab75750600085115b15611add57600c54600a54611adb916001600160a01b0390811691889116846124f6565b505b611aed3387878787878d30612da2565b838015611afa5750600085115b156114b957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611b359291169089906004016148b1565b602060405180830381600087803b158015611b4f57600080fd5b505af1158015611b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b87919061447e565b611ba35760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611bdb92911690899033906004016148f5565b602060405180830381600087803b158015611bf557600080fd5b505af1158015611c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2d919061451f565b5050505050505050565b611c3f614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152611c77614131565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611cc757600080fd5b505af1158015611cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cff919061451f565b808252600090611d0e9061337a565b9050611d1a8882613415565b8251611d269033613501565b6040820187905280611d6757611d4683600001518460400151898b6135a3565b602083018190526040830151611d619163ffffffff6127a716565b60408301525b611d74826040015161375c565b611d818260400151612262565b60608301819052611d8e57fe5b611da13483606001518460000151613785565b60808301526060820151611db69034906137c4565b60a08301528015611dd357611dce82608001516137f9565b611e06565b611de0826080015161389e565b6000611df9346001856060015160018760000151612bb8565b9050611e0481612c43565b505b8251604051635d6b480f60e01b81526001600160a01b0390911690635d6b480f90611e389033906001906004016148b1565b600060405180830381600087803b158015611e5257600080fd5b505af1158015611e66573d6000803e3d6000fd5b505084516040516372423c1760e01b81526001600160a01b0390911692506372423c179150611e9b90339034906004016148b1565b602060405180830381600087803b158015611eb557600080fd5b505af1158015611ec9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eed919061451f565b5082516060830151604051639976cf4560e01b81526001600160a01b0390921691639976cf4591611f23913391906004016148b1565b602060405180830381600087803b158015611f3d57600080fd5b505af1158015611f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f75919061451f565b5082516040516382fe3eb960e01b81526001600160a01b03909116906382fe3eb990611fa590339060040161485c565b600060405180830381600087803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b50508451604051630c7940bd60e11b81526001600160a01b0390911692506318f2817a915061200690339060040161485c565b602060405180830381600087803b15801561202057600080fd5b505af1158015612034573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612058919061451f565b60c0830152600b5460a08301516040516346f7cf8760e01b81526001600160a01b03909216916346f7cf8791612097913391908b908b906004016148ca565b600060405180830381600087803b1580156120b157600080fd5b505af11580156120c5573d6000803e3d6000fd5b505084516040516315d549f160e01b81526001600160a01b0390911692506315d549f191506120f890339060040161485c565b602060405180830381600087803b15801561211257600080fd5b505af1158015612126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214a919061451f565b60e0830181905260405133917f59cfd0cd754bc5748b6770e94a4ffa5f678d885cb899dcfadc5734edb97c67ab9161218291906152d8565b60405180910390a2612198836020015134613943565b6121b183602001518460400151868a86604001516139bf565b602083015160408401516006546121dd9291906001600160a01b03166801158e460913d00000806139bf565b606082015160c083015160405133926000805160206153378339815191529261220b92349190600090614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc0022741836020015160405161225091906152d8565b60405180910390a25050505050505050565b6000610959826801158e460913d0000063ffffffff6127a716565b6114b98787878787878733612da2565b6001600160a01b0381166122b35760405162461bcd60e51b81526004016106ff90614c3a565b803b806109895760405162461bcd60e51b81526004016106ff90614fde565b600c546001600160a01b03166122fa5760405162461bcd60e51b81526004016106ff90615237565b851580156123085750600087115b1561234f57600c54600a5461234d916001600160a01b039081169116857f000000000000000000000000000000000000000000000000000000000000000086866127cc565b505b61235f3389898989898f30612da2565b85801561236c5750600087115b15610df957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b3926123a7929116908b906004016148b1565b602060405180830381600087803b1580156123c157600080fd5b505af11580156123d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f9919061447e565b6124155760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b9261244d929116908b9033906004016148f5565b602060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f919061451f565b50505050505050505050565b60006124ed83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a79565b90505b92915050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561253257600080fd5b505afa158015612546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061256a91906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161259a919061485c565b60206040518083038186803b1580156125b257600080fd5b505afa1580156125c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ea919061451f565b9050306001600160a01b03831663605629d633838a893561261160408c0160208d01614803565b8b604001358c606001356040518863ffffffff1660e01b815260040161263d9796959493929190614870565b600060405180830381600087803b15801561265757600080fd5b505af115801561266b573d6000803e3d6000fd5b50505050866126fc83856001600160a01b03166370a08231856040518263ffffffff1660e01b81526004016126a0919061485c565b60206040518083038186803b1580156126b857600080fd5b505afa1580156126cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f0919061451f565b9063ffffffff6124ab16565b146127195760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c9223906127499089908b9033906004016148f5565b602060405180830381600087803b15801561276357600080fd5b505af1158015612777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279b919061451f565b98975050505050505050565b6000828201838110156124ed5760405162461bcd60e51b81526004016106ff90614a8a565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284091906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612870919061485c565b60206040518083038186803b15801561288857600080fd5b505afa15801561289c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c0919061451f565b87516020015190915030906001600160a01b0388166330f28b7a8a6128e58585613aa5565b338b8b6040518663ffffffff1660e01b8152600401612908959493929190615267565b600060405180830381600087803b15801561292257600080fd5b505af1158015612936573d6000803e3d6000fd5b505050508061296b84866001600160a01b03166370a08231866040518263ffffffff1660e01b81526004016126a0919061485c565b146129885760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c9223906129b8908d90859033906004016148f5565b602060405180830381600087803b1580156129d257600080fd5b505af11580156129e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0a919061451f565b9b9a5050505050505050505050565b6114a28660008660018787878c612da2565b6005546001600160a01b031633146106925760405162461bcd60e51b81526004016106ff9061507c565b6040516321e3780160e01b81526000906001600160a01b038416906321e3780190612a8490859060040161485c565b60206040518083038186803b158015612a9c57600080fd5b505afa158015612ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad4919061451f565b9050806001146109725760405162461bcd60e51b81526004016106ff90614ddf565b612aff8161337a565b156107115760405162461bcd60e51b81526004016106ff90614b8a565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190612b4a90869060040161485c565b60206040518083038186803b158015612b6257600080fd5b505afa158015612b76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9a919061451f565b10156109725760405162461bcd60e51b81526004016106ff90614997565b600080612bc36113a1565b90506000612bcf610ef5565b905086612beb57612be6828963ffffffff6124ab16565b612bfb565b612bfb828963ffffffff6127a716565b915084612c1757612c12818763ffffffff6124ab16565b612c27565b612c27818763ffffffff6127a716565b90506000612c36838387613785565b9998505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9157600080fd5b505afa158015612ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc9919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614d70565b60405163121cbc4d60e11b81526001600160a01b03851690632439789a90612d149084906004016152d8565b600060405180830381600087803b158015612d2e57600080fd5b505af1158015612d42573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b0386169250639dc29fac9150612d7490859085906004016148b1565b600060405180830381600087803b158015612d8e57600080fd5b505af1158015611c2d573d6000803e3d6000fd5b612daa614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152612de2614176565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e3257600080fd5b505af1158015612e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6a919061451f565b808252612e769061337a565b15156101c08201528615612e9c57612e9384826101c00151613415565b612e9c88613ad7565b612ea589613af7565b612eaf8989613b1e565b8151612ebb908b612a55565b336001600160a01b038b161480612ef157506005546001600160a01b031633148015612ee75750600034115b8015612ef1575087155b612ef757fe5b8151604051630b07655760e01b81526001600160a01b0390911690630b07655790612f26908d9060040161485c565b600060405180830381600087803b158015612f4057600080fd5b505af1158015612f54573d6000803e3d6000fd5b50505050612f62348a613b51565b15156060830152602082015260408101889052868015612f855750806101c00151155b15612fc057612f9e826000015183604001518a876135a3565b61012082018190526040820151612fba9163ffffffff6127a716565b60408201525b815160405163d66a255360e01b81526001600160a01b039091169063d66a255390612fef908d9060040161485c565b60206040518083038186803b15801561300757600080fd5b505afa15801561301b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303f919061451f565b608082015281516040516309019aaf60e31b81526001600160a01b039091169063480cd57890613073908d9060040161485c565b60206040518083038186803b15801561308b57600080fd5b505afa15801561309f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c3919061451f565b60a08201819052608082015182516130dc929190613785565b8160c001818152505061310c8160a0015182608001518360200151846060015185604001518c8760000151613b70565b60e082015260a081015189111561311f57fe5b613130816101c001518a8984613b94565b8615801561313e5750600088115b156131855761316061315b82604001516126f08460800151613c08565b61375c565b61317281608001518260400151613c23565b61318582604001518b8360400151612b1c565b6131a382600001518b8360200151846060015185604001518c613c5b565b6101408301526101608201528151604051630c7940bd60e11b81526001600160a01b03909116906318f2817a906131de908d9060040161485c565b602060405180830381600087803b1580156131f857600080fd5b505af115801561320c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613230919061451f565b8161018001818152505061325c8160a0015182608001518360200151846060015185604001518c613e89565b6101a08201819052600b5460405163015f109360e51b81526001600160a01b0390911691632be2126091613298918e918b908b906004016148ca565b600060405180830381600087803b1580156132b257600080fd5b505af11580156132c6573d6000803e3d6000fd5b50505050896001600160a01b031660008051602061533783398151915282610140015183610160015184610180015160026040516133079493929190614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc002274182610120015160405161334d91906152d8565b60405180910390a261249f8260200151836040015133846020015185606001518d8d88604001518b613eba565b60008061338683613f5e565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133d657600080fd5b505afa1580156133ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061340e919061451f565b1192915050565b801561344857670de0b6b3a76400008211156134435760405162461bcd60e51b81526004016106ff90614c71565b610989565b600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561349657600080fd5b505afa1580156134aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ce919061451f565b82101580156134e55750670de0b6b3a76400008211155b6109895760405162461bcd60e51b81526004016106ff906150c5565b6040516321e3780160e01b81526000906001600160a01b038416906321e378019061353090859060040161485c565b60206040518083038186803b15801561354857600080fd5b505afa15801561355c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613580919061451f565b905080600114156109725760405162461bcd60e51b81526004016106ff90615115565b6000846001600160a01b0316635dba4c4a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135e057600080fd5b505af11580156135f4573d6000803e3d6000fd5b5050604051630631203b60e41b8152600092506001600160a01b038816915063631203b0906136279087906004016152d8565b60206040518083038186803b15801561363f57600080fd5b505afa158015613653573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613677919061451f565b9050613684818585613f8a565b600d546040516340c10f1960e01b81526001600160a01b03878116926340c10f19926136b8929091169085906004016148b1565b600060405180830381600087803b1580156136d257600080fd5b505af11580156136e6573d6000803e3d6000fd5b50505050600d60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561373a57600080fd5b505af115801561374e573d6000803e3d6000fd5b509298975050505050505050565b6809c2007651b25000008110156107115760405162461bcd60e51b81526004016106ff90614f81565b600082156137b85760006137af846137a3878663ffffffff613fca16565b9063ffffffff61400416565b91506137bd9050565b506000195b9392505050565b600081156137f0576137e9826137a38568056bc75e2d6310000063ffffffff613fca16565b90506124f0565b506000196124f0565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561384757600080fd5b505afa15801561385b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387f919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614be3565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156138ec57600080fd5b505afa158015613900573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613924919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614f12565b6000826001600160a01b03168260405161395c9061483c565b60006040518083038185875af1925050503d8060008114613999576040519150601f19603f3d011682016040523d82523d6000602084013e61399e565b606091505b50509050806109725760405162461bcd60e51b81526004016106ff906149f4565b60405163f2e91d7160e01b81526001600160a01b0386169063f2e91d71906139eb9084906004016152d8565b600060405180830381600087803b158015613a0557600080fd5b505af1158015613a19573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b03871692506340c10f199150613a4b90869086906004016148b1565b600060405180830381600087803b158015613a6557600080fd5b505af1158015610df9573d6000803e3d6000fd5b60008184841115613a9d5760405162461bcd60e51b81526004016106ff9190614944565b505050900390565b613aad6141f0565b613ab56141f0565b5050604080518082019091526001600160a01b03929092168252602082015290565b600081116107115760405162461bcd60e51b81526004016106ff9061514c565b341580613b02575080155b6107115760405162461bcd60e51b81526004016106ff90614b3a565b34151580613b2b57508115155b80613b3557508015155b6109895760405162461bcd60e51b81526004016106ff90614cc3565b6000808315613b6557508290506001613b69565b8291505b9250929050565b6000806000613b838a8a8a8a8a8a614046565b915091506000612a0a838387613785565b8315613bcd57613ba38361409c565b8115613bc857613bb68160e001516137f9565b613bc88160e001518260c001516140ba565b610725565b613bda8160e0015161389e565b613bf7816020015182606001518360400151858560000151612bb8565b610100820181905261072590612c43565b6000610959826801158e460913d0000063ffffffff6124ab16565b613c3c826801158e460913d0000063ffffffff6124ab16565b8111156109895760405162461bcd60e51b81526004016106ff90615013565b600080600085613cea5760405163d3d6f84360e01b81526001600160a01b038a169063d3d6f84390613c93908b908b906004016148b1565b602060405180830381600087803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce5919061451f565b613d6a565b6040516372423c1760e01b81526001600160a01b038a16906372423c1790613d18908b908b906004016148b1565b602060405180830381600087803b158015613d3257600080fd5b505af1158015613d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d6a919061451f565b9050600084613df857604051630930874960e11b81526001600160a01b038b16906312610e9290613da1908c908a906004016148b1565b602060405180830381600087803b158015613dbb57600080fd5b505af1158015613dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df3919061451f565b613e78565b604051639976cf4560e01b81526001600160a01b038b1690639976cf4590613e26908c908a906004016148b1565b602060405180830381600087803b158015613e4057600080fd5b505af1158015613e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e78919061451f565b919a91995090975050505050505050565b6000806000613e9c898989898989614046565b915091506000613eac83836137c4565b9a9950505050505050505050565b8215613ed257613ecd89898387866139bf565b613ede565b613ede89898987612ce8565b8415613ef357613eee8987613943565b610df9565b6040516364a197f360e01b81526001600160a01b038a16906364a197f390613f21908a908a906004016148b1565b600060405180830381600087803b158015613f3b57600080fd5b505af1158015613f4f573d6000803e3d6000fd5b50505050505050505050505050565b600080613f696113a1565b90506000613f75610ef5565b9050613f82828286613785565b949350505050565b6000613fa8836137a386670de0b6b3a764000063ffffffff613fca16565b9050818111156107255760405162461bcd60e51b81526004016106ff90615200565b600082613fd9575060006124f0565b82820282848281613fe657fe5b04146124ed5760405162461bcd60e51b81526004016106ff90614d2f565b60006124ed83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506140da565b600080878786614065576140608a8963ffffffff6124ab16565b614075565b6140758a8963ffffffff6127a716565b91508461408c57613df3898763ffffffff6124ab16565b613e78898763ffffffff6127a716565b80156107115760405162461bcd60e51b81526004016106ff90614e5e565b808210156109895760405162461bcd60e51b81526004016106ff906151a3565b600081836140fb5760405162461bcd60e51b81526004016106ff9190614944565b50600083858161410757fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806101e00160405280600081526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b80356124f081615313565b60008083601f840112614223578182fd5b50813567ffffffffffffffff81111561423a578182fd5b602083019150836020828501011115613b6957600080fd5b600060808284031215614263578081fd5b50919050565b6000818303608081121561427b578182fd5b61428560606152e1565b9150604081121561429557600080fd5b506142a060406152e1565b82356142ab81615313565b808252506020830135602082015280825250604082013560208201526060820135604082015292915050565b6000602082840312156142e8578081fd5b81356124ed81615313565b600060208284031215614304578081fd5b81516124ed81615313565b60008060408385031215614321578081fd5b823561432c81615313565b9150602083013561433c81615313565b809150509250929050565b60008060006060848603121561435b578081fd5b833561436681615313565b9250602084013561437681615313565b9150604084013561438681615313565b809150509250925092565b6000806000806000806000806000806000806101808d8f0312156143b3578788fd5b8c356143be81615313565b9b5060208d01356143ce81615313565b9a5060408d01356143de81615313565b995060608d01356143ee81615313565b985060808d01356143fe81615313565b975060a08d013561440e81615313565b965061441d8e60c08f01614207565b955061442c8e60e08f01614207565b945061443c8e6101008f01614207565b935061444c8e6101208f01614207565b925061445c8e6101408f01614207565b915061446c8e6101608f01614207565b90509295989b509295989b509295989b565b60006020828403121561448f578081fd5b81516124ed81615328565b6000608082840312156144ab578081fd5b6124ed8383614252565b600080600060a084860312156144c9578283fd5b6144d38585614269565b9250608084013567ffffffffffffffff8111156144ee578283fd5b6144fa86828701614212565b9497909650939450505050565b600060208284031215614518578081fd5b5035919050565b600060208284031215614530578081fd5b5051919050565b60008060006060848603121561454b578283fd5b83359250602084013561437681615313565b60008060008060e08587031215614572578182fd5b84359350602085013561458481615313565b9250604085013561459481615313565b91506145a38660608701614252565b905092959194509250565b60008060008060008061010087890312156145c7578384fd5b8635955060208701356145d981615313565b945060408701356145e981615313565b93506145f88860608901614269565b925060e087013567ffffffffffffffff811115614613578283fd5b61461f89828a01614212565b979a9699509497509295939492505050565b60008060008060808587031215614646578182fd5b8435935060208501359250604085013561465f81615313565b9150606085013561466f81615313565b939692955090935050565b60008060008060008060c08789031215614692578384fd5b86359550602087013594506040870135935060608701356146b281615328565b925060808701356146c281615313565b915060a08701356146d281615313565b809150509295509295509295565b6000806000806000806000610140888a0312156146fb578081fd5b873596506020880135955060408801359450606088013561471b81615328565b9350608088013561472b81615313565b925060a088013561473b81615313565b915061474a8960c08a01614252565b905092959891949750929550565b60008060008060008060008060006101608a8c031215614776578283fd5b8935985060208a0135975060408a0135965060608a013561479681615328565b955060808a01356147a681615313565b945060a08a01356147b681615313565b93506147c58b60c08c01614269565b92506101408a013567ffffffffffffffff8111156147e1578283fd5b6147ed8c828d01614212565b8194508093505050509295985092959850929598565b600060208284031215614814578081fd5b813560ff811681146124ed578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b84815260208101849052604081018390526080810161493683615308565b606083015295945050505050565b6000602080835283518082850152825b8181101561497057858101830151858201604001528201614954565b818111156149815783604083870101525b50601f01601f1916929092016040019392505050565b6020808252603d908201527f426f72726f7765724f70733a2043616c6c657220646f65736e7420686176652060408201527f656e6f756768205a55534420746f206d616b652072657061796d656e74000000606082015260800190565b6020808252602d908201527f426f72726f7765724f70733a2053656e64696e672045544820746f204163746960408201526c1d99541bdbdb0819985a5b1959609a1b606082015260800190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f5a555344206973206e6f7420626f72726f77656420636f72726563746c790000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60208082526030908201527f426f72726f7765724f7065726174696f6e733a2043616e6e6f7420776974686460408201526f1c985dc8185b99081859190818dbdb1b60821b606082015260800190565b60208082526039908201527f426f72726f7765724f70733a204f7065726174696f6e206e6f74207065726d696040820152787474656420647572696e67205265636f76657279204d6f646560381b606082015260800190565b60208082526037908201527f426f72726f7765724f70733a204f7065726174696f6e206d757374206c65617660408201527632903a3937bb32903bb4ba341024a1a9101f1e9021a1a960491b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526032908201527f4d6178206665652070657263656e74616765206d757374206c657373207468616040820152716e206f7220657175616c20746f203130302560701b606082015260800190565b60208082526046908201527f426f72726f7765724f70733a205468657265206d75737420626520656974686560408201527f72206120636f6c6c61746572616c206368616e6765206f7220612064656274206060820152656368616e676560d01b608082015260a00190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20544352203c20434352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252602e908201527f426f72726f7765724f70733a2054726f766520646f6573206e6f74206578697360408201526d1d081bdc881a5cc818db1bdcd95960921b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252603e908201527f426f72726f7765724f70733a20436f6c6c61746572616c20776974686472617760408201527f616c206e6f74207065726d6974746564205265636f76657279204d6f64650000606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20494352203c204d4352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252603a908201527f426f72726f7765724f70733a2054726f76652773206e65742064656274206d7560408201527f73742062652067726561746572207468616e206d696e696d756d000000000000606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526043908201527f426f72726f7765724f70733a20416d6f756e7420726570616964206d7573742060408201527f6e6f74206265206c6172676572207468616e207468652054726f76652773206460608201526219589d60ea1b608082015260a00190565b60208082526029908201527f426f72726f7765724f70733a2043616c6c6572206973206e6f742053746162696040820152681b1a5d1e48141bdbdb60ba1b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252601c908201527f426f72726f7765724f70733a2054726f76652069732061637469766500000000604082015260600190565b60208082526037908201527f426f72726f7765724f70733a204465627420696e637265617365207265717569604082015276726573206e6f6e2d7a65726f20646562744368616e676560481b606082015260800190565b6020808252603e908201527f426f72726f7765724f70733a2043616e6e6f7420646563726561736520796f7560408201527f722054726f766527732049435220696e205265636f76657279204d6f64650000606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b60208082526016908201527513585cdcd95d081859191c995cdcc81b9bdd081cd95d60521b604082015260600190565b6000610100615277838951614824565b60208801516040840152604088015160608401526152986080840188614824565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b60405181810167ffffffffffffffff8111828210171561530057600080fd5b604052919050565b806003811061095c57fe5b6001600160a01b038116811461071157600080fd5b801515811461071157600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212209d20681b7b6630050fbad5344b16d370ece553865b2bf0ccb789b394933ed00f64736f6c634300060b0033", + "implementation": "0x99f58e20fb82b6cdf82b9f1f840198bf8a139d5b" +} diff --git a/external/deployments/rskTestnet/BorrowerOperations_Implementation.json b/external/deployments/rskTestnet/BorrowerOperations_Implementation.json new file mode 100644 index 000000000..29c9ceb36 --- /dev/null +++ b/external/deployments/rskTestnet/BorrowerOperations_Implementation.json @@ -0,0 +1,1572 @@ +{ + "address": "0x99f58e20fb82b6cdf82b9f1f840198bf8a139d5b", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + } + ], + "name": "CollSurplusPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + } + ], + "name": "FeeDistributorAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + } + ], + "name": "GasPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_massetManagerAddress", + "type": "address" + } + ], + "name": "MassetManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + } + ], + "name": "StabilityPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "arrayIndex", + "type": "uint256" + } + ], + "name": "TroveCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newTroveManagerAddress", + "type": "address" + } + ], + "name": "TroveManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum BorrowerOperations.BorrowerOperation", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "ZEROStakingAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDFee", + "type": "uint256" + } + ], + "name": "ZUSDBorrowingFeePaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "BORROWING_FEE_FLOOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "addColl", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "adjustNueTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "adjustNueTroveWithPermit2", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDChange", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_isDebtIncrease", + "type": "bool" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "adjustTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "claimCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "closeNueTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "closeNueTroveWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "closeTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeDistributor", + "outputs": [ + { + "internalType": "contract IFeeDistributor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + } + ], + "name": "getCompositeDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMassetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "massetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "moveETHGainToTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "openNueTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "openTrove", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "repayZUSD", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "repayZusdFromDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "repayZusdFromDLLRWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_massetManagerAddress", + "type": "address" + } + ], + "name": "setMassetManagerAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManager", + "outputs": [ + { + "internalType": "contract ITroveManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_collWithdrawal", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawColl", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawZUSD", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_ZUSDAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawZusdAndConvertToDLLR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "zeroStaking", + "outputs": [ + { + "internalType": "contract IZEROStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zeroStakingAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0x330ad35d02b52b6f132C3C31730Dd8F79Cb58b7E", + "transactionIndex": 0, + "gasUsed": "5799498", + "logsBloom": "0x00000800000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000001000000000000000000000000000000000000000", + "blockHash": "0x7de331c1815635488605d3e00b15a43084f7a6002e2ddf43d01f2c61ae10f888", + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748936, + "transactionHash": "0x1b90ac7d6d78e1a74dabce6d43c24e65d9115924499ec7ed309ea54d6806e93e", + "address": "0x330ad35d02b52b6f132C3C31730Dd8F79Cb58b7E", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x7de331c1815635488605d3e00b15a43084f7a6002e2ddf43d01f2c61ae10f888" + } + ], + "blockNumber": 4748936, + "cumulativeGasUsed": "5799498", + "status": 1, + "byzantium": true + }, + "args": ["0x000000000022d473030f116ddee9f6b43ac78ba3"], + "numDeployments": 3, + "solcInputHash": "849fadfa265e27de6fba2f2d99bdf763", + "metadata": "{\"compiler\":{\"version\":\"0.6.11+commit.5ef660b1\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_permit2\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_activePoolAddress\",\"type\":\"address\"}],\"name\":\"ActivePoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_collSurplusPoolAddress\",\"type\":\"address\"}],\"name\":\"CollSurplusPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_defaultPoolAddress\",\"type\":\"address\"}],\"name\":\"DefaultPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_feeDistributorAddress\",\"type\":\"address\"}],\"name\":\"FeeDistributorAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_gasPoolAddress\",\"type\":\"address\"}],\"name\":\"GasPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_massetManagerAddress\",\"type\":\"address\"}],\"name\":\"MassetManagerAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newPriceFeedAddress\",\"type\":\"address\"}],\"name\":\"PriceFeedAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_sortedTrovesAddress\",\"type\":\"address\"}],\"name\":\"SortedTrovesAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_stabilityPoolAddress\",\"type\":\"address\"}],\"name\":\"StabilityPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"arrayIndex\",\"type\":\"uint256\"}],\"name\":\"TroveCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newTroveManagerAddress\",\"type\":\"address\"}],\"name\":\"TroveManagerAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_coll\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"enum BorrowerOperations.BorrowerOperation\",\"name\":\"operation\",\"type\":\"uint8\"}],\"name\":\"TroveUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_zeroStakingAddress\",\"type\":\"address\"}],\"name\":\"ZEROStakingAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ZUSDFee\",\"type\":\"uint256\"}],\"name\":\"ZUSDBorrowingFeePaid\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_zusdTokenAddress\",\"type\":\"address\"}],\"name\":\"ZUSDTokenAddressChanged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BORROWING_FEE_FLOOR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DECIMAL_PRECISION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_NET_DEBT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZUSD_GAS_COMPENSATION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_100pct\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activePool\",\"outputs\":[{\"internalType\":\"contract IActivePool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"addColl\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_collWithdrawal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDChange\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_isDebtIncrease\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"adjustNueTrove\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_collWithdrawal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDChange\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_isDebtIncrease\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"adjustNueTroveWithPermit2\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_collWithdrawal\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDChange\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_isDebtIncrease\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"adjustTrove\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimCollateral\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"closeNueTrove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"closeNueTroveWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"closeTrove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultPool\",\"outputs\":[{\"internalType\":\"contract IDefaultPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeDistributor\",\"outputs\":[{\"internalType\":\"contract IFeeDistributor\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"}],\"name\":\"getCompositeDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemColl\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getMassetManager\",\"outputs\":[{\"internalType\":\"contract IMassetManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquityBaseParams\",\"outputs\":[{\"internalType\":\"contract ILiquityBaseParams\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"massetManager\",\"outputs\":[{\"internalType\":\"contract IMassetManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"moveETHGainToTrove\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"openNueTrove\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"openTrove\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceFeed\",\"outputs\":[{\"internalType\":\"contract IPriceFeed\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ZUSDAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"repayZUSD\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"repayZusdFromDLLR\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"repayZusdFromDLLRWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_feeDistributorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_liquityBaseParamsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_troveManagerAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_activePoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_defaultPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_stabilityPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_gasPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_collSurplusPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_priceFeedAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_sortedTrovesAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zusdTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zeroStakingAddress\",\"type\":\"address\"}],\"name\":\"setAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_massetManagerAddress\",\"type\":\"address\"}],\"name\":\"setMassetManagerAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortedTroves\",\"outputs\":[{\"internalType\":\"contract ISortedTroves\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"troveManager\",\"outputs\":[{\"internalType\":\"contract ITroveManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_collWithdrawal\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"withdrawColl\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"withdrawZUSD\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_ZUSDAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"withdrawZusdAndConvertToDLLR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zeroStaking\",\"outputs\":[{\"internalType\":\"contract IZEROStaking\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zeroStakingAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zusdToken\",\"outputs\":[{\"internalType\":\"contract IZUSDToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getOwner()\":{\"returns\":{\"_owner\":\"Address of the owner. \"}},\"setAddresses(address,address,address,address,address,address,address,address,address,address,address,address)\":{\"details\":\"initializer function, checks addresses are contracts\",\"params\":{\"_activePoolAddress\":\"ActivePool contract address\",\"_collSurplusPoolAddress\":\"CollSurplusPool contract address\",\"_defaultPoolAddress\":\"DefaultPool contract address\",\"_feeDistributorAddress\":\"feeDistributor contract address\",\"_gasPoolAddress\":\"GasPool contract address\",\"_liquityBaseParamsAddress\":\"LiquidityBaseParams contract address\",\"_priceFeedAddress\":\"PrideFeed contract address\",\"_sortedTrovesAddress\":\"SortedTroves contract address\",\"_stabilityPoolAddress\":\"StabilityPool contract address\",\"_troveManagerAddress\":\"TroveManager contract address\",\"_zeroStakingAddress\":\"ZEROStaking contract address\",\"_zusdTokenAddress\":\"ZUSDToken contract address\"}},\"setOwner(address)\":{\"params\":{\"_owner\":\"Address of the owner. \"}},\"withdrawZusdAndConvertToDLLR(uint256,uint256,address,address)\":{\"returns\":{\"_0\":\"DLLR amount minted\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"MIN_NET_DEBT()\":{\"notice\":\"Minimum amount of net ZUSD debt a trove must have\"},\"ZUSD_GAS_COMPENSATION()\":{\"notice\":\"Amount of ZUSD to be locked in gas pool on opening troves\"},\"addColl(address,address)\":{\"notice\":\"Send ETH as collateral to a trove\"},\"claimCollateral()\":{\"notice\":\"Claim remaining collateral from a redemption or from a liquidation with ICR > MCR in Recovery Mode\"},\"closeNueTrove((uint256,uint8,bytes32,bytes32))\":{\"notice\":\"allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE. This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\"},\"closeNueTroveWithPermit2(((address,uint256),uint256,uint256),bytes)\":{\"notice\":\"allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE. This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\"},\"closeTrove()\":{\"notice\":\"allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a ZUSD balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` ZUSD.\"},\"constructor\":\"Constructor \",\"getOwner()\":{\"notice\":\"Return address of the owner.\"},\"moveETHGainToTrove(address,address,address)\":{\"notice\":\"Send ETH as collateral to a trove. Called by only the Stability Pool.\"},\"permit2()\":{\"notice\":\"CONSTANT / IMMUTABLE VARIABLE ONLY \"},\"repayZUSD(uint256,address,address)\":{\"notice\":\"Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\"},\"repayZusdFromDLLR(uint256,address,address,(uint256,uint8,bytes32,bytes32))\":{\"notice\":\"Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly\"},\"repayZusdFromDLLRWithPermit2(uint256,address,address,((address,uint256),uint256,uint256),bytes)\":{\"notice\":\"Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly\"},\"setAddresses(address,address,address,address,address,address,address,address,address,address,address,address)\":{\"notice\":\"Called only once on init, to set addresses of other Zero contracts. Callable only by owner\"},\"setOwner(address)\":{\"notice\":\"Set address of the owner (only owner can call this function)\"},\"withdrawColl(uint256,address,address)\":{\"notice\":\"Withdraw ETH collateral from a trove\"},\"withdrawZUSD(uint256,uint256,address,address)\":{\"notice\":\"Withdraw ZUSD tokens from a trove: mint new ZUSD tokens to the owner, and increase the trove's debt accordingly\"},\"withdrawZusdAndConvertToDLLR(uint256,uint256,address,address)\":{\"notice\":\"Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction Zero Line of Credit owner can borrow a specified amount of ZUSD and convert it to DLLR via Sovryn Mynt\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/BorrowerOperations.sol\":\"BorrowerOperations\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"contracts/BorrowerOperations.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./Interfaces/ITroveManager.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/IZEROStaking.sol\\\";\\nimport \\\"./Interfaces/IFeeDistributor.sol\\\";\\nimport \\\"./Dependencies/LiquityBase.sol\\\";\\nimport \\\"./Dependencies/CheckContract.sol\\\";\\nimport \\\"./Dependencies/console.sol\\\";\\nimport \\\"./BorrowerOperationsStorage.sol\\\";\\nimport \\\"./Dependencies/Mynt/MyntLib.sol\\\";\\nimport \\\"./Interfaces/IPermit2.sol\\\";\\n\\ncontract BorrowerOperations is\\n LiquityBase,\\n BorrowerOperationsStorage,\\n CheckContract,\\n IBorrowerOperations\\n{\\n /** CONSTANT / IMMUTABLE VARIABLE ONLY */\\n IPermit2 public immutable permit2;\\n\\n /* --- Variable container structs ---\\n\\n Used to hold, return and assign variables inside a function, in order to avoid the error:\\n \\\"CompilerError: Stack too deep\\\". */\\n\\n struct LocalVariables_adjustTrove {\\n uint256 price;\\n uint256 collChange;\\n uint256 netDebtChange;\\n bool isCollIncrease;\\n uint256 debt;\\n uint256 coll;\\n uint256 oldICR;\\n uint256 newICR;\\n uint256 newTCR;\\n uint256 ZUSDFee;\\n uint256 newDebt;\\n uint256 newColl;\\n uint256 stake;\\n uint256 newNICR;\\n bool isRecoveryMode;\\n }\\n\\n struct LocalVariables_openTrove {\\n uint256 price;\\n uint256 ZUSDFee;\\n uint256 netDebt;\\n uint256 compositeDebt;\\n uint256 ICR;\\n uint256 NICR;\\n uint256 stake;\\n uint256 arrayIndex;\\n }\\n\\n struct ContractsCache {\\n ITroveManager troveManager;\\n IActivePool activePool;\\n IZUSDToken zusdToken;\\n }\\n\\n enum BorrowerOperation {\\n openTrove,\\n closeTrove,\\n adjustTrove\\n }\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n event MassetManagerAddressChanged(address _massetManagerAddress);\\n\\n event TroveCreated(address indexed _borrower, uint256 arrayIndex);\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n BorrowerOperation operation\\n );\\n event ZUSDBorrowingFeePaid(address indexed _borrower, uint256 _ZUSDFee);\\n\\n /** Constructor */\\n constructor(address _permit2) public {\\n permit2 = IPermit2(_permit2);\\n }\\n\\n // --- Dependency setters ---\\n\\n function setAddresses(\\n address _feeDistributorAddress,\\n address _liquityBaseParamsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _defaultPoolAddress,\\n address _stabilityPoolAddress,\\n address _gasPoolAddress,\\n address _collSurplusPoolAddress,\\n address _priceFeedAddress,\\n address _sortedTrovesAddress,\\n address _zusdTokenAddress,\\n address _zeroStakingAddress\\n ) external override onlyOwner {\\n // This makes impossible to open a trove with zero withdrawn ZUSD\\n assert(MIN_NET_DEBT > 0);\\n\\n checkContract(_feeDistributorAddress);\\n checkContract(_liquityBaseParamsAddress);\\n checkContract(_troveManagerAddress);\\n checkContract(_activePoolAddress);\\n checkContract(_defaultPoolAddress);\\n checkContract(_stabilityPoolAddress);\\n checkContract(_gasPoolAddress);\\n checkContract(_collSurplusPoolAddress);\\n checkContract(_priceFeedAddress);\\n checkContract(_sortedTrovesAddress);\\n checkContract(_zusdTokenAddress);\\n checkContract(_zeroStakingAddress);\\n\\n feeDistributor = IFeeDistributor(_feeDistributorAddress);\\n liquityBaseParams = ILiquityBaseParams(_liquityBaseParamsAddress);\\n troveManager = ITroveManager(_troveManagerAddress);\\n activePool = IActivePool(_activePoolAddress);\\n defaultPool = IDefaultPool(_defaultPoolAddress);\\n stabilityPoolAddress = _stabilityPoolAddress;\\n gasPoolAddress = _gasPoolAddress;\\n collSurplusPool = ICollSurplusPool(_collSurplusPoolAddress);\\n priceFeed = IPriceFeed(_priceFeedAddress);\\n sortedTroves = ISortedTroves(_sortedTrovesAddress);\\n zusdToken = IZUSDToken(_zusdTokenAddress);\\n zeroStakingAddress = _zeroStakingAddress;\\n zeroStaking = IZEROStaking(_zeroStakingAddress);\\n\\n emit FeeDistributorAddressChanged(_feeDistributorAddress);\\n emit TroveManagerAddressChanged(_troveManagerAddress);\\n emit ActivePoolAddressChanged(_activePoolAddress);\\n emit DefaultPoolAddressChanged(_defaultPoolAddress);\\n emit StabilityPoolAddressChanged(_stabilityPoolAddress);\\n emit GasPoolAddressChanged(_gasPoolAddress);\\n emit CollSurplusPoolAddressChanged(_collSurplusPoolAddress);\\n emit PriceFeedAddressChanged(_priceFeedAddress);\\n emit SortedTrovesAddressChanged(_sortedTrovesAddress);\\n emit ZUSDTokenAddressChanged(_zusdTokenAddress);\\n emit ZEROStakingAddressChanged(_zeroStakingAddress);\\n }\\n\\n function setMassetManagerAddress(address _massetManagerAddress) external onlyOwner {\\n massetManager = IMassetManager(_massetManagerAddress);\\n emit MassetManagerAddressChanged(_massetManagerAddress);\\n }\\n\\n function openTrove(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable override {\\n _openTrove(_maxFeePercentage, _ZUSDAmount, _upperHint, _lowerHint, msg.sender);\\n }\\n\\n function openNueTrove(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable override {\\n require(address(massetManager) != address(0), \\\"Masset address not set\\\");\\n\\n _openTrove(_maxFeePercentage, _ZUSDAmount, _upperHint, _lowerHint, address(this));\\n require(\\n zusdToken.approve(address(massetManager), _ZUSDAmount),\\n \\\"Failed to approve ZUSD amount for Mynt mAsset to redeem\\\"\\n );\\n massetManager.mintTo(address(zusdToken), _ZUSDAmount, msg.sender);\\n }\\n\\n // --- Borrower Trove Operations ---\\n function _openTrove(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint,\\n address _tokensRecipient\\n ) internal {\\n ContractsCache memory contractsCache = ContractsCache(troveManager, activePool, zusdToken);\\n LocalVariables_openTrove memory vars;\\n\\n vars.price = priceFeed.fetchPrice();\\n bool isRecoveryMode = _checkRecoveryMode(vars.price);\\n\\n _requireValidMaxFeePercentage(_maxFeePercentage, isRecoveryMode);\\n _requireTroveisNotActive(contractsCache.troveManager, msg.sender);\\n\\n vars.ZUSDFee;\\n vars.netDebt = _ZUSDAmount;\\n\\n if (!isRecoveryMode) {\\n vars.ZUSDFee = _triggerBorrowingFee(\\n contractsCache.troveManager,\\n contractsCache.zusdToken,\\n _ZUSDAmount,\\n _maxFeePercentage\\n );\\n vars.netDebt = vars.netDebt.add(vars.ZUSDFee);\\n }\\n _requireAtLeastMinNetDebt(vars.netDebt);\\n\\n // ICR is based on the composite debt, i.e. the requested ZUSD amount + ZUSD borrowing fee + ZUSD gas comp.\\n vars.compositeDebt = _getCompositeDebt(vars.netDebt);\\n assert(vars.compositeDebt > 0);\\n\\n vars.ICR = LiquityMath._computeCR(msg.value, vars.compositeDebt, vars.price);\\n vars.NICR = LiquityMath._computeNominalCR(msg.value, vars.compositeDebt);\\n\\n if (isRecoveryMode) {\\n _requireICRisAboveCCR(vars.ICR);\\n } else {\\n _requireICRisAboveMCR(vars.ICR);\\n uint256 newTCR = _getNewTCRFromTroveChange(\\n msg.value,\\n true,\\n vars.compositeDebt,\\n true,\\n vars.price\\n ); // bools: coll increase, debt increase\\n _requireNewTCRisAboveCCR(newTCR);\\n }\\n\\n // Set the trove struct's properties\\n contractsCache.troveManager.setTroveStatus(msg.sender, 1);\\n contractsCache.troveManager.increaseTroveColl(msg.sender, msg.value);\\n contractsCache.troveManager.increaseTroveDebt(msg.sender, vars.compositeDebt);\\n\\n contractsCache.troveManager.updateTroveRewardSnapshots(msg.sender);\\n vars.stake = contractsCache.troveManager.updateStakeAndTotalStakes(msg.sender);\\n\\n sortedTroves.insert(msg.sender, vars.NICR, _upperHint, _lowerHint);\\n vars.arrayIndex = contractsCache.troveManager.addTroveOwnerToArray(msg.sender);\\n emit TroveCreated(msg.sender, vars.arrayIndex);\\n\\n // Move the ether to the Active Pool, and mint the ZUSDAmount to the borrower\\n _activePoolAddColl(contractsCache.activePool, msg.value);\\n _mintZusdAndIncreaseActivePoolDebt(\\n contractsCache.activePool,\\n contractsCache.zusdToken,\\n _tokensRecipient,\\n _ZUSDAmount,\\n vars.netDebt\\n );\\n // Move the ZUSD gas compensation to the Gas Pool\\n _mintZusdAndIncreaseActivePoolDebt(\\n contractsCache.activePool,\\n contractsCache.zusdToken,\\n gasPoolAddress,\\n ZUSD_GAS_COMPENSATION,\\n ZUSD_GAS_COMPENSATION\\n );\\n\\n emit TroveUpdated(\\n msg.sender,\\n vars.compositeDebt,\\n msg.value,\\n vars.stake,\\n BorrowerOperation.openTrove\\n );\\n emit ZUSDBorrowingFeePaid(msg.sender, vars.ZUSDFee);\\n }\\n\\n /// Send ETH as collateral to a trove\\n function addColl(address _upperHint, address _lowerHint) external payable override {\\n _adjustTrove(msg.sender, 0, 0, false, _upperHint, _lowerHint, 0);\\n }\\n\\n /// Send ETH as collateral to a trove. Called by only the Stability Pool.\\n function moveETHGainToTrove(\\n address _borrower,\\n address _upperHint,\\n address _lowerHint\\n ) external payable override {\\n _requireCallerIsStabilityPool();\\n _adjustTrove(_borrower, 0, 0, false, _upperHint, _lowerHint, 0);\\n }\\n\\n /// Withdraw ETH collateral from a trove\\n function withdrawColl(\\n uint256 _collWithdrawal,\\n address _upperHint,\\n address _lowerHint\\n ) external override {\\n _adjustTrove(msg.sender, _collWithdrawal, 0, false, _upperHint, _lowerHint, 0);\\n }\\n\\n /// Withdraw ZUSD tokens from a trove: mint new ZUSD tokens to the owner, and increase the trove's debt accordingly\\n function withdrawZUSD(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external override {\\n _adjustTrove(msg.sender, 0, _ZUSDAmount, true, _upperHint, _lowerHint, _maxFeePercentage);\\n }\\n\\n /// Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction\\n /// Zero Line of Credit owner can borrow a specified amount of ZUSD and convert it to DLLR via Sovryn Mynt\\n ///@return DLLR amount minted\\n function withdrawZusdAndConvertToDLLR(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external override returns (uint256) {\\n address thisAddress = address(this);\\n uint256 balanceBefore = zusdToken.balanceOf(thisAddress);\\n\\n _withdrawZusdTo(\\n msg.sender,\\n thisAddress,\\n _ZUSDAmount,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage\\n );\\n\\n require(\\n zusdToken.balanceOf(thisAddress) == balanceBefore.add(_ZUSDAmount),\\n \\\"ZUSD is not borrowed correctly\\\"\\n );\\n require(\\n zusdToken.approve(address(massetManager), _ZUSDAmount),\\n \\\"Failed to approve ZUSD amount for Mynt mAsset to redeem\\\"\\n );\\n return massetManager.mintTo(address(zusdToken), _ZUSDAmount, msg.sender);\\n }\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZUSD(\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external override {\\n _adjustTrove(msg.sender, 0, _ZUSDAmount, false, _upperHint, _lowerHint, 0);\\n }\\n\\n /// Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly\\n function repayZusdFromDLLR(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external override {\\n _adjustNueTrove(0, 0, _dllrAmount, false, _upperHint, _lowerHint, _permitParams);\\n }\\n\\n /// Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly\\n function repayZusdFromDLLRWithPermit2(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external override {\\n _adjustNueTroveWithPermit2(0, 0, _dllrAmount, false, _upperHint, _lowerHint, _permit, _signature);\\n }\\n\\n function adjustTrove(\\n uint256 _maxFeePercentage,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint\\n ) external payable override {\\n _adjustTrove(\\n msg.sender,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage\\n );\\n }\\n\\n // in case of _isDebtIncrease = false MassetManager contract must have an approval of NUE tokens\\n function adjustNueTrove(\\n uint256 _maxFeePercentage,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external payable override {\\n _adjustNueTrove(\\n _maxFeePercentage,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _permitParams\\n );\\n }\\n\\n // in case of _isDebtIncrease = false MassetManager contract must have an approval of NUE tokens\\n function adjustNueTroveWithPermit2(\\n uint256 _maxFeePercentage,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external payable override {\\n _adjustNueTroveWithPermit2(\\n _maxFeePercentage,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _permit,\\n _signature\\n );\\n }\\n\\n // in case of _isDebtIncrease = false Masset Manager contract must have an approval of NUE tokens\\n function _adjustNueTrove(\\n uint256 _maxFeePercentage,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) internal {\\n require(address(massetManager) != address(0), \\\"Masset address not set\\\");\\n\\n if (!_isDebtIncrease && _ZUSDChange > 0) {\\n MyntLib.redeemZusdFromDllrWithPermit(\\n massetManager,\\n _ZUSDChange,\\n address(zusdToken),\\n _permitParams\\n );\\n }\\n _adjustSenderTrove(\\n msg.sender,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage,\\n address(this)\\n );\\n if (_isDebtIncrease && _ZUSDChange > 0) {\\n require(\\n zusdToken.approve(address(massetManager), _ZUSDChange),\\n \\\"Failed to approve ZUSD amount for Mynt mAsset to redeem\\\"\\n );\\n massetManager.mintTo(address(zusdToken), _ZUSDChange, msg.sender);\\n }\\n }\\n\\n // in case of _isDebtIncrease = false Masset Manager contract must have an approval of NUE tokens\\n function _adjustNueTroveWithPermit2(\\n uint256 _maxFeePercentage,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) internal {\\n require(address(massetManager) != address(0), \\\"Masset address not set\\\");\\n\\n if (!_isDebtIncrease && _ZUSDChange > 0) {\\n MyntLib.redeemZusdFromDllrWithPermit2(\\n massetManager,\\n address(zusdToken),\\n _permit,\\n permit2,\\n _signature\\n );\\n }\\n _adjustSenderTrove(\\n msg.sender,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage,\\n address(this)\\n );\\n if (_isDebtIncrease && _ZUSDChange > 0) {\\n require(\\n zusdToken.approve(address(massetManager), _ZUSDChange),\\n \\\"Failed to approve ZUSD amount for Mynt mAsset to redeem\\\"\\n );\\n massetManager.mintTo(address(zusdToken), _ZUSDChange, msg.sender);\\n }\\n }\\n\\n function _adjustTrove(\\n address _borrower,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n uint256 _maxFeePercentage\\n ) internal {\\n _adjustSenderTrove(\\n _borrower,\\n _collWithdrawal,\\n _ZUSDChange,\\n _isDebtIncrease,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage,\\n msg.sender\\n );\\n }\\n\\n // _withdrawZusd: _adjustTrove(msg.sender, 0, _ZUSDAmount, true, _upperHint, _lowerHint, _maxFeePercentage);\\n function _withdrawZusdTo(\\n address _borrower,\\n address _receiver,\\n uint256 _ZUSDChange,\\n address _upperHint,\\n address _lowerHint,\\n uint256 _maxFeePercentage\\n ) internal {\\n _adjustSenderTrove(\\n _borrower,\\n 0,\\n _ZUSDChange,\\n true,\\n _upperHint,\\n _lowerHint,\\n _maxFeePercentage,\\n _receiver\\n );\\n }\\n\\n /**\\n * _adjustSenderTrove(): Alongside a debt change, this function can perform either a collateral top-up or a collateral withdrawal.\\n *\\n * It therefore expects either a positive msg.value, or a positive _collWithdrawal argument.\\n *\\n * If both are positive, it will revert.\\n */\\n function _adjustSenderTrove(\\n address _borrower,\\n uint256 _collWithdrawal,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n uint256 _maxFeePercentage,\\n address _tokensRecipient\\n ) internal {\\n ContractsCache memory contractsCache = ContractsCache(troveManager, activePool, zusdToken);\\n LocalVariables_adjustTrove memory vars;\\n\\n vars.price = priceFeed.fetchPrice();\\n vars.isRecoveryMode = _checkRecoveryMode(vars.price);\\n\\n if (_isDebtIncrease) {\\n _requireValidMaxFeePercentage(_maxFeePercentage, vars.isRecoveryMode);\\n _requireNonZeroDebtChange(_ZUSDChange);\\n }\\n _requireSingularCollChange(_collWithdrawal);\\n _requireNonZeroAdjustment(_collWithdrawal, _ZUSDChange);\\n _requireTroveisActive(contractsCache.troveManager, _borrower);\\n\\n // Confirm the operation is either a borrower adjusting their own trove, or a pure ETH transfer from the Stability Pool to a trove\\n assert(\\n msg.sender == _borrower ||\\n (msg.sender == stabilityPoolAddress && msg.value > 0 && _ZUSDChange == 0)\\n );\\n\\n contractsCache.troveManager.applyPendingRewards(_borrower);\\n\\n // Get the collChange based on whether or not ETH was sent in the transaction\\n (vars.collChange, vars.isCollIncrease) = _getCollChange(msg.value, _collWithdrawal);\\n\\n vars.netDebtChange = _ZUSDChange;\\n\\n // If the adjustment incorporates a debt increase and system is in Normal Mode, then trigger a borrowing fee\\n if (_isDebtIncrease && !vars.isRecoveryMode) {\\n vars.ZUSDFee = _triggerBorrowingFee(\\n contractsCache.troveManager,\\n contractsCache.zusdToken,\\n _ZUSDChange,\\n _maxFeePercentage\\n );\\n vars.netDebtChange = vars.netDebtChange.add(vars.ZUSDFee); // The raw debt change includes the fee\\n }\\n\\n vars.debt = contractsCache.troveManager.getTroveDebt(_borrower);\\n vars.coll = contractsCache.troveManager.getTroveColl(_borrower);\\n\\n // Get the trove's old ICR before the adjustment, and what its new ICR will be after the adjustment\\n vars.oldICR = LiquityMath._computeCR(vars.coll, vars.debt, vars.price);\\n vars.newICR = _getNewICRFromTroveChange(\\n vars.coll,\\n vars.debt,\\n vars.collChange,\\n vars.isCollIncrease,\\n vars.netDebtChange,\\n _isDebtIncrease,\\n vars.price\\n );\\n assert(_collWithdrawal <= vars.coll);\\n\\n // Check the adjustment satisfies all conditions for the current system mode\\n _requireValidAdjustmentInCurrentMode(\\n vars.isRecoveryMode,\\n _collWithdrawal,\\n _isDebtIncrease,\\n vars\\n );\\n\\n // When the adjustment is a debt repayment, check it's a valid amount and that the caller has enough ZUSD\\n if (!_isDebtIncrease && _ZUSDChange > 0) {\\n _requireAtLeastMinNetDebt(_getNetDebt(vars.debt).sub(vars.netDebtChange));\\n _requireValidZUSDRepayment(vars.debt, vars.netDebtChange);\\n _requireSufficientZUSDBalance(contractsCache.zusdToken, _borrower, vars.netDebtChange);\\n }\\n\\n (vars.newColl, vars.newDebt) = _updateTroveFromAdjustment(\\n contractsCache.troveManager,\\n _borrower,\\n vars.collChange,\\n vars.isCollIncrease,\\n vars.netDebtChange,\\n _isDebtIncrease\\n );\\n vars.stake = contractsCache.troveManager.updateStakeAndTotalStakes(_borrower);\\n\\n // Re-insert trove in to the sorted list\\n vars.newNICR = _getNewNominalICRFromTroveChange(\\n vars.coll,\\n vars.debt,\\n vars.collChange,\\n vars.isCollIncrease,\\n vars.netDebtChange,\\n _isDebtIncrease\\n );\\n sortedTroves.reInsert(_borrower, vars.newNICR, _upperHint, _lowerHint);\\n\\n emit TroveUpdated(\\n _borrower,\\n vars.newDebt,\\n vars.newColl,\\n vars.stake,\\n BorrowerOperation.adjustTrove\\n );\\n emit ZUSDBorrowingFeePaid(msg.sender, vars.ZUSDFee);\\n\\n // Use the unmodified _ZUSDChange here, as we don't send the fee to the user\\n _moveTokensAndETHfromAdjustment(\\n contractsCache.activePool,\\n contractsCache.zusdToken,\\n msg.sender,\\n vars.collChange,\\n vars.isCollIncrease,\\n _ZUSDChange,\\n _isDebtIncrease,\\n vars.netDebtChange,\\n _tokensRecipient\\n );\\n }\\n\\n function closeTrove() external override {\\n _closeTrove();\\n }\\n\\n function closeNueTrove(IMassetManager.PermitParams calldata _permitParams) external override {\\n require(address(massetManager) != address(0), \\\"Masset address not set\\\");\\n\\n uint256 debt = troveManager.getTroveDebt(msg.sender);\\n\\n MyntLib.redeemZusdFromDllrWithPermit(\\n massetManager,\\n debt.sub(ZUSD_GAS_COMPENSATION),\\n address(zusdToken),\\n _permitParams\\n );\\n _closeTrove();\\n }\\n\\n function closeNueTroveWithPermit2(ISignatureTransfer.PermitTransferFrom memory _permit, bytes calldata _signature) external override {\\n require(address(massetManager) != address(0), \\\"Masset address not set\\\");\\n\\n uint256 debt = troveManager.getTroveDebt(msg.sender);\\n\\n MyntLib.redeemZusdFromDllrWithPermit2(\\n massetManager,\\n address(zusdToken),\\n _permit,\\n permit2,\\n _signature\\n );\\n\\n _closeTrove();\\n }\\n\\n function _closeTrove() internal {\\n ITroveManager troveManagerCached = troveManager;\\n IActivePool activePoolCached = activePool;\\n IZUSDToken zusdTokenCached = zusdToken;\\n\\n _requireTroveisActive(troveManagerCached, msg.sender);\\n uint256 price = priceFeed.fetchPrice();\\n _requireNotInRecoveryMode(price);\\n\\n troveManagerCached.applyPendingRewards(msg.sender);\\n\\n uint256 coll = troveManagerCached.getTroveColl(msg.sender);\\n uint256 debt = troveManagerCached.getTroveDebt(msg.sender);\\n\\n _requireSufficientZUSDBalance(\\n zusdTokenCached,\\n msg.sender,\\n debt.sub(ZUSD_GAS_COMPENSATION)\\n );\\n\\n uint256 newTCR = _getNewTCRFromTroveChange(coll, false, debt, false, price);\\n _requireNewTCRisAboveCCR(newTCR);\\n\\n troveManagerCached.removeStake(msg.sender);\\n troveManagerCached.closeTrove(msg.sender);\\n\\n emit TroveUpdated(msg.sender, 0, 0, 0, BorrowerOperation.closeTrove);\\n\\n // Burn the repaid ZUSD from the user's balance and the gas compensation from the Gas Pool\\n _burnZusdAndDecreaseActivePoolDebt(\\n activePoolCached,\\n zusdTokenCached,\\n msg.sender,\\n debt.sub(ZUSD_GAS_COMPENSATION)\\n );\\n _burnZusdAndDecreaseActivePoolDebt(\\n activePoolCached,\\n zusdTokenCached,\\n gasPoolAddress,\\n ZUSD_GAS_COMPENSATION\\n );\\n\\n // Send the collateral back to the user\\n activePoolCached.sendETH(msg.sender, coll);\\n }\\n\\n /**\\n * Claim remaining collateral from a redemption or from a liquidation with ICR > MCR in Recovery Mode\\n */\\n function claimCollateral() external override {\\n // send ETH from CollSurplus Pool to owner\\n collSurplusPool.claimColl(msg.sender);\\n }\\n\\n // --- Helper functions ---\\n\\n function _triggerBorrowingFee(\\n ITroveManager _troveManager,\\n IZUSDToken _zusdToken,\\n uint256 _ZUSDAmount,\\n uint256 _maxFeePercentage\\n ) internal returns (uint256) {\\n _troveManager.decayBaseRateFromBorrowing(); // decay the baseRate state variable\\n uint256 ZUSDFee = _troveManager.getBorrowingFee(_ZUSDAmount);\\n\\n _requireUserAcceptsFee(ZUSDFee, _ZUSDAmount, _maxFeePercentage);\\n _zusdToken.mint(address(feeDistributor), ZUSDFee);\\n feeDistributor.distributeFees();\\n\\n return ZUSDFee;\\n }\\n\\n function _getUSDValue(uint256 _coll, uint256 _price) internal pure returns (uint256) {\\n uint256 usdValue = _price.mul(_coll).div(DECIMAL_PRECISION);\\n\\n return usdValue;\\n }\\n\\n function _getCollChange(uint256 _collReceived, uint256 _requestedCollWithdrawal)\\n internal\\n pure\\n returns (uint256 collChange, bool isCollIncrease)\\n {\\n if (_collReceived != 0) {\\n collChange = _collReceived;\\n isCollIncrease = true;\\n } else {\\n collChange = _requestedCollWithdrawal;\\n }\\n }\\n\\n /// Update trove's coll and debt based on whether they increase or decrease\\n function _updateTroveFromAdjustment(\\n ITroveManager _troveManager,\\n address _borrower,\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _debtChange,\\n bool _isDebtIncrease\\n ) internal returns (uint256, uint256) {\\n uint256 newColl = (_isCollIncrease)\\n ? _troveManager.increaseTroveColl(_borrower, _collChange)\\n : _troveManager.decreaseTroveColl(_borrower, _collChange);\\n uint256 newDebt = (_isDebtIncrease)\\n ? _troveManager.increaseTroveDebt(_borrower, _debtChange)\\n : _troveManager.decreaseTroveDebt(_borrower, _debtChange);\\n\\n return (newColl, newDebt);\\n }\\n\\n function _moveTokensAndETHfromAdjustment(\\n IActivePool _activePool,\\n IZUSDToken _zusdToken,\\n address _borrower,\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _ZUSDChange,\\n bool _isDebtIncrease,\\n uint256 _netDebtChange,\\n address _tokensRecipient\\n ) internal {\\n if (_isDebtIncrease) {\\n _mintZusdAndIncreaseActivePoolDebt(\\n _activePool,\\n _zusdToken,\\n _tokensRecipient,\\n _ZUSDChange,\\n _netDebtChange\\n );\\n } else {\\n _burnZusdAndDecreaseActivePoolDebt(_activePool, _zusdToken, _borrower, _ZUSDChange);\\n }\\n\\n if (_isCollIncrease) {\\n _activePoolAddColl(_activePool, _collChange);\\n } else {\\n _activePool.sendETH(_borrower, _collChange);\\n }\\n }\\n\\n /// Send ETH to Active Pool and increase its recorded ETH balance\\n function _activePoolAddColl(IActivePool _activePool, uint256 _amount) internal {\\n (bool success, ) = address(_activePool).call{ value: _amount }(\\\"\\\");\\n require(success, \\\"BorrowerOps: Sending ETH to ActivePool failed\\\");\\n }\\n\\n /// Issue the specified amount of ZUSD to _account and increases the total active debt (_netDebtIncrease potentially includes a ZUSDFee)\\n function _mintZusdAndIncreaseActivePoolDebt(\\n IActivePool _activePool,\\n IZUSDToken _zusdToken,\\n address _account,\\n uint256 _ZUSDAmount,\\n uint256 _netDebtIncrease\\n ) internal {\\n _activePool.increaseZUSDDebt(_netDebtIncrease);\\n _zusdToken.mint(_account, _ZUSDAmount);\\n }\\n\\n /// Burn the specified amount of ZUSD from _account and decreases the total active debt\\n function _burnZusdAndDecreaseActivePoolDebt(\\n IActivePool _activePool,\\n IZUSDToken _zusdToken,\\n address _account,\\n uint256 _ZUSD\\n ) internal {\\n _activePool.decreaseZUSDDebt(_ZUSD);\\n _zusdToken.burn(_account, _ZUSD);\\n }\\n\\n // --- 'Require' wrapper functions ---\\n\\n function _requireSingularCollChange(uint256 _collWithdrawal) internal view {\\n require(\\n msg.value == 0 || _collWithdrawal == 0,\\n \\\"BorrowerOperations: Cannot withdraw and add coll\\\"\\n );\\n }\\n\\n function _requireCallerIsBorrower(address _borrower) internal view {\\n require(\\n msg.sender == _borrower,\\n \\\"BorrowerOps: Caller must be the borrower for a withdrawal\\\"\\n );\\n }\\n\\n function _requireNonZeroAdjustment(uint256 _collWithdrawal, uint256 _ZUSDChange)\\n internal\\n view\\n {\\n require(\\n msg.value != 0 || _collWithdrawal != 0 || _ZUSDChange != 0,\\n \\\"BorrowerOps: There must be either a collateral change or a debt change\\\"\\n );\\n }\\n\\n function _requireTroveisActive(ITroveManager _troveManager, address _borrower) internal view {\\n uint256 status = _troveManager.getTroveStatus(_borrower);\\n require(status == 1, \\\"BorrowerOps: Trove does not exist or is closed\\\");\\n }\\n\\n function _requireTroveisNotActive(ITroveManager _troveManager, address _borrower)\\n internal\\n view\\n {\\n uint256 status = _troveManager.getTroveStatus(_borrower);\\n require(status != 1, \\\"BorrowerOps: Trove is active\\\");\\n }\\n\\n function _requireNonZeroDebtChange(uint256 _ZUSDChange) internal pure {\\n require(_ZUSDChange > 0, \\\"BorrowerOps: Debt increase requires non-zero debtChange\\\");\\n }\\n\\n function _requireNotInRecoveryMode(uint256 _price) internal view {\\n require(\\n !_checkRecoveryMode(_price),\\n \\\"BorrowerOps: Operation not permitted during Recovery Mode\\\"\\n );\\n }\\n\\n function _requireNoCollWithdrawal(uint256 _collWithdrawal) internal pure {\\n require(\\n _collWithdrawal == 0,\\n \\\"BorrowerOps: Collateral withdrawal not permitted Recovery Mode\\\"\\n );\\n }\\n\\n function _requireValidAdjustmentInCurrentMode(\\n bool _isRecoveryMode,\\n uint256 _collWithdrawal,\\n bool _isDebtIncrease,\\n LocalVariables_adjustTrove memory _vars\\n ) internal view {\\n /*\\n *In Recovery Mode, only allow:\\n *\\n * - Pure collateral top-up\\n * - Pure debt repayment\\n * - Collateral top-up with debt repayment\\n * - A debt increase combined with a collateral top-up which makes the ICR >= 150% and improves the ICR (and by extension improves the TCR).\\n *\\n * In Normal Mode, ensure:\\n *\\n * - The new ICR is above MCR\\n * - The adjustment won't pull the TCR below CCR\\n */\\n if (_isRecoveryMode) {\\n _requireNoCollWithdrawal(_collWithdrawal);\\n if (_isDebtIncrease) {\\n _requireICRisAboveCCR(_vars.newICR);\\n _requireNewICRisAboveOldICR(_vars.newICR, _vars.oldICR);\\n }\\n } else {\\n // if Normal Mode\\n _requireICRisAboveMCR(_vars.newICR);\\n _vars.newTCR = _getNewTCRFromTroveChange(\\n _vars.collChange,\\n _vars.isCollIncrease,\\n _vars.netDebtChange,\\n _isDebtIncrease,\\n _vars.price\\n );\\n _requireNewTCRisAboveCCR(_vars.newTCR);\\n }\\n }\\n\\n function _requireICRisAboveMCR(uint256 _newICR) internal view {\\n require(\\n _newICR >= liquityBaseParams.MCR(),\\n \\\"BorrowerOps: An operation that would result in ICR < MCR is not permitted\\\"\\n );\\n }\\n\\n function _requireICRisAboveCCR(uint256 _newICR) internal view {\\n require(\\n _newICR >= liquityBaseParams.CCR(),\\n \\\"BorrowerOps: Operation must leave trove with ICR >= CCR\\\"\\n );\\n }\\n\\n function _requireNewICRisAboveOldICR(uint256 _newICR, uint256 _oldICR) internal pure {\\n require(\\n _newICR >= _oldICR,\\n \\\"BorrowerOps: Cannot decrease your Trove's ICR in Recovery Mode\\\"\\n );\\n }\\n\\n function _requireNewTCRisAboveCCR(uint256 _newTCR) internal view {\\n require(\\n _newTCR >= liquityBaseParams.CCR(),\\n \\\"BorrowerOps: An operation that would result in TCR < CCR is not permitted\\\"\\n );\\n }\\n\\n function _requireAtLeastMinNetDebt(uint256 _netDebt) internal pure {\\n require(\\n _netDebt >= MIN_NET_DEBT,\\n \\\"BorrowerOps: Trove's net debt must be greater than minimum\\\"\\n );\\n }\\n\\n function _requireValidZUSDRepayment(uint256 _currentDebt, uint256 _debtRepayment)\\n internal\\n pure\\n {\\n require(\\n _debtRepayment <= _currentDebt.sub(ZUSD_GAS_COMPENSATION),\\n \\\"BorrowerOps: Amount repaid must not be larger than the Trove's debt\\\"\\n );\\n }\\n\\n function _requireCallerIsStabilityPool() internal view {\\n require(msg.sender == stabilityPoolAddress, \\\"BorrowerOps: Caller is not Stability Pool\\\");\\n }\\n\\n function _requireSufficientZUSDBalance(\\n IZUSDToken _zusdToken,\\n address _borrower,\\n uint256 _debtRepayment\\n ) internal view {\\n require(\\n _zusdToken.balanceOf(_borrower) >= _debtRepayment,\\n \\\"BorrowerOps: Caller doesnt have enough ZUSD to make repayment\\\"\\n );\\n }\\n\\n function _requireValidMaxFeePercentage(uint256 _maxFeePercentage, bool _isRecoveryMode)\\n internal\\n view\\n {\\n if (_isRecoveryMode) {\\n require(\\n _maxFeePercentage <= DECIMAL_PRECISION,\\n \\\"Max fee percentage must less than or equal to 100%\\\"\\n );\\n } else {\\n require(\\n _maxFeePercentage >= liquityBaseParams.BORROWING_FEE_FLOOR() &&\\n _maxFeePercentage <= DECIMAL_PRECISION,\\n \\\"Max fee percentage must be between 0.5% and 100%\\\"\\n );\\n }\\n }\\n\\n // --- ICR and TCR getters ---\\n\\n /// Compute the new collateral ratio, considering the change in coll and debt. Assumes 0 pending rewards.\\n function _getNewNominalICRFromTroveChange(\\n uint256 _coll,\\n uint256 _debt,\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _debtChange,\\n bool _isDebtIncrease\\n ) internal pure returns (uint256) {\\n (uint256 newColl, uint256 newDebt) = _getNewTroveAmounts(\\n _coll,\\n _debt,\\n _collChange,\\n _isCollIncrease,\\n _debtChange,\\n _isDebtIncrease\\n );\\n\\n uint256 newNICR = LiquityMath._computeNominalCR(newColl, newDebt);\\n return newNICR;\\n }\\n\\n /// Compute the new collateral ratio, considering the change in coll and debt. Assumes 0 pending rewards.\\n function _getNewICRFromTroveChange(\\n uint256 _coll,\\n uint256 _debt,\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _debtChange,\\n bool _isDebtIncrease,\\n uint256 _price\\n ) internal pure returns (uint256) {\\n (uint256 newColl, uint256 newDebt) = _getNewTroveAmounts(\\n _coll,\\n _debt,\\n _collChange,\\n _isCollIncrease,\\n _debtChange,\\n _isDebtIncrease\\n );\\n\\n uint256 newICR = LiquityMath._computeCR(newColl, newDebt, _price);\\n return newICR;\\n }\\n\\n function _getNewTroveAmounts(\\n uint256 _coll,\\n uint256 _debt,\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _debtChange,\\n bool _isDebtIncrease\\n ) internal pure returns (uint256, uint256) {\\n uint256 newColl = _coll;\\n uint256 newDebt = _debt;\\n\\n newColl = _isCollIncrease ? _coll.add(_collChange) : _coll.sub(_collChange);\\n newDebt = _isDebtIncrease ? _debt.add(_debtChange) : _debt.sub(_debtChange);\\n\\n return (newColl, newDebt);\\n }\\n\\n function _getNewTCRFromTroveChange(\\n uint256 _collChange,\\n bool _isCollIncrease,\\n uint256 _debtChange,\\n bool _isDebtIncrease,\\n uint256 _price\\n ) internal view returns (uint256) {\\n uint256 totalColl = getEntireSystemColl();\\n uint256 totalDebt = getEntireSystemDebt();\\n\\n totalColl = _isCollIncrease ? totalColl.add(_collChange) : totalColl.sub(_collChange);\\n totalDebt = _isDebtIncrease ? totalDebt.add(_debtChange) : totalDebt.sub(_debtChange);\\n\\n uint256 newTCR = LiquityMath._computeCR(totalColl, totalDebt, _price);\\n return newTCR;\\n }\\n\\n function getCompositeDebt(uint256 _debt) external view override returns (uint256) {\\n return _getCompositeDebt(_debt);\\n }\\n\\n function BORROWING_FEE_FLOOR() external view override returns (uint256) {\\n return liquityBaseParams.BORROWING_FEE_FLOOR();\\n }\\n\\n function getMassetManager() external view override returns (IMassetManager) {\\n return massetManager;\\n }\\n}\\n\",\"keccak256\":\"0x957479bda38a67e573ea703be0178601a038fad630b4d3a8b6be5b291bf3b641\",\"license\":\"MIT\"},\"contracts/BorrowerOperationsStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./Interfaces/IActivePool.sol\\\";\\nimport \\\"./Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./Interfaces/ITroveManager.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/IZEROStaking.sol\\\";\\nimport \\\"./Interfaces/IFeeDistributor.sol\\\";\\nimport \\\"./Dependencies/Ownable.sol\\\";\\nimport \\\"./Dependencies/Mynt/IMassetManager.sol\\\";\\n\\ncontract BorrowerOperationsStorage is Ownable {\\n string public constant NAME = \\\"BorrowerOperations\\\";\\n\\n // --- Connected contract declarations ---\\n\\n ITroveManager public troveManager;\\n\\n address stabilityPoolAddress;\\n\\n address gasPoolAddress;\\n\\n ICollSurplusPool collSurplusPool;\\n\\n IZEROStaking public zeroStaking;\\n address public zeroStakingAddress;\\n\\n IZUSDToken public zusdToken;\\n\\n // A doubly linked list of Troves, sorted by their collateral ratios\\n ISortedTroves public sortedTroves;\\n\\n IMassetManager public massetManager;\\n IFeeDistributor public feeDistributor;\\n}\\n\",\"keccak256\":\"0x5708a00804a19b3fb47bc20dc2457775228a3d7b09c4f5b33d11c4995fe77c94\",\"license\":\"MIT\"},\"contracts/Dependencies/BaseMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\n\\ncontract BaseMath {\\n uint constant public DECIMAL_PRECISION = 1e18;\\n}\\n\",\"keccak256\":\"0x7e1369ca5cb09e818e345a2def19a261401f79c985a6030b55b7311dd6f53be4\",\"license\":\"MIT\"},\"contracts/Dependencies/CheckContract.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n\\ncontract CheckContract {\\n /**\\n * @dev Check that the account is an already deployed non-destroyed contract.\\n * See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L12\\n */\\n function checkContract(address _account) internal view {\\n require(_account != address(0), \\\"Account cannot be zero address\\\");\\n\\n uint256 size;\\n // solhint-disable-next-line no-inline-assembly\\n assembly { size := extcodesize(_account) }\\n require(size > 0, \\\"Account code size cannot be zero\\\");\\n }\\n}\\n\",\"keccak256\":\"0x4c7dc4d0197c27ebc7de671b00458a9ff45f57223aeb520e6ddd2eb6d2d89e5c\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on the OpenZeppelin IER20 interface:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol\\n *\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\\n function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n function name() external view returns (string memory);\\n function symbol() external view returns (string memory);\\n function decimals() external view returns (uint8);\\n \\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\",\"keccak256\":\"0xe0b2473eba89df8d27d7cea2a99fce788c212f3fd393c9508e449e51a3f220fa\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC2612.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * @dev Interface of the ERC2612 standard as defined in the EIP.\\n *\\n * Adds the {permit} method, which can be used to change one's\\n * {IERC20-allowance} without having to send a transaction, by signing a\\n * message. This allows users to spend tokens without having to hold Ether.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2612.\\n * \\n * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/\\n */\\ninterface IERC2612 {\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,\\n * given `owner`'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(address owner, address spender, uint256 amount, \\n uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;\\n \\n /**\\n * @dev Returns the current ERC2612 nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases `owner`'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n *\\n * `owner` can limit the time a Permit is valid for by setting `deadline` to \\n * a value in the near future. The deadline argument can be set to uint(-1) to \\n * create Permits that effectively never expire.\\n */\\n function nonces(address owner) external view returns (uint256);\\n \\n function version() external view returns (string memory);\\n function permitTypeHash() external view returns (bytes32);\\n function domainSeparator() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xd376458452f8b480bfea549637bd71d3f9eb1f12e9d59d1beff373417462d67f\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./BaseMath.sol\\\";\\nimport \\\"./LiquityMath.sol\\\";\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IPriceFeed.sol\\\";\\nimport \\\"../Interfaces/ILiquityBase.sol\\\";\\nimport \\\"../Interfaces/ILiquityBaseParams.sol\\\";\\n\\n/**\\n * Base contract for TroveManager, BorrowerOperations and StabilityPool. Contains global system constants and\\n * common functions.\\n */\\ncontract LiquityBase is BaseMath, ILiquityBase {\\n using SafeMath for uint256;\\n\\n uint256 public constant _100pct = 1000000000000000000; // 1e18 == 100%\\n\\n /// Amount of ZUSD to be locked in gas pool on opening troves\\n uint256 public constant ZUSD_GAS_COMPENSATION = 20e18;\\n\\n /// Minimum amount of net ZUSD debt a trove must have\\n uint256 public constant MIN_NET_DEBT = 180e18;\\n\\n IActivePool public activePool;\\n\\n IDefaultPool public defaultPool;\\n\\n IPriceFeed public override priceFeed;\\n\\n ILiquityBaseParams public override liquityBaseParams;\\n\\n // --- Gas compensation functions ---\\n\\n // Returns the composite debt (drawn debt + gas compensation) of a trove, for the purpose of ICR calculation\\n function _getCompositeDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.add(ZUSD_GAS_COMPENSATION);\\n }\\n\\n function _getNetDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.sub(ZUSD_GAS_COMPENSATION);\\n }\\n\\n /// Return the amount of ETH to be drawn from a trove's collateral and sent as gas compensation.\\n function _getCollGasCompensation(uint256 _entireColl) internal view returns (uint256) {\\n return _entireColl / liquityBaseParams.PERCENT_DIVISOR();\\n }\\n\\n function getEntireSystemColl() public view returns (uint256 entireSystemColl) {\\n uint256 activeColl = activePool.getETH();\\n uint256 liquidatedColl = defaultPool.getETH();\\n\\n return activeColl.add(liquidatedColl);\\n }\\n\\n function getEntireSystemDebt() public view returns (uint256 entireSystemDebt) {\\n uint256 activeDebt = activePool.getZUSDDebt();\\n uint256 closedDebt = defaultPool.getZUSDDebt();\\n\\n return activeDebt.add(closedDebt);\\n }\\n\\n function _getTCR(uint256 _price) internal view returns (uint256 TCR) {\\n uint256 entireSystemColl = getEntireSystemColl();\\n uint256 entireSystemDebt = getEntireSystemDebt();\\n\\n TCR = LiquityMath._computeCR(entireSystemColl, entireSystemDebt, _price);\\n\\n return TCR;\\n }\\n\\n function _checkRecoveryMode(uint256 _price) internal view returns (bool) {\\n uint256 TCR = _getTCR(_price);\\n\\n return TCR < liquityBaseParams.CCR();\\n }\\n\\n function _requireUserAcceptsFee(\\n uint256 _fee,\\n uint256 _amount,\\n uint256 _maxFeePercentage\\n ) internal pure {\\n uint256 feePercentage = _fee.mul(DECIMAL_PRECISION).div(_amount);\\n require(feePercentage <= _maxFeePercentage, \\\"Fee exceeded provided maximum\\\");\\n }\\n}\\n\",\"keccak256\":\"0x100b8a1c17caa95f5c9977e88f9263847a1977a365ca0a795753dd74aa1d6d7c\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./console.sol\\\";\\n\\nlibrary LiquityMath {\\n using SafeMath for uint;\\n\\n uint internal constant DECIMAL_PRECISION = 1e18;\\n\\n /* Precision for Nominal ICR (independent of price). Rationale for the value:\\n *\\n * - Making it \\u201ctoo high\\u201d could lead to overflows.\\n * - Making it \\u201ctoo low\\u201d could lead to an ICR equal to zero, due to truncation from Solidity floor division. \\n *\\n * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH,\\n * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.\\n *\\n */\\n uint internal constant NICR_PRECISION = 1e20;\\n\\n function _min(uint _a, uint _b) internal pure returns (uint) {\\n return (_a < _b) ? _a : _b;\\n }\\n\\n function _max(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a : _b;\\n }\\n\\n /* \\n * Multiply two decimal numbers and use normal rounding rules:\\n * -round product up if 19'th mantissa digit >= 5\\n * -round product down if 19'th mantissa digit < 5\\n *\\n * Used only inside the exponentiation, _decPow().\\n */\\n function decMul(uint x, uint y) internal pure returns (uint decProd) {\\n uint prod_xy = x.mul(y);\\n\\n decProd = prod_xy.add(DECIMAL_PRECISION / 2).div(DECIMAL_PRECISION);\\n }\\n\\n /* \\n * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.\\n * \\n * Uses the efficient \\\"exponentiation by squaring\\\" algorithm. O(log(n)) complexity. \\n * \\n * Called by two functions that represent time in units of minutes:\\n * 1) TroveManager._calcDecayedBaseRate\\n * 2) CommunityIssuance._getCumulativeIssuanceFraction \\n * \\n * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals\\n * \\\"minutes in 1000 years\\\": 60 * 24 * 365 * 1000\\n * \\n * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be\\n * negligibly different from just passing the cap, since: \\n *\\n * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years\\n * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible\\n */\\n function _decPow(uint _base, uint _minutes) internal pure returns (uint) {\\n \\n if (_minutes > 525600000) {_minutes = 525600000;} // cap to avoid overflow\\n \\n if (_minutes == 0) {return DECIMAL_PRECISION;}\\n\\n uint y = DECIMAL_PRECISION;\\n uint x = _base;\\n uint n = _minutes;\\n\\n // Exponentiation-by-squaring\\n while (n > 1) {\\n if (n % 2 == 0) {\\n x = decMul(x, x);\\n n = n.div(2);\\n } else { // if (n % 2 != 0)\\n y = decMul(x, y);\\n x = decMul(x, x);\\n n = (n.sub(1)).div(2);\\n }\\n }\\n\\n return decMul(x, y);\\n }\\n\\n function _getAbsoluteDifference(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a.sub(_b) : _b.sub(_a);\\n }\\n\\n function _computeNominalCR(uint _coll, uint _debt) internal pure returns (uint) {\\n if (_debt > 0) {\\n return _coll.mul(NICR_PRECISION).div(_debt);\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1;\\n }\\n }\\n\\n function _computeCR(uint _coll, uint _debt, uint _price) internal pure returns (uint) {\\n if (_debt > 0) {\\n uint newCollRatio = _coll.mul(_price).div(_debt);\\n\\n return newCollRatio;\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1; \\n }\\n }\\n}\\n\",\"keccak256\":\"0x7a95ed70d8937e0896c054b433ad0dfc87a9cfd028cae1694098e9d5d68127cd\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IDLLR.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\nimport \\\"../IERC20.sol\\\";\\n\\n/// Public interface for Sovryn Dollar DLLR (Meta Asset Token of Sovryn Mynt) exposing specific functions\\ninterface IDLLR is IERC20 {\\n /**\\n * @notice Only owner can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _recipient Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transfer(address _recipient, uint256 _amount) external override returns (bool);\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _amount\\n ) external override returns (bool);\\n\\n /**\\n * @notice transfer utilizing EIP-2612, to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @dev By calling this function, the allowance will be overwritten by the total amount.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of the token that will be transferred.\\n * @param _deadline Expiration time of the signature.\\n * @param _v Last 1 byte of ECDSA signature.\\n * @param _r First 32 bytes of ECDSA signature.\\n * @param _s 32 bytes after _r in ECDSA signature.\\n */\\n function transferWithPermit(\\n address _from,\\n address _to,\\n uint256 _amount,\\n uint256 _deadline,\\n uint8 _v,\\n bytes32 _r,\\n bytes32 _s\\n ) external;\\n\\n /**\\n * @notice Approves and then calls the receiving contract.\\n * Useful to encapsulate sending tokens to a contract in one call.\\n * Solidity has no native way to send tokens to contracts.\\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\\n * @param _spender The contract address to spend the tokens.\\n * @param _amount The amount of tokens to be sent.\\n * @param _data Parameters for the contract call, such as endpoint signature.\\n */\\n function approveAndCall(address _spender, uint256 _amount, bytes calldata _data) external;\\n}\\n\",\"keccak256\":\"0x1fcc09759323769fcaa430bef598cf08a9f5e98ce6a9bdd6faa79d8b7b6ecce2\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IMassetManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IMassetManager {\\n struct PermitParams {\\n uint256 deadline;\\n uint8 v;\\n bytes32 r;\\n bytes32 s;\\n }\\n\\n function mintTo(\\n address _bAsset,\\n uint256 _bAssetQuantity,\\n address _recipient\\n ) external returns (uint256);\\n\\n function getToken() external view returns (address);\\n\\n /**\\n * @dev Credits a recipient with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @param _recipient Address to credit with withdrawn bAssets.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeemTo(\\n address _bAsset,\\n uint256 _massetQuantity,\\n address _recipient\\n ) external returns (uint256 massetRedeemed);\\n}\\n\",\"keccak256\":\"0x3e8de462d45e8f07ef83b6b6e7eb90a5d09f21d3bcbb1225e8f781488ab4a771\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/MyntLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IMassetManager.sol\\\";\\nimport \\\"./IDLLR.sol\\\";\\nimport \\\"../SafeMath.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"../../Interfaces/IPermit2.sol\\\";\\n\\nlibrary MyntLib {\\n using SafeMath for uint256;\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @dev WARNING!! Do not us this lib function on RSK network because there is a griefing attack issue in the DLLR contract.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _dllrAmount The amount of the DLLR (mAsset) token that will be burned in exchange for _toToken\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permitParams EIP-2612 permit params:\\n * _deadline Expiration time of the signature.\\n * _v Last 1 byte of ECDSA signature.\\n * _r First 32 bytes of ECDSA signature.\\n * _s 32 bytes after _r in ECDSA signature.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit(\\n IMassetManager _myntMassetManager,\\n uint256 _dllrAmount,\\n address _toToken,\\n IMassetManager.PermitParams calldata _permitParams\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n dllr.transferWithPermit(\\n msg.sender,\\n thisAddress,\\n _dllrAmount,\\n _permitParams.deadline,\\n _permitParams.v,\\n _permitParams.r,\\n _permitParams.s\\n );\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit via a canonical Permit2 contract\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permit permit data, in form of PermitTransferFrom struct.\\n * @param _permit2 permit2 contract address\\n * @param _signature signatue of the permit data.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit2(\\n IMassetManager _myntMassetManager,\\n address _toToken,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n IPermit2 _permit2,\\n bytes calldata _signature\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n uint256 _dllrAmount = _permit.permitted.amount;\\n\\n _permit2.permitTransferFrom(\\n _permit,\\n _generateTransferDetails(thisAddress, _dllrAmount),\\n msg.sender,\\n _signature\\n );\\n\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @dev view function to construct SignatureTransferDetails struct to be used by Permit2\\n *\\n * @param _to ultimate recipient\\n * @param _amount amount of transfer\\n *\\n * @return SignatureTransferDetails struct object \\n */\\n function _generateTransferDetails(address _to, uint256 _amount) private view returns (ISignatureTransfer.SignatureTransferDetails memory) {\\n ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer.SignatureTransferDetails({\\n to: _to,\\n requestedAmount: _amount\\n });\\n\\n return transferDetails;\\n }\\n}\\n\",\"keccak256\":\"0x6f0c78d8c4ea0b5b5e6bbe8d78374b9d2d367ffc07054dde36b9cbe2061944b6\",\"license\":\"MIT\"},\"contracts/Dependencies/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's Ownable contract:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\\n *\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable {\\n bytes32 private constant KEY_OWNER = keccak256(\\\"key.ownable.owner\\\");\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor () internal {\\n _setOwner(msg.sender);\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(msg.sender == getOwner(), \\\"Ownable:: access denied\\\");\\n _;\\n }\\n\\n /**\\n * @notice Set address of the owner.\\n * @param _owner Address of the owner.\\n * */\\n function _setOwner(address _owner) internal {\\n require(_owner != address(0), \\\"Ownable::setOwner: invalid address\\\");\\n emit OwnershipTransferred(getOwner(), _owner);\\n\\n bytes32 key = KEY_OWNER;\\n assembly {\\n sstore(key, _owner)\\n }\\n }\\n\\n /**\\n * @notice Set address of the owner (only owner can call this function)\\n * @param _owner Address of the owner.\\n * */\\n function setOwner(address _owner) public onlyOwner {\\n _setOwner(_owner);\\n }\\n\\n /**\\n * @notice Return address of the owner.\\n * @return _owner Address of the owner.\\n * */\\n function getOwner() public view returns (address _owner) {\\n bytes32 key = KEY_OWNER;\\n assembly {\\n _owner := sload(key)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xb5fc626e0b227fc0feb1d84440585015a0a5f586547d298534a604dd113efec6\",\"license\":\"MIT\"},\"contracts/Dependencies/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's SafeMath:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol\\n *\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x666b890992a066cc791f36c2975cd595d9761a014c654c385ed36ffaf658f3fd\",\"license\":\"MIT\"},\"contracts/Dependencies/console.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Buidler's helper contract for console logging\\nlibrary console {\\n\\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\\n\\n\\tfunction log() internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log()\\\"));\\n\\t\\tignored;\\n\\t}\\tfunction logInt(int p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(int)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logUint(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logString(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBool(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logAddress(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes(bytes memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logByte(byte p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(byte)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes1(bytes1 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes1)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes2(bytes2 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes2)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes3(bytes3 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes3)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes4(bytes4 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes4)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes5(bytes5 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes5)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes6(bytes6 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes6)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes7(bytes7 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes7)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes8(bytes8 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes8)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes9(bytes9 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes9)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes10(bytes10 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes10)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes11(bytes11 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes11)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes12(bytes12 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes12)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes13(bytes13 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes13)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes14(bytes14 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes14)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes15(bytes15 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes15)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes16(bytes16 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes16)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes17(bytes17 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes17)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes18(bytes18 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes18)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes19(bytes19 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes19)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes20(bytes20 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes20)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes21(bytes21 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes21)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes22(bytes22 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes22)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes23(bytes23 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes23)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes24(bytes24 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes24)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes25(bytes25 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes25)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes26(bytes26 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes26)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes27(bytes27 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes27)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes28(bytes28 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes28)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes29(bytes29 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes29)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes30(bytes30 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes30)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes31(bytes31 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes31)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes32(bytes32 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes32)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n}\\n\",\"keccak256\":\"0x6fa1de4ffe22b8f58b0b64d65db11dd5037be9b9db47b365a72adb489e217000\",\"license\":\"MIT\"},\"contracts/Interfaces/IActivePool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\n/**\\n * The Active Pool holds the ETH collateral and ZUSD debt (but not ZUSD tokens) for all active troves.\\n *\\n * When a trove is liquidated, it's ETH and ZUSD debt are transferred from the Active Pool, to either the\\n * Stability Pool, the Default Pool, or both, depending on the liquidation conditions.\\n *\\n */\\ninterface IActivePool is IPool {\\n // --- Events ---\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolZUSDDebtUpdated(uint _ZUSDDebt);\\n event ActivePoolETHBalanceUpdated(uint _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH amount to given account. Updates ActivePool balance. Only callable by BorrowerOperations, TroveManager or StabilityPool.\\n /// @param _account account to receive the ETH amount\\n /// @param _amount ETH amount to send\\n function sendETH(address _account, uint _amount) external;\\n}\\n\",\"keccak256\":\"0xdd5f1b6fae4050b4c885a85a10c2d0e73b82187a51736d009065aaeea33bf0d0\",\"license\":\"MIT\"},\"contracts/Interfaces/IAllowanceTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title AllowanceTransfer\\n/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface IAllowanceTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an ordered nonce.\\n event NonceInvalidation(\\n address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.\\n event Approval(\\n address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.\\n event Permit(\\n address indexed owner,\\n address indexed token,\\n address indexed spender,\\n uint160 amount,\\n uint48 expiration,\\n uint48 nonce\\n );\\n\\n /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.\\n event Lockdown(address indexed owner, address token, address spender);\\n\\n /// @notice The permit data for a token\\n struct PermitDetails {\\n // ERC20 token address\\n address token;\\n // the maximum amount allowed to spend\\n uint160 amount;\\n // timestamp at which a spender's token allowances become invalid\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice The permit message signed for a single token allowance\\n struct PermitSingle {\\n // the permit data for a single token alownce\\n PermitDetails details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The permit message signed for multiple token allowances\\n struct PermitBatch {\\n // the permit data for multiple token allowances\\n PermitDetails[] details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The saved permissions\\n /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n struct PackedAllowance {\\n // amount allowed\\n uint160 amount;\\n // permission expiry\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice A token spender pair.\\n struct TokenSpenderPair {\\n // the token the spender is approved\\n address token;\\n // the spender address\\n address spender;\\n }\\n\\n /// @notice Details for a token transfer.\\n struct AllowanceTransferDetails {\\n // the owner of the token\\n address from;\\n // the recipient of the token\\n address to;\\n // the amount of the token\\n uint160 amount;\\n // the token to be transferred\\n address token;\\n }\\n\\n /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.\\n /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]\\n /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.\\n function allowance(address user, address token, address spender)\\n external\\n view\\n returns (uint160 amount, uint48 expiration, uint48 nonce);\\n\\n /// @notice Approves the spender to use up to amount of the specified token up until the expiration\\n /// @param token The token to approve\\n /// @param spender The spender address to approve\\n /// @param amount The approved amount of the token\\n /// @param expiration The timestamp at which the approval is no longer valid\\n /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n function approve(address token, address spender, uint160 amount, uint48 expiration) external;\\n\\n /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitSingle Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;\\n\\n /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitBatch Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;\\n\\n /// @notice Transfer approved tokens from one address to another\\n /// @param from The address to transfer from\\n /// @param to The address of the recipient\\n /// @param amount The amount of the token to transfer\\n /// @param token The token address to transfer\\n /// @dev Requires the from address to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(address from, address to, uint160 amount, address token) external;\\n\\n /// @notice Transfer approved tokens in a batch\\n /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers\\n /// @dev Requires the from addresses to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;\\n\\n /// @notice Enables performing a \\\"lockdown\\\" of the sender's Permit2 identity\\n /// by batch revoking approvals\\n /// @param approvals Array of approvals to revoke.\\n function lockdown(TokenSpenderPair[] calldata approvals) external;\\n\\n /// @notice Invalidate nonces for a given (token, spender) pair\\n /// @param token The token to invalidate nonces for\\n /// @param spender The spender to invalidate nonces for\\n /// @param newNonce The new nonce to set. Invalidates all nonces less than it.\\n /// @dev Can't invalidate more than 2**16 nonces per transaction.\\n function invalidateNonces(address token, address spender, uint48 newNonce) external;\\n}\\n\",\"keccak256\":\"0xf15059fb68f89542908f963f22e18c0b0ae9997a6f9aaf6a9fb46aa2424acac9\",\"license\":\"MIT\"},\"contracts/Interfaces/IBorrowerOperations.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface IBorrowerOperations {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event TroveCreated(address indexed _borrower, uint256 arrayIndex);\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event ZUSDBorrowingFeePaid(address indexed _borrower, uint256 _ZUSDFee);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeDistributorAddress feeDistributor contract address\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _defaultPoolAddress DefaultPool contract address\\n * @param _stabilityPoolAddress StabilityPool contract address\\n * @param _gasPoolAddress GasPool contract address\\n * @param _collSurplusPoolAddress CollSurplusPool contract address\\n * @param _priceFeedAddress PrideFeed contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n address _feeDistributorAddress,\\n address _liquityBaseParamsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _defaultPoolAddress,\\n address _stabilityPoolAddress,\\n address _gasPoolAddress,\\n address _collSurplusPoolAddress,\\n address _priceFeedAddress,\\n address _sortedTrovesAddress,\\n address _zusdTokenAddress,\\n address _zeroStakingAddress\\n ) external;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * This method is identical to `openTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openNueTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /// @notice payable function that adds the received Ether to the caller's active Trove.\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function addColl(address _upperHint, address _lowerHint) external payable;\\n\\n /// @notice send ETH as collateral to a trove. Called by only the Stability Pool.\\n /// @param _user user trove address\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function moveETHGainToTrove(\\n address _user,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice withdraws `_amount` of collateral from the caller\\u2019s Trove.\\n * Executes only if the user has an active Trove, the withdrawal would not pull the user\\u2019s Trove below the minimum collateralization ratio,\\n * and the resulting total collateralization ratio of the system is above 150%.\\n * @param _amount collateral amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawColl(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice issues `_amount` of ZUSD from the caller\\u2019s Trove to the caller.\\n * Executes only if the Trove's collateralization ratio would remain above the minimum, and the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _amount ZUSD amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawZUSD(\\n uint256 _maxFee,\\n uint256 _amount,\\n address _upperHint,\\n address _lowerHint\\n ) external;\\n\\n /// Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction\\n function withdrawZusdAndConvertToDLLR(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external returns (uint256);\\n\\n /// @notice repay `_amount` of ZUSD to the caller\\u2019s Trove, subject to leaving 50 debt in the Trove (which corresponds to the 50 ZUSD gas compensation).\\n /// @param _amount ZUSD amount to repay\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function repayZUSD(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLR(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLRWithPermit2(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a ZUSD balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` ZUSD.\\n */\\n function closeTrove() external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTrove(IMassetManager.PermitParams calldata _permitParams) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTroveWithPermit2(ISignatureTransfer.PermitTransferFrom memory _permit, bytes calldata _signature) external;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTroveWithPermit2(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external payable;\\n\\n /**\\n * @notice when a borrower\\u2019s Trove has been fully redeemed from and closed, or liquidated in Recovery Mode with a collateralization ratio above 110%,\\n * this function allows the borrower to claim their ETH collateral surplus that remains in the system (collateral - debt upon redemption; collateral - 110% of the debt upon liquidation).\\n */\\n function claimCollateral() external;\\n\\n function getCompositeDebt(uint256 _debt) external view returns (uint256);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint256);\\n\\n function getMassetManager() external view returns (IMassetManager);\\n}\\n\",\"keccak256\":\"0x75da117f4bc4cca15fc16ca0466c68894f1befed0471ea7a670fa9b466ef2bc5\",\"license\":\"MIT\"},\"contracts/Interfaces/ICollSurplusPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ICollSurplusPool {\\n // --- Events ---\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n\\n event CollBalanceUpdated(address indexed _account, uint256 _newBalance);\\n event EtherSent(address _to, uint256 _amount);\\n\\n // --- Contract setters ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH state variable\\n function getETH() external view returns (uint256);\\n\\n /// @param _account account to retrieve collateral\\n /// @return collateral\\n function getCollateral(address _account) external view returns (uint256);\\n\\n /// @notice adds amount to current account balance. Only callable by TroveManager.\\n /// @param _account account to add amount\\n /// @param _amount amount to add\\n function accountSurplus(address _account, uint256 _amount) external;\\n\\n /// @notice claims collateral for given account. Only callable by BorrowerOperations.\\n /// @param _account account to send claimable collateral\\n function claimColl(address _account) external;\\n}\\n\",\"keccak256\":\"0xac983936efe70d19205bff65a18b4e6000d489d4e4d1e2e92f951873cee91048\",\"license\":\"MIT\"},\"contracts/Interfaces/IDefaultPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\ninterface IDefaultPool is IPool {\\n // --- Events ---\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event DefaultPoolZUSDDebtUpdated(uint256 _ZUSDDebt);\\n event DefaultPoolETHBalanceUpdated(uint256 _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH to Active Pool\\n /// @param _amount ETH to send\\n function sendETHToActivePool(uint256 _amount) external;\\n}\\n\",\"keccak256\":\"0xfb2607676b2eb0f2defd248b4dd32895820048317f29aa6bdb572403a3e3d44e\",\"license\":\"MIT\"},\"contracts/Interfaces/IEIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\ninterface IEIP712 {\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xff52e9168eaa532ebacdad2ab6197f60171e3aa2fa2c1d6397d9da4d7782a543\",\"license\":\"MIT\"},\"contracts/Interfaces/IFeeDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/// Common interface for Fee Distributor.\\ninterface IFeeDistributor {\\n // --- Events ---\\n\\n event FeeSharingCollectorAddressChanged(address _feeSharingCollectorAddress);\\n event ZeroStakingAddressChanged(address _zeroStakingAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event WrbtcAddressChanged(address _wrbtcAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event ZUSDDistributed(uint256 _zusdDistributedAmount);\\n event RBTCistributed(uint256 _rbtcDistributedAmount);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeSharingCollectorAddress FeeSharingCollector address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n * @param _borrowerOperationsAddress borrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _wrbtcAddress wrbtc ERC20 contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _feeSharingCollectorAddress,\\n address _zeroStakingAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _wrbtcAddress,\\n address _zusdTokenAddress,\\n address _activePoolAddress\\n ) external;\\n\\n function distributeFees() external;\\n}\\n\",\"keccak256\":\"0x4b9bc6eaa8a9ea5e0570ffd84c0af2a92e74b001ae1ee1c8518d76382691a07f\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPriceFeed.sol\\\";\\nimport \\\"./ILiquityBaseParams.sol\\\";\\n\\ninterface ILiquityBase {\\n /// @return PriceFeed contract\\n function priceFeed() external view returns (IPriceFeed);\\n\\n /// @return LiquityBaseParams contract\\n function liquityBaseParams() external view returns (ILiquityBaseParams);\\n}\\n\",\"keccak256\":\"0xa4a57bd79e64d56a687c28d2a35c55b733fde8dda2a7ba861606eed3211724e1\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBaseParams.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ILiquityBaseParams {\\n\\n /// Minimum collateral ratio for individual troves\\n function MCR() external view returns (uint);\\n\\n /// Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.\\n function CCR() external view returns (uint);\\n\\n function PERCENT_DIVISOR() external view returns (uint);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint);\\n\\n /**\\n * Half-life of 12h. 12h = 720 min\\n * (1/2) = d^720 => d = (1/2)^(1/720)\\n */\\n function REDEMPTION_FEE_FLOOR() external view returns (uint);\\n\\n function MAX_BORROWING_FEE() external view returns (uint);\\n\\n}\",\"keccak256\":\"0xef8c0e8ad5d13d604c11b04983ff5bdd41768b646f2b33f45ddd988adec204e0\",\"license\":\"MIT\"},\"contracts/Interfaces/IPermit2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {ISignatureTransfer} from \\\"./ISignatureTransfer.sol\\\";\\nimport {IAllowanceTransfer} from \\\"./IAllowanceTransfer.sol\\\";\\n\\n/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer.\\n/// @dev Users must approve Permit2 before calling any of the transfer functions.\\ninterface IPermit2 is ISignatureTransfer, IAllowanceTransfer {\\n// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval.\\n}\\n\",\"keccak256\":\"0x3df819f5ca8de7324a676839d72e9f44c0f789c41c13bf0a892f3bb98d72ee86\",\"license\":\"MIT\"},\"contracts/Interfaces/IPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the Pools.\\ninterface IPool {\\n // --- Events ---\\n\\n event ETHBalanceUpdated(uint _newBalance);\\n event ZUSDBalanceUpdated(uint _newBalance);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event EtherSent(address _to, uint _amount);\\n\\n // --- Functions ---\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH pool balance\\n function getETH() external view returns (uint);\\n\\n /// @return ZUSD debt pool balance\\n function getZUSDDebt() external view returns (uint);\\n\\n /// @notice Increases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to add to the pool debt\\n function increaseZUSDDebt(uint _amount) external;\\n\\n /// @notice Decreases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to subtract to the pool debt\\n function decreaseZUSDDebt(uint _amount) external;\\n}\\n\",\"keccak256\":\"0x148e87ab38c6176d74f36c9e8989b99e768a7b18d8a045f1f01d6583b986806d\",\"license\":\"MIT\"},\"contracts/Interfaces/IPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IPriceFeed {\\n // --- Events ---\\n event LastGoodPriceUpdated(uint256 _lastGoodPrice);\\n\\n // --- Function ---\\n\\n /// @notice Returns the latest price obtained from the Oracle. Called by Zero functions that require a current price.\\n /// It uses the main price feed and fallback to the backup one in case of an error. If both fail return the last\\n /// good price seen.\\n /// @dev It's also callable by anyone externally\\n /// @return The price\\n function fetchPrice() external returns (uint256);\\n}\\n\",\"keccak256\":\"0x85fd97219a8156209d2cb5c6ae7c5ead01d893db000bf575023fcef0e62f9591\",\"license\":\"MIT\"},\"contracts/Interfaces/ISignatureTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title SignatureTransfer\\n/// @notice Handles ERC20 token transfers through signature based actions\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface ISignatureTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an unordered nonce.\\n event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);\\n\\n /// @notice The token and amount details for a transfer signed in the permit transfer signature\\n struct TokenPermissions {\\n // ERC20 token address\\n address token;\\n // the maximum amount that can be spent\\n uint256 amount;\\n }\\n\\n /// @notice The signed permit message for a single token transfer\\n struct PermitTransferFrom {\\n TokenPermissions permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice Specifies the recipient address and amount for batched transfers.\\n /// @dev Recipients and amounts correspond to the index of the signed token permissions array.\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount.\\n struct SignatureTransferDetails {\\n // recipient address\\n address to;\\n // spender requested amount\\n uint256 requestedAmount;\\n }\\n\\n /// @notice Used to reconstruct the signed permit message for multiple token transfers\\n /// @dev Do not need to pass in spender address as it is required that it is msg.sender\\n /// @dev Note that a user still signs over a spender address\\n struct PermitBatchTransferFrom {\\n // the tokens and corresponding amounts permitted for a transfer\\n TokenPermissions[] permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection\\n /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order\\n /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce\\n /// @dev It returns a uint256 bitmap\\n /// @dev The index, or wordPosition is capped at type(uint248).max\\n function nonceBitmap(address, uint256) external view returns (uint256);\\n\\n /// @notice Transfers a token using a signed permit message\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails The spender's requested transfer details for the permitted token\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitTransferFrom memory permit,\\n SignatureTransferDetails calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Transfers multiple tokens using a signed permit message\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails Specifies the recipient and requested amount for the token transfer\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitBatchTransferFrom memory permit,\\n SignatureTransferDetails[] calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Invalidates the bits specified in mask for the bitmap at the word position\\n /// @dev The wordPos is maxed at type(uint248).max\\n /// @param wordPos A number to index the nonceBitmap at\\n /// @param mask A bitmap masked against msg.sender's current bitmap at the word position\\n function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;\\n}\\n\",\"keccak256\":\"0x7efc63c119694e23dd76e44a5b125999829026bbc23409de7646a6a45e1ac341\",\"license\":\"MIT\"},\"contracts/Interfaces/ISortedTroves.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the SortedTroves Doubly Linked List.\\ninterface ISortedTroves {\\n // --- Events ---\\n\\n event SortedTrovesAddressChanged(address _sortedDoublyLLAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event NodeAdded(address _id, uint256 _NICR);\\n event NodeRemoved(address _id);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts and size. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _size max size of troves list\\n * @param _TroveManagerAddress TroveManager contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n */\\n function setParams(\\n uint256 _size,\\n address _TroveManagerAddress,\\n address _borrowerOperationsAddress\\n ) external;\\n\\n /**\\n * @dev Add a node to the list\\n * @param _id Node's id\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function insert(\\n address _id,\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Remove a node from the list\\n * @param _id Node's id\\n */\\n function remove(address _id) external;\\n\\n /**\\n * @dev Re-insert the node at a new position, based on its new NICR\\n * @param _id Node's id\\n * @param _newICR Node's new NICR\\n * @param _prevId Id of previous node for the new insert position\\n * @param _nextId Id of next node for the new insert position\\n */\\n function reInsert(\\n address _id,\\n uint256 _newICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Checks if the list contains a node\\n * @param _id Node's id\\n * @return true if list contains a node with given id\\n */\\n function contains(address _id) external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is full\\n * @return true if list is full\\n */\\n function isFull() external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is empty\\n * @return true if list is empty\\n */\\n function isEmpty() external view returns (bool);\\n\\n /**\\n * @return list current size\\n */\\n function getSize() external view returns (uint256);\\n\\n /**\\n * @return list max size\\n */\\n function getMaxSize() external view returns (uint256);\\n\\n /**\\n * @return the first node in the list (node with the largest NICR)\\n */\\n function getFirst() external view returns (address);\\n\\n /**\\n * @return the last node in the list (node with the smallest NICR)\\n */\\n function getLast() external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the next node (with a smaller NICR) in the list for a given node\\n */\\n function getNext(address _id) external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the previous node (with a larger NICR) in the list for a given node\\n */\\n function getPrev(address _id) external view returns (address);\\n\\n /**\\n * @notice Check if a pair of nodes is a valid insertion point for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function validInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (bool);\\n\\n /**\\n * @notice Find the insert position for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function findInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (address, address);\\n}\\n\",\"keccak256\":\"0x7328ad009da6230ddea1559564428464a5c3ace2258fb534dfbba5b5a8c7c60d\",\"license\":\"MIT\"},\"contracts/Interfaces/IStabilityPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/*\\n * The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors.\\n *\\n * When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with\\n * ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned.\\n *\\n * Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits.\\n * They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors,\\n * in the same proportion.\\n *\\n * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40%\\n * of the total ZUSD in the Stability Pool, depletes 40% of each deposit.\\n *\\n * A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit,\\n * multiplying it by some factor in range ]0,1[\\n *\\n * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations:\\n * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf\\n *\\n * --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS ---\\n *\\n * An SOV issuance event occurs at every deposit operation, and every liquidation.\\n *\\n * Each deposit is tagged with the address of the front end through which it was made.\\n *\\n * All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned\\n * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate.\\n *\\n * Please see the system Readme for an overview:\\n * https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers\\n */\\ninterface IStabilityPool {\\n // --- Events ---\\n\\n event StabilityPoolETHBalanceUpdated(uint _newBalance);\\n event StabilityPoolZUSDBalanceUpdated(uint _newBalance);\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event SortedTrovesAddressChanged(address _newSortedTrovesAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);\\n\\n event P_Updated(uint _P);\\n event S_Updated(uint _S, uint128 _epoch, uint128 _scale);\\n event G_Updated(uint _G, uint128 _epoch, uint128 _scale);\\n event EpochUpdated(uint128 _currentEpoch);\\n event ScaleUpdated(uint128 _currentScale);\\n\\n event FrontEndRegistered(address indexed _frontEnd, uint _kickbackRate);\\n event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd);\\n\\n event DepositSnapshotUpdated(address indexed _depositor, uint _P, uint _S, uint _G);\\n event FrontEndSnapshotUpdated(address indexed _frontEnd, uint _P, uint _G);\\n event UserDepositChanged(address indexed _depositor, uint _newDeposit);\\n event FrontEndStakeChanged(\\n address indexed _frontEnd,\\n uint _newFrontEndStake,\\n address _depositor\\n );\\n\\n event ETHGainWithdrawn(address indexed _depositor, uint _ETH, uint _ZUSDLoss);\\n event SOVPaidToDepositor(address indexed _depositor, uint _SOV);\\n event SOVPaidToFrontEnd(address indexed _frontEnd, uint _SOV);\\n event EtherSent(address _to, uint _amount);\\n\\n event WithdrawFromSpAndConvertToDLLR(\\n address _depositor,\\n uint256 _zusdAmountRequested,\\n uint256 _dllrAmountReceived\\n );\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Liquity contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _priceFeedAddress PriceFeed contract address\\n * @param _communityIssuanceAddress CommunityIssuanceAddress\\n */\\n function setAddresses(\\n address _liquityBaseParamsAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _zusdTokenAddress,\\n address _sortedTrovesAddress,\\n address _priceFeedAddress,\\n address _communityIssuanceAddress\\n ) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend is registered or zero address\\n * - Sender is not a registered frontend\\n * - _amount is not zero\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Tags the deposit with the provided front end tag param, if it's a new deposit\\n * - Sends depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Increases deposit and tagged front end's stake, and takes new snapshots for each.\\n * @param _amount amount to provide\\n * @param _frontEndTag frontend address to receive accumulated SOV gains\\n */\\n function provideToSP(uint _amount, address _frontEndTag) external;\\n\\n /**\\n * @notice Initial checks:\\n * - _amount is zero or there are no under collateralized troves left in the system\\n * - User has a non zero deposit\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Removes the deposit's front end tag if it is a full withdrawal\\n * - Sends all depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.\\n *\\n * If _amount > userDeposit, the user withdraws all of their compounded deposit.\\n * @param _amount amount to withdraw\\n */\\n function withdrawFromSP(uint _amount) external;\\n\\n /**\\n * @notice Initial checks:\\n * - User has a non zero deposit\\n * - User has an open trove\\n * - User has some ETH gain\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Sends all depositor's SOV gain to depositor\\n * - Sends all tagged front end's SOV gain to the tagged front end\\n * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove\\n * - Leaves their compounded deposit in the Stability Pool\\n * - Updates snapshots for deposit and tagged front end stake\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend (sender) not already registered\\n * - User (sender) has no deposit\\n * - _kickbackRate is in the range [0, 100%]\\n * ---\\n * Front end makes a one-time selection of kickback rate upon registering\\n * @param _kickbackRate kickback rate selected by frontend\\n */\\n function registerFrontEnd(uint _kickbackRate) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Caller is TroveManager\\n * ---\\n * Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible)\\n * and transfers the Trove's ETH collateral from ActivePool to StabilityPool.\\n * Only called by liquidation functions in the TroveManager.\\n * @param _debt debt to cancel\\n * @param _coll collateral to transfer\\n */\\n function offset(uint _debt, uint _coll) external;\\n\\n /**\\n * @return the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`,\\n * to exclude edge cases like ETH received from a self-destruct.\\n */\\n function getETH() external view returns (uint);\\n\\n /**\\n * @return ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\\n */\\n function getTotalZUSDDeposits() external view returns (uint);\\n\\n /**\\n * @notice Calculates the ETH gain earned by the deposit since its last snapshots were taken.\\n * @param _depositor address to calculate ETH gain\\n * @return ETH gain from given depositor\\n */\\n function getDepositorETHGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice Calculate the SOV gain earned by a deposit since its last snapshots were taken.\\n * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned.\\n * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through\\n * which they made their deposit.\\n * @param _depositor address to calculate ETH gain\\n * @return SOV gain from given depositor\\n */\\n function getDepositorSOVGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @param _frontEnd front end address\\n * @return the SOV gain earned by the front end.\\n */\\n function getFrontEndSOVGain(address _frontEnd) external view returns (uint);\\n\\n /**\\n * @param _depositor depositor address\\n * @return the user's compounded deposit.\\n */\\n function getCompoundedZUSDDeposit(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\\n * @param _frontEnd front end address\\n * @return the front end's compounded stake.\\n */\\n function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint);\\n\\n //DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDLLR(\\n uint _dllrAmount,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function provideToSpFromDllrWithPermit2(\\n uint256 _dllrAmount,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /// Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and optionally convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\\n function withdrawFromSpAndConvertToDLLR(uint256 _zusdAmount) external;\\n\\n /**\\n * Fallback function\\n * Only callable by Active Pool, it just accounts for ETH received\\n * receive() external payable;\\n */\\n}\\n\",\"keccak256\":\"0xb35c5ec991dd2b4f8ecb6b28ae29e97313fca6054aa0df14ebdb7336fcea84a6\",\"license\":\"MIT\"},\"contracts/Interfaces/ITroveManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./ILiquityBase.sol\\\";\\nimport \\\"./IStabilityPool.sol\\\";\\nimport \\\"./IZUSDToken.sol\\\";\\nimport \\\"./IZEROToken.sol\\\";\\nimport \\\"./IZEROStaking.sol\\\";\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface ITroveManager is ILiquityBase {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerRedeemOpsAddressChanged(address _troveManagerRedeemOps);\\n event LiquityBaseParamsAddressChanges(address _borrowerOperationsAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZEROTokenAddressChanged(address _zeroTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event Liquidation(\\n uint256 _liquidatedDebt,\\n uint256 _liquidatedColl,\\n uint256 _collGasCompensation,\\n uint256 _ZUSDGasCompensation\\n );\\n event Redemption(\\n uint256 _attemptedZUSDAmount,\\n uint256 _actualZUSDAmount,\\n uint256 _ETHSent,\\n uint256 _ETHFee\\n );\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event TroveLiquidated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint8 operation\\n );\\n event BaseRateUpdated(uint256 _baseRate);\\n event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);\\n event TotalStakesUpdated(uint256 _newTotalStakes);\\n event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);\\n event LTermsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveIndexUpdated(address _borrower, uint256 _newIndex);\\n\\n struct TroveManagerInitAddressesParams {\\n address _feeDistributorAddress;\\n address _troveManagerRedeemOps;\\n address _liquityBaseParamsAddress;\\n address _borrowerOperationsAddress;\\n address _activePoolAddress;\\n address _defaultPoolAddress;\\n address _stabilityPoolAddress;\\n address _gasPoolAddress;\\n address _collSurplusPoolAddress;\\n address _priceFeedAddress;\\n address _zusdTokenAddress;\\n address _sortedTrovesAddress;\\n address _zeroTokenAddress;\\n address _zeroStakingAddress;\\n }\\n\\n // --- Functions ---\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _troveManagerInitAddresses addresses list to intialize TroveManager with _\\n * _feeDistributorAddress feeDistributor contract address\\n * _troveManagerRedeemOps TroveManagerRedeemOps contract address\\n * _liquityBaseParamsAddress LiquityBaseParams contract address\\n * _borrowerOperationsAddress BorrowerOperations contract address\\n * _activePoolAddress ActivePool contract address\\n * _defaultPoolAddress DefaultPool contract address\\n * _stabilityPoolAddress StabilityPool contract address\\n * _gasPoolAddress GasPool contract address\\n * _collSurplusPoolAddress CollSurplusPool contract address\\n * _priceFeedAddress PriceFeed contract address\\n * _zusdTokenAddress ZUSDToken contract address\\n * _sortedTrovesAddress SortedTroves contract address\\n * _zeroTokenAddress ZEROToken contract address\\n * _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n TroveManagerInitAddressesParams memory _troveManagerInitAddresses\\n ) external;\\n\\n function setTroveManagerRedeemOps(address _troveManagerRedeemOps) external;\\n\\n /// @return Trove owners count\\n function getTroveOwnersCount() external view returns (uint256);\\n\\n /// @param _index Trove owner index\\n /// @return Trove from TroveOwners array in given index\\n function getTroveFromTroveOwnersArray(uint256 _index) external view returns (address);\\n\\n /// @param _borrower borrower address\\n /// @return the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getNominalICR(address _borrower) external view returns (uint256);\\n\\n /// @notice computes the user\\u2019s individual collateralization ratio (ICR) based on their total collateral and total ZUSD debt. Returns 2^256 -1 if they have 0 debt.\\n /// @param _borrower borrower address\\n /// @param _price ETH price\\n /// @return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getCurrentICR(address _borrower, uint256 _price) external view returns (uint256);\\n\\n /// @notice Closes the trove if its ICR is lower than the minimum collateral ratio.\\n /// @param _borrower borrower address\\n function liquidate(address _borrower) external;\\n\\n /**\\n * @notice Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves,\\n * starting from the one with the lowest collateral ratio in the system, and moving upwards\\n * @param _n max number of under-collateralized Troves to liquidate\\n */\\n function liquidateTroves(uint256 _n) external;\\n\\n /**\\n * @notice Attempt to liquidate a custom list of troves provided by the caller.\\n * @param _troveArray list of trove addresses\\n */\\n function batchLiquidateTroves(address[] calldata _troveArray) external;\\n\\n /**\\n * @notice Send _ZUSDamount ZUSD to the system and redeem the corresponding amount of collateral from as many Troves as are needed to fill the redemption\\n * request. Applies pending rewards to a Trove before reducing its debt and coll.\\n *\\n * Note that if _amount is very large, this function can run out of gas, specially if traversed troves are small. This can be easily avoided by\\n * splitting the total _amount in appropriate chunks and calling the function multiple times.\\n *\\n * Param `_maxIterations` can also be provided, so the loop through Troves is capped (if it\\u2019s zero, it will be ignored).This makes it easier to\\n * avoid OOG for the frontend, as only knowing approximately the average cost of an iteration is enough, without needing to know the \\u201ctopology\\u201d\\n * of the trove list. It also avoids the need to set the cap in stone in the contract, nor doing gas calculations, as both gas price and opcode\\n * costs can vary.\\n *\\n * All Troves that are redeemed from -- with the likely exception of the last one -- will end up with no debt left, therefore they will be closed.\\n * If the last Trove does have some remaining debt, it has a finite ICR, and the reinsertion could be anywhere in the list, therefore it requires a hint.\\n * A frontend should use getRedemptionHints() to calculate what the ICR of this Trove will be after redemption, and pass a hint for its position\\n * in the sortedTroves list along with the ICR value that the hint was found for.\\n *\\n * If another transaction modifies the list between calling getRedemptionHints() and passing the hints to redeemCollateral(), it\\n * is very likely that the last (partially) redeemed Trove would end up with a different ICR than what the hint is for. In this case the\\n * redemption will stop after the last completely redeemed Trove and the sender will keep the remaining ZUSD amount, which they can attempt\\n * to redeem later.\\n *\\n * @param _ZUSDAmount ZUSD amount to send to the system\\n * @param _firstRedemptionHint calculated ICR hint of first trove after redemption\\n * @param _maxIterations max Troves iterations (can be 0)\\n * @param _maxFee max fee percentage to accept\\n */\\n function redeemCollateral(\\n uint256 _ZUSDAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFee\\n ) external;\\n\\n function redeemCollateralViaDLLR(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function redeemCollateralViaDllrWithPermit2(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n \\n\\n /// @notice Update borrower's stake based on their latest collateral value\\n /// @param _borrower borrower address\\n function updateStakeAndTotalStakes(address _borrower) external returns (uint256);\\n\\n /// @notice Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values\\n /// @param _borrower borrower address\\n function updateTroveRewardSnapshots(address _borrower) external;\\n\\n /// @notice Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct\\n /// @param _borrower borrower address\\n /// @return index where Trove was inserted\\n function addTroveOwnerToArray(address _borrower) external returns (uint256 index);\\n\\n /// @notice Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\\n /// @param _borrower borrower address\\n function applyPendingRewards(address _borrower) external;\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ETH reward, earned by their stake\\n function getPendingETHReward(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ZUSD reward, earned by their stake\\n function getPendingZUSDDebtReward(address _borrower) external view returns (uint256);\\n\\n /*\\n * @notice A Trove has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:\\n * this indicates that rewards have occured since the snapshot was made, and the user therefore has\\n * pending rewards\\n *\\n * @param _borrower borrower address\\n * @return true if has pending rewards\\n */\\n function hasPendingRewards(address _borrower) external view returns (bool);\\n\\n /// @notice returns the Troves entire debt and coll, including pending rewards from redistributions.\\n /// @param _borrower borrower address\\n function getEntireDebtAndColl(\\n address _borrower\\n )\\n external\\n view\\n returns (\\n uint256 debt,\\n uint256 coll,\\n uint256 pendingZUSDDebtReward,\\n uint256 pendingETHReward\\n );\\n\\n /// @notice Close given trove. Called by BorrowerOperations.\\n /// @param _borrower borrower address\\n function closeTrove(address _borrower) external;\\n\\n /// @notice Remove borrower's stake from the totalStakes sum, and set their stake to 0\\n /// @param _borrower borrower address\\n function removeStake(address _borrower) external;\\n\\n /// @return calculated redemption rate using baseRate\\n function getRedemptionRate() external view returns (uint256);\\n\\n /// @return calculated redemption rate using calculated decayed as base rate\\n function getRedemptionRateWithDecay() external view returns (uint256);\\n\\n /// @notice The redemption fee is taken as a cut of the total ETH drawn from the system in a redemption. It is based on the current redemption rate.\\n /// @param _ETHDrawn ETH drawn\\n function getRedemptionFeeWithDecay(uint256 _ETHDrawn) external view returns (uint256);\\n\\n /// @return borrowing rate\\n function getBorrowingRate() external view returns (uint256);\\n\\n /// @return borrowing rate calculated using decayed as base rate\\n function getBorrowingRateWithDecay() external view returns (uint256);\\n\\n /// @param ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate\\n function getBorrowingFee(uint256 ZUSDDebt) external view returns (uint256);\\n\\n /// @param _ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate with decay\\n function getBorrowingFeeWithDecay(uint256 _ZUSDDebt) external view returns (uint256);\\n\\n /// @notice Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation.\\n function decayBaseRateFromBorrowing() external;\\n\\n /// @param _borrower borrower address\\n /// @return Trove status from given trove\\n function getTroveStatus(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove stake from given trove\\n function getTroveStake(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove debt from given trove\\n function getTroveDebt(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove collateral from given trove\\n function getTroveColl(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param num status to set\\n function setTroveStatus(address _borrower, uint256 num) external;\\n\\n /// @param _borrower borrower address\\n /// @param _collIncrease amount of collateral to increase\\n /// @return new trove collateral\\n function increaseTroveColl(\\n address _borrower,\\n uint256 _collIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _collDecrease amount of collateral to decrease\\n /// @return new trove collateral\\n function decreaseTroveColl(\\n address _borrower,\\n uint256 _collDecrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtIncrease amount of debt to increase\\n /// @return new trove debt\\n function increaseTroveDebt(\\n address _borrower,\\n uint256 _debtIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtDecrease amount of debt to decrease\\n /// @return new trove debt\\n function decreaseTroveDebt(\\n address _borrower,\\n uint256 _debtDecrease\\n ) external returns (uint256);\\n\\n /**\\n * @param _price ETH price\\n * @return the total collateralization ratio (TCR) of the system.\\n * The TCR is based on the the entire system debt and collateral (including pending rewards).\\n */\\n function getTCR(uint256 _price) external view returns (uint256);\\n\\n function MCR() external view returns (uint256);\\n\\n function CCR() external view returns (uint256);\\n\\n /// @notice reveals whether or not the system is in Recovery Mode (i.e. whether the Total Collateralization Ratio (TCR) is below the Critical Collateralization Ratio (CCR)).\\n function checkRecoveryMode(uint256 _price) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x396367eb7763c289e419a025532150e2a1d9d99eead359ceb6a081787501a00b\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROStaking.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IZEROStaking {\\n // --- Events --\\n\\n event ZEROTokenAddressSet(address _zeroTokenAddress);\\n event ZUSDTokenAddressSet(address _zusdTokenAddress);\\n event FeeDistributorAddressAddressSet(address _feeDistributorAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event StakeChanged(address indexed staker, uint256 newStake);\\n event StakingGainsWithdrawn(address indexed staker, uint256 ZUSDGain, uint256 ETHGain);\\n event F_ETHUpdated(uint256 _F_ETH);\\n event F_ZUSDUpdated(uint256 _F_ZUSD);\\n event TotalZEROStakedUpdated(uint256 _totalZEROStaked);\\n event EtherSent(address _account, uint256 _amount);\\n event StakerSnapshotsUpdated(address _staker, uint256 _F_ETH, uint256 _F_ZUSD);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _zeroTokenAddress ZEROToken contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _feeDistributorAddress FeeDistributorAddress contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _zeroTokenAddress,\\n address _zusdTokenAddress,\\n address _feeDistributorAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice If caller has a pre-existing stake, send any accumulated ETH and ZUSD gains to them.\\n /// @param _ZEROamount ZERO tokens to stake\\n function stake(uint256 _ZEROamount) external;\\n\\n /**\\n * @notice Unstake the ZERO and send the it back to the caller, along with their accumulated ZUSD & ETH gains.\\n * If requested amount > stake, send their entire stake.\\n * @param _ZEROamount ZERO tokens to unstake\\n */\\n function unstake(uint256 _ZEROamount) external;\\n\\n /// @param _ETHFee ETH fee\\n /// @notice increase ETH fee\\n function increaseF_ETH(uint256 _ETHFee) external;\\n\\n /// @param _ZEROFee ZUSD fee\\n /// @notice increase ZUSD fee\\n function increaseF_ZUSD(uint256 _ZEROFee) external;\\n\\n /// @param _user user address\\n /// @return pending ETH gain of given user\\n function getPendingETHGain(address _user) external view returns (uint256);\\n\\n /// @param _user user address\\n /// @return pending ZUSD gain of given user\\n function getPendingZUSDGain(address _user) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x4c7948ce7dff9ea9b8495054e511eabcf44a91c7db8520ec58ff2a002327e0c5\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZEROToken is IERC20, IERC2612 { \\n\\n // --- Functions ---\\n\\n /// @notice send zero tokens to ZEROStaking contract\\n /// @param _sender sender address\\n /// @param _amount amount to send\\n function sendToZEROStaking(address _sender, uint256 _amount) external;\\n\\n /// @return deployment start time\\n function getDeploymentStartTime() external view returns (uint256);\\n\\n}\\n\",\"keccak256\":\"0xbcc0baabe4c4686563a09cf1486f2d152b70404996676a89d525691f69637f66\",\"license\":\"MIT\"},\"contracts/Interfaces/IZUSDToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZUSDToken is IERC20, IERC2612 { \\n \\n // --- Events ---\\n\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n\\n event ZUSDTokenBalanceUpdated(address _user, uint _amount);\\n\\n // --- Functions ---\\n\\n function mint(address _account, uint256 _amount) external;\\n\\n function burn(address _account, uint256 _amount) external;\\n\\n function sendToPool(address _sender, address poolAddress, uint256 _amount) external;\\n\\n function returnFromPool(address poolAddress, address user, uint256 _amount ) external;\\n}\\n\",\"keccak256\":\"0xe52df063aa08f709640c28888edd27310c820f6d08564855538ae245eb2f5a8c\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60a06040523480156200001157600080fd5b506040516200556638038062005566833981016040819052620000349162000123565b62000048336001600160e01b036200005e16565b60601b6001600160601b031916608052620001b2565b6001600160a01b038116620000905760405162461bcd60e51b8152600401620000879062000170565b60405180910390fd5b6001600160a01b038116620000ad6001600160e01b036200010216565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f29062000153565b6040519081900390209190915550565b600080604051620001139062000153565b6040519081900390205492915050565b60006020828403121562000135578081fd5b81516001600160a01b03811681146200014c578182fd5b9392505050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160601c61538c620001da600039806106a552806110db5280612327525061538c6000f3fe60806040526004361061025c5760003560e01c80637778a3db11610144578063a20baee6116100b6578063c6a6cf201161007a578063c6a6cf2014610601578063e9fc346114610614578063ea9638bf14610629578063ec5472fd1461063c578063ec9f7d4614610651578063f92d3433146106665761025c565b8063a20baee614610414578063a3f4df7e14610595578063ae918754146105b7578063afbc74b5146105cc578063b5c89bab146105ec5761025c565b8063860665b311610108578063860665b314610510578063887105d314610523578063893d20e814610538578063899fe15e1461054d5780638d5c3dc11461056d5780639f070670146105805761025c565b80637778a3db14610486578063795d26c3146104a65780637d4f595d146104bb5780637e3eefdc146104db5780637f7dde4a146104fb5761025c565b8063485f190f116101dd5780636f0b0c1c116101a15780636f0b0c1c146103ff57806372fe25aa14610414578063734f622d14610429578063741bef1a14610449578063759b30341461045e578063763a0ef3146104735761025c565b8063485f190f146103795780634ff814431461038c5780635530273c146103ac57806368647db1146103cc5780636ea56960146103df5761025c565b80631a777717116102245780631a777717146102ed5780631bf435551461030d5780632771510a1461032f5780633cc742251461034f5780633d83908a146103645761025c565b80630d43e8ad146102615780630e704d501461028c5780630ff9a512146102a357806312261ee7146102b857806313af4035146102cd575b600080fd5b34801561026d57600080fd5b5061027661067b565b604051610283919061485c565b60405180910390f35b34801561029857600080fd5b506102a161068a565b005b3480156102af57600080fd5b50610276610694565b3480156102c457600080fd5b506102766106a3565b3480156102d957600080fd5b506102a16102e83660046142d7565b6106c7565b3480156102f957600080fd5b506102a161030836600461455d565b610714565b34801561031957600080fd5b5061032261072b565b60405161028391906152d8565b34801561033b57600080fd5b506102a161034a3660046142d7565b610738565b34801561035b57600080fd5b506102766107c6565b34801561037057600080fd5b506102766107d5565b6102a1610387366004614631565b6107e4565b34801561039857600080fd5b506103226103a7366004614507565b61094e565b3480156103b857600080fd5b506102a16103c7366004614537565b610961565b6102a16103da36600461430f565b610977565b3480156103eb57600080fd5b506102a16103fa366004614631565b61098d565b34801561040b57600080fd5b506102a161099e565b34801561042057600080fd5b506103226109fc565b34801561043557600080fd5b506102a1610444366004614391565b610a08565b34801561045557600080fd5b50610276610dcc565b34801561046a57600080fd5b50610322610ddb565b6102a1610481366004614758565b610de8565b34801561049257600080fd5b506102a16104a136600461449a565b610e04565b3480156104b257600080fd5b50610322610ef5565b3480156104c757600080fd5b506102a16104d63660046144b5565b611014565b3480156104e757600080fd5b506103226104f6366004614631565b61110a565b34801561050757600080fd5b50610276611385565b6102a161051e366004614631565b611394565b34801561052f57600080fd5b506103226113a1565b34801561054457600080fd5b50610276611470565b34801561055957600080fd5b506102a16105683660046145ae565b61148f565b6102a161057b3660046146e0565b6114aa565b34801561058c57600080fd5b506102766114c2565b3480156105a157600080fd5b506105aa6114d1565b6040516102839190614944565b3480156105c357600080fd5b506102766114ff565b3480156105d857600080fd5b506102a16105e7366004614537565b61150e565b3480156105f857600080fd5b50610276611520565b6102a161060f36600461467a565b61152f565b34801561062057600080fd5b5061027661153e565b6102a1610637366004614347565b61154d565b34801561064857600080fd5b50610276611567565b34801561065d57600080fd5b50610276611576565b34801561067257600080fd5b50610322611585565b600d546001600160a01b031681565b610692611607565b565b6009546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6106cf611470565b6001600160a01b0316336001600160a01b0316146107085760405162461bcd60e51b81526004016106ff90614e2d565b60405180910390fd5b610711816119f6565b50565b610725600080866000878787611a81565b50505050565b6809c2007651b250000081565b610740611470565b6001600160a01b0316336001600160a01b0316146107705760405162461bcd60e51b81526004016106ff90614e2d565b600c80546001600160a01b0319166001600160a01b0383161790556040517f6926b3375b54960080b7d8a184061f39a02e8c3bf64aa9df7e75359fdc00d814906107bb90839061485c565b60405180910390a150565b6001546001600160a01b031681565b6004546001600160a01b031681565b600c546001600160a01b031661080c5760405162461bcd60e51b81526004016106ff90615237565b6108198484848430611c37565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b39261084f9291169087906004016148b1565b602060405180830381600087803b15801561086957600080fd5b505af115801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a1919061447e565b6108bd5760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b926108f592911690879033906004016148f5565b602060405180830381600087803b15801561090f57600080fd5b505af1158015610923573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610947919061451f565b5050505050565b600061095982612262565b90505b919050565b61097233846000808686600061227d565b505050565b6109893360008060008686600061227d565b5050565b61072533600085600186868a61227d565b60075460405163b32beb5b60e01b81526001600160a01b039091169063b32beb5b906109ce90339060040161485c565b600060405180830381600087803b1580156109e857600080fd5b505af1158015610725573d6000803e3d6000fd5b670de0b6b3a764000081565b610a10611470565b6001600160a01b0316336001600160a01b031614610a405760405162461bcd60e51b81526004016106ff90614e2d565b610a498c61228d565b610a528b61228d565b610a5b8a61228d565b610a648961228d565b610a6d8861228d565b610a768761228d565b610a7f8661228d565b610a888561228d565b610a918461228d565b610a9a8361228d565b610aa38261228d565b610aac8161228d565b600d80546001600160a01b03199081166001600160a01b038f8116919091179092556003805482168e84161790556004805482168d84161790556000805482168c84161790556001805482168b84161790556005805482168a8416179055600680548216898416179055600780548216888416179055600280548216878416179055600b80548216868416179055600a8054821685841617905560098054821692841692831790556008805490911690911790556040517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db990610b90908e9061485c565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a56788a604051610bc7919061485c565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd88289604051610bfe919061485c565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b88604051610c35919061485c565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f87604051610c6c919061485c565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa086604051610ca3919061485c565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d85604051610cda919061485c565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db26484604051610d11919061485c565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe7880083604051610d48919061485c565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d82604051610d7f919061485c565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd81604051610db6919061485c565b60405180910390a1505050505050505050505050565b6002546001600160a01b031681565b6801158e460913d0000081565b610df98989898989898989896122d2565b505050505050505050565b600c546001600160a01b0316610e2c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a255391610e5e9133910161485c565b60206040518083038186803b158015610e7657600080fd5b505afa158015610e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eae919061451f565b600c54909150610eec906001600160a01b0316610eda836801158e460913d0000063ffffffff6124ab16565b600a546001600160a01b0316856124f6565b50610989611607565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f71919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b505afa158015610fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffb919061451f565b905061100d828263ffffffff6127a716565b9250505090565b600c546001600160a01b031661103c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a25539161106e9133910161485c565b60206040518083038186803b15801561108657600080fd5b505afa15801561109a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110be919061451f565b600c54600a54919250611101916001600160a01b039182169116867f000000000000000000000000000000000000000000000000000000000000000087876127cc565b50610725611607565b600a546040516370a0823160e01b8152600091309183916001600160a01b0316906370a082319061113f90859060040161485c565b60206040518083038186803b15801561115757600080fd5b505afa15801561116b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118f919061451f565b905061119f33838888888c612a19565b6111af818763ffffffff6127a716565b600a546040516370a0823160e01b81526001600160a01b03909116906370a08231906111df90869060040161485c565b60206040518083038186803b1580156111f757600080fd5b505afa15801561120b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122f919061451f565b1461124c5760405162461bcd60e51b81526004016106ff90614ac1565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611282929116908a906004016148b1565b602060405180830381600087803b15801561129c57600080fd5b505af11580156112b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d4919061447e565b6112f05760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611328929116908a9033906004016148f5565b602060405180830381600087803b15801561134257600080fd5b505af1158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a919061451f565b979650505050505050565b6000546001600160a01b031681565b6107258484848433611c37565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b60008060405161147f9061483f565b6040519081900390205492915050565b6114a260008088600089898989896122d2565b505050505050565b6114b987878787878787611a81565b50505050505050565b6003546001600160a01b031681565b60405180604001604052806012815260200171426f72726f7765724f7065726174696f6e7360701b81525081565b600b546001600160a01b031681565b6109723360008560008686600061227d565b600c546001600160a01b031681565b6114a23386868686868c61227d565b600c546001600160a01b031690565b611555612a2b565b6109728360008060008686600061227d565b6008546001600160a01b031681565b600a546001600160a01b031681565b6003546040805163f92d343360e01b815290516000926001600160a01b03169163f92d3433916004808301926020929190829003018186803b1580156115ca57600080fd5b505afa1580156115de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611602919061451f565b905090565b600454600054600a546001600160a01b0392831692918216911661162b8333612a55565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561167157600080fd5b505af1158015611685573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a9919061451f565b90506116b481612af6565b604051630b07655760e01b81526001600160a01b03851690630b076557906116e090339060040161485c565b600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50506040516309019aaf60e31b8152600092506001600160a01b038716915063480cd5789061174190339060040161485c565b60206040518083038186803b15801561175957600080fd5b505afa15801561176d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611791919061451f565b90506000856001600160a01b031663d66a2553336040518263ffffffff1660e01b81526004016117c1919061485c565b60206040518083038186803b1580156117d957600080fd5b505afa1580156117ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611811919061451f565b90506118368433611831846801158e460913d0000063ffffffff6124ab16565b612b1c565b600061184783600084600088612bb8565b905061185281612c43565b604051631fc5750960e31b81526001600160a01b0388169063fe2ba8489061187e90339060040161485c565b600060405180830381600087803b15801561189857600080fd5b505af11580156118ac573d6000803e3d6000fd5b50506040516365e89c5760e11b81526001600160a01b038a16925063cbd138ae91506118dc90339060040161485c565b600060405180830381600087803b1580156118f657600080fd5b505af115801561190a573d6000803e3d6000fd5b50505050336001600160a01b03166000805160206153378339815191526000806000600160405161193e9493929190614918565b60405180910390a261196a868633611965866801158e460913d0000063ffffffff6124ab16565b612ce8565b60065461198d90879087906001600160a01b03166801158e460913d00000612ce8565b6040516364a197f360e01b81526001600160a01b038716906364a197f3906119bb90339087906004016148b1565b600060405180830381600087803b1580156119d557600080fd5b505af11580156119e9573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038116611a1c5760405162461bcd60e51b81526004016106ff90614af8565b806001600160a01b0316611a2e611470565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611a719061483f565b6040519081900390209190915550565b600c546001600160a01b0316611aa95760405162461bcd60e51b81526004016106ff90615237565b83158015611ab75750600085115b15611add57600c54600a54611adb916001600160a01b0390811691889116846124f6565b505b611aed3387878787878d30612da2565b838015611afa5750600085115b156114b957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611b359291169089906004016148b1565b602060405180830381600087803b158015611b4f57600080fd5b505af1158015611b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b87919061447e565b611ba35760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611bdb92911690899033906004016148f5565b602060405180830381600087803b158015611bf557600080fd5b505af1158015611c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2d919061451f565b5050505050505050565b611c3f614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152611c77614131565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611cc757600080fd5b505af1158015611cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cff919061451f565b808252600090611d0e9061337a565b9050611d1a8882613415565b8251611d269033613501565b6040820187905280611d6757611d4683600001518460400151898b6135a3565b602083018190526040830151611d619163ffffffff6127a716565b60408301525b611d74826040015161375c565b611d818260400151612262565b60608301819052611d8e57fe5b611da13483606001518460000151613785565b60808301526060820151611db69034906137c4565b60a08301528015611dd357611dce82608001516137f9565b611e06565b611de0826080015161389e565b6000611df9346001856060015160018760000151612bb8565b9050611e0481612c43565b505b8251604051635d6b480f60e01b81526001600160a01b0390911690635d6b480f90611e389033906001906004016148b1565b600060405180830381600087803b158015611e5257600080fd5b505af1158015611e66573d6000803e3d6000fd5b505084516040516372423c1760e01b81526001600160a01b0390911692506372423c179150611e9b90339034906004016148b1565b602060405180830381600087803b158015611eb557600080fd5b505af1158015611ec9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eed919061451f565b5082516060830151604051639976cf4560e01b81526001600160a01b0390921691639976cf4591611f23913391906004016148b1565b602060405180830381600087803b158015611f3d57600080fd5b505af1158015611f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f75919061451f565b5082516040516382fe3eb960e01b81526001600160a01b03909116906382fe3eb990611fa590339060040161485c565b600060405180830381600087803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b50508451604051630c7940bd60e11b81526001600160a01b0390911692506318f2817a915061200690339060040161485c565b602060405180830381600087803b15801561202057600080fd5b505af1158015612034573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612058919061451f565b60c0830152600b5460a08301516040516346f7cf8760e01b81526001600160a01b03909216916346f7cf8791612097913391908b908b906004016148ca565b600060405180830381600087803b1580156120b157600080fd5b505af11580156120c5573d6000803e3d6000fd5b505084516040516315d549f160e01b81526001600160a01b0390911692506315d549f191506120f890339060040161485c565b602060405180830381600087803b15801561211257600080fd5b505af1158015612126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214a919061451f565b60e0830181905260405133917f59cfd0cd754bc5748b6770e94a4ffa5f678d885cb899dcfadc5734edb97c67ab9161218291906152d8565b60405180910390a2612198836020015134613943565b6121b183602001518460400151868a86604001516139bf565b602083015160408401516006546121dd9291906001600160a01b03166801158e460913d00000806139bf565b606082015160c083015160405133926000805160206153378339815191529261220b92349190600090614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc0022741836020015160405161225091906152d8565b60405180910390a25050505050505050565b6000610959826801158e460913d0000063ffffffff6127a716565b6114b98787878787878733612da2565b6001600160a01b0381166122b35760405162461bcd60e51b81526004016106ff90614c3a565b803b806109895760405162461bcd60e51b81526004016106ff90614fde565b600c546001600160a01b03166122fa5760405162461bcd60e51b81526004016106ff90615237565b851580156123085750600087115b1561234f57600c54600a5461234d916001600160a01b039081169116857f000000000000000000000000000000000000000000000000000000000000000086866127cc565b505b61235f3389898989898f30612da2565b85801561236c5750600087115b15610df957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b3926123a7929116908b906004016148b1565b602060405180830381600087803b1580156123c157600080fd5b505af11580156123d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f9919061447e565b6124155760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b9261244d929116908b9033906004016148f5565b602060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f919061451f565b50505050505050505050565b60006124ed83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a79565b90505b92915050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561253257600080fd5b505afa158015612546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061256a91906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161259a919061485c565b60206040518083038186803b1580156125b257600080fd5b505afa1580156125c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ea919061451f565b9050306001600160a01b03831663605629d633838a893561261160408c0160208d01614803565b8b604001358c606001356040518863ffffffff1660e01b815260040161263d9796959493929190614870565b600060405180830381600087803b15801561265757600080fd5b505af115801561266b573d6000803e3d6000fd5b50505050866126fc83856001600160a01b03166370a08231856040518263ffffffff1660e01b81526004016126a0919061485c565b60206040518083038186803b1580156126b857600080fd5b505afa1580156126cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f0919061451f565b9063ffffffff6124ab16565b146127195760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c9223906127499089908b9033906004016148f5565b602060405180830381600087803b15801561276357600080fd5b505af1158015612777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279b919061451f565b98975050505050505050565b6000828201838110156124ed5760405162461bcd60e51b81526004016106ff90614a8a565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284091906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612870919061485c565b60206040518083038186803b15801561288857600080fd5b505afa15801561289c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c0919061451f565b87516020015190915030906001600160a01b0388166330f28b7a8a6128e58585613aa5565b338b8b6040518663ffffffff1660e01b8152600401612908959493929190615267565b600060405180830381600087803b15801561292257600080fd5b505af1158015612936573d6000803e3d6000fd5b505050508061296b84866001600160a01b03166370a08231866040518263ffffffff1660e01b81526004016126a0919061485c565b146129885760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c9223906129b8908d90859033906004016148f5565b602060405180830381600087803b1580156129d257600080fd5b505af11580156129e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0a919061451f565b9b9a5050505050505050505050565b6114a28660008660018787878c612da2565b6005546001600160a01b031633146106925760405162461bcd60e51b81526004016106ff9061507c565b6040516321e3780160e01b81526000906001600160a01b038416906321e3780190612a8490859060040161485c565b60206040518083038186803b158015612a9c57600080fd5b505afa158015612ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad4919061451f565b9050806001146109725760405162461bcd60e51b81526004016106ff90614ddf565b612aff8161337a565b156107115760405162461bcd60e51b81526004016106ff90614b8a565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190612b4a90869060040161485c565b60206040518083038186803b158015612b6257600080fd5b505afa158015612b76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9a919061451f565b10156109725760405162461bcd60e51b81526004016106ff90614997565b600080612bc36113a1565b90506000612bcf610ef5565b905086612beb57612be6828963ffffffff6124ab16565b612bfb565b612bfb828963ffffffff6127a716565b915084612c1757612c12818763ffffffff6124ab16565b612c27565b612c27818763ffffffff6127a716565b90506000612c36838387613785565b9998505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9157600080fd5b505afa158015612ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc9919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614d70565b60405163121cbc4d60e11b81526001600160a01b03851690632439789a90612d149084906004016152d8565b600060405180830381600087803b158015612d2e57600080fd5b505af1158015612d42573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b0386169250639dc29fac9150612d7490859085906004016148b1565b600060405180830381600087803b158015612d8e57600080fd5b505af1158015611c2d573d6000803e3d6000fd5b612daa614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152612de2614176565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e3257600080fd5b505af1158015612e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6a919061451f565b808252612e769061337a565b15156101c08201528615612e9c57612e9384826101c00151613415565b612e9c88613ad7565b612ea589613af7565b612eaf8989613b1e565b8151612ebb908b612a55565b336001600160a01b038b161480612ef157506005546001600160a01b031633148015612ee75750600034115b8015612ef1575087155b612ef757fe5b8151604051630b07655760e01b81526001600160a01b0390911690630b07655790612f26908d9060040161485c565b600060405180830381600087803b158015612f4057600080fd5b505af1158015612f54573d6000803e3d6000fd5b50505050612f62348a613b51565b15156060830152602082015260408101889052868015612f855750806101c00151155b15612fc057612f9e826000015183604001518a876135a3565b61012082018190526040820151612fba9163ffffffff6127a716565b60408201525b815160405163d66a255360e01b81526001600160a01b039091169063d66a255390612fef908d9060040161485c565b60206040518083038186803b15801561300757600080fd5b505afa15801561301b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303f919061451f565b608082015281516040516309019aaf60e31b81526001600160a01b039091169063480cd57890613073908d9060040161485c565b60206040518083038186803b15801561308b57600080fd5b505afa15801561309f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c3919061451f565b60a08201819052608082015182516130dc929190613785565b8160c001818152505061310c8160a0015182608001518360200151846060015185604001518c8760000151613b70565b60e082015260a081015189111561311f57fe5b613130816101c001518a8984613b94565b8615801561313e5750600088115b156131855761316061315b82604001516126f08460800151613c08565b61375c565b61317281608001518260400151613c23565b61318582604001518b8360400151612b1c565b6131a382600001518b8360200151846060015185604001518c613c5b565b6101408301526101608201528151604051630c7940bd60e11b81526001600160a01b03909116906318f2817a906131de908d9060040161485c565b602060405180830381600087803b1580156131f857600080fd5b505af115801561320c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613230919061451f565b8161018001818152505061325c8160a0015182608001518360200151846060015185604001518c613e89565b6101a08201819052600b5460405163015f109360e51b81526001600160a01b0390911691632be2126091613298918e918b908b906004016148ca565b600060405180830381600087803b1580156132b257600080fd5b505af11580156132c6573d6000803e3d6000fd5b50505050896001600160a01b031660008051602061533783398151915282610140015183610160015184610180015160026040516133079493929190614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc002274182610120015160405161334d91906152d8565b60405180910390a261249f8260200151836040015133846020015185606001518d8d88604001518b613eba565b60008061338683613f5e565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133d657600080fd5b505afa1580156133ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061340e919061451f565b1192915050565b801561344857670de0b6b3a76400008211156134435760405162461bcd60e51b81526004016106ff90614c71565b610989565b600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561349657600080fd5b505afa1580156134aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ce919061451f565b82101580156134e55750670de0b6b3a76400008211155b6109895760405162461bcd60e51b81526004016106ff906150c5565b6040516321e3780160e01b81526000906001600160a01b038416906321e378019061353090859060040161485c565b60206040518083038186803b15801561354857600080fd5b505afa15801561355c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613580919061451f565b905080600114156109725760405162461bcd60e51b81526004016106ff90615115565b6000846001600160a01b0316635dba4c4a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135e057600080fd5b505af11580156135f4573d6000803e3d6000fd5b5050604051630631203b60e41b8152600092506001600160a01b038816915063631203b0906136279087906004016152d8565b60206040518083038186803b15801561363f57600080fd5b505afa158015613653573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613677919061451f565b9050613684818585613f8a565b600d546040516340c10f1960e01b81526001600160a01b03878116926340c10f19926136b8929091169085906004016148b1565b600060405180830381600087803b1580156136d257600080fd5b505af11580156136e6573d6000803e3d6000fd5b50505050600d60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561373a57600080fd5b505af115801561374e573d6000803e3d6000fd5b509298975050505050505050565b6809c2007651b25000008110156107115760405162461bcd60e51b81526004016106ff90614f81565b600082156137b85760006137af846137a3878663ffffffff613fca16565b9063ffffffff61400416565b91506137bd9050565b506000195b9392505050565b600081156137f0576137e9826137a38568056bc75e2d6310000063ffffffff613fca16565b90506124f0565b506000196124f0565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561384757600080fd5b505afa15801561385b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387f919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614be3565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156138ec57600080fd5b505afa158015613900573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613924919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614f12565b6000826001600160a01b03168260405161395c9061483c565b60006040518083038185875af1925050503d8060008114613999576040519150601f19603f3d011682016040523d82523d6000602084013e61399e565b606091505b50509050806109725760405162461bcd60e51b81526004016106ff906149f4565b60405163f2e91d7160e01b81526001600160a01b0386169063f2e91d71906139eb9084906004016152d8565b600060405180830381600087803b158015613a0557600080fd5b505af1158015613a19573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b03871692506340c10f199150613a4b90869086906004016148b1565b600060405180830381600087803b158015613a6557600080fd5b505af1158015610df9573d6000803e3d6000fd5b60008184841115613a9d5760405162461bcd60e51b81526004016106ff9190614944565b505050900390565b613aad6141f0565b613ab56141f0565b5050604080518082019091526001600160a01b03929092168252602082015290565b600081116107115760405162461bcd60e51b81526004016106ff9061514c565b341580613b02575080155b6107115760405162461bcd60e51b81526004016106ff90614b3a565b34151580613b2b57508115155b80613b3557508015155b6109895760405162461bcd60e51b81526004016106ff90614cc3565b6000808315613b6557508290506001613b69565b8291505b9250929050565b6000806000613b838a8a8a8a8a8a614046565b915091506000612a0a838387613785565b8315613bcd57613ba38361409c565b8115613bc857613bb68160e001516137f9565b613bc88160e001518260c001516140ba565b610725565b613bda8160e0015161389e565b613bf7816020015182606001518360400151858560000151612bb8565b610100820181905261072590612c43565b6000610959826801158e460913d0000063ffffffff6124ab16565b613c3c826801158e460913d0000063ffffffff6124ab16565b8111156109895760405162461bcd60e51b81526004016106ff90615013565b600080600085613cea5760405163d3d6f84360e01b81526001600160a01b038a169063d3d6f84390613c93908b908b906004016148b1565b602060405180830381600087803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce5919061451f565b613d6a565b6040516372423c1760e01b81526001600160a01b038a16906372423c1790613d18908b908b906004016148b1565b602060405180830381600087803b158015613d3257600080fd5b505af1158015613d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d6a919061451f565b9050600084613df857604051630930874960e11b81526001600160a01b038b16906312610e9290613da1908c908a906004016148b1565b602060405180830381600087803b158015613dbb57600080fd5b505af1158015613dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df3919061451f565b613e78565b604051639976cf4560e01b81526001600160a01b038b1690639976cf4590613e26908c908a906004016148b1565b602060405180830381600087803b158015613e4057600080fd5b505af1158015613e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e78919061451f565b919a91995090975050505050505050565b6000806000613e9c898989898989614046565b915091506000613eac83836137c4565b9a9950505050505050505050565b8215613ed257613ecd89898387866139bf565b613ede565b613ede89898987612ce8565b8415613ef357613eee8987613943565b610df9565b6040516364a197f360e01b81526001600160a01b038a16906364a197f390613f21908a908a906004016148b1565b600060405180830381600087803b158015613f3b57600080fd5b505af1158015613f4f573d6000803e3d6000fd5b50505050505050505050505050565b600080613f696113a1565b90506000613f75610ef5565b9050613f82828286613785565b949350505050565b6000613fa8836137a386670de0b6b3a764000063ffffffff613fca16565b9050818111156107255760405162461bcd60e51b81526004016106ff90615200565b600082613fd9575060006124f0565b82820282848281613fe657fe5b04146124ed5760405162461bcd60e51b81526004016106ff90614d2f565b60006124ed83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506140da565b600080878786614065576140608a8963ffffffff6124ab16565b614075565b6140758a8963ffffffff6127a716565b91508461408c57613df3898763ffffffff6124ab16565b613e78898763ffffffff6127a716565b80156107115760405162461bcd60e51b81526004016106ff90614e5e565b808210156109895760405162461bcd60e51b81526004016106ff906151a3565b600081836140fb5760405162461bcd60e51b81526004016106ff9190614944565b50600083858161410757fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806101e00160405280600081526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b80356124f081615313565b60008083601f840112614223578182fd5b50813567ffffffffffffffff81111561423a578182fd5b602083019150836020828501011115613b6957600080fd5b600060808284031215614263578081fd5b50919050565b6000818303608081121561427b578182fd5b61428560606152e1565b9150604081121561429557600080fd5b506142a060406152e1565b82356142ab81615313565b808252506020830135602082015280825250604082013560208201526060820135604082015292915050565b6000602082840312156142e8578081fd5b81356124ed81615313565b600060208284031215614304578081fd5b81516124ed81615313565b60008060408385031215614321578081fd5b823561432c81615313565b9150602083013561433c81615313565b809150509250929050565b60008060006060848603121561435b578081fd5b833561436681615313565b9250602084013561437681615313565b9150604084013561438681615313565b809150509250925092565b6000806000806000806000806000806000806101808d8f0312156143b3578788fd5b8c356143be81615313565b9b5060208d01356143ce81615313565b9a5060408d01356143de81615313565b995060608d01356143ee81615313565b985060808d01356143fe81615313565b975060a08d013561440e81615313565b965061441d8e60c08f01614207565b955061442c8e60e08f01614207565b945061443c8e6101008f01614207565b935061444c8e6101208f01614207565b925061445c8e6101408f01614207565b915061446c8e6101608f01614207565b90509295989b509295989b509295989b565b60006020828403121561448f578081fd5b81516124ed81615328565b6000608082840312156144ab578081fd5b6124ed8383614252565b600080600060a084860312156144c9578283fd5b6144d38585614269565b9250608084013567ffffffffffffffff8111156144ee578283fd5b6144fa86828701614212565b9497909650939450505050565b600060208284031215614518578081fd5b5035919050565b600060208284031215614530578081fd5b5051919050565b60008060006060848603121561454b578283fd5b83359250602084013561437681615313565b60008060008060e08587031215614572578182fd5b84359350602085013561458481615313565b9250604085013561459481615313565b91506145a38660608701614252565b905092959194509250565b60008060008060008061010087890312156145c7578384fd5b8635955060208701356145d981615313565b945060408701356145e981615313565b93506145f88860608901614269565b925060e087013567ffffffffffffffff811115614613578283fd5b61461f89828a01614212565b979a9699509497509295939492505050565b60008060008060808587031215614646578182fd5b8435935060208501359250604085013561465f81615313565b9150606085013561466f81615313565b939692955090935050565b60008060008060008060c08789031215614692578384fd5b86359550602087013594506040870135935060608701356146b281615328565b925060808701356146c281615313565b915060a08701356146d281615313565b809150509295509295509295565b6000806000806000806000610140888a0312156146fb578081fd5b873596506020880135955060408801359450606088013561471b81615328565b9350608088013561472b81615313565b925060a088013561473b81615313565b915061474a8960c08a01614252565b905092959891949750929550565b60008060008060008060008060006101608a8c031215614776578283fd5b8935985060208a0135975060408a0135965060608a013561479681615328565b955060808a01356147a681615313565b945060a08a01356147b681615313565b93506147c58b60c08c01614269565b92506101408a013567ffffffffffffffff8111156147e1578283fd5b6147ed8c828d01614212565b8194508093505050509295985092959850929598565b600060208284031215614814578081fd5b813560ff811681146124ed578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b84815260208101849052604081018390526080810161493683615308565b606083015295945050505050565b6000602080835283518082850152825b8181101561497057858101830151858201604001528201614954565b818111156149815783604083870101525b50601f01601f1916929092016040019392505050565b6020808252603d908201527f426f72726f7765724f70733a2043616c6c657220646f65736e7420686176652060408201527f656e6f756768205a55534420746f206d616b652072657061796d656e74000000606082015260800190565b6020808252602d908201527f426f72726f7765724f70733a2053656e64696e672045544820746f204163746960408201526c1d99541bdbdb0819985a5b1959609a1b606082015260800190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f5a555344206973206e6f7420626f72726f77656420636f72726563746c790000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60208082526030908201527f426f72726f7765724f7065726174696f6e733a2043616e6e6f7420776974686460408201526f1c985dc8185b99081859190818dbdb1b60821b606082015260800190565b60208082526039908201527f426f72726f7765724f70733a204f7065726174696f6e206e6f74207065726d696040820152787474656420647572696e67205265636f76657279204d6f646560381b606082015260800190565b60208082526037908201527f426f72726f7765724f70733a204f7065726174696f6e206d757374206c65617660408201527632903a3937bb32903bb4ba341024a1a9101f1e9021a1a960491b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526032908201527f4d6178206665652070657263656e74616765206d757374206c657373207468616040820152716e206f7220657175616c20746f203130302560701b606082015260800190565b60208082526046908201527f426f72726f7765724f70733a205468657265206d75737420626520656974686560408201527f72206120636f6c6c61746572616c206368616e6765206f7220612064656274206060820152656368616e676560d01b608082015260a00190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20544352203c20434352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252602e908201527f426f72726f7765724f70733a2054726f766520646f6573206e6f74206578697360408201526d1d081bdc881a5cc818db1bdcd95960921b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252603e908201527f426f72726f7765724f70733a20436f6c6c61746572616c20776974686472617760408201527f616c206e6f74207065726d6974746564205265636f76657279204d6f64650000606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20494352203c204d4352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252603a908201527f426f72726f7765724f70733a2054726f76652773206e65742064656274206d7560408201527f73742062652067726561746572207468616e206d696e696d756d000000000000606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526043908201527f426f72726f7765724f70733a20416d6f756e7420726570616964206d7573742060408201527f6e6f74206265206c6172676572207468616e207468652054726f76652773206460608201526219589d60ea1b608082015260a00190565b60208082526029908201527f426f72726f7765724f70733a2043616c6c6572206973206e6f742053746162696040820152681b1a5d1e48141bdbdb60ba1b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252601c908201527f426f72726f7765724f70733a2054726f76652069732061637469766500000000604082015260600190565b60208082526037908201527f426f72726f7765724f70733a204465627420696e637265617365207265717569604082015276726573206e6f6e2d7a65726f20646562744368616e676560481b606082015260800190565b6020808252603e908201527f426f72726f7765724f70733a2043616e6e6f7420646563726561736520796f7560408201527f722054726f766527732049435220696e205265636f76657279204d6f64650000606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b60208082526016908201527513585cdcd95d081859191c995cdcc81b9bdd081cd95d60521b604082015260600190565b6000610100615277838951614824565b60208801516040840152604088015160608401526152986080840188614824565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b60405181810167ffffffffffffffff8111828210171561530057600080fd5b604052919050565b806003811061095c57fe5b6001600160a01b038116811461071157600080fd5b801515811461071157600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212209d20681b7b6630050fbad5344b16d370ece553865b2bf0ccb789b394933ed00f64736f6c634300060b0033", + "deployedBytecode": "0x60806040526004361061025c5760003560e01c80637778a3db11610144578063a20baee6116100b6578063c6a6cf201161007a578063c6a6cf2014610601578063e9fc346114610614578063ea9638bf14610629578063ec5472fd1461063c578063ec9f7d4614610651578063f92d3433146106665761025c565b8063a20baee614610414578063a3f4df7e14610595578063ae918754146105b7578063afbc74b5146105cc578063b5c89bab146105ec5761025c565b8063860665b311610108578063860665b314610510578063887105d314610523578063893d20e814610538578063899fe15e1461054d5780638d5c3dc11461056d5780639f070670146105805761025c565b80637778a3db14610486578063795d26c3146104a65780637d4f595d146104bb5780637e3eefdc146104db5780637f7dde4a146104fb5761025c565b8063485f190f116101dd5780636f0b0c1c116101a15780636f0b0c1c146103ff57806372fe25aa14610414578063734f622d14610429578063741bef1a14610449578063759b30341461045e578063763a0ef3146104735761025c565b8063485f190f146103795780634ff814431461038c5780635530273c146103ac57806368647db1146103cc5780636ea56960146103df5761025c565b80631a777717116102245780631a777717146102ed5780631bf435551461030d5780632771510a1461032f5780633cc742251461034f5780633d83908a146103645761025c565b80630d43e8ad146102615780630e704d501461028c5780630ff9a512146102a357806312261ee7146102b857806313af4035146102cd575b600080fd5b34801561026d57600080fd5b5061027661067b565b604051610283919061485c565b60405180910390f35b34801561029857600080fd5b506102a161068a565b005b3480156102af57600080fd5b50610276610694565b3480156102c457600080fd5b506102766106a3565b3480156102d957600080fd5b506102a16102e83660046142d7565b6106c7565b3480156102f957600080fd5b506102a161030836600461455d565b610714565b34801561031957600080fd5b5061032261072b565b60405161028391906152d8565b34801561033b57600080fd5b506102a161034a3660046142d7565b610738565b34801561035b57600080fd5b506102766107c6565b34801561037057600080fd5b506102766107d5565b6102a1610387366004614631565b6107e4565b34801561039857600080fd5b506103226103a7366004614507565b61094e565b3480156103b857600080fd5b506102a16103c7366004614537565b610961565b6102a16103da36600461430f565b610977565b3480156103eb57600080fd5b506102a16103fa366004614631565b61098d565b34801561040b57600080fd5b506102a161099e565b34801561042057600080fd5b506103226109fc565b34801561043557600080fd5b506102a1610444366004614391565b610a08565b34801561045557600080fd5b50610276610dcc565b34801561046a57600080fd5b50610322610ddb565b6102a1610481366004614758565b610de8565b34801561049257600080fd5b506102a16104a136600461449a565b610e04565b3480156104b257600080fd5b50610322610ef5565b3480156104c757600080fd5b506102a16104d63660046144b5565b611014565b3480156104e757600080fd5b506103226104f6366004614631565b61110a565b34801561050757600080fd5b50610276611385565b6102a161051e366004614631565b611394565b34801561052f57600080fd5b506103226113a1565b34801561054457600080fd5b50610276611470565b34801561055957600080fd5b506102a16105683660046145ae565b61148f565b6102a161057b3660046146e0565b6114aa565b34801561058c57600080fd5b506102766114c2565b3480156105a157600080fd5b506105aa6114d1565b6040516102839190614944565b3480156105c357600080fd5b506102766114ff565b3480156105d857600080fd5b506102a16105e7366004614537565b61150e565b3480156105f857600080fd5b50610276611520565b6102a161060f36600461467a565b61152f565b34801561062057600080fd5b5061027661153e565b6102a1610637366004614347565b61154d565b34801561064857600080fd5b50610276611567565b34801561065d57600080fd5b50610276611576565b34801561067257600080fd5b50610322611585565b600d546001600160a01b031681565b610692611607565b565b6009546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6106cf611470565b6001600160a01b0316336001600160a01b0316146107085760405162461bcd60e51b81526004016106ff90614e2d565b60405180910390fd5b610711816119f6565b50565b610725600080866000878787611a81565b50505050565b6809c2007651b250000081565b610740611470565b6001600160a01b0316336001600160a01b0316146107705760405162461bcd60e51b81526004016106ff90614e2d565b600c80546001600160a01b0319166001600160a01b0383161790556040517f6926b3375b54960080b7d8a184061f39a02e8c3bf64aa9df7e75359fdc00d814906107bb90839061485c565b60405180910390a150565b6001546001600160a01b031681565b6004546001600160a01b031681565b600c546001600160a01b031661080c5760405162461bcd60e51b81526004016106ff90615237565b6108198484848430611c37565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b39261084f9291169087906004016148b1565b602060405180830381600087803b15801561086957600080fd5b505af115801561087d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a1919061447e565b6108bd5760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b926108f592911690879033906004016148f5565b602060405180830381600087803b15801561090f57600080fd5b505af1158015610923573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610947919061451f565b5050505050565b600061095982612262565b90505b919050565b61097233846000808686600061227d565b505050565b6109893360008060008686600061227d565b5050565b61072533600085600186868a61227d565b60075460405163b32beb5b60e01b81526001600160a01b039091169063b32beb5b906109ce90339060040161485c565b600060405180830381600087803b1580156109e857600080fd5b505af1158015610725573d6000803e3d6000fd5b670de0b6b3a764000081565b610a10611470565b6001600160a01b0316336001600160a01b031614610a405760405162461bcd60e51b81526004016106ff90614e2d565b610a498c61228d565b610a528b61228d565b610a5b8a61228d565b610a648961228d565b610a6d8861228d565b610a768761228d565b610a7f8661228d565b610a888561228d565b610a918461228d565b610a9a8361228d565b610aa38261228d565b610aac8161228d565b600d80546001600160a01b03199081166001600160a01b038f8116919091179092556003805482168e84161790556004805482168d84161790556000805482168c84161790556001805482168b84161790556005805482168a8416179055600680548216898416179055600780548216888416179055600280548216878416179055600b80548216868416179055600a8054821685841617905560098054821692841692831790556008805490911690911790556040517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db990610b90908e9061485c565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a56788a604051610bc7919061485c565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd88289604051610bfe919061485c565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b88604051610c35919061485c565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f87604051610c6c919061485c565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa086604051610ca3919061485c565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d85604051610cda919061485c565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db26484604051610d11919061485c565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe7880083604051610d48919061485c565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d82604051610d7f919061485c565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd81604051610db6919061485c565b60405180910390a1505050505050505050505050565b6002546001600160a01b031681565b6801158e460913d0000081565b610df98989898989898989896122d2565b505050505050505050565b600c546001600160a01b0316610e2c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a255391610e5e9133910161485c565b60206040518083038186803b158015610e7657600080fd5b505afa158015610e8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eae919061451f565b600c54909150610eec906001600160a01b0316610eda836801158e460913d0000063ffffffff6124ab16565b600a546001600160a01b0316856124f6565b50610989611607565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f71919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b505afa158015610fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffb919061451f565b905061100d828263ffffffff6127a716565b9250505090565b600c546001600160a01b031661103c5760405162461bcd60e51b81526004016106ff90615237565b6004805460405163d66a255360e01b81526000926001600160a01b039092169163d66a25539161106e9133910161485c565b60206040518083038186803b15801561108657600080fd5b505afa15801561109a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110be919061451f565b600c54600a54919250611101916001600160a01b039182169116867f000000000000000000000000000000000000000000000000000000000000000087876127cc565b50610725611607565b600a546040516370a0823160e01b8152600091309183916001600160a01b0316906370a082319061113f90859060040161485c565b60206040518083038186803b15801561115757600080fd5b505afa15801561116b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118f919061451f565b905061119f33838888888c612a19565b6111af818763ffffffff6127a716565b600a546040516370a0823160e01b81526001600160a01b03909116906370a08231906111df90869060040161485c565b60206040518083038186803b1580156111f757600080fd5b505afa15801561120b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122f919061451f565b1461124c5760405162461bcd60e51b81526004016106ff90614ac1565b600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611282929116908a906004016148b1565b602060405180830381600087803b15801561129c57600080fd5b505af11580156112b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d4919061447e565b6112f05760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611328929116908a9033906004016148f5565b602060405180830381600087803b15801561134257600080fd5b505af1158015611356573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137a919061451f565b979650505050505050565b6000546001600160a01b031681565b6107258484848433611c37565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156113e657600080fd5b505afa1580156113fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141e919061451f565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc357600080fd5b60008060405161147f9061483f565b6040519081900390205492915050565b6114a260008088600089898989896122d2565b505050505050565b6114b987878787878787611a81565b50505050505050565b6003546001600160a01b031681565b60405180604001604052806012815260200171426f72726f7765724f7065726174696f6e7360701b81525081565b600b546001600160a01b031681565b6109723360008560008686600061227d565b600c546001600160a01b031681565b6114a23386868686868c61227d565b600c546001600160a01b031690565b611555612a2b565b6109728360008060008686600061227d565b6008546001600160a01b031681565b600a546001600160a01b031681565b6003546040805163f92d343360e01b815290516000926001600160a01b03169163f92d3433916004808301926020929190829003018186803b1580156115ca57600080fd5b505afa1580156115de573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611602919061451f565b905090565b600454600054600a546001600160a01b0392831692918216911661162b8333612a55565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561167157600080fd5b505af1158015611685573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a9919061451f565b90506116b481612af6565b604051630b07655760e01b81526001600160a01b03851690630b076557906116e090339060040161485c565b600060405180830381600087803b1580156116fa57600080fd5b505af115801561170e573d6000803e3d6000fd5b50506040516309019aaf60e31b8152600092506001600160a01b038716915063480cd5789061174190339060040161485c565b60206040518083038186803b15801561175957600080fd5b505afa15801561176d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611791919061451f565b90506000856001600160a01b031663d66a2553336040518263ffffffff1660e01b81526004016117c1919061485c565b60206040518083038186803b1580156117d957600080fd5b505afa1580156117ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611811919061451f565b90506118368433611831846801158e460913d0000063ffffffff6124ab16565b612b1c565b600061184783600084600088612bb8565b905061185281612c43565b604051631fc5750960e31b81526001600160a01b0388169063fe2ba8489061187e90339060040161485c565b600060405180830381600087803b15801561189857600080fd5b505af11580156118ac573d6000803e3d6000fd5b50506040516365e89c5760e11b81526001600160a01b038a16925063cbd138ae91506118dc90339060040161485c565b600060405180830381600087803b1580156118f657600080fd5b505af115801561190a573d6000803e3d6000fd5b50505050336001600160a01b03166000805160206153378339815191526000806000600160405161193e9493929190614918565b60405180910390a261196a868633611965866801158e460913d0000063ffffffff6124ab16565b612ce8565b60065461198d90879087906001600160a01b03166801158e460913d00000612ce8565b6040516364a197f360e01b81526001600160a01b038716906364a197f3906119bb90339087906004016148b1565b600060405180830381600087803b1580156119d557600080fd5b505af11580156119e9573d6000803e3d6000fd5b5050505050505050505050565b6001600160a01b038116611a1c5760405162461bcd60e51b81526004016106ff90614af8565b806001600160a01b0316611a2e611470565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611a719061483f565b6040519081900390209190915550565b600c546001600160a01b0316611aa95760405162461bcd60e51b81526004016106ff90615237565b83158015611ab75750600085115b15611add57600c54600a54611adb916001600160a01b0390811691889116846124f6565b505b611aed3387878787878d30612da2565b838015611afa5750600085115b156114b957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611b359291169089906004016148b1565b602060405180830381600087803b158015611b4f57600080fd5b505af1158015611b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b87919061447e565b611ba35760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b92611bdb92911690899033906004016148f5565b602060405180830381600087803b158015611bf557600080fd5b505af1158015611c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2d919061451f565b5050505050505050565b611c3f614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152611c77614131565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611cc757600080fd5b505af1158015611cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cff919061451f565b808252600090611d0e9061337a565b9050611d1a8882613415565b8251611d269033613501565b6040820187905280611d6757611d4683600001518460400151898b6135a3565b602083018190526040830151611d619163ffffffff6127a716565b60408301525b611d74826040015161375c565b611d818260400151612262565b60608301819052611d8e57fe5b611da13483606001518460000151613785565b60808301526060820151611db69034906137c4565b60a08301528015611dd357611dce82608001516137f9565b611e06565b611de0826080015161389e565b6000611df9346001856060015160018760000151612bb8565b9050611e0481612c43565b505b8251604051635d6b480f60e01b81526001600160a01b0390911690635d6b480f90611e389033906001906004016148b1565b600060405180830381600087803b158015611e5257600080fd5b505af1158015611e66573d6000803e3d6000fd5b505084516040516372423c1760e01b81526001600160a01b0390911692506372423c179150611e9b90339034906004016148b1565b602060405180830381600087803b158015611eb557600080fd5b505af1158015611ec9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eed919061451f565b5082516060830151604051639976cf4560e01b81526001600160a01b0390921691639976cf4591611f23913391906004016148b1565b602060405180830381600087803b158015611f3d57600080fd5b505af1158015611f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f75919061451f565b5082516040516382fe3eb960e01b81526001600160a01b03909116906382fe3eb990611fa590339060040161485c565b600060405180830381600087803b158015611fbf57600080fd5b505af1158015611fd3573d6000803e3d6000fd5b50508451604051630c7940bd60e11b81526001600160a01b0390911692506318f2817a915061200690339060040161485c565b602060405180830381600087803b15801561202057600080fd5b505af1158015612034573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612058919061451f565b60c0830152600b5460a08301516040516346f7cf8760e01b81526001600160a01b03909216916346f7cf8791612097913391908b908b906004016148ca565b600060405180830381600087803b1580156120b157600080fd5b505af11580156120c5573d6000803e3d6000fd5b505084516040516315d549f160e01b81526001600160a01b0390911692506315d549f191506120f890339060040161485c565b602060405180830381600087803b15801561211257600080fd5b505af1158015612126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061214a919061451f565b60e0830181905260405133917f59cfd0cd754bc5748b6770e94a4ffa5f678d885cb899dcfadc5734edb97c67ab9161218291906152d8565b60405180910390a2612198836020015134613943565b6121b183602001518460400151868a86604001516139bf565b602083015160408401516006546121dd9291906001600160a01b03166801158e460913d00000806139bf565b606082015160c083015160405133926000805160206153378339815191529261220b92349190600090614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc0022741836020015160405161225091906152d8565b60405180910390a25050505050505050565b6000610959826801158e460913d0000063ffffffff6127a716565b6114b98787878787878733612da2565b6001600160a01b0381166122b35760405162461bcd60e51b81526004016106ff90614c3a565b803b806109895760405162461bcd60e51b81526004016106ff90614fde565b600c546001600160a01b03166122fa5760405162461bcd60e51b81526004016106ff90615237565b851580156123085750600087115b1561234f57600c54600a5461234d916001600160a01b039081169116857f000000000000000000000000000000000000000000000000000000000000000086866127cc565b505b61235f3389898989898f30612da2565b85801561236c5750600087115b15610df957600a54600c5460405163095ea7b360e01b81526001600160a01b039283169263095ea7b3926123a7929116908b906004016148b1565b602060405180830381600087803b1580156123c157600080fd5b505af11580156123d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f9919061447e565b6124155760405162461bcd60e51b81526004016106ff90614ebb565b600c54600a5460405163438b1b4b60e01b81526001600160a01b039283169263438b1b4b9261244d929116908b9033906004016148f5565b602060405180830381600087803b15801561246757600080fd5b505af115801561247b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249f919061451f565b50505050505050505050565b60006124ed83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a79565b90505b92915050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561253257600080fd5b505afa158015612546573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061256a91906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161259a919061485c565b60206040518083038186803b1580156125b257600080fd5b505afa1580156125c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ea919061451f565b9050306001600160a01b03831663605629d633838a893561261160408c0160208d01614803565b8b604001358c606001356040518863ffffffff1660e01b815260040161263d9796959493929190614870565b600060405180830381600087803b15801561265757600080fd5b505af115801561266b573d6000803e3d6000fd5b50505050866126fc83856001600160a01b03166370a08231856040518263ffffffff1660e01b81526004016126a0919061485c565b60206040518083038186803b1580156126b857600080fd5b505afa1580156126cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f0919061451f565b9063ffffffff6124ab16565b146127195760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c9223906127499089908b9033906004016148f5565b602060405180830381600087803b15801561276357600080fd5b505af1158015612777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279b919061451f565b98975050505050505050565b6000828201838110156124ed5760405162461bcd60e51b81526004016106ff90614a8a565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b15801561280857600080fd5b505afa15801561281c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284091906142f3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612870919061485c565b60206040518083038186803b15801561288857600080fd5b505afa15801561289c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c0919061451f565b87516020015190915030906001600160a01b0388166330f28b7a8a6128e58585613aa5565b338b8b6040518663ffffffff1660e01b8152600401612908959493929190615267565b600060405180830381600087803b15801561292257600080fd5b505af1158015612936573d6000803e3d6000fd5b505050508061296b84866001600160a01b03166370a08231866040518263ffffffff1660e01b81526004016126a0919061485c565b146129885760405162461bcd60e51b81526004016106ff90614a41565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c9223906129b8908d90859033906004016148f5565b602060405180830381600087803b1580156129d257600080fd5b505af11580156129e6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a0a919061451f565b9b9a5050505050505050505050565b6114a28660008660018787878c612da2565b6005546001600160a01b031633146106925760405162461bcd60e51b81526004016106ff9061507c565b6040516321e3780160e01b81526000906001600160a01b038416906321e3780190612a8490859060040161485c565b60206040518083038186803b158015612a9c57600080fd5b505afa158015612ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad4919061451f565b9050806001146109725760405162461bcd60e51b81526004016106ff90614ddf565b612aff8161337a565b156107115760405162461bcd60e51b81526004016106ff90614b8a565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190612b4a90869060040161485c565b60206040518083038186803b158015612b6257600080fd5b505afa158015612b76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b9a919061451f565b10156109725760405162461bcd60e51b81526004016106ff90614997565b600080612bc36113a1565b90506000612bcf610ef5565b905086612beb57612be6828963ffffffff6124ab16565b612bfb565b612bfb828963ffffffff6127a716565b915084612c1757612c12818763ffffffff6124ab16565b612c27565b612c27818763ffffffff6127a716565b90506000612c36838387613785565b9998505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c9157600080fd5b505afa158015612ca5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cc9919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614d70565b60405163121cbc4d60e11b81526001600160a01b03851690632439789a90612d149084906004016152d8565b600060405180830381600087803b158015612d2e57600080fd5b505af1158015612d42573d6000803e3d6000fd5b5050604051632770a7eb60e21b81526001600160a01b0386169250639dc29fac9150612d7490859085906004016148b1565b600060405180830381600087803b158015612d8e57600080fd5b505af1158015611c2d573d6000803e3d6000fd5b612daa614111565b50604080516060810182526004546001600160a01b03908116825260005481166020830152600a541691810191909152612de2614176565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612e3257600080fd5b505af1158015612e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6a919061451f565b808252612e769061337a565b15156101c08201528615612e9c57612e9384826101c00151613415565b612e9c88613ad7565b612ea589613af7565b612eaf8989613b1e565b8151612ebb908b612a55565b336001600160a01b038b161480612ef157506005546001600160a01b031633148015612ee75750600034115b8015612ef1575087155b612ef757fe5b8151604051630b07655760e01b81526001600160a01b0390911690630b07655790612f26908d9060040161485c565b600060405180830381600087803b158015612f4057600080fd5b505af1158015612f54573d6000803e3d6000fd5b50505050612f62348a613b51565b15156060830152602082015260408101889052868015612f855750806101c00151155b15612fc057612f9e826000015183604001518a876135a3565b61012082018190526040820151612fba9163ffffffff6127a716565b60408201525b815160405163d66a255360e01b81526001600160a01b039091169063d66a255390612fef908d9060040161485c565b60206040518083038186803b15801561300757600080fd5b505afa15801561301b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303f919061451f565b608082015281516040516309019aaf60e31b81526001600160a01b039091169063480cd57890613073908d9060040161485c565b60206040518083038186803b15801561308b57600080fd5b505afa15801561309f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c3919061451f565b60a08201819052608082015182516130dc929190613785565b8160c001818152505061310c8160a0015182608001518360200151846060015185604001518c8760000151613b70565b60e082015260a081015189111561311f57fe5b613130816101c001518a8984613b94565b8615801561313e5750600088115b156131855761316061315b82604001516126f08460800151613c08565b61375c565b61317281608001518260400151613c23565b61318582604001518b8360400151612b1c565b6131a382600001518b8360200151846060015185604001518c613c5b565b6101408301526101608201528151604051630c7940bd60e11b81526001600160a01b03909116906318f2817a906131de908d9060040161485c565b602060405180830381600087803b1580156131f857600080fd5b505af115801561320c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613230919061451f565b8161018001818152505061325c8160a0015182608001518360200151846060015185604001518c613e89565b6101a08201819052600b5460405163015f109360e51b81526001600160a01b0390911691632be2126091613298918e918b908b906004016148ca565b600060405180830381600087803b1580156132b257600080fd5b505af11580156132c6573d6000803e3d6000fd5b50505050896001600160a01b031660008051602061533783398151915282610140015183610160015184610180015160026040516133079493929190614918565b60405180910390a2336001600160a01b03167f71457d8a5ab7e4561ed49d05338674b73ac3b83b0b315f165f5b12bcc002274182610120015160405161334d91906152d8565b60405180910390a261249f8260200151836040015133846020015185606001518d8d88604001518b613eba565b60008061338683613f5e565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b1580156133d657600080fd5b505afa1580156133ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061340e919061451f565b1192915050565b801561344857670de0b6b3a76400008211156134435760405162461bcd60e51b81526004016106ff90614c71565b610989565b600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561349657600080fd5b505afa1580156134aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ce919061451f565b82101580156134e55750670de0b6b3a76400008211155b6109895760405162461bcd60e51b81526004016106ff906150c5565b6040516321e3780160e01b81526000906001600160a01b038416906321e378019061353090859060040161485c565b60206040518083038186803b15801561354857600080fd5b505afa15801561355c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613580919061451f565b905080600114156109725760405162461bcd60e51b81526004016106ff90615115565b6000846001600160a01b0316635dba4c4a6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156135e057600080fd5b505af11580156135f4573d6000803e3d6000fd5b5050604051630631203b60e41b8152600092506001600160a01b038816915063631203b0906136279087906004016152d8565b60206040518083038186803b15801561363f57600080fd5b505afa158015613653573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613677919061451f565b9050613684818585613f8a565b600d546040516340c10f1960e01b81526001600160a01b03878116926340c10f19926136b8929091169085906004016148b1565b600060405180830381600087803b1580156136d257600080fd5b505af11580156136e6573d6000803e3d6000fd5b50505050600d60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561373a57600080fd5b505af115801561374e573d6000803e3d6000fd5b509298975050505050505050565b6809c2007651b25000008110156107115760405162461bcd60e51b81526004016106ff90614f81565b600082156137b85760006137af846137a3878663ffffffff613fca16565b9063ffffffff61400416565b91506137bd9050565b506000195b9392505050565b600081156137f0576137e9826137a38568056bc75e2d6310000063ffffffff613fca16565b90506124f0565b506000196124f0565b600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561384757600080fd5b505afa15801561385b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061387f919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614be3565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156138ec57600080fd5b505afa158015613900573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613924919061451f565b8110156107115760405162461bcd60e51b81526004016106ff90614f12565b6000826001600160a01b03168260405161395c9061483c565b60006040518083038185875af1925050503d8060008114613999576040519150601f19603f3d011682016040523d82523d6000602084013e61399e565b606091505b50509050806109725760405162461bcd60e51b81526004016106ff906149f4565b60405163f2e91d7160e01b81526001600160a01b0386169063f2e91d71906139eb9084906004016152d8565b600060405180830381600087803b158015613a0557600080fd5b505af1158015613a19573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b03871692506340c10f199150613a4b90869086906004016148b1565b600060405180830381600087803b158015613a6557600080fd5b505af1158015610df9573d6000803e3d6000fd5b60008184841115613a9d5760405162461bcd60e51b81526004016106ff9190614944565b505050900390565b613aad6141f0565b613ab56141f0565b5050604080518082019091526001600160a01b03929092168252602082015290565b600081116107115760405162461bcd60e51b81526004016106ff9061514c565b341580613b02575080155b6107115760405162461bcd60e51b81526004016106ff90614b3a565b34151580613b2b57508115155b80613b3557508015155b6109895760405162461bcd60e51b81526004016106ff90614cc3565b6000808315613b6557508290506001613b69565b8291505b9250929050565b6000806000613b838a8a8a8a8a8a614046565b915091506000612a0a838387613785565b8315613bcd57613ba38361409c565b8115613bc857613bb68160e001516137f9565b613bc88160e001518260c001516140ba565b610725565b613bda8160e0015161389e565b613bf7816020015182606001518360400151858560000151612bb8565b610100820181905261072590612c43565b6000610959826801158e460913d0000063ffffffff6124ab16565b613c3c826801158e460913d0000063ffffffff6124ab16565b8111156109895760405162461bcd60e51b81526004016106ff90615013565b600080600085613cea5760405163d3d6f84360e01b81526001600160a01b038a169063d3d6f84390613c93908b908b906004016148b1565b602060405180830381600087803b158015613cad57600080fd5b505af1158015613cc1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce5919061451f565b613d6a565b6040516372423c1760e01b81526001600160a01b038a16906372423c1790613d18908b908b906004016148b1565b602060405180830381600087803b158015613d3257600080fd5b505af1158015613d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d6a919061451f565b9050600084613df857604051630930874960e11b81526001600160a01b038b16906312610e9290613da1908c908a906004016148b1565b602060405180830381600087803b158015613dbb57600080fd5b505af1158015613dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613df3919061451f565b613e78565b604051639976cf4560e01b81526001600160a01b038b1690639976cf4590613e26908c908a906004016148b1565b602060405180830381600087803b158015613e4057600080fd5b505af1158015613e54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e78919061451f565b919a91995090975050505050505050565b6000806000613e9c898989898989614046565b915091506000613eac83836137c4565b9a9950505050505050505050565b8215613ed257613ecd89898387866139bf565b613ede565b613ede89898987612ce8565b8415613ef357613eee8987613943565b610df9565b6040516364a197f360e01b81526001600160a01b038a16906364a197f390613f21908a908a906004016148b1565b600060405180830381600087803b158015613f3b57600080fd5b505af1158015613f4f573d6000803e3d6000fd5b50505050505050505050505050565b600080613f696113a1565b90506000613f75610ef5565b9050613f82828286613785565b949350505050565b6000613fa8836137a386670de0b6b3a764000063ffffffff613fca16565b9050818111156107255760405162461bcd60e51b81526004016106ff90615200565b600082613fd9575060006124f0565b82820282848281613fe657fe5b04146124ed5760405162461bcd60e51b81526004016106ff90614d2f565b60006124ed83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506140da565b600080878786614065576140608a8963ffffffff6124ab16565b614075565b6140758a8963ffffffff6127a716565b91508461408c57613df3898763ffffffff6124ab16565b613e78898763ffffffff6127a716565b80156107115760405162461bcd60e51b81526004016106ff90614e5e565b808210156109895760405162461bcd60e51b81526004016106ff906151a3565b600081836140fb5760405162461bcd60e51b81526004016106ff9190614944565b50600083858161410757fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806101e00160405280600081526020016000815260200160008152602001600015158152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b80356124f081615313565b60008083601f840112614223578182fd5b50813567ffffffffffffffff81111561423a578182fd5b602083019150836020828501011115613b6957600080fd5b600060808284031215614263578081fd5b50919050565b6000818303608081121561427b578182fd5b61428560606152e1565b9150604081121561429557600080fd5b506142a060406152e1565b82356142ab81615313565b808252506020830135602082015280825250604082013560208201526060820135604082015292915050565b6000602082840312156142e8578081fd5b81356124ed81615313565b600060208284031215614304578081fd5b81516124ed81615313565b60008060408385031215614321578081fd5b823561432c81615313565b9150602083013561433c81615313565b809150509250929050565b60008060006060848603121561435b578081fd5b833561436681615313565b9250602084013561437681615313565b9150604084013561438681615313565b809150509250925092565b6000806000806000806000806000806000806101808d8f0312156143b3578788fd5b8c356143be81615313565b9b5060208d01356143ce81615313565b9a5060408d01356143de81615313565b995060608d01356143ee81615313565b985060808d01356143fe81615313565b975060a08d013561440e81615313565b965061441d8e60c08f01614207565b955061442c8e60e08f01614207565b945061443c8e6101008f01614207565b935061444c8e6101208f01614207565b925061445c8e6101408f01614207565b915061446c8e6101608f01614207565b90509295989b509295989b509295989b565b60006020828403121561448f578081fd5b81516124ed81615328565b6000608082840312156144ab578081fd5b6124ed8383614252565b600080600060a084860312156144c9578283fd5b6144d38585614269565b9250608084013567ffffffffffffffff8111156144ee578283fd5b6144fa86828701614212565b9497909650939450505050565b600060208284031215614518578081fd5b5035919050565b600060208284031215614530578081fd5b5051919050565b60008060006060848603121561454b578283fd5b83359250602084013561437681615313565b60008060008060e08587031215614572578182fd5b84359350602085013561458481615313565b9250604085013561459481615313565b91506145a38660608701614252565b905092959194509250565b60008060008060008061010087890312156145c7578384fd5b8635955060208701356145d981615313565b945060408701356145e981615313565b93506145f88860608901614269565b925060e087013567ffffffffffffffff811115614613578283fd5b61461f89828a01614212565b979a9699509497509295939492505050565b60008060008060808587031215614646578182fd5b8435935060208501359250604085013561465f81615313565b9150606085013561466f81615313565b939692955090935050565b60008060008060008060c08789031215614692578384fd5b86359550602087013594506040870135935060608701356146b281615328565b925060808701356146c281615313565b915060a08701356146d281615313565b809150509295509295509295565b6000806000806000806000610140888a0312156146fb578081fd5b873596506020880135955060408801359450606088013561471b81615328565b9350608088013561472b81615313565b925060a088013561473b81615313565b915061474a8960c08a01614252565b905092959891949750929550565b60008060008060008060008060006101608a8c031215614776578283fd5b8935985060208a0135975060408a0135965060608a013561479681615328565b955060808a01356147a681615313565b945060a08a01356147b681615313565b93506147c58b60c08c01614269565b92506101408a013567ffffffffffffffff8111156147e1578283fd5b6147ed8c828d01614212565b8194508093505050509295985092959850929598565b600060208284031215614814578081fd5b813560ff811681146124ed578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b84815260208101849052604081018390526080810161493683615308565b606083015295945050505050565b6000602080835283518082850152825b8181101561497057858101830151858201604001528201614954565b818111156149815783604083870101525b50601f01601f1916929092016040019392505050565b6020808252603d908201527f426f72726f7765724f70733a2043616c6c657220646f65736e7420686176652060408201527f656e6f756768205a55534420746f206d616b652072657061796d656e74000000606082015260800190565b6020808252602d908201527f426f72726f7765724f70733a2053656e64696e672045544820746f204163746960408201526c1d99541bdbdb0819985a5b1959609a1b606082015260800190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601e908201527f5a555344206973206e6f7420626f72726f77656420636f72726563746c790000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60208082526030908201527f426f72726f7765724f7065726174696f6e733a2043616e6e6f7420776974686460408201526f1c985dc8185b99081859190818dbdb1b60821b606082015260800190565b60208082526039908201527f426f72726f7765724f70733a204f7065726174696f6e206e6f74207065726d696040820152787474656420647572696e67205265636f76657279204d6f646560381b606082015260800190565b60208082526037908201527f426f72726f7765724f70733a204f7065726174696f6e206d757374206c65617660408201527632903a3937bb32903bb4ba341024a1a9101f1e9021a1a960491b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526032908201527f4d6178206665652070657263656e74616765206d757374206c657373207468616040820152716e206f7220657175616c20746f203130302560701b606082015260800190565b60208082526046908201527f426f72726f7765724f70733a205468657265206d75737420626520656974686560408201527f72206120636f6c6c61746572616c206368616e6765206f7220612064656274206060820152656368616e676560d01b608082015260a00190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20544352203c20434352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252602e908201527f426f72726f7765724f70733a2054726f766520646f6573206e6f74206578697360408201526d1d081bdc881a5cc818db1bdcd95960921b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252603e908201527f426f72726f7765724f70733a20436f6c6c61746572616c20776974686472617760408201527f616c206e6f74207065726d6974746564205265636f76657279204d6f64650000606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b60208082526049908201527f426f72726f7765724f70733a20416e206f7065726174696f6e2074686174207760408201527f6f756c6420726573756c7420696e20494352203c204d4352206973206e6f74206060820152681c195c9b5a5d1d195960ba1b608082015260a00190565b6020808252603a908201527f426f72726f7765724f70733a2054726f76652773206e65742064656274206d7560408201527f73742062652067726561746572207468616e206d696e696d756d000000000000606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526043908201527f426f72726f7765724f70733a20416d6f756e7420726570616964206d7573742060408201527f6e6f74206265206c6172676572207468616e207468652054726f76652773206460608201526219589d60ea1b608082015260a00190565b60208082526029908201527f426f72726f7765724f70733a2043616c6c6572206973206e6f742053746162696040820152681b1a5d1e48141bdbdb60ba1b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252601c908201527f426f72726f7765724f70733a2054726f76652069732061637469766500000000604082015260600190565b60208082526037908201527f426f72726f7765724f70733a204465627420696e637265617365207265717569604082015276726573206e6f6e2d7a65726f20646562744368616e676560481b606082015260800190565b6020808252603e908201527f426f72726f7765724f70733a2043616e6e6f7420646563726561736520796f7560408201527f722054726f766527732049435220696e205265636f76657279204d6f64650000606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b60208082526016908201527513585cdcd95d081859191c995cdcc81b9bdd081cd95d60521b604082015260600190565b6000610100615277838951614824565b60208801516040840152604088015160608401526152986080840188614824565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b60405181810167ffffffffffffffff8111828210171561530057600080fd5b604052919050565b806003811061095c57fe5b6001600160a01b038116811461071157600080fd5b801515811461071157600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212209d20681b7b6630050fbad5344b16d370ece553865b2bf0ccb789b394933ed00f64736f6c634300060b0033", + "devdoc": { + "kind": "dev", + "methods": { + "getOwner()": { + "returns": { + "_owner": "Address of the owner. " + } + }, + "setAddresses(address,address,address,address,address,address,address,address,address,address,address,address)": { + "details": "initializer function, checks addresses are contracts", + "params": { + "_activePoolAddress": "ActivePool contract address", + "_collSurplusPoolAddress": "CollSurplusPool contract address", + "_defaultPoolAddress": "DefaultPool contract address", + "_feeDistributorAddress": "feeDistributor contract address", + "_gasPoolAddress": "GasPool contract address", + "_liquityBaseParamsAddress": "LiquidityBaseParams contract address", + "_priceFeedAddress": "PrideFeed contract address", + "_sortedTrovesAddress": "SortedTroves contract address", + "_stabilityPoolAddress": "StabilityPool contract address", + "_troveManagerAddress": "TroveManager contract address", + "_zeroStakingAddress": "ZEROStaking contract address", + "_zusdTokenAddress": "ZUSDToken contract address" + } + }, + "setOwner(address)": { + "params": { + "_owner": "Address of the owner. " + } + }, + "withdrawZusdAndConvertToDLLR(uint256,uint256,address,address)": { + "returns": { + "_0": "DLLR amount minted" + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "MIN_NET_DEBT()": { + "notice": "Minimum amount of net ZUSD debt a trove must have" + }, + "ZUSD_GAS_COMPENSATION()": { + "notice": "Amount of ZUSD to be locked in gas pool on opening troves" + }, + "addColl(address,address)": { + "notice": "Send ETH as collateral to a trove" + }, + "claimCollateral()": { + "notice": "Claim remaining collateral from a redemption or from a liquidation with ICR > MCR in Recovery Mode" + }, + "closeNueTrove((uint256,uint8,bytes32,bytes32))": { + "notice": "allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE. This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD." + }, + "closeNueTroveWithPermit2(((address,uint256),uint256,uint256),bytes)": { + "notice": "allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE. This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD." + }, + "closeTrove()": { + "notice": "allows a borrower to repay all debt, withdraw all their collateral, and close their Trove. Requires the borrower have a ZUSD balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` ZUSD." + }, + "constructor": "Constructor ", + "getOwner()": { + "notice": "Return address of the owner." + }, + "moveETHGainToTrove(address,address,address)": { + "notice": "Send ETH as collateral to a trove. Called by only the Stability Pool." + }, + "permit2()": { + "notice": "CONSTANT / IMMUTABLE VARIABLE ONLY " + }, + "repayZUSD(uint256,address,address)": { + "notice": "Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly" + }, + "repayZusdFromDLLR(uint256,address,address,(uint256,uint8,bytes32,bytes32))": { + "notice": "Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly" + }, + "repayZusdFromDLLRWithPermit2(uint256,address,address,((address,uint256),uint256,uint256),bytes)": { + "notice": "Repay ZUSD tokens to a Trove by DLLR: convert DLLR to ZUSD tokens, and then reduce the trove's debt accordingly" + }, + "setAddresses(address,address,address,address,address,address,address,address,address,address,address,address)": { + "notice": "Called only once on init, to set addresses of other Zero contracts. Callable only by owner" + }, + "setOwner(address)": { + "notice": "Set address of the owner (only owner can call this function)" + }, + "withdrawColl(uint256,address,address)": { + "notice": "Withdraw ETH collateral from a trove" + }, + "withdrawZUSD(uint256,uint256,address,address)": { + "notice": "Withdraw ZUSD tokens from a trove: mint new ZUSD tokens to the owner, and increase the trove's debt accordingly" + }, + "withdrawZusdAndConvertToDLLR(uint256,uint256,address,address)": { + "notice": "Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction Zero Line of Credit owner can borrow a specified amount of ZUSD and convert it to DLLR via Sovryn Mynt" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 5495, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "activePool", + "offset": 0, + "slot": "0", + "type": "t_contract(IActivePool)19557" + }, + { + "astId": 5497, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "defaultPool", + "offset": 0, + "slot": "1", + "type": "t_contract(IDefaultPool)20229" + }, + { + "astId": 5500, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "priceFeed", + "offset": 0, + "slot": "2", + "type": "t_contract(IPriceFeed)20458" + }, + { + "astId": 5503, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "liquityBaseParams", + "offset": 0, + "slot": "3", + "type": "t_contract(ILiquityBaseParams)20379" + }, + { + "astId": 4622, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "troveManager", + "offset": 0, + "slot": "4", + "type": "t_contract(ITroveManager)21635" + }, + { + "astId": 4624, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "stabilityPoolAddress", + "offset": 0, + "slot": "5", + "type": "t_address" + }, + { + "astId": 4626, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "gasPoolAddress", + "offset": 0, + "slot": "6", + "type": "t_address" + }, + { + "astId": 4628, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "collSurplusPool", + "offset": 0, + "slot": "7", + "type": "t_contract(ICollSurplusPool)20130" + }, + { + "astId": 4630, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "zeroStaking", + "offset": 0, + "slot": "8", + "type": "t_contract(IZEROStaking)21760" + }, + { + "astId": 4632, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "zeroStakingAddress", + "offset": 0, + "slot": "9", + "type": "t_address" + }, + { + "astId": 4634, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "zusdToken", + "offset": 0, + "slot": "10", + "type": "t_contract(IZUSDToken)21842" + }, + { + "astId": 4636, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "sortedTroves", + "offset": 0, + "slot": "11", + "type": "t_contract(ISortedTroves)20817" + }, + { + "astId": 4638, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "massetManager", + "offset": 0, + "slot": "12", + "type": "t_contract(IMassetManager)6083" + }, + { + "astId": 4640, + "contract": "contracts/BorrowerOperations.sol:BorrowerOperations", + "label": "feeDistributor", + "offset": 0, + "slot": "13", + "type": "t_contract(IFeeDistributor)20298" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_contract(IActivePool)19557": { + "encoding": "inplace", + "label": "contract IActivePool", + "numberOfBytes": "20" + }, + "t_contract(ICollSurplusPool)20130": { + "encoding": "inplace", + "label": "contract ICollSurplusPool", + "numberOfBytes": "20" + }, + "t_contract(IDefaultPool)20229": { + "encoding": "inplace", + "label": "contract IDefaultPool", + "numberOfBytes": "20" + }, + "t_contract(IFeeDistributor)20298": { + "encoding": "inplace", + "label": "contract IFeeDistributor", + "numberOfBytes": "20" + }, + "t_contract(ILiquityBaseParams)20379": { + "encoding": "inplace", + "label": "contract ILiquityBaseParams", + "numberOfBytes": "20" + }, + "t_contract(IMassetManager)6083": { + "encoding": "inplace", + "label": "contract IMassetManager", + "numberOfBytes": "20" + }, + "t_contract(IPriceFeed)20458": { + "encoding": "inplace", + "label": "contract IPriceFeed", + "numberOfBytes": "20" + }, + "t_contract(ISortedTroves)20817": { + "encoding": "inplace", + "label": "contract ISortedTroves", + "numberOfBytes": "20" + }, + "t_contract(ITroveManager)21635": { + "encoding": "inplace", + "label": "contract ITroveManager", + "numberOfBytes": "20" + }, + "t_contract(IZEROStaking)21760": { + "encoding": "inplace", + "label": "contract IZEROStaking", + "numberOfBytes": "20" + }, + "t_contract(IZUSDToken)21842": { + "encoding": "inplace", + "label": "contract IZUSDToken", + "numberOfBytes": "20" + } + } + } +} diff --git a/external/deployments/rskTestnet/BorrowerOperations_Proxy.json b/external/deployments/rskTestnet/BorrowerOperations_Proxy.json new file mode 100644 index 000000000..1f8be056d --- /dev/null +++ b/external/deployments/rskTestnet/BorrowerOperations_Proxy.json @@ -0,0 +1,110 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "UpgradableProxy", + "sourceName": "contracts/Proxy/UpgradableProxy.sol", + "address": "0xba8d7B80bcb3A01A5e713c356fD18EeD299B70D0", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_oldImplementation", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_newImplementation", + "type": "address" + } + ], + "name": "ImplementationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610023336001600160e01b0361002816565b610110565b6001600160a01b03811661006d5760405162461bcd60e51b81526004018080602001828103825260228152602001806105e26022913960400191505060405180910390fd5b6001600160a01b0381166100886001600160e01b036100e616565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b6104c38061011f6000396000f3fe6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b00334f776e61626c653a3a7365744f776e65723a20696e76616c69642061646472657373", + "deployedBytecode": "0x6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/external/deployments/rskTestnet/MocIntegration.json b/external/deployments/rskTestnet/MocIntegration.json new file mode 100644 index 000000000..01719d36a --- /dev/null +++ b/external/deployments/rskTestnet/MocIntegration.json @@ -0,0 +1,547 @@ +{ + "address": "0xdC3e5232db60088D67aA7AF10595979D7eB5290f", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_moc", + "type": "address" + }, + { + "internalType": "address", + "name": "_doc", + "type": "address" + }, + { + "internalType": "address", + "name": "_dllr", + "type": "address" + }, + { + "internalType": "address", + "name": "_massetManager", + "type": "address" + }, + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fromDLLR", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "toRBTC", + "type": "uint256" + } + ], + "name": "GetDocFromDllrAndRedeemRBTC", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newMocVendorAccount", + "type": "address" + } + ], + "name": "MocVendorAccountSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "dllr", + "outputs": [ + { + "internalType": "contract IDLLR", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "doc", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "getDocFromDllrAndRedeemRBTC", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "getDocFromDllrAndRedeemRbtcWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getProxyImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_mocVendorAccount", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "massetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "moc", + "outputs": [ + { + "internalType": "contract IMocMintRedeemDoc", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "mocVendorAccount", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "newMocVedorAccount", + "type": "address" + } + ], + "name": "setMocVendorAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "numDeployments": 6, + "bytecode": "0x6101206040523480156200001257600080fd5b50604051620012cd380380620012cd833981016040819052620000359162000140565b6001600160a01b038516158015906200005657506001600160a01b03841615155b80156200006b57506001600160a01b03831615155b80156200008057506001600160a01b03821615155b80156200009557506001600160a01b03811615155b620000f95760405162461bcd60e51b815260206004820152602a60248201527f4d6f63496e746567726174696f6e3a3a206e6f206e756c6c2061646472657373604482015269195cc8185b1b1bddd95960b21b606482015260840160405180910390fd5b6001600160a01b0394851660805292841660a05290831660c052821660e0521661010052620001b0565b80516001600160a01b03811681146200013b57600080fd5b919050565b600080600080600060a086880312156200015957600080fd5b620001648662000123565b9450620001746020870162000123565b9350620001846040870162000123565b9250620001946060870162000123565b9150620001a46080870162000123565b90509295509295909350565b60805160a05160c05160e051610100516110a16200022c6000396000818160ff015261069301526000818161027501528181610435015261074f01526000818161014f01526103220152600081816101ee015281816103fb01526107150152600081816101a5015281816104f7015261080801526110a16000f3fe6080604052600436106100e15760003560e01c806390e4b7201161007f578063c4d66de811610059578063c4d66de814610297578063e5085517146102b7578063f2fde38b146102d7578063fc176819146102f757600080fd5b806390e4b7201461022e5780639b2633ae14610243578063b5c89bab1461026357600080fd5b806353428253116100bb5780635342825314610193578063715018a6146101c75780637a0a3ac5146101dc5780638da5cb5b1461021057600080fd5b806312261ee7146100ed57806333c507ae1461013d578063460f2de11461017157600080fd5b366100e857005b600080fd5b3480156100f957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b34801561014957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561017d57600080fd5b5061019161018c366004610c64565b610317565b005b34801561019f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d357600080fd5b50610191610619565b3480156101e857600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561021c57600080fd5b506033546001600160a01b0316610121565b34801561023a57600080fd5b5061012161062d565b34801561024f57600080fd5b5061019161025e366004610d7d565b610665565b34801561026f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156102a357600080fd5b506101916102b2366004610e40565b61092c565b3480156102c357600080fd5b506101916102d2366004610e40565b610a47565b3480156102e357600080fd5b506101916102f2366004610e40565b610a5b565b34801561030357600080fd5b50609754610121906001600160a01b031681565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663605629d6338386863561035c6040890160208a01610e64565b604080516001600160e01b031960e089901b1681526001600160a01b0396871660048201529590941660248601526044850192909252606484015260ff16608483015285013560a4820152606085013560c482015260e401600060405180830381600087803b1580156103ce57600080fd5b505af11580156103e2573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820187905284811660448301528693507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af115801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a39190610e87565b146104c95760405162461bcd60e51b81526004016104c090610ea0565b60405180910390fd5b60975460405163b7aa53e760e01b8152600481018590526001600160a01b03918216602482015282821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561053b57600080fd5b505af115801561054f573d6000803e3d6000fd5b50505050600081836001600160a01b03163161056b9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146105b0576040519150601f19603f3d011682016040523d82523d6000602084013e6105b5565b606091505b50509050806105d65760405162461bcd60e51b81526004016104c090610f0f565b604080518781526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a2505050505050565b610621610ad1565b61062b6000610b2b565b565b60006106607f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b815160200151309060006106798383610b7d565b60405163187945bd60e11b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906330f28b7a906106ce908890859033908a90600401610f60565b600060405180830381600087803b1580156106e857600080fd5b505af11580156106fc573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820186905286811660448301528593507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af1158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd9190610e87565b146107da5760405162461bcd60e51b81526004016104c090610ea0565b60975460405163b7aa53e760e01b8152600481018490526001600160a01b03918216602482015284821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561084c57600080fd5b505af1158015610860573d6000803e3d6000fd5b50505050600081856001600160a01b03163161087c9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146108c1576040519150601f19603f3d011682016040523d82523d6000602084013e6108c6565b606091505b50509050806108e75760405162461bcd60e51b81526004016104c090610f0f565b604080518681526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a25050505050505050565b600054610100900460ff161580801561094c5750600054600160ff909116105b806109665750303b158015610966575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104c0565b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b6109f4610bb1565b6109fd82610be0565b8015610a43576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b610a4f610ad1565b610a5881610be0565b50565b610a63610ad1565b6001600160a01b038116610ac85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104c0565b610a5881610b2b565b6033546001600160a01b0316331461062b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104c0565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080518082018252600080825260209182015281518083019092526001600160a01b038416825281018290525b92915050565b600054610100900460ff16610bd85760405162461bcd60e51b81526004016104c090611020565b61062b610c34565b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527fc2a1feb9d65ecb31b0e93a520a66d19319929a2bf58046d92d762c04e7dd06c99060200160405180910390a150565b600054610100900460ff16610c5b5760405162461bcd60e51b81526004016104c090611020565b61062b33610b2b565b60008082840360a0811215610c7857600080fd5b833592506080601f1982011215610c8e57600080fd5b506020830190509250929050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610cd557610cd5610c9c565b60405290565b6001600160a01b0381168114610a5857600080fd5b600082601f830112610d0157600080fd5b813567ffffffffffffffff80821115610d1c57610d1c610c9c565b604051601f8301601f19908116603f01168101908282118183101715610d4457610d44610c9c565b81604052838152866020858801011115610d5d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008082840360a0811215610d9157600080fd5b6080811215610d9f57600080fd5b6040516060810167ffffffffffffffff8282108183111715610dc357610dc3610c9c565b816040526040841215610dd557600080fd5b610ddd610cb2565b935086359150610dec82610cdb565b8184526020870135602085015283835260408701356020840152606087013560408401528295506080870135935080841115610e2757600080fd5b505050610e3685828601610cf0565b9150509250929050565b600060208284031215610e5257600080fd5b8135610e5d81610cdb565b9392505050565b600060208284031215610e7657600080fd5b813560ff81168114610e5d57600080fd5b600060208284031215610e9957600080fd5b5051919050565b6020808252602e908201527f4d6f63496e746567726174696f6e3a3a2072656465656d656420696e636f727260408201526d1958dd08111bd0c8185b5bdd5b9d60921b606082015260800190565b81810381811115610bab57634e487b7160e01b600052601160045260246000fd5b60208082526031908201527f4d6f63496e746567726174696f6e3a3a206572726f72207472616e7366657272604082015270696e672072656465656d6564205242544360781b606082015260800190565b6000610100610f8383885180516001600160a01b03168252602090810151910152565b602080880151604085015260408801516060850152610fb8608085018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c085015260e0840182905284519184018290526000915b80831015610ff957858301820151858401610120015291810191610fda565b6101209250600083828701015282601f19601f830116860101935050505095945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220d0fcc7c15da2d0cf8a6f0df865b7535edea2c45483b951fb883a7a57908c9d0764736f6c63430008110033", + "deployedBytecode": "0x6080604052600436106100e15760003560e01c806390e4b7201161007f578063c4d66de811610059578063c4d66de814610297578063e5085517146102b7578063f2fde38b146102d7578063fc176819146102f757600080fd5b806390e4b7201461022e5780639b2633ae14610243578063b5c89bab1461026357600080fd5b806353428253116100bb5780635342825314610193578063715018a6146101c75780637a0a3ac5146101dc5780638da5cb5b1461021057600080fd5b806312261ee7146100ed57806333c507ae1461013d578063460f2de11461017157600080fd5b366100e857005b600080fd5b3480156100f957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b34801561014957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561017d57600080fd5b5061019161018c366004610c64565b610317565b005b34801561019f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d357600080fd5b50610191610619565b3480156101e857600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561021c57600080fd5b506033546001600160a01b0316610121565b34801561023a57600080fd5b5061012161062d565b34801561024f57600080fd5b5061019161025e366004610d7d565b610665565b34801561026f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156102a357600080fd5b506101916102b2366004610e40565b61092c565b3480156102c357600080fd5b506101916102d2366004610e40565b610a47565b3480156102e357600080fd5b506101916102f2366004610e40565b610a5b565b34801561030357600080fd5b50609754610121906001600160a01b031681565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663605629d6338386863561035c6040890160208a01610e64565b604080516001600160e01b031960e089901b1681526001600160a01b0396871660048201529590941660248601526044850192909252606484015260ff16608483015285013560a4820152606085013560c482015260e401600060405180830381600087803b1580156103ce57600080fd5b505af11580156103e2573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820187905284811660448301528693507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af115801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a39190610e87565b146104c95760405162461bcd60e51b81526004016104c090610ea0565b60405180910390fd5b60975460405163b7aa53e760e01b8152600481018590526001600160a01b03918216602482015282821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561053b57600080fd5b505af115801561054f573d6000803e3d6000fd5b50505050600081836001600160a01b03163161056b9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146105b0576040519150601f19603f3d011682016040523d82523d6000602084013e6105b5565b606091505b50509050806105d65760405162461bcd60e51b81526004016104c090610f0f565b604080518781526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a2505050505050565b610621610ad1565b61062b6000610b2b565b565b60006106607f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b815160200151309060006106798383610b7d565b60405163187945bd60e11b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906330f28b7a906106ce908890859033908a90600401610f60565b600060405180830381600087803b1580156106e857600080fd5b505af11580156106fc573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820186905286811660448301528593507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af1158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd9190610e87565b146107da5760405162461bcd60e51b81526004016104c090610ea0565b60975460405163b7aa53e760e01b8152600481018490526001600160a01b03918216602482015284821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561084c57600080fd5b505af1158015610860573d6000803e3d6000fd5b50505050600081856001600160a01b03163161087c9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146108c1576040519150601f19603f3d011682016040523d82523d6000602084013e6108c6565b606091505b50509050806108e75760405162461bcd60e51b81526004016104c090610f0f565b604080518681526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a25050505050505050565b600054610100900460ff161580801561094c5750600054600160ff909116105b806109665750303b158015610966575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104c0565b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b6109f4610bb1565b6109fd82610be0565b8015610a43576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b610a4f610ad1565b610a5881610be0565b50565b610a63610ad1565b6001600160a01b038116610ac85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104c0565b610a5881610b2b565b6033546001600160a01b0316331461062b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104c0565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080518082018252600080825260209182015281518083019092526001600160a01b038416825281018290525b92915050565b600054610100900460ff16610bd85760405162461bcd60e51b81526004016104c090611020565b61062b610c34565b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527fc2a1feb9d65ecb31b0e93a520a66d19319929a2bf58046d92d762c04e7dd06c99060200160405180910390a150565b600054610100900460ff16610c5b5760405162461bcd60e51b81526004016104c090611020565b61062b33610b2b565b60008082840360a0811215610c7857600080fd5b833592506080601f1982011215610c8e57600080fd5b506020830190509250929050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610cd557610cd5610c9c565b60405290565b6001600160a01b0381168114610a5857600080fd5b600082601f830112610d0157600080fd5b813567ffffffffffffffff80821115610d1c57610d1c610c9c565b604051601f8301601f19908116603f01168101908282118183101715610d4457610d44610c9c565b81604052838152866020858801011115610d5d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008082840360a0811215610d9157600080fd5b6080811215610d9f57600080fd5b6040516060810167ffffffffffffffff8282108183111715610dc357610dc3610c9c565b816040526040841215610dd557600080fd5b610ddd610cb2565b935086359150610dec82610cdb565b8184526020870135602085015283835260408701356020840152606087013560408401528295506080870135935080841115610e2757600080fd5b505050610e3685828601610cf0565b9150509250929050565b600060208284031215610e5257600080fd5b8135610e5d81610cdb565b9392505050565b600060208284031215610e7657600080fd5b813560ff81168114610e5d57600080fd5b600060208284031215610e9957600080fd5b5051919050565b6020808252602e908201527f4d6f63496e746567726174696f6e3a3a2072656465656d656420696e636f727260408201526d1958dd08111bd0c8185b5bdd5b9d60921b606082015260800190565b81810381811115610bab57634e487b7160e01b600052601160045260246000fd5b60208082526031908201527f4d6f63496e746567726174696f6e3a3a206572726f72207472616e7366657272604082015270696e672072656465656d6564205242544360781b606082015260800190565b6000610100610f8383885180516001600160a01b03168252602090810151910152565b602080880151604085015260408801516060850152610fb8608085018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c085015260e0840182905284519184018290526000915b80831015610ff957858301820151858401610120015291810191610fda565b6101209250600083828701015282601f19601f830116860101935050505095945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220d0fcc7c15da2d0cf8a6f0df865b7535edea2c45483b951fb883a7a57908c9d0764736f6c63430008110033", + "implementation": "0x6C4FBCA418B4310cAa59Ce9a3B1D3e8c1E635AdE", + "devdoc": { + "kind": "dev", + "methods": { + "constructor": { + "params": { + "_dllr": "DLLR contract address", + "_doc": "DoC contract address", + "_massetManager": "MassetManager contract address", + "_moc": "MoC main contract address" + } + }, + "getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))": { + "params": { + "_dllrAmount": "The amount of the DLLR (mAsset) that will be burned in exchange for _toToken", + "_permitParams": "EIP-2612 permit params: _deadline Expiration time of the signature. _v Last 1 byte of ECDSA signature. _r First 32 bytes of ECDSA signature. _s 32 bytes after _r in ECDSA signature." + } + }, + "getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)": { + "params": { + "permit": "permit data, in form of PermitTransferFrom struct.", + "signature": "of the permit data." + } + }, + "getProxyImplementation()": { + "details": "get the implementation logic address referring to ERC1967 standard.", + "returns": { + "_0": "logic implementation address." + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))": { + "notice": "how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------" + }, + "getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)": { + "notice": "how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------" + }, + "setMocVendorAccount(address)": { + "notice": "Set MoC registered Vendor account to receive markup fees https://docs.moneyonchain.com/main-rbtc-contract/integration-with-moc-platform/vendors" + } + }, + "notice": "This contract provides compound functions with Money On Chain wrapping them in one transaction for convenience and to save on gas", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 534, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8" + }, + { + "astId": 537, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 1021, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 10, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "t_address" + }, + { + "astId": 130, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "52", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 516, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 3845, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "mocVendorAccount", + "offset": 0, + "slot": "151", + "type": "t_address" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)49_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } + } +} diff --git a/external/deployments/rskTestnet/MocIntegration_Implementation.json b/external/deployments/rskTestnet/MocIntegration_Implementation.json new file mode 100644 index 000000000..199241806 --- /dev/null +++ b/external/deployments/rskTestnet/MocIntegration_Implementation.json @@ -0,0 +1,571 @@ +{ + "address": "0x6C4FBCA418B4310cAa59Ce9a3B1D3e8c1E635AdE", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_moc", + "type": "address" + }, + { + "internalType": "address", + "name": "_doc", + "type": "address" + }, + { + "internalType": "address", + "name": "_dllr", + "type": "address" + }, + { + "internalType": "address", + "name": "_massetManager", + "type": "address" + }, + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "fromDLLR", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "toRBTC", + "type": "uint256" + } + ], + "name": "GetDocFromDllrAndRedeemRBTC", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "newMocVendorAccount", + "type": "address" + } + ], + "name": "MocVendorAccountSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "inputs": [], + "name": "dllr", + "outputs": [ + { + "internalType": "contract IDLLR", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "doc", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "getDocFromDllrAndRedeemRBTC", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "getDocFromDllrAndRedeemRbtcWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getProxyImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_mocVendorAccount", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "massetManager", + "outputs": [ + { + "internalType": "contract IMassetManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "moc", + "outputs": [ + { + "internalType": "contract IMocMintRedeemDoc", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "mocVendorAccount", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "newMocVedorAccount", + "type": "address" + } + ], + "name": "setMocVendorAccount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x9da3fad1e2b1b2f63b235969ea2a9a12368e1e8b4990377fb7740a37e18dc8d5", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0x6C4FBCA418B4310cAa59Ce9a3B1D3e8c1E635AdE", + "transactionIndex": 0, + "gasUsed": "1203648", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x7172167abee76ddf856ef97959e510b3825a6c94897096885f451798ca2df997", + "transactionHash": "0x9da3fad1e2b1b2f63b235969ea2a9a12368e1e8b4990377fb7740a37e18dc8d5", + "logs": [], + "blockNumber": 4748912, + "cumulativeGasUsed": "1203648", + "status": 1, + "byzantium": true + }, + "args": [ + "0x2820f6d4d199b8d8838a4b26f9917754b86a0c1f", + "0xcb46c0ddc60d18efeb0e586c17af6ea36452dae0", + "0x007b3AA69A846cB1f76b60b3088230A52D2A83AC", + "0xac2d05A148aB512EDEDc7280c00292ED33d31f1A", + "0x000000000022d473030f116ddee9f6b43ac78ba3" + ], + "numDeployments": 6, + "solcInputHash": "a479fe3ce562e2144d83ea46d24c05f8", + "metadata": "{\"compiler\":{\"version\":\"0.8.17+commit.8df45f5f\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_moc\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_doc\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_dllr\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_massetManager\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_permit2\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"}],\"name\":\"BeaconUpgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fromDLLR\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"toRBTC\",\"type\":\"uint256\"}],\"name\":\"GetDocFromDllrAndRedeemRBTC\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newMocVendorAccount\",\"type\":\"address\"}],\"name\":\"MocVendorAccountSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"dllr\",\"outputs\":[{\"internalType\":\"contract IDLLR\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"doc\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"getDocFromDllrAndRedeemRBTC\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"}],\"name\":\"getDocFromDllrAndRedeemRbtcWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProxyImplementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_mocVendorAccount\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"massetManager\",\"outputs\":[{\"internalType\":\"contract IMassetManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"moc\",\"outputs\":[{\"internalType\":\"contract IMocMintRedeemDoc\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"mocVendorAccount\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"newMocVedorAccount\",\"type\":\"address\"}],\"name\":\"setMocVendorAccount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"constructor\":{\"params\":{\"_dllr\":\"DLLR contract address\",\"_doc\":\"DoC contract address\",\"_massetManager\":\"MassetManager contract address\",\"_moc\":\"MoC main contract address\"}},\"getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))\":{\"params\":{\"_dllrAmount\":\"The amount of the DLLR (mAsset) that will be burned in exchange for _toToken\",\"_permitParams\":\"EIP-2612 permit params: _deadline Expiration time of the signature. _v Last 1 byte of ECDSA signature. _r First 32 bytes of ECDSA signature. _s 32 bytes after _r in ECDSA signature.\"}},\"getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)\":{\"params\":{\"permit\":\"permit data, in form of PermitTransferFrom struct.\",\"signature\":\"of the permit data.\"}},\"getProxyImplementation()\":{\"details\":\"get the implementation logic address referring to ERC1967 standard.\",\"returns\":{\"_0\":\"logic implementation address.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))\":{\"notice\":\"how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------\"},\"getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)\":{\"notice\":\"how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------\"},\"setMocVendorAccount(address)\":{\"notice\":\"Set MoC registered Vendor account to receive markup fees https://docs.moneyonchain.com/main-rbtc-contract/integration-with-moc-platform/vendors\"}},\"notice\":\"This contract provides compound functions with Money On Chain wrapping them in one transaction for convenience and to save on gas\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/integration/MoC/MocIntegration.sol\":\"MocIntegration\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/ContextUpgradeable.sol\\\";\\nimport \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n function __Ownable_init() internal onlyInitializing {\\n __Ownable_init_unchained();\\n }\\n\\n function __Ownable_init_unchained() internal onlyInitializing {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n\\n /**\\n * @dev This empty reserved space is put in place to allow future versions to add new\\n * variables without shifting down storage in the inheritance chain.\\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n */\\n uint256[49] private __gap;\\n}\\n\",\"keccak256\":\"0x247c62047745915c0af6b955470a72d1696ebad4352d7d3011aef1a2463cd888\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/interfaces/IERC1967Upgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.3) (interfaces/IERC1967.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.\\n *\\n * _Available since v4.9._\\n */\\ninterface IERC1967Upgradeable {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Emitted when the admin account has changed.\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @dev Emitted when the beacon is changed.\\n */\\n event BeaconUpgraded(address indexed beacon);\\n}\\n\",\"keccak256\":\"0xb8d68221343ed784c7b76edb6a686cb65e49c476d9e22bb89a5c0c3947ff14db\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/interfaces/draft-IERC1822Upgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\\n * proxy whose upgrades are fully controlled by the current implementation.\\n */\\ninterface IERC1822ProxiableUpgradeable {\\n /**\\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\\n * address.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy.\\n */\\n function proxiableUUID() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x77c89f893e403efc6929ba842b7ccf6534d4ffe03afe31670b4a528c0ad78c0f\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.3) (proxy/ERC1967/ERC1967Upgrade.sol)\\n\\npragma solidity ^0.8.2;\\n\\nimport \\\"../beacon/IBeaconUpgradeable.sol\\\";\\nimport \\\"../../interfaces/IERC1967Upgradeable.sol\\\";\\nimport \\\"../../interfaces/draft-IERC1822Upgradeable.sol\\\";\\nimport \\\"../../utils/AddressUpgradeable.sol\\\";\\nimport \\\"../../utils/StorageSlotUpgradeable.sol\\\";\\nimport \\\"../utils/Initializable.sol\\\";\\n\\n/**\\n * @dev This abstract contract provides getters and event emitting update functions for\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\\n *\\n * _Available since v4.1._\\n *\\n * @custom:oz-upgrades-unsafe-allow delegatecall\\n */\\nabstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable {\\n function __ERC1967Upgrade_init() internal onlyInitializing {\\n }\\n\\n function __ERC1967Upgrade_init_unchained() internal onlyInitializing {\\n }\\n // This is the keccak-256 hash of \\\"eip1967.proxy.rollback\\\" subtracted by 1\\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _getImplementation() internal view returns (address) {\\n return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 implementation slot.\\n */\\n function _setImplementation(address newImplementation) private {\\n require(AddressUpgradeable.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n }\\n\\n /**\\n * @dev Perform implementation upgrade\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCall(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _upgradeTo(newImplementation);\\n if (data.length > 0 || forceCall) {\\n _functionDelegateCall(newImplementation, data);\\n }\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCallUUPS(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n // Upgrades from old implementations will perform a rollback test. This test requires the new\\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\\n // this special case will break upgrade paths from old UUPS implementation to new ones.\\n if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {\\n _setImplementation(newImplementation);\\n } else {\\n try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n require(slot == _IMPLEMENTATION_SLOT, \\\"ERC1967Upgrade: unsupported proxiableUUID\\\");\\n } catch {\\n revert(\\\"ERC1967Upgrade: new implementation is not UUPS\\\");\\n }\\n _upgradeToAndCall(newImplementation, data, forceCall);\\n }\\n }\\n\\n /**\\n * @dev Storage slot with the admin of the contract.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.admin\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _getAdmin() internal view returns (address) {\\n return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 admin slot.\\n */\\n function _setAdmin(address newAdmin) private {\\n require(newAdmin != address(0), \\\"ERC1967: new admin is the zero address\\\");\\n StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n */\\n function _changeAdmin(address newAdmin) internal {\\n emit AdminChanged(_getAdmin(), newAdmin);\\n _setAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\\n */\\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\\n\\n /**\\n * @dev Returns the current beacon.\\n */\\n function _getBeacon() internal view returns (address) {\\n return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new beacon in the EIP1967 beacon slot.\\n */\\n function _setBeacon(address newBeacon) private {\\n require(AddressUpgradeable.isContract(newBeacon), \\\"ERC1967: new beacon is not a contract\\\");\\n require(\\n AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),\\n \\\"ERC1967: beacon implementation is not a contract\\\"\\n );\\n StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;\\n }\\n\\n /**\\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\\n *\\n * Emits a {BeaconUpgraded} event.\\n */\\n function _upgradeBeaconToAndCall(\\n address newBeacon,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _setBeacon(newBeacon);\\n emit BeaconUpgraded(newBeacon);\\n if (data.length > 0 || forceCall) {\\n _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);\\n }\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) {\\n require(AddressUpgradeable.isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n // solhint-disable-next-line avoid-low-level-calls\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return AddressUpgradeable.verifyCallResult(success, returndata, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev This empty reserved space is put in place to allow future versions to add new\\n * variables without shifting down storage in the inheritance chain.\\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n */\\n uint256[50] private __gap;\\n}\\n\",\"keccak256\":\"0x1599637b52d20dc3954cea44914b2a4a9a8a5caade58d9da947e0b6c9acc07ba\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/proxy/beacon/IBeaconUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\\n */\\ninterface IBeaconUpgradeable {\\n /**\\n * @dev Must return an address that can be used as a delegate call target.\\n *\\n * {BeaconProxy} will check that this address is a contract.\\n */\\n function implementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0x24b86ac8c005b8c654fbf6ac34a5a4f61580d7273541e83e013e89d66fbf0908\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)\\n\\npragma solidity ^0.8.2;\\n\\nimport \\\"../../utils/AddressUpgradeable.sol\\\";\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n * ====\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n * @custom:oz-retyped-from bool\\n */\\n uint8 private _initialized;\\n\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool private _initializing;\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint8 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\\n * constructor.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n bool isTopLevelCall = !_initializing;\\n require(\\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\\n \\\"Initializable: contract is already initialized\\\"\\n );\\n _initialized = 1;\\n if (isTopLevelCall) {\\n _initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n _initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: setting the version to 255 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint8 version) {\\n require(!_initializing && _initialized < version, \\\"Initializable: contract is already initialized\\\");\\n _initialized = version;\\n _initializing = true;\\n _;\\n _initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n require(_initializing, \\\"Initializable: contract is not initializing\\\");\\n _;\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n require(!_initializing, \\\"Initializable: contract is initializing\\\");\\n if (_initialized < type(uint8).max) {\\n _initialized = type(uint8).max;\\n emit Initialized(type(uint8).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint8) {\\n return _initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _initializing;\\n }\\n}\\n\",\"keccak256\":\"0x037c334add4b033ad3493038c25be1682d78c00992e1acb0e2795caff3925271\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary AddressUpgradeable {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\\n *\\n * _Available since v4.8._\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n if (success) {\\n if (returndata.length == 0) {\\n // only check isContract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n }\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason or using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n _revert(returndata, errorMessage);\\n }\\n }\\n\\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x2edcb41c121abc510932e8d83ff8b82cf9cdde35e7c297622f5c29ef0af25183\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\nimport \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract ContextUpgradeable is Initializable {\\n function __Context_init() internal onlyInitializing {\\n }\\n\\n function __Context_init_unchained() internal onlyInitializing {\\n }\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n\\n /**\\n * @dev This empty reserved space is put in place to allow future versions to add new\\n * variables without shifting down storage in the inheritance chain.\\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\\n */\\n uint256[50] private __gap;\\n}\\n\",\"keccak256\":\"0x963ea7f0b48b032eef72fe3a7582edf78408d6f834115b9feadd673a4d5bd149\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/StorageSlotUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for reading and writing primitive types to specific storage slots.\\n *\\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\\n * This library helps with reading and writing to such slots without the need for inline assembly.\\n *\\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\\n *\\n * Example usage to set ERC1967 implementation slot:\\n * ```\\n * contract ERC1967 {\\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n *\\n * function _getImplementation() internal view returns (address) {\\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n * }\\n *\\n * function _setImplementation(address newImplementation) internal {\\n * require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n * }\\n * }\\n * ```\\n *\\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\\n */\\nlibrary StorageSlotUpgradeable {\\n struct AddressSlot {\\n address value;\\n }\\n\\n struct BooleanSlot {\\n bool value;\\n }\\n\\n struct Bytes32Slot {\\n bytes32 value;\\n }\\n\\n struct Uint256Slot {\\n uint256 value;\\n }\\n\\n /**\\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\\n */\\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\\n */\\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\\n */\\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\\n */\\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n}\\n\",\"keccak256\":\"0x09864aea84f01e39313375b5610c73a3c1c68abbdc51e5ccdd25ff977fdadf9a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n address private _owner;\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor() {\\n _transferOwnership(_msgSender());\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n _checkOwner();\\n _;\\n }\\n\\n /**\\n * @dev Returns the address of the current owner.\\n */\\n function owner() public view virtual returns (address) {\\n return _owner;\\n }\\n\\n /**\\n * @dev Throws if the sender is not the owner.\\n */\\n function _checkOwner() internal view virtual {\\n require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n }\\n\\n /**\\n * @dev Leaves the contract without owner. It will not be possible to call\\n * `onlyOwner` functions anymore. Can only be called by the current owner.\\n *\\n * NOTE: Renouncing ownership will leave the contract without an owner,\\n * thereby removing any functionality that is only available to the owner.\\n */\\n function renounceOwnership() public virtual onlyOwner {\\n _transferOwnership(address(0));\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Can only be called by the current owner.\\n */\\n function transferOwnership(address newOwner) public virtual onlyOwner {\\n require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n _transferOwnership(newOwner);\\n }\\n\\n /**\\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n * Internal function without access restriction.\\n */\\n function _transferOwnership(address newOwner) internal virtual {\\n address oldOwner = _owner;\\n _owner = newOwner;\\n emit OwnershipTransferred(oldOwner, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0xa94b34880e3c1b0b931662cb1c09e5dfa6662f31cba80e07c5ee71cd135c9673\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./IERC20.sol\\\";\\nimport \\\"./extensions/IERC20Metadata.sol\\\";\\nimport \\\"../../utils/Context.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC20} interface.\\n *\\n * This implementation is agnostic to the way tokens are created. This means\\n * that a supply mechanism has to be added in a derived contract using {_mint}.\\n * For a generic mechanism see {ERC20PresetMinterPauser}.\\n *\\n * TIP: For a detailed writeup see our guide\\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\\n * to implement supply mechanisms].\\n *\\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\\n * instead returning `false` on failure. This behavior is nonetheless\\n * conventional and does not conflict with the expectations of ERC20\\n * applications.\\n *\\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\\n * This allows applications to reconstruct the allowance for all accounts just\\n * by listening to said events. Other implementations of the EIP may not emit\\n * these events, as it isn't required by the specification.\\n *\\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\\n * functions have been added to mitigate the well-known issues around setting\\n * allowances. See {IERC20-approve}.\\n */\\ncontract ERC20 is Context, IERC20, IERC20Metadata {\\n mapping(address => uint256) private _balances;\\n\\n mapping(address => mapping(address => uint256)) private _allowances;\\n\\n uint256 private _totalSupply;\\n\\n string private _name;\\n string private _symbol;\\n\\n /**\\n * @dev Sets the values for {name} and {symbol}.\\n *\\n * The default value of {decimals} is 18. To select a different value for\\n * {decimals} you should overload it.\\n *\\n * All two of these values are immutable: they can only be set once during\\n * construction.\\n */\\n constructor(string memory name_, string memory symbol_) {\\n _name = name_;\\n _symbol = symbol_;\\n }\\n\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() public view virtual override returns (string memory) {\\n return _name;\\n }\\n\\n /**\\n * @dev Returns the symbol of the token, usually a shorter version of the\\n * name.\\n */\\n function symbol() public view virtual override returns (string memory) {\\n return _symbol;\\n }\\n\\n /**\\n * @dev Returns the number of decimals used to get its user representation.\\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\\n *\\n * Tokens usually opt for a value of 18, imitating the relationship between\\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\\n * overridden;\\n *\\n * NOTE: This information is only used for _display_ purposes: it in\\n * no way affects any of the arithmetic of the contract, including\\n * {IERC20-balanceOf} and {IERC20-transfer}.\\n */\\n function decimals() public view virtual override returns (uint8) {\\n return 18;\\n }\\n\\n /**\\n * @dev See {IERC20-totalSupply}.\\n */\\n function totalSupply() public view virtual override returns (uint256) {\\n return _totalSupply;\\n }\\n\\n /**\\n * @dev See {IERC20-balanceOf}.\\n */\\n function balanceOf(address account) public view virtual override returns (uint256) {\\n return _balances[account];\\n }\\n\\n /**\\n * @dev See {IERC20-transfer}.\\n *\\n * Requirements:\\n *\\n * - `to` cannot be the zero address.\\n * - the caller must have a balance of at least `amount`.\\n */\\n function transfer(address to, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _transfer(owner, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-allowance}.\\n */\\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\\n return _allowances[owner][spender];\\n }\\n\\n /**\\n * @dev See {IERC20-approve}.\\n *\\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\\n * `transferFrom`. This is semantically equivalent to an infinite approval.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, amount);\\n return true;\\n }\\n\\n /**\\n * @dev See {IERC20-transferFrom}.\\n *\\n * Emits an {Approval} event indicating the updated allowance. This is not\\n * required by the EIP. See the note at the beginning of {ERC20}.\\n *\\n * NOTE: Does not update the allowance if the current allowance\\n * is the maximum `uint256`.\\n *\\n * Requirements:\\n *\\n * - `from` and `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n * - the caller must have allowance for ``from``'s tokens of at least\\n * `amount`.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual override returns (bool) {\\n address spender = _msgSender();\\n _spendAllowance(from, spender, amount);\\n _transfer(from, to, amount);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically increases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n */\\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n _approve(owner, spender, allowance(owner, spender) + addedValue);\\n return true;\\n }\\n\\n /**\\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\\n *\\n * This is an alternative to {approve} that can be used as a mitigation for\\n * problems described in {IERC20-approve}.\\n *\\n * Emits an {Approval} event indicating the updated allowance.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `spender` must have allowance for the caller of at least\\n * `subtractedValue`.\\n */\\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\\n address owner = _msgSender();\\n uint256 currentAllowance = allowance(owner, spender);\\n require(currentAllowance >= subtractedValue, \\\"ERC20: decreased allowance below zero\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - subtractedValue);\\n }\\n\\n return true;\\n }\\n\\n /**\\n * @dev Moves `amount` of tokens from `from` to `to`.\\n *\\n * This internal function is equivalent to {transfer}, and can be used to\\n * e.g. implement automatic token fees, slashing mechanisms, etc.\\n *\\n * Emits a {Transfer} event.\\n *\\n * Requirements:\\n *\\n * - `from` cannot be the zero address.\\n * - `to` cannot be the zero address.\\n * - `from` must have a balance of at least `amount`.\\n */\\n function _transfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {\\n require(from != address(0), \\\"ERC20: transfer from the zero address\\\");\\n require(to != address(0), \\\"ERC20: transfer to the zero address\\\");\\n\\n _beforeTokenTransfer(from, to, amount);\\n\\n uint256 fromBalance = _balances[from];\\n require(fromBalance >= amount, \\\"ERC20: transfer amount exceeds balance\\\");\\n unchecked {\\n _balances[from] = fromBalance - amount;\\n // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\\n // decrementing then incrementing.\\n _balances[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n _afterTokenTransfer(from, to, amount);\\n }\\n\\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\\n * the total supply.\\n *\\n * Emits a {Transfer} event with `from` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n */\\n function _mint(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: mint to the zero address\\\");\\n\\n _beforeTokenTransfer(address(0), account, amount);\\n\\n _totalSupply += amount;\\n unchecked {\\n // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\\n _balances[account] += amount;\\n }\\n emit Transfer(address(0), account, amount);\\n\\n _afterTokenTransfer(address(0), account, amount);\\n }\\n\\n /**\\n * @dev Destroys `amount` tokens from `account`, reducing the\\n * total supply.\\n *\\n * Emits a {Transfer} event with `to` set to the zero address.\\n *\\n * Requirements:\\n *\\n * - `account` cannot be the zero address.\\n * - `account` must have at least `amount` tokens.\\n */\\n function _burn(address account, uint256 amount) internal virtual {\\n require(account != address(0), \\\"ERC20: burn from the zero address\\\");\\n\\n _beforeTokenTransfer(account, address(0), amount);\\n\\n uint256 accountBalance = _balances[account];\\n require(accountBalance >= amount, \\\"ERC20: burn amount exceeds balance\\\");\\n unchecked {\\n _balances[account] = accountBalance - amount;\\n // Overflow not possible: amount <= accountBalance <= totalSupply.\\n _totalSupply -= amount;\\n }\\n\\n emit Transfer(account, address(0), amount);\\n\\n _afterTokenTransfer(account, address(0), amount);\\n }\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\\n *\\n * This internal function is equivalent to `approve`, and can be used to\\n * e.g. set automatic allowances for certain subsystems, etc.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n */\\n function _approve(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n require(owner != address(0), \\\"ERC20: approve from the zero address\\\");\\n require(spender != address(0), \\\"ERC20: approve to the zero address\\\");\\n\\n _allowances[owner][spender] = amount;\\n emit Approval(owner, spender, amount);\\n }\\n\\n /**\\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\\n *\\n * Does not update the allowance amount in case of infinite allowance.\\n * Revert if not enough allowance is available.\\n *\\n * Might emit an {Approval} event.\\n */\\n function _spendAllowance(\\n address owner,\\n address spender,\\n uint256 amount\\n ) internal virtual {\\n uint256 currentAllowance = allowance(owner, spender);\\n if (currentAllowance != type(uint256).max) {\\n require(currentAllowance >= amount, \\\"ERC20: insufficient allowance\\\");\\n unchecked {\\n _approve(owner, spender, currentAllowance - amount);\\n }\\n }\\n }\\n\\n /**\\n * @dev Hook that is called before any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * will be transferred to `to`.\\n * - when `from` is zero, `amount` tokens will be minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _beforeTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n\\n /**\\n * @dev Hook that is called after any transfer of tokens. This includes\\n * minting and burning.\\n *\\n * Calling conditions:\\n *\\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\\n * has been transferred to `to`.\\n * - when `from` is zero, `amount` tokens have been minted for `to`.\\n * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\\n * - `from` and `to` are never both zero.\\n *\\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\\n */\\n function _afterTokenTransfer(\\n address from,\\n address to,\\n uint256 amount\\n ) internal virtual {}\\n}\\n\",\"keccak256\":\"0x4ffc0547c02ad22925310c585c0f166f8759e2648a09e9b489100c42f15dd98d\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `to`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address to, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `from` to `to` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n /**\\n * @dev Returns the name of the token.\\n */\\n function name() external view returns (string memory);\\n\\n /**\\n * @dev Returns the symbol of the token.\\n */\\n function symbol() external view returns (string memory);\\n\\n /**\\n * @dev Returns the decimals places of the token.\\n */\\n function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./draft-IERC20Permit.sol\\\";\\nimport \\\"../ERC20.sol\\\";\\nimport \\\"../../../utils/cryptography/ECDSA.sol\\\";\\nimport \\\"../../../utils/cryptography/EIP712.sol\\\";\\nimport \\\"../../../utils/Counters.sol\\\";\\n\\n/**\\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n *\\n * _Available since v3.4._\\n */\\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\\n using Counters for Counters.Counter;\\n\\n mapping(address => Counters.Counter) private _nonces;\\n\\n // solhint-disable-next-line var-name-mixedcase\\n bytes32 private constant _PERMIT_TYPEHASH =\\n keccak256(\\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\");\\n /**\\n * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`.\\n * However, to ensure consistency with the upgradeable transpiler, we will continue\\n * to reserve a slot.\\n * @custom:oz-renamed-from _PERMIT_TYPEHASH\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;\\n\\n /**\\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\\\"1\\\"`.\\n *\\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\\n */\\n constructor(string memory name) EIP712(name, \\\"1\\\") {}\\n\\n /**\\n * @dev See {IERC20Permit-permit}.\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public virtual override {\\n require(block.timestamp <= deadline, \\\"ERC20Permit: expired deadline\\\");\\n\\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));\\n\\n bytes32 hash = _hashTypedDataV4(structHash);\\n\\n address signer = ECDSA.recover(hash, v, r, s);\\n require(signer == owner, \\\"ERC20Permit: invalid signature\\\");\\n\\n _approve(owner, spender, value);\\n }\\n\\n /**\\n * @dev See {IERC20Permit-nonces}.\\n */\\n function nonces(address owner) public view virtual override returns (uint256) {\\n return _nonces[owner].current();\\n }\\n\\n /**\\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\\n return _domainSeparatorV4();\\n }\\n\\n /**\\n * @dev \\\"Consume a nonce\\\": return the current value and increment.\\n *\\n * _Available since v4.1._\\n */\\n function _useNonce(address owner) internal virtual returns (uint256 current) {\\n Counters.Counter storage nonce = _nonces[owner];\\n current = nonce.current();\\n nonce.increment();\\n }\\n}\\n\",\"keccak256\":\"0xd2dd6003a2dc02ab905fd405938322e510429d19ae6c07c2c683d70f13ab2f36\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xf41ca991f30855bf80ffd11e9347856a517b977f0a6c2d52e6421a99b7840329\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Counters.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @title Counters\\n * @author Matt Condon (@shrugs)\\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\\n *\\n * Include with `using Counters for Counters.Counter;`\\n */\\nlibrary Counters {\\n struct Counter {\\n // This variable should never be directly accessed by users of the library: interactions must be restricted to\\n // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\\n // this feature: see https://github.com/ethereum/solidity/issues/4637\\n uint256 _value; // default: 0\\n }\\n\\n function current(Counter storage counter) internal view returns (uint256) {\\n return counter._value;\\n }\\n\\n function increment(Counter storage counter) internal {\\n unchecked {\\n counter._value += 1;\\n }\\n }\\n\\n function decrement(Counter storage counter) internal {\\n uint256 value = counter._value;\\n require(value > 0, \\\"Counter: decrement overflow\\\");\\n unchecked {\\n counter._value = value - 1;\\n }\\n }\\n\\n function reset(Counter storage counter) internal {\\n counter._value = 0;\\n }\\n}\\n\",\"keccak256\":\"0xf0018c2440fbe238dd3a8732fa8e17a0f9dce84d31451dc8a32f6d62b349c9f1\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Strings.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./math/Math.sol\\\";\\n\\n/**\\n * @dev String operations.\\n */\\nlibrary Strings {\\n bytes16 private constant _SYMBOLS = \\\"0123456789abcdef\\\";\\n uint8 private constant _ADDRESS_LENGTH = 20;\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\\n */\\n function toString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n uint256 length = Math.log10(value) + 1;\\n string memory buffer = new string(length);\\n uint256 ptr;\\n /// @solidity memory-safe-assembly\\n assembly {\\n ptr := add(buffer, add(32, length))\\n }\\n while (true) {\\n ptr--;\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\\n }\\n value /= 10;\\n if (value == 0) break;\\n }\\n return buffer;\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\\n */\\n function toHexString(uint256 value) internal pure returns (string memory) {\\n unchecked {\\n return toHexString(value, Math.log256(value) + 1);\\n }\\n }\\n\\n /**\\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\\n */\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\\n bytes memory buffer = new bytes(2 * length + 2);\\n buffer[0] = \\\"0\\\";\\n buffer[1] = \\\"x\\\";\\n for (uint256 i = 2 * length + 1; i > 1; --i) {\\n buffer[i] = _SYMBOLS[value & 0xf];\\n value >>= 4;\\n }\\n require(value == 0, \\\"Strings: hex length insufficient\\\");\\n return string(buffer);\\n }\\n\\n /**\\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\\n */\\n function toHexString(address addr) internal pure returns (string memory) {\\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\\n }\\n}\\n\",\"keccak256\":\"0xa4d1d62251f8574deb032a35fc948386a9b4de74b812d4f545a1ac120486b48a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Strings.sol\\\";\\n\\n/**\\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\\n *\\n * These functions can be used to verify that a message was signed by the holder\\n * of the private keys of a given address.\\n */\\nlibrary ECDSA {\\n enum RecoverError {\\n NoError,\\n InvalidSignature,\\n InvalidSignatureLength,\\n InvalidSignatureS,\\n InvalidSignatureV // Deprecated in v4.8\\n }\\n\\n function _throwError(RecoverError error) private pure {\\n if (error == RecoverError.NoError) {\\n return; // no error: do nothing\\n } else if (error == RecoverError.InvalidSignature) {\\n revert(\\\"ECDSA: invalid signature\\\");\\n } else if (error == RecoverError.InvalidSignatureLength) {\\n revert(\\\"ECDSA: invalid signature length\\\");\\n } else if (error == RecoverError.InvalidSignatureS) {\\n revert(\\\"ECDSA: invalid signature 's' value\\\");\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature` or error string. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n *\\n * Documentation for signature generation:\\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\\n if (signature.length == 65) {\\n bytes32 r;\\n bytes32 s;\\n uint8 v;\\n // ecrecover takes the signature parameters, and the only way to get them\\n // currently is to use assembly.\\n /// @solidity memory-safe-assembly\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n return tryRecover(hash, v, r, s);\\n } else {\\n return (address(0), RecoverError.InvalidSignatureLength);\\n }\\n }\\n\\n /**\\n * @dev Returns the address that signed a hashed message (`hash`) with\\n * `signature`. This address can then be used for verification purposes.\\n *\\n * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\\n * this function rejects them by requiring the `s` value to be in the lower\\n * half order, and the `v` value to be either 27 or 28.\\n *\\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\\n * verification to be secure: it is possible to craft signatures that\\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\\n * this is by receiving a hash of the original message (which may otherwise\\n * be too long), and then calling {toEthSignedMessageHash} on it.\\n */\\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, signature);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address, RecoverError) {\\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\\n uint8 v = uint8((uint256(vs) >> 255) + 27);\\n return tryRecover(hash, v, r, s);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\\n *\\n * _Available since v4.2._\\n */\\n function recover(\\n bytes32 hash,\\n bytes32 r,\\n bytes32 vs\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, r, vs);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n *\\n * _Available since v4.3._\\n */\\n function tryRecover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address, RecoverError) {\\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\\n // the valid range for s in (301): 0 < s < secp256k1n \\u00f7 2 + 1, and for v in (302): v \\u2208 {27, 28}. Most\\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\\n //\\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\\n // these malleable signatures as well.\\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n return (address(0), RecoverError.InvalidSignatureS);\\n }\\n\\n // If the signature is valid (and not malleable), return the signer address\\n address signer = ecrecover(hash, v, r, s);\\n if (signer == address(0)) {\\n return (address(0), RecoverError.InvalidSignature);\\n }\\n\\n return (signer, RecoverError.NoError);\\n }\\n\\n /**\\n * @dev Overload of {ECDSA-recover} that receives the `v`,\\n * `r` and `s` signature fields separately.\\n */\\n function recover(\\n bytes32 hash,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) internal pure returns (address) {\\n (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\\n _throwError(error);\\n return recovered;\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from a `hash`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\\n // 32 is the length in bytes of hash,\\n // enforced by the type signature above\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n32\\\", hash));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Message, created from `s`. This\\n * produces hash corresponding to the one signed with the\\n * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\\n * JSON-RPC method as part of EIP-191.\\n *\\n * See {recover}.\\n */\\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19Ethereum Signed Message:\\\\n\\\", Strings.toString(s.length), s));\\n }\\n\\n /**\\n * @dev Returns an Ethereum Signed Typed Data, created from a\\n * `domainSeparator` and a `structHash`. This produces hash corresponding\\n * to the one signed with the\\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\\n * JSON-RPC method as part of EIP-712.\\n *\\n * See {recover}.\\n */\\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\\n return keccak256(abi.encodePacked(\\\"\\\\x19\\\\x01\\\", domainSeparator, structHash));\\n }\\n}\\n\",\"keccak256\":\"0xda898fa084aa1ddfdb346e6a40459e00a59d87071cce7c315a46d648dd71d0ba\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/cryptography/EIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"./ECDSA.sol\\\";\\n\\n/**\\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\\n *\\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\\n *\\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\\n * ({_hashTypedDataV4}).\\n *\\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\\n * the chain id to protect against replay attacks on an eventual fork of the chain.\\n *\\n * NOTE: This contract implements the version of the encoding known as \\\"v4\\\", as implemented by the JSON RPC method\\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\\n *\\n * _Available since v3.4._\\n */\\nabstract contract EIP712 {\\n /* solhint-disable var-name-mixedcase */\\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\\n // invalidate the cached domain separator if the chain id changes.\\n bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\\n uint256 private immutable _CACHED_CHAIN_ID;\\n address private immutable _CACHED_THIS;\\n\\n bytes32 private immutable _HASHED_NAME;\\n bytes32 private immutable _HASHED_VERSION;\\n bytes32 private immutable _TYPE_HASH;\\n\\n /* solhint-enable var-name-mixedcase */\\n\\n /**\\n * @dev Initializes the domain separator and parameter caches.\\n *\\n * The meaning of `name` and `version` is specified in\\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\\n *\\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\\n * - `version`: the current major version of the signing domain.\\n *\\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\\n * contract upgrade].\\n */\\n constructor(string memory name, string memory version) {\\n bytes32 hashedName = keccak256(bytes(name));\\n bytes32 hashedVersion = keccak256(bytes(version));\\n bytes32 typeHash = keccak256(\\n \\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"\\n );\\n _HASHED_NAME = hashedName;\\n _HASHED_VERSION = hashedVersion;\\n _CACHED_CHAIN_ID = block.chainid;\\n _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\\n _CACHED_THIS = address(this);\\n _TYPE_HASH = typeHash;\\n }\\n\\n /**\\n * @dev Returns the domain separator for the current chain.\\n */\\n function _domainSeparatorV4() internal view returns (bytes32) {\\n if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\\n return _CACHED_DOMAIN_SEPARATOR;\\n } else {\\n return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\\n }\\n }\\n\\n function _buildDomainSeparator(\\n bytes32 typeHash,\\n bytes32 nameHash,\\n bytes32 versionHash\\n ) private view returns (bytes32) {\\n return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\\n }\\n\\n /**\\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\\n * function returns the hash of the fully encoded EIP712 message for this domain.\\n *\\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\\n *\\n * ```solidity\\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\\n * keccak256(\\\"Mail(address to,string contents)\\\"),\\n * mailTo,\\n * keccak256(bytes(mailContents))\\n * )));\\n * address signer = ECDSA.recover(digest, signature);\\n * ```\\n */\\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\\n return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\\n }\\n}\\n\",\"keccak256\":\"0x948d8b2d18f38141ec78c5229d770d950ebc781ed3f44cc9e3ccbb9fded5846a\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/math/Math.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Standard math utilities missing in the Solidity language.\\n */\\nlibrary Math {\\n enum Rounding {\\n Down, // Toward negative infinity\\n Up, // Toward infinity\\n Zero // Toward zero\\n }\\n\\n /**\\n * @dev Returns the largest of two numbers.\\n */\\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a > b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the smallest of two numbers.\\n */\\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\\n return a < b ? a : b;\\n }\\n\\n /**\\n * @dev Returns the average of two numbers. The result is rounded towards\\n * zero.\\n */\\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b) / 2 can overflow.\\n return (a & b) + (a ^ b) / 2;\\n }\\n\\n /**\\n * @dev Returns the ceiling of the division of two numbers.\\n *\\n * This differs from standard division with `/` in that it rounds up instead\\n * of rounding down.\\n */\\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\\n // (a + b - 1) / b can overflow on addition, so we distribute.\\n return a == 0 ? 0 : (a - 1) / b + 1;\\n }\\n\\n /**\\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\\n * with further edits by Uniswap Labs also under MIT license.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator\\n ) internal pure returns (uint256 result) {\\n unchecked {\\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\\n // variables such that product = prod1 * 2^256 + prod0.\\n uint256 prod0; // Least significant 256 bits of the product\\n uint256 prod1; // Most significant 256 bits of the product\\n assembly {\\n let mm := mulmod(x, y, not(0))\\n prod0 := mul(x, y)\\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\\n }\\n\\n // Handle non-overflow cases, 256 by 256 division.\\n if (prod1 == 0) {\\n return prod0 / denominator;\\n }\\n\\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\\n require(denominator > prod1);\\n\\n ///////////////////////////////////////////////\\n // 512 by 256 division.\\n ///////////////////////////////////////////////\\n\\n // Make division exact by subtracting the remainder from [prod1 prod0].\\n uint256 remainder;\\n assembly {\\n // Compute remainder using mulmod.\\n remainder := mulmod(x, y, denominator)\\n\\n // Subtract 256 bit number from 512 bit number.\\n prod1 := sub(prod1, gt(remainder, prod0))\\n prod0 := sub(prod0, remainder)\\n }\\n\\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\\n // See https://cs.stackexchange.com/q/138556/92363.\\n\\n // Does not overflow because the denominator cannot be zero at this stage in the function.\\n uint256 twos = denominator & (~denominator + 1);\\n assembly {\\n // Divide denominator by twos.\\n denominator := div(denominator, twos)\\n\\n // Divide [prod1 prod0] by twos.\\n prod0 := div(prod0, twos)\\n\\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\\n twos := add(div(sub(0, twos), twos), 1)\\n }\\n\\n // Shift in bits from prod1 into prod0.\\n prod0 |= prod1 * twos;\\n\\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\\n // four bits. That is, denominator * inv = 1 mod 2^4.\\n uint256 inverse = (3 * denominator) ^ 2;\\n\\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\\n // in modular arithmetic, doubling the correct bits in each step.\\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\\n\\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\\n // is no longer required.\\n result = prod0 * inverse;\\n return result;\\n }\\n }\\n\\n /**\\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\\n */\\n function mulDiv(\\n uint256 x,\\n uint256 y,\\n uint256 denominator,\\n Rounding rounding\\n ) internal pure returns (uint256) {\\n uint256 result = mulDiv(x, y, denominator);\\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\\n result += 1;\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\\n *\\n * Inspired by Henry S. Warren, Jr.'s \\\"Hacker's Delight\\\" (Chapter 11).\\n */\\n function sqrt(uint256 a) internal pure returns (uint256) {\\n if (a == 0) {\\n return 0;\\n }\\n\\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\\n //\\n // We know that the \\\"msb\\\" (most significant bit) of our target number `a` is a power of 2 such that we have\\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\\n //\\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\\n // \\u2192 `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\\n // \\u2192 `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\\n //\\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\\n uint256 result = 1 << (log2(a) >> 1);\\n\\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\\n // into the expected uint128 result.\\n unchecked {\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n result = (result + a / result) >> 1;\\n return min(result, a / result);\\n }\\n }\\n\\n /**\\n * @notice Calculates sqrt(a), following the selected rounding direction.\\n */\\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = sqrt(a);\\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 2, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 128;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 64;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 32;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 16;\\n }\\n if (value >> 8 > 0) {\\n value >>= 8;\\n result += 8;\\n }\\n if (value >> 4 > 0) {\\n value >>= 4;\\n result += 4;\\n }\\n if (value >> 2 > 0) {\\n value >>= 2;\\n result += 2;\\n }\\n if (value >> 1 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log2(value);\\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 10, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >= 10**64) {\\n value /= 10**64;\\n result += 64;\\n }\\n if (value >= 10**32) {\\n value /= 10**32;\\n result += 32;\\n }\\n if (value >= 10**16) {\\n value /= 10**16;\\n result += 16;\\n }\\n if (value >= 10**8) {\\n value /= 10**8;\\n result += 8;\\n }\\n if (value >= 10**4) {\\n value /= 10**4;\\n result += 4;\\n }\\n if (value >= 10**2) {\\n value /= 10**2;\\n result += 2;\\n }\\n if (value >= 10**1) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log10(value);\\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\\n }\\n }\\n\\n /**\\n * @dev Return the log in base 256, rounded down, of a positive value.\\n * Returns 0 if given 0.\\n *\\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\\n */\\n function log256(uint256 value) internal pure returns (uint256) {\\n uint256 result = 0;\\n unchecked {\\n if (value >> 128 > 0) {\\n value >>= 128;\\n result += 16;\\n }\\n if (value >> 64 > 0) {\\n value >>= 64;\\n result += 8;\\n }\\n if (value >> 32 > 0) {\\n value >>= 32;\\n result += 4;\\n }\\n if (value >> 16 > 0) {\\n value >>= 16;\\n result += 2;\\n }\\n if (value >> 8 > 0) {\\n result += 1;\\n }\\n }\\n return result;\\n }\\n\\n /**\\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\\n * Returns 0 if given 0.\\n */\\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\\n unchecked {\\n uint256 result = log256(value);\\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\\n }\\n }\\n}\\n\",\"keccak256\":\"0xa1e8e83cd0087785df04ac79fb395d9f3684caeaf973d9e2c71caef723a3a5d6\",\"license\":\"MIT\"},\"contracts/integration/MoC/IMoC.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\n/// Interface to the Money OnChain main contract MoC to mint DoC and redeem RBTC\\ninterface IMocMintRedeemDoc {\\n /**\\n @dev Returns the total amount of Docs in the redeem queue for redeemer\\n @param redeemer address for which ^ is computed\\n @return total amount of Docs in the redeem queue for redeemer\\n */\\n function docAmountToRedeem(address redeemer) external view returns (uint256);\\n\\n /**\\n * @dev Creates or updates the amount of a Doc redeem Request from the msg.sender\\n * @param docAmount Amount of Docs to redeem on settlement [using mocPrecision]\\n */\\n function redeemDocRequest(uint256 docAmount) external;\\n\\n /**\\n @dev Alters the redeem amount position for the redeemer\\n @param isAddition true if adding amount to redeem, false to substract.\\n @param delta the amount to add/substract to current position\\n */\\n function alterRedeemRequestAmount(bool isAddition, uint256 delta) external;\\n\\n /**\\n @dev Mint Doc tokens and pays the commisions of the operation (retrocompatible function).\\n @dev Retrocompatible function.\\n @param btcToMint Amount in RBTC to mint\\n */\\n function mintDoc(uint256 btcToMint) external payable;\\n\\n /**\\n * @dev Mint Doc tokens and pays the commisions of the operation\\n * @param btcToMint Amount in RBTC to mint\\n * @param vendorAccount Vendor address\\n */\\n function mintDocVendors(uint256 btcToMint, address payable vendorAccount) external payable;\\n\\n /**\\n @dev Redeems the requested amount for the msg.sender, or the max amount of free docs possible (retrocompatible function).\\n @dev Retrocompatible function.\\n @param docAmount Amount of Docs to redeem.\\n */\\n function redeemFreeDoc(uint256 docAmount) external;\\n\\n /**\\n @dev Redeems the requested amount for the msg.sender, or the max amount of free docs possible.\\n @param docAmount Amount of Docs to redeem.\\n @param vendorAccount Vendor address\\n */\\n function redeemFreeDocVendors(uint256 docAmount, address payable vendorAccount) external;\\n\\n /**\\n @dev Allow redeem on liquidation state, user DoCs get burned and he receives\\n the equivalent BTCs if can be covered, or the maximum available\\n */\\n function redeemAllDoc() external;\\n}\\n\\n/// An aggregating interface\\ninterface IMoC is IMocMintRedeemDoc {\\n\\n}\\n\",\"keccak256\":\"0xc571f8c743be8c85e8d570ec0378abef85ffc676e58a6fd3861501689721f944\",\"license\":\"MIT\"},\"contracts/integration/MoC/MocIntegration.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\nimport \\\"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\\\";\\nimport \\\"@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol\\\";\\nimport { IMocMintRedeemDoc } from \\\"./IMoC.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/utils/Counters.sol\\\";\\nimport \\\"../../meta-asset-token/DLLR.sol\\\";\\nimport \\\"../../interfaces/IMassetManager.sol\\\";\\nimport { IDLLR, PermitParams } from \\\"../../interfaces/IDLLR.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"../../permit2/interfaces/IPermit2.sol\\\";\\n\\n/// @notice This contract provides compound functions with Money On Chain wrapping them in one transaction for convenience and to save on gas\\ncontract MocIntegration is OwnableUpgradeable, ERC1967UpgradeUpgradeable {\\n using Counters for Counters.Counter;\\n // Money On Chain DoC redeem interface at MoC main contract address\\n IMocMintRedeemDoc public immutable moc;\\n // IERC20@[DoC token]\\n IERC20 public immutable doc;\\n IDLLR public immutable dllr;\\n IMassetManager public immutable massetManager;\\n\\n address public mocVendorAccount;\\n\\n IPermit2 public immutable permit2;\\n\\n event GetDocFromDllrAndRedeemRBTC(address indexed from, uint256 fromDLLR, uint256 toRBTC);\\n event MocVendorAccountSet(address newMocVendorAccount);\\n\\n /**\\n * @param _moc MoC main contract address\\n * @param _doc DoC contract address\\n * @param _dllr DLLR contract address\\n * @param _massetManager MassetManager contract address\\n */\\n constructor(\\n address _moc,\\n address _doc,\\n address _dllr,\\n address _massetManager,\\n address _permit2\\n ) {\\n require(\\n _moc != address(0) &&\\n _doc != address(0) &&\\n _dllr != address(0) &&\\n _massetManager != address(0) &&\\n _permit2 != address(0),\\n \\\"MocIntegration:: no null addresses allowed\\\"\\n );\\n moc = IMocMintRedeemDoc(_moc);\\n doc = IERC20(_doc);\\n dllr = IDLLR(_dllr);\\n massetManager = IMassetManager(_massetManager);\\n permit2 = IPermit2(_permit2);\\n }\\n\\n function initialize(address payable _mocVendorAccount) external initializer {\\n __Ownable_init();\\n _setMocVendorAccount(_mocVendorAccount);\\n }\\n\\n ///@dev the contract requires receiving funds temporarily before transferring them to users\\n receive() external payable {}\\n\\n /**\\n * @notice how getDocFromDllrAndRedeemRBTC function works:\\n * -------------------------------------------------------------------------------------------\\n * | Mynt | Money On Chain |\\n * -------------------------------------------------------------------------------------------\\n * | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user |\\n * -------------------------------------------------------------------------------------------\\n *\\n * @param _dllrAmount The amount of the DLLR (mAsset) that will be burned in exchange for _toToken\\n * @param _permitParams EIP-2612 permit params:\\n * _deadline Expiration time of the signature.\\n * _v Last 1 byte of ECDSA signature.\\n * _r First 32 bytes of ECDSA signature.\\n * _s 32 bytes after _r in ECDSA signature.\\n */\\n function getDocFromDllrAndRedeemRBTC(\\n uint256 _dllrAmount,\\n PermitParams calldata _permitParams\\n ) external {\\n // transfer _dllrAmount to this contract by permit (EIP-2612)\\n address thisAddress = address(this);\\n dllr.transferWithPermit(\\n msg.sender,\\n thisAddress,\\n _dllrAmount,\\n _permitParams.deadline,\\n _permitParams.v,\\n _permitParams.r,\\n _permitParams.s\\n );\\n\\n // redeem DoC from DLLR\\n require(\\n massetManager.redeemTo(address(doc), _dllrAmount, thisAddress) == _dllrAmount,\\n \\\"MocIntegration:: redeemed incorrect DoC amount\\\"\\n );\\n\\n // redeem RBTC from DoC using Money On Chain and send to the user\\n uint256 rbtcBalanceBefore = thisAddress.balance;\\n moc.redeemFreeDocVendors(_dllrAmount, payable(mocVendorAccount));\\n uint256 rbtcAmount = thisAddress.balance - rbtcBalanceBefore;\\n (bool success, ) = msg.sender.call{ value: rbtcAmount }(\\\"\\\");\\n require(success, \\\"MocIntegration:: error transferring redeemed RBTC\\\");\\n\\n emit GetDocFromDllrAndRedeemRBTC(msg.sender, _dllrAmount, rbtcAmount);\\n }\\n\\n /**\\n * @notice how getDocFromDllrAndRedeemRBTC function works:\\n * -------------------------------------------------------------------------------------------\\n * | Mynt | Money On Chain |\\n * -------------------------------------------------------------------------------------------\\n * | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user |\\n * -------------------------------------------------------------------------------------------\\n *\\n * @param permit permit data, in form of PermitTransferFrom struct.\\n * @param signature of the permit data.\\n */\\n function getDocFromDllrAndRedeemRbtcWithPermit2(\\n ISignatureTransfer.PermitTransferFrom memory permit,\\n bytes memory signature\\n ) external {\\n address thisAddress = address(this);\\n uint256 _dllrAmount = permit.permitted.amount;\\n\\n ISignatureTransfer.SignatureTransferDetails\\n memory transferDetails = _generateTransferDetails(thisAddress, _dllrAmount);\\n\\n permit2.permitTransferFrom(permit, transferDetails, msg.sender, signature);\\n\\n // redeem DoC from DLLR\\n require(\\n massetManager.redeemTo(address(doc), _dllrAmount, thisAddress) == _dllrAmount,\\n \\\"MocIntegration:: redeemed incorrect DoC amount\\\"\\n );\\n\\n // redeem RBTC from DoC using Money On Chain and send to the user\\n uint256 rbtcBalanceBefore = thisAddress.balance;\\n moc.redeemFreeDocVendors(_dllrAmount, payable(mocVendorAccount));\\n uint256 rbtcAmount = thisAddress.balance - rbtcBalanceBefore;\\n (bool success, ) = msg.sender.call{ value: rbtcAmount }(\\\"\\\");\\n require(success, \\\"MocIntegration:: error transferring redeemed RBTC\\\");\\n\\n emit GetDocFromDllrAndRedeemRBTC(msg.sender, _dllrAmount, rbtcAmount);\\n }\\n\\n /// Set MoC registered Vendor account to receive markup fees https://docs.moneyonchain.com/main-rbtc-contract/integration-with-moc-platform/vendors\\n function setMocVendorAccount(address payable newMocVedorAccount) external onlyOwner {\\n _setMocVendorAccount(newMocVedorAccount);\\n }\\n\\n function _setMocVendorAccount(address newMocVedorAccount) internal {\\n mocVendorAccount = newMocVedorAccount;\\n emit MocVendorAccountSet(mocVendorAccount);\\n }\\n\\n /**\\n * @dev get the implementation logic address referring to ERC1967 standard.\\n *\\n * @return logic implementation address.\\n */\\n function getProxyImplementation() external view returns (address) {\\n return ERC1967UpgradeUpgradeable._getImplementation();\\n }\\n\\n /**\\n * @dev view function to construct SignatureTransferDetails struct to be used by Permit2\\n *\\n * @param _to ultimate recipient\\n * @param _amount amount of transfer\\n *\\n * @return SignatureTransferDetails struct object\\n */\\n function _generateTransferDetails(\\n address _to,\\n uint256 _amount\\n ) private pure returns (ISignatureTransfer.SignatureTransferDetails memory) {\\n ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer\\n .SignatureTransferDetails({ to: _to, requestedAmount: _amount });\\n\\n return transferDetails;\\n }\\n}\\n\",\"keccak256\":\"0x5369b9bbb3e887e5d93413aed76f45df17085f6ee9d8f4826ab35c239f7a5539\",\"license\":\"MIT\"},\"contracts/interfaces/IApproveAndCall.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\n/**\\n * @title Interface for contract governance/ApprovalReceiver.sol\\n * @dev Interfaces are used to cast a contract address into a callable instance.\\n */\\ninterface IApproveAndCall {\\n /**\\n * @notice Receives approval from SOV token.\\n * @param _sender The sender of SOV.approveAndCall function.\\n * @param _amount The amount was approved.\\n * @param _token The address of token.\\n * @param _data The data will be used for low level call.\\n * */\\n function receiveApproval(\\n address _sender,\\n uint256 _amount,\\n address _token,\\n bytes calldata _data\\n ) external;\\n}\\n\",\"keccak256\":\"0x0dd8105c56c42841b136acb14c8058f7802800727d76daf708ec67f614f8f7f3\",\"license\":\"MIT\"},\"contracts/interfaces/IDLLR.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/token/ERC20/IERC20.sol\\\";\\n\\n/**\\n * @dev Permit params (EIP-2612) wrapper struct\\n */\\nstruct PermitParams {\\n uint256 deadline;\\n uint8 v;\\n bytes32 r;\\n bytes32 s;\\n}\\n\\n/**\\n * @title DLLR mAsset interface.\\n * @dev mAsset - Meta Asset Token implementation.\\n * Inherits from ERC20.\\n * mint and burn functions.\\n */\\ninterface IDLLR is IERC20 {\\n // events\\n\\n /**\\n * @dev Emitted when MassetManager config is changed.\\n * @param _newMassetManagerProxy Address of new MassetManager proxy.\\n */\\n event MassetManagerProxyChanged(address indexed _newMassetManagerProxy);\\n\\n /**\\n * @dev Emitted when Basket Manager config is changed.\\n * @param _newBasketManagerProxy Address of new Basket Manager proxy.\\n */\\n event BasketManagerProxyChanged(address indexed _newBasketManagerProxy);\\n\\n /**\\n * @dev getter function of MassetManager implementation address\\n *\\n * @return MassetManager implementation address\\n */\\n function massetManagerImplementation() external view returns (address);\\n\\n /**\\n * @dev getter function of basket manager implementation address\\n *\\n * @return basket manager implementation address\\n */\\n function basketManagerImplementation() external view returns (address);\\n\\n /**\\n * @notice setMassetManagerProxy sets the MassetManager proxy address\\n * @param _massetManagerProxy The address of the MassetManager proxy contract\\n */\\n function setMassetManagerProxy(address _massetManagerProxy) external;\\n\\n /**\\n * @notice setBasketManagerConfig sets the Basket Manager proxy address\\n * @param _basketManagerProxy The address of the Basket Manager proxy contract\\n */\\n function setBasketManagerProxy(address _basketManagerProxy) external;\\n\\n /**\\n * @notice Creates new tokens and sends them to the recipient.\\n * @notice Can be minted only by the MassetManager proxy contract.\\n *\\n * @param _account The recipient address to get the minted tokens.\\n * @param _amount The amount of tokens to be minted.\\n */\\n function mint(address _account, uint256 _amount) external;\\n\\n /**\\n * @notice Burns tokens for the given account.\\n * @notice Can be burned only by the MassetManager proxy contract.\\n *\\n * @param _account The recipient address to get the minted tokens.\\n * @param _amount The amount of tokens to be minted.\\n */\\n function burn(address _account, uint256 _amount) external;\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _recipient Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transfer(address _recipient, uint256 _amount) external returns (bool);\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transferFrom(address _from, address _to, uint256 _amount) external returns (bool);\\n\\n /**\\n * @notice transfer utilizing EIP-2612, to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @dev By calling this function, the allowance will be overwritten by the total amount.\\n *\\n * @param _from Owner of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of the token that will be transferred.\\n * @param _deadline Expiration time of the signature.\\n * @param _v Last 1 byte of ECDSA signature.\\n * @param _r First 32 bytes of ECDSA signature.\\n * @param _s 32 bytes after _r in ECDSA signature.\\n */\\n function transferWithPermit(\\n address _from,\\n address _to,\\n uint256 _amount,\\n uint256 _deadline,\\n uint8 _v,\\n bytes32 _r,\\n bytes32 _s\\n ) external;\\n\\n /**\\n * @notice Approves and then calls the receiving contract.\\n * Useful to encapsulate sending tokens to a contract in one call.\\n * Solidity has no native way to send tokens to contracts.\\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\\n * @param _spender The contract address to spend the tokens.\\n * @param _amount The amount of tokens to be sent.\\n * @param _data Parameters for the contract call, such as endpoint signature.\\n */\\n function approveAndCall(address _spender, uint256 _amount, bytes calldata _data) external;\\n\\n /**\\n * @dev to support EIP712, will need the token contract to return the chain id.\\n *\\n * @return chain id.\\n *\\n */\\n function getChainId() external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x34068131b6d47697cdf66239fe8f28b191afe6e13b5d145a39e7c93c8a092a01\",\"license\":\"MIT\"},\"contracts/interfaces/IMassetManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\n/**\\n * @title MassetManager\\n * @dev Contract is responsible for managing mAsset and bAsset.\\n * Used for minting and burning tokens and calculating fees\\n * if transaction based on token from another blockchain.\\n */\\n\\ninterface IMassetManager {\\n // events\\n\\n /**\\n * @dev Emitted when deposit is completed.\\n * @param minter Address of the minter.\\n * @param recipient Address of the recipient.\\n * @param massetQuantity Masset quantity.\\n * @param bAsset Address of the bAsset.\\n * @param bassetQuantity Basset quantity.\\n */\\n event Minted(\\n address indexed minter,\\n address indexed recipient,\\n uint256 massetQuantity,\\n address bAsset,\\n uint256 bassetQuantity\\n );\\n\\n /**\\n * @dev Emitted when withdrawal is completed.\\n * @param redeemer Address of the redeemer.\\n * @param recipient Address of the recipient.\\n * @param massetQuantity Masset quantity.\\n * @param bAsset Address of the bAsset.\\n * @param bassetQuantity Basset quantity.\\n */\\n event Redeemed(\\n address indexed redeemer,\\n address indexed recipient,\\n uint256 massetQuantity,\\n address bAsset,\\n uint256 bassetQuantity\\n );\\n\\n /***************************************\\n MINTING (PUBLIC)\\n ****************************************/\\n\\n /**\\n * @dev Mint a single mAsset, at a 1:1 ratio with the bAsset. This contract\\n * must have approval to spend the senders bAsset.\\n * @param _bAsset Address of the bAsset.\\n * @param _bAssetQuantity Quantity in bAsset units.\\n * @return massetMinted Quantity of newly minted mAsset.\\n */\\n function mint(\\n address _bAsset,\\n uint256 _bAssetQuantity\\n ) external returns (uint256 massetMinted);\\n\\n /**\\n * @dev Mint a single mAsset to recipient address, at a 1:1 ratio with the bAsset.\\n * This contract must have approval to spend the senders bAsset.\\n * @param _bAsset Address of the bAsset.\\n * @param _bAssetQuantity Quantity in bAsset units.\\n * @param _recipient Receipient of the newly minted mAsset tokens.\\n * @return massetMinted Number of newly minted mAssets.\\n */\\n function mintTo(\\n address _bAsset,\\n uint256 _bAssetQuantity,\\n address _recipient\\n ) external returns (uint256 massetMinted);\\n\\n /***************************************\\n REDEMPTION (PUBLIC)\\n ****************************************/\\n\\n /**\\n * @dev Credits the sender with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small mAsset fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeem(\\n address _bAsset,\\n uint256 _massetQuantity\\n ) external returns (uint256 massetRedeemed);\\n\\n /**\\n * @dev Credits a recipient with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @param _recipient Address to credit with withdrawn bAssets.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeemTo(\\n address _bAsset,\\n uint256 _massetQuantity,\\n address _recipient\\n ) external returns (uint256 massetRedeemed);\\n\\n // Getters\\n\\n function getFeesVault() external view returns (address);\\n\\n function getFeesManager() external view returns (address);\\n\\n function getVersion() external view returns (string memory);\\n\\n function getToken() external view returns (address);\\n\\n function getBasketManager() external view returns (address);\\n\\n /**\\n * @dev get the implementation logic address referring to ERC1967 standard.\\n *\\n * @return logic implementation address.\\n */\\n function getProxyImplementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0xa1f03fbed78848636e091cf9558ad018306a099d58dec55738aee06f3dec432a\",\"license\":\"MIT\"},\"contracts/interfaces/IProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity ^0.8.17;\\n\\ninterface IProxy {\\n function getProxyImplementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0x5bf844214dbafb99a41cd0dff86537312cd3f20636dbb8d27cc91496fd808bc5\",\"license\":\"MIT\"},\"contracts/meta-asset-token/DLLR.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\nimport \\\"./MetaAssetToken.sol\\\";\\n\\ncontract DLLR is MetaAssetToken {\\n constructor() MetaAssetToken(\\\"Sovryn Dollar\\\", \\\"DLLR\\\") {}\\n}\\n\",\"keccak256\":\"0x38a864f85b864d9b413c67d789493690aca728ca555ac6d0a345a40ee5b1794f\",\"license\":\"MIT\"},\"contracts/meta-asset-token/MetaAssetToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.17;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol\\\";\\nimport \\\"../interfaces/IApproveAndCall.sol\\\";\\nimport \\\"../interfaces/IProxy.sol\\\";\\n\\n/**\\n * @title MetaAssetToken\\n * @dev mAsset - Meta Asset Token implementation.\\n * Inherits from ERC20.\\n * mint and burn functions.\\n */\\n\\ncontract MetaAssetToken is ERC20Permit, Ownable {\\n // events\\n\\n /**\\n * @dev Emitted when MassetManager config is changed.\\n * @param _newMassetManagerProxy Address of new MassetManager proxy.\\n */\\n event MassetManagerProxyChanged(address indexed _newMassetManagerProxy);\\n\\n /**\\n * @dev Emitted when Basket Manager config is changed.\\n * @param _newBasketManagerProxy Address of new Basket Manager proxy.\\n */\\n event BasketManagerProxyChanged(address indexed _newBasketManagerProxy);\\n\\n /**\\n * @dev Emitted when transfer Manager config is changed.\\n */\\n event TransferWithPermit(address _from, address _to, uint256 _amount);\\n\\n // state\\n\\n address public massetManagerProxy;\\n address public basketManagerProxy;\\n\\n // modifiers\\n modifier onlyMassetManagerProxy() {\\n require(msg.sender == massetManagerProxy, \\\"DLLR:unauthorized MassetManager proxy\\\");\\n _;\\n }\\n\\n modifier requireValidRecipient(address _recipient) {\\n require(\\n _recipient != address(0) && _recipient != address(this),\\n \\\"DLLR: Invalid address. Cannot transfer DLLR to the null address.\\\"\\n );\\n _;\\n }\\n\\n /**\\n * @notice Constructor called on deployment, initiates the contract.\\n */\\n constructor(\\n string memory _tokenName,\\n string memory _symbol\\n ) ERC20(_tokenName, _symbol) ERC20Permit(_tokenName) {}\\n\\n /**\\n * @dev getter function of MassetManager implementation address\\n *\\n * @return MassetManager implementation address\\n */\\n function massetManagerImplementation() public view virtual returns (address) {\\n return IProxy(massetManagerProxy).getProxyImplementation();\\n }\\n\\n /**\\n * @dev getter function of basket manager implementation address\\n *\\n * @return basket manager implementation address\\n */\\n function basketManagerImplementation() public view virtual returns (address) {\\n return IProxy(basketManagerProxy).getProxyImplementation();\\n }\\n\\n /**\\n * @notice setMassetManagerProxy sets the MassetManager proxy address\\n * @param _massetManagerProxy The address of the MassetManager proxy contract\\n */\\n function setMassetManagerProxy(address _massetManagerProxy) external onlyOwner {\\n require(_massetManagerProxy != address(0), \\\"invalid MassetManager proxy address\\\");\\n massetManagerProxy = _massetManagerProxy;\\n\\n emit MassetManagerProxyChanged(massetManagerProxy);\\n }\\n\\n /**\\n * @notice setBasketManagerConfig sets the Basket Manager proxy address\\n * @param _basketManagerProxy The address of the Basket Manager proxy contract\\n */\\n function setBasketManagerProxy(address _basketManagerProxy) external onlyOwner {\\n require(_basketManagerProxy != address(0), \\\"invalid address\\\");\\n basketManagerProxy = _basketManagerProxy;\\n emit BasketManagerProxyChanged(basketManagerProxy);\\n }\\n\\n /**\\n * @notice Creates new tokens and sends them to the recipient.\\n * @notice Can be minted only by the MassetManager proxy contract.\\n *\\n * @param _account The recipient address to get the minted tokens.\\n * @param _amount The amount of tokens to be minted.\\n */\\n function mint(address _account, uint256 _amount) external onlyMassetManagerProxy {\\n _mint(_account, _amount);\\n }\\n\\n /**\\n * @notice Burns tokens for the given account.\\n * @notice Can be burned only by the MassetManager proxy contract.\\n *\\n * @param _account The recipient address to get the minted tokens.\\n * @param _amount The amount of tokens to be minted.\\n */\\n function burn(address _account, uint256 _amount) external onlyMassetManagerProxy {\\n _burn(_account, _amount);\\n }\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _recipient Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transfer(\\n address _recipient,\\n uint256 _amount\\n ) public override requireValidRecipient(_recipient) returns (bool) {\\n _transfer(_msgSender(), _recipient, _amount);\\n return true;\\n }\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _amount\\n ) public override requireValidRecipient(_to) returns (bool) {\\n _approve(_from, msg.sender, allowance(_from, msg.sender) - _amount);\\n _transfer(_from, _to, _amount);\\n return true;\\n }\\n\\n /**\\n * @notice transfer utilizing EIP-2612, to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @dev By calling this function, the allowance will be overwritten by the total amount.\\n *\\n * @param _from Owner of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of the token that will be transferred.\\n * @param _deadline Expiration time of the signature.\\n * @param _v Last 1 byte of ECDSA signature.\\n * @param _r First 32 bytes of ECDSA signature.\\n * @param _s 32 bytes after _r in ECDSA signature.\\n */\\n function transferWithPermit(\\n address _from,\\n address _to,\\n uint256 _amount,\\n uint256 _deadline,\\n uint8 _v,\\n bytes32 _r,\\n bytes32 _s\\n ) external requireValidRecipient(_to) {\\n permit(_from, msg.sender, _amount, _deadline, _v, _r, _s);\\n require(\\n transferFrom(_from, _to, _amount),\\n \\\"MetaAssetToken::transferWithPermit: transfer failed\\\"\\n );\\n\\n emit TransferWithPermit(_from, _to, _amount);\\n }\\n\\n /**\\n * @notice Approves and then calls the receiving contract.\\n * Useful to encapsulate sending tokens to a contract in one call.\\n * Solidity has no native way to send tokens to contracts.\\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\\n * @param _spender The contract address to spend the tokens.\\n * @param _amount The amount of tokens to be sent.\\n * @param _data Parameters for the contract call, such as endpoint signature.\\n */\\n function approveAndCall(address _spender, uint256 _amount, bytes calldata _data) external {\\n approve(_spender, _amount);\\n IApproveAndCall(_spender).receiveApproval(msg.sender, _amount, address(this), _data);\\n }\\n\\n /**\\n * @dev to support EIP712, will need the token contract to return the chain id.\\n *\\n * @return chain id.\\n *\\n */\\n function getChainId() external view returns (uint256) {\\n return block.chainid;\\n }\\n}\\n\",\"keccak256\":\"0x887c09ca5cf835d67db8389c8f4ab4fc2689444bb5806370431e1a18900b66d7\",\"license\":\"MIT\"},\"contracts/permit2/interfaces/IAllowanceTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title AllowanceTransfer\\n/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface IAllowanceTransfer is IEIP712 {\\n /// @notice Thrown when an allowance on a token has expired.\\n /// @param deadline The timestamp at which the allowed amount is no longer valid\\n error AllowanceExpired(uint256 deadline);\\n\\n /// @notice Thrown when an allowance on a token has been depleted.\\n /// @param amount The maximum amount allowed\\n error InsufficientAllowance(uint256 amount);\\n\\n /// @notice Thrown when too many nonces are invalidated.\\n error ExcessiveInvalidation();\\n\\n /// @notice Emits an event when the owner successfully invalidates an ordered nonce.\\n event NonceInvalidation(\\n address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.\\n event Approval(\\n address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.\\n event Permit(\\n address indexed owner,\\n address indexed token,\\n address indexed spender,\\n uint160 amount,\\n uint48 expiration,\\n uint48 nonce\\n );\\n\\n /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.\\n event Lockdown(address indexed owner, address token, address spender);\\n\\n /// @notice The permit data for a token\\n struct PermitDetails {\\n // ERC20 token address\\n address token;\\n // the maximum amount allowed to spend\\n uint160 amount;\\n // timestamp at which a spender's token allowances become invalid\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice The permit message signed for a single token allowance\\n struct PermitSingle {\\n // the permit data for a single token alownce\\n PermitDetails details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The permit message signed for multiple token allowances\\n struct PermitBatch {\\n // the permit data for multiple token allowances\\n PermitDetails[] details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The saved permissions\\n /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n struct PackedAllowance {\\n // amount allowed\\n uint160 amount;\\n // permission expiry\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice A token spender pair.\\n struct TokenSpenderPair {\\n // the token the spender is approved\\n address token;\\n // the spender address\\n address spender;\\n }\\n\\n /// @notice Details for a token transfer.\\n struct AllowanceTransferDetails {\\n // the owner of the token\\n address from;\\n // the recipient of the token\\n address to;\\n // the amount of the token\\n uint160 amount;\\n // the token to be transferred\\n address token;\\n }\\n\\n /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.\\n /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]\\n /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.\\n function allowance(address user, address token, address spender)\\n external\\n view\\n returns (uint160 amount, uint48 expiration, uint48 nonce);\\n\\n /// @notice Approves the spender to use up to amount of the specified token up until the expiration\\n /// @param token The token to approve\\n /// @param spender The spender address to approve\\n /// @param amount The approved amount of the token\\n /// @param expiration The timestamp at which the approval is no longer valid\\n /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n function approve(address token, address spender, uint160 amount, uint48 expiration) external;\\n\\n /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitSingle Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;\\n\\n /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitBatch Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;\\n\\n /// @notice Transfer approved tokens from one address to another\\n /// @param from The address to transfer from\\n /// @param to The address of the recipient\\n /// @param amount The amount of the token to transfer\\n /// @param token The token address to transfer\\n /// @dev Requires the from address to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(address from, address to, uint160 amount, address token) external;\\n\\n /// @notice Transfer approved tokens in a batch\\n /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers\\n /// @dev Requires the from addresses to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;\\n\\n /// @notice Enables performing a \\\"lockdown\\\" of the sender's Permit2 identity\\n /// by batch revoking approvals\\n /// @param approvals Array of approvals to revoke.\\n function lockdown(TokenSpenderPair[] calldata approvals) external;\\n\\n /// @notice Invalidate nonces for a given (token, spender) pair\\n /// @param token The token to invalidate nonces for\\n /// @param spender The spender to invalidate nonces for\\n /// @param newNonce The new nonce to set. Invalidates all nonces less than it.\\n /// @dev Can't invalidate more than 2**16 nonces per transaction.\\n function invalidateNonces(address token, address spender, uint48 newNonce) external;\\n}\\n\",\"keccak256\":\"0x37f0ac203b6ef605c9533e1a739477e8e9dcea90710b40e645a367f8a21ace29\",\"license\":\"MIT\"},\"contracts/permit2/interfaces/IEIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\ninterface IEIP712 {\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xfdccf2b9639070803cd0e4198427fb0df3cc452ca59bd3b8a0d957a9a4254138\",\"license\":\"MIT\"},\"contracts/permit2/interfaces/IPermit2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {ISignatureTransfer} from \\\"./ISignatureTransfer.sol\\\";\\nimport {IAllowanceTransfer} from \\\"./IAllowanceTransfer.sol\\\";\\n\\n/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer.\\n/// @dev Users must approve Permit2 before calling any of the transfer functions.\\ninterface IPermit2 is ISignatureTransfer, IAllowanceTransfer {\\n// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval.\\n}\\n\",\"keccak256\":\"0xaa631cc9f53e699301d94233007110a345e6779011def484e8dd97b8fe0af771\",\"license\":\"MIT\"},\"contracts/permit2/interfaces/ISignatureTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title SignatureTransfer\\n/// @notice Handles ERC20 token transfers through signature based actions\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface ISignatureTransfer is IEIP712 {\\n /// @notice Thrown when the requested amount for a transfer is larger than the permissioned amount\\n /// @param maxAmount The maximum amount a spender can request to transfer\\n error InvalidAmount(uint256 maxAmount);\\n\\n /// @notice Thrown when the number of tokens permissioned to a spender does not match the number of tokens being transferred\\n /// @dev If the spender does not need to transfer the number of tokens permitted, the spender can request amount 0 to be transferred\\n error LengthMismatch();\\n\\n /// @notice Emits an event when the owner successfully invalidates an unordered nonce.\\n event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);\\n\\n /// @notice The token and amount details for a transfer signed in the permit transfer signature\\n struct TokenPermissions {\\n // ERC20 token address\\n address token;\\n // the maximum amount that can be spent\\n uint256 amount;\\n }\\n\\n /// @notice The signed permit message for a single token transfer\\n struct PermitTransferFrom {\\n TokenPermissions permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice Specifies the recipient address and amount for batched transfers.\\n /// @dev Recipients and amounts correspond to the index of the signed token permissions array.\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount.\\n struct SignatureTransferDetails {\\n // recipient address\\n address to;\\n // spender requested amount\\n uint256 requestedAmount;\\n }\\n\\n /// @notice Used to reconstruct the signed permit message for multiple token transfers\\n /// @dev Do not need to pass in spender address as it is required that it is msg.sender\\n /// @dev Note that a user still signs over a spender address\\n struct PermitBatchTransferFrom {\\n // the tokens and corresponding amounts permitted for a transfer\\n TokenPermissions[] permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection\\n /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order\\n /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce\\n /// @dev It returns a uint256 bitmap\\n /// @dev The index, or wordPosition is capped at type(uint248).max\\n function nonceBitmap(address, uint256) external view returns (uint256);\\n\\n /// @notice Transfers a token using a signed permit message\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails The spender's requested transfer details for the permitted token\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitTransferFrom memory permit,\\n SignatureTransferDetails calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Transfers multiple tokens using a signed permit message\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails Specifies the recipient and requested amount for the token transfer\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitBatchTransferFrom memory permit,\\n SignatureTransferDetails[] calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Invalidates the bits specified in mask for the bitmap at the word position\\n /// @dev The wordPos is maxed at type(uint248).max\\n /// @param wordPos A number to index the nonceBitmap at\\n /// @param mask A bitmap masked against msg.sender's current bitmap at the word position\\n function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;\\n}\\n\",\"keccak256\":\"0xaffef816ae65c11123e5ac0ae0e7bf73506635bf6004d1ae3b4deed8c1bc69bd\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6101206040523480156200001257600080fd5b50604051620012cd380380620012cd833981016040819052620000359162000140565b6001600160a01b038516158015906200005657506001600160a01b03841615155b80156200006b57506001600160a01b03831615155b80156200008057506001600160a01b03821615155b80156200009557506001600160a01b03811615155b620000f95760405162461bcd60e51b815260206004820152602a60248201527f4d6f63496e746567726174696f6e3a3a206e6f206e756c6c2061646472657373604482015269195cc8185b1b1bddd95960b21b606482015260840160405180910390fd5b6001600160a01b0394851660805292841660a05290831660c052821660e0521661010052620001b0565b80516001600160a01b03811681146200013b57600080fd5b919050565b600080600080600060a086880312156200015957600080fd5b620001648662000123565b9450620001746020870162000123565b9350620001846040870162000123565b9250620001946060870162000123565b9150620001a46080870162000123565b90509295509295909350565b60805160a05160c05160e051610100516110a16200022c6000396000818160ff015261069301526000818161027501528181610435015261074f01526000818161014f01526103220152600081816101ee015281816103fb01526107150152600081816101a5015281816104f7015261080801526110a16000f3fe6080604052600436106100e15760003560e01c806390e4b7201161007f578063c4d66de811610059578063c4d66de814610297578063e5085517146102b7578063f2fde38b146102d7578063fc176819146102f757600080fd5b806390e4b7201461022e5780639b2633ae14610243578063b5c89bab1461026357600080fd5b806353428253116100bb5780635342825314610193578063715018a6146101c75780637a0a3ac5146101dc5780638da5cb5b1461021057600080fd5b806312261ee7146100ed57806333c507ae1461013d578063460f2de11461017157600080fd5b366100e857005b600080fd5b3480156100f957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b34801561014957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561017d57600080fd5b5061019161018c366004610c64565b610317565b005b34801561019f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d357600080fd5b50610191610619565b3480156101e857600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561021c57600080fd5b506033546001600160a01b0316610121565b34801561023a57600080fd5b5061012161062d565b34801561024f57600080fd5b5061019161025e366004610d7d565b610665565b34801561026f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156102a357600080fd5b506101916102b2366004610e40565b61092c565b3480156102c357600080fd5b506101916102d2366004610e40565b610a47565b3480156102e357600080fd5b506101916102f2366004610e40565b610a5b565b34801561030357600080fd5b50609754610121906001600160a01b031681565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663605629d6338386863561035c6040890160208a01610e64565b604080516001600160e01b031960e089901b1681526001600160a01b0396871660048201529590941660248601526044850192909252606484015260ff16608483015285013560a4820152606085013560c482015260e401600060405180830381600087803b1580156103ce57600080fd5b505af11580156103e2573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820187905284811660448301528693507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af115801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a39190610e87565b146104c95760405162461bcd60e51b81526004016104c090610ea0565b60405180910390fd5b60975460405163b7aa53e760e01b8152600481018590526001600160a01b03918216602482015282821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561053b57600080fd5b505af115801561054f573d6000803e3d6000fd5b50505050600081836001600160a01b03163161056b9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146105b0576040519150601f19603f3d011682016040523d82523d6000602084013e6105b5565b606091505b50509050806105d65760405162461bcd60e51b81526004016104c090610f0f565b604080518781526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a2505050505050565b610621610ad1565b61062b6000610b2b565b565b60006106607f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b815160200151309060006106798383610b7d565b60405163187945bd60e11b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906330f28b7a906106ce908890859033908a90600401610f60565b600060405180830381600087803b1580156106e857600080fd5b505af11580156106fc573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820186905286811660448301528593507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af1158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd9190610e87565b146107da5760405162461bcd60e51b81526004016104c090610ea0565b60975460405163b7aa53e760e01b8152600481018490526001600160a01b03918216602482015284821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561084c57600080fd5b505af1158015610860573d6000803e3d6000fd5b50505050600081856001600160a01b03163161087c9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146108c1576040519150601f19603f3d011682016040523d82523d6000602084013e6108c6565b606091505b50509050806108e75760405162461bcd60e51b81526004016104c090610f0f565b604080518681526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a25050505050505050565b600054610100900460ff161580801561094c5750600054600160ff909116105b806109665750303b158015610966575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104c0565b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b6109f4610bb1565b6109fd82610be0565b8015610a43576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b610a4f610ad1565b610a5881610be0565b50565b610a63610ad1565b6001600160a01b038116610ac85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104c0565b610a5881610b2b565b6033546001600160a01b0316331461062b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104c0565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080518082018252600080825260209182015281518083019092526001600160a01b038416825281018290525b92915050565b600054610100900460ff16610bd85760405162461bcd60e51b81526004016104c090611020565b61062b610c34565b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527fc2a1feb9d65ecb31b0e93a520a66d19319929a2bf58046d92d762c04e7dd06c99060200160405180910390a150565b600054610100900460ff16610c5b5760405162461bcd60e51b81526004016104c090611020565b61062b33610b2b565b60008082840360a0811215610c7857600080fd5b833592506080601f1982011215610c8e57600080fd5b506020830190509250929050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610cd557610cd5610c9c565b60405290565b6001600160a01b0381168114610a5857600080fd5b600082601f830112610d0157600080fd5b813567ffffffffffffffff80821115610d1c57610d1c610c9c565b604051601f8301601f19908116603f01168101908282118183101715610d4457610d44610c9c565b81604052838152866020858801011115610d5d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008082840360a0811215610d9157600080fd5b6080811215610d9f57600080fd5b6040516060810167ffffffffffffffff8282108183111715610dc357610dc3610c9c565b816040526040841215610dd557600080fd5b610ddd610cb2565b935086359150610dec82610cdb565b8184526020870135602085015283835260408701356020840152606087013560408401528295506080870135935080841115610e2757600080fd5b505050610e3685828601610cf0565b9150509250929050565b600060208284031215610e5257600080fd5b8135610e5d81610cdb565b9392505050565b600060208284031215610e7657600080fd5b813560ff81168114610e5d57600080fd5b600060208284031215610e9957600080fd5b5051919050565b6020808252602e908201527f4d6f63496e746567726174696f6e3a3a2072656465656d656420696e636f727260408201526d1958dd08111bd0c8185b5bdd5b9d60921b606082015260800190565b81810381811115610bab57634e487b7160e01b600052601160045260246000fd5b60208082526031908201527f4d6f63496e746567726174696f6e3a3a206572726f72207472616e7366657272604082015270696e672072656465656d6564205242544360781b606082015260800190565b6000610100610f8383885180516001600160a01b03168252602090810151910152565b602080880151604085015260408801516060850152610fb8608085018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c085015260e0840182905284519184018290526000915b80831015610ff957858301820151858401610120015291810191610fda565b6101209250600083828701015282601f19601f830116860101935050505095945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220d0fcc7c15da2d0cf8a6f0df865b7535edea2c45483b951fb883a7a57908c9d0764736f6c63430008110033", + "deployedBytecode": "0x6080604052600436106100e15760003560e01c806390e4b7201161007f578063c4d66de811610059578063c4d66de814610297578063e5085517146102b7578063f2fde38b146102d7578063fc176819146102f757600080fd5b806390e4b7201461022e5780639b2633ae14610243578063b5c89bab1461026357600080fd5b806353428253116100bb5780635342825314610193578063715018a6146101c75780637a0a3ac5146101dc5780638da5cb5b1461021057600080fd5b806312261ee7146100ed57806333c507ae1461013d578063460f2de11461017157600080fd5b366100e857005b600080fd5b3480156100f957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b34801561014957600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561017d57600080fd5b5061019161018c366004610c64565b610317565b005b34801561019f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156101d357600080fd5b50610191610619565b3480156101e857600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b34801561021c57600080fd5b506033546001600160a01b0316610121565b34801561023a57600080fd5b5061012161062d565b34801561024f57600080fd5b5061019161025e366004610d7d565b610665565b34801561026f57600080fd5b506101217f000000000000000000000000000000000000000000000000000000000000000081565b3480156102a357600080fd5b506101916102b2366004610e40565b61092c565b3480156102c357600080fd5b506101916102d2366004610e40565b610a47565b3480156102e357600080fd5b506101916102f2366004610e40565b610a5b565b34801561030357600080fd5b50609754610121906001600160a01b031681565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663605629d6338386863561035c6040890160208a01610e64565b604080516001600160e01b031960e089901b1681526001600160a01b0396871660048201529590941660248601526044850192909252606484015260ff16608483015285013560a4820152606085013560c482015260e401600060405180830381600087803b1580156103ce57600080fd5b505af11580156103e2573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820187905284811660448301528693507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af115801561047f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104a39190610e87565b146104c95760405162461bcd60e51b81526004016104c090610ea0565b60405180910390fd5b60975460405163b7aa53e760e01b8152600481018590526001600160a01b03918216602482015282821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561053b57600080fd5b505af115801561054f573d6000803e3d6000fd5b50505050600081836001600160a01b03163161056b9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146105b0576040519150601f19603f3d011682016040523d82523d6000602084013e6105b5565b606091505b50509050806105d65760405162461bcd60e51b81526004016104c090610f0f565b604080518781526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a2505050505050565b610621610ad1565b61062b6000610b2b565b565b60006106607f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b815160200151309060006106798383610b7d565b60405163187945bd60e11b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906330f28b7a906106ce908890859033908a90600401610f60565b600060405180830381600087803b1580156106e857600080fd5b505af11580156106fc573d6000803e3d6000fd5b505060405163fb2c922360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820186905286811660448301528593507f000000000000000000000000000000000000000000000000000000000000000016915063fb2c9223906064016020604051808303816000875af1158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd9190610e87565b146107da5760405162461bcd60e51b81526004016104c090610ea0565b60975460405163b7aa53e760e01b8152600481018490526001600160a01b03918216602482015284821631917f0000000000000000000000000000000000000000000000000000000000000000169063b7aa53e790604401600060405180830381600087803b15801561084c57600080fd5b505af1158015610860573d6000803e3d6000fd5b50505050600081856001600160a01b03163161087c9190610eee565b604051909150600090339083908381818185875af1925050503d80600081146108c1576040519150601f19603f3d011682016040523d82523d6000602084013e6108c6565b606091505b50509050806108e75760405162461bcd60e51b81526004016104c090610f0f565b604080518681526020810184905233917f5933f612d4a5aafda234d2ad17b54eba4187e2bb520cf7373e223c5894851ca5910160405180910390a25050505050505050565b600054610100900460ff161580801561094c5750600054600160ff909116105b806109665750303b158015610966575060005460ff166001145b6109c95760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016104c0565b6000805460ff1916600117905580156109ec576000805461ff0019166101001790555b6109f4610bb1565b6109fd82610be0565b8015610a43576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b610a4f610ad1565b610a5881610be0565b50565b610a63610ad1565b6001600160a01b038116610ac85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016104c0565b610a5881610b2b565b6033546001600160a01b0316331461062b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104c0565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b604080518082018252600080825260209182015281518083019092526001600160a01b038416825281018290525b92915050565b600054610100900460ff16610bd85760405162461bcd60e51b81526004016104c090611020565b61062b610c34565b609780546001600160a01b0319166001600160a01b0383169081179091556040519081527fc2a1feb9d65ecb31b0e93a520a66d19319929a2bf58046d92d762c04e7dd06c99060200160405180910390a150565b600054610100900460ff16610c5b5760405162461bcd60e51b81526004016104c090611020565b61062b33610b2b565b60008082840360a0811215610c7857600080fd5b833592506080601f1982011215610c8e57600080fd5b506020830190509250929050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715610cd557610cd5610c9c565b60405290565b6001600160a01b0381168114610a5857600080fd5b600082601f830112610d0157600080fd5b813567ffffffffffffffff80821115610d1c57610d1c610c9c565b604051601f8301601f19908116603f01168101908282118183101715610d4457610d44610c9c565b81604052838152866020858801011115610d5d57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008082840360a0811215610d9157600080fd5b6080811215610d9f57600080fd5b6040516060810167ffffffffffffffff8282108183111715610dc357610dc3610c9c565b816040526040841215610dd557600080fd5b610ddd610cb2565b935086359150610dec82610cdb565b8184526020870135602085015283835260408701356020840152606087013560408401528295506080870135935080841115610e2757600080fd5b505050610e3685828601610cf0565b9150509250929050565b600060208284031215610e5257600080fd5b8135610e5d81610cdb565b9392505050565b600060208284031215610e7657600080fd5b813560ff81168114610e5d57600080fd5b600060208284031215610e9957600080fd5b5051919050565b6020808252602e908201527f4d6f63496e746567726174696f6e3a3a2072656465656d656420696e636f727260408201526d1958dd08111bd0c8185b5bdd5b9d60921b606082015260800190565b81810381811115610bab57634e487b7160e01b600052601160045260246000fd5b60208082526031908201527f4d6f63496e746567726174696f6e3a3a206572726f72207472616e7366657272604082015270696e672072656465656d6564205242544360781b606082015260800190565b6000610100610f8383885180516001600160a01b03168252602090810151910152565b602080880151604085015260408801516060850152610fb8608085018880516001600160a01b03168252602090810151910152565b6001600160a01b03861660c085015260e0840182905284519184018290526000915b80831015610ff957858301820151858401610120015291810191610fda565b6101209250600083828701015282601f19601f830116860101935050505095945050505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056fea2646970667358221220d0fcc7c15da2d0cf8a6f0df865b7535edea2c45483b951fb883a7a57908c9d0764736f6c63430008110033", + "devdoc": { + "kind": "dev", + "methods": { + "constructor": { + "params": { + "_dllr": "DLLR contract address", + "_doc": "DoC contract address", + "_massetManager": "MassetManager contract address", + "_moc": "MoC main contract address" + } + }, + "getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))": { + "params": { + "_dllrAmount": "The amount of the DLLR (mAsset) that will be burned in exchange for _toToken", + "_permitParams": "EIP-2612 permit params: _deadline Expiration time of the signature. _v Last 1 byte of ECDSA signature. _r First 32 bytes of ECDSA signature. _s 32 bytes after _r in ECDSA signature." + } + }, + "getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)": { + "params": { + "permit": "permit data, in form of PermitTransferFrom struct.", + "signature": "of the permit data." + } + }, + "getProxyImplementation()": { + "details": "get the implementation logic address referring to ERC1967 standard.", + "returns": { + "_0": "logic implementation address." + } + }, + "owner()": { + "details": "Returns the address of the current owner." + }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner." + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "getDocFromDllrAndRedeemRBTC(uint256,(uint256,uint8,bytes32,bytes32))": { + "notice": "how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------" + }, + "getDocFromDllrAndRedeemRbtcWithPermit2(((address,uint256),uint256,uint256),bytes)": { + "notice": "how getDocFromDllrAndRedeemRBTC function works: ------------------------------------------------------------------------------------------- | Mynt | Money On Chain | ------------------------------------------------------------------------------------------- | get DLLR (EIP-2612) -> convert DLLR to DoC | -> get RBTC from DoC -> send RBTC to user | -------------------------------------------------------------------------------------------" + }, + "setMocVendorAccount(address)": { + "notice": "Set MoC registered Vendor account to receive markup fees https://docs.moneyonchain.com/main-rbtc-contract/integration-with-moc-platform/vendors" + } + }, + "notice": "This contract provides compound functions with Money On Chain wrapping them in one transaction for convenience and to save on gas", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 534, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8" + }, + { + "astId": 537, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 1021, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 10, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "_owner", + "offset": 0, + "slot": "51", + "type": "t_address" + }, + { + "astId": 130, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "52", + "type": "t_array(t_uint256)49_storage" + }, + { + "astId": 516, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "__gap", + "offset": 0, + "slot": "101", + "type": "t_array(t_uint256)50_storage" + }, + { + "astId": 3845, + "contract": "contracts/integration/MoC/MocIntegration.sol:MocIntegration", + "label": "mocVendorAccount", + "offset": 0, + "slot": "151", + "type": "t_address" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)49_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "base": "t_uint256", + "encoding": "inplace", + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "encoding": "inplace", + "label": "uint8", + "numberOfBytes": "1" + } + } + } +} diff --git a/external/deployments/rskTestnet/MocIntegration_Proxy.json b/external/deployments/rskTestnet/MocIntegration_Proxy.json new file mode 100644 index 000000000..93a321ae9 --- /dev/null +++ b/external/deployments/rskTestnet/MocIntegration_Proxy.json @@ -0,0 +1,233 @@ +{ + "address": "0xdC3e5232db60088D67aA7AF10595979D7eB5290f", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "admin_", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "admin_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "changeAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "implementation_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x553b5317bb24535c892f6dd850e988b46590ca9989545fda423e35d89ba0b734", + "receipt": { + "to": null, + "from": "0xCF311E7375083b9513566a47B9f3e93F1FcdCfBF", + "contractAddress": "0xdC3e5232db60088D67aA7AF10595979D7eB5290f", + "transactionIndex": 0, + "gasUsed": "928290", + "logsBloom": "0x00000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000008000000000002000000000000000000000000000000000000000000000000000000000000000000000000800000000000000400000000000000000000000000000000000000000000000000000000000000000000820010000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000400000000000000000000000000000020000000000000000000000000000000000000000000000000000000", + "blockHash": "0x2362b768ecbcf3bb971d1fedb20c60960a43e722ae708e1f898b1c2b9f90c246", + "transactionHash": "0x553b5317bb24535c892f6dd850e988b46590ca9989545fda423e35d89ba0b734", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 3440477, + "transactionHash": "0x553b5317bb24535c892f6dd850e988b46590ca9989545fda423e35d89ba0b734", + "address": "0xdC3e5232db60088D67aA7AF10595979D7eB5290f", + "topics": [ + "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", + "0x0000000000000000000000000c5b9385cc9fa96bc26a0ab066ac3047a8f0ffa3" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x2362b768ecbcf3bb971d1fedb20c60960a43e722ae708e1f898b1c2b9f90c246" + }, + { + "transactionIndex": 0, + "blockNumber": 3440477, + "transactionHash": "0x553b5317bb24535c892f6dd850e988b46590ca9989545fda423e35d89ba0b734", + "address": "0xdC3e5232db60088D67aA7AF10595979D7eB5290f", + "topics": ["0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f"], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000718425f091df36637e14602635b9a17a20ba23e4", + "logIndex": 1, + "blockHash": "0x2362b768ecbcf3bb971d1fedb20c60960a43e722ae708e1f898b1c2b9f90c246" + } + ], + "blockNumber": 3440477, + "cumulativeGasUsed": "928290", + "status": 1, + "byzantium": true + }, + "args": [ + "0x0c5b9385Cc9fa96bc26A0Ab066ac3047A8f0FFa3", + "0x718425f091Df36637e14602635B9a17a20Ba23E4", + "0x" + ], + "numDeployments": 1, + "solcInputHash": "0e89febeebc7444140de8e67c9067d2c", + "metadata": "{\"compiler\":{\"version\":\"0.8.10+commit.fc410830\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_logic\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"beacon\",\"type\":\"address\"}],\"name\":\"BeaconUpgraded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"changeAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"implementation_\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newImplementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"details\":\"This contract implements a proxy that is upgradeable by an admin. To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector clashing], which can potentially be used in an attack, this contract uses the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two things that go hand in hand: 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if that call matches one of the admin functions exposed by the proxy itself. 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the implementation. If the admin tries to call a function on the implementation it will fail with an error that says \\\"admin cannot fallback to proxy target\\\". These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to call a function from the proxy implementation. Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\",\"kind\":\"dev\",\"methods\":{\"admin()\":{\"details\":\"Returns the current admin. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\"},\"changeAdmin(address)\":{\"details\":\"Changes the admin of the proxy. Emits an {AdminChanged} event. NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.\"},\"constructor\":{\"details\":\"Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\"},\"implementation()\":{\"details\":\"Returns the current implementation. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\"},\"upgradeTo(address)\":{\"details\":\"Upgrade the implementation of the proxy. NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.\"},\"upgradeToAndCall(address,bytes)\":{\"details\":\"Upgrade the implementation of the proxy, and then call a function from the new implementation as specified by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the proxied contract. NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"solc_0.8/openzeppelin/proxy/transparent/TransparentUpgradeableProxy.sol\":\"TransparentUpgradeableProxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"solc_0.8/openzeppelin/interfaces/draft-IERC1822.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (interfaces/draft-IERC1822.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\\n * proxy whose upgrades are fully controlled by the current implementation.\\n */\\ninterface IERC1822Proxiable {\\n /**\\n * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\\n * address.\\n *\\n * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\\n * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\\n * function revert if invoked through a proxy.\\n */\\n function proxiableUUID() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x93b4e21c931252739a1ec13ea31d3d35a5c068be3163ccab83e4d70c40355f03\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/proxy/ERC1967/ERC1967Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../Proxy.sol\\\";\\nimport \\\"./ERC1967Upgrade.sol\\\";\\n\\n/**\\n * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an\\n * implementation address that can be changed. This address is stored in storage in the location specified by\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the\\n * implementation behind the proxy.\\n */\\ncontract ERC1967Proxy is Proxy, ERC1967Upgrade {\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded\\n * function call, and allows initializating the storage of the proxy like a Solidity constructor.\\n */\\n constructor(address _logic, bytes memory _data) payable {\\n assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256(\\\"eip1967.proxy.implementation\\\")) - 1));\\n _upgradeToAndCall(_logic, _data, false);\\n }\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _implementation() internal view virtual override returns (address impl) {\\n return ERC1967Upgrade._getImplementation();\\n }\\n}\\n\",\"keccak256\":\"0x6309f9f39dc6f4f45a24f296543867aa358e32946cd6b2874627a996d606b3a0\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/proxy/ERC1967/ERC1967Upgrade.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (proxy/ERC1967/ERC1967Upgrade.sol)\\n\\npragma solidity ^0.8.2;\\n\\nimport \\\"../beacon/IBeacon.sol\\\";\\nimport \\\"../../interfaces/draft-IERC1822.sol\\\";\\nimport \\\"../../utils/Address.sol\\\";\\nimport \\\"../../utils/StorageSlot.sol\\\";\\n\\n/**\\n * @dev This abstract contract provides getters and event emitting update functions for\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\\n *\\n * _Available since v4.1._\\n *\\n * @custom:oz-upgrades-unsafe-allow delegatecall\\n */\\nabstract contract ERC1967Upgrade {\\n // This is the keccak-256 hash of \\\"eip1967.proxy.rollback\\\" subtracted by 1\\n bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function _getImplementation() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 implementation slot.\\n */\\n function _setImplementation(address newImplementation) private {\\n require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n }\\n\\n /**\\n * @dev Perform implementation upgrade\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeTo(address newImplementation) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCall(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _upgradeTo(newImplementation);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(newImplementation, data);\\n }\\n }\\n\\n /**\\n * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\\n *\\n * Emits an {Upgraded} event.\\n */\\n function _upgradeToAndCallUUPS(\\n address newImplementation,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n // Upgrades from old implementations will perform a rollback test. This test requires the new\\n // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\\n // this special case will break upgrade paths from old UUPS implementation to new ones.\\n if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\\n _setImplementation(newImplementation);\\n } else {\\n try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\\n require(slot == _IMPLEMENTATION_SLOT, \\\"ERC1967Upgrade: unsupported proxiableUUID\\\");\\n } catch {\\n revert(\\\"ERC1967Upgrade: new implementation is not UUPS\\\");\\n }\\n _upgradeToAndCall(newImplementation, data, forceCall);\\n }\\n }\\n\\n /**\\n * @dev Storage slot with the admin of the contract.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.admin\\\" subtracted by 1, and is\\n * validated in the constructor.\\n */\\n bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n /**\\n * @dev Emitted when the admin account has changed.\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _getAdmin() internal view virtual returns (address) {\\n return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 admin slot.\\n */\\n function _setAdmin(address newAdmin) private {\\n require(newAdmin != address(0), \\\"ERC1967: new admin is the zero address\\\");\\n StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n */\\n function _changeAdmin(address newAdmin) internal {\\n emit AdminChanged(_getAdmin(), newAdmin);\\n _setAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\\n * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\\n */\\n bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\\n\\n /**\\n * @dev Emitted when the beacon is upgraded.\\n */\\n event BeaconUpgraded(address indexed beacon);\\n\\n /**\\n * @dev Returns the current beacon.\\n */\\n function _getBeacon() internal view returns (address) {\\n return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new beacon in the EIP1967 beacon slot.\\n */\\n function _setBeacon(address newBeacon) private {\\n require(Address.isContract(newBeacon), \\\"ERC1967: new beacon is not a contract\\\");\\n require(Address.isContract(IBeacon(newBeacon).implementation()), \\\"ERC1967: beacon implementation is not a contract\\\");\\n StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\\n }\\n\\n /**\\n * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\\n * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\\n *\\n * Emits a {BeaconUpgraded} event.\\n */\\n function _upgradeBeaconToAndCall(\\n address newBeacon,\\n bytes memory data,\\n bool forceCall\\n ) internal {\\n _setBeacon(newBeacon);\\n emit BeaconUpgraded(newBeacon);\\n if (data.length > 0 || forceCall) {\\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\\n }\\n }\\n}\\n\",\"keccak256\":\"0x17668652127feebed0ce8d9431ef95ccc8c4292f03e3b8cf06c6ca16af396633\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/proxy/Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (proxy/Proxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\\n * be specified by overriding the virtual {_implementation} function.\\n *\\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\\n * different contract through the {_delegate} function.\\n *\\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\\n */\\nabstract contract Proxy {\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal virtual {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n /**\\n * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function\\n * and {_fallback} should delegate.\\n */\\n function _implementation() internal view virtual returns (address);\\n\\n /**\\n * @dev Delegates the current call to the address returned by `_implementation()`.\\n *\\n * This function does not return to its internall call site, it will return directly to the external caller.\\n */\\n function _fallback() internal virtual {\\n _beforeFallback();\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\\n * is empty.\\n */\\n receive() external payable virtual {\\n _fallback();\\n }\\n\\n /**\\n * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\\n * call, or as part of the Solidity `fallback` or `receive` functions.\\n *\\n * If overriden should call `super._beforeFallback()`.\\n */\\n function _beforeFallback() internal virtual {}\\n}\\n\",\"keccak256\":\"0xd5d1fd16e9faff7fcb3a52e02a8d49156f42a38a03f07b5f1810c21c2149a8ab\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/proxy/beacon/IBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\\n */\\ninterface IBeacon {\\n /**\\n * @dev Must return an address that can be used as a delegate call target.\\n *\\n * {BeaconProxy} will check that this address is a contract.\\n */\\n function implementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0xd50a3421ac379ccb1be435fa646d66a65c986b4924f0849839f08692f39dde61\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/proxy/transparent/TransparentUpgradeableProxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../ERC1967/ERC1967Proxy.sol\\\";\\n\\n/**\\n * @dev This contract implements a proxy that is upgradeable by an admin.\\n *\\n * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector\\n * clashing], which can potentially be used in an attack, this contract uses the\\n * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two\\n * things that go hand in hand:\\n *\\n * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if\\n * that call matches one of the admin functions exposed by the proxy itself.\\n * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the\\n * implementation. If the admin tries to call a function on the implementation it will fail with an error that says\\n * \\\"admin cannot fallback to proxy target\\\".\\n *\\n * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing\\n * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due\\n * to sudden errors when trying to call a function from the proxy implementation.\\n *\\n * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,\\n * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\\n */\\ncontract TransparentUpgradeableProxy is ERC1967Proxy {\\n /**\\n * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and\\n * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\\n */\\n constructor(\\n address _logic,\\n address admin_,\\n bytes memory _data\\n ) payable ERC1967Proxy(_logic, _data) {\\n assert(_ADMIN_SLOT == bytes32(uint256(keccak256(\\\"eip1967.proxy.admin\\\")) - 1));\\n _changeAdmin(admin_);\\n }\\n\\n /**\\n * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.\\n */\\n modifier ifAdmin() {\\n if (msg.sender == _getAdmin()) {\\n _;\\n } else {\\n _fallback();\\n }\\n }\\n\\n /**\\n * @dev Returns the current admin.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\\n */\\n function admin() external ifAdmin returns (address admin_) {\\n admin_ = _getAdmin();\\n }\\n\\n /**\\n * @dev Returns the current implementation.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\\n * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\\n */\\n function implementation() external ifAdmin returns (address implementation_) {\\n implementation_ = _implementation();\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {AdminChanged} event.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.\\n */\\n function changeAdmin(address newAdmin) external virtual ifAdmin {\\n _changeAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev Upgrade the implementation of the proxy.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.\\n */\\n function upgradeTo(address newImplementation) external ifAdmin {\\n _upgradeToAndCall(newImplementation, bytes(\\\"\\\"), false);\\n }\\n\\n /**\\n * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified\\n * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the\\n * proxied contract.\\n *\\n * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.\\n */\\n function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {\\n _upgradeToAndCall(newImplementation, data, true);\\n }\\n\\n /**\\n * @dev Returns the current admin.\\n */\\n function _admin() internal view virtual returns (address) {\\n return _getAdmin();\\n }\\n\\n /**\\n * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.\\n */\\n function _beforeFallback() internal virtual override {\\n require(msg.sender != _getAdmin(), \\\"TransparentUpgradeableProxy: admin cannot fallback to proxy target\\\");\\n super._beforeFallback();\\n }\\n}\\n\",\"keccak256\":\"0x140055a64cf579d622e04f5a198595832bf2cb193cd0005f4f2d4d61ca906253\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0-rc.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev Returns true if `account` is a contract.\\n *\\n * [IMPORTANT]\\n * ====\\n * It is unsafe to assume that an address for which this function returns\\n * false is an externally-owned account (EOA) and not a contract.\\n *\\n * Among others, `isContract` will return false for the following\\n * types of addresses:\\n *\\n * - an externally-owned account\\n * - a contract in construction\\n * - an address where a contract will be created\\n * - an address where a contract lived, but was destroyed\\n * ====\\n *\\n * [IMPORTANT]\\n * ====\\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n *\\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n * constructor.\\n * ====\\n */\\n function isContract(address account) internal view returns (bool) {\\n // This method relies on extcodesize/address.code.length, which returns 0\\n // for contracts in construction, since the code is only stored at the end\\n // of the constructor execution.\\n\\n return account.code.length > 0;\\n }\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason, it is bubbled up by this\\n * function (like regular Solidity function calls).\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n * `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value\\n ) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n * with `errorMessage` as a fallback revert reason when `target` reverts.\\n *\\n * _Available since v3.1._\\n */\\n function functionCallWithValue(\\n address target,\\n bytes memory data,\\n uint256 value,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a static call.\\n *\\n * _Available since v3.3._\\n */\\n function functionStaticCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal view returns (bytes memory) {\\n require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n * but performing a delegate call.\\n *\\n * _Available since v3.4._\\n */\\n function functionDelegateCall(\\n address target,\\n bytes memory data,\\n string memory errorMessage\\n ) internal returns (bytes memory) {\\n require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResult(success, returndata, errorMessage);\\n }\\n\\n /**\\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n * revert reason using the provided one.\\n *\\n * _Available since v4.3._\\n */\\n function verifyCallResult(\\n bool success,\\n bytes memory returndata,\\n string memory errorMessage\\n ) internal pure returns (bytes memory) {\\n if (success) {\\n return returndata;\\n } else {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert(errorMessage);\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3777e696b62134e6177440dbe6e6601c0c156a443f57167194b67e75527439de\",\"license\":\"MIT\"},\"solc_0.8/openzeppelin/utils/StorageSlot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Library for reading and writing primitive types to specific storage slots.\\n *\\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\\n * This library helps with reading and writing to such slots without the need for inline assembly.\\n *\\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\\n *\\n * Example usage to set ERC1967 implementation slot:\\n * ```\\n * contract ERC1967 {\\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n *\\n * function _getImplementation() internal view returns (address) {\\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n * }\\n *\\n * function _setImplementation(address newImplementation) internal {\\n * require(Address.isContract(newImplementation), \\\"ERC1967: new implementation is not a contract\\\");\\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n * }\\n * }\\n * ```\\n *\\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\\n */\\nlibrary StorageSlot {\\n struct AddressSlot {\\n address value;\\n }\\n\\n struct BooleanSlot {\\n bool value;\\n }\\n\\n struct Bytes32Slot {\\n bytes32 value;\\n }\\n\\n struct Uint256Slot {\\n uint256 value;\\n }\\n\\n /**\\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\\n */\\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\\n */\\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\\n */\\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\\n */\\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\\n assembly {\\n r.slot := slot\\n }\\n }\\n}\\n\",\"keccak256\":\"0xfe1b7a9aa2a530a9e705b220e26cd584e2fbdc9602a3a1066032b12816b46aca\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x6080604052604051620011b2380380620011b2833981016040819052620000269162000519565b82816200005560017f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbd620005f9565b6000805160206200116b833981519152146200007557620000756200061f565b6200008382826000620000e7565b50620000b3905060017fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6104620005f9565b6000805160206200114b83398151915214620000d357620000d36200061f565b620000de8262000124565b50505062000688565b620000f2836200017f565b600082511180620001005750805b156200011f576200011d8383620001c160201b620002ff1760201c565b505b505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6200014f620001f0565b604080516001600160a01b03928316815291841660208301520160405180910390a16200017c8162000229565b50565b6200018a81620002de565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060620001e983836040518060600160405280602781526020016200118b6027913962000381565b9392505050565b60006200021a6000805160206200114b83398151915260001b6200046760201b620002731760201c565b546001600160a01b0316919050565b6001600160a01b038116620002945760405162461bcd60e51b815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b80620002bd6000805160206200114b83398151915260001b6200046760201b620002731760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b620002f4816200046a60201b6200032b1760201c565b620003585760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016200028b565b80620002bd6000805160206200116b83398151915260001b6200046760201b620002731760201c565b60606001600160a01b0384163b620003eb5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016200028b565b600080856001600160a01b03168560405162000408919062000635565b600060405180830381855af49150503d806000811462000445576040519150601f19603f3d011682016040523d82523d6000602084013e6200044a565b606091505b5090925090506200045d82828662000479565b9695505050505050565b90565b6001600160a01b03163b151590565b606083156200048a575081620001e9565b8251156200049b5782518084602001fd5b8160405162461bcd60e51b81526004016200028b919062000653565b80516001600160a01b0381168114620004cf57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000507578181015183820152602001620004ed565b838111156200011d5750506000910152565b6000806000606084860312156200052f57600080fd5b6200053a84620004b7565b92506200054a60208501620004b7565b60408501519092506001600160401b03808211156200056857600080fd5b818601915086601f8301126200057d57600080fd5b815181811115620005925762000592620004d4565b604051601f8201601f19908116603f01168101908382118183101715620005bd57620005bd620004d4565b81604052828152896020848701011115620005d757600080fd5b620005ea836020830160208801620004ea565b80955050505050509250925092565b6000828210156200061a57634e487b7160e01b600052601160045260246000fd5b500390565b634e487b7160e01b600052600160045260246000fd5b6000825162000649818460208701620004ea565b9190910192915050565b602081526000825180602084015262000674816040850160208701620004ea565b601f01601f19169190910160400192915050565b610ab380620006986000396000f3fe60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b61009036600461091f565b610135565b61006b6100a336600461093a565b610196565b3480156100b457600080fd5b506100bd610221565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b61010136600461091f565b610276565b34801561011257600080fd5b506100bd6102ba565b610123610347565b61013361012e610435565b61043f565b565b61013d610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561018e5761018b816040518060200160405280600081525060006104a3565b50565b61018b61011b565b61019e610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610219576102148383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600192506104a3915050565b505050565b61021461011b565b600061022b610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026b57610266610435565b905090565b61027361011b565b90565b61027e610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561018e5761018b816104ce565b60006102c4610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026b57610266610463565b60606103248383604051806060016040528060278152602001610a576027913961052f565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b61034f610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b6000610266610657565b3660008037600080366000845af43d6000803e80801561045e573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b6104ac8361067f565b6000825111806104b95750805b15610214576104c883836102ff565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6104f7610463565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161018b816106cc565b606073ffffffffffffffffffffffffffffffffffffffff84163b6105d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e74726163740000000000000000000000000000000000000000000000000000606482015260840161042c565b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516105fd91906109e9565b600060405180830381855af49150503d8060008114610638576040519150601f19603f3d011682016040523d82523d6000602084013e61063d565b606091505b509150915061064d8282866107d8565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610487565b6106888161082b565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b73ffffffffffffffffffffffffffffffffffffffff811661076f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161042c565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b606083156107e7575081610324565b8251156107f75782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161042c9190610a05565b73ffffffffffffffffffffffffffffffffffffffff81163b6108cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e747261637400000000000000000000000000000000000000606482015260840161042c565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610792565b803573ffffffffffffffffffffffffffffffffffffffff8116811461091a57600080fd5b919050565b60006020828403121561093157600080fd5b610324826108f6565b60008060006040848603121561094f57600080fd5b610958846108f6565b9250602084013567ffffffffffffffff8082111561097557600080fd5b818601915086601f83011261098957600080fd5b81358181111561099857600080fd5b8760208285010111156109aa57600080fd5b6020830194508093505050509250925092565b60005b838110156109d85781810151838201526020016109c0565b838111156104c85750506000910152565b600082516109fb8184602087016109bd565b9190910192915050565b6020815260008251806020840152610a248160408501602087016109bd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220b29caa54336b3ee836679675e9732ec5e526fb3f803cca2fe336cc3555aba62264736f6c634300080a0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564", + "deployedBytecode": "0x60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100a85780638f283970146100e6578063f851a440146101065761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61011b565b005b61006b61011b565b34801561008157600080fd5b5061006b61009036600461091f565b610135565b61006b6100a336600461093a565b610196565b3480156100b457600080fd5b506100bd610221565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100f257600080fd5b5061006b61010136600461091f565b610276565b34801561011257600080fd5b506100bd6102ba565b610123610347565b61013361012e610435565b61043f565b565b61013d610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561018e5761018b816040518060200160405280600081525060006104a3565b50565b61018b61011b565b61019e610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610219576102148383838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250600192506104a3915050565b505050565b61021461011b565b600061022b610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026b57610266610435565b905090565b61027361011b565b90565b61027e610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561018e5761018b816104ce565b60006102c4610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561026b57610266610463565b60606103248383604051806060016040528060278152602001610a576027913961052f565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b61034f610463565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604260248201527f5472616e73706172656e745570677261646561626c6550726f78793a2061646d60448201527f696e2063616e6e6f742066616c6c6261636b20746f2070726f7879207461726760648201527f6574000000000000000000000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b6000610266610657565b3660008037600080366000845af43d6000803e80801561045e573d6000f35b3d6000fd5b60007fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b5473ffffffffffffffffffffffffffffffffffffffff16919050565b6104ac8361067f565b6000825111806104b95750805b15610214576104c883836102ff565b50505050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f6104f7610463565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301520160405180910390a161018b816106cc565b606073ffffffffffffffffffffffffffffffffffffffff84163b6105d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f60448201527f6e74726163740000000000000000000000000000000000000000000000000000606482015260840161042c565b6000808573ffffffffffffffffffffffffffffffffffffffff16856040516105fd91906109e9565b600060405180830381855af49150503d8060008114610638576040519150601f19603f3d011682016040523d82523d6000602084013e61063d565b606091505b509150915061064d8282866107d8565b9695505050505050565b60007f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610487565b6106888161082b565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b73ffffffffffffffffffffffffffffffffffffffff811661076f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f455243313936373a206e65772061646d696e20697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161042c565b807fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9290921691909117905550565b606083156107e7575081610324565b8251156107f75782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161042c9190610a05565b73ffffffffffffffffffffffffffffffffffffffff81163b6108cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e747261637400000000000000000000000000000000000000606482015260840161042c565b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc610792565b803573ffffffffffffffffffffffffffffffffffffffff8116811461091a57600080fd5b919050565b60006020828403121561093157600080fd5b610324826108f6565b60008060006040848603121561094f57600080fd5b610958846108f6565b9250602084013567ffffffffffffffff8082111561097557600080fd5b818601915086601f83011261098957600080fd5b81358181111561099857600080fd5b8760208285010111156109aa57600080fd5b6020830194508093505050509250925092565b60005b838110156109d85781810151838201526020016109c0565b838111156104c85750506000910152565b600082516109fb8184602087016109bd565b9190910192915050565b6020815260008251806020840152610a248160408501602087016109bd565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220b29caa54336b3ee836679675e9732ec5e526fb3f803cca2fe336cc3555aba62264736f6c634300080a0033", + "devdoc": { + "details": "This contract implements a proxy that is upgradeable by an admin. To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector clashing], which can potentially be used in an attack, this contract uses the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two things that go hand in hand: 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if that call matches one of the admin functions exposed by the proxy itself. 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the implementation. If the admin tries to call a function on the implementation it will fail with an error that says \"admin cannot fallback to proxy target\". These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to call a function from the proxy implementation. Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way, you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.", + "kind": "dev", + "methods": { + "admin()": { + "details": "Returns the current admin. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`" + }, + "changeAdmin(address)": { + "details": "Changes the admin of the proxy. Emits an {AdminChanged} event. NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}." + }, + "constructor": { + "details": "Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}." + }, + "implementation()": { + "details": "Returns the current implementation. NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}. TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`" + }, + "upgradeTo(address)": { + "details": "Upgrade the implementation of the proxy. NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}." + }, + "upgradeToAndCall(address,bytes)": { + "details": "Upgrade the implementation of the proxy, and then call a function from the new implementation as specified by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the proxied contract. NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} diff --git a/external/deployments/rskTestnet/Permit2.json b/external/deployments/rskTestnet/Permit2.json new file mode 100644 index 000000000..311219e0f --- /dev/null +++ b/external/deployments/rskTestnet/Permit2.json @@ -0,0 +1,904 @@ +{ + "address": "0x000000000022d473030f116ddee9f6b43ac78ba3", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "AllowanceExpired", + "type": "error" + }, + { + "inputs": [], + "name": "ExcessiveInvalidation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "maxAmount", + "type": "uint256" + } + ], + "name": "InvalidAmount", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidContractSignature", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidNonce", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSignature", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSignatureLength", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSigner", + "type": "error" + }, + { + "inputs": [], + "name": "LengthMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "signatureDeadline", + "type": "uint256" + } + ], + "name": "SignatureExpired", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "Lockdown", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "newNonce", + "type": "uint48" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "oldNonce", + "type": "uint48" + } + ], + "name": "NonceInvalidation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "indexed": false, + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "name": "Permit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "word", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "mask", + "type": "uint256" + } + ], + "name": "UnorderedNonceInvalidation", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint48", + "name": "newNonce", + "type": "uint48" + } + ], + "name": "invalidateNonces", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "wordPos", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "mask", + "type": "uint256" + } + ], + "name": "invalidateUnorderedNonces", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "internalType": "struct IAllowanceTransfer.TokenSpenderPair[]", + "name": "approvals", + "type": "tuple[]" + } + ], + "name": "lockdown", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "nonceBitmap", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "internalType": "struct IAllowanceTransfer.PermitDetails[]", + "name": "details", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sigDeadline", + "type": "uint256" + } + ], + "internalType": "struct IAllowanceTransfer.PermitBatch", + "name": "permitBatch", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "uint48", + "name": "expiration", + "type": "uint48" + }, + { + "internalType": "uint48", + "name": "nonce", + "type": "uint48" + } + ], + "internalType": "struct IAllowanceTransfer.PermitDetails", + "name": "details", + "type": "tuple" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "sigDeadline", + "type": "uint256" + } + ], + "internalType": "struct IAllowanceTransfer.PermitSingle", + "name": "permitSingle", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails", + "name": "transferDetails", + "type": "tuple" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permitTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions[]", + "name": "permitted", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitBatchTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails[]", + "name": "transferDetails", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permitTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails", + "name": "transferDetails", + "type": "tuple" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "witness", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "witnessTypeString", + "type": "string" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permitWitnessTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions[]", + "name": "permitted", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitBatchTransferFrom", + "name": "permit", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "requestedAmount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.SignatureTransferDetails[]", + "name": "transferDetails", + "type": "tuple[]" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "witness", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "witnessTypeString", + "type": "string" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "permitWitnessTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "internalType": "struct IAllowanceTransfer.AllowanceTransferDetails[]", + "name": "transferDetails", + "type": "tuple[]" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint160", + "name": "amount", + "type": "uint160" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/external/deployments/rskTestnet/StabilityPool.json b/external/deployments/rskTestnet/StabilityPool.json new file mode 100644 index 000000000..597002159 --- /dev/null +++ b/external/deployments/rskTestnet/StabilityPool.json @@ -0,0 +1,1534 @@ +{ + "address": "0x176D218CaB70002CEF08e15271476187c37ed25f", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_oldImplementation", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_newImplementation", + "type": "address" + } + ], + "name": "ImplementationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newActivePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newBorrowerOperationsAddress", + "type": "address" + } + ], + "name": "BorrowerOperationsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newCommunityIssuanceAddress", + "type": "address" + } + ], + "name": "CommunityIssuanceAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newDefaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_S", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + } + ], + "name": "DepositSnapshotUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDLoss", + "type": "uint256" + } + ], + "name": "ETHGainWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint128", + "name": "_currentEpoch", + "type": "uint128" + } + ], + "name": "EpochUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "EtherSent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_kickbackRate", + "type": "uint256" + } + ], + "name": "FrontEndRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + } + ], + "name": "FrontEndSnapshotUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newFrontEndStake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "FrontEndStakeChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "FrontEndTagSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_epoch", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_scale", + "type": "uint128" + } + ], + "name": "G_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + } + ], + "name": "P_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_SOV", + "type": "uint256" + } + ], + "name": "SOVPaidToDepositor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_SOV", + "type": "uint256" + } + ], + "name": "SOVPaidToFrontEnd", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_S", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_epoch", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_scale", + "type": "uint128" + } + ], + "name": "S_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint128", + "name": "_currentScale", + "type": "uint128" + } + ], + "name": "ScaleUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newSortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newBalance", + "type": "uint256" + } + ], + "name": "StabilityPoolETHBalanceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newBalance", + "type": "uint256" + } + ], + "name": "StabilityPoolZUSDBalanceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newTroveManagerAddress", + "type": "address" + } + ], + "name": "TroveManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newDeposit", + "type": "uint256" + } + ], + "name": "UserDepositChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_zusdAmountRequested", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_dllrAmountReceived", + "type": "uint256" + } + ], + "name": "WithdrawFromSpAndConvertToDLLR", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newZUSDTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "P", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SCALE_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "borrowerOperations", + "outputs": [ + { + "internalType": "contract IBorrowerOperations", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "communityIssuance", + "outputs": [ + { + "internalType": "contract ICommunityIssuance", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentEpoch", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentScale", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "depositSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "S", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "P", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "G", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "scale", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "epoch", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "deposits", + "outputs": [ + { + "internalType": "uint256", + "name": "initialValue", + "type": "uint256" + }, + { + "internalType": "address", + "name": "frontEndTag", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "name": "epochToScaleToG", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "name": "epochToScaleToSum", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEndSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "S", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "P", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "G", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "scale", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "epoch", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEndStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEnds", + "outputs": [ + { + "internalType": "uint256", + "name": "kickbackRate", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "registered", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "getCompoundedFrontEndStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getCompoundedZUSDDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getDepositorETHGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getDepositorSOVGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getETH", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "getFrontEndSOVGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalZUSDDeposits", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastETHError_Offset", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastSOVError", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastZUSDLossError_Offset", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_debtToOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collToAdd", + "type": "uint256" + } + ], + "name": "offset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_frontEndTag", + "type": "address" + } + ], + "name": "provideToSP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "provideToSpFromDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "provideToSpFromDllrWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_kickbackRate", + "type": "uint256" + } + ], + "name": "registerFrontEnd", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_communityIssuanceAddress", + "type": "address" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_communityIssuanceAddress", + "type": "address" + } + ], + "name": "setCommunityIssuanceAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManager", + "outputs": [ + { + "internalType": "contract ITroveManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawETHGainToTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "withdrawFromSP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_zusdAmountRequested", + "type": "uint256" + } + ], + "name": "withdrawFromSpAndConvertToDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0xC959895CE6224dde0BdF7eb84519814dE23f2ee5", + "transactionIndex": 0, + "gasUsed": "5135892", + "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000040000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x26eb0b71917b7e14376847d8f22d8b657ac8a4a9756f9bace883ec60614ed674", + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748945, + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "address": "0xC959895CE6224dde0BdF7eb84519814dE23f2ee5", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x26eb0b71917b7e14376847d8f22d8b657ac8a4a9756f9bace883ec60614ed674" + } + ], + "blockNumber": 4748945, + "cumulativeGasUsed": "5135892", + "status": 1, + "byzantium": true + }, + "numDeployments": 4, + "bytecode": "0x60a06040523480156200001157600080fd5b5060405162004b8c38038062004b8c833981016040819052620000349162000123565b62000048336001600160e01b036200005e16565b60601b6001600160601b031916608052620001b2565b6001600160a01b038116620000905760405162461bcd60e51b8152600401620000879062000170565b60405180910390fd5b6001600160a01b038116620000ad6001600160e01b036200010216565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f29062000153565b6040519081900390209190915550565b600080604051620001139062000153565b6040519081900390205492915050565b60006020828403121562000135578081fd5b81516001600160a01b03811681146200014c578182fd5b9392505050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160601c6149b7620001d560003980610ad0528061189a52506149b76000f3fe6080604052600436106102ad5760003560e01c806382e0a57411610165578063b31ee965116100cc578063de13da3c11610085578063de13da3c14610788578063df9cd84f146107a8578063e49d3667146107c8578063ec9f7d46146107e8578063fc7e286d146107fd578063fce6b7341461082b578063fda0101a1461084b576102f8565b8063b31ee965146106f4578063bdaf37ea14610709578063c3a34a0e1461071e578063ce4b5bbe1461073e578063d733cfd014610753578063d7fb044314610773576102f8565b80639f0706701161011e5780639f07067014610665578063a20baee614610531578063a3f4df7e1461067a578063a4e59ac81461069c578063a7bfff97146106b1578063ae918754146106df576102f8565b806382e0a574146105d157806386da0824146105f1578063887105d314610611578063893d20e8146106265780638b8fbd921461063b57806395fb16bb14610650576102f8565b80633d83908a1161021457806372fe25aa116101cd57806372fe25aa14610531578063741bef1a14610546578063759b30341461055b578063766718081461057057806377553ad414610592578063795d26c3146105a75780637f7dde4a146105bc576102f8565b80633d83908a1461048757806340ed1afd1461049c578063556be101146104bc5780635d2de642146104dc5780635f788d65146104fc57806370f1b5721461051c576102f8565b80632199b66f116102665780632199b66f146103d257806328a0a04d146103f25780632e54bf9514610412578063335525ad14610432578063389e92a5146104525780633cc7422514610472576102f8565b80630fbfe38b146102fd57806312261ee71461031f57806313af40351461034a57806314f6c3be1461036a57806316b9d3c51461038c5780631bf43555146103bd576102f8565b366102f8576102ba61086b565b6009546102cd903463ffffffff6108a016565b6009819055604051600080516020614902833981519152916102ee91614847565b60405180910390a1005b600080fd5b34801561030957600080fd5b5061031d610318366004613d86565b6108ce565b005b34801561032b57600080fd5b50610334610ace565b6040516103419190613f43565b60405180910390f35b34801561035657600080fd5b5061031d610365366004613c1a565b610af2565b34801561037657600080fd5b5061037f610b36565b6040516103419190614847565b34801561039857600080fd5b506103ac6103a7366004613c1a565b610b3c565b604051610341959493929190614896565b3480156103c957600080fd5b5061037f610b77565b3480156103de57600080fd5b5061031d6103ed366004613c1a565b610b84565b3480156103fe57600080fd5b5061037f61040d366004613d52565b610c1b565b34801561041e57600080fd5b5061031d61042d366004613d86565b610c38565b34801561043e57600080fd5b5061031d61044d366004613ec9565b610c46565b34801561045e57600080fd5b5061037f61046d366004613c1a565b610ca9565b34801561047e57600080fd5b50610334610d51565b34801561049357600080fd5b50610334610d60565b3480156104a857600080fd5b5061037f6104b7366004613c1a565b610d6f565b3480156104c857600080fd5b5061031d6104d7366004613d86565b610e0c565b3480156104e857600080fd5b5061037f6104f7366004613c1a565b610e84565b34801561050857600080fd5b5061031d610517366004613db6565b610e96565b34801561052857600080fd5b5061037f610ea0565b34801561053d57600080fd5b5061037f610ea6565b34801561055257600080fd5b50610334610eb2565b34801561056757600080fd5b5061037f610ec1565b34801561057c57600080fd5b50610585610ece565b6040516103419190614833565b34801561059e57600080fd5b50610334610ee4565b3480156105b357600080fd5b5061037f610ef3565b3480156105c857600080fd5b50610334611012565b3480156105dd57600080fd5b5061037f6105ec366004613d52565b611021565b3480156105fd57600080fd5b506103ac61060c366004613c1a565b61103e565b34801561061d57600080fd5b5061037f611079565b34801561063257600080fd5b50610334611148565b34801561064757600080fd5b5061037f611167565b34801561065c57600080fd5b5061033461116d565b34801561067157600080fd5b5061033461117c565b34801561068657600080fd5b5061068f61118b565b6040516103419190614060565b3480156106a857600080fd5b506105856111b4565b3480156106bd57600080fd5b506106d16106cc366004613c1a565b6111c3565b604051610341929190614867565b3480156106eb57600080fd5b506103346111df565b34801561070057600080fd5b5061037f6111ee565b34801561071557600080fd5b5061037f6111f4565b34801561072a57600080fd5b5061031d610739366004613dda565b6111fa565b34801561074a57600080fd5b5061037f61129e565b34801561075f57600080fd5b5061031d61076e366004613c8a565b6112a6565b34801561077f57600080fd5b5061037f611538565b34801561079457600080fd5b5061037f6107a3366004613c1a565b61153e565b3480156107b457600080fd5b5061037f6107c3366004613c1a565b611642565b3480156107d457600080fd5b5061037f6107e3366004613c1a565b6116df565b3480156107f457600080fd5b506103346117dc565b34801561080957600080fd5b5061081d610818366004613c1a565b6117eb565b604051610341929190614850565b34801561083757600080fd5b5061031d610846366004613e10565b61180d565b34801561085757600080fd5b5061031d610866366004613c52565b6118cd565b6000546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614258565b60405180910390fd5b565b6000828201838110156108c55760405162461bcd60e51b815260040161089590614168565b90505b92915050565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561091e57600080fd5b505afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613c36565b905060006109648330611b13565b60065460405163095ea7b360e01b81529192506001600160a01b03169063095ea7b3906109979085908590600401613fdf565b602060405180830381600087803b1580156109b157600080fd5b505af11580156109c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e99190613d32565b610a055760405162461bcd60e51b8152600401610895906145ef565b60065460405163438b1b4b60e01b81526001600160a01b038481169263438b1b4b92610a3b929091169085903390600401614019565b602060405180830381600087803b158015610a5557600080fd5b505af1158015610a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8d9190613d9e565b507f2b0fbec1c4e7e30517f196a714775ffe72770d2348f5d586854bb3c0fdf41df8338483604051610ac193929190613ff8565b60405180910390a1505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b610afa611148565b6001600160a01b0316336001600160a01b031614610b2a5760405162461bcd60e51b81526004016108959061451d565b610b3381611cde565b50565b60095490565b600f602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6809c2007651b250000081565b610b8c611148565b6001600160a01b0316336001600160a01b031614610bbc5760405162461bcd60e51b81526004016108959061451d565b610bc581611d69565b600880546001600160a01b0319166001600160a01b0383161790556040517f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac681190610c10908390613f43565b60405180910390a150565b601260209081526000928352604080842090915290825290205481565b610c428133611b13565b5050565b610c4e611dae565b600a54801580610c5c575082155b15610c675750610c42565b600854610c7c906001600160a01b0316611dd8565b600080610c8a848685611e65565b91509150610c988282611f5e565b610ca2848661225f565b5050505050565b6001600160a01b0381166000908152600b602052604081205480610cd1576000915050610d4c565b610cd9613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612395565b93505050505b919050565b6001546001600160a01b031681565b6005546001600160a01b031681565b6001600160a01b0381166000908152600b602052604081205480610d97576000915050610d4c565b610d9f613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b610e1533612582565b610e1e336125be565b610e27816125f5565b336000818152600d6020526040908190208381556001908101805460ff19169091179055517f19bc932fb9e16a8b5a1e41be9f4c2de59d5ddd7567b8b81405f532ca00a9880e90610e79908490614847565b60405180910390a250565b600e6020526000908152604090205481565b610c42828261261d565b60145481565b670de0b6b3a764000081565b6002546001600160a01b031681565b6801158e460913d0000081565b601154600160801b90046001600160801b031681565b6004546001600160a01b031681565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3757600080fd5b505afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b505afa158015610fd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff99190613d9e565b905061100b828263ffffffff6108a016565b9250505090565b6000546001600160a01b031681565b601360209081526000928352604080842090915290825290205481565b600c602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156110be57600080fd5b505afa1580156110d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f69190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b60008060405161115790613f26565b6040519081900390205492915050565b60105481565b6008546001600160a01b031681565b6003546001600160a01b031681565b6040518060400160405280600d81526020016c14dd18589a5b1a5d1e541bdbdb609a1b81525081565b6011546001600160801b031681565b600d602052600090815260409020805460019091015460ff1682565b6007546001600160a01b031681565b60165481565b600a5490565b600480546040805163e9fc346160e01b8152905160009361128c936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561124057600080fd5b505afa158015611254573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112789190613c36565b60065485906001600160a01b0316856127c0565b905061129981600061261d565b505050565b633b9aca0081565b6112ae611148565b6001600160a01b0316336001600160a01b0316146112de5760405162461bcd60e51b81526004016108959061451d565b6112e788611d69565b6112f087611d69565b6112f986611d69565b61130285611d69565b61130b84611d69565b61131483611d69565b61131d82611d69565b61132681611d69565b670de0b6b3a7640000601055600380546001600160a01b03199081166001600160a01b038b8116919091179092556004805482168a8416179055600580548216898416179055600080548216888416179055600680548216878416179055600780548216868416179055600280548216858416179055600880549091169183169190911790556040517f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed985906113dc908990613f43565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a5678866040516114139190613f43565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828560405161144a9190613f43565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d846040516114819190613f43565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800836040516114b89190613f43565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264826040516114ef9190613f43565b60405180910390a17f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac6811816040516115269190613f43565b60405180910390a15050505050505050565b60155481565b6001600160a01b0381166000908152600e602052604081205480611566576000915050610d4c565b6001600160a01b0383166000908152600d602052604081205490611598670de0b6b3a76400008363ffffffff612a6516565b90506115a2613b64565b506001600160a01b0385166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b869063ffffffff612b3316565b9063ffffffff612b6d16565b979650505050505050565b6001600160a01b0381166000908152600e60205260408120548061166a576000915050610d4c565b611672613b64565b506001600160a01b0383166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b6001600160a01b0381166000908152600b602052604081205480611707576000915050610d4c565b6001600160a01b038084166000908152600b602052604081206001015490911690811561174c576001600160a01b0382166000908152600d6020526040902054611756565b670de0b6b3a76400005b9050611760613b64565b506001600160a01b0385166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b6006546001600160a01b031681565b600b60205260009081526040902080546001909101546001600160a01b031682565b600480546040805163e9fc346160e01b815290516000936118c0936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561185357600080fd5b505afa158015611867573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188b9190613c36565b6006546001600160a01b0316867f00000000000000000000000000000000000000000000000000000000000000008787612baf565b9050610ca281600061261d565b336000908152600b60205260409020546118e681612dfc565b6118ef33612e1c565b6118f833612ebb565b6008546001600160a01b031661190d81611dd8565b600061191833610ca9565b9050600061192533610d6f565b90506000611939858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b039091169061196790869083612ee8565b600061197282611642565b90508061197f838261305d565b826001600160a01b031660008051602061496283398151915282336040516119a8929190614850565b60405180910390a26119ba33866131a5565b336001600160a01b031660008051602061494283398151915287866040516119e392919061403c565b60405180910390a2336001600160a01b031660008051602061492283398151915286604051611a129190614847565b60405180910390a2600954611a2d908763ffffffff612a6516565b600981905560405160008051602061490283398151915291611a4e91614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123387604051611a87929190613fdf565b60405180910390a1600460009054906101000a90046001600160a01b03166001600160a01b031663ea9638bf87338d8d6040518563ffffffff1660e01b8152600401611ad593929190613f57565b6000604051808303818588803b158015611aee57600080fd5b505af1158015611b02573d6000803e3d6000fd5b505050505050505050505050505050565b60006001600160a01b038216611b3b5760405162461bcd60e51b815260040161089590614434565b8215611b4957611b4961331a565b336000908152600b6020526040902054611b6281612dfc565b6008546001600160a01b0316611b7781611dd8565b6000611b8233610ca9565b90506000611b8f33610d6f565b90506000611b9d8883613551565b90506000611bb1868463ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b0390911690611bdf90879083612ee8565b6000611bea82611642565b90506000611bfe828663ffffffff612a6516565b9050611c0a838261305d565b826001600160a01b03166000805160206149628339815191528233604051611c33929190614850565b60405180910390a2611c458b86613567565b6000611c57878763ffffffff612a6516565b9050611c6333826131a5565b336001600160a01b031660008051602061492283398151915282604051611c8a9190614847565b60405180910390a2336001600160a01b03166000805160206149428339815191528987604051611cbb92919061403c565b60405180910390a2611ccd88336135e0565b50939b9a5050505050505050505050565b6001600160a01b038116611d045760405162461bcd60e51b81526004016108959061429f565b806001600160a01b0316611d16611148565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611d5990613f26565b6040519081900390209190915550565b6001600160a01b038116611d8f5760405162461bcd60e51b8152600401610895906142e1565b803b80610c425760405162461bcd60e51b815260040161089590614646565b6005546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614369565b600a54604051636cbdcf4760e01b81526000916001600160a01b03841691636cbdcf4791611e0891600401614847565b602060405180830381600087803b158015611e2257600080fd5b505af1158015611e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5a9190613d9e565b9050610c428161370f565b6000806000611e97601554611e8b670de0b6b3a764000089612b3390919063ffffffff16565b9063ffffffff6108a016565b905083851115611ea357fe5b83851415611ec0576000601655670de0b6b3a76400009150611f20565b601654600090611eee90611ee288670de0b6b3a764000063ffffffff612b3316565b9063ffffffff612a6516565b9050611f056001611e8b838863ffffffff612b6d16565b9250611f1b81611ee2858863ffffffff612b3316565b601655505b611f30818563ffffffff612b6d16565b9250611f52611f45848663ffffffff612b3316565b829063ffffffff612a6516565b60155550935093915050565b6010546000670de0b6b3a7640000831115611f7557fe5b6000611f8f670de0b6b3a76400008563ffffffff612a6516565b6011546001600160801b03600160801b820481166000818152601260209081526040808320949095168083529390529283205493945090929091611fd38988612b33565b90506000611fe7838363ffffffff6108a016565b6001600160801b038086166000908152601260209081526040808320938a168352929052819020829055519091507fe12e2cd2c9afa8069203ca07e7eff1edce4a075686d0736a8e7e0d593597b2079061204690839087908990614877565b60405180910390a18561211f5761206d6001600160801b038516600163ffffffff61382016565b601180546001600160801b03908116600160801b938216840217918290556040517fb50f0f59e7cb5b421dc77581c3a9919e3806e076e5fa78a874c3f120cb7d874d936120be930490911690614833565b60405180910390a1601180546001600160801b03191690556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9061210790600090614833565b60405180910390a1670de0b6b3a7640000965061220c565b633b9aca00612140670de0b6b3a764000061162b8b8a63ffffffff612b3316565b10156121ed57612176670de0b6b3a764000061162b633b9aca0061216a8c8b63ffffffff612b3316565b9063ffffffff612b3316565b96506121926001600160801b038616600163ffffffff61382016565b601180546001600160801b0319166001600160801b0392831617908190556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe926121e0921690614833565b60405180910390a161220c565b612209670de0b6b3a764000061162b8a8963ffffffff612b3316565b96505b6000871161221657fe5b60108790556040517fc1a9618cb59ebca77cbdbc2949f126823c407ff13edb285fd0262519a9c18e8c9061224b908990614847565b60405180910390a150505050505050505050565b60005460405163121cbc4d60e11b81526001600160a01b03909116908190632439789a90612291908590600401614847565b600060405180830381600087803b1580156122ab57600080fd5b505af11580156122bf573d6000803e3d6000fd5b505050506122cc82613851565b600654604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906122fe9030908690600401613fdf565b600060405180830381600087803b15801561231857600080fd5b505af115801561232c573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b03841692506364a197f3915061235e9030908790600401613fdf565b600060405180830381600087803b15801561237857600080fd5b505af115801561238c573d6000803e3d6000fd5b50505050505050565b6080810151606082015182516020808501516001600160801b038086166000908152601284526040808220928716825291909352822054919493929185906123e3908463ffffffff612a6516565b6001600160801b0380871660009081526012602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b6001600160801b031681526020810191909152604001600020549063ffffffff612b6d16565b90506000612478670de0b6b3a764000061162b868161246b888863ffffffff6108a016565b8f9063ffffffff612b3316565b9a9950505050505050505050565b6020810151606082015160808301516011546000939291906001600160801b03600160801b909104811690821610156124c557600093505050506108c8565b60115460009081906124e6906001600160801b03168563ffffffff6138ab16565b90506001600160801b0381166125165761250f8561162b6010548b612b3390919063ffffffff16565b915061254e565b806001600160801b0316600114156125495761250f633b9aca0061162b8761162b6010548d612b3390919063ffffffff16565b600091505b61256288633b9aca0063ffffffff612b6d16565b821015612577576000955050505050506108c8565b509695505050505050565b6001600160a01b0381166000908152600d602052604090206001015460ff1615610b335760405162461bcd60e51b81526004016108959061454e565b6001600160a01b0381166000908152600b60205260409020548015610c425760405162461bcd60e51b8152600401610895906145a7565b670de0b6b3a7640000811115610b335760405162461bcd60e51b815260040161089590614484565b612626816138e5565b61262f33612582565b61263882613932565b336000908152600b60205260409020546008546001600160a01b031661265d81611dd8565b8161266c5761266c3384613952565b600061267733610ca9565b9050600061268433610d6f565b90506000612698858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b03909116906126c690869083612ee8565b60006126d182611642565b905060006126e5828b63ffffffff6108a016565b90506126f1838261305d565b826001600160a01b0316600080516020614962833981519152823360405161271a929190614850565b60405180910390a261272c338b6139ac565b600061273e868c63ffffffff6108a016565b905061274a33826131a5565b336001600160a01b0316600080516020614922833981519152826040516127719190614847565b60405180910390a2336001600160a01b031660008051602061494283398151915288876040516127a292919061403c565b60405180910390a26127b387613a60565b5050505050505050505050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b1580156127fc57600080fd5b505afa158015612810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128349190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016128649190613f43565b60206040518083038186803b15801561287c57600080fd5b505afa158015612890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b49190613d9e565b9050306001600160a01b03831663605629d633838a89356128db60408c0160208d01613eea565b8b604001358c606001356040518863ffffffff1660e01b81526004016129079796959493929190613f9e565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b50505050866129ba83856001600160a01b03166370a08231856040518263ffffffff1660e01b815260040161296a9190613f43565b60206040518083038186803b15801561298257600080fd5b505afa158015612996573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee29190613d9e565b146129d75760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390612a079089908b903390600401614019565b602060405180830381600087803b158015612a2157600080fd5b505af1158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613d9e565b98975050505050505050565b60006108c583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a6a565b608081015160608201516040808401516020808601516001600160801b03808716600090815260138452858120918716815292529281205490949392908590612af6908463ffffffff612a6516565b6001600160801b0380871660009081526013602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b600082612b42575060006108c8565b82820282848281612b4f57fe5b04146108c55760405162461bcd60e51b8152600401610895906143f3565b60006108c583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613a96565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015612beb57600080fd5b505afa158015612bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c239190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612c539190613f43565b60206040518083038186803b158015612c6b57600080fd5b505afa158015612c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca39190613d9e565b87516020015190915030906001600160a01b0388166330f28b7a8a612cc88585613acd565b338b8b6040518663ffffffff1660e01b8152600401612ceb9594939291906147c2565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b5050505080612d4e84866001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161296a9190613f43565b14612d6b5760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390612d9b908d9085903390600401614019565b602060405180830381600087803b158015612db557600080fd5b505af1158015612dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ded9190613d9e565b9b9a5050505050505050505050565b60008111610b335760405162461bcd60e51b81526004016108959061467b565b6005546040516321e3780160e01b81526001600160a01b03909116906321e3780190612e4c908490600401613f43565b60206040518083038186803b158015612e6457600080fd5b505afa158015612e78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9c9190613d9e565b600114610b335760405162461bcd60e51b8152600401610895906140b3565b6000612ec682610ca9565b905060008111610c425760405162461bcd60e51b815260040161089590614318565b6001600160a01b03811615612fa8576000612f028261153e565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612f339085908590600401613fdf565b600060405180830381600087803b158015612f4d57600080fd5b505af1158015612f61573d6000803e3d6000fd5b50505050816001600160a01b03167f732e331072fe280a520929e5f2cc76c223389ff57d32a4e278cfded03e6f1caa82604051612f9e9190614847565b60405180910390a2505b6000612fb3836116df565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612fe49086908590600401613fdf565b600060405180830381600087803b158015612ffe57600080fd5b505af1158015613012573d6000803e3d6000fd5b50505050826001600160a01b03167fe9ac2dcd83e719358f1dc0c5c80491937f67d4ec61ef62c262bbe3b78578f92a8260405161304f9190614847565b60405180910390a250505050565b6001600160a01b0382166000908152600e60205260409020819055806130e8576001600160a01b0382166000818152600f60205260408082208281556001810183905560028101839055600301829055517fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e45916130db91819061403c565b60405180910390a2610c42565b6011546010546001600160801b03600160801b80840482166000818152601360209081526040808320978616808452978252808320546001600160a01b038b16808552600f90935292819020600181018890556002810184905560030180546001600160801b0319168917909616948402949094179094559151909392907fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e4590613195908590859061403c565b60405180910390a2505050505050565b6001600160a01b0382166000908152600b6020526040902081905580613243576001600160a01b0382166000818152600b60209081526040808320600190810180546001600160a01b0319169055600c909252808320838155918201839055600282018390556003909101829055517f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a916130db918190819061404a565b6011546010546001600160801b03600160801b8084048216600081815260126020908152604080832097861680845297825280832054848452601383528184208985528352818420546001600160a01b038c16808652600c90945293829020600181018990558181556002810185905560030180546001600160801b0319168a1790971695850295909517909555935191949390917f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a906133099086908690869061404a565b60405180910390a250505050505050565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561336057600080fd5b505af1158015613374573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133989190613d9e565b90506000600760009054906101000a90046001600160a01b03166001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ea57600080fd5b505afa1580156133fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134229190613c36565b600554604051630d293c7160e41b81529192506000916001600160a01b039091169063d293c7109061345a9085908790600401613fdf565b60206040518083038186803b15801561347257600080fd5b505afa158015613486573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134aa9190613d9e565b9050600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156134fa57600080fd5b505afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135329190613d9e565b8110156112995760405162461bcd60e51b815260040161089590614758565b600081831061356057816108c5565b5090919050565b8061357157610c42565b600654604051631062c15f60e11b81526001600160a01b03909116906320c582be906135a590309086908690600401613f7a565b600060405180830381600087803b1580156135bf57600080fd5b505af11580156135d3573d6000803e3d6000fd5b50505050610c4281613851565b6001600160a01b0381166136065760405162461bcd60e51b81526004016108959061419f565b8161361057610c42565b600954600090613626908463ffffffff612a6516565b9050806009819055506000805160206149028339815191528160405161364c9190614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123384604051613685929190613fdf565b60405180910390a16000336001600160a01b0316846040516136a690613f23565b60006040518083038185875af1925050503d80600081146136e3576040519150601f19603f3d011682016040523d82523d6000602084013e6136e8565b606091505b50509050806137095760405162461bcd60e51b8152600401610895906143b2565b50505050565b600a5480158061371d575081155b156137285750610b33565b60006137348383613aff565b9050600061374d60105483612b3390919063ffffffff16565b6011546001600160801b03600160801b820481166000908152601360209081526040808320939094168252919091522054909150613791908263ffffffff6108a016565b601180546001600160801b03600160801b80830482166000908152601360208181526040808420968616845295815285832097909755945491820483168082529486528381209190921680835294528190205490517f2d6127771b164a9cc8827d24b5955db2a77e7a81dac389107ebb8bce9fb64968936138129391614877565b60405180910390a150505050565b60008282016001600160801b0380851690821610156108c55760405162461bcd60e51b815260040161089590614713565b600a54600090613867908363ffffffff612a6516565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c78160405161389f9190614847565b60405180910390a15050565b6000826001600160801b0316826001600160801b031611156138df5760405162461bcd60e51b8152600401610895906146cb565b50900390565b6001600160a01b0381166000908152600d602052604090206001015460ff168061391657506001600160a01b038116155b610b335760405162461bcd60e51b8152600401610895906141ec565b60008111610b335760405162461bcd60e51b8152600401610895906144d7565b6001600160a01b038281166000818152600b602052604080822060010180546001600160a01b0319169486169485179055517f094c08e96a8890877a8390b4f967180a7507ad8622244d05fcd0f9f8e086564e9190a35050565b600654604051632ee65eeb60e21b81526001600160a01b039091169063bb997bac906139e090859030908690600401613f7a565b600060405180830381600087803b1580156139fa57600080fd5b505af1158015613a0e573d6000803e3d6000fd5b5050600a5460009250613a2891508363ffffffff6108a016565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c781604051610ac19190614847565b610b3381336135e0565b60008184841115613a8e5760405162461bcd60e51b81526004016108959190614060565b505050900390565b60008183613ab75760405162461bcd60e51b81526004016108959190614060565b506000838581613ac357fe5b0495945050505050565b613ad5613ba5565b613add613ba5565b5050604080518082019091526001600160a01b03929092168252602082015290565b600080613b23601454611e8b670de0b6b3a764000087612b3390919063ffffffff16565b90506000613b37828563ffffffff612b6d16565b9050613b59613b4c828663ffffffff612b3316565b839063ffffffff612a6516565b601455949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b604080518082019091526000808252602082015290565b60008083601f840112613bcd578182fd5b50813567ffffffffffffffff811115613be4578182fd5b602083019150836020828501011115613bfc57600080fd5b9250929050565b80356001600160801b03811681146108c857600080fd5b600060208284031215613c2b578081fd5b81356108c5816148ec565b600060208284031215613c47578081fd5b81516108c5816148ec565b60008060408385031215613c64578081fd5b8235613c6f816148ec565b91506020830135613c7f816148ec565b809150509250929050565b600080600080600080600080610100898b031215613ca6578384fd5b8835613cb1816148ec565b97506020890135613cc1816148ec565b96506040890135613cd1816148ec565b95506060890135613ce1816148ec565b94506080890135613cf1816148ec565b935060a0890135613d01816148ec565b925060c0890135613d11816148ec565b915060e0890135613d21816148ec565b809150509295985092959890939650565b600060208284031215613d43578081fd5b815180151581146108c5578182fd5b60008060408385031215613d64578182fd5b613d6e8484613c03565b9150613d7d8460208501613c03565b90509250929050565b600060208284031215613d97578081fd5b5035919050565b600060208284031215613daf578081fd5b5051919050565b60008060408385031215613dc8578182fd5b823591506020830135613c7f816148ec565b60008082840360a0811215613ded578283fd5b833592506080601f1982011215613e02578182fd5b506020830190509250929050565b60008060008084860360c0811215613e26578485fd5b85359450601f1981016080811215613e3c578485fd5b613e4660606148c5565b91506040811215613e55578485fd5b50613e6060406148c5565b6020870135613e6e816148ec565b80825250604087013560208201528082525060608601356020820152608086013560408201528093505060a085013567ffffffffffffffff811115613eb1578283fd5b613ebd87828801613bbc565b95989497509550505050565b60008060408385031215613edb578182fd5b50508035926020909101359150565b600060208284031215613efb578081fd5b813560ff811681146108c5578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b6000602080835283518082850152825b8181101561408c57858101830151858201604001528201614070565b8181111561409d5783604083870101525b50601f01601f1916929092016040019392505050565b60208082526046908201527f53746162696c697479506f6f6c3a2063616c6c6572206d75737420686176652060408201527f616e206163746976652074726f766520746f207769746864726177204554484760608201526561696e20746f60d01b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252602d908201527f53503a3a5f73656e644554484761696e546f3a205f726563656976657220697360408201526c207a65726f206164647265737360981b606082015260800190565b60208082526046908201527f53746162696c697479506f6f6c3a20546167206d75737420626520612072656760408201527f697374657265642066726f6e7420656e642c206f7220746865207a65726f206160608201526564647265737360d01b608082015260a00190565b60208082526027908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f74204163746040820152661a5d99541bdbdb60ca1b606082015260800190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526031908201527f53746162696c697479506f6f6c3a2063616c6c6572206d7573742068617665206040820152703737b716bd32b9379022aa241023b0b4b760791b606082015260800190565b60208082526029908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f742054726f6040820152683b32a6b0b730b3b2b960b91b606082015260800190565b60208082526021908201527f53746162696c697479506f6f6c3a2073656e64696e6720455448206661696c656040820152601960fa1b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526030908201527f53503a3a5f776974686472617746726f6d5370546f3a205f726563656976657260408201526f206973207a65726f206164647265737360801b606082015260800190565b60208082526033908201527f53746162696c697479506f6f6c3a204b69636b6261636b2072617465206d75736040820152727420626520696e2072616e6765205b302c315d60681b606082015260800190565b60208082526026908201527f53746162696c697479506f6f6c3a20416d6f756e74206d757374206265206e6f6040820152656e2d7a65726f60d01b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526039908201527f53746162696c697479506f6f6c3a206d757374206e6f7420616c72656164792060408201527818994818481c9959da5cdd195c995908199c9bdb9d08195b99603a1b606082015260800190565b60208082526028908201527f53746162696c697479506f6f6c3a2055736572206d7573742068617665206e6f6040820152670819195c1bdcda5d60c21b606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526030908201527f53746162696c697479506f6f6c3a2055736572206d757374206861766520612060408201526f1b9bdb8b5e995c9bc819195c1bdcda5d60821b606082015260800190565b60208082526028908201527f4c697175697479536166654d6174683132383a207375627472616374696f6e206040820152676f766572666c6f7760c01b606082015260800190565b60208082526025908201527f4c697175697479536166654d6174683132383a206164646974696f6e206f766560408201526472666c6f7760d81b606082015260800190565b60208082526044908201527f53746162696c697479506f6f6c3a2043616e6e6f74207769746864726177207760408201527f68696c65207468657265206172652074726f766573207769746820494352203c6060820152631026a1a960e11b608082015260a00190565b60006101006147d2838951613f0b565b60208801516040840152604088015160608401526147f36080840188613f0b565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b6001600160801b0391909116815260200190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9182521515602082015260400190565b9283526001600160801b03918216602084015216604082015260600190565b948552602085019390935260408401919091526001600160801b03908116606084015216608082015260a00190565b60405181810167ffffffffffffffff811182821017156148e457600080fd5b604052919050565b6001600160a01b0381168114610b3357600080fdfeceb6d671277d4354fd29977ada70695fbd93a16612abf765d6b0e25c28dc6db3bce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c951457222ebca92c335c9c86e2baa1cc0e40ffaa9084a51452980d5ba8dec2f6399920012339b5a3368d3a04b8606ce412c46ed92b7dcd8602d41fc8862cb8f25a2646970667358221220b12079f570461c3902a02d925635ecefb92e70f4556abddd99509e1ecfffdece64736f6c634300060b0033", + "deployedBytecode": "0x6080604052600436106102ad5760003560e01c806382e0a57411610165578063b31ee965116100cc578063de13da3c11610085578063de13da3c14610788578063df9cd84f146107a8578063e49d3667146107c8578063ec9f7d46146107e8578063fc7e286d146107fd578063fce6b7341461082b578063fda0101a1461084b576102f8565b8063b31ee965146106f4578063bdaf37ea14610709578063c3a34a0e1461071e578063ce4b5bbe1461073e578063d733cfd014610753578063d7fb044314610773576102f8565b80639f0706701161011e5780639f07067014610665578063a20baee614610531578063a3f4df7e1461067a578063a4e59ac81461069c578063a7bfff97146106b1578063ae918754146106df576102f8565b806382e0a574146105d157806386da0824146105f1578063887105d314610611578063893d20e8146106265780638b8fbd921461063b57806395fb16bb14610650576102f8565b80633d83908a1161021457806372fe25aa116101cd57806372fe25aa14610531578063741bef1a14610546578063759b30341461055b578063766718081461057057806377553ad414610592578063795d26c3146105a75780637f7dde4a146105bc576102f8565b80633d83908a1461048757806340ed1afd1461049c578063556be101146104bc5780635d2de642146104dc5780635f788d65146104fc57806370f1b5721461051c576102f8565b80632199b66f116102665780632199b66f146103d257806328a0a04d146103f25780632e54bf9514610412578063335525ad14610432578063389e92a5146104525780633cc7422514610472576102f8565b80630fbfe38b146102fd57806312261ee71461031f57806313af40351461034a57806314f6c3be1461036a57806316b9d3c51461038c5780631bf43555146103bd576102f8565b366102f8576102ba61086b565b6009546102cd903463ffffffff6108a016565b6009819055604051600080516020614902833981519152916102ee91614847565b60405180910390a1005b600080fd5b34801561030957600080fd5b5061031d610318366004613d86565b6108ce565b005b34801561032b57600080fd5b50610334610ace565b6040516103419190613f43565b60405180910390f35b34801561035657600080fd5b5061031d610365366004613c1a565b610af2565b34801561037657600080fd5b5061037f610b36565b6040516103419190614847565b34801561039857600080fd5b506103ac6103a7366004613c1a565b610b3c565b604051610341959493929190614896565b3480156103c957600080fd5b5061037f610b77565b3480156103de57600080fd5b5061031d6103ed366004613c1a565b610b84565b3480156103fe57600080fd5b5061037f61040d366004613d52565b610c1b565b34801561041e57600080fd5b5061031d61042d366004613d86565b610c38565b34801561043e57600080fd5b5061031d61044d366004613ec9565b610c46565b34801561045e57600080fd5b5061037f61046d366004613c1a565b610ca9565b34801561047e57600080fd5b50610334610d51565b34801561049357600080fd5b50610334610d60565b3480156104a857600080fd5b5061037f6104b7366004613c1a565b610d6f565b3480156104c857600080fd5b5061031d6104d7366004613d86565b610e0c565b3480156104e857600080fd5b5061037f6104f7366004613c1a565b610e84565b34801561050857600080fd5b5061031d610517366004613db6565b610e96565b34801561052857600080fd5b5061037f610ea0565b34801561053d57600080fd5b5061037f610ea6565b34801561055257600080fd5b50610334610eb2565b34801561056757600080fd5b5061037f610ec1565b34801561057c57600080fd5b50610585610ece565b6040516103419190614833565b34801561059e57600080fd5b50610334610ee4565b3480156105b357600080fd5b5061037f610ef3565b3480156105c857600080fd5b50610334611012565b3480156105dd57600080fd5b5061037f6105ec366004613d52565b611021565b3480156105fd57600080fd5b506103ac61060c366004613c1a565b61103e565b34801561061d57600080fd5b5061037f611079565b34801561063257600080fd5b50610334611148565b34801561064757600080fd5b5061037f611167565b34801561065c57600080fd5b5061033461116d565b34801561067157600080fd5b5061033461117c565b34801561068657600080fd5b5061068f61118b565b6040516103419190614060565b3480156106a857600080fd5b506105856111b4565b3480156106bd57600080fd5b506106d16106cc366004613c1a565b6111c3565b604051610341929190614867565b3480156106eb57600080fd5b506103346111df565b34801561070057600080fd5b5061037f6111ee565b34801561071557600080fd5b5061037f6111f4565b34801561072a57600080fd5b5061031d610739366004613dda565b6111fa565b34801561074a57600080fd5b5061037f61129e565b34801561075f57600080fd5b5061031d61076e366004613c8a565b6112a6565b34801561077f57600080fd5b5061037f611538565b34801561079457600080fd5b5061037f6107a3366004613c1a565b61153e565b3480156107b457600080fd5b5061037f6107c3366004613c1a565b611642565b3480156107d457600080fd5b5061037f6107e3366004613c1a565b6116df565b3480156107f457600080fd5b506103346117dc565b34801561080957600080fd5b5061081d610818366004613c1a565b6117eb565b604051610341929190614850565b34801561083757600080fd5b5061031d610846366004613e10565b61180d565b34801561085757600080fd5b5061031d610866366004613c52565b6118cd565b6000546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614258565b60405180910390fd5b565b6000828201838110156108c55760405162461bcd60e51b815260040161089590614168565b90505b92915050565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561091e57600080fd5b505afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613c36565b905060006109648330611b13565b60065460405163095ea7b360e01b81529192506001600160a01b03169063095ea7b3906109979085908590600401613fdf565b602060405180830381600087803b1580156109b157600080fd5b505af11580156109c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e99190613d32565b610a055760405162461bcd60e51b8152600401610895906145ef565b60065460405163438b1b4b60e01b81526001600160a01b038481169263438b1b4b92610a3b929091169085903390600401614019565b602060405180830381600087803b158015610a5557600080fd5b505af1158015610a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8d9190613d9e565b507f2b0fbec1c4e7e30517f196a714775ffe72770d2348f5d586854bb3c0fdf41df8338483604051610ac193929190613ff8565b60405180910390a1505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b610afa611148565b6001600160a01b0316336001600160a01b031614610b2a5760405162461bcd60e51b81526004016108959061451d565b610b3381611cde565b50565b60095490565b600f602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6809c2007651b250000081565b610b8c611148565b6001600160a01b0316336001600160a01b031614610bbc5760405162461bcd60e51b81526004016108959061451d565b610bc581611d69565b600880546001600160a01b0319166001600160a01b0383161790556040517f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac681190610c10908390613f43565b60405180910390a150565b601260209081526000928352604080842090915290825290205481565b610c428133611b13565b5050565b610c4e611dae565b600a54801580610c5c575082155b15610c675750610c42565b600854610c7c906001600160a01b0316611dd8565b600080610c8a848685611e65565b91509150610c988282611f5e565b610ca2848661225f565b5050505050565b6001600160a01b0381166000908152600b602052604081205480610cd1576000915050610d4c565b610cd9613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612395565b93505050505b919050565b6001546001600160a01b031681565b6005546001600160a01b031681565b6001600160a01b0381166000908152600b602052604081205480610d97576000915050610d4c565b610d9f613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b610e1533612582565b610e1e336125be565b610e27816125f5565b336000818152600d6020526040908190208381556001908101805460ff19169091179055517f19bc932fb9e16a8b5a1e41be9f4c2de59d5ddd7567b8b81405f532ca00a9880e90610e79908490614847565b60405180910390a250565b600e6020526000908152604090205481565b610c42828261261d565b60145481565b670de0b6b3a764000081565b6002546001600160a01b031681565b6801158e460913d0000081565b601154600160801b90046001600160801b031681565b6004546001600160a01b031681565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3757600080fd5b505afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b505afa158015610fd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff99190613d9e565b905061100b828263ffffffff6108a016565b9250505090565b6000546001600160a01b031681565b601360209081526000928352604080842090915290825290205481565b600c602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156110be57600080fd5b505afa1580156110d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f69190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b60008060405161115790613f26565b6040519081900390205492915050565b60105481565b6008546001600160a01b031681565b6003546001600160a01b031681565b6040518060400160405280600d81526020016c14dd18589a5b1a5d1e541bdbdb609a1b81525081565b6011546001600160801b031681565b600d602052600090815260409020805460019091015460ff1682565b6007546001600160a01b031681565b60165481565b600a5490565b600480546040805163e9fc346160e01b8152905160009361128c936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561124057600080fd5b505afa158015611254573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112789190613c36565b60065485906001600160a01b0316856127c0565b905061129981600061261d565b505050565b633b9aca0081565b6112ae611148565b6001600160a01b0316336001600160a01b0316146112de5760405162461bcd60e51b81526004016108959061451d565b6112e788611d69565b6112f087611d69565b6112f986611d69565b61130285611d69565b61130b84611d69565b61131483611d69565b61131d82611d69565b61132681611d69565b670de0b6b3a7640000601055600380546001600160a01b03199081166001600160a01b038b8116919091179092556004805482168a8416179055600580548216898416179055600080548216888416179055600680548216878416179055600780548216868416179055600280548216858416179055600880549091169183169190911790556040517f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed985906113dc908990613f43565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a5678866040516114139190613f43565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828560405161144a9190613f43565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d846040516114819190613f43565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800836040516114b89190613f43565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264826040516114ef9190613f43565b60405180910390a17f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac6811816040516115269190613f43565b60405180910390a15050505050505050565b60155481565b6001600160a01b0381166000908152600e602052604081205480611566576000915050610d4c565b6001600160a01b0383166000908152600d602052604081205490611598670de0b6b3a76400008363ffffffff612a6516565b90506115a2613b64565b506001600160a01b0385166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b869063ffffffff612b3316565b9063ffffffff612b6d16565b979650505050505050565b6001600160a01b0381166000908152600e60205260408120548061166a576000915050610d4c565b611672613b64565b506001600160a01b0383166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b6001600160a01b0381166000908152600b602052604081205480611707576000915050610d4c565b6001600160a01b038084166000908152600b602052604081206001015490911690811561174c576001600160a01b0382166000908152600d6020526040902054611756565b670de0b6b3a76400005b9050611760613b64565b506001600160a01b0385166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b6006546001600160a01b031681565b600b60205260009081526040902080546001909101546001600160a01b031682565b600480546040805163e9fc346160e01b815290516000936118c0936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561185357600080fd5b505afa158015611867573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188b9190613c36565b6006546001600160a01b0316867f00000000000000000000000000000000000000000000000000000000000000008787612baf565b9050610ca281600061261d565b336000908152600b60205260409020546118e681612dfc565b6118ef33612e1c565b6118f833612ebb565b6008546001600160a01b031661190d81611dd8565b600061191833610ca9565b9050600061192533610d6f565b90506000611939858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b039091169061196790869083612ee8565b600061197282611642565b90508061197f838261305d565b826001600160a01b031660008051602061496283398151915282336040516119a8929190614850565b60405180910390a26119ba33866131a5565b336001600160a01b031660008051602061494283398151915287866040516119e392919061403c565b60405180910390a2336001600160a01b031660008051602061492283398151915286604051611a129190614847565b60405180910390a2600954611a2d908763ffffffff612a6516565b600981905560405160008051602061490283398151915291611a4e91614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123387604051611a87929190613fdf565b60405180910390a1600460009054906101000a90046001600160a01b03166001600160a01b031663ea9638bf87338d8d6040518563ffffffff1660e01b8152600401611ad593929190613f57565b6000604051808303818588803b158015611aee57600080fd5b505af1158015611b02573d6000803e3d6000fd5b505050505050505050505050505050565b60006001600160a01b038216611b3b5760405162461bcd60e51b815260040161089590614434565b8215611b4957611b4961331a565b336000908152600b6020526040902054611b6281612dfc565b6008546001600160a01b0316611b7781611dd8565b6000611b8233610ca9565b90506000611b8f33610d6f565b90506000611b9d8883613551565b90506000611bb1868463ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b0390911690611bdf90879083612ee8565b6000611bea82611642565b90506000611bfe828663ffffffff612a6516565b9050611c0a838261305d565b826001600160a01b03166000805160206149628339815191528233604051611c33929190614850565b60405180910390a2611c458b86613567565b6000611c57878763ffffffff612a6516565b9050611c6333826131a5565b336001600160a01b031660008051602061492283398151915282604051611c8a9190614847565b60405180910390a2336001600160a01b03166000805160206149428339815191528987604051611cbb92919061403c565b60405180910390a2611ccd88336135e0565b50939b9a5050505050505050505050565b6001600160a01b038116611d045760405162461bcd60e51b81526004016108959061429f565b806001600160a01b0316611d16611148565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611d5990613f26565b6040519081900390209190915550565b6001600160a01b038116611d8f5760405162461bcd60e51b8152600401610895906142e1565b803b80610c425760405162461bcd60e51b815260040161089590614646565b6005546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614369565b600a54604051636cbdcf4760e01b81526000916001600160a01b03841691636cbdcf4791611e0891600401614847565b602060405180830381600087803b158015611e2257600080fd5b505af1158015611e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5a9190613d9e565b9050610c428161370f565b6000806000611e97601554611e8b670de0b6b3a764000089612b3390919063ffffffff16565b9063ffffffff6108a016565b905083851115611ea357fe5b83851415611ec0576000601655670de0b6b3a76400009150611f20565b601654600090611eee90611ee288670de0b6b3a764000063ffffffff612b3316565b9063ffffffff612a6516565b9050611f056001611e8b838863ffffffff612b6d16565b9250611f1b81611ee2858863ffffffff612b3316565b601655505b611f30818563ffffffff612b6d16565b9250611f52611f45848663ffffffff612b3316565b829063ffffffff612a6516565b60155550935093915050565b6010546000670de0b6b3a7640000831115611f7557fe5b6000611f8f670de0b6b3a76400008563ffffffff612a6516565b6011546001600160801b03600160801b820481166000818152601260209081526040808320949095168083529390529283205493945090929091611fd38988612b33565b90506000611fe7838363ffffffff6108a016565b6001600160801b038086166000908152601260209081526040808320938a168352929052819020829055519091507fe12e2cd2c9afa8069203ca07e7eff1edce4a075686d0736a8e7e0d593597b2079061204690839087908990614877565b60405180910390a18561211f5761206d6001600160801b038516600163ffffffff61382016565b601180546001600160801b03908116600160801b938216840217918290556040517fb50f0f59e7cb5b421dc77581c3a9919e3806e076e5fa78a874c3f120cb7d874d936120be930490911690614833565b60405180910390a1601180546001600160801b03191690556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9061210790600090614833565b60405180910390a1670de0b6b3a7640000965061220c565b633b9aca00612140670de0b6b3a764000061162b8b8a63ffffffff612b3316565b10156121ed57612176670de0b6b3a764000061162b633b9aca0061216a8c8b63ffffffff612b3316565b9063ffffffff612b3316565b96506121926001600160801b038616600163ffffffff61382016565b601180546001600160801b0319166001600160801b0392831617908190556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe926121e0921690614833565b60405180910390a161220c565b612209670de0b6b3a764000061162b8a8963ffffffff612b3316565b96505b6000871161221657fe5b60108790556040517fc1a9618cb59ebca77cbdbc2949f126823c407ff13edb285fd0262519a9c18e8c9061224b908990614847565b60405180910390a150505050505050505050565b60005460405163121cbc4d60e11b81526001600160a01b03909116908190632439789a90612291908590600401614847565b600060405180830381600087803b1580156122ab57600080fd5b505af11580156122bf573d6000803e3d6000fd5b505050506122cc82613851565b600654604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906122fe9030908690600401613fdf565b600060405180830381600087803b15801561231857600080fd5b505af115801561232c573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b03841692506364a197f3915061235e9030908790600401613fdf565b600060405180830381600087803b15801561237857600080fd5b505af115801561238c573d6000803e3d6000fd5b50505050505050565b6080810151606082015182516020808501516001600160801b038086166000908152601284526040808220928716825291909352822054919493929185906123e3908463ffffffff612a6516565b6001600160801b0380871660009081526012602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b6001600160801b031681526020810191909152604001600020549063ffffffff612b6d16565b90506000612478670de0b6b3a764000061162b868161246b888863ffffffff6108a016565b8f9063ffffffff612b3316565b9a9950505050505050505050565b6020810151606082015160808301516011546000939291906001600160801b03600160801b909104811690821610156124c557600093505050506108c8565b60115460009081906124e6906001600160801b03168563ffffffff6138ab16565b90506001600160801b0381166125165761250f8561162b6010548b612b3390919063ffffffff16565b915061254e565b806001600160801b0316600114156125495761250f633b9aca0061162b8761162b6010548d612b3390919063ffffffff16565b600091505b61256288633b9aca0063ffffffff612b6d16565b821015612577576000955050505050506108c8565b509695505050505050565b6001600160a01b0381166000908152600d602052604090206001015460ff1615610b335760405162461bcd60e51b81526004016108959061454e565b6001600160a01b0381166000908152600b60205260409020548015610c425760405162461bcd60e51b8152600401610895906145a7565b670de0b6b3a7640000811115610b335760405162461bcd60e51b815260040161089590614484565b612626816138e5565b61262f33612582565b61263882613932565b336000908152600b60205260409020546008546001600160a01b031661265d81611dd8565b8161266c5761266c3384613952565b600061267733610ca9565b9050600061268433610d6f565b90506000612698858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b03909116906126c690869083612ee8565b60006126d182611642565b905060006126e5828b63ffffffff6108a016565b90506126f1838261305d565b826001600160a01b0316600080516020614962833981519152823360405161271a929190614850565b60405180910390a261272c338b6139ac565b600061273e868c63ffffffff6108a016565b905061274a33826131a5565b336001600160a01b0316600080516020614922833981519152826040516127719190614847565b60405180910390a2336001600160a01b031660008051602061494283398151915288876040516127a292919061403c565b60405180910390a26127b387613a60565b5050505050505050505050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b1580156127fc57600080fd5b505afa158015612810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128349190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016128649190613f43565b60206040518083038186803b15801561287c57600080fd5b505afa158015612890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b49190613d9e565b9050306001600160a01b03831663605629d633838a89356128db60408c0160208d01613eea565b8b604001358c606001356040518863ffffffff1660e01b81526004016129079796959493929190613f9e565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b50505050866129ba83856001600160a01b03166370a08231856040518263ffffffff1660e01b815260040161296a9190613f43565b60206040518083038186803b15801561298257600080fd5b505afa158015612996573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee29190613d9e565b146129d75760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390612a079089908b903390600401614019565b602060405180830381600087803b158015612a2157600080fd5b505af1158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613d9e565b98975050505050505050565b60006108c583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a6a565b608081015160608201516040808401516020808601516001600160801b03808716600090815260138452858120918716815292529281205490949392908590612af6908463ffffffff612a6516565b6001600160801b0380871660009081526013602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b600082612b42575060006108c8565b82820282848281612b4f57fe5b04146108c55760405162461bcd60e51b8152600401610895906143f3565b60006108c583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613a96565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015612beb57600080fd5b505afa158015612bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c239190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612c539190613f43565b60206040518083038186803b158015612c6b57600080fd5b505afa158015612c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca39190613d9e565b87516020015190915030906001600160a01b0388166330f28b7a8a612cc88585613acd565b338b8b6040518663ffffffff1660e01b8152600401612ceb9594939291906147c2565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b5050505080612d4e84866001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161296a9190613f43565b14612d6b5760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390612d9b908d9085903390600401614019565b602060405180830381600087803b158015612db557600080fd5b505af1158015612dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ded9190613d9e565b9b9a5050505050505050505050565b60008111610b335760405162461bcd60e51b81526004016108959061467b565b6005546040516321e3780160e01b81526001600160a01b03909116906321e3780190612e4c908490600401613f43565b60206040518083038186803b158015612e6457600080fd5b505afa158015612e78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9c9190613d9e565b600114610b335760405162461bcd60e51b8152600401610895906140b3565b6000612ec682610ca9565b905060008111610c425760405162461bcd60e51b815260040161089590614318565b6001600160a01b03811615612fa8576000612f028261153e565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612f339085908590600401613fdf565b600060405180830381600087803b158015612f4d57600080fd5b505af1158015612f61573d6000803e3d6000fd5b50505050816001600160a01b03167f732e331072fe280a520929e5f2cc76c223389ff57d32a4e278cfded03e6f1caa82604051612f9e9190614847565b60405180910390a2505b6000612fb3836116df565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612fe49086908590600401613fdf565b600060405180830381600087803b158015612ffe57600080fd5b505af1158015613012573d6000803e3d6000fd5b50505050826001600160a01b03167fe9ac2dcd83e719358f1dc0c5c80491937f67d4ec61ef62c262bbe3b78578f92a8260405161304f9190614847565b60405180910390a250505050565b6001600160a01b0382166000908152600e60205260409020819055806130e8576001600160a01b0382166000818152600f60205260408082208281556001810183905560028101839055600301829055517fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e45916130db91819061403c565b60405180910390a2610c42565b6011546010546001600160801b03600160801b80840482166000818152601360209081526040808320978616808452978252808320546001600160a01b038b16808552600f90935292819020600181018890556002810184905560030180546001600160801b0319168917909616948402949094179094559151909392907fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e4590613195908590859061403c565b60405180910390a2505050505050565b6001600160a01b0382166000908152600b6020526040902081905580613243576001600160a01b0382166000818152600b60209081526040808320600190810180546001600160a01b0319169055600c909252808320838155918201839055600282018390556003909101829055517f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a916130db918190819061404a565b6011546010546001600160801b03600160801b8084048216600081815260126020908152604080832097861680845297825280832054848452601383528184208985528352818420546001600160a01b038c16808652600c90945293829020600181018990558181556002810185905560030180546001600160801b0319168a1790971695850295909517909555935191949390917f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a906133099086908690869061404a565b60405180910390a250505050505050565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561336057600080fd5b505af1158015613374573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133989190613d9e565b90506000600760009054906101000a90046001600160a01b03166001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ea57600080fd5b505afa1580156133fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134229190613c36565b600554604051630d293c7160e41b81529192506000916001600160a01b039091169063d293c7109061345a9085908790600401613fdf565b60206040518083038186803b15801561347257600080fd5b505afa158015613486573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134aa9190613d9e565b9050600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156134fa57600080fd5b505afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135329190613d9e565b8110156112995760405162461bcd60e51b815260040161089590614758565b600081831061356057816108c5565b5090919050565b8061357157610c42565b600654604051631062c15f60e11b81526001600160a01b03909116906320c582be906135a590309086908690600401613f7a565b600060405180830381600087803b1580156135bf57600080fd5b505af11580156135d3573d6000803e3d6000fd5b50505050610c4281613851565b6001600160a01b0381166136065760405162461bcd60e51b81526004016108959061419f565b8161361057610c42565b600954600090613626908463ffffffff612a6516565b9050806009819055506000805160206149028339815191528160405161364c9190614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123384604051613685929190613fdf565b60405180910390a16000336001600160a01b0316846040516136a690613f23565b60006040518083038185875af1925050503d80600081146136e3576040519150601f19603f3d011682016040523d82523d6000602084013e6136e8565b606091505b50509050806137095760405162461bcd60e51b8152600401610895906143b2565b50505050565b600a5480158061371d575081155b156137285750610b33565b60006137348383613aff565b9050600061374d60105483612b3390919063ffffffff16565b6011546001600160801b03600160801b820481166000908152601360209081526040808320939094168252919091522054909150613791908263ffffffff6108a016565b601180546001600160801b03600160801b80830482166000908152601360208181526040808420968616845295815285832097909755945491820483168082529486528381209190921680835294528190205490517f2d6127771b164a9cc8827d24b5955db2a77e7a81dac389107ebb8bce9fb64968936138129391614877565b60405180910390a150505050565b60008282016001600160801b0380851690821610156108c55760405162461bcd60e51b815260040161089590614713565b600a54600090613867908363ffffffff612a6516565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c78160405161389f9190614847565b60405180910390a15050565b6000826001600160801b0316826001600160801b031611156138df5760405162461bcd60e51b8152600401610895906146cb565b50900390565b6001600160a01b0381166000908152600d602052604090206001015460ff168061391657506001600160a01b038116155b610b335760405162461bcd60e51b8152600401610895906141ec565b60008111610b335760405162461bcd60e51b8152600401610895906144d7565b6001600160a01b038281166000818152600b602052604080822060010180546001600160a01b0319169486169485179055517f094c08e96a8890877a8390b4f967180a7507ad8622244d05fcd0f9f8e086564e9190a35050565b600654604051632ee65eeb60e21b81526001600160a01b039091169063bb997bac906139e090859030908690600401613f7a565b600060405180830381600087803b1580156139fa57600080fd5b505af1158015613a0e573d6000803e3d6000fd5b5050600a5460009250613a2891508363ffffffff6108a016565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c781604051610ac19190614847565b610b3381336135e0565b60008184841115613a8e5760405162461bcd60e51b81526004016108959190614060565b505050900390565b60008183613ab75760405162461bcd60e51b81526004016108959190614060565b506000838581613ac357fe5b0495945050505050565b613ad5613ba5565b613add613ba5565b5050604080518082019091526001600160a01b03929092168252602082015290565b600080613b23601454611e8b670de0b6b3a764000087612b3390919063ffffffff16565b90506000613b37828563ffffffff612b6d16565b9050613b59613b4c828663ffffffff612b3316565b839063ffffffff612a6516565b601455949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b604080518082019091526000808252602082015290565b60008083601f840112613bcd578182fd5b50813567ffffffffffffffff811115613be4578182fd5b602083019150836020828501011115613bfc57600080fd5b9250929050565b80356001600160801b03811681146108c857600080fd5b600060208284031215613c2b578081fd5b81356108c5816148ec565b600060208284031215613c47578081fd5b81516108c5816148ec565b60008060408385031215613c64578081fd5b8235613c6f816148ec565b91506020830135613c7f816148ec565b809150509250929050565b600080600080600080600080610100898b031215613ca6578384fd5b8835613cb1816148ec565b97506020890135613cc1816148ec565b96506040890135613cd1816148ec565b95506060890135613ce1816148ec565b94506080890135613cf1816148ec565b935060a0890135613d01816148ec565b925060c0890135613d11816148ec565b915060e0890135613d21816148ec565b809150509295985092959890939650565b600060208284031215613d43578081fd5b815180151581146108c5578182fd5b60008060408385031215613d64578182fd5b613d6e8484613c03565b9150613d7d8460208501613c03565b90509250929050565b600060208284031215613d97578081fd5b5035919050565b600060208284031215613daf578081fd5b5051919050565b60008060408385031215613dc8578182fd5b823591506020830135613c7f816148ec565b60008082840360a0811215613ded578283fd5b833592506080601f1982011215613e02578182fd5b506020830190509250929050565b60008060008084860360c0811215613e26578485fd5b85359450601f1981016080811215613e3c578485fd5b613e4660606148c5565b91506040811215613e55578485fd5b50613e6060406148c5565b6020870135613e6e816148ec565b80825250604087013560208201528082525060608601356020820152608086013560408201528093505060a085013567ffffffffffffffff811115613eb1578283fd5b613ebd87828801613bbc565b95989497509550505050565b60008060408385031215613edb578182fd5b50508035926020909101359150565b600060208284031215613efb578081fd5b813560ff811681146108c5578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b6000602080835283518082850152825b8181101561408c57858101830151858201604001528201614070565b8181111561409d5783604083870101525b50601f01601f1916929092016040019392505050565b60208082526046908201527f53746162696c697479506f6f6c3a2063616c6c6572206d75737420686176652060408201527f616e206163746976652074726f766520746f207769746864726177204554484760608201526561696e20746f60d01b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252602d908201527f53503a3a5f73656e644554484761696e546f3a205f726563656976657220697360408201526c207a65726f206164647265737360981b606082015260800190565b60208082526046908201527f53746162696c697479506f6f6c3a20546167206d75737420626520612072656760408201527f697374657265642066726f6e7420656e642c206f7220746865207a65726f206160608201526564647265737360d01b608082015260a00190565b60208082526027908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f74204163746040820152661a5d99541bdbdb60ca1b606082015260800190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526031908201527f53746162696c697479506f6f6c3a2063616c6c6572206d7573742068617665206040820152703737b716bd32b9379022aa241023b0b4b760791b606082015260800190565b60208082526029908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f742054726f6040820152683b32a6b0b730b3b2b960b91b606082015260800190565b60208082526021908201527f53746162696c697479506f6f6c3a2073656e64696e6720455448206661696c656040820152601960fa1b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526030908201527f53503a3a5f776974686472617746726f6d5370546f3a205f726563656976657260408201526f206973207a65726f206164647265737360801b606082015260800190565b60208082526033908201527f53746162696c697479506f6f6c3a204b69636b6261636b2072617465206d75736040820152727420626520696e2072616e6765205b302c315d60681b606082015260800190565b60208082526026908201527f53746162696c697479506f6f6c3a20416d6f756e74206d757374206265206e6f6040820152656e2d7a65726f60d01b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526039908201527f53746162696c697479506f6f6c3a206d757374206e6f7420616c72656164792060408201527818994818481c9959da5cdd195c995908199c9bdb9d08195b99603a1b606082015260800190565b60208082526028908201527f53746162696c697479506f6f6c3a2055736572206d7573742068617665206e6f6040820152670819195c1bdcda5d60c21b606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526030908201527f53746162696c697479506f6f6c3a2055736572206d757374206861766520612060408201526f1b9bdb8b5e995c9bc819195c1bdcda5d60821b606082015260800190565b60208082526028908201527f4c697175697479536166654d6174683132383a207375627472616374696f6e206040820152676f766572666c6f7760c01b606082015260800190565b60208082526025908201527f4c697175697479536166654d6174683132383a206164646974696f6e206f766560408201526472666c6f7760d81b606082015260800190565b60208082526044908201527f53746162696c697479506f6f6c3a2043616e6e6f74207769746864726177207760408201527f68696c65207468657265206172652074726f766573207769746820494352203c6060820152631026a1a960e11b608082015260a00190565b60006101006147d2838951613f0b565b60208801516040840152604088015160608401526147f36080840188613f0b565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b6001600160801b0391909116815260200190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9182521515602082015260400190565b9283526001600160801b03918216602084015216604082015260600190565b948552602085019390935260408401919091526001600160801b03908116606084015216608082015260a00190565b60405181810167ffffffffffffffff811182821017156148e457600080fd5b604052919050565b6001600160a01b0381168114610b3357600080fdfeceb6d671277d4354fd29977ada70695fbd93a16612abf765d6b0e25c28dc6db3bce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c951457222ebca92c335c9c86e2baa1cc0e40ffaa9084a51452980d5ba8dec2f6399920012339b5a3368d3a04b8606ce412c46ed92b7dcd8602d41fc8862cb8f25a2646970667358221220b12079f570461c3902a02d925635ecefb92e70f4556abddd99509e1ecfffdece64736f6c634300060b0033", + "implementation": "0xab257df54103424d7f0873b42f7e169466fe7aa1" +} diff --git a/external/deployments/rskTestnet/StabilityPool_Implementation.json b/external/deployments/rskTestnet/StabilityPool_Implementation.json new file mode 100644 index 000000000..fb9c29a2e --- /dev/null +++ b/external/deployments/rskTestnet/StabilityPool_Implementation.json @@ -0,0 +1,1943 @@ +{ + "address": "0xab257df54103424d7f0873b42f7e169466fe7aa1", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newActivePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newBorrowerOperationsAddress", + "type": "address" + } + ], + "name": "BorrowerOperationsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newCommunityIssuanceAddress", + "type": "address" + } + ], + "name": "CommunityIssuanceAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newDefaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_S", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + } + ], + "name": "DepositSnapshotUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDLoss", + "type": "uint256" + } + ], + "name": "ETHGainWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint128", + "name": "_currentEpoch", + "type": "uint128" + } + ], + "name": "EpochUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "EtherSent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_kickbackRate", + "type": "uint256" + } + ], + "name": "FrontEndRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + } + ], + "name": "FrontEndSnapshotUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newFrontEndStake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "FrontEndStakeChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "FrontEndTagSet", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_G", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_epoch", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_scale", + "type": "uint128" + } + ], + "name": "G_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_P", + "type": "uint256" + } + ], + "name": "P_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_SOV", + "type": "uint256" + } + ], + "name": "SOVPaidToDepositor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_frontEnd", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_SOV", + "type": "uint256" + } + ], + "name": "SOVPaidToFrontEnd", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_S", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_epoch", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "_scale", + "type": "uint128" + } + ], + "name": "S_Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint128", + "name": "_currentScale", + "type": "uint128" + } + ], + "name": "ScaleUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newSortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newBalance", + "type": "uint256" + } + ], + "name": "StabilityPoolETHBalanceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newBalance", + "type": "uint256" + } + ], + "name": "StabilityPoolZUSDBalanceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newTroveManagerAddress", + "type": "address" + } + ], + "name": "TroveManagerAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newDeposit", + "type": "uint256" + } + ], + "name": "UserDepositChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_depositor", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_zusdAmountRequested", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_dllrAmountReceived", + "type": "uint256" + } + ], + "name": "WithdrawFromSpAndConvertToDLLR", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newZUSDTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "P", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SCALE_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "borrowerOperations", + "outputs": [ + { + "internalType": "contract IBorrowerOperations", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "communityIssuance", + "outputs": [ + { + "internalType": "contract ICommunityIssuance", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentEpoch", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "currentScale", + "outputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "depositSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "S", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "P", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "G", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "scale", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "epoch", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "deposits", + "outputs": [ + { + "internalType": "uint256", + "name": "initialValue", + "type": "uint256" + }, + { + "internalType": "address", + "name": "frontEndTag", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "name": "epochToScaleToG", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint128", + "name": "", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "", + "type": "uint128" + } + ], + "name": "epochToScaleToSum", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEndSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "S", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "P", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "G", + "type": "uint256" + }, + { + "internalType": "uint128", + "name": "scale", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "epoch", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEndStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "frontEnds", + "outputs": [ + { + "internalType": "uint256", + "name": "kickbackRate", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "registered", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "getCompoundedFrontEndStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getCompoundedZUSDDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getDepositorETHGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_depositor", + "type": "address" + } + ], + "name": "getDepositorSOVGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getETH", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_frontEnd", + "type": "address" + } + ], + "name": "getFrontEndSOVGain", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalZUSDDeposits", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastETHError_Offset", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastSOVError", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastZUSDLossError_Offset", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_debtToOffset", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_collToAdd", + "type": "uint256" + } + ], + "name": "offset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_frontEndTag", + "type": "address" + } + ], + "name": "provideToSP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "provideToSpFromDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "provideToSpFromDllrWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_kickbackRate", + "type": "uint256" + } + ], + "name": "registerFrontEnd", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_communityIssuanceAddress", + "type": "address" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_communityIssuanceAddress", + "type": "address" + } + ], + "name": "setCommunityIssuanceAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManager", + "outputs": [ + { + "internalType": "contract ITroveManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_upperHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerHint", + "type": "address" + } + ], + "name": "withdrawETHGainToTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "withdrawFromSP", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_zusdAmountRequested", + "type": "uint256" + } + ], + "name": "withdrawFromSpAndConvertToDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0xC959895CE6224dde0BdF7eb84519814dE23f2ee5", + "transactionIndex": 0, + "gasUsed": "5135892", + "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000040000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x26eb0b71917b7e14376847d8f22d8b657ac8a4a9756f9bace883ec60614ed674", + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748945, + "transactionHash": "0x1abdbd2388abebfb2b987c678ee06a38046e552728b35dbe0dfb5debbbe6c2a5", + "address": "0xC959895CE6224dde0BdF7eb84519814dE23f2ee5", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x26eb0b71917b7e14376847d8f22d8b657ac8a4a9756f9bace883ec60614ed674" + } + ], + "blockNumber": 4748945, + "cumulativeGasUsed": "5135892", + "status": 1, + "byzantium": true + }, + "args": ["0x000000000022d473030f116ddee9f6b43ac78ba3"], + "numDeployments": 3, + "solcInputHash": "849fadfa265e27de6fba2f2d99bdf763", + "metadata": "{\"compiler\":{\"version\":\"0.6.11+commit.5ef660b1\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_permit2\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newActivePoolAddress\",\"type\":\"address\"}],\"name\":\"ActivePoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newBorrowerOperationsAddress\",\"type\":\"address\"}],\"name\":\"BorrowerOperationsAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newCommunityIssuanceAddress\",\"type\":\"address\"}],\"name\":\"CommunityIssuanceAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newDefaultPoolAddress\",\"type\":\"address\"}],\"name\":\"DefaultPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_P\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_S\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_G\",\"type\":\"uint256\"}],\"name\":\"DepositSnapshotUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ETH\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ZUSDLoss\",\"type\":\"uint256\"}],\"name\":\"ETHGainWithdrawn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_currentEpoch\",\"type\":\"uint128\"}],\"name\":\"EpochUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"EtherSent\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_kickbackRate\",\"type\":\"uint256\"}],\"name\":\"FrontEndRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_P\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_G\",\"type\":\"uint256\"}],\"name\":\"FrontEndSnapshotUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newFrontEndStake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"}],\"name\":\"FrontEndStakeChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"}],\"name\":\"FrontEndTagSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_G\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_epoch\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_scale\",\"type\":\"uint128\"}],\"name\":\"G_Updated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_P\",\"type\":\"uint256\"}],\"name\":\"P_Updated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newPriceFeedAddress\",\"type\":\"address\"}],\"name\":\"PriceFeedAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_SOV\",\"type\":\"uint256\"}],\"name\":\"SOVPaidToDepositor\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_SOV\",\"type\":\"uint256\"}],\"name\":\"SOVPaidToFrontEnd\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_S\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_epoch\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_scale\",\"type\":\"uint128\"}],\"name\":\"S_Updated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"_currentScale\",\"type\":\"uint128\"}],\"name\":\"ScaleUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newSortedTrovesAddress\",\"type\":\"address\"}],\"name\":\"SortedTrovesAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newBalance\",\"type\":\"uint256\"}],\"name\":\"StabilityPoolETHBalanceUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newBalance\",\"type\":\"uint256\"}],\"name\":\"StabilityPoolZUSDBalanceUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newTroveManagerAddress\",\"type\":\"address\"}],\"name\":\"TroveManagerAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newDeposit\",\"type\":\"uint256\"}],\"name\":\"UserDepositChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_zusdAmountRequested\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_dllrAmountReceived\",\"type\":\"uint256\"}],\"name\":\"WithdrawFromSpAndConvertToDLLR\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newZUSDTokenAddress\",\"type\":\"address\"}],\"name\":\"ZUSDTokenAddressChanged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DECIMAL_PRECISION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_NET_DEBT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"P\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SCALE_FACTOR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZUSD_GAS_COMPENSATION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_100pct\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activePool\",\"outputs\":[{\"internalType\":\"contract IActivePool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"borrowerOperations\",\"outputs\":[{\"internalType\":\"contract IBorrowerOperations\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"communityIssuance\",\"outputs\":[{\"internalType\":\"contract ICommunityIssuance\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentEpoch\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentScale\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultPool\",\"outputs\":[{\"internalType\":\"contract IDefaultPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"depositSnapshots\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"S\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"P\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"G\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"scale\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"epoch\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"deposits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"initialValue\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"frontEndTag\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"name\":\"epochToScaleToG\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"name\":\"epochToScaleToSum\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"frontEndSnapshots\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"S\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"P\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"G\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"scale\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"epoch\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"frontEndStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"frontEnds\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"kickbackRate\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"registered\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"}],\"name\":\"getCompoundedFrontEndStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"}],\"name\":\"getCompoundedZUSDDeposit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"}],\"name\":\"getDepositorETHGain\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_depositor\",\"type\":\"address\"}],\"name\":\"getDepositorSOVGain\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getETH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemColl\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_frontEnd\",\"type\":\"address\"}],\"name\":\"getFrontEndSOVGain\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalZUSDDeposits\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastETHError_Offset\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastSOVError\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastZUSDLossError_Offset\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquityBaseParams\",\"outputs\":[{\"internalType\":\"contract ILiquityBaseParams\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_debtToOffset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_collToAdd\",\"type\":\"uint256\"}],\"name\":\"offset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceFeed\",\"outputs\":[{\"internalType\":\"contract IPriceFeed\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_frontEndTag\",\"type\":\"address\"}],\"name\":\"provideToSP\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"provideToSpFromDLLR\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"provideToSpFromDllrWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_kickbackRate\",\"type\":\"uint256\"}],\"name\":\"registerFrontEnd\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_liquityBaseParamsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_borrowerOperationsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_troveManagerAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_activePoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zusdTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_sortedTrovesAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_priceFeedAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_communityIssuanceAddress\",\"type\":\"address\"}],\"name\":\"setAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_communityIssuanceAddress\",\"type\":\"address\"}],\"name\":\"setCommunityIssuanceAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortedTroves\",\"outputs\":[{\"internalType\":\"contract ISortedTroves\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"troveManager\",\"outputs\":[{\"internalType\":\"contract ITroveManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_upperHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerHint\",\"type\":\"address\"}],\"name\":\"withdrawETHGainToTrove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdrawFromSP\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_zusdAmountRequested\",\"type\":\"uint256\"}],\"name\":\"withdrawFromSpAndConvertToDLLR\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"zusdToken\",\"outputs\":[{\"internalType\":\"contract IZUSDToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getETH()\":{\"returns\":{\"_0\":\"the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`, to exclude edge cases like ETH received from a self-destruct.\"}},\"getOwner()\":{\"returns\":{\"_owner\":\"Address of the owner. \"}},\"getTotalZUSDDeposits()\":{\"returns\":{\"_0\":\"ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\"}},\"setAddresses(address,address,address,address,address,address,address,address)\":{\"details\":\"initializer function, checks addresses are contracts\",\"params\":{\"_activePoolAddress\":\"ActivePool contract address\",\"_borrowerOperationsAddress\":\"BorrowerOperations contract address\",\"_communityIssuanceAddress\":\"CommunityIssuanceAddress\",\"_liquityBaseParamsAddress\":\"LiquidityBaseParams contract address\",\"_priceFeedAddress\":\"PriceFeed contract address\",\"_sortedTrovesAddress\":\"SortedTroves contract address\",\"_troveManagerAddress\":\"TroveManager contract address\",\"_zusdTokenAddress\":\"ZUSDToken contract address\"}},\"setCommunityIssuanceAddress(address)\":{\"details\":\"setter function specific for community issuance contract.\",\"params\":{\"_communityIssuanceAddress\":\"address of new community issuance contract.\"}},\"setOwner(address)\":{\"params\":{\"_owner\":\"Address of the owner. \"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"MIN_NET_DEBT()\":{\"notice\":\"Minimum amount of net ZUSD debt a trove must have\"},\"ZUSD_GAS_COMPENSATION()\":{\"notice\":\"Amount of ZUSD to be locked in gas pool on opening troves\"},\"constructor\":\"Constructor \",\"getCompoundedFrontEndStake(address)\":{\"notice\":\"Return the front end's compounded stake. Given by the formula: D = D0 * P/P(0) where P(0) is the depositor's snapshot of the product P, taken at the last time when one of the front end's tagged deposits updated their deposit. The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\"},\"getCompoundedZUSDDeposit(address)\":{\"notice\":\"Return the user's compounded deposit. Given by the formula: d = d0 * P/P(0) where P(0) is the depositor's snapshot of the product P, taken when they last updated their deposit.\"},\"getDepositorETHGain(address)\":{\"notice\":\"Calculates the ETH gain earned by the deposit since its last snapshots were taken. Given by the formula: E = d0 * (S - S(0))/P(0) where S(0) and P(0) are the depositor's snapshots of the sum S and product P, respectively. d0 is the last recorded deposit value.\"},\"getDepositorSOVGain(address)\":{\"notice\":\"Calculate the SOV gain earned by a deposit since its last snapshots were taken. Given by the formula: SOV = d0 * (G - G(0))/P(0) where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively. d0 is the last recorded deposit value.\"},\"getFrontEndSOVGain(address)\":{\"notice\":\"Return the SOV gain earned by the front end. Given by the formula: E = D0 * (G - G(0))/P(0) where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively. D0 is the last recorded value of the front end's total tagged deposits.\"},\"getOwner()\":{\"notice\":\"Return address of the owner.\"},\"offset(uint256,uint256)\":{\"notice\":\"Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible) and transfers the Trove's ETH collateral from ActivePool to StabilityPool. Only called by liquidation functions in the TroveManager.\"},\"provideToSP(uint256,address)\":{\"notice\":\"provideToSP(): - Triggers a SOV issuance, based on time passed since the last issuance and total amount of deposited ZUSD. The SOV issuance is shared between *all* depositors and front ends - Tags the deposit with the provided front end tag param, if it's a new deposit - Sends depositor's accumulated gains (SOV, ETH) to depositor - Sends the tagged front end's accumulated SOV gains to the tagged front end - Increases deposit and tagged front end's stake, and takes new snapshots for each.\"},\"provideToSpFromDLLR(uint256,(uint256,uint8,bytes32,bytes32))\":{\"notice\":\"DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\"},\"provideToSpFromDllrWithPermit2(uint256,((address,uint256),uint256,uint256),bytes)\":{\"notice\":\"DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\"},\"registerFrontEnd(uint256)\":{\"notice\":\"Front end makes a one-time selection of kickback rate upon registering\"},\"setAddresses(address,address,address,address,address,address,address,address)\":{\"notice\":\"Called only once on init, to set addresses of other Liquity contracts. Callable only by owner\"},\"setOwner(address)\":{\"notice\":\"Set address of the owner (only owner can call this function)\"},\"withdrawETHGainToTrove(address,address)\":{\"notice\":\"withdrawETHGainToTrove: - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends - Sends all depositor's SOV gain to depositor - Sends all tagged front end's SOV gain to the tagged front end - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove - Leaves their compounded deposit in the Stability Pool - Updates snapshots for deposit and tagged front end stake \"},\"withdrawFromSP(uint256)\":{\"notice\":\"withdrawFromSP(): - Triggers a SOV issuance, based on time passed since the last issuance and total amount of ZUSD is deposited. The SOV issuance is shared between *all* depositors and front ends - Removes the deposit's front end tag if it is a full withdrawal - Sends all depositor's accumulated gains (SOV, ETH) to depositor - Sends the tagged front end's accumulated SOV gains to the tagged front end - Decreases deposit and tagged front end's stake, and takes new snapshots for each. If _amount > userDeposit, the user withdraws all of their compounded deposit.\"},\"withdrawFromSpAndConvertToDLLR(uint256)\":{\"notice\":\"Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\"}},\"notice\":\"The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors. When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned. Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits. They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors, in the same proportion. When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40% of the total ZUSD in the Stability Pool, depletes 40% of each deposit. A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit, multiplying it by some factor in range ]0,1[ --- IMPLEMENTATION --- We use a highly scalable method of tracking deposits and ETH gains that has O(1) complexity. When a liquidation occurs, rather than updating each depositor's deposit and ETH gain, we simply update two state variables: a product P, and a sum S. A mathematical manipulation allows us to factor out the initial deposit, and accurately track all depositors' compounded deposits and accumulated ETH gains over time, as liquidations occur, using just these two variables P and S. When depositors join the Stability Pool, they get a snapshot of the latest P and S: P_t and S_t, respectively. The formula for a depositor's accumulated ETH gain is derived here: https://github.com/liquity/dev/blob/main/packages/contracts/mathProofs/Scalable%20Compounding%20Stability%20Pool%20Deposits.pdf For a given deposit d_t, the ratio P/P_t tells us the factor by which a deposit has decreased since it joined the Stability Pool, and the term d_t * (S - S_t)/P_t gives us the deposit's total accumulated ETH gain. Each liquidation updates the product P and sum S. After a series of liquidations, a compounded deposit and corresponding ETH gain can be calculated using the initial deposit, the depositor\\u2019s snapshots of P and S, and the latest values of P and S. Any time a depositor updates their deposit (withdrawal, top-up) their accumulated ETH gain is paid out, their new deposit is recorded (based on their latest compounded deposit and modified by the withdrawal/top-up), and they receive new snapshots of the latest P and S. Essentially, they make a fresh deposit that overwrites the old one. --- SCALE FACTOR --- Since P is a running product in range ]0,1] that is always-decreasing, it should never reach 0 when multiplied by a number in range ]0,1[. Unfortunately, Solidity floor division always reaches 0, sooner or later. A series of liquidations that nearly empty the Pool (and thus each multiply P by a very small number in range ]0,1[ ) may push P to its 18 digit decimal limit, and round it to 0, when in fact the Pool hasn't been emptied: this would break deposit tracking. So, to track P accurately, we use a scale factor: if a liquidation would cause P to decrease to <1e-9 (and be rounded to 0 by Solidity), we first multiply P by 1e9, and increment a currentScale factor by 1. The added benefit of using 1e9 for the scale factor (rather than 1e18) is that it ensures negligible precision loss close to the scale boundary: when P is at its minimum value of 1e9, the relative precision loss in P due to floor division is only on the order of 1e-9. --- EPOCHS --- Whenever a liquidation fully empties the Stability Pool, all deposits should become 0. However, setting P to 0 would make P be 0 forever, and break all future reward calculations. So, every time the Stability Pool is emptied by a liquidation, we reset P = 1 and currentScale = 0, and increment the currentEpoch by 1. --- TRACKING DEPOSIT OVER SCALE CHANGES AND EPOCHS --- When a deposit is made, it gets snapshots of the currentEpoch and the currentScale. When calculating a compounded deposit, we compare the current epoch to the deposit's epoch snapshot. If the current epoch is newer, then the deposit was present during a pool-emptying liquidation, and necessarily has been depleted to 0. Otherwise, we then compare the current scale to the deposit's scale snapshot. If they're equal, the compounded deposit is given by d_t * P/P_t. If it spans one scale change, it is given by d_t * P/(P_t * 1e9). If it spans more than one scale change, we define the compounded deposit as 0, since it is now less than 1e-9'th of its initial value (e.g. a deposit of 1 billion ZUSD has depleted to < 1 ZUSD). --- TRACKING DEPOSITOR'S ETH GAIN OVER SCALE CHANGES AND EPOCHS --- In the current epoch, the latest value of S is stored upon each scale change, and the mapping (scale -> S) is stored for each epoch. This allows us to calculate a deposit's accumulated ETH gain, during the epoch in which the deposit was non-zero and earned ETH. We calculate the depositor's accumulated ETH gain for the scale at which they made the deposit, using the ETH gain formula: e_1 = d_t * (S - S_t) / P_t and also for scale after, taking care to divide the latter by a factor of 1e9: e_2 = d_t * S / (P_t * 1e9) The gain in the second scale will be full, as the starting point was in the previous scale, thus no need to subtract anything. The deposit therefore was present for reward events from the beginning of that second scale. S_i-S_t + S_{i+1} .<--------.------------> . . . S_i . S_{i+1} <--.-------->.<-----------> S_t. . <->. . t . |---+---------|-------------|-----... i i+1 The sum of (e_1 + e_2) captures the depositor's total accumulated ETH gain, handling the case where their deposit spanned one scale change. We only care about gains across one scale change, since the compounded deposit is defined as being 0 once it has spanned more than one scale change. --- UPDATING P WHEN A LIQUIDATION OCCURS --- Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations: https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS --- An SOV issuance event occurs at every deposit operation, and every liquidation. Each deposit is tagged with the address of the front end through which it was made. All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate. Please see the system Readme for an overview: https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers We use the same mathematical product-sum approach to track SOV gains for depositors, where 'G' is the sum corresponding to SOV gains. The product P (and snapshot P_t) is re-used, as the ratio P/P_t tracks a deposit's depletion due to liquidations.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/StabilityPool.sol\":\"StabilityPool\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"contracts/Dependencies/BaseMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\n\\ncontract BaseMath {\\n uint constant public DECIMAL_PRECISION = 1e18;\\n}\\n\",\"keccak256\":\"0x7e1369ca5cb09e818e345a2def19a261401f79c985a6030b55b7311dd6f53be4\",\"license\":\"MIT\"},\"contracts/Dependencies/CheckContract.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n\\ncontract CheckContract {\\n /**\\n * @dev Check that the account is an already deployed non-destroyed contract.\\n * See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L12\\n */\\n function checkContract(address _account) internal view {\\n require(_account != address(0), \\\"Account cannot be zero address\\\");\\n\\n uint256 size;\\n // solhint-disable-next-line no-inline-assembly\\n assembly { size := extcodesize(_account) }\\n require(size > 0, \\\"Account code size cannot be zero\\\");\\n }\\n}\\n\",\"keccak256\":\"0x4c7dc4d0197c27ebc7de671b00458a9ff45f57223aeb520e6ddd2eb6d2d89e5c\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on the OpenZeppelin IER20 interface:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol\\n *\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\\n function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n function name() external view returns (string memory);\\n function symbol() external view returns (string memory);\\n function decimals() external view returns (uint8);\\n \\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\",\"keccak256\":\"0xe0b2473eba89df8d27d7cea2a99fce788c212f3fd393c9508e449e51a3f220fa\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC2612.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * @dev Interface of the ERC2612 standard as defined in the EIP.\\n *\\n * Adds the {permit} method, which can be used to change one's\\n * {IERC20-allowance} without having to send a transaction, by signing a\\n * message. This allows users to spend tokens without having to hold Ether.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2612.\\n * \\n * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/\\n */\\ninterface IERC2612 {\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,\\n * given `owner`'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(address owner, address spender, uint256 amount, \\n uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;\\n \\n /**\\n * @dev Returns the current ERC2612 nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases `owner`'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n *\\n * `owner` can limit the time a Permit is valid for by setting `deadline` to \\n * a value in the near future. The deadline argument can be set to uint(-1) to \\n * create Permits that effectively never expire.\\n */\\n function nonces(address owner) external view returns (uint256);\\n \\n function version() external view returns (string memory);\\n function permitTypeHash() external view returns (bytes32);\\n function domainSeparator() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xd376458452f8b480bfea549637bd71d3f9eb1f12e9d59d1beff373417462d67f\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./BaseMath.sol\\\";\\nimport \\\"./LiquityMath.sol\\\";\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IPriceFeed.sol\\\";\\nimport \\\"../Interfaces/ILiquityBase.sol\\\";\\nimport \\\"../Interfaces/ILiquityBaseParams.sol\\\";\\n\\n/**\\n * Base contract for TroveManager, BorrowerOperations and StabilityPool. Contains global system constants and\\n * common functions.\\n */\\ncontract LiquityBase is BaseMath, ILiquityBase {\\n using SafeMath for uint256;\\n\\n uint256 public constant _100pct = 1000000000000000000; // 1e18 == 100%\\n\\n /// Amount of ZUSD to be locked in gas pool on opening troves\\n uint256 public constant ZUSD_GAS_COMPENSATION = 20e18;\\n\\n /// Minimum amount of net ZUSD debt a trove must have\\n uint256 public constant MIN_NET_DEBT = 180e18;\\n\\n IActivePool public activePool;\\n\\n IDefaultPool public defaultPool;\\n\\n IPriceFeed public override priceFeed;\\n\\n ILiquityBaseParams public override liquityBaseParams;\\n\\n // --- Gas compensation functions ---\\n\\n // Returns the composite debt (drawn debt + gas compensation) of a trove, for the purpose of ICR calculation\\n function _getCompositeDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.add(ZUSD_GAS_COMPENSATION);\\n }\\n\\n function _getNetDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.sub(ZUSD_GAS_COMPENSATION);\\n }\\n\\n /// Return the amount of ETH to be drawn from a trove's collateral and sent as gas compensation.\\n function _getCollGasCompensation(uint256 _entireColl) internal view returns (uint256) {\\n return _entireColl / liquityBaseParams.PERCENT_DIVISOR();\\n }\\n\\n function getEntireSystemColl() public view returns (uint256 entireSystemColl) {\\n uint256 activeColl = activePool.getETH();\\n uint256 liquidatedColl = defaultPool.getETH();\\n\\n return activeColl.add(liquidatedColl);\\n }\\n\\n function getEntireSystemDebt() public view returns (uint256 entireSystemDebt) {\\n uint256 activeDebt = activePool.getZUSDDebt();\\n uint256 closedDebt = defaultPool.getZUSDDebt();\\n\\n return activeDebt.add(closedDebt);\\n }\\n\\n function _getTCR(uint256 _price) internal view returns (uint256 TCR) {\\n uint256 entireSystemColl = getEntireSystemColl();\\n uint256 entireSystemDebt = getEntireSystemDebt();\\n\\n TCR = LiquityMath._computeCR(entireSystemColl, entireSystemDebt, _price);\\n\\n return TCR;\\n }\\n\\n function _checkRecoveryMode(uint256 _price) internal view returns (bool) {\\n uint256 TCR = _getTCR(_price);\\n\\n return TCR < liquityBaseParams.CCR();\\n }\\n\\n function _requireUserAcceptsFee(\\n uint256 _fee,\\n uint256 _amount,\\n uint256 _maxFeePercentage\\n ) internal pure {\\n uint256 feePercentage = _fee.mul(DECIMAL_PRECISION).div(_amount);\\n require(feePercentage <= _maxFeePercentage, \\\"Fee exceeded provided maximum\\\");\\n }\\n}\\n\",\"keccak256\":\"0x100b8a1c17caa95f5c9977e88f9263847a1977a365ca0a795753dd74aa1d6d7c\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./console.sol\\\";\\n\\nlibrary LiquityMath {\\n using SafeMath for uint;\\n\\n uint internal constant DECIMAL_PRECISION = 1e18;\\n\\n /* Precision for Nominal ICR (independent of price). Rationale for the value:\\n *\\n * - Making it \\u201ctoo high\\u201d could lead to overflows.\\n * - Making it \\u201ctoo low\\u201d could lead to an ICR equal to zero, due to truncation from Solidity floor division. \\n *\\n * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH,\\n * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.\\n *\\n */\\n uint internal constant NICR_PRECISION = 1e20;\\n\\n function _min(uint _a, uint _b) internal pure returns (uint) {\\n return (_a < _b) ? _a : _b;\\n }\\n\\n function _max(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a : _b;\\n }\\n\\n /* \\n * Multiply two decimal numbers and use normal rounding rules:\\n * -round product up if 19'th mantissa digit >= 5\\n * -round product down if 19'th mantissa digit < 5\\n *\\n * Used only inside the exponentiation, _decPow().\\n */\\n function decMul(uint x, uint y) internal pure returns (uint decProd) {\\n uint prod_xy = x.mul(y);\\n\\n decProd = prod_xy.add(DECIMAL_PRECISION / 2).div(DECIMAL_PRECISION);\\n }\\n\\n /* \\n * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.\\n * \\n * Uses the efficient \\\"exponentiation by squaring\\\" algorithm. O(log(n)) complexity. \\n * \\n * Called by two functions that represent time in units of minutes:\\n * 1) TroveManager._calcDecayedBaseRate\\n * 2) CommunityIssuance._getCumulativeIssuanceFraction \\n * \\n * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals\\n * \\\"minutes in 1000 years\\\": 60 * 24 * 365 * 1000\\n * \\n * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be\\n * negligibly different from just passing the cap, since: \\n *\\n * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years\\n * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible\\n */\\n function _decPow(uint _base, uint _minutes) internal pure returns (uint) {\\n \\n if (_minutes > 525600000) {_minutes = 525600000;} // cap to avoid overflow\\n \\n if (_minutes == 0) {return DECIMAL_PRECISION;}\\n\\n uint y = DECIMAL_PRECISION;\\n uint x = _base;\\n uint n = _minutes;\\n\\n // Exponentiation-by-squaring\\n while (n > 1) {\\n if (n % 2 == 0) {\\n x = decMul(x, x);\\n n = n.div(2);\\n } else { // if (n % 2 != 0)\\n y = decMul(x, y);\\n x = decMul(x, x);\\n n = (n.sub(1)).div(2);\\n }\\n }\\n\\n return decMul(x, y);\\n }\\n\\n function _getAbsoluteDifference(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a.sub(_b) : _b.sub(_a);\\n }\\n\\n function _computeNominalCR(uint _coll, uint _debt) internal pure returns (uint) {\\n if (_debt > 0) {\\n return _coll.mul(NICR_PRECISION).div(_debt);\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1;\\n }\\n }\\n\\n function _computeCR(uint _coll, uint _debt, uint _price) internal pure returns (uint) {\\n if (_debt > 0) {\\n uint newCollRatio = _coll.mul(_price).div(_debt);\\n\\n return newCollRatio;\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1; \\n }\\n }\\n}\\n\",\"keccak256\":\"0x7a95ed70d8937e0896c054b433ad0dfc87a9cfd028cae1694098e9d5d68127cd\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquitySafeMath128.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// uint128 addition and subtraction, with overflow protection.\\n\\nlibrary LiquitySafeMath128 {\\n function add(uint128 a, uint128 b) internal pure returns (uint128) {\\n uint128 c = a + b;\\n require(c >= a, \\\"LiquitySafeMath128: addition overflow\\\");\\n\\n return c;\\n }\\n \\n function sub(uint128 a, uint128 b) internal pure returns (uint128) {\\n require(b <= a, \\\"LiquitySafeMath128: subtraction overflow\\\");\\n uint128 c = a - b;\\n\\n return c;\\n }\\n}\",\"keccak256\":\"0x6e51d34d6fe3a2afbf5b64d1e14984a170f30247b318f62e04b9f4afdb660fc5\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IDLLR.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\nimport \\\"../IERC20.sol\\\";\\n\\n/// Public interface for Sovryn Dollar DLLR (Meta Asset Token of Sovryn Mynt) exposing specific functions\\ninterface IDLLR is IERC20 {\\n /**\\n * @notice Only owner can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _recipient Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transfer(address _recipient, uint256 _amount) external override returns (bool);\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _amount\\n ) external override returns (bool);\\n\\n /**\\n * @notice transfer utilizing EIP-2612, to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @dev By calling this function, the allowance will be overwritten by the total amount.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of the token that will be transferred.\\n * @param _deadline Expiration time of the signature.\\n * @param _v Last 1 byte of ECDSA signature.\\n * @param _r First 32 bytes of ECDSA signature.\\n * @param _s 32 bytes after _r in ECDSA signature.\\n */\\n function transferWithPermit(\\n address _from,\\n address _to,\\n uint256 _amount,\\n uint256 _deadline,\\n uint8 _v,\\n bytes32 _r,\\n bytes32 _s\\n ) external;\\n\\n /**\\n * @notice Approves and then calls the receiving contract.\\n * Useful to encapsulate sending tokens to a contract in one call.\\n * Solidity has no native way to send tokens to contracts.\\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\\n * @param _spender The contract address to spend the tokens.\\n * @param _amount The amount of tokens to be sent.\\n * @param _data Parameters for the contract call, such as endpoint signature.\\n */\\n function approveAndCall(address _spender, uint256 _amount, bytes calldata _data) external;\\n}\\n\",\"keccak256\":\"0x1fcc09759323769fcaa430bef598cf08a9f5e98ce6a9bdd6faa79d8b7b6ecce2\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IMassetManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IMassetManager {\\n struct PermitParams {\\n uint256 deadline;\\n uint8 v;\\n bytes32 r;\\n bytes32 s;\\n }\\n\\n function mintTo(\\n address _bAsset,\\n uint256 _bAssetQuantity,\\n address _recipient\\n ) external returns (uint256);\\n\\n function getToken() external view returns (address);\\n\\n /**\\n * @dev Credits a recipient with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @param _recipient Address to credit with withdrawn bAssets.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeemTo(\\n address _bAsset,\\n uint256 _massetQuantity,\\n address _recipient\\n ) external returns (uint256 massetRedeemed);\\n}\\n\",\"keccak256\":\"0x3e8de462d45e8f07ef83b6b6e7eb90a5d09f21d3bcbb1225e8f781488ab4a771\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/MyntLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IMassetManager.sol\\\";\\nimport \\\"./IDLLR.sol\\\";\\nimport \\\"../SafeMath.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"../../Interfaces/IPermit2.sol\\\";\\n\\nlibrary MyntLib {\\n using SafeMath for uint256;\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @dev WARNING!! Do not us this lib function on RSK network because there is a griefing attack issue in the DLLR contract.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _dllrAmount The amount of the DLLR (mAsset) token that will be burned in exchange for _toToken\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permitParams EIP-2612 permit params:\\n * _deadline Expiration time of the signature.\\n * _v Last 1 byte of ECDSA signature.\\n * _r First 32 bytes of ECDSA signature.\\n * _s 32 bytes after _r in ECDSA signature.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit(\\n IMassetManager _myntMassetManager,\\n uint256 _dllrAmount,\\n address _toToken,\\n IMassetManager.PermitParams calldata _permitParams\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n dllr.transferWithPermit(\\n msg.sender,\\n thisAddress,\\n _dllrAmount,\\n _permitParams.deadline,\\n _permitParams.v,\\n _permitParams.r,\\n _permitParams.s\\n );\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit via a canonical Permit2 contract\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permit permit data, in form of PermitTransferFrom struct.\\n * @param _permit2 permit2 contract address\\n * @param _signature signatue of the permit data.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit2(\\n IMassetManager _myntMassetManager,\\n address _toToken,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n IPermit2 _permit2,\\n bytes calldata _signature\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n uint256 _dllrAmount = _permit.permitted.amount;\\n\\n _permit2.permitTransferFrom(\\n _permit,\\n _generateTransferDetails(thisAddress, _dllrAmount),\\n msg.sender,\\n _signature\\n );\\n\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @dev view function to construct SignatureTransferDetails struct to be used by Permit2\\n *\\n * @param _to ultimate recipient\\n * @param _amount amount of transfer\\n *\\n * @return SignatureTransferDetails struct object \\n */\\n function _generateTransferDetails(address _to, uint256 _amount) private view returns (ISignatureTransfer.SignatureTransferDetails memory) {\\n ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer.SignatureTransferDetails({\\n to: _to,\\n requestedAmount: _amount\\n });\\n\\n return transferDetails;\\n }\\n}\\n\",\"keccak256\":\"0x6f0c78d8c4ea0b5b5e6bbe8d78374b9d2d367ffc07054dde36b9cbe2061944b6\",\"license\":\"MIT\"},\"contracts/Dependencies/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's Ownable contract:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\\n *\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable {\\n bytes32 private constant KEY_OWNER = keccak256(\\\"key.ownable.owner\\\");\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor () internal {\\n _setOwner(msg.sender);\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(msg.sender == getOwner(), \\\"Ownable:: access denied\\\");\\n _;\\n }\\n\\n /**\\n * @notice Set address of the owner.\\n * @param _owner Address of the owner.\\n * */\\n function _setOwner(address _owner) internal {\\n require(_owner != address(0), \\\"Ownable::setOwner: invalid address\\\");\\n emit OwnershipTransferred(getOwner(), _owner);\\n\\n bytes32 key = KEY_OWNER;\\n assembly {\\n sstore(key, _owner)\\n }\\n }\\n\\n /**\\n * @notice Set address of the owner (only owner can call this function)\\n * @param _owner Address of the owner.\\n * */\\n function setOwner(address _owner) public onlyOwner {\\n _setOwner(_owner);\\n }\\n\\n /**\\n * @notice Return address of the owner.\\n * @return _owner Address of the owner.\\n * */\\n function getOwner() public view returns (address _owner) {\\n bytes32 key = KEY_OWNER;\\n assembly {\\n _owner := sload(key)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xb5fc626e0b227fc0feb1d84440585015a0a5f586547d298534a604dd113efec6\",\"license\":\"MIT\"},\"contracts/Dependencies/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's SafeMath:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol\\n *\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x666b890992a066cc791f36c2975cd595d9761a014c654c385ed36ffaf658f3fd\",\"license\":\"MIT\"},\"contracts/Dependencies/console.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Buidler's helper contract for console logging\\nlibrary console {\\n\\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\\n\\n\\tfunction log() internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log()\\\"));\\n\\t\\tignored;\\n\\t}\\tfunction logInt(int p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(int)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logUint(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logString(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBool(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logAddress(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes(bytes memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logByte(byte p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(byte)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes1(bytes1 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes1)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes2(bytes2 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes2)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes3(bytes3 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes3)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes4(bytes4 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes4)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes5(bytes5 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes5)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes6(bytes6 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes6)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes7(bytes7 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes7)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes8(bytes8 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes8)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes9(bytes9 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes9)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes10(bytes10 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes10)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes11(bytes11 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes11)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes12(bytes12 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes12)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes13(bytes13 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes13)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes14(bytes14 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes14)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes15(bytes15 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes15)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes16(bytes16 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes16)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes17(bytes17 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes17)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes18(bytes18 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes18)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes19(bytes19 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes19)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes20(bytes20 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes20)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes21(bytes21 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes21)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes22(bytes22 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes22)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes23(bytes23 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes23)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes24(bytes24 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes24)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes25(bytes25 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes25)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes26(bytes26 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes26)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes27(bytes27 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes27)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes28(bytes28 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes28)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes29(bytes29 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes29)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes30(bytes30 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes30)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes31(bytes31 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes31)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes32(bytes32 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes32)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n}\\n\",\"keccak256\":\"0x6fa1de4ffe22b8f58b0b64d65db11dd5037be9b9db47b365a72adb489e217000\",\"license\":\"MIT\"},\"contracts/Interfaces/IActivePool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\n/**\\n * The Active Pool holds the ETH collateral and ZUSD debt (but not ZUSD tokens) for all active troves.\\n *\\n * When a trove is liquidated, it's ETH and ZUSD debt are transferred from the Active Pool, to either the\\n * Stability Pool, the Default Pool, or both, depending on the liquidation conditions.\\n *\\n */\\ninterface IActivePool is IPool {\\n // --- Events ---\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolZUSDDebtUpdated(uint _ZUSDDebt);\\n event ActivePoolETHBalanceUpdated(uint _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH amount to given account. Updates ActivePool balance. Only callable by BorrowerOperations, TroveManager or StabilityPool.\\n /// @param _account account to receive the ETH amount\\n /// @param _amount ETH amount to send\\n function sendETH(address _account, uint _amount) external;\\n}\\n\",\"keccak256\":\"0xdd5f1b6fae4050b4c885a85a10c2d0e73b82187a51736d009065aaeea33bf0d0\",\"license\":\"MIT\"},\"contracts/Interfaces/IAllowanceTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title AllowanceTransfer\\n/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface IAllowanceTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an ordered nonce.\\n event NonceInvalidation(\\n address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.\\n event Approval(\\n address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.\\n event Permit(\\n address indexed owner,\\n address indexed token,\\n address indexed spender,\\n uint160 amount,\\n uint48 expiration,\\n uint48 nonce\\n );\\n\\n /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.\\n event Lockdown(address indexed owner, address token, address spender);\\n\\n /// @notice The permit data for a token\\n struct PermitDetails {\\n // ERC20 token address\\n address token;\\n // the maximum amount allowed to spend\\n uint160 amount;\\n // timestamp at which a spender's token allowances become invalid\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice The permit message signed for a single token allowance\\n struct PermitSingle {\\n // the permit data for a single token alownce\\n PermitDetails details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The permit message signed for multiple token allowances\\n struct PermitBatch {\\n // the permit data for multiple token allowances\\n PermitDetails[] details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The saved permissions\\n /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n struct PackedAllowance {\\n // amount allowed\\n uint160 amount;\\n // permission expiry\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice A token spender pair.\\n struct TokenSpenderPair {\\n // the token the spender is approved\\n address token;\\n // the spender address\\n address spender;\\n }\\n\\n /// @notice Details for a token transfer.\\n struct AllowanceTransferDetails {\\n // the owner of the token\\n address from;\\n // the recipient of the token\\n address to;\\n // the amount of the token\\n uint160 amount;\\n // the token to be transferred\\n address token;\\n }\\n\\n /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.\\n /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]\\n /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.\\n function allowance(address user, address token, address spender)\\n external\\n view\\n returns (uint160 amount, uint48 expiration, uint48 nonce);\\n\\n /// @notice Approves the spender to use up to amount of the specified token up until the expiration\\n /// @param token The token to approve\\n /// @param spender The spender address to approve\\n /// @param amount The approved amount of the token\\n /// @param expiration The timestamp at which the approval is no longer valid\\n /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n function approve(address token, address spender, uint160 amount, uint48 expiration) external;\\n\\n /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitSingle Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;\\n\\n /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitBatch Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;\\n\\n /// @notice Transfer approved tokens from one address to another\\n /// @param from The address to transfer from\\n /// @param to The address of the recipient\\n /// @param amount The amount of the token to transfer\\n /// @param token The token address to transfer\\n /// @dev Requires the from address to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(address from, address to, uint160 amount, address token) external;\\n\\n /// @notice Transfer approved tokens in a batch\\n /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers\\n /// @dev Requires the from addresses to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;\\n\\n /// @notice Enables performing a \\\"lockdown\\\" of the sender's Permit2 identity\\n /// by batch revoking approvals\\n /// @param approvals Array of approvals to revoke.\\n function lockdown(TokenSpenderPair[] calldata approvals) external;\\n\\n /// @notice Invalidate nonces for a given (token, spender) pair\\n /// @param token The token to invalidate nonces for\\n /// @param spender The spender to invalidate nonces for\\n /// @param newNonce The new nonce to set. Invalidates all nonces less than it.\\n /// @dev Can't invalidate more than 2**16 nonces per transaction.\\n function invalidateNonces(address token, address spender, uint48 newNonce) external;\\n}\\n\",\"keccak256\":\"0xf15059fb68f89542908f963f22e18c0b0ae9997a6f9aaf6a9fb46aa2424acac9\",\"license\":\"MIT\"},\"contracts/Interfaces/IBorrowerOperations.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface IBorrowerOperations {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event TroveCreated(address indexed _borrower, uint256 arrayIndex);\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event ZUSDBorrowingFeePaid(address indexed _borrower, uint256 _ZUSDFee);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeDistributorAddress feeDistributor contract address\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _defaultPoolAddress DefaultPool contract address\\n * @param _stabilityPoolAddress StabilityPool contract address\\n * @param _gasPoolAddress GasPool contract address\\n * @param _collSurplusPoolAddress CollSurplusPool contract address\\n * @param _priceFeedAddress PrideFeed contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n address _feeDistributorAddress,\\n address _liquityBaseParamsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _defaultPoolAddress,\\n address _stabilityPoolAddress,\\n address _gasPoolAddress,\\n address _collSurplusPoolAddress,\\n address _priceFeedAddress,\\n address _sortedTrovesAddress,\\n address _zusdTokenAddress,\\n address _zeroStakingAddress\\n ) external;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * This method is identical to `openTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openNueTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /// @notice payable function that adds the received Ether to the caller's active Trove.\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function addColl(address _upperHint, address _lowerHint) external payable;\\n\\n /// @notice send ETH as collateral to a trove. Called by only the Stability Pool.\\n /// @param _user user trove address\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function moveETHGainToTrove(\\n address _user,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice withdraws `_amount` of collateral from the caller\\u2019s Trove.\\n * Executes only if the user has an active Trove, the withdrawal would not pull the user\\u2019s Trove below the minimum collateralization ratio,\\n * and the resulting total collateralization ratio of the system is above 150%.\\n * @param _amount collateral amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawColl(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice issues `_amount` of ZUSD from the caller\\u2019s Trove to the caller.\\n * Executes only if the Trove's collateralization ratio would remain above the minimum, and the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _amount ZUSD amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawZUSD(\\n uint256 _maxFee,\\n uint256 _amount,\\n address _upperHint,\\n address _lowerHint\\n ) external;\\n\\n /// Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction\\n function withdrawZusdAndConvertToDLLR(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external returns (uint256);\\n\\n /// @notice repay `_amount` of ZUSD to the caller\\u2019s Trove, subject to leaving 50 debt in the Trove (which corresponds to the 50 ZUSD gas compensation).\\n /// @param _amount ZUSD amount to repay\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function repayZUSD(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLR(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLRWithPermit2(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a ZUSD balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` ZUSD.\\n */\\n function closeTrove() external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTrove(IMassetManager.PermitParams calldata _permitParams) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTroveWithPermit2(ISignatureTransfer.PermitTransferFrom memory _permit, bytes calldata _signature) external;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTroveWithPermit2(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external payable;\\n\\n /**\\n * @notice when a borrower\\u2019s Trove has been fully redeemed from and closed, or liquidated in Recovery Mode with a collateralization ratio above 110%,\\n * this function allows the borrower to claim their ETH collateral surplus that remains in the system (collateral - debt upon redemption; collateral - 110% of the debt upon liquidation).\\n */\\n function claimCollateral() external;\\n\\n function getCompositeDebt(uint256 _debt) external view returns (uint256);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint256);\\n\\n function getMassetManager() external view returns (IMassetManager);\\n}\\n\",\"keccak256\":\"0x75da117f4bc4cca15fc16ca0466c68894f1befed0471ea7a670fa9b466ef2bc5\",\"license\":\"MIT\"},\"contracts/Interfaces/ICommunityIssuance.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ICommunityIssuance { \\n \\n // --- Events ---\\n \\n event SOVTokenAddressSet(address _zeroTokenAddress);\\n event ZUSDTokenAddressSet(address _zusdTokenAddress);\\n event StabilityPoolAddressSet(address _stabilityPoolAddress);\\n event PriceFeedAddressSet(address _priceFeed);\\n event RewardManagerAddressSet(address _rewardManagerAddress);\\n event APRSet(uint256 _APR);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other contracts. Callable only by owner.\\n * @dev initializer function, checks addresses are contracts\\n * @param _sovTokenAddress sov token address.\\n * @param _zusdTokenAddress zero token address.\\n * @param _stabilityPoolAddress stability pool address.\\n * @param _priceFeed price feed address.\\n * @param _APR apr in basis points.\\n */\\n function initialize(\\n address _sovTokenAddress,\\n address _zusdTokenAddress,\\n address _stabilityPoolAddress,\\n address _priceFeed,\\n uint256 _APR\\n ) external;\\n\\n /**\\n * @dev setter function to set the APR value in basis points.\\n * can only be called by reward manager.\\n * @param _APR apr value in basis points.\\n */\\n function setAPR(uint256 _APR) external;\\n\\n /**\\n * @dev setter function to set the price feed.\\n * can only be called by the owner.\\n * @param _priceFeedAddress price feed address.\\n */\\n function setPriceFeed(address _priceFeedAddress) external;\\n\\n /**\\n * @dev setter function to set reward manager.\\n * can only be called by the owner.\\n * @param _rewardManagerAddress reward manager address.\\n */\\n function setRewardManager(address _rewardManagerAddress) external;\\n\\n /// @notice issues SOV tokens based on total zusd is deposited.\\n /// @return SOV tokens issuance \\n function issueSOV(uint256 _totalZUSDDeposits) external returns (uint256);\\n\\n /// @notice sends ZERO tokens to given account\\n /// @param _account account to receive the tokens\\n /// @param _ZEROamount amount of tokens to transfer\\n function sendSOV(address _account, uint _ZEROamount) external;\\n}\\n\",\"keccak256\":\"0x39b482323f5bfa1983ab020b5a8dc805116ffceb03f2729ffbe91b164403a96a\",\"license\":\"MIT\"},\"contracts/Interfaces/IDefaultPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\ninterface IDefaultPool is IPool {\\n // --- Events ---\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event DefaultPoolZUSDDebtUpdated(uint256 _ZUSDDebt);\\n event DefaultPoolETHBalanceUpdated(uint256 _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH to Active Pool\\n /// @param _amount ETH to send\\n function sendETHToActivePool(uint256 _amount) external;\\n}\\n\",\"keccak256\":\"0xfb2607676b2eb0f2defd248b4dd32895820048317f29aa6bdb572403a3e3d44e\",\"license\":\"MIT\"},\"contracts/Interfaces/IEIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\ninterface IEIP712 {\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xff52e9168eaa532ebacdad2ab6197f60171e3aa2fa2c1d6397d9da4d7782a543\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPriceFeed.sol\\\";\\nimport \\\"./ILiquityBaseParams.sol\\\";\\n\\ninterface ILiquityBase {\\n /// @return PriceFeed contract\\n function priceFeed() external view returns (IPriceFeed);\\n\\n /// @return LiquityBaseParams contract\\n function liquityBaseParams() external view returns (ILiquityBaseParams);\\n}\\n\",\"keccak256\":\"0xa4a57bd79e64d56a687c28d2a35c55b733fde8dda2a7ba861606eed3211724e1\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBaseParams.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ILiquityBaseParams {\\n\\n /// Minimum collateral ratio for individual troves\\n function MCR() external view returns (uint);\\n\\n /// Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.\\n function CCR() external view returns (uint);\\n\\n function PERCENT_DIVISOR() external view returns (uint);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint);\\n\\n /**\\n * Half-life of 12h. 12h = 720 min\\n * (1/2) = d^720 => d = (1/2)^(1/720)\\n */\\n function REDEMPTION_FEE_FLOOR() external view returns (uint);\\n\\n function MAX_BORROWING_FEE() external view returns (uint);\\n\\n}\",\"keccak256\":\"0xef8c0e8ad5d13d604c11b04983ff5bdd41768b646f2b33f45ddd988adec204e0\",\"license\":\"MIT\"},\"contracts/Interfaces/IPermit2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {ISignatureTransfer} from \\\"./ISignatureTransfer.sol\\\";\\nimport {IAllowanceTransfer} from \\\"./IAllowanceTransfer.sol\\\";\\n\\n/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer.\\n/// @dev Users must approve Permit2 before calling any of the transfer functions.\\ninterface IPermit2 is ISignatureTransfer, IAllowanceTransfer {\\n// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval.\\n}\\n\",\"keccak256\":\"0x3df819f5ca8de7324a676839d72e9f44c0f789c41c13bf0a892f3bb98d72ee86\",\"license\":\"MIT\"},\"contracts/Interfaces/IPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the Pools.\\ninterface IPool {\\n // --- Events ---\\n\\n event ETHBalanceUpdated(uint _newBalance);\\n event ZUSDBalanceUpdated(uint _newBalance);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event EtherSent(address _to, uint _amount);\\n\\n // --- Functions ---\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH pool balance\\n function getETH() external view returns (uint);\\n\\n /// @return ZUSD debt pool balance\\n function getZUSDDebt() external view returns (uint);\\n\\n /// @notice Increases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to add to the pool debt\\n function increaseZUSDDebt(uint _amount) external;\\n\\n /// @notice Decreases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to subtract to the pool debt\\n function decreaseZUSDDebt(uint _amount) external;\\n}\\n\",\"keccak256\":\"0x148e87ab38c6176d74f36c9e8989b99e768a7b18d8a045f1f01d6583b986806d\",\"license\":\"MIT\"},\"contracts/Interfaces/IPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IPriceFeed {\\n // --- Events ---\\n event LastGoodPriceUpdated(uint256 _lastGoodPrice);\\n\\n // --- Function ---\\n\\n /// @notice Returns the latest price obtained from the Oracle. Called by Zero functions that require a current price.\\n /// It uses the main price feed and fallback to the backup one in case of an error. If both fail return the last\\n /// good price seen.\\n /// @dev It's also callable by anyone externally\\n /// @return The price\\n function fetchPrice() external returns (uint256);\\n}\\n\",\"keccak256\":\"0x85fd97219a8156209d2cb5c6ae7c5ead01d893db000bf575023fcef0e62f9591\",\"license\":\"MIT\"},\"contracts/Interfaces/ISignatureTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title SignatureTransfer\\n/// @notice Handles ERC20 token transfers through signature based actions\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface ISignatureTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an unordered nonce.\\n event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);\\n\\n /// @notice The token and amount details for a transfer signed in the permit transfer signature\\n struct TokenPermissions {\\n // ERC20 token address\\n address token;\\n // the maximum amount that can be spent\\n uint256 amount;\\n }\\n\\n /// @notice The signed permit message for a single token transfer\\n struct PermitTransferFrom {\\n TokenPermissions permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice Specifies the recipient address and amount for batched transfers.\\n /// @dev Recipients and amounts correspond to the index of the signed token permissions array.\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount.\\n struct SignatureTransferDetails {\\n // recipient address\\n address to;\\n // spender requested amount\\n uint256 requestedAmount;\\n }\\n\\n /// @notice Used to reconstruct the signed permit message for multiple token transfers\\n /// @dev Do not need to pass in spender address as it is required that it is msg.sender\\n /// @dev Note that a user still signs over a spender address\\n struct PermitBatchTransferFrom {\\n // the tokens and corresponding amounts permitted for a transfer\\n TokenPermissions[] permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection\\n /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order\\n /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce\\n /// @dev It returns a uint256 bitmap\\n /// @dev The index, or wordPosition is capped at type(uint248).max\\n function nonceBitmap(address, uint256) external view returns (uint256);\\n\\n /// @notice Transfers a token using a signed permit message\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails The spender's requested transfer details for the permitted token\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitTransferFrom memory permit,\\n SignatureTransferDetails calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Transfers multiple tokens using a signed permit message\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails Specifies the recipient and requested amount for the token transfer\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitBatchTransferFrom memory permit,\\n SignatureTransferDetails[] calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Invalidates the bits specified in mask for the bitmap at the word position\\n /// @dev The wordPos is maxed at type(uint248).max\\n /// @param wordPos A number to index the nonceBitmap at\\n /// @param mask A bitmap masked against msg.sender's current bitmap at the word position\\n function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;\\n}\\n\",\"keccak256\":\"0x7efc63c119694e23dd76e44a5b125999829026bbc23409de7646a6a45e1ac341\",\"license\":\"MIT\"},\"contracts/Interfaces/ISortedTroves.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the SortedTroves Doubly Linked List.\\ninterface ISortedTroves {\\n // --- Events ---\\n\\n event SortedTrovesAddressChanged(address _sortedDoublyLLAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event NodeAdded(address _id, uint256 _NICR);\\n event NodeRemoved(address _id);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts and size. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _size max size of troves list\\n * @param _TroveManagerAddress TroveManager contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n */\\n function setParams(\\n uint256 _size,\\n address _TroveManagerAddress,\\n address _borrowerOperationsAddress\\n ) external;\\n\\n /**\\n * @dev Add a node to the list\\n * @param _id Node's id\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function insert(\\n address _id,\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Remove a node from the list\\n * @param _id Node's id\\n */\\n function remove(address _id) external;\\n\\n /**\\n * @dev Re-insert the node at a new position, based on its new NICR\\n * @param _id Node's id\\n * @param _newICR Node's new NICR\\n * @param _prevId Id of previous node for the new insert position\\n * @param _nextId Id of next node for the new insert position\\n */\\n function reInsert(\\n address _id,\\n uint256 _newICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Checks if the list contains a node\\n * @param _id Node's id\\n * @return true if list contains a node with given id\\n */\\n function contains(address _id) external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is full\\n * @return true if list is full\\n */\\n function isFull() external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is empty\\n * @return true if list is empty\\n */\\n function isEmpty() external view returns (bool);\\n\\n /**\\n * @return list current size\\n */\\n function getSize() external view returns (uint256);\\n\\n /**\\n * @return list max size\\n */\\n function getMaxSize() external view returns (uint256);\\n\\n /**\\n * @return the first node in the list (node with the largest NICR)\\n */\\n function getFirst() external view returns (address);\\n\\n /**\\n * @return the last node in the list (node with the smallest NICR)\\n */\\n function getLast() external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the next node (with a smaller NICR) in the list for a given node\\n */\\n function getNext(address _id) external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the previous node (with a larger NICR) in the list for a given node\\n */\\n function getPrev(address _id) external view returns (address);\\n\\n /**\\n * @notice Check if a pair of nodes is a valid insertion point for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function validInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (bool);\\n\\n /**\\n * @notice Find the insert position for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function findInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (address, address);\\n}\\n\",\"keccak256\":\"0x7328ad009da6230ddea1559564428464a5c3ace2258fb534dfbba5b5a8c7c60d\",\"license\":\"MIT\"},\"contracts/Interfaces/IStabilityPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/*\\n * The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors.\\n *\\n * When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with\\n * ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned.\\n *\\n * Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits.\\n * They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors,\\n * in the same proportion.\\n *\\n * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40%\\n * of the total ZUSD in the Stability Pool, depletes 40% of each deposit.\\n *\\n * A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit,\\n * multiplying it by some factor in range ]0,1[\\n *\\n * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations:\\n * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf\\n *\\n * --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS ---\\n *\\n * An SOV issuance event occurs at every deposit operation, and every liquidation.\\n *\\n * Each deposit is tagged with the address of the front end through which it was made.\\n *\\n * All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned\\n * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate.\\n *\\n * Please see the system Readme for an overview:\\n * https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers\\n */\\ninterface IStabilityPool {\\n // --- Events ---\\n\\n event StabilityPoolETHBalanceUpdated(uint _newBalance);\\n event StabilityPoolZUSDBalanceUpdated(uint _newBalance);\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event SortedTrovesAddressChanged(address _newSortedTrovesAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);\\n\\n event P_Updated(uint _P);\\n event S_Updated(uint _S, uint128 _epoch, uint128 _scale);\\n event G_Updated(uint _G, uint128 _epoch, uint128 _scale);\\n event EpochUpdated(uint128 _currentEpoch);\\n event ScaleUpdated(uint128 _currentScale);\\n\\n event FrontEndRegistered(address indexed _frontEnd, uint _kickbackRate);\\n event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd);\\n\\n event DepositSnapshotUpdated(address indexed _depositor, uint _P, uint _S, uint _G);\\n event FrontEndSnapshotUpdated(address indexed _frontEnd, uint _P, uint _G);\\n event UserDepositChanged(address indexed _depositor, uint _newDeposit);\\n event FrontEndStakeChanged(\\n address indexed _frontEnd,\\n uint _newFrontEndStake,\\n address _depositor\\n );\\n\\n event ETHGainWithdrawn(address indexed _depositor, uint _ETH, uint _ZUSDLoss);\\n event SOVPaidToDepositor(address indexed _depositor, uint _SOV);\\n event SOVPaidToFrontEnd(address indexed _frontEnd, uint _SOV);\\n event EtherSent(address _to, uint _amount);\\n\\n event WithdrawFromSpAndConvertToDLLR(\\n address _depositor,\\n uint256 _zusdAmountRequested,\\n uint256 _dllrAmountReceived\\n );\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Liquity contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _priceFeedAddress PriceFeed contract address\\n * @param _communityIssuanceAddress CommunityIssuanceAddress\\n */\\n function setAddresses(\\n address _liquityBaseParamsAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _zusdTokenAddress,\\n address _sortedTrovesAddress,\\n address _priceFeedAddress,\\n address _communityIssuanceAddress\\n ) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend is registered or zero address\\n * - Sender is not a registered frontend\\n * - _amount is not zero\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Tags the deposit with the provided front end tag param, if it's a new deposit\\n * - Sends depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Increases deposit and tagged front end's stake, and takes new snapshots for each.\\n * @param _amount amount to provide\\n * @param _frontEndTag frontend address to receive accumulated SOV gains\\n */\\n function provideToSP(uint _amount, address _frontEndTag) external;\\n\\n /**\\n * @notice Initial checks:\\n * - _amount is zero or there are no under collateralized troves left in the system\\n * - User has a non zero deposit\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Removes the deposit's front end tag if it is a full withdrawal\\n * - Sends all depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.\\n *\\n * If _amount > userDeposit, the user withdraws all of their compounded deposit.\\n * @param _amount amount to withdraw\\n */\\n function withdrawFromSP(uint _amount) external;\\n\\n /**\\n * @notice Initial checks:\\n * - User has a non zero deposit\\n * - User has an open trove\\n * - User has some ETH gain\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Sends all depositor's SOV gain to depositor\\n * - Sends all tagged front end's SOV gain to the tagged front end\\n * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove\\n * - Leaves their compounded deposit in the Stability Pool\\n * - Updates snapshots for deposit and tagged front end stake\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend (sender) not already registered\\n * - User (sender) has no deposit\\n * - _kickbackRate is in the range [0, 100%]\\n * ---\\n * Front end makes a one-time selection of kickback rate upon registering\\n * @param _kickbackRate kickback rate selected by frontend\\n */\\n function registerFrontEnd(uint _kickbackRate) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Caller is TroveManager\\n * ---\\n * Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible)\\n * and transfers the Trove's ETH collateral from ActivePool to StabilityPool.\\n * Only called by liquidation functions in the TroveManager.\\n * @param _debt debt to cancel\\n * @param _coll collateral to transfer\\n */\\n function offset(uint _debt, uint _coll) external;\\n\\n /**\\n * @return the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`,\\n * to exclude edge cases like ETH received from a self-destruct.\\n */\\n function getETH() external view returns (uint);\\n\\n /**\\n * @return ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\\n */\\n function getTotalZUSDDeposits() external view returns (uint);\\n\\n /**\\n * @notice Calculates the ETH gain earned by the deposit since its last snapshots were taken.\\n * @param _depositor address to calculate ETH gain\\n * @return ETH gain from given depositor\\n */\\n function getDepositorETHGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice Calculate the SOV gain earned by a deposit since its last snapshots were taken.\\n * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned.\\n * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through\\n * which they made their deposit.\\n * @param _depositor address to calculate ETH gain\\n * @return SOV gain from given depositor\\n */\\n function getDepositorSOVGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @param _frontEnd front end address\\n * @return the SOV gain earned by the front end.\\n */\\n function getFrontEndSOVGain(address _frontEnd) external view returns (uint);\\n\\n /**\\n * @param _depositor depositor address\\n * @return the user's compounded deposit.\\n */\\n function getCompoundedZUSDDeposit(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\\n * @param _frontEnd front end address\\n * @return the front end's compounded stake.\\n */\\n function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint);\\n\\n //DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDLLR(\\n uint _dllrAmount,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function provideToSpFromDllrWithPermit2(\\n uint256 _dllrAmount,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /// Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and optionally convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\\n function withdrawFromSpAndConvertToDLLR(uint256 _zusdAmount) external;\\n\\n /**\\n * Fallback function\\n * Only callable by Active Pool, it just accounts for ETH received\\n * receive() external payable;\\n */\\n}\\n\",\"keccak256\":\"0xb35c5ec991dd2b4f8ecb6b28ae29e97313fca6054aa0df14ebdb7336fcea84a6\",\"license\":\"MIT\"},\"contracts/Interfaces/ITroveManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./ILiquityBase.sol\\\";\\nimport \\\"./IStabilityPool.sol\\\";\\nimport \\\"./IZUSDToken.sol\\\";\\nimport \\\"./IZEROToken.sol\\\";\\nimport \\\"./IZEROStaking.sol\\\";\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface ITroveManager is ILiquityBase {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerRedeemOpsAddressChanged(address _troveManagerRedeemOps);\\n event LiquityBaseParamsAddressChanges(address _borrowerOperationsAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZEROTokenAddressChanged(address _zeroTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event Liquidation(\\n uint256 _liquidatedDebt,\\n uint256 _liquidatedColl,\\n uint256 _collGasCompensation,\\n uint256 _ZUSDGasCompensation\\n );\\n event Redemption(\\n uint256 _attemptedZUSDAmount,\\n uint256 _actualZUSDAmount,\\n uint256 _ETHSent,\\n uint256 _ETHFee\\n );\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event TroveLiquidated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint8 operation\\n );\\n event BaseRateUpdated(uint256 _baseRate);\\n event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);\\n event TotalStakesUpdated(uint256 _newTotalStakes);\\n event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);\\n event LTermsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveIndexUpdated(address _borrower, uint256 _newIndex);\\n\\n struct TroveManagerInitAddressesParams {\\n address _feeDistributorAddress;\\n address _troveManagerRedeemOps;\\n address _liquityBaseParamsAddress;\\n address _borrowerOperationsAddress;\\n address _activePoolAddress;\\n address _defaultPoolAddress;\\n address _stabilityPoolAddress;\\n address _gasPoolAddress;\\n address _collSurplusPoolAddress;\\n address _priceFeedAddress;\\n address _zusdTokenAddress;\\n address _sortedTrovesAddress;\\n address _zeroTokenAddress;\\n address _zeroStakingAddress;\\n }\\n\\n // --- Functions ---\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _troveManagerInitAddresses addresses list to intialize TroveManager with _\\n * _feeDistributorAddress feeDistributor contract address\\n * _troveManagerRedeemOps TroveManagerRedeemOps contract address\\n * _liquityBaseParamsAddress LiquityBaseParams contract address\\n * _borrowerOperationsAddress BorrowerOperations contract address\\n * _activePoolAddress ActivePool contract address\\n * _defaultPoolAddress DefaultPool contract address\\n * _stabilityPoolAddress StabilityPool contract address\\n * _gasPoolAddress GasPool contract address\\n * _collSurplusPoolAddress CollSurplusPool contract address\\n * _priceFeedAddress PriceFeed contract address\\n * _zusdTokenAddress ZUSDToken contract address\\n * _sortedTrovesAddress SortedTroves contract address\\n * _zeroTokenAddress ZEROToken contract address\\n * _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n TroveManagerInitAddressesParams memory _troveManagerInitAddresses\\n ) external;\\n\\n function setTroveManagerRedeemOps(address _troveManagerRedeemOps) external;\\n\\n /// @return Trove owners count\\n function getTroveOwnersCount() external view returns (uint256);\\n\\n /// @param _index Trove owner index\\n /// @return Trove from TroveOwners array in given index\\n function getTroveFromTroveOwnersArray(uint256 _index) external view returns (address);\\n\\n /// @param _borrower borrower address\\n /// @return the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getNominalICR(address _borrower) external view returns (uint256);\\n\\n /// @notice computes the user\\u2019s individual collateralization ratio (ICR) based on their total collateral and total ZUSD debt. Returns 2^256 -1 if they have 0 debt.\\n /// @param _borrower borrower address\\n /// @param _price ETH price\\n /// @return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getCurrentICR(address _borrower, uint256 _price) external view returns (uint256);\\n\\n /// @notice Closes the trove if its ICR is lower than the minimum collateral ratio.\\n /// @param _borrower borrower address\\n function liquidate(address _borrower) external;\\n\\n /**\\n * @notice Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves,\\n * starting from the one with the lowest collateral ratio in the system, and moving upwards\\n * @param _n max number of under-collateralized Troves to liquidate\\n */\\n function liquidateTroves(uint256 _n) external;\\n\\n /**\\n * @notice Attempt to liquidate a custom list of troves provided by the caller.\\n * @param _troveArray list of trove addresses\\n */\\n function batchLiquidateTroves(address[] calldata _troveArray) external;\\n\\n /**\\n * @notice Send _ZUSDamount ZUSD to the system and redeem the corresponding amount of collateral from as many Troves as are needed to fill the redemption\\n * request. Applies pending rewards to a Trove before reducing its debt and coll.\\n *\\n * Note that if _amount is very large, this function can run out of gas, specially if traversed troves are small. This can be easily avoided by\\n * splitting the total _amount in appropriate chunks and calling the function multiple times.\\n *\\n * Param `_maxIterations` can also be provided, so the loop through Troves is capped (if it\\u2019s zero, it will be ignored).This makes it easier to\\n * avoid OOG for the frontend, as only knowing approximately the average cost of an iteration is enough, without needing to know the \\u201ctopology\\u201d\\n * of the trove list. It also avoids the need to set the cap in stone in the contract, nor doing gas calculations, as both gas price and opcode\\n * costs can vary.\\n *\\n * All Troves that are redeemed from -- with the likely exception of the last one -- will end up with no debt left, therefore they will be closed.\\n * If the last Trove does have some remaining debt, it has a finite ICR, and the reinsertion could be anywhere in the list, therefore it requires a hint.\\n * A frontend should use getRedemptionHints() to calculate what the ICR of this Trove will be after redemption, and pass a hint for its position\\n * in the sortedTroves list along with the ICR value that the hint was found for.\\n *\\n * If another transaction modifies the list between calling getRedemptionHints() and passing the hints to redeemCollateral(), it\\n * is very likely that the last (partially) redeemed Trove would end up with a different ICR than what the hint is for. In this case the\\n * redemption will stop after the last completely redeemed Trove and the sender will keep the remaining ZUSD amount, which they can attempt\\n * to redeem later.\\n *\\n * @param _ZUSDAmount ZUSD amount to send to the system\\n * @param _firstRedemptionHint calculated ICR hint of first trove after redemption\\n * @param _maxIterations max Troves iterations (can be 0)\\n * @param _maxFee max fee percentage to accept\\n */\\n function redeemCollateral(\\n uint256 _ZUSDAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFee\\n ) external;\\n\\n function redeemCollateralViaDLLR(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function redeemCollateralViaDllrWithPermit2(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n \\n\\n /// @notice Update borrower's stake based on their latest collateral value\\n /// @param _borrower borrower address\\n function updateStakeAndTotalStakes(address _borrower) external returns (uint256);\\n\\n /// @notice Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values\\n /// @param _borrower borrower address\\n function updateTroveRewardSnapshots(address _borrower) external;\\n\\n /// @notice Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct\\n /// @param _borrower borrower address\\n /// @return index where Trove was inserted\\n function addTroveOwnerToArray(address _borrower) external returns (uint256 index);\\n\\n /// @notice Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\\n /// @param _borrower borrower address\\n function applyPendingRewards(address _borrower) external;\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ETH reward, earned by their stake\\n function getPendingETHReward(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ZUSD reward, earned by their stake\\n function getPendingZUSDDebtReward(address _borrower) external view returns (uint256);\\n\\n /*\\n * @notice A Trove has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:\\n * this indicates that rewards have occured since the snapshot was made, and the user therefore has\\n * pending rewards\\n *\\n * @param _borrower borrower address\\n * @return true if has pending rewards\\n */\\n function hasPendingRewards(address _borrower) external view returns (bool);\\n\\n /// @notice returns the Troves entire debt and coll, including pending rewards from redistributions.\\n /// @param _borrower borrower address\\n function getEntireDebtAndColl(\\n address _borrower\\n )\\n external\\n view\\n returns (\\n uint256 debt,\\n uint256 coll,\\n uint256 pendingZUSDDebtReward,\\n uint256 pendingETHReward\\n );\\n\\n /// @notice Close given trove. Called by BorrowerOperations.\\n /// @param _borrower borrower address\\n function closeTrove(address _borrower) external;\\n\\n /// @notice Remove borrower's stake from the totalStakes sum, and set their stake to 0\\n /// @param _borrower borrower address\\n function removeStake(address _borrower) external;\\n\\n /// @return calculated redemption rate using baseRate\\n function getRedemptionRate() external view returns (uint256);\\n\\n /// @return calculated redemption rate using calculated decayed as base rate\\n function getRedemptionRateWithDecay() external view returns (uint256);\\n\\n /// @notice The redemption fee is taken as a cut of the total ETH drawn from the system in a redemption. It is based on the current redemption rate.\\n /// @param _ETHDrawn ETH drawn\\n function getRedemptionFeeWithDecay(uint256 _ETHDrawn) external view returns (uint256);\\n\\n /// @return borrowing rate\\n function getBorrowingRate() external view returns (uint256);\\n\\n /// @return borrowing rate calculated using decayed as base rate\\n function getBorrowingRateWithDecay() external view returns (uint256);\\n\\n /// @param ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate\\n function getBorrowingFee(uint256 ZUSDDebt) external view returns (uint256);\\n\\n /// @param _ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate with decay\\n function getBorrowingFeeWithDecay(uint256 _ZUSDDebt) external view returns (uint256);\\n\\n /// @notice Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation.\\n function decayBaseRateFromBorrowing() external;\\n\\n /// @param _borrower borrower address\\n /// @return Trove status from given trove\\n function getTroveStatus(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove stake from given trove\\n function getTroveStake(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove debt from given trove\\n function getTroveDebt(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove collateral from given trove\\n function getTroveColl(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param num status to set\\n function setTroveStatus(address _borrower, uint256 num) external;\\n\\n /// @param _borrower borrower address\\n /// @param _collIncrease amount of collateral to increase\\n /// @return new trove collateral\\n function increaseTroveColl(\\n address _borrower,\\n uint256 _collIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _collDecrease amount of collateral to decrease\\n /// @return new trove collateral\\n function decreaseTroveColl(\\n address _borrower,\\n uint256 _collDecrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtIncrease amount of debt to increase\\n /// @return new trove debt\\n function increaseTroveDebt(\\n address _borrower,\\n uint256 _debtIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtDecrease amount of debt to decrease\\n /// @return new trove debt\\n function decreaseTroveDebt(\\n address _borrower,\\n uint256 _debtDecrease\\n ) external returns (uint256);\\n\\n /**\\n * @param _price ETH price\\n * @return the total collateralization ratio (TCR) of the system.\\n * The TCR is based on the the entire system debt and collateral (including pending rewards).\\n */\\n function getTCR(uint256 _price) external view returns (uint256);\\n\\n function MCR() external view returns (uint256);\\n\\n function CCR() external view returns (uint256);\\n\\n /// @notice reveals whether or not the system is in Recovery Mode (i.e. whether the Total Collateralization Ratio (TCR) is below the Critical Collateralization Ratio (CCR)).\\n function checkRecoveryMode(uint256 _price) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x396367eb7763c289e419a025532150e2a1d9d99eead359ceb6a081787501a00b\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROStaking.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IZEROStaking {\\n // --- Events --\\n\\n event ZEROTokenAddressSet(address _zeroTokenAddress);\\n event ZUSDTokenAddressSet(address _zusdTokenAddress);\\n event FeeDistributorAddressAddressSet(address _feeDistributorAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event StakeChanged(address indexed staker, uint256 newStake);\\n event StakingGainsWithdrawn(address indexed staker, uint256 ZUSDGain, uint256 ETHGain);\\n event F_ETHUpdated(uint256 _F_ETH);\\n event F_ZUSDUpdated(uint256 _F_ZUSD);\\n event TotalZEROStakedUpdated(uint256 _totalZEROStaked);\\n event EtherSent(address _account, uint256 _amount);\\n event StakerSnapshotsUpdated(address _staker, uint256 _F_ETH, uint256 _F_ZUSD);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _zeroTokenAddress ZEROToken contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _feeDistributorAddress FeeDistributorAddress contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _zeroTokenAddress,\\n address _zusdTokenAddress,\\n address _feeDistributorAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice If caller has a pre-existing stake, send any accumulated ETH and ZUSD gains to them.\\n /// @param _ZEROamount ZERO tokens to stake\\n function stake(uint256 _ZEROamount) external;\\n\\n /**\\n * @notice Unstake the ZERO and send the it back to the caller, along with their accumulated ZUSD & ETH gains.\\n * If requested amount > stake, send their entire stake.\\n * @param _ZEROamount ZERO tokens to unstake\\n */\\n function unstake(uint256 _ZEROamount) external;\\n\\n /// @param _ETHFee ETH fee\\n /// @notice increase ETH fee\\n function increaseF_ETH(uint256 _ETHFee) external;\\n\\n /// @param _ZEROFee ZUSD fee\\n /// @notice increase ZUSD fee\\n function increaseF_ZUSD(uint256 _ZEROFee) external;\\n\\n /// @param _user user address\\n /// @return pending ETH gain of given user\\n function getPendingETHGain(address _user) external view returns (uint256);\\n\\n /// @param _user user address\\n /// @return pending ZUSD gain of given user\\n function getPendingZUSDGain(address _user) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x4c7948ce7dff9ea9b8495054e511eabcf44a91c7db8520ec58ff2a002327e0c5\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZEROToken is IERC20, IERC2612 { \\n\\n // --- Functions ---\\n\\n /// @notice send zero tokens to ZEROStaking contract\\n /// @param _sender sender address\\n /// @param _amount amount to send\\n function sendToZEROStaking(address _sender, uint256 _amount) external;\\n\\n /// @return deployment start time\\n function getDeploymentStartTime() external view returns (uint256);\\n\\n}\\n\",\"keccak256\":\"0xbcc0baabe4c4686563a09cf1486f2d152b70404996676a89d525691f69637f66\",\"license\":\"MIT\"},\"contracts/Interfaces/IZUSDToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZUSDToken is IERC20, IERC2612 { \\n \\n // --- Events ---\\n\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n\\n event ZUSDTokenBalanceUpdated(address _user, uint _amount);\\n\\n // --- Functions ---\\n\\n function mint(address _account, uint256 _amount) external;\\n\\n function burn(address _account, uint256 _amount) external;\\n\\n function sendToPool(address _sender, address poolAddress, uint256 _amount) external;\\n\\n function returnFromPool(address poolAddress, address user, uint256 _amount ) external;\\n}\\n\",\"keccak256\":\"0xe52df063aa08f709640c28888edd27310c820f6d08564855538ae245eb2f5a8c\",\"license\":\"MIT\"},\"contracts/StabilityPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./Interfaces/IStabilityPool.sol\\\";\\nimport \\\"./Interfaces/ITroveManager.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/ICommunityIssuance.sol\\\";\\nimport \\\"./Dependencies/LiquityBase.sol\\\";\\nimport \\\"./Dependencies/LiquitySafeMath128.sol\\\";\\nimport \\\"./Dependencies/CheckContract.sol\\\";\\nimport \\\"./Dependencies/Mynt/MyntLib.sol\\\";\\nimport \\\"./StabilityPoolStorage.sol\\\";\\nimport \\\"./Interfaces/IPermit2.sol\\\";\\n\\n/**\\n * The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors.\\n *\\n * When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with\\n * ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned.\\n *\\n * Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits.\\n * They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors,\\n * in the same proportion.\\n *\\n * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40%\\n * of the total ZUSD in the Stability Pool, depletes 40% of each deposit.\\n *\\n * A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit,\\n * multiplying it by some factor in range ]0,1[\\n *\\n *\\n * --- IMPLEMENTATION ---\\n *\\n * We use a highly scalable method of tracking deposits and ETH gains that has O(1) complexity.\\n *\\n * When a liquidation occurs, rather than updating each depositor's deposit and ETH gain, we simply update two state variables:\\n * a product P, and a sum S.\\n *\\n * A mathematical manipulation allows us to factor out the initial deposit, and accurately track all depositors' compounded deposits\\n * and accumulated ETH gains over time, as liquidations occur, using just these two variables P and S. When depositors join the\\n * Stability Pool, they get a snapshot of the latest P and S: P_t and S_t, respectively.\\n *\\n * The formula for a depositor's accumulated ETH gain is derived here:\\n * https://github.com/liquity/dev/blob/main/packages/contracts/mathProofs/Scalable%20Compounding%20Stability%20Pool%20Deposits.pdf\\n *\\n * For a given deposit d_t, the ratio P/P_t tells us the factor by which a deposit has decreased since it joined the Stability Pool,\\n * and the term d_t * (S - S_t)/P_t gives us the deposit's total accumulated ETH gain.\\n *\\n * Each liquidation updates the product P and sum S. After a series of liquidations, a compounded deposit and corresponding ETH gain\\n * can be calculated using the initial deposit, the depositor\\u2019s snapshots of P and S, and the latest values of P and S.\\n *\\n * Any time a depositor updates their deposit (withdrawal, top-up) their accumulated ETH gain is paid out, their new deposit is recorded\\n * (based on their latest compounded deposit and modified by the withdrawal/top-up), and they receive new snapshots of the latest P and S.\\n * Essentially, they make a fresh deposit that overwrites the old one.\\n *\\n *\\n * --- SCALE FACTOR ---\\n *\\n * Since P is a running product in range ]0,1] that is always-decreasing, it should never reach 0 when multiplied by a number in range ]0,1[.\\n * Unfortunately, Solidity floor division always reaches 0, sooner or later.\\n *\\n * A series of liquidations that nearly empty the Pool (and thus each multiply P by a very small number in range ]0,1[ ) may push P\\n * to its 18 digit decimal limit, and round it to 0, when in fact the Pool hasn't been emptied: this would break deposit tracking.\\n *\\n * So, to track P accurately, we use a scale factor: if a liquidation would cause P to decrease to <1e-9 (and be rounded to 0 by Solidity),\\n * we first multiply P by 1e9, and increment a currentScale factor by 1.\\n *\\n * The added benefit of using 1e9 for the scale factor (rather than 1e18) is that it ensures negligible precision loss close to the\\n * scale boundary: when P is at its minimum value of 1e9, the relative precision loss in P due to floor division is only on the\\n * order of 1e-9.\\n *\\n * --- EPOCHS ---\\n *\\n * Whenever a liquidation fully empties the Stability Pool, all deposits should become 0. However, setting P to 0 would make P be 0\\n * forever, and break all future reward calculations.\\n *\\n * So, every time the Stability Pool is emptied by a liquidation, we reset P = 1 and currentScale = 0, and increment the currentEpoch by 1.\\n *\\n * --- TRACKING DEPOSIT OVER SCALE CHANGES AND EPOCHS ---\\n *\\n * When a deposit is made, it gets snapshots of the currentEpoch and the currentScale.\\n *\\n * When calculating a compounded deposit, we compare the current epoch to the deposit's epoch snapshot. If the current epoch is newer,\\n * then the deposit was present during a pool-emptying liquidation, and necessarily has been depleted to 0.\\n *\\n * Otherwise, we then compare the current scale to the deposit's scale snapshot. If they're equal, the compounded deposit is given by d_t * P/P_t.\\n * If it spans one scale change, it is given by d_t * P/(P_t * 1e9). If it spans more than one scale change, we define the compounded deposit\\n * as 0, since it is now less than 1e-9'th of its initial value (e.g. a deposit of 1 billion ZUSD has depleted to < 1 ZUSD).\\n *\\n *\\n * --- TRACKING DEPOSITOR'S ETH GAIN OVER SCALE CHANGES AND EPOCHS ---\\n *\\n * In the current epoch, the latest value of S is stored upon each scale change, and the mapping (scale -> S) is stored for each epoch.\\n *\\n * This allows us to calculate a deposit's accumulated ETH gain, during the epoch in which the deposit was non-zero and earned ETH.\\n *\\n * We calculate the depositor's accumulated ETH gain for the scale at which they made the deposit, using the ETH gain formula:\\n * e_1 = d_t * (S - S_t) / P_t\\n *\\n * and also for scale after, taking care to divide the latter by a factor of 1e9:\\n * e_2 = d_t * S / (P_t * 1e9)\\n *\\n * The gain in the second scale will be full, as the starting point was in the previous scale, thus no need to subtract anything.\\n * The deposit therefore was present for reward events from the beginning of that second scale.\\n *\\n * S_i-S_t + S_{i+1}\\n * .<--------.------------>\\n * . .\\n * . S_i . S_{i+1}\\n * <--.-------->.<----------->\\n * S_t. .\\n * <->. .\\n * t .\\n * |---+---------|-------------|-----...\\n * i i+1\\n *\\n * The sum of (e_1 + e_2) captures the depositor's total accumulated ETH gain, handling the case where their\\n * deposit spanned one scale change. We only care about gains across one scale change, since the compounded\\n * deposit is defined as being 0 once it has spanned more than one scale change.\\n *\\n *\\n * --- UPDATING P WHEN A LIQUIDATION OCCURS ---\\n *\\n * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations:\\n * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf\\n *\\n *\\n * --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS ---\\n *\\n * An SOV issuance event occurs at every deposit operation, and every liquidation.\\n *\\n * Each deposit is tagged with the address of the front end through which it was made.\\n *\\n * All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned\\n * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate.\\n *\\n * Please see the system Readme for an overview:\\n * https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers\\n *\\n * We use the same mathematical product-sum approach to track SOV gains for depositors, where 'G' is the sum corresponding to SOV gains.\\n * The product P (and snapshot P_t) is re-used, as the ratio P/P_t tracks a deposit's depletion due to liquidations.\\n *\\n */\\ncontract StabilityPool is LiquityBase, StabilityPoolStorage, CheckContract, IStabilityPool {\\n using LiquitySafeMath128 for uint128;\\n address private constant ADDRESS_ZERO = address(0);\\n IPermit2 public immutable permit2;\\n\\n // --- Events ---\\n\\n event StabilityPoolETHBalanceUpdated(uint256 _newBalance);\\n event StabilityPoolZUSDBalanceUpdated(uint256 _newBalance);\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event SortedTrovesAddressChanged(address _newSortedTrovesAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);\\n\\n event P_Updated(uint256 _P);\\n event S_Updated(uint256 _S, uint128 _epoch, uint128 _scale);\\n event G_Updated(uint256 _G, uint128 _epoch, uint128 _scale);\\n event EpochUpdated(uint128 _currentEpoch);\\n event ScaleUpdated(uint128 _currentScale);\\n\\n event FrontEndRegistered(address indexed _frontEnd, uint256 _kickbackRate);\\n event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd);\\n\\n event DepositSnapshotUpdated(address indexed _depositor, uint256 _P, uint256 _S, uint256 _G);\\n event FrontEndSnapshotUpdated(address indexed _frontEnd, uint256 _P, uint256 _G);\\n event UserDepositChanged(address indexed _depositor, uint256 _newDeposit);\\n event FrontEndStakeChanged(\\n address indexed _frontEnd,\\n uint256 _newFrontEndStake,\\n address _depositor\\n );\\n\\n event ETHGainWithdrawn(address indexed _depositor, uint256 _ETH, uint256 _ZUSDLoss);\\n event SOVPaidToDepositor(address indexed _depositor, uint256 _SOV);\\n event SOVPaidToFrontEnd(address indexed _frontEnd, uint256 _SOV);\\n event EtherSent(address _to, uint256 _amount);\\n\\n /** Constructor */\\n constructor(address _permit2) public {\\n permit2 = IPermit2(_permit2);\\n }\\n\\n // --- Contract setters ---\\n\\n function setAddresses(\\n address _liquityBaseParamsAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _zusdTokenAddress,\\n address _sortedTrovesAddress,\\n address _priceFeedAddress,\\n address _communityIssuanceAddress\\n ) external override onlyOwner {\\n checkContract(_liquityBaseParamsAddress);\\n checkContract(_borrowerOperationsAddress);\\n checkContract(_troveManagerAddress);\\n checkContract(_activePoolAddress);\\n checkContract(_zusdTokenAddress);\\n checkContract(_sortedTrovesAddress);\\n checkContract(_priceFeedAddress);\\n checkContract(_communityIssuanceAddress);\\n\\n P = DECIMAL_PRECISION;\\n\\n liquityBaseParams = ILiquityBaseParams(_liquityBaseParamsAddress);\\n borrowerOperations = IBorrowerOperations(_borrowerOperationsAddress);\\n troveManager = ITroveManager(_troveManagerAddress);\\n activePool = IActivePool(_activePoolAddress);\\n zusdToken = IZUSDToken(_zusdTokenAddress);\\n sortedTroves = ISortedTroves(_sortedTrovesAddress);\\n priceFeed = IPriceFeed(_priceFeedAddress);\\n communityIssuance = ICommunityIssuance(_communityIssuanceAddress);\\n\\n emit BorrowerOperationsAddressChanged(_borrowerOperationsAddress);\\n emit TroveManagerAddressChanged(_troveManagerAddress);\\n emit ActivePoolAddressChanged(_activePoolAddress);\\n emit ZUSDTokenAddressChanged(_zusdTokenAddress);\\n emit SortedTrovesAddressChanged(_sortedTrovesAddress);\\n emit PriceFeedAddressChanged(_priceFeedAddress);\\n emit CommunityIssuanceAddressChanged(_communityIssuanceAddress);\\n }\\n\\n /**\\n * @dev setter function specific for community issuance contract.\\n * @param _communityIssuanceAddress address of new community issuance contract.\\n */\\n function setCommunityIssuanceAddress(address _communityIssuanceAddress) external onlyOwner {\\n checkContract(_communityIssuanceAddress);\\n communityIssuance = ICommunityIssuance(_communityIssuanceAddress);\\n emit CommunityIssuanceAddressChanged(_communityIssuanceAddress);\\n }\\n\\n // --- Getters for public variables. Required by IPool interface ---\\n\\n function getETH() external view override returns (uint256) {\\n return ETH;\\n }\\n\\n function getTotalZUSDDeposits() external view override returns (uint256) {\\n return totalZUSDDeposits;\\n }\\n\\n // --- External Depositor Functions ---\\n\\n /** provideToSP():\\n *\\n * - Triggers a SOV issuance, based on time passed since the last issuance and total amount of deposited ZUSD. The SOV issuance is shared between *all* depositors and front ends\\n * - Tags the deposit with the provided front end tag param, if it's a new deposit\\n * - Sends depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Increases deposit and tagged front end's stake, and takes new snapshots for each.\\n */\\n function provideToSP(uint256 _amount, address _frontEndTag) external override {\\n _provideToSP(_amount, _frontEndTag);\\n }\\n\\n function _provideToSP(uint256 _amount, address _frontEndTag) internal {\\n _requireFrontEndIsRegisteredOrZero(_frontEndTag);\\n _requireFrontEndNotRegistered(msg.sender);\\n _requireNonZeroAmount(_amount);\\n\\n uint256 initialDeposit = deposits[msg.sender].initialValue;\\n\\n ICommunityIssuance communityIssuanceCached = communityIssuance;\\n\\n _triggerSOVIssuance(communityIssuanceCached);\\n\\n if (initialDeposit == 0) {\\n _setFrontEndTag(msg.sender, _frontEndTag);\\n }\\n uint256 depositorETHGain = getDepositorETHGain(msg.sender);\\n uint256 compoundedZUSDDeposit = getCompoundedZUSDDeposit(msg.sender);\\n uint256 ZUSDLoss = initialDeposit.sub(compoundedZUSDDeposit); // Needed only for event log\\n\\n // First pay out any SOV gains\\n address frontEnd = deposits[msg.sender].frontEndTag;\\n _payOutSOVGains(communityIssuanceCached, msg.sender, frontEnd);\\n\\n // Update front end stake\\n uint256 compoundedFrontEndStake = getCompoundedFrontEndStake(frontEnd);\\n uint256 newFrontEndStake = compoundedFrontEndStake.add(_amount);\\n _updateFrontEndStakeAndSnapshots(frontEnd, newFrontEndStake);\\n emit FrontEndStakeChanged(frontEnd, newFrontEndStake, msg.sender);\\n\\n _sendZUSDtoStabilityPool(msg.sender, _amount);\\n\\n uint256 newDeposit = compoundedZUSDDeposit.add(_amount);\\n _updateDepositAndSnapshots(msg.sender, newDeposit);\\n emit UserDepositChanged(msg.sender, newDeposit);\\n\\n emit ETHGainWithdrawn(msg.sender, depositorETHGain, ZUSDLoss); // ZUSD Loss required for event log\\n\\n _sendETHGainToDepositor(depositorETHGain);\\n }\\n\\n ///DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDLLR(\\n uint256 _dllrAmount,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external override {\\n uint256 _ZUSDAmount = MyntLib.redeemZusdFromDllrWithPermit(\\n borrowerOperations.getMassetManager(),\\n _dllrAmount,\\n address(zusdToken),\\n _permitParams\\n );\\n\\n _provideToSP(_ZUSDAmount, ADDRESS_ZERO);\\n }\\n\\n ///DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDllrWithPermit2(\\n uint256 _dllrAmount,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external override {\\n uint256 _ZUSDAmount = MyntLib.redeemZusdFromDllrWithPermit2(\\n borrowerOperations.getMassetManager(),\\n address(zusdToken),\\n _permit,\\n permit2,\\n _signature\\n );\\n\\n _provideToSP(_ZUSDAmount, ADDRESS_ZERO);\\n }\\n\\n /** withdrawFromSP():\\n *\\n * - Triggers a SOV issuance, based on time passed since the last issuance and total amount of ZUSD is deposited. The SOV issuance is shared between *all* depositors and front ends\\n * - Removes the deposit's front end tag if it is a full withdrawal\\n * - Sends all depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.\\n *\\n * If _amount > userDeposit, the user withdraws all of their compounded deposit.\\n */\\n function withdrawFromSP(uint256 _amount) external override {\\n _withdrawFromSpTo(_amount, msg.sender);\\n }\\n\\n ///@return actual ZUSD amount withdrawn\\n function _withdrawFromSpTo(uint256 _amount, address _receiver) internal returns (uint256) {\\n require(_receiver != address(0), \\\"SP::_withdrawFromSpTo: _receiver is zero address\\\");\\n if (_amount != 0) {\\n _requireNoUnderCollateralizedTroves();\\n }\\n uint256 initialDeposit = deposits[msg.sender].initialValue;\\n _requireUserHasDeposit(initialDeposit);\\n\\n ICommunityIssuance communityIssuanceCached = communityIssuance;\\n\\n _triggerSOVIssuance(communityIssuanceCached);\\n\\n uint256 depositorETHGain = getDepositorETHGain(msg.sender);\\n\\n uint256 compoundedZUSDDeposit = getCompoundedZUSDDeposit(msg.sender);\\n uint256 ZUSDtoWithdraw = LiquityMath._min(_amount, compoundedZUSDDeposit);\\n uint256 ZUSDLoss = initialDeposit.sub(compoundedZUSDDeposit); // Needed only for event log\\n\\n // First pay out any SOV gains\\n address frontEnd = deposits[msg.sender].frontEndTag;\\n _payOutSOVGains(communityIssuanceCached, msg.sender, frontEnd);\\n\\n // Update front end stake\\n uint256 compoundedFrontEndStake = getCompoundedFrontEndStake(frontEnd);\\n uint256 newFrontEndStake = compoundedFrontEndStake.sub(ZUSDtoWithdraw);\\n _updateFrontEndStakeAndSnapshots(frontEnd, newFrontEndStake);\\n emit FrontEndStakeChanged(frontEnd, newFrontEndStake, msg.sender);\\n\\n _sendZUSDToDepositor(_receiver, ZUSDtoWithdraw);\\n\\n // Update deposit\\n uint256 newDeposit = compoundedZUSDDeposit.sub(ZUSDtoWithdraw);\\n _updateDepositAndSnapshots(msg.sender, newDeposit);\\n emit UserDepositChanged(msg.sender, newDeposit);\\n\\n emit ETHGainWithdrawn(msg.sender, depositorETHGain, ZUSDLoss); // ZUSD Loss required for event log\\n\\n _sendETHGainTo(depositorETHGain, msg.sender);\\n\\n return ZUSDtoWithdraw;\\n }\\n\\n ///Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\\n function withdrawFromSpAndConvertToDLLR(uint256 _zusdAmountRequested) external override {\\n IMassetManager massetManager = borrowerOperations.getMassetManager();\\n uint256 amountWithdrawn = _withdrawFromSpTo(_zusdAmountRequested, address(this));\\n require(\\n zusdToken.approve(address(massetManager), amountWithdrawn),\\n \\\"Failed to approve ZUSD amount for Mynt mAsset to redeem\\\"\\n );\\n massetManager.mintTo(address(zusdToken), amountWithdrawn, msg.sender);\\n emit WithdrawFromSpAndConvertToDLLR(msg.sender, _zusdAmountRequested, amountWithdrawn);\\n }\\n\\n /** withdrawETHGainToTrove:\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Sends all depositor's SOV gain to depositor\\n * - Sends all tagged front end's SOV gain to the tagged front end\\n * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove\\n * - Leaves their compounded deposit in the Stability Pool\\n * - Updates snapshots for deposit and tagged front end stake */\\n function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external override {\\n uint256 initialDeposit = deposits[msg.sender].initialValue;\\n _requireUserHasDeposit(initialDeposit);\\n _requireUserHasTrove(msg.sender);\\n _requireUserHasETHGain(msg.sender);\\n\\n ICommunityIssuance communityIssuanceCached = communityIssuance;\\n\\n _triggerSOVIssuance(communityIssuanceCached);\\n\\n uint256 depositorETHGain = getDepositorETHGain(msg.sender);\\n\\n uint256 compoundedZUSDDeposit = getCompoundedZUSDDeposit(msg.sender);\\n uint256 ZUSDLoss = initialDeposit.sub(compoundedZUSDDeposit); // Needed only for event log\\n\\n // First pay out any SOV gains\\n address frontEnd = deposits[msg.sender].frontEndTag;\\n _payOutSOVGains(communityIssuanceCached, msg.sender, frontEnd);\\n\\n // Update front end stake\\n uint256 compoundedFrontEndStake = getCompoundedFrontEndStake(frontEnd);\\n uint256 newFrontEndStake = compoundedFrontEndStake;\\n _updateFrontEndStakeAndSnapshots(frontEnd, newFrontEndStake);\\n emit FrontEndStakeChanged(frontEnd, newFrontEndStake, msg.sender);\\n\\n _updateDepositAndSnapshots(msg.sender, compoundedZUSDDeposit);\\n\\n /* Emit events before transferring ETH gain to Trove.\\n This lets the event log make more sense (i.e. so it appears that first the ETH gain is withdrawn\\n and then it is deposited into the Trove, not the other way around). */\\n emit ETHGainWithdrawn(msg.sender, depositorETHGain, ZUSDLoss);\\n emit UserDepositChanged(msg.sender, compoundedZUSDDeposit);\\n\\n ETH = ETH.sub(depositorETHGain);\\n emit StabilityPoolETHBalanceUpdated(ETH);\\n emit EtherSent(msg.sender, depositorETHGain);\\n\\n borrowerOperations.moveETHGainToTrove{ value: depositorETHGain }(\\n msg.sender,\\n _upperHint,\\n _lowerHint\\n );\\n }\\n\\n // --- SOV issuance functions ---\\n\\n function _triggerSOVIssuance(ICommunityIssuance _communityIssuance) internal {\\n uint256 SOVIssuance = _communityIssuance.issueSOV(totalZUSDDeposits);\\n _updateG(SOVIssuance);\\n }\\n\\n function _updateG(uint256 _SOVIssuance) internal {\\n uint256 totalZUSD = totalZUSDDeposits; // cached to save an SLOAD\\n /*\\n * When total deposits is 0, G is not updated. In this case, the SOV issued can not be obtained by later\\n * depositors - it is missed out on, and remains in the balanceof the CommunityIssuance contract.\\n *\\n */\\n if (totalZUSD == 0 || _SOVIssuance == 0) {\\n return;\\n }\\n\\n uint256 SOVPerUnitStaked;\\n SOVPerUnitStaked = _computeSOVPerUnitStaked(_SOVIssuance, totalZUSD);\\n\\n uint256 marginalSOVGain = SOVPerUnitStaked.mul(P);\\n epochToScaleToG[currentEpoch][currentScale] = epochToScaleToG[currentEpoch][currentScale]\\n .add(marginalSOVGain);\\n\\n emit G_Updated(epochToScaleToG[currentEpoch][currentScale], currentEpoch, currentScale);\\n }\\n\\n function _computeSOVPerUnitStaked(uint256 _SOVIssuance, uint256 _totalZUSDDeposits)\\n internal\\n returns (uint256)\\n {\\n /*\\n * Calculate the SOV-per-unit staked. Division uses a \\\"feedback\\\" error correction, to keep the\\n * cumulative error low in the running total G:\\n *\\n * 1) Form a numerator which compensates for the floor division error that occurred the last time this\\n * function was called.\\n * 2) Calculate \\\"per-unit-staked\\\" ratio.\\n * 3) Multiply the ratio back by its denominator, to reveal the current floor division error.\\n * 4) Store this error for use in the next correction when this function is called.\\n * 5) Note: static analysis tools complain about this \\\"division before multiplication\\\", however, it is intended.\\n */\\n uint256 SOVNumerator = _SOVIssuance.mul(DECIMAL_PRECISION).add(lastSOVError);\\n\\n uint256 SOVPerUnitStaked = SOVNumerator.div(_totalZUSDDeposits);\\n lastSOVError = SOVNumerator.sub(SOVPerUnitStaked.mul(_totalZUSDDeposits));\\n\\n return SOVPerUnitStaked;\\n }\\n\\n // --- Liquidation functions ---\\n\\n /**\\n * Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible)\\n * and transfers the Trove's ETH collateral from ActivePool to StabilityPool.\\n * Only called by liquidation functions in the TroveManager.\\n */\\n function offset(uint256 _debtToOffset, uint256 _collToAdd) external override {\\n _requireCallerIsTroveManager();\\n uint256 totalZUSD = totalZUSDDeposits; // cached to save an SLOAD\\n if (totalZUSD == 0 || _debtToOffset == 0) {\\n return;\\n }\\n\\n _triggerSOVIssuance(communityIssuance);\\n\\n (\\n uint256 ETHGainPerUnitStaked,\\n uint256 ZUSDLossPerUnitStaked\\n ) = _computeRewardsPerUnitStaked(_collToAdd, _debtToOffset, totalZUSD);\\n\\n _updateRewardSumAndProduct(ETHGainPerUnitStaked, ZUSDLossPerUnitStaked); // updates S and P\\n\\n _moveOffsetCollAndDebt(_collToAdd, _debtToOffset);\\n }\\n\\n // --- Offset helper functions ---\\n\\n function _computeRewardsPerUnitStaked(\\n uint256 _collToAdd,\\n uint256 _debtToOffset,\\n uint256 _totalZUSDDeposits\\n ) internal returns (uint256 ETHGainPerUnitStaked, uint256 ZUSDLossPerUnitStaked) {\\n /*\\n * Compute the ZUSD and ETH rewards. Uses a \\\"feedback\\\" error correction, to keep\\n * the cumulative error in the P and S state variables low:\\n *\\n * 1) Form numerators which compensate for the floor division errors that occurred the last time this\\n * function was called.\\n * 2) Calculate \\\"per-unit-staked\\\" ratios.\\n * 3) Multiply each ratio back by its denominator, to reveal the current floor division error.\\n * 4) Store these errors for use in the next correction when this function is called.\\n * 5) Note: static analysis tools complain about this \\\"division before multiplication\\\", however, it is intended.\\n */\\n uint256 ETHNumerator = _collToAdd.mul(DECIMAL_PRECISION).add(lastETHError_Offset);\\n\\n assert(_debtToOffset <= _totalZUSDDeposits);\\n if (_debtToOffset == _totalZUSDDeposits) {\\n ZUSDLossPerUnitStaked = DECIMAL_PRECISION; // When the Pool depletes to 0, so does each deposit\\n lastZUSDLossError_Offset = 0;\\n } else {\\n uint256 ZUSDLossNumerator = _debtToOffset.mul(DECIMAL_PRECISION).sub(\\n lastZUSDLossError_Offset\\n );\\n /*\\n * Add 1 to make error in quotient positive. We want \\\"slightly too much\\\" ZUSD loss,\\n * which ensures the error in any given compoundedZUSDDeposit favors the Stability Pool.\\n */\\n ZUSDLossPerUnitStaked = (ZUSDLossNumerator.div(_totalZUSDDeposits)).add(1);\\n lastZUSDLossError_Offset = (ZUSDLossPerUnitStaked.mul(_totalZUSDDeposits)).sub(\\n ZUSDLossNumerator\\n );\\n }\\n\\n ETHGainPerUnitStaked = ETHNumerator.div(_totalZUSDDeposits);\\n lastETHError_Offset = ETHNumerator.sub(ETHGainPerUnitStaked.mul(_totalZUSDDeposits));\\n\\n return (ETHGainPerUnitStaked, ZUSDLossPerUnitStaked);\\n }\\n\\n /// Update the Stability Pool reward sum S and product P\\n function _updateRewardSumAndProduct(\\n uint256 _ETHGainPerUnitStaked,\\n uint256 _ZUSDLossPerUnitStaked\\n ) internal {\\n uint256 currentP = P;\\n uint256 newP;\\n\\n assert(_ZUSDLossPerUnitStaked <= DECIMAL_PRECISION);\\n /*\\n * The newProductFactor is the factor by which to change all deposits, due to the depletion of Stability Pool ZUSD in the liquidation.\\n * We make the product factor 0 if there was a pool-emptying. Otherwise, it is (1 - ZUSDLossPerUnitStaked)\\n */\\n uint256 newProductFactor = uint256(DECIMAL_PRECISION).sub(_ZUSDLossPerUnitStaked);\\n\\n uint128 currentScaleCached = currentScale;\\n uint128 currentEpochCached = currentEpoch;\\n uint256 currentS = epochToScaleToSum[currentEpochCached][currentScaleCached];\\n\\n /*\\n * Calculate the new S first, before we update P.\\n * The ETH gain for any given depositor from a liquidation depends on the value of their deposit\\n * (and the value of totalDeposits) prior to the Stability being depleted by the debt in the liquidation.\\n *\\n * Since S corresponds to ETH gain, and P to deposit loss, we update S first.\\n */\\n uint256 marginalETHGain = _ETHGainPerUnitStaked.mul(currentP);\\n uint256 newS = currentS.add(marginalETHGain);\\n epochToScaleToSum[currentEpochCached][currentScaleCached] = newS;\\n emit S_Updated(newS, currentEpochCached, currentScaleCached);\\n\\n // If the Stability Pool was emptied, increment the epoch, and reset the scale and product P\\n if (newProductFactor == 0) {\\n currentEpoch = currentEpochCached.add(1);\\n emit EpochUpdated(currentEpoch);\\n currentScale = 0;\\n emit ScaleUpdated(currentScale);\\n newP = DECIMAL_PRECISION;\\n\\n // If multiplying P by a non-zero product factor would reduce P below the scale boundary, increment the scale\\n } else if (currentP.mul(newProductFactor).div(DECIMAL_PRECISION) < SCALE_FACTOR) {\\n newP = currentP.mul(newProductFactor).mul(SCALE_FACTOR).div(DECIMAL_PRECISION);\\n currentScale = currentScaleCached.add(1);\\n emit ScaleUpdated(currentScale);\\n } else {\\n newP = currentP.mul(newProductFactor).div(DECIMAL_PRECISION);\\n }\\n\\n assert(newP > 0);\\n P = newP;\\n\\n emit P_Updated(newP);\\n }\\n\\n function _moveOffsetCollAndDebt(uint256 _collToAdd, uint256 _debtToOffset) internal {\\n IActivePool activePoolCached = activePool;\\n\\n // Cancel the liquidated ZUSD debt with the ZUSD in the stability pool\\n activePoolCached.decreaseZUSDDebt(_debtToOffset);\\n _decreaseZUSD(_debtToOffset);\\n\\n // Burn the debt that was successfully offset\\n zusdToken.burn(address(this), _debtToOffset);\\n\\n activePoolCached.sendETH(address(this), _collToAdd);\\n }\\n\\n function _decreaseZUSD(uint256 _amount) internal {\\n uint256 newTotalZUSDDeposits = totalZUSDDeposits.sub(_amount);\\n totalZUSDDeposits = newTotalZUSDDeposits;\\n emit StabilityPoolZUSDBalanceUpdated(newTotalZUSDDeposits);\\n }\\n\\n // --- Reward calculator functions for depositor and front end ---\\n\\n /** Calculates the ETH gain earned by the deposit since its last snapshots were taken.\\n * Given by the formula: E = d0 * (S - S(0))/P(0)\\n * where S(0) and P(0) are the depositor's snapshots of the sum S and product P, respectively.\\n * d0 is the last recorded deposit value.\\n */\\n function getDepositorETHGain(address _depositor) public view override returns (uint256) {\\n uint256 initialDeposit = deposits[_depositor].initialValue;\\n\\n if (initialDeposit == 0) {\\n return 0;\\n }\\n\\n Snapshots memory snapshots = depositSnapshots[_depositor];\\n\\n uint256 ETHGain = _getETHGainFromSnapshots(initialDeposit, snapshots);\\n return ETHGain;\\n }\\n\\n function _getETHGainFromSnapshots(uint256 initialDeposit, Snapshots memory snapshots)\\n internal\\n view\\n returns (uint256)\\n {\\n /*\\n * Grab the sum 'S' from the epoch at which the stake was made. The ETH gain may span up to one scale change.\\n * If it does, the second portion of the ETH gain is scaled by 1e9.\\n * If the gain spans no scale change, the second portion will be 0.\\n */\\n uint128 epochSnapshot = snapshots.epoch;\\n uint128 scaleSnapshot = snapshots.scale;\\n uint256 S_Snapshot = snapshots.S;\\n uint256 P_Snapshot = snapshots.P;\\n\\n uint256 firstPortion = epochToScaleToSum[epochSnapshot][scaleSnapshot].sub(S_Snapshot);\\n uint256 secondPortion = epochToScaleToSum[epochSnapshot][scaleSnapshot.add(1)].div(\\n SCALE_FACTOR\\n );\\n\\n uint256 ETHGain = initialDeposit.mul(firstPortion.add(secondPortion)).div(P_Snapshot).div(\\n DECIMAL_PRECISION\\n );\\n\\n return ETHGain;\\n }\\n\\n /**\\n * Calculate the SOV gain earned by a deposit since its last snapshots were taken.\\n * Given by the formula: SOV = d0 * (G - G(0))/P(0)\\n * where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively.\\n * d0 is the last recorded deposit value.\\n */\\n function getDepositorSOVGain(address _depositor) public view override returns (uint256) {\\n uint256 initialDeposit = deposits[_depositor].initialValue;\\n if (initialDeposit == 0) {\\n return 0;\\n }\\n\\n address frontEndTag = deposits[_depositor].frontEndTag;\\n\\n /*\\n * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned.\\n * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through\\n * which they made their deposit.\\n */\\n uint256 kickbackRate = frontEndTag == ADDRESS_ZERO\\n ? DECIMAL_PRECISION\\n : frontEnds[frontEndTag].kickbackRate;\\n\\n Snapshots memory snapshots = depositSnapshots[_depositor];\\n\\n uint256 SOVGain = kickbackRate\\n .mul(_getSOVGainFromSnapshots(initialDeposit, snapshots))\\n .div(DECIMAL_PRECISION);\\n\\n return SOVGain;\\n }\\n\\n /**\\n * Return the SOV gain earned by the front end. Given by the formula: E = D0 * (G - G(0))/P(0)\\n * where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively.\\n *\\n * D0 is the last recorded value of the front end's total tagged deposits.\\n */\\n function getFrontEndSOVGain(address _frontEnd) public view override returns (uint256) {\\n uint256 frontEndStake = frontEndStakes[_frontEnd];\\n if (frontEndStake == 0) {\\n return 0;\\n }\\n\\n uint256 kickbackRate = frontEnds[_frontEnd].kickbackRate;\\n uint256 frontEndShare = uint256(DECIMAL_PRECISION).sub(kickbackRate);\\n\\n Snapshots memory snapshots = frontEndSnapshots[_frontEnd];\\n\\n uint256 SOVGain = frontEndShare\\n .mul(_getSOVGainFromSnapshots(frontEndStake, snapshots))\\n .div(DECIMAL_PRECISION);\\n return SOVGain;\\n }\\n\\n function _getSOVGainFromSnapshots(uint256 initialStake, Snapshots memory snapshots)\\n internal\\n view\\n returns (uint256)\\n {\\n /*\\n * Grab the sum 'G' from the epoch at which the stake was made. The SOV gain may span up to one scale change.\\n * If it does, the second portion of the SOV gain is scaled by 1e9.\\n * If the gain spans no scale change, the second portion will be 0.\\n */\\n uint128 epochSnapshot = snapshots.epoch;\\n uint128 scaleSnapshot = snapshots.scale;\\n uint256 G_Snapshot = snapshots.G;\\n uint256 P_Snapshot = snapshots.P;\\n\\n uint256 firstPortion = epochToScaleToG[epochSnapshot][scaleSnapshot].sub(G_Snapshot);\\n uint256 secondPortion = epochToScaleToG[epochSnapshot][scaleSnapshot.add(1)].div(\\n SCALE_FACTOR\\n );\\n\\n uint256 SOVGain = initialStake.mul(firstPortion.add(secondPortion)).div(P_Snapshot).div(\\n DECIMAL_PRECISION\\n );\\n\\n return SOVGain;\\n }\\n\\n // --- Compounded deposit and compounded front end stake ---\\n\\n /**\\n * Return the user's compounded deposit. Given by the formula: d = d0 * P/P(0)\\n * where P(0) is the depositor's snapshot of the product P, taken when they last updated their deposit.\\n */\\n function getCompoundedZUSDDeposit(address _depositor) public view override returns (uint256) {\\n uint256 initialDeposit = deposits[_depositor].initialValue;\\n if (initialDeposit == 0) {\\n return 0;\\n }\\n\\n Snapshots memory snapshots = depositSnapshots[_depositor];\\n\\n uint256 compoundedDeposit = _getCompoundedStakeFromSnapshots(initialDeposit, snapshots);\\n return compoundedDeposit;\\n }\\n\\n /**\\n * Return the front end's compounded stake. Given by the formula: D = D0 * P/P(0)\\n * where P(0) is the depositor's snapshot of the product P, taken at the last time\\n * when one of the front end's tagged deposits updated their deposit.\\n *\\n * The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\\n */\\n function getCompoundedFrontEndStake(address _frontEnd) public view override returns (uint256) {\\n uint256 frontEndStake = frontEndStakes[_frontEnd];\\n if (frontEndStake == 0) {\\n return 0;\\n }\\n\\n Snapshots memory snapshots = frontEndSnapshots[_frontEnd];\\n\\n uint256 compoundedFrontEndStake = _getCompoundedStakeFromSnapshots(\\n frontEndStake,\\n snapshots\\n );\\n return compoundedFrontEndStake;\\n }\\n\\n // Internal function, used to calculcate compounded deposits and compounded front end stakes.\\n function _getCompoundedStakeFromSnapshots(uint256 initialStake, Snapshots memory snapshots)\\n internal\\n view\\n returns (uint256)\\n {\\n uint256 snapshot_P = snapshots.P;\\n uint128 scaleSnapshot = snapshots.scale;\\n uint128 epochSnapshot = snapshots.epoch;\\n\\n // If stake was made before a pool-emptying event, then it has been fully cancelled with debt -- so, return 0\\n if (epochSnapshot < currentEpoch) {\\n return 0;\\n }\\n\\n uint256 compoundedStake;\\n uint128 scaleDiff = currentScale.sub(scaleSnapshot);\\n\\n /* Compute the compounded stake. If a scale change in P was made during the stake's lifetime,\\n * account for it. If more than one scale change was made, then the stake has decreased by a factor of\\n * at least 1e-9 -- so return 0.\\n */\\n if (scaleDiff == 0) {\\n compoundedStake = initialStake.mul(P).div(snapshot_P);\\n } else if (scaleDiff == 1) {\\n compoundedStake = initialStake.mul(P).div(snapshot_P).div(SCALE_FACTOR);\\n } else {\\n // if scaleDiff >= 2\\n compoundedStake = 0;\\n }\\n\\n /*\\n * If compounded deposit is less than a billionth of the initial deposit, return 0.\\n *\\n * NOTE: originally, this line was in place to stop rounding errors making the deposit too large. However, the error\\n * corrections should ensure the error in P \\\"favors the Pool\\\", i.e. any given compounded deposit should slightly less\\n * than it's theoretical value.\\n *\\n * Thus it's unclear whether this line is still really needed.\\n */\\n if (compoundedStake < initialStake.div(1e9)) {\\n return 0;\\n }\\n\\n return compoundedStake;\\n }\\n\\n // --- Sender functions for ZUSD deposit, ETH gains and SOV gains ---\\n\\n /// Transfer the ZUSD tokens from the user to the Stability Pool's address, and update its recorded ZUSD\\n function _sendZUSDtoStabilityPool(address _address, uint256 _amount) internal {\\n zusdToken.sendToPool(_address, address(this), _amount);\\n uint256 newTotalZUSDDeposits = totalZUSDDeposits.add(_amount);\\n totalZUSDDeposits = newTotalZUSDDeposits;\\n emit StabilityPoolZUSDBalanceUpdated(newTotalZUSDDeposits);\\n }\\n\\n function _sendETHGainToDepositor(uint256 _amount) internal {\\n _sendETHGainTo(_amount, msg.sender);\\n }\\n\\n function _sendETHGainTo(uint256 _amount, address _receiver) internal {\\n require(_receiver != address(0), \\\"SP::_sendETHGainTo: _receiver is zero address\\\");\\n if (_amount == 0) {\\n return;\\n }\\n uint256 newETH = ETH.sub(_amount);\\n ETH = newETH;\\n emit StabilityPoolETHBalanceUpdated(newETH);\\n emit EtherSent(msg.sender, _amount);\\n\\n (bool success, ) = msg.sender.call{ value: _amount }(\\\"\\\");\\n require(success, \\\"StabilityPool: sending ETH failed\\\");\\n }\\n\\n /// Send ZUSD to user and decrease ZUSD in Pool\\n function _sendZUSDToDepositor(address _depositor, uint256 ZUSDWithdrawal) internal {\\n if (ZUSDWithdrawal == 0) {\\n return;\\n }\\n\\n zusdToken.returnFromPool(address(this), _depositor, ZUSDWithdrawal);\\n _decreaseZUSD(ZUSDWithdrawal);\\n }\\n\\n // --- External Front End functions ---\\n\\n /// Front end makes a one-time selection of kickback rate upon registering\\n function registerFrontEnd(uint256 _kickbackRate) external override {\\n _requireFrontEndNotRegistered(msg.sender);\\n _requireUserHasNoDeposit(msg.sender);\\n _requireValidKickbackRate(_kickbackRate);\\n\\n frontEnds[msg.sender].kickbackRate = _kickbackRate;\\n frontEnds[msg.sender].registered = true;\\n\\n emit FrontEndRegistered(msg.sender, _kickbackRate);\\n }\\n\\n // --- Stability Pool Deposit Functionality ---\\n\\n function _setFrontEndTag(address _depositor, address _frontEndTag) internal {\\n deposits[_depositor].frontEndTag = _frontEndTag;\\n emit FrontEndTagSet(_depositor, _frontEndTag);\\n }\\n\\n function _updateDepositAndSnapshots(address _depositor, uint256 _newValue) internal {\\n deposits[_depositor].initialValue = _newValue;\\n\\n if (_newValue == 0) {\\n delete deposits[_depositor].frontEndTag;\\n delete depositSnapshots[_depositor];\\n emit DepositSnapshotUpdated(_depositor, 0, 0, 0);\\n return;\\n }\\n uint128 currentScaleCached = currentScale;\\n uint128 currentEpochCached = currentEpoch;\\n uint256 currentP = P;\\n\\n // Get S and G for the current epoch and current scale\\n uint256 currentS = epochToScaleToSum[currentEpochCached][currentScaleCached];\\n uint256 currentG = epochToScaleToG[currentEpochCached][currentScaleCached];\\n\\n // Record new snapshots of the latest running product P, sum S, and sum G, for the depositor\\n depositSnapshots[_depositor].P = currentP;\\n depositSnapshots[_depositor].S = currentS;\\n depositSnapshots[_depositor].G = currentG;\\n depositSnapshots[_depositor].scale = currentScaleCached;\\n depositSnapshots[_depositor].epoch = currentEpochCached;\\n\\n emit DepositSnapshotUpdated(_depositor, currentP, currentS, currentG);\\n }\\n\\n function _updateFrontEndStakeAndSnapshots(address _frontEnd, uint256 _newValue) internal {\\n frontEndStakes[_frontEnd] = _newValue;\\n\\n if (_newValue == 0) {\\n delete frontEndSnapshots[_frontEnd];\\n emit FrontEndSnapshotUpdated(_frontEnd, 0, 0);\\n return;\\n }\\n\\n uint128 currentScaleCached = currentScale;\\n uint128 currentEpochCached = currentEpoch;\\n uint256 currentP = P;\\n\\n // Get G for the current epoch and current scale\\n uint256 currentG = epochToScaleToG[currentEpochCached][currentScaleCached];\\n\\n // Record new snapshots of the latest running product P and sum G for the front end\\n frontEndSnapshots[_frontEnd].P = currentP;\\n frontEndSnapshots[_frontEnd].G = currentG;\\n frontEndSnapshots[_frontEnd].scale = currentScaleCached;\\n frontEndSnapshots[_frontEnd].epoch = currentEpochCached;\\n\\n emit FrontEndSnapshotUpdated(_frontEnd, currentP, currentG);\\n }\\n\\n function _payOutSOVGains(\\n ICommunityIssuance _communityIssuance,\\n address _depositor,\\n address _frontEnd\\n ) internal {\\n // Pay out front end's SOV gain\\n if (_frontEnd != ADDRESS_ZERO) {\\n uint256 frontEndSOVGain = getFrontEndSOVGain(_frontEnd);\\n _communityIssuance.sendSOV(_frontEnd, frontEndSOVGain);\\n emit SOVPaidToFrontEnd(_frontEnd, frontEndSOVGain);\\n }\\n\\n // Pay out depositor's SOV gain\\n uint256 depositorSOVGain = getDepositorSOVGain(_depositor);\\n _communityIssuance.sendSOV(_depositor, depositorSOVGain);\\n emit SOVPaidToDepositor(_depositor, depositorSOVGain);\\n }\\n\\n // --- 'require' functions ---\\n\\n function _requireCallerIsActivePool() internal view {\\n require(msg.sender == address(activePool), \\\"StabilityPool: Caller is not ActivePool\\\");\\n }\\n\\n function _requireCallerIsTroveManager() internal view {\\n require(msg.sender == address(troveManager), \\\"StabilityPool: Caller is not TroveManager\\\");\\n }\\n\\n function _requireNoUnderCollateralizedTroves() internal {\\n uint256 price = priceFeed.fetchPrice();\\n address lowestTrove = sortedTroves.getLast();\\n uint256 ICR = troveManager.getCurrentICR(lowestTrove, price);\\n require(\\n ICR >= liquityBaseParams.MCR(),\\n \\\"StabilityPool: Cannot withdraw while there are troves with ICR < MCR\\\"\\n );\\n }\\n\\n function _requireUserHasDeposit(uint256 _initialDeposit) internal pure {\\n require(_initialDeposit > 0, \\\"StabilityPool: User must have a non-zero deposit\\\");\\n }\\n\\n function _requireUserHasNoDeposit(address _address) internal view {\\n uint256 initialDeposit = deposits[_address].initialValue;\\n require(initialDeposit == 0, \\\"StabilityPool: User must have no deposit\\\");\\n }\\n\\n function _requireNonZeroAmount(uint256 _amount) internal pure {\\n require(_amount > 0, \\\"StabilityPool: Amount must be non-zero\\\");\\n }\\n\\n function _requireUserHasTrove(address _depositor) internal view {\\n require(\\n troveManager.getTroveStatus(_depositor) == 1,\\n \\\"StabilityPool: caller must have an active trove to withdraw ETHGain to\\\"\\n );\\n }\\n\\n function _requireUserHasETHGain(address _depositor) internal view {\\n uint256 ETHGain = getDepositorETHGain(_depositor);\\n require(ETHGain > 0, \\\"StabilityPool: caller must have non-zero ETH Gain\\\");\\n }\\n\\n function _requireFrontEndNotRegistered(address _address) internal view {\\n require(\\n !frontEnds[_address].registered,\\n \\\"StabilityPool: must not already be a registered front end\\\"\\n );\\n }\\n\\n function _requireFrontEndIsRegisteredOrZero(address _address) internal view {\\n require(\\n frontEnds[_address].registered || _address == ADDRESS_ZERO,\\n \\\"StabilityPool: Tag must be a registered front end, or the zero address\\\"\\n );\\n }\\n\\n function _requireValidKickbackRate(uint256 _kickbackRate) internal pure {\\n require(\\n _kickbackRate <= DECIMAL_PRECISION,\\n \\\"StabilityPool: Kickback rate must be in range [0,1]\\\"\\n );\\n }\\n\\n // --- Fallback function ---\\n\\n receive() external payable {\\n _requireCallerIsActivePool();\\n ETH = ETH.add(msg.value);\\n StabilityPoolETHBalanceUpdated(ETH);\\n }\\n}\\n\",\"keccak256\":\"0xba9a1f4ef8bf737262b6aa77fac2247ea1ae68d51267496c46ad817bfc9f7acd\",\"license\":\"MIT\"},\"contracts/StabilityPoolStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./Interfaces/IStabilityPool.sol\\\";\\nimport \\\"./Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./Interfaces/ITroveManager.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/ICommunityIssuance.sol\\\";\\nimport \\\"./Dependencies/Ownable.sol\\\";\\nimport \\\"./Dependencies/BaseMath.sol\\\";\\n\\ncontract StabilityPoolStorage is Ownable, BaseMath {\\n string public constant NAME = \\\"StabilityPool\\\";\\n\\n IBorrowerOperations public borrowerOperations;\\n\\n ITroveManager public troveManager;\\n\\n IZUSDToken public zusdToken;\\n\\n // Needed to check if there are pending liquidations\\n ISortedTroves public sortedTroves;\\n\\n ICommunityIssuance public communityIssuance;\\n\\n uint256 internal ETH; // deposited ether tracker\\n\\n // Tracker for ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\\n uint256 internal totalZUSDDeposits;\\n\\n // --- Data structures ---\\n\\n struct FrontEnd {\\n uint256 kickbackRate;\\n bool registered;\\n }\\n\\n struct Deposit {\\n uint256 initialValue;\\n address frontEndTag;\\n }\\n\\n struct Snapshots {\\n uint256 S;\\n uint256 P;\\n uint256 G;\\n uint128 scale;\\n uint128 epoch;\\n }\\n\\n mapping(address => Deposit) public deposits; // depositor address -> Deposit struct\\n mapping(address => Snapshots) public depositSnapshots; // depositor address -> snapshots struct\\n\\n mapping(address => FrontEnd) public frontEnds; // front end address -> FrontEnd struct\\n mapping(address => uint256) public frontEndStakes; // front end address -> last recorded total deposits, tagged with that front end\\n mapping(address => Snapshots) public frontEndSnapshots; // front end address -> snapshots struct\\n\\n /* Product 'P': Running product by which to multiply an initial deposit, in order to find the current compounded deposit,\\n * after a series of liquidations have occurred, each of which cancel some ZUSD debt with the deposit.\\n *\\n * During its lifetime, a deposit's value evolves from d_t to d_t * P / P_t , where P_t\\n * is the snapshot of P taken at the instant the deposit was made. 18-digit decimal.\\n */\\n uint256 public P;\\n\\n uint256 public constant SCALE_FACTOR = 1e9;\\n\\n // Each time the scale of P shifts by SCALE_FACTOR, the scale is incremented by 1\\n uint128 public currentScale;\\n\\n // With each offset that fully empties the Pool, the epoch is incremented by 1\\n uint128 public currentEpoch;\\n\\n /* ETH Gain sum 'S': During its lifetime, each deposit d_t earns an ETH gain of ( d_t * [S - S_t] )/P_t, where S_t\\n * is the depositor's snapshot of S taken at the time t when the deposit was made.\\n *\\n * The 'S' sums are stored in a nested mapping (epoch => scale => sum):\\n *\\n * - The inner mapping records the sum S at different scales\\n * - The outer mapping records the (scale => sum) mappings, for different epochs.\\n */\\n mapping(uint128 => mapping(uint128 => uint256)) public epochToScaleToSum;\\n\\n /*\\n * Similarly, the sum 'G' is used to calculate SOV gains. During it's lifetime, each deposit d_t earns a SOV gain of\\n * ( d_t * [G - G_t] )/P_t, where G_t is the depositor's snapshot of G taken at time t when the deposit was made.\\n *\\n * SOV reward events occur are triggered by depositor operations (new deposit, topup, withdrawal), and liquidations.\\n * In each case, the SOV reward is issued (i.e. G is updated), before other state changes are made.\\n */\\n mapping(uint128 => mapping(uint128 => uint256)) public epochToScaleToG;\\n\\n // Error tracker for the error correction in the SOV issuance calculation\\n uint256 public lastSOVError;\\n // Error trackers for the error correction in the offset calculation\\n uint256 public lastETHError_Offset;\\n uint256 public lastZUSDLossError_Offset;\\n}\\n\",\"keccak256\":\"0x046ee6c1e461c41f97120bec0380f90c35dfc6042ff10249ab3ed75f2217b7d0\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60a06040523480156200001157600080fd5b5060405162004b8c38038062004b8c833981016040819052620000349162000123565b62000048336001600160e01b036200005e16565b60601b6001600160601b031916608052620001b2565b6001600160a01b038116620000905760405162461bcd60e51b8152600401620000879062000170565b60405180910390fd5b6001600160a01b038116620000ad6001600160e01b036200010216565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f29062000153565b6040519081900390209190915550565b600080604051620001139062000153565b6040519081900390205492915050565b60006020828403121562000135578081fd5b81516001600160a01b03811681146200014c578182fd5b9392505050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160601c6149b7620001d560003980610ad0528061189a52506149b76000f3fe6080604052600436106102ad5760003560e01c806382e0a57411610165578063b31ee965116100cc578063de13da3c11610085578063de13da3c14610788578063df9cd84f146107a8578063e49d3667146107c8578063ec9f7d46146107e8578063fc7e286d146107fd578063fce6b7341461082b578063fda0101a1461084b576102f8565b8063b31ee965146106f4578063bdaf37ea14610709578063c3a34a0e1461071e578063ce4b5bbe1461073e578063d733cfd014610753578063d7fb044314610773576102f8565b80639f0706701161011e5780639f07067014610665578063a20baee614610531578063a3f4df7e1461067a578063a4e59ac81461069c578063a7bfff97146106b1578063ae918754146106df576102f8565b806382e0a574146105d157806386da0824146105f1578063887105d314610611578063893d20e8146106265780638b8fbd921461063b57806395fb16bb14610650576102f8565b80633d83908a1161021457806372fe25aa116101cd57806372fe25aa14610531578063741bef1a14610546578063759b30341461055b578063766718081461057057806377553ad414610592578063795d26c3146105a75780637f7dde4a146105bc576102f8565b80633d83908a1461048757806340ed1afd1461049c578063556be101146104bc5780635d2de642146104dc5780635f788d65146104fc57806370f1b5721461051c576102f8565b80632199b66f116102665780632199b66f146103d257806328a0a04d146103f25780632e54bf9514610412578063335525ad14610432578063389e92a5146104525780633cc7422514610472576102f8565b80630fbfe38b146102fd57806312261ee71461031f57806313af40351461034a57806314f6c3be1461036a57806316b9d3c51461038c5780631bf43555146103bd576102f8565b366102f8576102ba61086b565b6009546102cd903463ffffffff6108a016565b6009819055604051600080516020614902833981519152916102ee91614847565b60405180910390a1005b600080fd5b34801561030957600080fd5b5061031d610318366004613d86565b6108ce565b005b34801561032b57600080fd5b50610334610ace565b6040516103419190613f43565b60405180910390f35b34801561035657600080fd5b5061031d610365366004613c1a565b610af2565b34801561037657600080fd5b5061037f610b36565b6040516103419190614847565b34801561039857600080fd5b506103ac6103a7366004613c1a565b610b3c565b604051610341959493929190614896565b3480156103c957600080fd5b5061037f610b77565b3480156103de57600080fd5b5061031d6103ed366004613c1a565b610b84565b3480156103fe57600080fd5b5061037f61040d366004613d52565b610c1b565b34801561041e57600080fd5b5061031d61042d366004613d86565b610c38565b34801561043e57600080fd5b5061031d61044d366004613ec9565b610c46565b34801561045e57600080fd5b5061037f61046d366004613c1a565b610ca9565b34801561047e57600080fd5b50610334610d51565b34801561049357600080fd5b50610334610d60565b3480156104a857600080fd5b5061037f6104b7366004613c1a565b610d6f565b3480156104c857600080fd5b5061031d6104d7366004613d86565b610e0c565b3480156104e857600080fd5b5061037f6104f7366004613c1a565b610e84565b34801561050857600080fd5b5061031d610517366004613db6565b610e96565b34801561052857600080fd5b5061037f610ea0565b34801561053d57600080fd5b5061037f610ea6565b34801561055257600080fd5b50610334610eb2565b34801561056757600080fd5b5061037f610ec1565b34801561057c57600080fd5b50610585610ece565b6040516103419190614833565b34801561059e57600080fd5b50610334610ee4565b3480156105b357600080fd5b5061037f610ef3565b3480156105c857600080fd5b50610334611012565b3480156105dd57600080fd5b5061037f6105ec366004613d52565b611021565b3480156105fd57600080fd5b506103ac61060c366004613c1a565b61103e565b34801561061d57600080fd5b5061037f611079565b34801561063257600080fd5b50610334611148565b34801561064757600080fd5b5061037f611167565b34801561065c57600080fd5b5061033461116d565b34801561067157600080fd5b5061033461117c565b34801561068657600080fd5b5061068f61118b565b6040516103419190614060565b3480156106a857600080fd5b506105856111b4565b3480156106bd57600080fd5b506106d16106cc366004613c1a565b6111c3565b604051610341929190614867565b3480156106eb57600080fd5b506103346111df565b34801561070057600080fd5b5061037f6111ee565b34801561071557600080fd5b5061037f6111f4565b34801561072a57600080fd5b5061031d610739366004613dda565b6111fa565b34801561074a57600080fd5b5061037f61129e565b34801561075f57600080fd5b5061031d61076e366004613c8a565b6112a6565b34801561077f57600080fd5b5061037f611538565b34801561079457600080fd5b5061037f6107a3366004613c1a565b61153e565b3480156107b457600080fd5b5061037f6107c3366004613c1a565b611642565b3480156107d457600080fd5b5061037f6107e3366004613c1a565b6116df565b3480156107f457600080fd5b506103346117dc565b34801561080957600080fd5b5061081d610818366004613c1a565b6117eb565b604051610341929190614850565b34801561083757600080fd5b5061031d610846366004613e10565b61180d565b34801561085757600080fd5b5061031d610866366004613c52565b6118cd565b6000546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614258565b60405180910390fd5b565b6000828201838110156108c55760405162461bcd60e51b815260040161089590614168565b90505b92915050565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561091e57600080fd5b505afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613c36565b905060006109648330611b13565b60065460405163095ea7b360e01b81529192506001600160a01b03169063095ea7b3906109979085908590600401613fdf565b602060405180830381600087803b1580156109b157600080fd5b505af11580156109c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e99190613d32565b610a055760405162461bcd60e51b8152600401610895906145ef565b60065460405163438b1b4b60e01b81526001600160a01b038481169263438b1b4b92610a3b929091169085903390600401614019565b602060405180830381600087803b158015610a5557600080fd5b505af1158015610a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8d9190613d9e565b507f2b0fbec1c4e7e30517f196a714775ffe72770d2348f5d586854bb3c0fdf41df8338483604051610ac193929190613ff8565b60405180910390a1505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b610afa611148565b6001600160a01b0316336001600160a01b031614610b2a5760405162461bcd60e51b81526004016108959061451d565b610b3381611cde565b50565b60095490565b600f602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6809c2007651b250000081565b610b8c611148565b6001600160a01b0316336001600160a01b031614610bbc5760405162461bcd60e51b81526004016108959061451d565b610bc581611d69565b600880546001600160a01b0319166001600160a01b0383161790556040517f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac681190610c10908390613f43565b60405180910390a150565b601260209081526000928352604080842090915290825290205481565b610c428133611b13565b5050565b610c4e611dae565b600a54801580610c5c575082155b15610c675750610c42565b600854610c7c906001600160a01b0316611dd8565b600080610c8a848685611e65565b91509150610c988282611f5e565b610ca2848661225f565b5050505050565b6001600160a01b0381166000908152600b602052604081205480610cd1576000915050610d4c565b610cd9613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612395565b93505050505b919050565b6001546001600160a01b031681565b6005546001600160a01b031681565b6001600160a01b0381166000908152600b602052604081205480610d97576000915050610d4c565b610d9f613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b610e1533612582565b610e1e336125be565b610e27816125f5565b336000818152600d6020526040908190208381556001908101805460ff19169091179055517f19bc932fb9e16a8b5a1e41be9f4c2de59d5ddd7567b8b81405f532ca00a9880e90610e79908490614847565b60405180910390a250565b600e6020526000908152604090205481565b610c42828261261d565b60145481565b670de0b6b3a764000081565b6002546001600160a01b031681565b6801158e460913d0000081565b601154600160801b90046001600160801b031681565b6004546001600160a01b031681565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3757600080fd5b505afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b505afa158015610fd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff99190613d9e565b905061100b828263ffffffff6108a016565b9250505090565b6000546001600160a01b031681565b601360209081526000928352604080842090915290825290205481565b600c602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156110be57600080fd5b505afa1580156110d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f69190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b60008060405161115790613f26565b6040519081900390205492915050565b60105481565b6008546001600160a01b031681565b6003546001600160a01b031681565b6040518060400160405280600d81526020016c14dd18589a5b1a5d1e541bdbdb609a1b81525081565b6011546001600160801b031681565b600d602052600090815260409020805460019091015460ff1682565b6007546001600160a01b031681565b60165481565b600a5490565b600480546040805163e9fc346160e01b8152905160009361128c936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561124057600080fd5b505afa158015611254573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112789190613c36565b60065485906001600160a01b0316856127c0565b905061129981600061261d565b505050565b633b9aca0081565b6112ae611148565b6001600160a01b0316336001600160a01b0316146112de5760405162461bcd60e51b81526004016108959061451d565b6112e788611d69565b6112f087611d69565b6112f986611d69565b61130285611d69565b61130b84611d69565b61131483611d69565b61131d82611d69565b61132681611d69565b670de0b6b3a7640000601055600380546001600160a01b03199081166001600160a01b038b8116919091179092556004805482168a8416179055600580548216898416179055600080548216888416179055600680548216878416179055600780548216868416179055600280548216858416179055600880549091169183169190911790556040517f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed985906113dc908990613f43565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a5678866040516114139190613f43565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828560405161144a9190613f43565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d846040516114819190613f43565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800836040516114b89190613f43565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264826040516114ef9190613f43565b60405180910390a17f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac6811816040516115269190613f43565b60405180910390a15050505050505050565b60155481565b6001600160a01b0381166000908152600e602052604081205480611566576000915050610d4c565b6001600160a01b0383166000908152600d602052604081205490611598670de0b6b3a76400008363ffffffff612a6516565b90506115a2613b64565b506001600160a01b0385166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b869063ffffffff612b3316565b9063ffffffff612b6d16565b979650505050505050565b6001600160a01b0381166000908152600e60205260408120548061166a576000915050610d4c565b611672613b64565b506001600160a01b0383166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b6001600160a01b0381166000908152600b602052604081205480611707576000915050610d4c565b6001600160a01b038084166000908152600b602052604081206001015490911690811561174c576001600160a01b0382166000908152600d6020526040902054611756565b670de0b6b3a76400005b9050611760613b64565b506001600160a01b0385166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b6006546001600160a01b031681565b600b60205260009081526040902080546001909101546001600160a01b031682565b600480546040805163e9fc346160e01b815290516000936118c0936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561185357600080fd5b505afa158015611867573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188b9190613c36565b6006546001600160a01b0316867f00000000000000000000000000000000000000000000000000000000000000008787612baf565b9050610ca281600061261d565b336000908152600b60205260409020546118e681612dfc565b6118ef33612e1c565b6118f833612ebb565b6008546001600160a01b031661190d81611dd8565b600061191833610ca9565b9050600061192533610d6f565b90506000611939858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b039091169061196790869083612ee8565b600061197282611642565b90508061197f838261305d565b826001600160a01b031660008051602061496283398151915282336040516119a8929190614850565b60405180910390a26119ba33866131a5565b336001600160a01b031660008051602061494283398151915287866040516119e392919061403c565b60405180910390a2336001600160a01b031660008051602061492283398151915286604051611a129190614847565b60405180910390a2600954611a2d908763ffffffff612a6516565b600981905560405160008051602061490283398151915291611a4e91614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123387604051611a87929190613fdf565b60405180910390a1600460009054906101000a90046001600160a01b03166001600160a01b031663ea9638bf87338d8d6040518563ffffffff1660e01b8152600401611ad593929190613f57565b6000604051808303818588803b158015611aee57600080fd5b505af1158015611b02573d6000803e3d6000fd5b505050505050505050505050505050565b60006001600160a01b038216611b3b5760405162461bcd60e51b815260040161089590614434565b8215611b4957611b4961331a565b336000908152600b6020526040902054611b6281612dfc565b6008546001600160a01b0316611b7781611dd8565b6000611b8233610ca9565b90506000611b8f33610d6f565b90506000611b9d8883613551565b90506000611bb1868463ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b0390911690611bdf90879083612ee8565b6000611bea82611642565b90506000611bfe828663ffffffff612a6516565b9050611c0a838261305d565b826001600160a01b03166000805160206149628339815191528233604051611c33929190614850565b60405180910390a2611c458b86613567565b6000611c57878763ffffffff612a6516565b9050611c6333826131a5565b336001600160a01b031660008051602061492283398151915282604051611c8a9190614847565b60405180910390a2336001600160a01b03166000805160206149428339815191528987604051611cbb92919061403c565b60405180910390a2611ccd88336135e0565b50939b9a5050505050505050505050565b6001600160a01b038116611d045760405162461bcd60e51b81526004016108959061429f565b806001600160a01b0316611d16611148565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611d5990613f26565b6040519081900390209190915550565b6001600160a01b038116611d8f5760405162461bcd60e51b8152600401610895906142e1565b803b80610c425760405162461bcd60e51b815260040161089590614646565b6005546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614369565b600a54604051636cbdcf4760e01b81526000916001600160a01b03841691636cbdcf4791611e0891600401614847565b602060405180830381600087803b158015611e2257600080fd5b505af1158015611e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5a9190613d9e565b9050610c428161370f565b6000806000611e97601554611e8b670de0b6b3a764000089612b3390919063ffffffff16565b9063ffffffff6108a016565b905083851115611ea357fe5b83851415611ec0576000601655670de0b6b3a76400009150611f20565b601654600090611eee90611ee288670de0b6b3a764000063ffffffff612b3316565b9063ffffffff612a6516565b9050611f056001611e8b838863ffffffff612b6d16565b9250611f1b81611ee2858863ffffffff612b3316565b601655505b611f30818563ffffffff612b6d16565b9250611f52611f45848663ffffffff612b3316565b829063ffffffff612a6516565b60155550935093915050565b6010546000670de0b6b3a7640000831115611f7557fe5b6000611f8f670de0b6b3a76400008563ffffffff612a6516565b6011546001600160801b03600160801b820481166000818152601260209081526040808320949095168083529390529283205493945090929091611fd38988612b33565b90506000611fe7838363ffffffff6108a016565b6001600160801b038086166000908152601260209081526040808320938a168352929052819020829055519091507fe12e2cd2c9afa8069203ca07e7eff1edce4a075686d0736a8e7e0d593597b2079061204690839087908990614877565b60405180910390a18561211f5761206d6001600160801b038516600163ffffffff61382016565b601180546001600160801b03908116600160801b938216840217918290556040517fb50f0f59e7cb5b421dc77581c3a9919e3806e076e5fa78a874c3f120cb7d874d936120be930490911690614833565b60405180910390a1601180546001600160801b03191690556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9061210790600090614833565b60405180910390a1670de0b6b3a7640000965061220c565b633b9aca00612140670de0b6b3a764000061162b8b8a63ffffffff612b3316565b10156121ed57612176670de0b6b3a764000061162b633b9aca0061216a8c8b63ffffffff612b3316565b9063ffffffff612b3316565b96506121926001600160801b038616600163ffffffff61382016565b601180546001600160801b0319166001600160801b0392831617908190556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe926121e0921690614833565b60405180910390a161220c565b612209670de0b6b3a764000061162b8a8963ffffffff612b3316565b96505b6000871161221657fe5b60108790556040517fc1a9618cb59ebca77cbdbc2949f126823c407ff13edb285fd0262519a9c18e8c9061224b908990614847565b60405180910390a150505050505050505050565b60005460405163121cbc4d60e11b81526001600160a01b03909116908190632439789a90612291908590600401614847565b600060405180830381600087803b1580156122ab57600080fd5b505af11580156122bf573d6000803e3d6000fd5b505050506122cc82613851565b600654604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906122fe9030908690600401613fdf565b600060405180830381600087803b15801561231857600080fd5b505af115801561232c573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b03841692506364a197f3915061235e9030908790600401613fdf565b600060405180830381600087803b15801561237857600080fd5b505af115801561238c573d6000803e3d6000fd5b50505050505050565b6080810151606082015182516020808501516001600160801b038086166000908152601284526040808220928716825291909352822054919493929185906123e3908463ffffffff612a6516565b6001600160801b0380871660009081526012602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b6001600160801b031681526020810191909152604001600020549063ffffffff612b6d16565b90506000612478670de0b6b3a764000061162b868161246b888863ffffffff6108a016565b8f9063ffffffff612b3316565b9a9950505050505050505050565b6020810151606082015160808301516011546000939291906001600160801b03600160801b909104811690821610156124c557600093505050506108c8565b60115460009081906124e6906001600160801b03168563ffffffff6138ab16565b90506001600160801b0381166125165761250f8561162b6010548b612b3390919063ffffffff16565b915061254e565b806001600160801b0316600114156125495761250f633b9aca0061162b8761162b6010548d612b3390919063ffffffff16565b600091505b61256288633b9aca0063ffffffff612b6d16565b821015612577576000955050505050506108c8565b509695505050505050565b6001600160a01b0381166000908152600d602052604090206001015460ff1615610b335760405162461bcd60e51b81526004016108959061454e565b6001600160a01b0381166000908152600b60205260409020548015610c425760405162461bcd60e51b8152600401610895906145a7565b670de0b6b3a7640000811115610b335760405162461bcd60e51b815260040161089590614484565b612626816138e5565b61262f33612582565b61263882613932565b336000908152600b60205260409020546008546001600160a01b031661265d81611dd8565b8161266c5761266c3384613952565b600061267733610ca9565b9050600061268433610d6f565b90506000612698858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b03909116906126c690869083612ee8565b60006126d182611642565b905060006126e5828b63ffffffff6108a016565b90506126f1838261305d565b826001600160a01b0316600080516020614962833981519152823360405161271a929190614850565b60405180910390a261272c338b6139ac565b600061273e868c63ffffffff6108a016565b905061274a33826131a5565b336001600160a01b0316600080516020614922833981519152826040516127719190614847565b60405180910390a2336001600160a01b031660008051602061494283398151915288876040516127a292919061403c565b60405180910390a26127b387613a60565b5050505050505050505050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b1580156127fc57600080fd5b505afa158015612810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128349190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016128649190613f43565b60206040518083038186803b15801561287c57600080fd5b505afa158015612890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b49190613d9e565b9050306001600160a01b03831663605629d633838a89356128db60408c0160208d01613eea565b8b604001358c606001356040518863ffffffff1660e01b81526004016129079796959493929190613f9e565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b50505050866129ba83856001600160a01b03166370a08231856040518263ffffffff1660e01b815260040161296a9190613f43565b60206040518083038186803b15801561298257600080fd5b505afa158015612996573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee29190613d9e565b146129d75760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390612a079089908b903390600401614019565b602060405180830381600087803b158015612a2157600080fd5b505af1158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613d9e565b98975050505050505050565b60006108c583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a6a565b608081015160608201516040808401516020808601516001600160801b03808716600090815260138452858120918716815292529281205490949392908590612af6908463ffffffff612a6516565b6001600160801b0380871660009081526013602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b600082612b42575060006108c8565b82820282848281612b4f57fe5b04146108c55760405162461bcd60e51b8152600401610895906143f3565b60006108c583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613a96565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015612beb57600080fd5b505afa158015612bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c239190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612c539190613f43565b60206040518083038186803b158015612c6b57600080fd5b505afa158015612c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca39190613d9e565b87516020015190915030906001600160a01b0388166330f28b7a8a612cc88585613acd565b338b8b6040518663ffffffff1660e01b8152600401612ceb9594939291906147c2565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b5050505080612d4e84866001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161296a9190613f43565b14612d6b5760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390612d9b908d9085903390600401614019565b602060405180830381600087803b158015612db557600080fd5b505af1158015612dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ded9190613d9e565b9b9a5050505050505050505050565b60008111610b335760405162461bcd60e51b81526004016108959061467b565b6005546040516321e3780160e01b81526001600160a01b03909116906321e3780190612e4c908490600401613f43565b60206040518083038186803b158015612e6457600080fd5b505afa158015612e78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9c9190613d9e565b600114610b335760405162461bcd60e51b8152600401610895906140b3565b6000612ec682610ca9565b905060008111610c425760405162461bcd60e51b815260040161089590614318565b6001600160a01b03811615612fa8576000612f028261153e565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612f339085908590600401613fdf565b600060405180830381600087803b158015612f4d57600080fd5b505af1158015612f61573d6000803e3d6000fd5b50505050816001600160a01b03167f732e331072fe280a520929e5f2cc76c223389ff57d32a4e278cfded03e6f1caa82604051612f9e9190614847565b60405180910390a2505b6000612fb3836116df565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612fe49086908590600401613fdf565b600060405180830381600087803b158015612ffe57600080fd5b505af1158015613012573d6000803e3d6000fd5b50505050826001600160a01b03167fe9ac2dcd83e719358f1dc0c5c80491937f67d4ec61ef62c262bbe3b78578f92a8260405161304f9190614847565b60405180910390a250505050565b6001600160a01b0382166000908152600e60205260409020819055806130e8576001600160a01b0382166000818152600f60205260408082208281556001810183905560028101839055600301829055517fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e45916130db91819061403c565b60405180910390a2610c42565b6011546010546001600160801b03600160801b80840482166000818152601360209081526040808320978616808452978252808320546001600160a01b038b16808552600f90935292819020600181018890556002810184905560030180546001600160801b0319168917909616948402949094179094559151909392907fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e4590613195908590859061403c565b60405180910390a2505050505050565b6001600160a01b0382166000908152600b6020526040902081905580613243576001600160a01b0382166000818152600b60209081526040808320600190810180546001600160a01b0319169055600c909252808320838155918201839055600282018390556003909101829055517f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a916130db918190819061404a565b6011546010546001600160801b03600160801b8084048216600081815260126020908152604080832097861680845297825280832054848452601383528184208985528352818420546001600160a01b038c16808652600c90945293829020600181018990558181556002810185905560030180546001600160801b0319168a1790971695850295909517909555935191949390917f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a906133099086908690869061404a565b60405180910390a250505050505050565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561336057600080fd5b505af1158015613374573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133989190613d9e565b90506000600760009054906101000a90046001600160a01b03166001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ea57600080fd5b505afa1580156133fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134229190613c36565b600554604051630d293c7160e41b81529192506000916001600160a01b039091169063d293c7109061345a9085908790600401613fdf565b60206040518083038186803b15801561347257600080fd5b505afa158015613486573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134aa9190613d9e565b9050600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156134fa57600080fd5b505afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135329190613d9e565b8110156112995760405162461bcd60e51b815260040161089590614758565b600081831061356057816108c5565b5090919050565b8061357157610c42565b600654604051631062c15f60e11b81526001600160a01b03909116906320c582be906135a590309086908690600401613f7a565b600060405180830381600087803b1580156135bf57600080fd5b505af11580156135d3573d6000803e3d6000fd5b50505050610c4281613851565b6001600160a01b0381166136065760405162461bcd60e51b81526004016108959061419f565b8161361057610c42565b600954600090613626908463ffffffff612a6516565b9050806009819055506000805160206149028339815191528160405161364c9190614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123384604051613685929190613fdf565b60405180910390a16000336001600160a01b0316846040516136a690613f23565b60006040518083038185875af1925050503d80600081146136e3576040519150601f19603f3d011682016040523d82523d6000602084013e6136e8565b606091505b50509050806137095760405162461bcd60e51b8152600401610895906143b2565b50505050565b600a5480158061371d575081155b156137285750610b33565b60006137348383613aff565b9050600061374d60105483612b3390919063ffffffff16565b6011546001600160801b03600160801b820481166000908152601360209081526040808320939094168252919091522054909150613791908263ffffffff6108a016565b601180546001600160801b03600160801b80830482166000908152601360208181526040808420968616845295815285832097909755945491820483168082529486528381209190921680835294528190205490517f2d6127771b164a9cc8827d24b5955db2a77e7a81dac389107ebb8bce9fb64968936138129391614877565b60405180910390a150505050565b60008282016001600160801b0380851690821610156108c55760405162461bcd60e51b815260040161089590614713565b600a54600090613867908363ffffffff612a6516565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c78160405161389f9190614847565b60405180910390a15050565b6000826001600160801b0316826001600160801b031611156138df5760405162461bcd60e51b8152600401610895906146cb565b50900390565b6001600160a01b0381166000908152600d602052604090206001015460ff168061391657506001600160a01b038116155b610b335760405162461bcd60e51b8152600401610895906141ec565b60008111610b335760405162461bcd60e51b8152600401610895906144d7565b6001600160a01b038281166000818152600b602052604080822060010180546001600160a01b0319169486169485179055517f094c08e96a8890877a8390b4f967180a7507ad8622244d05fcd0f9f8e086564e9190a35050565b600654604051632ee65eeb60e21b81526001600160a01b039091169063bb997bac906139e090859030908690600401613f7a565b600060405180830381600087803b1580156139fa57600080fd5b505af1158015613a0e573d6000803e3d6000fd5b5050600a5460009250613a2891508363ffffffff6108a016565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c781604051610ac19190614847565b610b3381336135e0565b60008184841115613a8e5760405162461bcd60e51b81526004016108959190614060565b505050900390565b60008183613ab75760405162461bcd60e51b81526004016108959190614060565b506000838581613ac357fe5b0495945050505050565b613ad5613ba5565b613add613ba5565b5050604080518082019091526001600160a01b03929092168252602082015290565b600080613b23601454611e8b670de0b6b3a764000087612b3390919063ffffffff16565b90506000613b37828563ffffffff612b6d16565b9050613b59613b4c828663ffffffff612b3316565b839063ffffffff612a6516565b601455949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b604080518082019091526000808252602082015290565b60008083601f840112613bcd578182fd5b50813567ffffffffffffffff811115613be4578182fd5b602083019150836020828501011115613bfc57600080fd5b9250929050565b80356001600160801b03811681146108c857600080fd5b600060208284031215613c2b578081fd5b81356108c5816148ec565b600060208284031215613c47578081fd5b81516108c5816148ec565b60008060408385031215613c64578081fd5b8235613c6f816148ec565b91506020830135613c7f816148ec565b809150509250929050565b600080600080600080600080610100898b031215613ca6578384fd5b8835613cb1816148ec565b97506020890135613cc1816148ec565b96506040890135613cd1816148ec565b95506060890135613ce1816148ec565b94506080890135613cf1816148ec565b935060a0890135613d01816148ec565b925060c0890135613d11816148ec565b915060e0890135613d21816148ec565b809150509295985092959890939650565b600060208284031215613d43578081fd5b815180151581146108c5578182fd5b60008060408385031215613d64578182fd5b613d6e8484613c03565b9150613d7d8460208501613c03565b90509250929050565b600060208284031215613d97578081fd5b5035919050565b600060208284031215613daf578081fd5b5051919050565b60008060408385031215613dc8578182fd5b823591506020830135613c7f816148ec565b60008082840360a0811215613ded578283fd5b833592506080601f1982011215613e02578182fd5b506020830190509250929050565b60008060008084860360c0811215613e26578485fd5b85359450601f1981016080811215613e3c578485fd5b613e4660606148c5565b91506040811215613e55578485fd5b50613e6060406148c5565b6020870135613e6e816148ec565b80825250604087013560208201528082525060608601356020820152608086013560408201528093505060a085013567ffffffffffffffff811115613eb1578283fd5b613ebd87828801613bbc565b95989497509550505050565b60008060408385031215613edb578182fd5b50508035926020909101359150565b600060208284031215613efb578081fd5b813560ff811681146108c5578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b6000602080835283518082850152825b8181101561408c57858101830151858201604001528201614070565b8181111561409d5783604083870101525b50601f01601f1916929092016040019392505050565b60208082526046908201527f53746162696c697479506f6f6c3a2063616c6c6572206d75737420686176652060408201527f616e206163746976652074726f766520746f207769746864726177204554484760608201526561696e20746f60d01b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252602d908201527f53503a3a5f73656e644554484761696e546f3a205f726563656976657220697360408201526c207a65726f206164647265737360981b606082015260800190565b60208082526046908201527f53746162696c697479506f6f6c3a20546167206d75737420626520612072656760408201527f697374657265642066726f6e7420656e642c206f7220746865207a65726f206160608201526564647265737360d01b608082015260a00190565b60208082526027908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f74204163746040820152661a5d99541bdbdb60ca1b606082015260800190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526031908201527f53746162696c697479506f6f6c3a2063616c6c6572206d7573742068617665206040820152703737b716bd32b9379022aa241023b0b4b760791b606082015260800190565b60208082526029908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f742054726f6040820152683b32a6b0b730b3b2b960b91b606082015260800190565b60208082526021908201527f53746162696c697479506f6f6c3a2073656e64696e6720455448206661696c656040820152601960fa1b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526030908201527f53503a3a5f776974686472617746726f6d5370546f3a205f726563656976657260408201526f206973207a65726f206164647265737360801b606082015260800190565b60208082526033908201527f53746162696c697479506f6f6c3a204b69636b6261636b2072617465206d75736040820152727420626520696e2072616e6765205b302c315d60681b606082015260800190565b60208082526026908201527f53746162696c697479506f6f6c3a20416d6f756e74206d757374206265206e6f6040820152656e2d7a65726f60d01b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526039908201527f53746162696c697479506f6f6c3a206d757374206e6f7420616c72656164792060408201527818994818481c9959da5cdd195c995908199c9bdb9d08195b99603a1b606082015260800190565b60208082526028908201527f53746162696c697479506f6f6c3a2055736572206d7573742068617665206e6f6040820152670819195c1bdcda5d60c21b606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526030908201527f53746162696c697479506f6f6c3a2055736572206d757374206861766520612060408201526f1b9bdb8b5e995c9bc819195c1bdcda5d60821b606082015260800190565b60208082526028908201527f4c697175697479536166654d6174683132383a207375627472616374696f6e206040820152676f766572666c6f7760c01b606082015260800190565b60208082526025908201527f4c697175697479536166654d6174683132383a206164646974696f6e206f766560408201526472666c6f7760d81b606082015260800190565b60208082526044908201527f53746162696c697479506f6f6c3a2043616e6e6f74207769746864726177207760408201527f68696c65207468657265206172652074726f766573207769746820494352203c6060820152631026a1a960e11b608082015260a00190565b60006101006147d2838951613f0b565b60208801516040840152604088015160608401526147f36080840188613f0b565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b6001600160801b0391909116815260200190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9182521515602082015260400190565b9283526001600160801b03918216602084015216604082015260600190565b948552602085019390935260408401919091526001600160801b03908116606084015216608082015260a00190565b60405181810167ffffffffffffffff811182821017156148e457600080fd5b604052919050565b6001600160a01b0381168114610b3357600080fdfeceb6d671277d4354fd29977ada70695fbd93a16612abf765d6b0e25c28dc6db3bce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c951457222ebca92c335c9c86e2baa1cc0e40ffaa9084a51452980d5ba8dec2f6399920012339b5a3368d3a04b8606ce412c46ed92b7dcd8602d41fc8862cb8f25a2646970667358221220b12079f570461c3902a02d925635ecefb92e70f4556abddd99509e1ecfffdece64736f6c634300060b0033", + "deployedBytecode": "0x6080604052600436106102ad5760003560e01c806382e0a57411610165578063b31ee965116100cc578063de13da3c11610085578063de13da3c14610788578063df9cd84f146107a8578063e49d3667146107c8578063ec9f7d46146107e8578063fc7e286d146107fd578063fce6b7341461082b578063fda0101a1461084b576102f8565b8063b31ee965146106f4578063bdaf37ea14610709578063c3a34a0e1461071e578063ce4b5bbe1461073e578063d733cfd014610753578063d7fb044314610773576102f8565b80639f0706701161011e5780639f07067014610665578063a20baee614610531578063a3f4df7e1461067a578063a4e59ac81461069c578063a7bfff97146106b1578063ae918754146106df576102f8565b806382e0a574146105d157806386da0824146105f1578063887105d314610611578063893d20e8146106265780638b8fbd921461063b57806395fb16bb14610650576102f8565b80633d83908a1161021457806372fe25aa116101cd57806372fe25aa14610531578063741bef1a14610546578063759b30341461055b578063766718081461057057806377553ad414610592578063795d26c3146105a75780637f7dde4a146105bc576102f8565b80633d83908a1461048757806340ed1afd1461049c578063556be101146104bc5780635d2de642146104dc5780635f788d65146104fc57806370f1b5721461051c576102f8565b80632199b66f116102665780632199b66f146103d257806328a0a04d146103f25780632e54bf9514610412578063335525ad14610432578063389e92a5146104525780633cc7422514610472576102f8565b80630fbfe38b146102fd57806312261ee71461031f57806313af40351461034a57806314f6c3be1461036a57806316b9d3c51461038c5780631bf43555146103bd576102f8565b366102f8576102ba61086b565b6009546102cd903463ffffffff6108a016565b6009819055604051600080516020614902833981519152916102ee91614847565b60405180910390a1005b600080fd5b34801561030957600080fd5b5061031d610318366004613d86565b6108ce565b005b34801561032b57600080fd5b50610334610ace565b6040516103419190613f43565b60405180910390f35b34801561035657600080fd5b5061031d610365366004613c1a565b610af2565b34801561037657600080fd5b5061037f610b36565b6040516103419190614847565b34801561039857600080fd5b506103ac6103a7366004613c1a565b610b3c565b604051610341959493929190614896565b3480156103c957600080fd5b5061037f610b77565b3480156103de57600080fd5b5061031d6103ed366004613c1a565b610b84565b3480156103fe57600080fd5b5061037f61040d366004613d52565b610c1b565b34801561041e57600080fd5b5061031d61042d366004613d86565b610c38565b34801561043e57600080fd5b5061031d61044d366004613ec9565b610c46565b34801561045e57600080fd5b5061037f61046d366004613c1a565b610ca9565b34801561047e57600080fd5b50610334610d51565b34801561049357600080fd5b50610334610d60565b3480156104a857600080fd5b5061037f6104b7366004613c1a565b610d6f565b3480156104c857600080fd5b5061031d6104d7366004613d86565b610e0c565b3480156104e857600080fd5b5061037f6104f7366004613c1a565b610e84565b34801561050857600080fd5b5061031d610517366004613db6565b610e96565b34801561052857600080fd5b5061037f610ea0565b34801561053d57600080fd5b5061037f610ea6565b34801561055257600080fd5b50610334610eb2565b34801561056757600080fd5b5061037f610ec1565b34801561057c57600080fd5b50610585610ece565b6040516103419190614833565b34801561059e57600080fd5b50610334610ee4565b3480156105b357600080fd5b5061037f610ef3565b3480156105c857600080fd5b50610334611012565b3480156105dd57600080fd5b5061037f6105ec366004613d52565b611021565b3480156105fd57600080fd5b506103ac61060c366004613c1a565b61103e565b34801561061d57600080fd5b5061037f611079565b34801561063257600080fd5b50610334611148565b34801561064757600080fd5b5061037f611167565b34801561065c57600080fd5b5061033461116d565b34801561067157600080fd5b5061033461117c565b34801561068657600080fd5b5061068f61118b565b6040516103419190614060565b3480156106a857600080fd5b506105856111b4565b3480156106bd57600080fd5b506106d16106cc366004613c1a565b6111c3565b604051610341929190614867565b3480156106eb57600080fd5b506103346111df565b34801561070057600080fd5b5061037f6111ee565b34801561071557600080fd5b5061037f6111f4565b34801561072a57600080fd5b5061031d610739366004613dda565b6111fa565b34801561074a57600080fd5b5061037f61129e565b34801561075f57600080fd5b5061031d61076e366004613c8a565b6112a6565b34801561077f57600080fd5b5061037f611538565b34801561079457600080fd5b5061037f6107a3366004613c1a565b61153e565b3480156107b457600080fd5b5061037f6107c3366004613c1a565b611642565b3480156107d457600080fd5b5061037f6107e3366004613c1a565b6116df565b3480156107f457600080fd5b506103346117dc565b34801561080957600080fd5b5061081d610818366004613c1a565b6117eb565b604051610341929190614850565b34801561083757600080fd5b5061031d610846366004613e10565b61180d565b34801561085757600080fd5b5061031d610866366004613c52565b6118cd565b6000546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614258565b60405180910390fd5b565b6000828201838110156108c55760405162461bcd60e51b815260040161089590614168565b90505b92915050565b6000600460009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561091e57600080fd5b505afa158015610932573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109569190613c36565b905060006109648330611b13565b60065460405163095ea7b360e01b81529192506001600160a01b03169063095ea7b3906109979085908590600401613fdf565b602060405180830381600087803b1580156109b157600080fd5b505af11580156109c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e99190613d32565b610a055760405162461bcd60e51b8152600401610895906145ef565b60065460405163438b1b4b60e01b81526001600160a01b038481169263438b1b4b92610a3b929091169085903390600401614019565b602060405180830381600087803b158015610a5557600080fd5b505af1158015610a69573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8d9190613d9e565b507f2b0fbec1c4e7e30517f196a714775ffe72770d2348f5d586854bb3c0fdf41df8338483604051610ac193929190613ff8565b60405180910390a1505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b610afa611148565b6001600160a01b0316336001600160a01b031614610b2a5760405162461bcd60e51b81526004016108959061451d565b610b3381611cde565b50565b60095490565b600f602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6809c2007651b250000081565b610b8c611148565b6001600160a01b0316336001600160a01b031614610bbc5760405162461bcd60e51b81526004016108959061451d565b610bc581611d69565b600880546001600160a01b0319166001600160a01b0383161790556040517f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac681190610c10908390613f43565b60405180910390a150565b601260209081526000928352604080842090915290825290205481565b610c428133611b13565b5050565b610c4e611dae565b600a54801580610c5c575082155b15610c675750610c42565b600854610c7c906001600160a01b0316611dd8565b600080610c8a848685611e65565b91509150610c988282611f5e565b610ca2848661225f565b5050505050565b6001600160a01b0381166000908152600b602052604081205480610cd1576000915050610d4c565b610cd9613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612395565b93505050505b919050565b6001546001600160a01b031681565b6005546001600160a01b031681565b6001600160a01b0381166000908152600b602052604081205480610d97576000915050610d4c565b610d9f613b64565b506001600160a01b0383166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b610e1533612582565b610e1e336125be565b610e27816125f5565b336000818152600d6020526040908190208381556001908101805460ff19169091179055517f19bc932fb9e16a8b5a1e41be9f4c2de59d5ddd7567b8b81405f532ca00a9880e90610e79908490614847565b60405180910390a250565b600e6020526000908152604090205481565b610c42828261261d565b60145481565b670de0b6b3a764000081565b6002546001600160a01b031681565b6801158e460913d0000081565b601154600160801b90046001600160801b031681565b6004546001600160a01b031681565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015610f3757600080fd5b505afa158015610f4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6f9190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b505afa158015610fd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff99190613d9e565b905061100b828263ffffffff6108a016565b9250505090565b6000546001600160a01b031681565b601360209081526000928352604080842090915290825290205481565b600c602052600090815260409020805460018201546002830154600390930154919290916001600160801b0380821691600160801b90041685565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156110be57600080fd5b505afa1580156110d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f69190613d9e565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc157600080fd5b60008060405161115790613f26565b6040519081900390205492915050565b60105481565b6008546001600160a01b031681565b6003546001600160a01b031681565b6040518060400160405280600d81526020016c14dd18589a5b1a5d1e541bdbdb609a1b81525081565b6011546001600160801b031681565b600d602052600090815260409020805460019091015460ff1682565b6007546001600160a01b031681565b60165481565b600a5490565b600480546040805163e9fc346160e01b8152905160009361128c936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561124057600080fd5b505afa158015611254573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112789190613c36565b60065485906001600160a01b0316856127c0565b905061129981600061261d565b505050565b633b9aca0081565b6112ae611148565b6001600160a01b0316336001600160a01b0316146112de5760405162461bcd60e51b81526004016108959061451d565b6112e788611d69565b6112f087611d69565b6112f986611d69565b61130285611d69565b61130b84611d69565b61131483611d69565b61131d82611d69565b61132681611d69565b670de0b6b3a7640000601055600380546001600160a01b03199081166001600160a01b038b8116919091179092556004805482168a8416179055600580548216898416179055600080548216888416179055600680548216878416179055600780548216868416179055600280548216858416179055600880549091169183169190911790556040517f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed985906113dc908990613f43565b60405180910390a17f143219c9e69b09e07e095fcc889b43d8f46ca892bba65f08dc3a0050869a5678866040516114139190613f43565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828560405161144a9190613f43565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d846040516114819190613f43565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800836040516114b89190613f43565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264826040516114ef9190613f43565b60405180910390a17f3055265812fb8447b9ada4a5d804ec43bd528ec40e89c952bbc7b85dc5ac6811816040516115269190613f43565b60405180910390a15050505050505050565b60155481565b6001600160a01b0381166000908152600e602052604081205480611566576000915050610d4c565b6001600160a01b0383166000908152600d602052604081205490611598670de0b6b3a76400008363ffffffff612a6516565b90506115a2613b64565b506001600160a01b0385166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b869063ffffffff612b3316565b9063ffffffff612b6d16565b979650505050505050565b6001600160a01b0381166000908152600e60205260408120548061166a576000915050610d4c565b611672613b64565b506001600160a01b0383166000908152600f60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290610d468383612486565b6001600160a01b0381166000908152600b602052604081205480611707576000915050610d4c565b6001600160a01b038084166000908152600b602052604081206001015490911690811561174c576001600160a01b0382166000908152600d6020526040902054611756565b670de0b6b3a76400005b9050611760613b64565b506001600160a01b0385166000908152600c60209081526040808320815160a08101835281548152600182015493810193909352600281015491830191909152600301546001600160801b038082166060840152600160801b90910416608082015290611637670de0b6b3a764000061162b61161e8886612aa7565b6006546001600160a01b031681565b600b60205260009081526040902080546001909101546001600160a01b031682565b600480546040805163e9fc346160e01b815290516000936118c0936001600160a01b03169263e9fc34619281830192602092829003018186803b15801561185357600080fd5b505afa158015611867573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188b9190613c36565b6006546001600160a01b0316867f00000000000000000000000000000000000000000000000000000000000000008787612baf565b9050610ca281600061261d565b336000908152600b60205260409020546118e681612dfc565b6118ef33612e1c565b6118f833612ebb565b6008546001600160a01b031661190d81611dd8565b600061191833610ca9565b9050600061192533610d6f565b90506000611939858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b039091169061196790869083612ee8565b600061197282611642565b90508061197f838261305d565b826001600160a01b031660008051602061496283398151915282336040516119a8929190614850565b60405180910390a26119ba33866131a5565b336001600160a01b031660008051602061494283398151915287866040516119e392919061403c565b60405180910390a2336001600160a01b031660008051602061492283398151915286604051611a129190614847565b60405180910390a2600954611a2d908763ffffffff612a6516565b600981905560405160008051602061490283398151915291611a4e91614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123387604051611a87929190613fdf565b60405180910390a1600460009054906101000a90046001600160a01b03166001600160a01b031663ea9638bf87338d8d6040518563ffffffff1660e01b8152600401611ad593929190613f57565b6000604051808303818588803b158015611aee57600080fd5b505af1158015611b02573d6000803e3d6000fd5b505050505050505050505050505050565b60006001600160a01b038216611b3b5760405162461bcd60e51b815260040161089590614434565b8215611b4957611b4961331a565b336000908152600b6020526040902054611b6281612dfc565b6008546001600160a01b0316611b7781611dd8565b6000611b8233610ca9565b90506000611b8f33610d6f565b90506000611b9d8883613551565b90506000611bb1868463ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b0390911690611bdf90879083612ee8565b6000611bea82611642565b90506000611bfe828663ffffffff612a6516565b9050611c0a838261305d565b826001600160a01b03166000805160206149628339815191528233604051611c33929190614850565b60405180910390a2611c458b86613567565b6000611c57878763ffffffff612a6516565b9050611c6333826131a5565b336001600160a01b031660008051602061492283398151915282604051611c8a9190614847565b60405180910390a2336001600160a01b03166000805160206149428339815191528987604051611cbb92919061403c565b60405180910390a2611ccd88336135e0565b50939b9a5050505050505050505050565b6001600160a01b038116611d045760405162461bcd60e51b81526004016108959061429f565b806001600160a01b0316611d16611148565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611d5990613f26565b6040519081900390209190915550565b6001600160a01b038116611d8f5760405162461bcd60e51b8152600401610895906142e1565b803b80610c425760405162461bcd60e51b815260040161089590614646565b6005546001600160a01b0316331461089e5760405162461bcd60e51b815260040161089590614369565b600a54604051636cbdcf4760e01b81526000916001600160a01b03841691636cbdcf4791611e0891600401614847565b602060405180830381600087803b158015611e2257600080fd5b505af1158015611e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e5a9190613d9e565b9050610c428161370f565b6000806000611e97601554611e8b670de0b6b3a764000089612b3390919063ffffffff16565b9063ffffffff6108a016565b905083851115611ea357fe5b83851415611ec0576000601655670de0b6b3a76400009150611f20565b601654600090611eee90611ee288670de0b6b3a764000063ffffffff612b3316565b9063ffffffff612a6516565b9050611f056001611e8b838863ffffffff612b6d16565b9250611f1b81611ee2858863ffffffff612b3316565b601655505b611f30818563ffffffff612b6d16565b9250611f52611f45848663ffffffff612b3316565b829063ffffffff612a6516565b60155550935093915050565b6010546000670de0b6b3a7640000831115611f7557fe5b6000611f8f670de0b6b3a76400008563ffffffff612a6516565b6011546001600160801b03600160801b820481166000818152601260209081526040808320949095168083529390529283205493945090929091611fd38988612b33565b90506000611fe7838363ffffffff6108a016565b6001600160801b038086166000908152601260209081526040808320938a168352929052819020829055519091507fe12e2cd2c9afa8069203ca07e7eff1edce4a075686d0736a8e7e0d593597b2079061204690839087908990614877565b60405180910390a18561211f5761206d6001600160801b038516600163ffffffff61382016565b601180546001600160801b03908116600160801b938216840217918290556040517fb50f0f59e7cb5b421dc77581c3a9919e3806e076e5fa78a874c3f120cb7d874d936120be930490911690614833565b60405180910390a1601180546001600160801b03191690556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe9061210790600090614833565b60405180910390a1670de0b6b3a7640000965061220c565b633b9aca00612140670de0b6b3a764000061162b8b8a63ffffffff612b3316565b10156121ed57612176670de0b6b3a764000061162b633b9aca0061216a8c8b63ffffffff612b3316565b9063ffffffff612b3316565b96506121926001600160801b038616600163ffffffff61382016565b601180546001600160801b0319166001600160801b0392831617908190556040517f1f9dfc70cd666adb18a39d60a797518f7b4febf4b6e24ef37d44f6e1e7219fbe926121e0921690614833565b60405180910390a161220c565b612209670de0b6b3a764000061162b8a8963ffffffff612b3316565b96505b6000871161221657fe5b60108790556040517fc1a9618cb59ebca77cbdbc2949f126823c407ff13edb285fd0262519a9c18e8c9061224b908990614847565b60405180910390a150505050505050505050565b60005460405163121cbc4d60e11b81526001600160a01b03909116908190632439789a90612291908590600401614847565b600060405180830381600087803b1580156122ab57600080fd5b505af11580156122bf573d6000803e3d6000fd5b505050506122cc82613851565b600654604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac906122fe9030908690600401613fdf565b600060405180830381600087803b15801561231857600080fd5b505af115801561232c573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b03841692506364a197f3915061235e9030908790600401613fdf565b600060405180830381600087803b15801561237857600080fd5b505af115801561238c573d6000803e3d6000fd5b50505050505050565b6080810151606082015182516020808501516001600160801b038086166000908152601284526040808220928716825291909352822054919493929185906123e3908463ffffffff612a6516565b6001600160801b0380871660009081526012602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b6001600160801b031681526020810191909152604001600020549063ffffffff612b6d16565b90506000612478670de0b6b3a764000061162b868161246b888863ffffffff6108a016565b8f9063ffffffff612b3316565b9a9950505050505050505050565b6020810151606082015160808301516011546000939291906001600160801b03600160801b909104811690821610156124c557600093505050506108c8565b60115460009081906124e6906001600160801b03168563ffffffff6138ab16565b90506001600160801b0381166125165761250f8561162b6010548b612b3390919063ffffffff16565b915061254e565b806001600160801b0316600114156125495761250f633b9aca0061162b8761162b6010548d612b3390919063ffffffff16565b600091505b61256288633b9aca0063ffffffff612b6d16565b821015612577576000955050505050506108c8565b509695505050505050565b6001600160a01b0381166000908152600d602052604090206001015460ff1615610b335760405162461bcd60e51b81526004016108959061454e565b6001600160a01b0381166000908152600b60205260409020548015610c425760405162461bcd60e51b8152600401610895906145a7565b670de0b6b3a7640000811115610b335760405162461bcd60e51b815260040161089590614484565b612626816138e5565b61262f33612582565b61263882613932565b336000908152600b60205260409020546008546001600160a01b031661265d81611dd8565b8161266c5761266c3384613952565b600061267733610ca9565b9050600061268433610d6f565b90506000612698858363ffffffff612a6516565b336000818152600b60205260409020600101549192506001600160a01b03909116906126c690869083612ee8565b60006126d182611642565b905060006126e5828b63ffffffff6108a016565b90506126f1838261305d565b826001600160a01b0316600080516020614962833981519152823360405161271a929190614850565b60405180910390a261272c338b6139ac565b600061273e868c63ffffffff6108a016565b905061274a33826131a5565b336001600160a01b0316600080516020614922833981519152826040516127719190614847565b60405180910390a2336001600160a01b031660008051602061494283398151915288876040516127a292919061403c565b60405180910390a26127b387613a60565b5050505050505050505050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b1580156127fc57600080fd5b505afa158015612810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128349190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016128649190613f43565b60206040518083038186803b15801561287c57600080fd5b505afa158015612890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128b49190613d9e565b9050306001600160a01b03831663605629d633838a89356128db60408c0160208d01613eea565b8b604001358c606001356040518863ffffffff1660e01b81526004016129079796959493929190613f9e565b600060405180830381600087803b15801561292157600080fd5b505af1158015612935573d6000803e3d6000fd5b50505050866129ba83856001600160a01b03166370a08231856040518263ffffffff1660e01b815260040161296a9190613f43565b60206040518083038186803b15801561298257600080fd5b505afa158015612996573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ee29190613d9e565b146129d75760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390612a079089908b903390600401614019565b602060405180830381600087803b158015612a2157600080fd5b505af1158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613d9e565b98975050505050505050565b60006108c583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613a6a565b608081015160608201516040808401516020808601516001600160801b03808716600090815260138452858120918716815292529281205490949392908590612af6908463ffffffff612a6516565b6001600160801b0380871660009081526013602052604081209293509161244691633b9aca0091908490612420908a16600163ffffffff61382016565b600082612b42575060006108c8565b82820282848281612b4f57fe5b04146108c55760405162461bcd60e51b8152600401610895906143f3565b60006108c583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613a96565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015612beb57600080fd5b505afa158015612bff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c239190613c36565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401612c539190613f43565b60206040518083038186803b158015612c6b57600080fd5b505afa158015612c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca39190613d9e565b87516020015190915030906001600160a01b0388166330f28b7a8a612cc88585613acd565b338b8b6040518663ffffffff1660e01b8152600401612ceb9594939291906147c2565b600060405180830381600087803b158015612d0557600080fd5b505af1158015612d19573d6000803e3d6000fd5b5050505080612d4e84866001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161296a9190613f43565b14612d6b5760405162461bcd60e51b81526004016108959061411f565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390612d9b908d9085903390600401614019565b602060405180830381600087803b158015612db557600080fd5b505af1158015612dc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ded9190613d9e565b9b9a5050505050505050505050565b60008111610b335760405162461bcd60e51b81526004016108959061467b565b6005546040516321e3780160e01b81526001600160a01b03909116906321e3780190612e4c908490600401613f43565b60206040518083038186803b158015612e6457600080fd5b505afa158015612e78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e9c9190613d9e565b600114610b335760405162461bcd60e51b8152600401610895906140b3565b6000612ec682610ca9565b905060008111610c425760405162461bcd60e51b815260040161089590614318565b6001600160a01b03811615612fa8576000612f028261153e565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612f339085908590600401613fdf565b600060405180830381600087803b158015612f4d57600080fd5b505af1158015612f61573d6000803e3d6000fd5b50505050816001600160a01b03167f732e331072fe280a520929e5f2cc76c223389ff57d32a4e278cfded03e6f1caa82604051612f9e9190614847565b60405180910390a2505b6000612fb3836116df565b604051633e30771b60e21b81529091506001600160a01b0385169063f8c1dc6c90612fe49086908590600401613fdf565b600060405180830381600087803b158015612ffe57600080fd5b505af1158015613012573d6000803e3d6000fd5b50505050826001600160a01b03167fe9ac2dcd83e719358f1dc0c5c80491937f67d4ec61ef62c262bbe3b78578f92a8260405161304f9190614847565b60405180910390a250505050565b6001600160a01b0382166000908152600e60205260409020819055806130e8576001600160a01b0382166000818152600f60205260408082208281556001810183905560028101839055600301829055517fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e45916130db91819061403c565b60405180910390a2610c42565b6011546010546001600160801b03600160801b80840482166000818152601360209081526040808320978616808452978252808320546001600160a01b038b16808552600f90935292819020600181018890556002810184905560030180546001600160801b0319168917909616948402949094179094559151909392907fbb1322f85cc7cc8bac4e172a5bc5dcc0c1959007f9a030032abf9258205f0e4590613195908590859061403c565b60405180910390a2505050505050565b6001600160a01b0382166000908152600b6020526040902081905580613243576001600160a01b0382166000818152600b60209081526040808320600190810180546001600160a01b0319169055600c909252808320838155918201839055600282018390556003909101829055517f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a916130db918190819061404a565b6011546010546001600160801b03600160801b8084048216600081815260126020908152604080832097861680845297825280832054848452601383528184208985528352818420546001600160a01b038c16808652600c90945293829020600181018990558181556002810185905560030180546001600160801b0319168a1790971695850295909517909555935191949390917f2d6cc0bcdf72c9486f6451bde6b80f44066f4558f77f44dbfedbe7d8b295225a906133099086908690869061404a565b60405180910390a250505050505050565b60025460408051630fdb11cf60e01b815290516000926001600160a01b031691630fdb11cf91600480830192602092919082900301818787803b15801561336057600080fd5b505af1158015613374573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133989190613d9e565b90506000600760009054906101000a90046001600160a01b03166001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156133ea57600080fd5b505afa1580156133fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134229190613c36565b600554604051630d293c7160e41b81529192506000916001600160a01b039091169063d293c7109061345a9085908790600401613fdf565b60206040518083038186803b15801561347257600080fd5b505afa158015613486573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134aa9190613d9e565b9050600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156134fa57600080fd5b505afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135329190613d9e565b8110156112995760405162461bcd60e51b815260040161089590614758565b600081831061356057816108c5565b5090919050565b8061357157610c42565b600654604051631062c15f60e11b81526001600160a01b03909116906320c582be906135a590309086908690600401613f7a565b600060405180830381600087803b1580156135bf57600080fd5b505af11580156135d3573d6000803e3d6000fd5b50505050610c4281613851565b6001600160a01b0381166136065760405162461bcd60e51b81526004016108959061419f565b8161361057610c42565b600954600090613626908463ffffffff612a6516565b9050806009819055506000805160206149028339815191528160405161364c9190614847565b60405180910390a17f6109e2559dfa766aaec7118351d48a523f0a4157f49c8d68749c8ac41318ad123384604051613685929190613fdf565b60405180910390a16000336001600160a01b0316846040516136a690613f23565b60006040518083038185875af1925050503d80600081146136e3576040519150601f19603f3d011682016040523d82523d6000602084013e6136e8565b606091505b50509050806137095760405162461bcd60e51b8152600401610895906143b2565b50505050565b600a5480158061371d575081155b156137285750610b33565b60006137348383613aff565b9050600061374d60105483612b3390919063ffffffff16565b6011546001600160801b03600160801b820481166000908152601360209081526040808320939094168252919091522054909150613791908263ffffffff6108a016565b601180546001600160801b03600160801b80830482166000908152601360208181526040808420968616845295815285832097909755945491820483168082529486528381209190921680835294528190205490517f2d6127771b164a9cc8827d24b5955db2a77e7a81dac389107ebb8bce9fb64968936138129391614877565b60405180910390a150505050565b60008282016001600160801b0380851690821610156108c55760405162461bcd60e51b815260040161089590614713565b600a54600090613867908363ffffffff612a6516565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c78160405161389f9190614847565b60405180910390a15050565b6000826001600160801b0316826001600160801b031611156138df5760405162461bcd60e51b8152600401610895906146cb565b50900390565b6001600160a01b0381166000908152600d602052604090206001015460ff168061391657506001600160a01b038116155b610b335760405162461bcd60e51b8152600401610895906141ec565b60008111610b335760405162461bcd60e51b8152600401610895906144d7565b6001600160a01b038281166000818152600b602052604080822060010180546001600160a01b0319169486169485179055517f094c08e96a8890877a8390b4f967180a7507ad8622244d05fcd0f9f8e086564e9190a35050565b600654604051632ee65eeb60e21b81526001600160a01b039091169063bb997bac906139e090859030908690600401613f7a565b600060405180830381600087803b1580156139fa57600080fd5b505af1158015613a0e573d6000803e3d6000fd5b5050600a5460009250613a2891508363ffffffff6108a016565b905080600a819055507ff3c69a10dcea5d744225cbe910fb39d6f8208bb8e21fff523d6756a7966093c781604051610ac19190614847565b610b3381336135e0565b60008184841115613a8e5760405162461bcd60e51b81526004016108959190614060565b505050900390565b60008183613ab75760405162461bcd60e51b81526004016108959190614060565b506000838581613ac357fe5b0495945050505050565b613ad5613ba5565b613add613ba5565b5050604080518082019091526001600160a01b03929092168252602082015290565b600080613b23601454611e8b670de0b6b3a764000087612b3390919063ffffffff16565b90506000613b37828563ffffffff612b6d16565b9050613b59613b4c828663ffffffff612b3316565b839063ffffffff612a6516565b601455949350505050565b6040518060a0016040528060008152602001600081526020016000815260200160006001600160801b0316815260200160006001600160801b031681525090565b604080518082019091526000808252602082015290565b60008083601f840112613bcd578182fd5b50813567ffffffffffffffff811115613be4578182fd5b602083019150836020828501011115613bfc57600080fd5b9250929050565b80356001600160801b03811681146108c857600080fd5b600060208284031215613c2b578081fd5b81356108c5816148ec565b600060208284031215613c47578081fd5b81516108c5816148ec565b60008060408385031215613c64578081fd5b8235613c6f816148ec565b91506020830135613c7f816148ec565b809150509250929050565b600080600080600080600080610100898b031215613ca6578384fd5b8835613cb1816148ec565b97506020890135613cc1816148ec565b96506040890135613cd1816148ec565b95506060890135613ce1816148ec565b94506080890135613cf1816148ec565b935060a0890135613d01816148ec565b925060c0890135613d11816148ec565b915060e0890135613d21816148ec565b809150509295985092959890939650565b600060208284031215613d43578081fd5b815180151581146108c5578182fd5b60008060408385031215613d64578182fd5b613d6e8484613c03565b9150613d7d8460208501613c03565b90509250929050565b600060208284031215613d97578081fd5b5035919050565b600060208284031215613daf578081fd5b5051919050565b60008060408385031215613dc8578182fd5b823591506020830135613c7f816148ec565b60008082840360a0811215613ded578283fd5b833592506080601f1982011215613e02578182fd5b506020830190509250929050565b60008060008084860360c0811215613e26578485fd5b85359450601f1981016080811215613e3c578485fd5b613e4660606148c5565b91506040811215613e55578485fd5b50613e6060406148c5565b6020870135613e6e816148ec565b80825250604087013560208201528082525060608601356020820152608086013560408201528093505060a085013567ffffffffffffffff811115613eb1578283fd5b613ebd87828801613bbc565b95989497509550505050565b60008060408385031215613edb578182fd5b50508035926020909101359150565b600060208284031215613efb578081fd5b813560ff811681146108c5578182fd5b80516001600160a01b03168252602090810151910152565b90565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0393841681529183166020830152909116604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b6000602080835283518082850152825b8181101561408c57858101830151858201604001528201614070565b8181111561409d5783604083870101525b50601f01601f1916929092016040019392505050565b60208082526046908201527f53746162696c697479506f6f6c3a2063616c6c6572206d75737420686176652060408201527f616e206163746976652074726f766520746f207769746864726177204554484760608201526561696e20746f60d01b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252602d908201527f53503a3a5f73656e644554484761696e546f3a205f726563656976657220697360408201526c207a65726f206164647265737360981b606082015260800190565b60208082526046908201527f53746162696c697479506f6f6c3a20546167206d75737420626520612072656760408201527f697374657265642066726f6e7420656e642c206f7220746865207a65726f206160608201526564647265737360d01b608082015260a00190565b60208082526027908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f74204163746040820152661a5d99541bdbdb60ca1b606082015260800190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b60208082526031908201527f53746162696c697479506f6f6c3a2063616c6c6572206d7573742068617665206040820152703737b716bd32b9379022aa241023b0b4b760791b606082015260800190565b60208082526029908201527f53746162696c697479506f6f6c3a2043616c6c6572206973206e6f742054726f6040820152683b32a6b0b730b3b2b960b91b606082015260800190565b60208082526021908201527f53746162696c697479506f6f6c3a2073656e64696e6720455448206661696c656040820152601960fa1b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526030908201527f53503a3a5f776974686472617746726f6d5370546f3a205f726563656976657260408201526f206973207a65726f206164647265737360801b606082015260800190565b60208082526033908201527f53746162696c697479506f6f6c3a204b69636b6261636b2072617465206d75736040820152727420626520696e2072616e6765205b302c315d60681b606082015260800190565b60208082526026908201527f53746162696c697479506f6f6c3a20416d6f756e74206d757374206265206e6f6040820152656e2d7a65726f60d01b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526039908201527f53746162696c697479506f6f6c3a206d757374206e6f7420616c72656164792060408201527818994818481c9959da5cdd195c995908199c9bdb9d08195b99603a1b606082015260800190565b60208082526028908201527f53746162696c697479506f6f6c3a2055736572206d7573742068617665206e6f6040820152670819195c1bdcda5d60c21b606082015260800190565b60208082526037908201527f4661696c656420746f20617070726f7665205a55534420616d6f756e7420666f60408201527672204d796e74206d417373657420746f2072656465656d60481b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526030908201527f53746162696c697479506f6f6c3a2055736572206d757374206861766520612060408201526f1b9bdb8b5e995c9bc819195c1bdcda5d60821b606082015260800190565b60208082526028908201527f4c697175697479536166654d6174683132383a207375627472616374696f6e206040820152676f766572666c6f7760c01b606082015260800190565b60208082526025908201527f4c697175697479536166654d6174683132383a206164646974696f6e206f766560408201526472666c6f7760d81b606082015260800190565b60208082526044908201527f53746162696c697479506f6f6c3a2043616e6e6f74207769746864726177207760408201527f68696c65207468657265206172652074726f766573207769746820494352203c6060820152631026a1a960e11b608082015260a00190565b60006101006147d2838951613f0b565b60208801516040840152604088015160608401526147f36080840188613f0b565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b6001600160801b0391909116815260200190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9182521515602082015260400190565b9283526001600160801b03918216602084015216604082015260600190565b948552602085019390935260408401919091526001600160801b03908116606084015216608082015260a00190565b60405181810167ffffffffffffffff811182821017156148e457600080fd5b604052919050565b6001600160a01b0381168114610b3357600080fdfeceb6d671277d4354fd29977ada70695fbd93a16612abf765d6b0e25c28dc6db3bce78369dccab09eec1986f4d409ab09ffbb47d65423e5148fcf98411c5111c951457222ebca92c335c9c86e2baa1cc0e40ffaa9084a51452980d5ba8dec2f6399920012339b5a3368d3a04b8606ce412c46ed92b7dcd8602d41fc8862cb8f25a2646970667358221220b12079f570461c3902a02d925635ecefb92e70f4556abddd99509e1ecfffdece64736f6c634300060b0033", + "devdoc": { + "kind": "dev", + "methods": { + "getETH()": { + "returns": { + "_0": "the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`, to exclude edge cases like ETH received from a self-destruct." + } + }, + "getOwner()": { + "returns": { + "_owner": "Address of the owner. " + } + }, + "getTotalZUSDDeposits()": { + "returns": { + "_0": "ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset." + } + }, + "setAddresses(address,address,address,address,address,address,address,address)": { + "details": "initializer function, checks addresses are contracts", + "params": { + "_activePoolAddress": "ActivePool contract address", + "_borrowerOperationsAddress": "BorrowerOperations contract address", + "_communityIssuanceAddress": "CommunityIssuanceAddress", + "_liquityBaseParamsAddress": "LiquidityBaseParams contract address", + "_priceFeedAddress": "PriceFeed contract address", + "_sortedTrovesAddress": "SortedTroves contract address", + "_troveManagerAddress": "TroveManager contract address", + "_zusdTokenAddress": "ZUSDToken contract address" + } + }, + "setCommunityIssuanceAddress(address)": { + "details": "setter function specific for community issuance contract.", + "params": { + "_communityIssuanceAddress": "address of new community issuance contract." + } + }, + "setOwner(address)": { + "params": { + "_owner": "Address of the owner. " + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "MIN_NET_DEBT()": { + "notice": "Minimum amount of net ZUSD debt a trove must have" + }, + "ZUSD_GAS_COMPENSATION()": { + "notice": "Amount of ZUSD to be locked in gas pool on opening troves" + }, + "constructor": "Constructor ", + "getCompoundedFrontEndStake(address)": { + "notice": "Return the front end's compounded stake. Given by the formula: D = D0 * P/P(0) where P(0) is the depositor's snapshot of the product P, taken at the last time when one of the front end's tagged deposits updated their deposit. The front end's compounded stake is equal to the sum of its depositors' compounded deposits." + }, + "getCompoundedZUSDDeposit(address)": { + "notice": "Return the user's compounded deposit. Given by the formula: d = d0 * P/P(0) where P(0) is the depositor's snapshot of the product P, taken when they last updated their deposit." + }, + "getDepositorETHGain(address)": { + "notice": "Calculates the ETH gain earned by the deposit since its last snapshots were taken. Given by the formula: E = d0 * (S - S(0))/P(0) where S(0) and P(0) are the depositor's snapshots of the sum S and product P, respectively. d0 is the last recorded deposit value." + }, + "getDepositorSOVGain(address)": { + "notice": "Calculate the SOV gain earned by a deposit since its last snapshots were taken. Given by the formula: SOV = d0 * (G - G(0))/P(0) where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively. d0 is the last recorded deposit value." + }, + "getFrontEndSOVGain(address)": { + "notice": "Return the SOV gain earned by the front end. Given by the formula: E = D0 * (G - G(0))/P(0) where G(0) and P(0) are the depositor's snapshots of the sum G and product P, respectively. D0 is the last recorded value of the front end's total tagged deposits." + }, + "getOwner()": { + "notice": "Return address of the owner." + }, + "offset(uint256,uint256)": { + "notice": "Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible) and transfers the Trove's ETH collateral from ActivePool to StabilityPool. Only called by liquidation functions in the TroveManager." + }, + "provideToSP(uint256,address)": { + "notice": "provideToSP(): - Triggers a SOV issuance, based on time passed since the last issuance and total amount of deposited ZUSD. The SOV issuance is shared between *all* depositors and front ends - Tags the deposit with the provided front end tag param, if it's a new deposit - Sends depositor's accumulated gains (SOV, ETH) to depositor - Sends the tagged front end's accumulated SOV gains to the tagged front end - Increases deposit and tagged front end's stake, and takes new snapshots for each." + }, + "provideToSpFromDLLR(uint256,(uint256,uint8,bytes32,bytes32))": { + "notice": "DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction" + }, + "provideToSpFromDllrWithPermit2(uint256,((address,uint256),uint256,uint256),bytes)": { + "notice": "DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction" + }, + "registerFrontEnd(uint256)": { + "notice": "Front end makes a one-time selection of kickback rate upon registering" + }, + "setAddresses(address,address,address,address,address,address,address,address)": { + "notice": "Called only once on init, to set addresses of other Liquity contracts. Callable only by owner" + }, + "setOwner(address)": { + "notice": "Set address of the owner (only owner can call this function)" + }, + "withdrawETHGainToTrove(address,address)": { + "notice": "withdrawETHGainToTrove: - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends - Sends all depositor's SOV gain to depositor - Sends all tagged front end's SOV gain to the tagged front end - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove - Leaves their compounded deposit in the Stability Pool - Updates snapshots for deposit and tagged front end stake " + }, + "withdrawFromSP(uint256)": { + "notice": "withdrawFromSP(): - Triggers a SOV issuance, based on time passed since the last issuance and total amount of ZUSD is deposited. The SOV issuance is shared between *all* depositors and front ends - Removes the deposit's front end tag if it is a full withdrawal - Sends all depositor's accumulated gains (SOV, ETH) to depositor - Sends the tagged front end's accumulated SOV gains to the tagged front end - Decreases deposit and tagged front end's stake, and takes new snapshots for each. If _amount > userDeposit, the user withdraws all of their compounded deposit." + }, + "withdrawFromSpAndConvertToDLLR(uint256)": { + "notice": "Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction" + } + }, + "notice": "The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors. When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned. Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits. They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors, in the same proportion. When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40% of the total ZUSD in the Stability Pool, depletes 40% of each deposit. A deposit that has experienced a series of liquidations is termed a \"compounded deposit\": each liquidation depletes the deposit, multiplying it by some factor in range ]0,1[ --- IMPLEMENTATION --- We use a highly scalable method of tracking deposits and ETH gains that has O(1) complexity. When a liquidation occurs, rather than updating each depositor's deposit and ETH gain, we simply update two state variables: a product P, and a sum S. A mathematical manipulation allows us to factor out the initial deposit, and accurately track all depositors' compounded deposits and accumulated ETH gains over time, as liquidations occur, using just these two variables P and S. When depositors join the Stability Pool, they get a snapshot of the latest P and S: P_t and S_t, respectively. The formula for a depositor's accumulated ETH gain is derived here: https://github.com/liquity/dev/blob/main/packages/contracts/mathProofs/Scalable%20Compounding%20Stability%20Pool%20Deposits.pdf For a given deposit d_t, the ratio P/P_t tells us the factor by which a deposit has decreased since it joined the Stability Pool, and the term d_t * (S - S_t)/P_t gives us the deposit's total accumulated ETH gain. Each liquidation updates the product P and sum S. After a series of liquidations, a compounded deposit and corresponding ETH gain can be calculated using the initial deposit, the depositor’s snapshots of P and S, and the latest values of P and S. Any time a depositor updates their deposit (withdrawal, top-up) their accumulated ETH gain is paid out, their new deposit is recorded (based on their latest compounded deposit and modified by the withdrawal/top-up), and they receive new snapshots of the latest P and S. Essentially, they make a fresh deposit that overwrites the old one. --- SCALE FACTOR --- Since P is a running product in range ]0,1] that is always-decreasing, it should never reach 0 when multiplied by a number in range ]0,1[. Unfortunately, Solidity floor division always reaches 0, sooner or later. A series of liquidations that nearly empty the Pool (and thus each multiply P by a very small number in range ]0,1[ ) may push P to its 18 digit decimal limit, and round it to 0, when in fact the Pool hasn't been emptied: this would break deposit tracking. So, to track P accurately, we use a scale factor: if a liquidation would cause P to decrease to <1e-9 (and be rounded to 0 by Solidity), we first multiply P by 1e9, and increment a currentScale factor by 1. The added benefit of using 1e9 for the scale factor (rather than 1e18) is that it ensures negligible precision loss close to the scale boundary: when P is at its minimum value of 1e9, the relative precision loss in P due to floor division is only on the order of 1e-9. --- EPOCHS --- Whenever a liquidation fully empties the Stability Pool, all deposits should become 0. However, setting P to 0 would make P be 0 forever, and break all future reward calculations. So, every time the Stability Pool is emptied by a liquidation, we reset P = 1 and currentScale = 0, and increment the currentEpoch by 1. --- TRACKING DEPOSIT OVER SCALE CHANGES AND EPOCHS --- When a deposit is made, it gets snapshots of the currentEpoch and the currentScale. When calculating a compounded deposit, we compare the current epoch to the deposit's epoch snapshot. If the current epoch is newer, then the deposit was present during a pool-emptying liquidation, and necessarily has been depleted to 0. Otherwise, we then compare the current scale to the deposit's scale snapshot. If they're equal, the compounded deposit is given by d_t * P/P_t. If it spans one scale change, it is given by d_t * P/(P_t * 1e9). If it spans more than one scale change, we define the compounded deposit as 0, since it is now less than 1e-9'th of its initial value (e.g. a deposit of 1 billion ZUSD has depleted to < 1 ZUSD). --- TRACKING DEPOSITOR'S ETH GAIN OVER SCALE CHANGES AND EPOCHS --- In the current epoch, the latest value of S is stored upon each scale change, and the mapping (scale -> S) is stored for each epoch. This allows us to calculate a deposit's accumulated ETH gain, during the epoch in which the deposit was non-zero and earned ETH. We calculate the depositor's accumulated ETH gain for the scale at which they made the deposit, using the ETH gain formula: e_1 = d_t * (S - S_t) / P_t and also for scale after, taking care to divide the latter by a factor of 1e9: e_2 = d_t * S / (P_t * 1e9) The gain in the second scale will be full, as the starting point was in the previous scale, thus no need to subtract anything. The deposit therefore was present for reward events from the beginning of that second scale. S_i-S_t + S_{i+1} .<--------.------------> . . . S_i . S_{i+1} <--.-------->.<-----------> S_t. . <->. . t . |---+---------|-------------|-----... i i+1 The sum of (e_1 + e_2) captures the depositor's total accumulated ETH gain, handling the case where their deposit spanned one scale change. We only care about gains across one scale change, since the compounded deposit is defined as being 0 once it has spanned more than one scale change. --- UPDATING P WHEN A LIQUIDATION OCCURS --- Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations: https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS --- An SOV issuance event occurs at every deposit operation, and every liquidation. Each deposit is tagged with the address of the front end through which it was made. All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate. Please see the system Readme for an overview: https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers We use the same mathematical product-sum approach to track SOV gains for depositors, where 'G' is the sum corresponding to SOV gains. The product P (and snapshot P_t) is re-used, as the ratio P/P_t tracks a deposit's depletion due to liquidations.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 5495, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "activePool", + "offset": 0, + "slot": "0", + "type": "t_contract(IActivePool)19557" + }, + { + "astId": 5497, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "defaultPool", + "offset": 0, + "slot": "1", + "type": "t_contract(IDefaultPool)20229" + }, + { + "astId": 5500, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "priceFeed", + "offset": 0, + "slot": "2", + "type": "t_contract(IPriceFeed)20458" + }, + { + "astId": 5503, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "liquityBaseParams", + "offset": 0, + "slot": "3", + "type": "t_contract(ILiquityBaseParams)20379" + }, + { + "astId": 28084, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "borrowerOperations", + "offset": 0, + "slot": "4", + "type": "t_contract(IBorrowerOperations)20065" + }, + { + "astId": 28086, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "troveManager", + "offset": 0, + "slot": "5", + "type": "t_contract(ITroveManager)21635" + }, + { + "astId": 28088, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "zusdToken", + "offset": 0, + "slot": "6", + "type": "t_contract(IZUSDToken)21842" + }, + { + "astId": 28090, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "sortedTroves", + "offset": 0, + "slot": "7", + "type": "t_contract(ISortedTroves)20817" + }, + { + "astId": 28092, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "communityIssuance", + "offset": 0, + "slot": "8", + "type": "t_contract(ICommunityIssuance)20205" + }, + { + "astId": 28094, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "ETH", + "offset": 0, + "slot": "9", + "type": "t_uint256" + }, + { + "astId": 28096, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "totalZUSDDeposits", + "offset": 0, + "slot": "10", + "type": "t_uint256" + }, + { + "astId": 28121, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "deposits", + "offset": 0, + "slot": "11", + "type": "t_mapping(t_address,t_struct(Deposit)28106_storage)" + }, + { + "astId": 28125, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "depositSnapshots", + "offset": 0, + "slot": "12", + "type": "t_mapping(t_address,t_struct(Snapshots)28117_storage)" + }, + { + "astId": 28129, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "frontEnds", + "offset": 0, + "slot": "13", + "type": "t_mapping(t_address,t_struct(FrontEnd)28101_storage)" + }, + { + "astId": 28133, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "frontEndStakes", + "offset": 0, + "slot": "14", + "type": "t_mapping(t_address,t_uint256)" + }, + { + "astId": 28137, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "frontEndSnapshots", + "offset": 0, + "slot": "15", + "type": "t_mapping(t_address,t_struct(Snapshots)28117_storage)" + }, + { + "astId": 28139, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "P", + "offset": 0, + "slot": "16", + "type": "t_uint256" + }, + { + "astId": 28144, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "currentScale", + "offset": 0, + "slot": "17", + "type": "t_uint128" + }, + { + "astId": 28146, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "currentEpoch", + "offset": 16, + "slot": "17", + "type": "t_uint128" + }, + { + "astId": 28152, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "epochToScaleToSum", + "offset": 0, + "slot": "18", + "type": "t_mapping(t_uint128,t_mapping(t_uint128,t_uint256))" + }, + { + "astId": 28158, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "epochToScaleToG", + "offset": 0, + "slot": "19", + "type": "t_mapping(t_uint128,t_mapping(t_uint128,t_uint256))" + }, + { + "astId": 28160, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "lastSOVError", + "offset": 0, + "slot": "20", + "type": "t_uint256" + }, + { + "astId": 28162, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "lastETHError_Offset", + "offset": 0, + "slot": "21", + "type": "t_uint256" + }, + { + "astId": 28164, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "lastZUSDLossError_Offset", + "offset": 0, + "slot": "22", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(IActivePool)19557": { + "encoding": "inplace", + "label": "contract IActivePool", + "numberOfBytes": "20" + }, + "t_contract(IBorrowerOperations)20065": { + "encoding": "inplace", + "label": "contract IBorrowerOperations", + "numberOfBytes": "20" + }, + "t_contract(ICommunityIssuance)20205": { + "encoding": "inplace", + "label": "contract ICommunityIssuance", + "numberOfBytes": "20" + }, + "t_contract(IDefaultPool)20229": { + "encoding": "inplace", + "label": "contract IDefaultPool", + "numberOfBytes": "20" + }, + "t_contract(ILiquityBaseParams)20379": { + "encoding": "inplace", + "label": "contract ILiquityBaseParams", + "numberOfBytes": "20" + }, + "t_contract(IPriceFeed)20458": { + "encoding": "inplace", + "label": "contract IPriceFeed", + "numberOfBytes": "20" + }, + "t_contract(ISortedTroves)20817": { + "encoding": "inplace", + "label": "contract ISortedTroves", + "numberOfBytes": "20" + }, + "t_contract(ITroveManager)21635": { + "encoding": "inplace", + "label": "contract ITroveManager", + "numberOfBytes": "20" + }, + "t_contract(IZUSDToken)21842": { + "encoding": "inplace", + "label": "contract IZUSDToken", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_struct(Deposit)28106_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct StabilityPoolStorage.Deposit)", + "numberOfBytes": "32", + "value": "t_struct(Deposit)28106_storage" + }, + "t_mapping(t_address,t_struct(FrontEnd)28101_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct StabilityPoolStorage.FrontEnd)", + "numberOfBytes": "32", + "value": "t_struct(FrontEnd)28101_storage" + }, + "t_mapping(t_address,t_struct(Snapshots)28117_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct StabilityPoolStorage.Snapshots)", + "numberOfBytes": "32", + "value": "t_struct(Snapshots)28117_storage" + }, + "t_mapping(t_address,t_uint256)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_mapping(t_uint128,t_mapping(t_uint128,t_uint256))": { + "encoding": "mapping", + "key": "t_uint128", + "label": "mapping(uint128 => mapping(uint128 => uint256))", + "numberOfBytes": "32", + "value": "t_mapping(t_uint128,t_uint256)" + }, + "t_mapping(t_uint128,t_uint256)": { + "encoding": "mapping", + "key": "t_uint128", + "label": "mapping(uint128 => uint256)", + "numberOfBytes": "32", + "value": "t_uint256" + }, + "t_struct(Deposit)28106_storage": { + "encoding": "inplace", + "label": "struct StabilityPoolStorage.Deposit", + "members": [ + { + "astId": 28103, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "initialValue", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 28105, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "frontEndTag", + "offset": 0, + "slot": "1", + "type": "t_address" + } + ], + "numberOfBytes": "64" + }, + "t_struct(FrontEnd)28101_storage": { + "encoding": "inplace", + "label": "struct StabilityPoolStorage.FrontEnd", + "members": [ + { + "astId": 28098, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "kickbackRate", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 28100, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "registered", + "offset": 0, + "slot": "1", + "type": "t_bool" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Snapshots)28117_storage": { + "encoding": "inplace", + "label": "struct StabilityPoolStorage.Snapshots", + "members": [ + { + "astId": 28108, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "S", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 28110, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "P", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 28112, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "G", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 28114, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "scale", + "offset": 0, + "slot": "3", + "type": "t_uint128" + }, + { + "astId": 28116, + "contract": "contracts/StabilityPool.sol:StabilityPool", + "label": "epoch", + "offset": 16, + "slot": "3", + "type": "t_uint128" + } + ], + "numberOfBytes": "128" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/external/deployments/rskTestnet/StabilityPool_Proxy.json b/external/deployments/rskTestnet/StabilityPool_Proxy.json new file mode 100644 index 000000000..7febe8d89 --- /dev/null +++ b/external/deployments/rskTestnet/StabilityPool_Proxy.json @@ -0,0 +1,110 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "UpgradableProxy", + "sourceName": "contracts/Proxy/UpgradableProxy.sol", + "address": "0x176D218CaB70002CEF08e15271476187c37ed25f", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_oldImplementation", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_newImplementation", + "type": "address" + } + ], + "name": "ImplementationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610023336001600160e01b0361002816565b610110565b6001600160a01b03811661006d5760405162461bcd60e51b81526004018080602001828103825260228152602001806105e26022913960400191505060405180910390fd5b6001600160a01b0381166100886001600160e01b036100e616565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b6104c38061011f6000396000f3fe6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b00334f776e61626c653a3a7365744f776e65723a20696e76616c69642061646472657373", + "deployedBytecode": "0x6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/external/deployments/rskTestnet/TroveManager.json b/external/deployments/rskTestnet/TroveManager.json new file mode 100644 index 000000000..e6ed7e3ac --- /dev/null +++ b/external/deployments/rskTestnet/TroveManager.json @@ -0,0 +1,2091 @@ +{ + "address": "0xd8aB7EC3bd20A0Ce3084e124bFBC9Aa96a6D7FdD", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_bootstrapPeriod", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_baseRate", + "type": "uint256" + } + ], + "name": "BaseRateUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newBorrowerOperationsAddress", + "type": "address" + } + ], + "name": "BorrowerOperationsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + } + ], + "name": "CollSurplusPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + } + ], + "name": "FeeDistributorAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + } + ], + "name": "GasPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "LTermsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_lastFeeOpTime", + "type": "uint256" + } + ], + "name": "LastFeeOpTimeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedDebt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedColl", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_collGasCompensation", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDGasCompensation", + "type": "uint256" + } + ], + "name": "Liquidation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + } + ], + "name": "LiquityBaseParamsAddressChanges", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_attemptedZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_actualZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHSent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHFee", + "type": "uint256" + } + ], + "name": "Redemption", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + } + ], + "name": "StabilityPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_totalStakesSnapshot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalCollateralSnapshot", + "type": "uint256" + } + ], + "name": "SystemSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newTotalStakes", + "type": "uint256" + } + ], + "name": "TotalStakesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newIndex", + "type": "uint256" + } + ], + "name": "TroveIndexUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveLiquidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + } + ], + "name": "TroveManagerRedeemOpsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "TroveSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "ZEROStakingAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroTokenAddress", + "type": "address" + } + ], + "name": "ZEROTokenAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newZUSDTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "BETA", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BOOTSTRAP_PERIOD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "CCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ETH", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ZUSDDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINUTE_DECAY_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SECONDS_IN_ONE_MINUTE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "TroveOwners", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "Troves", + "outputs": [ + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coll", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "internalType": "enum TroveManagerStorage.Status", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "arrayIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "_getCurrentICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingETHReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingZUSDDebtReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_getRedemptionRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_hasPendingRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_stabilityPool", + "outputs": [ + { + "internalType": "contract IStabilityPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroStaking", + "outputs": [ + { + "internalType": "contract IZEROStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroToken", + "outputs": [ + { + "internalType": "contract IZEROToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "addTroveOwnerToArray", + "outputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "applyPendingRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_troveArray", + "type": "address[]" + } + ], + "name": "batchLiquidateTroves", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "borrowerOperationsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "checkRecoveryMode", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "closeTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decayBaseRateFromBorrowing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_collDecrease", + "type": "uint256" + } + ], + "name": "decreaseTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_debtDecrease", + "type": "uint256" + } + ], + "name": "decreaseTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeDistributor", + "outputs": [ + { + "internalType": "contract IFeeDistributor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDDebt", + "type": "uint256" + } + ], + "name": "getBorrowingFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDDebt", + "type": "uint256" + } + ], + "name": "getBorrowingFeeWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBorrowingRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBorrowingRateWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "getCurrentICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getEntireDebtAndColl", + "outputs": [ + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coll", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pendingZUSDDebtReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pendingETHReward", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getNominalICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getPendingETHReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getPendingZUSDDebtReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ETHDrawn", + "type": "uint256" + } + ], + "name": "getRedemptionFeeWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRedemptionRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRedemptionRateWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "getTCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_index", + "type": "uint256" + } + ], + "name": "getTroveFromTroveOwnersArray", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTroveOwnersCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveStatus", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "hasPendingRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_collIncrease", + "type": "uint256" + } + ], + "name": "increaseTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_debtIncrease", + "type": "uint256" + } + ], + "name": "increaseTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lastETHError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFeeOperationTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastZUSDDebtError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "liquidate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_n", + "type": "uint256" + } + ], + "name": "liquidateTroves", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDamount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + } + ], + "name": "redeemCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "redeemCollateralViaDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "redeemCollateralViaDllrWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "removeStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "rewardSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "ETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ZUSDDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + }, + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "internalType": "struct ITroveManager.TroveManagerInitAddressesParams", + "name": "_troveManagerInitAddressesParams", + "type": "tuple" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + } + ], + "name": "setTroveManagerRedeemOps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_num", + "type": "uint256" + } + ], + "name": "setTroveStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalCollateralSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakesSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManagerRedeemOps", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "updateStakeAndTotalStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "updateTroveRewardSnapshots", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0xdC03c72c1730b149E3178624FD4d9Bf51501A6E0", + "transactionIndex": 0, + "gasUsed": "6045491", + "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000080000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000400000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x63ae44ab567d090410beb39dd6c2dad30f27c33679e013ac466adf6afc60e169", + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748962, + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "address": "0xdC03c72c1730b149E3178624FD4d9Bf51501A6E0", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x63ae44ab567d090410beb39dd6c2dad30f27c33679e013ac466adf6afc60e169" + } + ], + "blockNumber": 4748962, + "cumulativeGasUsed": "6045491", + "status": 1, + "byzantium": true + }, + "numDeployments": 5, + "bytecode": "0x60c06040523480156200001157600080fd5b50604051620058f2380380620058f2833981016040819052620000349162000128565b8162000049336001600160e01b036200006316565b60805260601b6001600160601b03191660a05250620001c4565b6001600160a01b038116620000955760405162461bcd60e51b81526004016200008c9062000182565b60405180910390fd5b6001600160a01b038116620000b26001600160e01b036200010716565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f79062000165565b6040519081900390209190915550565b600080604051620001189062000165565b6040519081900390205492915050565b600080604083850312156200013b578182fd5b825160208401519092506001600160a01b03811681146200015a578182fd5b809150509250929050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160a05160601c615707620001eb60003980610ff152508061223252506157076000f3fe608060405234801561001057600080fd5b50600436106104c25760003560e01c8063756b253e11610278578063b0d8e1811161015c578063d293c710116100ce578063d815e8e911610092578063d815e8e91461095a578063d9a7244414610962578063e056e91814610975578063e2ac77b014610988578063f36b24251461099b578063fe2ba848146109a3576104c2565b8063d293c71014610906578063d380a37c14610919578063d3d6f84314610921578063d5b3563514610934578063d66a255314610947576104c2565b8063be4b033411610120578063be4b0334146108cb578063bf9befb1146108d3578063c35bc550146108db578063c52861f2146108e3578063c7b55481146108eb578063cbd138ae146108f3576104c2565b8063b0d8e18114610867578063b7f8cf9b1461087a578063b82f263d14610882578063b91af97c14610895578063bcd37526146108b8576104c2565b8063887105d3116101f55780639dd233d2116101b95780639dd233d2146108325780639f0706701461083a578063a20baee614610773578063a3f4df7e14610842578063ae7bec1914610857578063ae9187541461085f576104c2565b8063887105d3146107f4578063893d20e8146107fc57806396d711ff146108045780639708daf41461080c5780639976cf451461081f576104c2565b80637cf54e401161023c5780637cf54e40146107b65780637f7dde4a146107be578063807d138d146107c657806382fe3eb9146107ce57806387436936146107e1576104c2565b8063756b253e14610783578063759b303414610796578063794e57241461079e578063795d26c3146107a6578063797250e3146107ae576104c2565b80633cc74225116103aa57806361ec893d1161031c5780636b444952116102e05780636b4449521461072c5780636ef6433814610734578063716c47e61461075857806372423c171461076057806372fe25aa14610773578063741bef1a1461077b576104c2565b806361ec893d146106e3578063631203b0146106eb57806364cee260146106fe578063653d46e71461071157806366ca4a2114610724576104c2565b80634a767d681161036e5780634a767d681461067a5780634e443d9e1461068d5780635733d58f146106ad5780635d6b480f146106b55780635d8c9609146106c85780635dba4c4a146106db576104c2565b80633cc742251461063157806342ccf1e414610639578063477d66cf1461064c578063480cd5781461065f57806349eefeee14610672576104c2565b806317c62b17116104435780631f68f20a116104075780631f68f20a146105eb57806321e37801146105f35780632b11551a146106065780632f8655681461060e57806331c903b0146106215780633a12859514610629576104c2565b806317c62b171461059757806318f2817a146105aa5780631a59a50e146105bd5780631bf43555146105d05780631e8b1c2b146105d8576104c2565b806312261ee71161048a57806312261ee71461053557806312610e921461053d57806313af40351461055057806315d549f1146105635780631673c79a14610576576104c2565b806301f16e18146104c757806305b6f5ca146104dc578063071a7541146104ef5780630b0765571461050d5780630d43e8ad14610520575b600080fd5b6104da6104d5366004614d96565b6109b6565b005b6104da6104ea366004614f61565b610f1c565b6104f7610fb3565b6040516105049190615568565b60405180910390f35b6104da61051b366004614c9f565b610fb8565b610528610fe0565b604051610504919061512e565b610528610fef565b6104f761054b366004614cd7565b611013565b6104da61055e366004614c9f565b61106b565b6104f7610571366004614c9f565b6110ac565b610589610584366004614c9f565b6110d0565b604051610504929190615571565b6104f76105a5366004614c9f565b6110e9565b6104f76105b8366004614c9f565b6110f4565b6104f76105cb366004614c9f565b611107565b6104f76111cd565b6104da6105e6366004614d02565b6111da565b6104f761153b565b6104f7610601366004614c9f565b611541565b6104f761156b565b6104da61061c366004614c9f565b61157a565b6104f76115e0565b6105286115ed565b6105286115fc565b6104f7610647366004614c9f565b61160b565b6104f761065a366004614ec4565b61163c565b6104f761066d366004614c9f565b61164f565b6104f761166d565b6104f7610688366004614cd7565b611673565b6106a061069b366004614ec4565b611692565b60405161050491906151a1565b6104f761169d565b6104da6106c3366004614cd7565b61171a565b6104f76106d6366004614c9f565b611766565b6104da611771565b6104f76117dc565b6104f76106f9366004614ec4565b6117e1565b6104f761070c366004614c9f565b6117ee565b6104da61071f366004614ec4565b61180c565b6104f7611b96565b6104f7611ba8565b610747610742366004614c9f565b611bae565b6040516105049594939291906155a3565b610528611be8565b6104f761076e366004614cd7565b611bf7565b6104f7611c54565b610528611c60565b610528610791366004614ec4565b611c6f565b6104f7611c96565b6104f7611ca3565b6104f7611ce8565b6104f7611e07565b610528611e0d565b610528611e1c565b6104f7611e2b565b6104da6107dc366004614c9f565b611e31565b6104da6107ef366004614c9f565b611e42565b6104f7611ece565b610528611f9d565b6104f7611fbc565b6104da61081a366004614feb565b611fc2565b6104f761082d366004614cd7565b61205b565b6104f761208e565b610528612094565b61084a6120a3565b60405161050491906151da565b6105286120cb565b6105286120da565b6104f7610875366004614c9f565b6120e9565b610528612110565b6104f7610890366004614ec4565b61211f565b6108a86108a3366004614c9f565b61212a565b604051610504949392919061560f565b6104da6108c6366004614ef4565b61218e565b6104f7612224565b6104f761222a565b6104f7612230565b6104f7612254565b6104f7612266565b6104da610901366004614c9f565b612272565b6104f7610914366004614cd7565b612285565b6104f7612298565b6104f761092f366004614cd7565b61229e565b6104f7610942366004614ec4565b6122d4565b6104f7610955366004614c9f565b6122e7565b610528612302565b610528610970366004614ec4565b612311565b6106a0610983366004614c9f565b61233b565b6106a0610996366004614c9f565b612399565b6104f76123a4565b6104da6109b1366004614c9f565b6123b1565b6109be611f9d565b6001600160a01b0316336001600160a01b0316146109f75760405162461bcd60e51b81526004016109ee906153c5565b60405180910390fd5b8051610a02906123c2565b610a0f81602001516123c2565b610a1c81604001516123c2565b610a2981606001516123c2565b610a3681608001516123c2565b610a438160a001516123c2565b610a508160c001516123c2565b610a5d8160e001516123c2565b610a6b8161010001516123c2565b610a798161012001516123c2565b610a878161014001516123c2565b610a958161016001516123c2565b610aa38161018001516123c2565b610ab1816101a001516123c2565b8051600c80546001600160a01b03199081166001600160a01b038085169190911790925560208401516004805483169184169190911790556040808501516003805484169185169190911790556060850151600580548416918516919091179055608085015160008054841691851691909117905560a085015160018054841691851691909117905560c085015160068054841691851691909117905560e0850151600780548416918516919091179055610100850151600880548416918516919091179055610120850151600280548416918516919091179055610140850151600980548416918516919091179055610160850151600d80548416918516919091179055610180850151600a805484169185169190911790556101a0850151600b80549093169316929092179055517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db991610c0c9161512e565b60405180910390a17f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b18160200151604051610c47919061512e565b60405180910390a17fbf65195e6d5213f6fcbce65b1454c925197a45e616dabd2e243542b039b050928160600151604051610c82919061512e565b60405180910390a17f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed9858160600151604051610cbd919061512e565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828160800151604051610cf8919061512e565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b8160a00151604051610d33919061512e565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f8160c00151604051610d6e919061512e565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa08160e00151604051610da9919061512e565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d816101000151604051610de5919061512e565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264816101200151604051610e21919061512e565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d816101400151604051610e5d919061512e565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800816101600151604051610e99919061512e565b60405180910390a17f61e0c29d5028a9e4facaa476a46e78912e99f1ba945c9560b86b82ebe36ee52d816101800151604051610ed5919061512e565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd816101a00151604051610f11919061512e565b60405180910390a150565b6004546040516000916060916001600160a01b0390911690610f419084903690615101565b600060405180830381855af49150503d8060008114610f7c576040519150601f19603f3d011682016040523d82523d6000602084013e610f81565b606091505b5091509150818190610fa65760405162461bcd60e51b81526004016109ee91906151da565b5050505050505050505050565b600281565b610fc0612407565b600054600154610fdd916001600160a01b03908116911683612433565b50565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061101d612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff61254516565b6001600160a01b03851660009081526010602052604090208190559150505b92915050565b611073611f9d565b6001600160a01b0316336001600160a01b0316146110a35760405162461bcd60e51b81526004016109ee906153c5565b610fdd81612587565b60006110b6612407565b6110bf82612612565b6001600160801b031690505b919050565b6016602052600090815260409020805460019091015482565b60006110658261160b565b60006110fe612407565b611065826126ac565b6001600160a01b0381166000908152601660205260408120546014548290611135908363ffffffff61254516565b905080158061116e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561116b57fe5b14155b1561117e576000925050506110cb565b6001600160a01b038416600090815260106020526040812060020154906111c3670de0b6b3a76400006111b7848663ffffffff61275f16565b9063ffffffff61279916565b9695505050505050565b6809c2007651b250000081565b80516111f85760405162461bcd60e51b81526004016109ee906153f6565b6000546001546006546001600160a01b0392831692918216911661121a614b2b565b611222614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ec57600080fd5b505afa158015611300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113249190614edc565b60208301528151611334906127db565b158015604084015261135c576113558585846000015185602001518a612876565b9050611374565b6113718585846000015185602001518a612b8b565b90505b60008160200151116113985760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad926113cc92600401615571565b600060405180830381600087803b1580156113e657600080fd5b505af11580156113fa573d6000803e3d6000fd5b5050505061141285858360c001518460e00151612ccb565b61010081015115611489576008546101008201516040516364a197f360e01b81526001600160a01b03888116936364a197f393611456939290911691600401615188565b600060405180830381600087803b15801561147057600080fd5b505af1158015611484573d6000803e3d6000fd5b505050505b611497858260400151612f2f565b60208101516060830152610100810151604082015182516114cf92916114c3919063ffffffff61254516565b9063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611517949092909161560f565b60405180910390a1611533853383606001518460400151613090565b505050505050565b600e5481565b6001600160a01b03811660009081526010602052604081206003015460ff16600481111561106557fe5b60006115756115e0565b905090565b6115838161316d565b6040805160018082528183019092526060916020808301908036833701905050905081816000815181106115b357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506115dc816111da565b5050565b6000611575600e546131b6565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290611135908363ffffffff61254516565b6000611065611649611b96565b83613253565b6001600160a01b031660009081526010602052604090206001015490565b60175490565b600080600061168185613271565b9150915060006111c38383876132f7565b6000611065826127db565b60035460408051635733d58f60e01b815290516000926001600160a01b031691635733d58f916004808301926020929190829003018186803b1580156116e257600080fd5b505afa1580156116f6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115759190614edc565b611722612407565b80600481111561172e57fe5b6001600160a01b0383166000908152601060205260409020600301805460ff1916600183600481111561175d57fe5b02179055505050565b600061106582611107565b611779612407565b6000611783613329565b9050670de0b6b3a764000081111561179757fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c906117cc908390615568565b60405180910390a1610fdd61336d565b603c81565b60006110656116496123a4565b6001600160a01b031660009081526010602052604090206002015490565b611814614ba8565b506040805160e081018252600080546001600160a01b0390811683526001548116602084015292820181905260608201819052600d548316608083015260a0820181905260c082015260065490911661186b614b2b565b611873614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fb9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b15801561193d57600080fd5b505afa158015611951573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119759190614edc565b60208301528151611985906127db565b15801560408401526119ac576119a58483600001518460200151886133c2565b90506119cc565b6119c9846000015185602001518460000151856020015189613869565b90505b60008160200151116119f05760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad92611a2492600401615571565b600060405180830381600087803b158015611a3e57600080fd5b505af1158015611a52573d6000803e3d6000fd5b50505050611a72846000015185602001518360c001518460e00151612ccb565b61010081015115611ae95783516008546101008301516040516364a197f360e01b81526001600160a01b03938416936364a197f393611ab693911691600401615188565b600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050505b611afb84600001518260400151612f2f565b6020810151606083015261010081015160408201518251611b2792916114c3919063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611b6f949092909161560f565b60405180910390a1611b8f84600001513383606001518460400151613090565b5050505050565b6000611575611ba3613329565b613a1f565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b6000611c01612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff613b0116565b6001600160a01b038516600090815260106020526040902060010181905591505092915050565b670de0b6b3a764000081565b6002546001600160a01b031681565b60178181548110611c7c57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60035460408051631e5395c960e21b815290516000926001600160a01b03169163794e5724916004808301926020929190829003018186803b1580156116e257600080fd5b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015611d2c57600080fd5b505afa158015611d40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d649190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b505afa158015611dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dee9190614edc565b9050611e00828263ffffffff613b0116565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b611e39612407565b610fdd81613b26565b611e4a611f9d565b6001600160a01b0316336001600160a01b031614611e7a5760405162461bcd60e51b81526004016109ee906153c5565b611e83816123c2565b600480546001600160a01b0319166001600160a01b0383161790556040517f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b190610f1190839061512e565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b158015611f1357600080fd5b505afa158015611f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4b9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b600080604051611fac90615111565b6040519081900390205492915050565b60135481565b6004546040516000916060916001600160a01b0390911690611fe79084903690615101565b600060405180830381855af49150503d8060008114612022576040519150601f19603f3d011682016040523d82523d6000602084013e612027565b606091505b509150915081819061204c5760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050505050565b6000612065612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff613b0116565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b60008060006120f784613271565b9150915060006121078383613b83565b95945050505050565b6005546001600160a01b031681565b600061106582613bb8565b6001600160a01b03811660009081526010602052604081208054600190910154909180612156856110e9565b915061216185611766565b9050612173848363ffffffff613b0116565b9350612185838263ffffffff613b0116565b92509193509193565b6004546040516000916060916001600160a01b03909116906121b39084903690615101565b600060405180830381855af49150503d80600081146121ee576040519150601f19603f3d011682016040523d82523d6000602084013e6121f3565b606091505b50915091508181906122185760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000611575612261613329565b6131b6565b670ddd4b8c6c7d70d881565b61227a612407565b610fdd816002613be4565b60006122918383611673565b9392505050565b600f5481565b60006122a8612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff61254516565b60006110656122e1612254565b83613cf9565b6001600160a01b031660009081526010602052604090205490565b6009546001600160a01b031681565b60006017828154811061232057fe5b6000918252602090912001546001600160a01b031692915050565b600060016001600160a01b03831660009081526010602052604090206003015460ff16600481111561236957fe5b14612376575060006110cb565b506014546001600160a01b03821660009081526016602052604090205410919050565b60006110658261233b565b6000611575600e54613a1f565b6123b9612407565b610fdd81613d39565b6001600160a01b0381166123e85760405162461bcd60e51b81526004016109ee906152a6565b803b806115dc5760405162461bcd60e51b81526004016109ee9061544c565b6005546001600160a01b031633146124315760405162461bcd60e51b81526004016109ee90615368565b565b61243c8161233b565b156125405761244a8161316d565b600061245582611107565b905060006124628361160b565b6001600160a01b038416600090815260106020526040902060010154909150612491908363ffffffff613b0116565b6001600160a01b03841660009081526010602052604090206001810191909155546124c2908263ffffffff613b0116565b6001600160a01b0384166000908152601060205260409020556124e483613b26565b6124f085858385613d89565b6001600160a01b0383166000818152601060205260408082208054600182015460029092015492516000805160206156b28339815191529461253594929392916155e3565b60405180910390a250505b505050565b600061229183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613e71565b6001600160a01b0381166125ad5760405162461bcd60e51b81526004016109ee90615264565b806001600160a01b03166125bf611f9d565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600060405161260290615111565b6040519081900390209190915550565b601780546001808201835560008381527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1590920180546001600160a01b0319166001600160a01b0386161790559154909161266d9190612545565b6001600160a01b039290921660009081526010602052604090206003018054610100600160881b0319166101006001600160801b038516021790555090565b6001600160a01b03811660009081526010602052604081206001015481906126d390613e9d565b6001600160a01b03841660009081526010602052604090206002018054908290556011549192509061271d908390612711908463ffffffff61254516565b9063ffffffff613b0116565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829161275091615568565b60405180910390a15092915050565b60008261276e57506000611065565b8282028284828161277b57fe5b04146122915760405162461bcd60e51b81526004016109ee90615327565b600061229183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ed9565b6000806127e783613bb8565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561283757600080fd5b505afa15801561284b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286f9190614edc565b1192915050565b61287e614b5c565b612886614be4565b61288e614b5c565b848252600060808301526128a0611ce8565b60a08301526128ad611ece565b60c0830152600060208301525b835182602001511015612b8057838260200151815181106128d757fe5b6020908102919091018101516001600160a01b03166060840181905260009081526010909152604090206003015460019060ff16600481111561291657fe5b1461292057612b70565b61292e826060015187611673565b60408301526080820151612a9557600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561298a57600080fd5b505afa15801561299e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c29190614edc565b8260400151101580156129d457508151155b156129de57612b70565b60006129f38360c001518460a00151896132f7565b9050612a108989856060015186604001518760000151868d613f10565b60808101518451919350612a2a919063ffffffff61254516565b8352608082015160a0840151612a459163ffffffff61254516565b60a08085019190915282015160c0840151612a659163ffffffff61254516565b60c0840152612a7484836142e6565b9350612a898360c001518460a00151896143fd565b15608084015250612b70565b81608001518015612b2e5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015612aef57600080fd5b505afa158015612b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b279190614edc565b8260400151105b15612b7057612b4788888460600151856000015161449c565b60808101518351919250612b61919063ffffffff61254516565b8252612b6d83826142e6565b92505b60208201805160010190526128ba565b505095945050505050565b612b93614b5c565b612b9b614be4565b612ba3614b5c565b848252600060208301525b835182602001511015612b805783826020015181518110612bcb57fe5b60209081029190910101516001600160a01b031660608301819052612bf09087611673565b6040808401919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c739190614edc565b82604001511015612cbb57612c9288888460600151856000015161449c565b60808101518351919250612cac919063ffffffff61254516565b8252612cb883826142e6565b92505b6020820180516001019052612bae565b81612cd557612f29565b601854600090612cf79061271184670de0b6b3a764000063ffffffff61275f16565b90506000612d1c601954612711670de0b6b3a76400008761275f90919063ffffffff16565b90506000612d356011548461279990919063ffffffff16565b90506000612d4e6011548461279990919063ffffffff16565b9050612d75612d686011548461275f90919063ffffffff16565b859063ffffffff61254516565b601855601154612d9d90612d9090839063ffffffff61275f16565b849063ffffffff61254516565b601955601454612db3908363ffffffff613b0116565b601455601554612dc9908263ffffffff613b0116565b60158190556014546040517f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e392612e009291615571565b60405180910390a160405163121cbc4d60e11b81526001600160a01b03891690632439789a90612e34908990600401615568565b600060405180830381600087803b158015612e4e57600080fd5b505af1158015612e62573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038a16925063f2e91d719150612e92908990600401615568565b600060405180830381600087803b158015612eac57600080fd5b505af1158015612ec0573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b038b1692506364a197f39150612ef2908a908990600401615188565b600060405180830381600087803b158015612f0c57600080fd5b505af1158015612f20573d6000803e3d6000fd5b50505050505050505b50505050565b6011546012819055506000826001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7357600080fd5b505afa158015612f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fab9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ffd57600080fd5b505afa158015613011573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130359190614edc565b905061304b81612711848663ffffffff61254516565b60138190556012546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf60926130829291615571565b60405180910390a150505050565b811561310157600954600754604051631062c15f60e11b81526001600160a01b03928316926320c582be926130ce9291169087908790600401615142565b600060405180830381600087803b1580156130e857600080fd5b505af11580156130fc573d6000803e3d6000fd5b505050505b8015612f29576040516364a197f360e01b81526001600160a01b038516906364a197f3906131359086908590600401615188565b600060405180830381600087803b15801561314f57600080fd5b505af1158015613163573d6000803e3d6000fd5b5050505050505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561319957fe5b14610fdd5760405162461bcd60e51b81526004016109ee90615519565b600061106561324583600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b505afa158015613221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127119190614edc565b670de0b6b3a76400006145ce565b6000612291670de0b6b3a76400006111b7858563ffffffff61275f16565b600080600061327f84611107565b9050600061328c8561160b565b6001600160a01b038616600090815260106020526040812060010154919250906132bc908463ffffffff613b0116565b6001600160a01b038716600090815260106020526040812054919250906132e9908463ffffffff613b0116565b919550909350505050915091565b6000821561331e576000613315846111b7878663ffffffff61275f16565b91506122919050565b506000199392505050565b6000806133346145e4565b9050600061334a670ddd4b8c6c7d70d883614600565b9050611e00670de0b6b3a76400006111b783600e5461275f90919063ffffffff16565b6000613384600f544261254590919063ffffffff16565b9050603c8110610fdd5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc91610f1191615568565b6133ca614b5c565b6133d2614be4565b6133da614b5c565b848252600060808301526133ec611ce8565b60a08301526133f9611ece565b8260c001818152505086608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561343f57600080fd5b505afa158015613453573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134779190614cbb565b82606001906001600160a01b031690816001600160a01b031681525050600087608001516001600160a01b0316631e2231436040518163ffffffff1660e01b815260040160206040518083038186803b1580156134d357600080fd5b505afa1580156134e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350b9190614cbb565b6000602085015290505b84836020015110801561353e5750806001600160a01b031683606001516001600160a01b031614155b1561385e5760808801516060840151604051632dc9c0eb60e21b81526000926001600160a01b03169163b72703ac9161357a919060040161512e565b60206040518083038186803b15801561359257600080fd5b505afa1580156135a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ca9190614cbb565b90506135da846060015189611673565b6040850152608084015161375357600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561363657600080fd5b505afa15801561364a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061366e9190614edc565b84604001511015801561368057508351155b1561368b575061385e565b60006136a08560c001518660a001518b6132f7565b8a5160208c01516060880151604089015189519495506136c194868f613f10565b608081015186519195506136db919063ffffffff61254516565b8552608084015160a08601516136f69163ffffffff61254516565b8560a00181815250506137238461010001516114c38660a001518860c0015161254590919063ffffffff16565b60c086015261373286856142e6565b95506137478560c001518660a001518b6143fd565b15608086015250613840565b836080015180156137ec5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156137ad57600080fd5b505afa1580156137c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e59190614edc565b8460400151105b1561383a5761380d89600001518a602001518660600151876000015161449c565b60808101518551919450613827919063ffffffff61254516565b845261383385846142e6565b9450613840565b5061385e565b6001600160a01b031660608401526020830180516001019052613515565b505050949350505050565b613871614b5c565b613879614be4565b613881614b5c565b600d54858352600060208401526001600160a01b03165b8483602001511015613a1357806001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156138dd57600080fd5b505afa1580156138f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139159190614cbb565b6001600160a01b03166060840181905261392f9088611673565b6040808501919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b15801561397a57600080fd5b505afa15801561398e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b29190614edc565b836040015110156139fe576139d189898560600151866000015161449c565b608081015184519193506139eb919063ffffffff61254516565b83526139f784836142e6565b9350613a03565b613a13565b6020830180516001019052613898565b50505095945050505050565b6000611065613a7683600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b031663240926696040518163ffffffff1660e01b815260040160206040518083038186803b158015613ac457600080fd5b505afa158015613ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613afc9190614edc565b6145ce565b6000828201838110156122915760405162461bcd60e51b81526004016109ee9061522d565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92610f11929091615571565b60008115613baf57613ba8826111b78568056bc75e2d6310000063ffffffff61275f16565b9050611065565b50600019611065565b600080613bc3611ece565b90506000613bcf611ce8565b9050613bdc8282866132f7565b949350505050565b6000816004811115613bf257fe5b14158015613c0c57506001816004811115613c0957fe5b14155b613c1257fe5b601754613c1e816146ab565b6001600160a01b0383166000908152601060205260409020600301805483919060ff19166001836004811115613c5057fe5b02179055506001600160a01b0383166000908152601060209081526040808320600180820185905590849055601690925282208281550155613c928382614751565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e90613cc290869060040161512e565b600060405180830381600087803b158015613cdc57600080fd5b505af1158015613cf0573d6000803e3d6000fd5b50505050505050565b600080613d18670de0b6b3a76400006111b7868663ffffffff61275f16565b90508281106122915760405162461bcd60e51b81526004016109ee90615481565b6001600160a01b038116600090815260106020526040902060020154601154613d68908263ffffffff61254516565b601155506001600160a01b0316600090815260106020526040812060020155565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a90613db5908590600401615568565b600060405180830381600087803b158015613dcf57600080fd5b505af1158015613de3573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150613e13908590600401615568565b600060405180830381600087803b158015613e2d57600080fd5b505af1158015613e41573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150613135908490600401615568565b60008184841115613e955760405162461bcd60e51b81526004016109ee91906151da565b505050900390565b60008060135460001415613eb2575081611065565b600060125411613ebe57fe5b6122916013546111b76012548661275f90919063ffffffff16565b60008183613efa5760405162461bcd60e51b81526004016109ee91906151da565b506000838581613f0657fe5b0495945050505050565b613f18614b5c565b613f20614c2c565b601754600110613f3057506142db565b613f398761212a565b60408501526020848101919091528401819052908352613f58906148f2565b604083018190526801158e460913d0000060608401526020830151613f829163ffffffff61254516565b8152670de0b6b3a7640000861161404d57613fa7898983602001518460400151613d89565b613fb087613d39565b60006080830181905260a0830152815160c0830152805160e0830152613fd7876003613be4565b815160208301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b60405180910390a2866001600160a01b03166000805160206156b28339815191526000806000600260405161404094939291906151ac565b60405180910390a26142d9565b670de0b6b3a7640000861180156140e85750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156140ad57600080fd5b505afa1580156140c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e59190614edc565b86105b1561413857614101898983602001518460400151613d89565b61410a87613d39565b8151815161411991908761497e565b60e086015260c085015260a08401526080830152613fd7876003613be4565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561418657600080fd5b505afa15801561419a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141be9190614edc565b86101580156141cc57508386105b80156141d9575081518510155b156142c8576141f2898983602001518460400151613d89565b846141f957fe5b61420287613d39565b61421582600001518360200151856149ea565b9150614222876003613be4565b6101008201511561429757600854610100830151604051633f10abab60e01b81526001600160a01b0390921691633f10abab91614264918b9190600401615188565b600060405180830381600087803b15801561427e57600080fd5b505af1158015614292573d6000803e3d6000fd5b505050505b815160a08301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b6142d0614b5c565b91506142db9050565b505b979650505050505050565b6142ee614b5c565b604080830151908401516143079163ffffffff613b0116565b6040820152606080830151908401516143259163ffffffff613b0116565b6060820152815160208401516143409163ffffffff613b0116565b602080830191909152820151835161435d9163ffffffff613b0116565b8152608080830151908401516143789163ffffffff613b0116565b608082015260a080830151908401516143969163ffffffff613b0116565b60a082015260c080830151908401516143b49163ffffffff613b0116565b60c082015260e080830151908401516143d29163ffffffff613b0116565b60e082015261010080830151908401516143f19163ffffffff613b0116565b61010082015292915050565b60008061440b8585856132f7565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561445b57600080fd5b505afa15801561446f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144939190614edc565b11949350505050565b6144a4614b5c565b6144ac614c2c565b6144b58461212a565b604085019081526020858101928352860192909252918452905190516144df918891889190613d89565b6144e884613d39565b6144f582602001516148f2565b604083018190526801158e460913d0000060608401526020830151600091614523919063ffffffff61254516565b90506145348360000151828661497e565b60e087015260c086015260a08501526080840152614553856003613be4565b825160208401516040516001600160a01b03881692600080516020615692833981519152926145849260019061557f565b60405180910390a2846001600160a01b03166000805160206156b2833981519152600080600060016040516145bc94939291906151ac565b60405180910390a25050949350505050565b60008183106145dd5781612291565b5090919050565b6000611575603c6111b7600f544261254590919063ffffffff16565b6000631f54050082111561461657631f54050091505b8161462a5750670de0b6b3a7640000611065565b670de0b6b3a764000083835b60018111156146a1576002810661466b576146518283614af8565b915061466481600263ffffffff61279916565b905061469c565b6146758284614af8565b92506146818283614af8565b915061469960026111b783600163ffffffff61254516565b90505b614636565b6111c38284614af8565b6001811180156147355750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b1580156146fb57600080fd5b505afa15801561470f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147339190614edc565b115b610fdd5760405162461bcd60e51b81526004016109ee906152dd565b6001600160a01b03821660009081526010602052604081206003015460ff169081600481111561477d57fe5b141580156147975750600181600481111561479457fe5b14155b61479d57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b03169083906147d5826001612545565b905080836001600160801b031611156147ea57fe5b6000601782815481106147f957fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b03871690811061482b57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a906148b49083908790615166565b60405180910390a160178054806148c757fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b600354604080516324386ecd60e11b815290516000926001600160a01b031691634870dd9a916004808301926020929190829003018186803b15801561493757600080fd5b505afa15801561494b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496f9190614edc565b828161497757fe5b0492915050565b600080808084156149d45761499387866145ce565b93506149a9876111b7888763ffffffff61275f16565b92506149bb878563ffffffff61254516565b91506149cd868463ffffffff61254516565b90506149e1565b5060009250829150859050845b93509350935093565b6149f2614b5c565b838152602080820184905260035460408051631e5395c960e21b81529051600093614a8e9387936111b7936001600160a01b039092169263794e572492600480840193829003018186803b158015614a4957600080fd5b505afa158015614a5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a819190614edc565b889063ffffffff61275f16565b9050614a99816148f2565b604083018190526801158e460913d00000606084015260808301869052614ac790829063ffffffff61254516565b60a0830152614adc848263ffffffff61254516565b61010083015250600060c0820181905260e08201529392505050565b600080614b0b848463ffffffff61275f16565b9050613bdc670de0b6b3a76400006111b7836706f05b59d3b20000613b01565b6040518060a00160405280600081526020016000815260200160001515815260200160008152602001600081525090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040518060e0016040528060008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b80356110658161567c565b60008083601f840112614c69578081fd5b50813567ffffffffffffffff811115614c80578182fd5b602083019150836020828501011115614c9857600080fd5b9250929050565b600060208284031215614cb0578081fd5b81356122918161567c565b600060208284031215614ccc578081fd5b81516122918161567c565b60008060408385031215614ce9578081fd5b8235614cf48161567c565b946020939093013593505050565b60006020808385031215614d14578182fd5b823567ffffffffffffffff811115614d2a578283fd5b80840185601f820112614d3b578384fd5b80359150614d50614d4b83615651565b61562a565b8281528381019082850185850284018601891015614d6c578687fd5b8693505b848410156142d957614d828982614c4d565b835260019390930192918501918501614d70565b60006101c0808385031215614da9578182fd5b614db28161562a565b614dbc8585614c4d565b8152614dcb8560208601614c4d565b6020820152614ddd8560408601614c4d565b6040820152614def8560608601614c4d565b6060820152614e018560808601614c4d565b6080820152614e138560a08601614c4d565b60a0820152614e258560c08601614c4d565b60c0820152614e378560e08601614c4d565b60e08201526101009150614e4d85838601614c4d565b828201526101209150614e6285838601614c4d565b828201526101409150614e7785838601614c4d565b828201526101609150614e8c85838601614c4d565b828201526101809150614ea185838601614c4d565b828201526101a09150614eb685838601614c4d565b918101919091529392505050565b600060208284031215614ed5578081fd5b5035919050565b600060208284031215614eed578081fd5b5051919050565b600080600080600080600060e0888a031215614f0e578283fd5b873596506020880135614f208161567c565b95506040880135614f308161567c565b94506060880135614f408161567c565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a03610160811215614f7e578182fd5b8935985060208a0135614f908161567c565b975060408a0135614fa08161567c565b965060608a0135614fb08161567c565b955060808a810135955060a08b0135945060c08b0135935060df1982011215614fd7578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c0361018081121561500b578485fd5b8b359a5060208c013561501d8161567c565b995060408c013561502d8161567c565b985060608c013561503d8161567c565b975060808c810135975060a08d0135965060c08d0135955060df19820190811215615066578384fd5b615070606061562a565b9150604081121561507f578384fd5b5061508a604061562a565b60e08d01356150988161567c565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff8111156150dd578283fd5b6150e98d828e01614c58565b8194508093505050509295989b9194979a5092959850565b6000828483379101908152919050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b848152602081018490526040810183905260808101600483106151cb57fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015615206578581018301518582016040015282016151ea565b818111156152175783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252603b908201527f54726f76654d616e616765723a2043616c6c6572206973206e6f74207468652060408201527f426f72726f7765724f7065726174696f6e7320636f6e74726163740000000000606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2043616c6c646174612061646472657373206160408201527572726179206d757374206e6f7420626520656d70747960501b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526022908201527f54726f76654d616e616765723a206e6f7468696e6720746f206c697175696461604082015261746560f01b606082015260800190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b90815260200190565b918252602082015260400190565b838152602081018390526060810161559683615671565b6040830152949350505050565b858152602081018590526040810184905260a08101600584106155c257fe5b60608201939093526001600160801b03919091166080909101529392505050565b84815260208101849052604081018390526080810161560183615671565b606083015295945050505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff8111828210171561564957600080fd5b604052919050565b600067ffffffffffffffff821115615667578081fd5b5060209081020190565b80600481106110cb57fe5b6001600160a01b0381168114610fdd57600080fdfeea67486ed7ebe3eea8ab3390efd4a3c8aae48be5bea27df104a8af786c408434c3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba2646970667358221220a4c2a9a9ec603c1ba14143d02dd4e890d8f91d610315ce69bf8078c0892e8c2464736f6c634300060b0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106104c25760003560e01c8063756b253e11610278578063b0d8e1811161015c578063d293c710116100ce578063d815e8e911610092578063d815e8e91461095a578063d9a7244414610962578063e056e91814610975578063e2ac77b014610988578063f36b24251461099b578063fe2ba848146109a3576104c2565b8063d293c71014610906578063d380a37c14610919578063d3d6f84314610921578063d5b3563514610934578063d66a255314610947576104c2565b8063be4b033411610120578063be4b0334146108cb578063bf9befb1146108d3578063c35bc550146108db578063c52861f2146108e3578063c7b55481146108eb578063cbd138ae146108f3576104c2565b8063b0d8e18114610867578063b7f8cf9b1461087a578063b82f263d14610882578063b91af97c14610895578063bcd37526146108b8576104c2565b8063887105d3116101f55780639dd233d2116101b95780639dd233d2146108325780639f0706701461083a578063a20baee614610773578063a3f4df7e14610842578063ae7bec1914610857578063ae9187541461085f576104c2565b8063887105d3146107f4578063893d20e8146107fc57806396d711ff146108045780639708daf41461080c5780639976cf451461081f576104c2565b80637cf54e401161023c5780637cf54e40146107b65780637f7dde4a146107be578063807d138d146107c657806382fe3eb9146107ce57806387436936146107e1576104c2565b8063756b253e14610783578063759b303414610796578063794e57241461079e578063795d26c3146107a6578063797250e3146107ae576104c2565b80633cc74225116103aa57806361ec893d1161031c5780636b444952116102e05780636b4449521461072c5780636ef6433814610734578063716c47e61461075857806372423c171461076057806372fe25aa14610773578063741bef1a1461077b576104c2565b806361ec893d146106e3578063631203b0146106eb57806364cee260146106fe578063653d46e71461071157806366ca4a2114610724576104c2565b80634a767d681161036e5780634a767d681461067a5780634e443d9e1461068d5780635733d58f146106ad5780635d6b480f146106b55780635d8c9609146106c85780635dba4c4a146106db576104c2565b80633cc742251461063157806342ccf1e414610639578063477d66cf1461064c578063480cd5781461065f57806349eefeee14610672576104c2565b806317c62b17116104435780631f68f20a116104075780631f68f20a146105eb57806321e37801146105f35780632b11551a146106065780632f8655681461060e57806331c903b0146106215780633a12859514610629576104c2565b806317c62b171461059757806318f2817a146105aa5780631a59a50e146105bd5780631bf43555146105d05780631e8b1c2b146105d8576104c2565b806312261ee71161048a57806312261ee71461053557806312610e921461053d57806313af40351461055057806315d549f1146105635780631673c79a14610576576104c2565b806301f16e18146104c757806305b6f5ca146104dc578063071a7541146104ef5780630b0765571461050d5780630d43e8ad14610520575b600080fd5b6104da6104d5366004614d96565b6109b6565b005b6104da6104ea366004614f61565b610f1c565b6104f7610fb3565b6040516105049190615568565b60405180910390f35b6104da61051b366004614c9f565b610fb8565b610528610fe0565b604051610504919061512e565b610528610fef565b6104f761054b366004614cd7565b611013565b6104da61055e366004614c9f565b61106b565b6104f7610571366004614c9f565b6110ac565b610589610584366004614c9f565b6110d0565b604051610504929190615571565b6104f76105a5366004614c9f565b6110e9565b6104f76105b8366004614c9f565b6110f4565b6104f76105cb366004614c9f565b611107565b6104f76111cd565b6104da6105e6366004614d02565b6111da565b6104f761153b565b6104f7610601366004614c9f565b611541565b6104f761156b565b6104da61061c366004614c9f565b61157a565b6104f76115e0565b6105286115ed565b6105286115fc565b6104f7610647366004614c9f565b61160b565b6104f761065a366004614ec4565b61163c565b6104f761066d366004614c9f565b61164f565b6104f761166d565b6104f7610688366004614cd7565b611673565b6106a061069b366004614ec4565b611692565b60405161050491906151a1565b6104f761169d565b6104da6106c3366004614cd7565b61171a565b6104f76106d6366004614c9f565b611766565b6104da611771565b6104f76117dc565b6104f76106f9366004614ec4565b6117e1565b6104f761070c366004614c9f565b6117ee565b6104da61071f366004614ec4565b61180c565b6104f7611b96565b6104f7611ba8565b610747610742366004614c9f565b611bae565b6040516105049594939291906155a3565b610528611be8565b6104f761076e366004614cd7565b611bf7565b6104f7611c54565b610528611c60565b610528610791366004614ec4565b611c6f565b6104f7611c96565b6104f7611ca3565b6104f7611ce8565b6104f7611e07565b610528611e0d565b610528611e1c565b6104f7611e2b565b6104da6107dc366004614c9f565b611e31565b6104da6107ef366004614c9f565b611e42565b6104f7611ece565b610528611f9d565b6104f7611fbc565b6104da61081a366004614feb565b611fc2565b6104f761082d366004614cd7565b61205b565b6104f761208e565b610528612094565b61084a6120a3565b60405161050491906151da565b6105286120cb565b6105286120da565b6104f7610875366004614c9f565b6120e9565b610528612110565b6104f7610890366004614ec4565b61211f565b6108a86108a3366004614c9f565b61212a565b604051610504949392919061560f565b6104da6108c6366004614ef4565b61218e565b6104f7612224565b6104f761222a565b6104f7612230565b6104f7612254565b6104f7612266565b6104da610901366004614c9f565b612272565b6104f7610914366004614cd7565b612285565b6104f7612298565b6104f761092f366004614cd7565b61229e565b6104f7610942366004614ec4565b6122d4565b6104f7610955366004614c9f565b6122e7565b610528612302565b610528610970366004614ec4565b612311565b6106a0610983366004614c9f565b61233b565b6106a0610996366004614c9f565b612399565b6104f76123a4565b6104da6109b1366004614c9f565b6123b1565b6109be611f9d565b6001600160a01b0316336001600160a01b0316146109f75760405162461bcd60e51b81526004016109ee906153c5565b60405180910390fd5b8051610a02906123c2565b610a0f81602001516123c2565b610a1c81604001516123c2565b610a2981606001516123c2565b610a3681608001516123c2565b610a438160a001516123c2565b610a508160c001516123c2565b610a5d8160e001516123c2565b610a6b8161010001516123c2565b610a798161012001516123c2565b610a878161014001516123c2565b610a958161016001516123c2565b610aa38161018001516123c2565b610ab1816101a001516123c2565b8051600c80546001600160a01b03199081166001600160a01b038085169190911790925560208401516004805483169184169190911790556040808501516003805484169185169190911790556060850151600580548416918516919091179055608085015160008054841691851691909117905560a085015160018054841691851691909117905560c085015160068054841691851691909117905560e0850151600780548416918516919091179055610100850151600880548416918516919091179055610120850151600280548416918516919091179055610140850151600980548416918516919091179055610160850151600d80548416918516919091179055610180850151600a805484169185169190911790556101a0850151600b80549093169316929092179055517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db991610c0c9161512e565b60405180910390a17f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b18160200151604051610c47919061512e565b60405180910390a17fbf65195e6d5213f6fcbce65b1454c925197a45e616dabd2e243542b039b050928160600151604051610c82919061512e565b60405180910390a17f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed9858160600151604051610cbd919061512e565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828160800151604051610cf8919061512e565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b8160a00151604051610d33919061512e565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f8160c00151604051610d6e919061512e565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa08160e00151604051610da9919061512e565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d816101000151604051610de5919061512e565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264816101200151604051610e21919061512e565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d816101400151604051610e5d919061512e565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800816101600151604051610e99919061512e565b60405180910390a17f61e0c29d5028a9e4facaa476a46e78912e99f1ba945c9560b86b82ebe36ee52d816101800151604051610ed5919061512e565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd816101a00151604051610f11919061512e565b60405180910390a150565b6004546040516000916060916001600160a01b0390911690610f419084903690615101565b600060405180830381855af49150503d8060008114610f7c576040519150601f19603f3d011682016040523d82523d6000602084013e610f81565b606091505b5091509150818190610fa65760405162461bcd60e51b81526004016109ee91906151da565b5050505050505050505050565b600281565b610fc0612407565b600054600154610fdd916001600160a01b03908116911683612433565b50565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061101d612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff61254516565b6001600160a01b03851660009081526010602052604090208190559150505b92915050565b611073611f9d565b6001600160a01b0316336001600160a01b0316146110a35760405162461bcd60e51b81526004016109ee906153c5565b610fdd81612587565b60006110b6612407565b6110bf82612612565b6001600160801b031690505b919050565b6016602052600090815260409020805460019091015482565b60006110658261160b565b60006110fe612407565b611065826126ac565b6001600160a01b0381166000908152601660205260408120546014548290611135908363ffffffff61254516565b905080158061116e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561116b57fe5b14155b1561117e576000925050506110cb565b6001600160a01b038416600090815260106020526040812060020154906111c3670de0b6b3a76400006111b7848663ffffffff61275f16565b9063ffffffff61279916565b9695505050505050565b6809c2007651b250000081565b80516111f85760405162461bcd60e51b81526004016109ee906153f6565b6000546001546006546001600160a01b0392831692918216911661121a614b2b565b611222614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ec57600080fd5b505afa158015611300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113249190614edc565b60208301528151611334906127db565b158015604084015261135c576113558585846000015185602001518a612876565b9050611374565b6113718585846000015185602001518a612b8b565b90505b60008160200151116113985760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad926113cc92600401615571565b600060405180830381600087803b1580156113e657600080fd5b505af11580156113fa573d6000803e3d6000fd5b5050505061141285858360c001518460e00151612ccb565b61010081015115611489576008546101008201516040516364a197f360e01b81526001600160a01b03888116936364a197f393611456939290911691600401615188565b600060405180830381600087803b15801561147057600080fd5b505af1158015611484573d6000803e3d6000fd5b505050505b611497858260400151612f2f565b60208101516060830152610100810151604082015182516114cf92916114c3919063ffffffff61254516565b9063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611517949092909161560f565b60405180910390a1611533853383606001518460400151613090565b505050505050565b600e5481565b6001600160a01b03811660009081526010602052604081206003015460ff16600481111561106557fe5b60006115756115e0565b905090565b6115838161316d565b6040805160018082528183019092526060916020808301908036833701905050905081816000815181106115b357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506115dc816111da565b5050565b6000611575600e546131b6565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290611135908363ffffffff61254516565b6000611065611649611b96565b83613253565b6001600160a01b031660009081526010602052604090206001015490565b60175490565b600080600061168185613271565b9150915060006111c38383876132f7565b6000611065826127db565b60035460408051635733d58f60e01b815290516000926001600160a01b031691635733d58f916004808301926020929190829003018186803b1580156116e257600080fd5b505afa1580156116f6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115759190614edc565b611722612407565b80600481111561172e57fe5b6001600160a01b0383166000908152601060205260409020600301805460ff1916600183600481111561175d57fe5b02179055505050565b600061106582611107565b611779612407565b6000611783613329565b9050670de0b6b3a764000081111561179757fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c906117cc908390615568565b60405180910390a1610fdd61336d565b603c81565b60006110656116496123a4565b6001600160a01b031660009081526010602052604090206002015490565b611814614ba8565b506040805160e081018252600080546001600160a01b0390811683526001548116602084015292820181905260608201819052600d548316608083015260a0820181905260c082015260065490911661186b614b2b565b611873614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fb9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b15801561193d57600080fd5b505afa158015611951573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119759190614edc565b60208301528151611985906127db565b15801560408401526119ac576119a58483600001518460200151886133c2565b90506119cc565b6119c9846000015185602001518460000151856020015189613869565b90505b60008160200151116119f05760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad92611a2492600401615571565b600060405180830381600087803b158015611a3e57600080fd5b505af1158015611a52573d6000803e3d6000fd5b50505050611a72846000015185602001518360c001518460e00151612ccb565b61010081015115611ae95783516008546101008301516040516364a197f360e01b81526001600160a01b03938416936364a197f393611ab693911691600401615188565b600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050505b611afb84600001518260400151612f2f565b6020810151606083015261010081015160408201518251611b2792916114c3919063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611b6f949092909161560f565b60405180910390a1611b8f84600001513383606001518460400151613090565b5050505050565b6000611575611ba3613329565b613a1f565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b6000611c01612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff613b0116565b6001600160a01b038516600090815260106020526040902060010181905591505092915050565b670de0b6b3a764000081565b6002546001600160a01b031681565b60178181548110611c7c57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60035460408051631e5395c960e21b815290516000926001600160a01b03169163794e5724916004808301926020929190829003018186803b1580156116e257600080fd5b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015611d2c57600080fd5b505afa158015611d40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d649190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b505afa158015611dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dee9190614edc565b9050611e00828263ffffffff613b0116565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b611e39612407565b610fdd81613b26565b611e4a611f9d565b6001600160a01b0316336001600160a01b031614611e7a5760405162461bcd60e51b81526004016109ee906153c5565b611e83816123c2565b600480546001600160a01b0319166001600160a01b0383161790556040517f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b190610f1190839061512e565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b158015611f1357600080fd5b505afa158015611f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4b9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b600080604051611fac90615111565b6040519081900390205492915050565b60135481565b6004546040516000916060916001600160a01b0390911690611fe79084903690615101565b600060405180830381855af49150503d8060008114612022576040519150601f19603f3d011682016040523d82523d6000602084013e612027565b606091505b509150915081819061204c5760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050505050565b6000612065612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff613b0116565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b60008060006120f784613271565b9150915060006121078383613b83565b95945050505050565b6005546001600160a01b031681565b600061106582613bb8565b6001600160a01b03811660009081526010602052604081208054600190910154909180612156856110e9565b915061216185611766565b9050612173848363ffffffff613b0116565b9350612185838263ffffffff613b0116565b92509193509193565b6004546040516000916060916001600160a01b03909116906121b39084903690615101565b600060405180830381855af49150503d80600081146121ee576040519150601f19603f3d011682016040523d82523d6000602084013e6121f3565b606091505b50915091508181906122185760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000611575612261613329565b6131b6565b670ddd4b8c6c7d70d881565b61227a612407565b610fdd816002613be4565b60006122918383611673565b9392505050565b600f5481565b60006122a8612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff61254516565b60006110656122e1612254565b83613cf9565b6001600160a01b031660009081526010602052604090205490565b6009546001600160a01b031681565b60006017828154811061232057fe5b6000918252602090912001546001600160a01b031692915050565b600060016001600160a01b03831660009081526010602052604090206003015460ff16600481111561236957fe5b14612376575060006110cb565b506014546001600160a01b03821660009081526016602052604090205410919050565b60006110658261233b565b6000611575600e54613a1f565b6123b9612407565b610fdd81613d39565b6001600160a01b0381166123e85760405162461bcd60e51b81526004016109ee906152a6565b803b806115dc5760405162461bcd60e51b81526004016109ee9061544c565b6005546001600160a01b031633146124315760405162461bcd60e51b81526004016109ee90615368565b565b61243c8161233b565b156125405761244a8161316d565b600061245582611107565b905060006124628361160b565b6001600160a01b038416600090815260106020526040902060010154909150612491908363ffffffff613b0116565b6001600160a01b03841660009081526010602052604090206001810191909155546124c2908263ffffffff613b0116565b6001600160a01b0384166000908152601060205260409020556124e483613b26565b6124f085858385613d89565b6001600160a01b0383166000818152601060205260408082208054600182015460029092015492516000805160206156b28339815191529461253594929392916155e3565b60405180910390a250505b505050565b600061229183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613e71565b6001600160a01b0381166125ad5760405162461bcd60e51b81526004016109ee90615264565b806001600160a01b03166125bf611f9d565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600060405161260290615111565b6040519081900390209190915550565b601780546001808201835560008381527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1590920180546001600160a01b0319166001600160a01b0386161790559154909161266d9190612545565b6001600160a01b039290921660009081526010602052604090206003018054610100600160881b0319166101006001600160801b038516021790555090565b6001600160a01b03811660009081526010602052604081206001015481906126d390613e9d565b6001600160a01b03841660009081526010602052604090206002018054908290556011549192509061271d908390612711908463ffffffff61254516565b9063ffffffff613b0116565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829161275091615568565b60405180910390a15092915050565b60008261276e57506000611065565b8282028284828161277b57fe5b04146122915760405162461bcd60e51b81526004016109ee90615327565b600061229183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ed9565b6000806127e783613bb8565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561283757600080fd5b505afa15801561284b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286f9190614edc565b1192915050565b61287e614b5c565b612886614be4565b61288e614b5c565b848252600060808301526128a0611ce8565b60a08301526128ad611ece565b60c0830152600060208301525b835182602001511015612b8057838260200151815181106128d757fe5b6020908102919091018101516001600160a01b03166060840181905260009081526010909152604090206003015460019060ff16600481111561291657fe5b1461292057612b70565b61292e826060015187611673565b60408301526080820151612a9557600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561298a57600080fd5b505afa15801561299e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c29190614edc565b8260400151101580156129d457508151155b156129de57612b70565b60006129f38360c001518460a00151896132f7565b9050612a108989856060015186604001518760000151868d613f10565b60808101518451919350612a2a919063ffffffff61254516565b8352608082015160a0840151612a459163ffffffff61254516565b60a08085019190915282015160c0840151612a659163ffffffff61254516565b60c0840152612a7484836142e6565b9350612a898360c001518460a00151896143fd565b15608084015250612b70565b81608001518015612b2e5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015612aef57600080fd5b505afa158015612b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b279190614edc565b8260400151105b15612b7057612b4788888460600151856000015161449c565b60808101518351919250612b61919063ffffffff61254516565b8252612b6d83826142e6565b92505b60208201805160010190526128ba565b505095945050505050565b612b93614b5c565b612b9b614be4565b612ba3614b5c565b848252600060208301525b835182602001511015612b805783826020015181518110612bcb57fe5b60209081029190910101516001600160a01b031660608301819052612bf09087611673565b6040808401919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c739190614edc565b82604001511015612cbb57612c9288888460600151856000015161449c565b60808101518351919250612cac919063ffffffff61254516565b8252612cb883826142e6565b92505b6020820180516001019052612bae565b81612cd557612f29565b601854600090612cf79061271184670de0b6b3a764000063ffffffff61275f16565b90506000612d1c601954612711670de0b6b3a76400008761275f90919063ffffffff16565b90506000612d356011548461279990919063ffffffff16565b90506000612d4e6011548461279990919063ffffffff16565b9050612d75612d686011548461275f90919063ffffffff16565b859063ffffffff61254516565b601855601154612d9d90612d9090839063ffffffff61275f16565b849063ffffffff61254516565b601955601454612db3908363ffffffff613b0116565b601455601554612dc9908263ffffffff613b0116565b60158190556014546040517f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e392612e009291615571565b60405180910390a160405163121cbc4d60e11b81526001600160a01b03891690632439789a90612e34908990600401615568565b600060405180830381600087803b158015612e4e57600080fd5b505af1158015612e62573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038a16925063f2e91d719150612e92908990600401615568565b600060405180830381600087803b158015612eac57600080fd5b505af1158015612ec0573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b038b1692506364a197f39150612ef2908a908990600401615188565b600060405180830381600087803b158015612f0c57600080fd5b505af1158015612f20573d6000803e3d6000fd5b50505050505050505b50505050565b6011546012819055506000826001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7357600080fd5b505afa158015612f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fab9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ffd57600080fd5b505afa158015613011573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130359190614edc565b905061304b81612711848663ffffffff61254516565b60138190556012546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf60926130829291615571565b60405180910390a150505050565b811561310157600954600754604051631062c15f60e11b81526001600160a01b03928316926320c582be926130ce9291169087908790600401615142565b600060405180830381600087803b1580156130e857600080fd5b505af11580156130fc573d6000803e3d6000fd5b505050505b8015612f29576040516364a197f360e01b81526001600160a01b038516906364a197f3906131359086908590600401615188565b600060405180830381600087803b15801561314f57600080fd5b505af1158015613163573d6000803e3d6000fd5b5050505050505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561319957fe5b14610fdd5760405162461bcd60e51b81526004016109ee90615519565b600061106561324583600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b505afa158015613221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127119190614edc565b670de0b6b3a76400006145ce565b6000612291670de0b6b3a76400006111b7858563ffffffff61275f16565b600080600061327f84611107565b9050600061328c8561160b565b6001600160a01b038616600090815260106020526040812060010154919250906132bc908463ffffffff613b0116565b6001600160a01b038716600090815260106020526040812054919250906132e9908463ffffffff613b0116565b919550909350505050915091565b6000821561331e576000613315846111b7878663ffffffff61275f16565b91506122919050565b506000199392505050565b6000806133346145e4565b9050600061334a670ddd4b8c6c7d70d883614600565b9050611e00670de0b6b3a76400006111b783600e5461275f90919063ffffffff16565b6000613384600f544261254590919063ffffffff16565b9050603c8110610fdd5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc91610f1191615568565b6133ca614b5c565b6133d2614be4565b6133da614b5c565b848252600060808301526133ec611ce8565b60a08301526133f9611ece565b8260c001818152505086608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561343f57600080fd5b505afa158015613453573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134779190614cbb565b82606001906001600160a01b031690816001600160a01b031681525050600087608001516001600160a01b0316631e2231436040518163ffffffff1660e01b815260040160206040518083038186803b1580156134d357600080fd5b505afa1580156134e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350b9190614cbb565b6000602085015290505b84836020015110801561353e5750806001600160a01b031683606001516001600160a01b031614155b1561385e5760808801516060840151604051632dc9c0eb60e21b81526000926001600160a01b03169163b72703ac9161357a919060040161512e565b60206040518083038186803b15801561359257600080fd5b505afa1580156135a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ca9190614cbb565b90506135da846060015189611673565b6040850152608084015161375357600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561363657600080fd5b505afa15801561364a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061366e9190614edc565b84604001511015801561368057508351155b1561368b575061385e565b60006136a08560c001518660a001518b6132f7565b8a5160208c01516060880151604089015189519495506136c194868f613f10565b608081015186519195506136db919063ffffffff61254516565b8552608084015160a08601516136f69163ffffffff61254516565b8560a00181815250506137238461010001516114c38660a001518860c0015161254590919063ffffffff16565b60c086015261373286856142e6565b95506137478560c001518660a001518b6143fd565b15608086015250613840565b836080015180156137ec5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156137ad57600080fd5b505afa1580156137c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e59190614edc565b8460400151105b1561383a5761380d89600001518a602001518660600151876000015161449c565b60808101518551919450613827919063ffffffff61254516565b845261383385846142e6565b9450613840565b5061385e565b6001600160a01b031660608401526020830180516001019052613515565b505050949350505050565b613871614b5c565b613879614be4565b613881614b5c565b600d54858352600060208401526001600160a01b03165b8483602001511015613a1357806001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156138dd57600080fd5b505afa1580156138f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139159190614cbb565b6001600160a01b03166060840181905261392f9088611673565b6040808501919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b15801561397a57600080fd5b505afa15801561398e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b29190614edc565b836040015110156139fe576139d189898560600151866000015161449c565b608081015184519193506139eb919063ffffffff61254516565b83526139f784836142e6565b9350613a03565b613a13565b6020830180516001019052613898565b50505095945050505050565b6000611065613a7683600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b031663240926696040518163ffffffff1660e01b815260040160206040518083038186803b158015613ac457600080fd5b505afa158015613ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613afc9190614edc565b6145ce565b6000828201838110156122915760405162461bcd60e51b81526004016109ee9061522d565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92610f11929091615571565b60008115613baf57613ba8826111b78568056bc75e2d6310000063ffffffff61275f16565b9050611065565b50600019611065565b600080613bc3611ece565b90506000613bcf611ce8565b9050613bdc8282866132f7565b949350505050565b6000816004811115613bf257fe5b14158015613c0c57506001816004811115613c0957fe5b14155b613c1257fe5b601754613c1e816146ab565b6001600160a01b0383166000908152601060205260409020600301805483919060ff19166001836004811115613c5057fe5b02179055506001600160a01b0383166000908152601060209081526040808320600180820185905590849055601690925282208281550155613c928382614751565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e90613cc290869060040161512e565b600060405180830381600087803b158015613cdc57600080fd5b505af1158015613cf0573d6000803e3d6000fd5b50505050505050565b600080613d18670de0b6b3a76400006111b7868663ffffffff61275f16565b90508281106122915760405162461bcd60e51b81526004016109ee90615481565b6001600160a01b038116600090815260106020526040902060020154601154613d68908263ffffffff61254516565b601155506001600160a01b0316600090815260106020526040812060020155565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a90613db5908590600401615568565b600060405180830381600087803b158015613dcf57600080fd5b505af1158015613de3573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150613e13908590600401615568565b600060405180830381600087803b158015613e2d57600080fd5b505af1158015613e41573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150613135908490600401615568565b60008184841115613e955760405162461bcd60e51b81526004016109ee91906151da565b505050900390565b60008060135460001415613eb2575081611065565b600060125411613ebe57fe5b6122916013546111b76012548661275f90919063ffffffff16565b60008183613efa5760405162461bcd60e51b81526004016109ee91906151da565b506000838581613f0657fe5b0495945050505050565b613f18614b5c565b613f20614c2c565b601754600110613f3057506142db565b613f398761212a565b60408501526020848101919091528401819052908352613f58906148f2565b604083018190526801158e460913d0000060608401526020830151613f829163ffffffff61254516565b8152670de0b6b3a7640000861161404d57613fa7898983602001518460400151613d89565b613fb087613d39565b60006080830181905260a0830152815160c0830152805160e0830152613fd7876003613be4565b815160208301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b60405180910390a2866001600160a01b03166000805160206156b28339815191526000806000600260405161404094939291906151ac565b60405180910390a26142d9565b670de0b6b3a7640000861180156140e85750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156140ad57600080fd5b505afa1580156140c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e59190614edc565b86105b1561413857614101898983602001518460400151613d89565b61410a87613d39565b8151815161411991908761497e565b60e086015260c085015260a08401526080830152613fd7876003613be4565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561418657600080fd5b505afa15801561419a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141be9190614edc565b86101580156141cc57508386105b80156141d9575081518510155b156142c8576141f2898983602001518460400151613d89565b846141f957fe5b61420287613d39565b61421582600001518360200151856149ea565b9150614222876003613be4565b6101008201511561429757600854610100830151604051633f10abab60e01b81526001600160a01b0390921691633f10abab91614264918b9190600401615188565b600060405180830381600087803b15801561427e57600080fd5b505af1158015614292573d6000803e3d6000fd5b505050505b815160a08301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b6142d0614b5c565b91506142db9050565b505b979650505050505050565b6142ee614b5c565b604080830151908401516143079163ffffffff613b0116565b6040820152606080830151908401516143259163ffffffff613b0116565b6060820152815160208401516143409163ffffffff613b0116565b602080830191909152820151835161435d9163ffffffff613b0116565b8152608080830151908401516143789163ffffffff613b0116565b608082015260a080830151908401516143969163ffffffff613b0116565b60a082015260c080830151908401516143b49163ffffffff613b0116565b60c082015260e080830151908401516143d29163ffffffff613b0116565b60e082015261010080830151908401516143f19163ffffffff613b0116565b61010082015292915050565b60008061440b8585856132f7565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561445b57600080fd5b505afa15801561446f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144939190614edc565b11949350505050565b6144a4614b5c565b6144ac614c2c565b6144b58461212a565b604085019081526020858101928352860192909252918452905190516144df918891889190613d89565b6144e884613d39565b6144f582602001516148f2565b604083018190526801158e460913d0000060608401526020830151600091614523919063ffffffff61254516565b90506145348360000151828661497e565b60e087015260c086015260a08501526080840152614553856003613be4565b825160208401516040516001600160a01b03881692600080516020615692833981519152926145849260019061557f565b60405180910390a2846001600160a01b03166000805160206156b2833981519152600080600060016040516145bc94939291906151ac565b60405180910390a25050949350505050565b60008183106145dd5781612291565b5090919050565b6000611575603c6111b7600f544261254590919063ffffffff16565b6000631f54050082111561461657631f54050091505b8161462a5750670de0b6b3a7640000611065565b670de0b6b3a764000083835b60018111156146a1576002810661466b576146518283614af8565b915061466481600263ffffffff61279916565b905061469c565b6146758284614af8565b92506146818283614af8565b915061469960026111b783600163ffffffff61254516565b90505b614636565b6111c38284614af8565b6001811180156147355750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b1580156146fb57600080fd5b505afa15801561470f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147339190614edc565b115b610fdd5760405162461bcd60e51b81526004016109ee906152dd565b6001600160a01b03821660009081526010602052604081206003015460ff169081600481111561477d57fe5b141580156147975750600181600481111561479457fe5b14155b61479d57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b03169083906147d5826001612545565b905080836001600160801b031611156147ea57fe5b6000601782815481106147f957fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b03871690811061482b57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a906148b49083908790615166565b60405180910390a160178054806148c757fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b600354604080516324386ecd60e11b815290516000926001600160a01b031691634870dd9a916004808301926020929190829003018186803b15801561493757600080fd5b505afa15801561494b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496f9190614edc565b828161497757fe5b0492915050565b600080808084156149d45761499387866145ce565b93506149a9876111b7888763ffffffff61275f16565b92506149bb878563ffffffff61254516565b91506149cd868463ffffffff61254516565b90506149e1565b5060009250829150859050845b93509350935093565b6149f2614b5c565b838152602080820184905260035460408051631e5395c960e21b81529051600093614a8e9387936111b7936001600160a01b039092169263794e572492600480840193829003018186803b158015614a4957600080fd5b505afa158015614a5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a819190614edc565b889063ffffffff61275f16565b9050614a99816148f2565b604083018190526801158e460913d00000606084015260808301869052614ac790829063ffffffff61254516565b60a0830152614adc848263ffffffff61254516565b61010083015250600060c0820181905260e08201529392505050565b600080614b0b848463ffffffff61275f16565b9050613bdc670de0b6b3a76400006111b7836706f05b59d3b20000613b01565b6040518060a00160405280600081526020016000815260200160001515815260200160008152602001600081525090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040518060e0016040528060008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b80356110658161567c565b60008083601f840112614c69578081fd5b50813567ffffffffffffffff811115614c80578182fd5b602083019150836020828501011115614c9857600080fd5b9250929050565b600060208284031215614cb0578081fd5b81356122918161567c565b600060208284031215614ccc578081fd5b81516122918161567c565b60008060408385031215614ce9578081fd5b8235614cf48161567c565b946020939093013593505050565b60006020808385031215614d14578182fd5b823567ffffffffffffffff811115614d2a578283fd5b80840185601f820112614d3b578384fd5b80359150614d50614d4b83615651565b61562a565b8281528381019082850185850284018601891015614d6c578687fd5b8693505b848410156142d957614d828982614c4d565b835260019390930192918501918501614d70565b60006101c0808385031215614da9578182fd5b614db28161562a565b614dbc8585614c4d565b8152614dcb8560208601614c4d565b6020820152614ddd8560408601614c4d565b6040820152614def8560608601614c4d565b6060820152614e018560808601614c4d565b6080820152614e138560a08601614c4d565b60a0820152614e258560c08601614c4d565b60c0820152614e378560e08601614c4d565b60e08201526101009150614e4d85838601614c4d565b828201526101209150614e6285838601614c4d565b828201526101409150614e7785838601614c4d565b828201526101609150614e8c85838601614c4d565b828201526101809150614ea185838601614c4d565b828201526101a09150614eb685838601614c4d565b918101919091529392505050565b600060208284031215614ed5578081fd5b5035919050565b600060208284031215614eed578081fd5b5051919050565b600080600080600080600060e0888a031215614f0e578283fd5b873596506020880135614f208161567c565b95506040880135614f308161567c565b94506060880135614f408161567c565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a03610160811215614f7e578182fd5b8935985060208a0135614f908161567c565b975060408a0135614fa08161567c565b965060608a0135614fb08161567c565b955060808a810135955060a08b0135945060c08b0135935060df1982011215614fd7578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c0361018081121561500b578485fd5b8b359a5060208c013561501d8161567c565b995060408c013561502d8161567c565b985060608c013561503d8161567c565b975060808c810135975060a08d0135965060c08d0135955060df19820190811215615066578384fd5b615070606061562a565b9150604081121561507f578384fd5b5061508a604061562a565b60e08d01356150988161567c565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff8111156150dd578283fd5b6150e98d828e01614c58565b8194508093505050509295989b9194979a5092959850565b6000828483379101908152919050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b848152602081018490526040810183905260808101600483106151cb57fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015615206578581018301518582016040015282016151ea565b818111156152175783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252603b908201527f54726f76654d616e616765723a2043616c6c6572206973206e6f74207468652060408201527f426f72726f7765724f7065726174696f6e7320636f6e74726163740000000000606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2043616c6c646174612061646472657373206160408201527572726179206d757374206e6f7420626520656d70747960501b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526022908201527f54726f76654d616e616765723a206e6f7468696e6720746f206c697175696461604082015261746560f01b606082015260800190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b90815260200190565b918252602082015260400190565b838152602081018390526060810161559683615671565b6040830152949350505050565b858152602081018590526040810184905260a08101600584106155c257fe5b60608201939093526001600160801b03919091166080909101529392505050565b84815260208101849052604081018390526080810161560183615671565b606083015295945050505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff8111828210171561564957600080fd5b604052919050565b600067ffffffffffffffff821115615667578081fd5b5060209081020190565b80600481106110cb57fe5b6001600160a01b0381168114610fdd57600080fdfeea67486ed7ebe3eea8ab3390efd4a3c8aae48be5bea27df104a8af786c408434c3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba2646970667358221220a4c2a9a9ec603c1ba14143d02dd4e890d8f91d610315ce69bf8078c0892e8c2464736f6c634300060b0033", + "implementation": "0x2c51a1ff7a7dcb8e93d4bd137a9e402445ea4037" +} diff --git a/external/deployments/rskTestnet/TroveManagerRedeemOps.json b/external/deployments/rskTestnet/TroveManagerRedeemOps.json new file mode 100644 index 000000000..da9adaeb2 --- /dev/null +++ b/external/deployments/rskTestnet/TroveManagerRedeemOps.json @@ -0,0 +1,1587 @@ +{ + "address": "0x51e93f35ab4fcfa610b280fd32696d28c9482aa8", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_bootstrapPeriod", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_baseRate", + "type": "uint256" + } + ], + "name": "BaseRateUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "LTermsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_lastFeeOpTime", + "type": "uint256" + } + ], + "name": "LastFeeOpTimeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedDebt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedColl", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_collGasCompensation", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDGasCompensation", + "type": "uint256" + } + ], + "name": "Liquidation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_attemptedZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_actualZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHSent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHFee", + "type": "uint256" + } + ], + "name": "Redemption", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_totalStakesSnapshot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalCollateralSnapshot", + "type": "uint256" + } + ], + "name": "SystemSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newTotalStakes", + "type": "uint256" + } + ], + "name": "TotalStakesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newIndex", + "type": "uint256" + } + ], + "name": "TroveIndexUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum TroveManagerBase.TroveManagerOperation", + "name": "_operation", + "type": "uint8" + } + ], + "name": "TroveLiquidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "TroveSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_stake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum TroveManagerBase.TroveManagerOperation", + "name": "_operation", + "type": "uint8" + } + ], + "name": "TroveUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "BETA", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BOOTSTRAP_PERIOD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ETH", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ZUSDDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINUTE_DECAY_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SECONDS_IN_ONE_MINUTE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "TroveOwners", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "Troves", + "outputs": [ + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coll", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "internalType": "enum TroveManagerStorage.Status", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "arrayIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "_getCurrentICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingETHReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingZUSDDebtReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_getRedemptionRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_hasPendingRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_stabilityPool", + "outputs": [ + { + "internalType": "contract IStabilityPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroStaking", + "outputs": [ + { + "internalType": "contract IZEROStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroToken", + "outputs": [ + { + "internalType": "contract IZEROToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "borrowerOperationsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeDistributor", + "outputs": [ + { + "internalType": "contract IFeeDistributor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastETHError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFeeOperationTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastZUSDDebtError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDamount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + } + ], + "name": "redeemCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "redeemCollateralViaDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "redeemCollateralViaDllrWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "rewardSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "ETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ZUSDDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalCollateralSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakesSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManagerRedeemOps", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xa204ada1c6efe89dd25c0bcafa2150b377068ec91f2be2124ca46bade37b35fb", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0x5835205e52C6e23c2E7D74F2117538fA8bC3Fc0B", + "transactionIndex": 0, + "gasUsed": "4195652", + "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000001010000000000000000000000000000008000020000000000000000001800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xac4b5fe40db4d9eed4c31111782207da277eb3022a8d4c3252f9a4906681a64c", + "transactionHash": "0xa204ada1c6efe89dd25c0bcafa2150b377068ec91f2be2124ca46bade37b35fb", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748983, + "transactionHash": "0xa204ada1c6efe89dd25c0bcafa2150b377068ec91f2be2124ca46bade37b35fb", + "address": "0x5835205e52C6e23c2E7D74F2117538fA8bC3Fc0B", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0xac4b5fe40db4d9eed4c31111782207da277eb3022a8d4c3252f9a4906681a64c" + } + ], + "blockNumber": 4748983, + "cumulativeGasUsed": "4195652", + "status": 1, + "byzantium": true + }, + "args": ["1209600", "0x000000000022d473030f116ddee9f6b43ac78ba3"], + "numDeployments": 3, + "solcInputHash": "849fadfa265e27de6fba2f2d99bdf763", + "metadata": "{\"compiler\":{\"version\":\"0.6.11+commit.5ef660b1\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_bootstrapPeriod\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_permit2\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_baseRate\",\"type\":\"uint256\"}],\"name\":\"BaseRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ETH\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"LTermsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_lastFeeOpTime\",\"type\":\"uint256\"}],\"name\":\"LastFeeOpTimeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_liquidatedDebt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_liquidatedColl\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_collGasCompensation\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ZUSDGasCompensation\",\"type\":\"uint256\"}],\"name\":\"Liquidation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_attemptedZUSDAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_actualZUSDAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ETHSent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ETHFee\",\"type\":\"uint256\"}],\"name\":\"Redemption\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalStakesSnapshot\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalCollateralSnapshot\",\"type\":\"uint256\"}],\"name\":\"SystemSnapshotsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newTotalStakes\",\"type\":\"uint256\"}],\"name\":\"TotalStakesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newIndex\",\"type\":\"uint256\"}],\"name\":\"TroveIndexUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_coll\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"enum TroveManagerBase.TroveManagerOperation\",\"name\":\"_operation\",\"type\":\"uint8\"}],\"name\":\"TroveLiquidated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ETH\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"TroveSnapshotsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_coll\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_stake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"enum TroveManagerBase.TroveManagerOperation\",\"name\":\"_operation\",\"type\":\"uint8\"}],\"name\":\"TroveUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BETA\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"BOOTSTRAP_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DECIMAL_PRECISION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L_ETH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L_ZUSDDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MINUTE_DECAY_FACTOR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_NET_DEBT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SECONDS_IN_ONE_MINUTE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"TroveOwners\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"Troves\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"debt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"coll\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"enum TroveManagerStorage.Status\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint128\",\"name\":\"arrayIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZUSD_GAS_COMPENSATION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_100pct\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_price\",\"type\":\"uint256\"}],\"name\":\"_getCurrentICR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_getPendingETHReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_getPendingZUSDDebtReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_getRedemptionRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_hasPendingRewards\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_stabilityPool\",\"outputs\":[{\"internalType\":\"contract IStabilityPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zeroStaking\",\"outputs\":[{\"internalType\":\"contract IZEROStaking\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zeroToken\",\"outputs\":[{\"internalType\":\"contract IZEROToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zusdToken\",\"outputs\":[{\"internalType\":\"contract IZUSDToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activePool\",\"outputs\":[{\"internalType\":\"contract IActivePool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"borrowerOperationsAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultPool\",\"outputs\":[{\"internalType\":\"contract IDefaultPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeDistributor\",\"outputs\":[{\"internalType\":\"contract IFeeDistributor\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemColl\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastETHError_Redistribution\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFeeOperationTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastZUSDDebtError_Redistribution\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquityBaseParams\",\"outputs\":[{\"internalType\":\"contract ILiquityBaseParams\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceFeed\",\"outputs\":[{\"internalType\":\"contract IPriceFeed\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ZUSDamount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"}],\"name\":\"redeemCollateral\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"redeemCollateralViaDLLR\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"redeemCollateralViaDllrWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"rewardSnapshots\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"ETH\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"ZUSDDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortedTroves\",\"outputs\":[{\"internalType\":\"contract ISortedTroves\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalCollateralSnapshot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalStakesSnapshot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"troveManagerRedeemOps\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getOwner()\":{\"returns\":{\"_owner\":\"Address of the owner. \"}},\"setOwner(address)\":{\"params\":{\"_owner\":\"Address of the owner. \"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BETA()\":{\"notice\":\"BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption. Corresponds to (1 / ALPHA) in the white paper.\"},\"BOOTSTRAP_PERIOD()\":{\"notice\":\"During bootsrap period redemptions are not allowed\"},\"MIN_NET_DEBT()\":{\"notice\":\"Minimum amount of net ZUSD debt a trove must have\"},\"ZUSD_GAS_COMPENSATION()\":{\"notice\":\"Amount of ZUSD to be locked in gas pool on opening troves\"},\"_getCurrentICR(address,uint256)\":{\"notice\":\"Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\"},\"_getPendingETHReward(address)\":{\"notice\":\"Get the borrower's pending accumulated ETH reward, earned by their stake\"},\"_getPendingZUSDDebtReward(address)\":{\"notice\":\"Get the borrower's pending accumulated ZUSD reward, earned by their stake\"},\"constructor\":\"Constructor \",\"getOwner()\":{\"notice\":\"Return address of the owner.\"},\"permit2()\":{\"notice\":\"CONSTANT / IMMUTABLE VARIABLE ONLY \"},\"redeemCollateralViaDLLR(uint256,address,address,address,uint256,uint256,uint256,(uint256,uint8,bytes32,bytes32))\":{\"notice\":\"DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\"},\"redeemCollateralViaDllrWithPermit2(uint256,address,address,address,uint256,uint256,uint256,((address,uint256),uint256,uint256),bytes)\":{\"notice\":\"DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\"},\"setOwner(address)\":{\"notice\":\"Set address of the owner (only owner can call this function)\"}},\"notice\":\"This contract is designed to be used via delegatecall from the TroveManager contract TroveManagerBase constructor param is bootsrap period when redemptions are not allowed\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Dependencies/TroveManagerRedeemOps.sol\":\"TroveManagerRedeemOps\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"contracts/Dependencies/BaseMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\n\\ncontract BaseMath {\\n uint constant public DECIMAL_PRECISION = 1e18;\\n}\\n\",\"keccak256\":\"0x7e1369ca5cb09e818e345a2def19a261401f79c985a6030b55b7311dd6f53be4\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on the OpenZeppelin IER20 interface:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol\\n *\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\\n function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n function name() external view returns (string memory);\\n function symbol() external view returns (string memory);\\n function decimals() external view returns (uint8);\\n \\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\",\"keccak256\":\"0xe0b2473eba89df8d27d7cea2a99fce788c212f3fd393c9508e449e51a3f220fa\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC2612.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * @dev Interface of the ERC2612 standard as defined in the EIP.\\n *\\n * Adds the {permit} method, which can be used to change one's\\n * {IERC20-allowance} without having to send a transaction, by signing a\\n * message. This allows users to spend tokens without having to hold Ether.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2612.\\n * \\n * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/\\n */\\ninterface IERC2612 {\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,\\n * given `owner`'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(address owner, address spender, uint256 amount, \\n uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;\\n \\n /**\\n * @dev Returns the current ERC2612 nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases `owner`'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n *\\n * `owner` can limit the time a Permit is valid for by setting `deadline` to \\n * a value in the near future. The deadline argument can be set to uint(-1) to \\n * create Permits that effectively never expire.\\n */\\n function nonces(address owner) external view returns (uint256);\\n \\n function version() external view returns (string memory);\\n function permitTypeHash() external view returns (bytes32);\\n function domainSeparator() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xd376458452f8b480bfea549637bd71d3f9eb1f12e9d59d1beff373417462d67f\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./BaseMath.sol\\\";\\nimport \\\"./LiquityMath.sol\\\";\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IPriceFeed.sol\\\";\\nimport \\\"../Interfaces/ILiquityBase.sol\\\";\\nimport \\\"../Interfaces/ILiquityBaseParams.sol\\\";\\n\\n/**\\n * Base contract for TroveManager, BorrowerOperations and StabilityPool. Contains global system constants and\\n * common functions.\\n */\\ncontract LiquityBase is BaseMath, ILiquityBase {\\n using SafeMath for uint256;\\n\\n uint256 public constant _100pct = 1000000000000000000; // 1e18 == 100%\\n\\n /// Amount of ZUSD to be locked in gas pool on opening troves\\n uint256 public constant ZUSD_GAS_COMPENSATION = 20e18;\\n\\n /// Minimum amount of net ZUSD debt a trove must have\\n uint256 public constant MIN_NET_DEBT = 180e18;\\n\\n IActivePool public activePool;\\n\\n IDefaultPool public defaultPool;\\n\\n IPriceFeed public override priceFeed;\\n\\n ILiquityBaseParams public override liquityBaseParams;\\n\\n // --- Gas compensation functions ---\\n\\n // Returns the composite debt (drawn debt + gas compensation) of a trove, for the purpose of ICR calculation\\n function _getCompositeDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.add(ZUSD_GAS_COMPENSATION);\\n }\\n\\n function _getNetDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.sub(ZUSD_GAS_COMPENSATION);\\n }\\n\\n /// Return the amount of ETH to be drawn from a trove's collateral and sent as gas compensation.\\n function _getCollGasCompensation(uint256 _entireColl) internal view returns (uint256) {\\n return _entireColl / liquityBaseParams.PERCENT_DIVISOR();\\n }\\n\\n function getEntireSystemColl() public view returns (uint256 entireSystemColl) {\\n uint256 activeColl = activePool.getETH();\\n uint256 liquidatedColl = defaultPool.getETH();\\n\\n return activeColl.add(liquidatedColl);\\n }\\n\\n function getEntireSystemDebt() public view returns (uint256 entireSystemDebt) {\\n uint256 activeDebt = activePool.getZUSDDebt();\\n uint256 closedDebt = defaultPool.getZUSDDebt();\\n\\n return activeDebt.add(closedDebt);\\n }\\n\\n function _getTCR(uint256 _price) internal view returns (uint256 TCR) {\\n uint256 entireSystemColl = getEntireSystemColl();\\n uint256 entireSystemDebt = getEntireSystemDebt();\\n\\n TCR = LiquityMath._computeCR(entireSystemColl, entireSystemDebt, _price);\\n\\n return TCR;\\n }\\n\\n function _checkRecoveryMode(uint256 _price) internal view returns (bool) {\\n uint256 TCR = _getTCR(_price);\\n\\n return TCR < liquityBaseParams.CCR();\\n }\\n\\n function _requireUserAcceptsFee(\\n uint256 _fee,\\n uint256 _amount,\\n uint256 _maxFeePercentage\\n ) internal pure {\\n uint256 feePercentage = _fee.mul(DECIMAL_PRECISION).div(_amount);\\n require(feePercentage <= _maxFeePercentage, \\\"Fee exceeded provided maximum\\\");\\n }\\n}\\n\",\"keccak256\":\"0x100b8a1c17caa95f5c9977e88f9263847a1977a365ca0a795753dd74aa1d6d7c\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./console.sol\\\";\\n\\nlibrary LiquityMath {\\n using SafeMath for uint;\\n\\n uint internal constant DECIMAL_PRECISION = 1e18;\\n\\n /* Precision for Nominal ICR (independent of price). Rationale for the value:\\n *\\n * - Making it \\u201ctoo high\\u201d could lead to overflows.\\n * - Making it \\u201ctoo low\\u201d could lead to an ICR equal to zero, due to truncation from Solidity floor division. \\n *\\n * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH,\\n * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.\\n *\\n */\\n uint internal constant NICR_PRECISION = 1e20;\\n\\n function _min(uint _a, uint _b) internal pure returns (uint) {\\n return (_a < _b) ? _a : _b;\\n }\\n\\n function _max(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a : _b;\\n }\\n\\n /* \\n * Multiply two decimal numbers and use normal rounding rules:\\n * -round product up if 19'th mantissa digit >= 5\\n * -round product down if 19'th mantissa digit < 5\\n *\\n * Used only inside the exponentiation, _decPow().\\n */\\n function decMul(uint x, uint y) internal pure returns (uint decProd) {\\n uint prod_xy = x.mul(y);\\n\\n decProd = prod_xy.add(DECIMAL_PRECISION / 2).div(DECIMAL_PRECISION);\\n }\\n\\n /* \\n * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.\\n * \\n * Uses the efficient \\\"exponentiation by squaring\\\" algorithm. O(log(n)) complexity. \\n * \\n * Called by two functions that represent time in units of minutes:\\n * 1) TroveManager._calcDecayedBaseRate\\n * 2) CommunityIssuance._getCumulativeIssuanceFraction \\n * \\n * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals\\n * \\\"minutes in 1000 years\\\": 60 * 24 * 365 * 1000\\n * \\n * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be\\n * negligibly different from just passing the cap, since: \\n *\\n * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years\\n * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible\\n */\\n function _decPow(uint _base, uint _minutes) internal pure returns (uint) {\\n \\n if (_minutes > 525600000) {_minutes = 525600000;} // cap to avoid overflow\\n \\n if (_minutes == 0) {return DECIMAL_PRECISION;}\\n\\n uint y = DECIMAL_PRECISION;\\n uint x = _base;\\n uint n = _minutes;\\n\\n // Exponentiation-by-squaring\\n while (n > 1) {\\n if (n % 2 == 0) {\\n x = decMul(x, x);\\n n = n.div(2);\\n } else { // if (n % 2 != 0)\\n y = decMul(x, y);\\n x = decMul(x, x);\\n n = (n.sub(1)).div(2);\\n }\\n }\\n\\n return decMul(x, y);\\n }\\n\\n function _getAbsoluteDifference(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a.sub(_b) : _b.sub(_a);\\n }\\n\\n function _computeNominalCR(uint _coll, uint _debt) internal pure returns (uint) {\\n if (_debt > 0) {\\n return _coll.mul(NICR_PRECISION).div(_debt);\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1;\\n }\\n }\\n\\n function _computeCR(uint _coll, uint _debt, uint _price) internal pure returns (uint) {\\n if (_debt > 0) {\\n uint newCollRatio = _coll.mul(_price).div(_debt);\\n\\n return newCollRatio;\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1; \\n }\\n }\\n}\\n\",\"keccak256\":\"0x7a95ed70d8937e0896c054b433ad0dfc87a9cfd028cae1694098e9d5d68127cd\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IDLLR.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\nimport \\\"../IERC20.sol\\\";\\n\\n/// Public interface for Sovryn Dollar DLLR (Meta Asset Token of Sovryn Mynt) exposing specific functions\\ninterface IDLLR is IERC20 {\\n /**\\n * @notice Only owner can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _recipient Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transfer(address _recipient, uint256 _amount) external override returns (bool);\\n\\n /**\\n * @notice Only owner who can transfer the token.\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of token that will be transferred.\\n *\\n * @return true / false.\\n */\\n function transferFrom(\\n address _from,\\n address _to,\\n uint256 _amount\\n ) external override returns (bool);\\n\\n /**\\n * @notice transfer utilizing EIP-2612, to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @notice destination cannot be:\\n * - zero (0x0) address.\\n *\\n * @dev By calling this function, the allowance will be overwritten by the total amount.\\n *\\n * @param _from Sender of the token.\\n * @param _to Recipient of the token.\\n * @param _amount The amount of the token that will be transferred.\\n * @param _deadline Expiration time of the signature.\\n * @param _v Last 1 byte of ECDSA signature.\\n * @param _r First 32 bytes of ECDSA signature.\\n * @param _s 32 bytes after _r in ECDSA signature.\\n */\\n function transferWithPermit(\\n address _from,\\n address _to,\\n uint256 _amount,\\n uint256 _deadline,\\n uint8 _v,\\n bytes32 _r,\\n bytes32 _s\\n ) external;\\n\\n /**\\n * @notice Approves and then calls the receiving contract.\\n * Useful to encapsulate sending tokens to a contract in one call.\\n * Solidity has no native way to send tokens to contracts.\\n * ERC-20 tokens require approval to be spent by third parties, such as a contract in this case.\\n * @param _spender The contract address to spend the tokens.\\n * @param _amount The amount of tokens to be sent.\\n * @param _data Parameters for the contract call, such as endpoint signature.\\n */\\n function approveAndCall(address _spender, uint256 _amount, bytes calldata _data) external;\\n}\\n\",\"keccak256\":\"0x1fcc09759323769fcaa430bef598cf08a9f5e98ce6a9bdd6faa79d8b7b6ecce2\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IMassetManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IMassetManager {\\n struct PermitParams {\\n uint256 deadline;\\n uint8 v;\\n bytes32 r;\\n bytes32 s;\\n }\\n\\n function mintTo(\\n address _bAsset,\\n uint256 _bAssetQuantity,\\n address _recipient\\n ) external returns (uint256);\\n\\n function getToken() external view returns (address);\\n\\n /**\\n * @dev Credits a recipient with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @param _recipient Address to credit with withdrawn bAssets.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeemTo(\\n address _bAsset,\\n uint256 _massetQuantity,\\n address _recipient\\n ) external returns (uint256 massetRedeemed);\\n}\\n\",\"keccak256\":\"0x3e8de462d45e8f07ef83b6b6e7eb90a5d09f21d3bcbb1225e8f781488ab4a771\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/MyntLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IMassetManager.sol\\\";\\nimport \\\"./IDLLR.sol\\\";\\nimport \\\"../SafeMath.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"../../Interfaces/IPermit2.sol\\\";\\n\\nlibrary MyntLib {\\n using SafeMath for uint256;\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @dev WARNING!! Do not us this lib function on RSK network because there is a griefing attack issue in the DLLR contract.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _dllrAmount The amount of the DLLR (mAsset) token that will be burned in exchange for _toToken\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permitParams EIP-2612 permit params:\\n * _deadline Expiration time of the signature.\\n * _v Last 1 byte of ECDSA signature.\\n * _r First 32 bytes of ECDSA signature.\\n * _s 32 bytes after _r in ECDSA signature.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit(\\n IMassetManager _myntMassetManager,\\n uint256 _dllrAmount,\\n address _toToken,\\n IMassetManager.PermitParams calldata _permitParams\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n dllr.transferWithPermit(\\n msg.sender,\\n thisAddress,\\n _dllrAmount,\\n _permitParams.deadline,\\n _permitParams.v,\\n _permitParams.r,\\n _permitParams.s\\n );\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @notice Convert DLLR _dllrAmount to _toToken utilizing EIP-2612 permit via a canonical Permit2 contract\\n * to reduce the additional sending transaction for doing the approval to the spender.\\n *\\n * @param _myntMassetManager Mynt protocol MassetManager contract address - needed for integration\\n * @param _toToken bAsset token address to withdraw from DLLR\\n * @param _permit permit data, in form of PermitTransferFrom struct.\\n * @param _permit2 permit2 contract address\\n * @param _signature signatue of the permit data.\\n * @return redeemed ZUSD amount\\n */\\n function redeemZusdFromDllrWithPermit2(\\n IMassetManager _myntMassetManager,\\n address _toToken,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n IPermit2 _permit2,\\n bytes calldata _signature\\n ) internal returns (uint256) {\\n IDLLR dllr = IDLLR(_myntMassetManager.getToken());\\n uint256 thisBalanceBefore = dllr.balanceOf(address(this));\\n address thisAddress = address(this);\\n uint256 _dllrAmount = _permit.permitted.amount;\\n\\n _permit2.permitTransferFrom(\\n _permit,\\n _generateTransferDetails(thisAddress, _dllrAmount),\\n msg.sender,\\n _signature\\n );\\n\\n require(\\n dllr.balanceOf(thisAddress).sub(thisBalanceBefore) == _dllrAmount,\\n \\\"DLLR transferred amount validation failed\\\"\\n );\\n return _myntMassetManager.redeemTo(_toToken, _dllrAmount, msg.sender);\\n }\\n\\n /**\\n * @dev view function to construct SignatureTransferDetails struct to be used by Permit2\\n *\\n * @param _to ultimate recipient\\n * @param _amount amount of transfer\\n *\\n * @return SignatureTransferDetails struct object \\n */\\n function _generateTransferDetails(address _to, uint256 _amount) private view returns (ISignatureTransfer.SignatureTransferDetails memory) {\\n ISignatureTransfer.SignatureTransferDetails memory transferDetails = ISignatureTransfer.SignatureTransferDetails({\\n to: _to,\\n requestedAmount: _amount\\n });\\n\\n return transferDetails;\\n }\\n}\\n\",\"keccak256\":\"0x6f0c78d8c4ea0b5b5e6bbe8d78374b9d2d367ffc07054dde36b9cbe2061944b6\",\"license\":\"MIT\"},\"contracts/Dependencies/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's Ownable contract:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\\n *\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable {\\n bytes32 private constant KEY_OWNER = keccak256(\\\"key.ownable.owner\\\");\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor () internal {\\n _setOwner(msg.sender);\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(msg.sender == getOwner(), \\\"Ownable:: access denied\\\");\\n _;\\n }\\n\\n /**\\n * @notice Set address of the owner.\\n * @param _owner Address of the owner.\\n * */\\n function _setOwner(address _owner) internal {\\n require(_owner != address(0), \\\"Ownable::setOwner: invalid address\\\");\\n emit OwnershipTransferred(getOwner(), _owner);\\n\\n bytes32 key = KEY_OWNER;\\n assembly {\\n sstore(key, _owner)\\n }\\n }\\n\\n /**\\n * @notice Set address of the owner (only owner can call this function)\\n * @param _owner Address of the owner.\\n * */\\n function setOwner(address _owner) public onlyOwner {\\n _setOwner(_owner);\\n }\\n\\n /**\\n * @notice Return address of the owner.\\n * @return _owner Address of the owner.\\n * */\\n function getOwner() public view returns (address _owner) {\\n bytes32 key = KEY_OWNER;\\n assembly {\\n _owner := sload(key)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xb5fc626e0b227fc0feb1d84440585015a0a5f586547d298534a604dd113efec6\",\"license\":\"MIT\"},\"contracts/Dependencies/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's SafeMath:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol\\n *\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x666b890992a066cc791f36c2975cd595d9761a014c654c385ed36ffaf658f3fd\",\"license\":\"MIT\"},\"contracts/Dependencies/TroveManagerBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IZUSDToken.sol\\\";\\nimport \\\"../Interfaces/IZEROStaking.sol\\\";\\nimport \\\"../Interfaces/ISortedTroves.sol\\\";\\nimport \\\"../Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"../TroveManagerStorage.sol\\\";\\nimport \\\"./LiquityBase.sol\\\";\\n\\ncontract TroveManagerBase is LiquityBase, TroveManagerStorage {\\n uint256 public constant SECONDS_IN_ONE_MINUTE = 60;\\n\\n uint256 public constant MINUTE_DECAY_FACTOR = 999037758833783000;\\n\\n /// During bootsrap period redemptions are not allowed\\n uint256 public immutable BOOTSTRAP_PERIOD;\\n\\n /**\\n BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption.\\n Corresponds to (1 / ALPHA) in the white paper.\\n */\\n uint256 public constant BETA = 2;\\n\\n /**\\n --- Variable container structs for liquidations ---\\n \\n These structs are used to hold, return and assign variables inside the liquidation functions,\\n in order to avoid the error: \\\"CompilerError: Stack too deep\\\".\\n */\\n\\n struct LocalVariables_OuterLiquidationFunction {\\n uint256 price;\\n uint256 ZUSDInStabPool;\\n bool recoveryModeAtStart;\\n uint256 liquidatedDebt;\\n uint256 liquidatedColl;\\n }\\n\\n struct LocalVariables_InnerSingleLiquidateFunction {\\n uint256 collToLiquidate;\\n uint256 pendingDebtReward;\\n uint256 pendingCollReward;\\n }\\n\\n struct LocalVariables_LiquidationSequence {\\n uint256 remainingZUSDInStabPool;\\n uint256 i;\\n uint256 ICR;\\n address user;\\n bool backToNormalMode;\\n uint256 entireSystemDebt;\\n uint256 entireSystemColl;\\n }\\n\\n struct LiquidationValues {\\n uint256 entireTroveDebt;\\n uint256 entireTroveColl;\\n uint256 collGasCompensation;\\n uint256 ZUSDGasCompensation;\\n uint256 debtToOffset;\\n uint256 collToSendToSP;\\n uint256 debtToRedistribute;\\n uint256 collToRedistribute;\\n uint256 collSurplus;\\n }\\n\\n struct LiquidationTotals {\\n uint256 totalCollInSequence;\\n uint256 totalDebtInSequence;\\n uint256 totalCollGasCompensation;\\n uint256 totalZUSDGasCompensation;\\n uint256 totalDebtToOffset;\\n uint256 totalCollToSendToSP;\\n uint256 totalDebtToRedistribute;\\n uint256 totalCollToRedistribute;\\n uint256 totalCollSurplus;\\n }\\n\\n struct ContractsCache {\\n IActivePool activePool;\\n IDefaultPool defaultPool;\\n IZUSDToken zusdToken;\\n IZEROStaking zeroStaking;\\n ISortedTroves sortedTroves;\\n ICollSurplusPool collSurplusPool;\\n address gasPoolAddress;\\n }\\n // --- Variable container structs for redemptions ---\\n\\n struct RedemptionTotals {\\n uint256 remainingZUSD;\\n uint256 totalZUSDToRedeem;\\n uint256 totalETHDrawn;\\n uint256 ETHFee;\\n uint256 ETHToSendToRedeemer;\\n uint256 decayedBaseRate;\\n uint256 price;\\n uint256 totalZUSDSupplyAtStart;\\n }\\n\\n struct SingleRedemptionValues {\\n uint256 ZUSDLot;\\n uint256 ETHLot;\\n bool cancelledPartial;\\n }\\n\\n // --- Events ---\\n\\n event Liquidation(\\n uint256 _liquidatedDebt,\\n uint256 _liquidatedColl,\\n uint256 _collGasCompensation,\\n uint256 _ZUSDGasCompensation\\n );\\n event Redemption(\\n uint256 _attemptedZUSDAmount,\\n uint256 _actualZUSDAmount,\\n uint256 _ETHSent,\\n uint256 _ETHFee\\n );\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 _stake,\\n TroveManagerOperation _operation\\n );\\n event TroveLiquidated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n TroveManagerOperation _operation\\n );\\n event BaseRateUpdated(uint256 _baseRate);\\n event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);\\n event TotalStakesUpdated(uint256 _newTotalStakes);\\n event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);\\n event LTermsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveIndexUpdated(address _borrower, uint256 _newIndex);\\n\\n enum TroveManagerOperation {\\n applyPendingRewards,\\n liquidateInNormalMode,\\n liquidateInRecoveryMode,\\n redeemCollateral\\n }\\n\\n constructor(uint256 _bootstrapPeriod) public {\\n BOOTSTRAP_PERIOD = _bootstrapPeriod;\\n }\\n\\n /// Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function _getCurrentICR(address _borrower, uint256 _price) public view returns (uint256) {\\n (uint256 currentETH, uint256 currentZUSDDebt) = _getCurrentTroveAmounts(_borrower);\\n\\n uint256 ICR = LiquityMath._computeCR(currentETH, currentZUSDDebt, _price);\\n return ICR;\\n }\\n\\n function _getCurrentTroveAmounts(address _borrower) internal view returns (uint256, uint256) {\\n uint256 pendingETHReward = _getPendingETHReward(_borrower);\\n uint256 pendingZUSDDebtReward = _getPendingZUSDDebtReward(_borrower);\\n\\n uint256 currentETH = Troves[_borrower].coll.add(pendingETHReward);\\n uint256 currentZUSDDebt = Troves[_borrower].debt.add(pendingZUSDDebtReward);\\n\\n return (currentETH, currentZUSDDebt);\\n }\\n\\n /// Get the borrower's pending accumulated ETH reward, earned by their stake\\n function _getPendingETHReward(address _borrower) public view returns (uint256) {\\n uint256 snapshotETH = rewardSnapshots[_borrower].ETH;\\n uint256 rewardPerUnitStaked = L_ETH.sub(snapshotETH);\\n\\n if (rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) {\\n return 0;\\n }\\n\\n uint256 stake = Troves[_borrower].stake;\\n\\n uint256 pendingETHReward = stake.mul(rewardPerUnitStaked).div(DECIMAL_PRECISION);\\n\\n return pendingETHReward;\\n }\\n\\n /// Get the borrower's pending accumulated ZUSD reward, earned by their stake\\n function _getPendingZUSDDebtReward(address _borrower) public view returns (uint256) {\\n uint256 snapshotZUSDDebt = rewardSnapshots[_borrower].ZUSDDebt;\\n uint256 rewardPerUnitStaked = L_ZUSDDebt.sub(snapshotZUSDDebt);\\n\\n if (rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) {\\n return 0;\\n }\\n\\n uint256 stake = Troves[_borrower].stake;\\n\\n uint256 pendingZUSDDebtReward = stake.mul(rewardPerUnitStaked).div(DECIMAL_PRECISION);\\n\\n return pendingZUSDDebtReward;\\n }\\n\\n /// Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\\n function _applyPendingRewards(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n address _borrower\\n ) internal {\\n if (_hasPendingRewards(_borrower)) {\\n _requireTroveIsActive(_borrower);\\n\\n // Compute pending rewards\\n uint256 pendingETHReward = _getPendingETHReward(_borrower);\\n uint256 pendingZUSDDebtReward = _getPendingZUSDDebtReward(_borrower);\\n\\n // Apply pending rewards to trove's state\\n Troves[_borrower].coll = Troves[_borrower].coll.add(pendingETHReward);\\n Troves[_borrower].debt = Troves[_borrower].debt.add(pendingZUSDDebtReward);\\n\\n _updateTroveRewardSnapshots(_borrower);\\n\\n // Transfer from DefaultPool to ActivePool\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n pendingZUSDDebtReward,\\n pendingETHReward\\n );\\n\\n emit TroveUpdated(\\n _borrower,\\n Troves[_borrower].debt,\\n Troves[_borrower].coll,\\n Troves[_borrower].stake,\\n TroveManagerOperation.applyPendingRewards\\n );\\n }\\n }\\n\\n function _hasPendingRewards(address _borrower) public view returns (bool) {\\n /*\\n * A Trove has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:\\n * this indicates that rewards have occured since the snapshot was made, and the user therefore has\\n * pending rewards\\n */\\n if (Troves[_borrower].status != Status.active) {\\n return false;\\n }\\n\\n return (rewardSnapshots[_borrower].ETH < L_ETH);\\n }\\n\\n function _updateTroveRewardSnapshots(address _borrower) internal {\\n rewardSnapshots[_borrower].ETH = L_ETH;\\n rewardSnapshots[_borrower].ZUSDDebt = L_ZUSDDebt;\\n emit TroveSnapshotsUpdated(L_ETH, L_ZUSDDebt);\\n }\\n\\n /// Move a Trove's pending debt and collateral rewards from distributions, from the Default Pool to the Active Pool\\n function _movePendingTroveRewardsToActivePool(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _ZUSD,\\n uint256 _ETH\\n ) internal {\\n _defaultPool.decreaseZUSDDebt(_ZUSD);\\n _activePool.increaseZUSDDebt(_ZUSD);\\n _defaultPool.sendETHToActivePool(_ETH);\\n }\\n\\n /// Remove borrower's stake from the totalStakes sum, and set their stake to 0\\n function _removeStake(address _borrower) internal {\\n uint256 stake = Troves[_borrower].stake;\\n totalStakes = totalStakes.sub(stake);\\n Troves[_borrower].stake = 0;\\n }\\n\\n function _closeTrove(address _borrower, Status closedStatus) internal {\\n assert(closedStatus != Status.nonExistent && closedStatus != Status.active);\\n\\n uint256 TroveOwnersArrayLength = TroveOwners.length;\\n _requireMoreThanOneTroveInSystem(TroveOwnersArrayLength);\\n\\n Troves[_borrower].status = closedStatus;\\n Troves[_borrower].coll = 0;\\n Troves[_borrower].debt = 0;\\n\\n rewardSnapshots[_borrower].ETH = 0;\\n rewardSnapshots[_borrower].ZUSDDebt = 0;\\n\\n _removeTroveOwner(_borrower, TroveOwnersArrayLength);\\n sortedTroves.remove(_borrower);\\n }\\n\\n /// Update borrower's stake based on their latest collateral value\\n function _updateStakeAndTotalStakes(address _borrower) internal returns (uint256) {\\n uint256 newStake = _computeNewStake(Troves[_borrower].coll);\\n uint256 oldStake = Troves[_borrower].stake;\\n Troves[_borrower].stake = newStake;\\n\\n totalStakes = totalStakes.sub(oldStake).add(newStake);\\n emit TotalStakesUpdated(totalStakes);\\n\\n return newStake;\\n }\\n\\n // Calculate a new stake based on the snapshots of the totalStakes and totalCollateral taken at the last liquidation\\n function _computeNewStake(uint256 _coll) internal view returns (uint256) {\\n uint256 stake;\\n if (totalCollateralSnapshot == 0) {\\n stake = _coll;\\n } else {\\n /*\\n * The following assert() holds true because:\\n * - The system always contains >= 1 trove\\n * - When we close or liquidate a trove, we redistribute the pending rewards, so if all troves were closed/liquidated,\\n * rewards would\\u2019ve been emptied and totalCollateralSnapshot would be zero too.\\n */\\n assert(totalStakesSnapshot > 0);\\n stake = _coll.mul(totalStakesSnapshot).div(totalCollateralSnapshot);\\n }\\n return stake;\\n }\\n\\n function _calcDecayedBaseRate() internal view returns (uint256) {\\n uint256 minutesPassed = _minutesPassedSinceLastFeeOp();\\n uint256 decayFactor = LiquityMath._decPow(MINUTE_DECAY_FACTOR, minutesPassed);\\n\\n return baseRate.mul(decayFactor).div(DECIMAL_PRECISION);\\n }\\n\\n function _minutesPassedSinceLastFeeOp() internal view returns (uint256) {\\n return (block.timestamp.sub(lastFeeOperationTime)).div(SECONDS_IN_ONE_MINUTE);\\n }\\n\\n // Update the last fee operation time only if time passed >= decay interval. This prevents base rate griefing.\\n function _updateLastFeeOpTime() internal {\\n uint256 timePassed = block.timestamp.sub(lastFeeOperationTime);\\n\\n if (timePassed >= SECONDS_IN_ONE_MINUTE) {\\n lastFeeOperationTime = block.timestamp;\\n emit LastFeeOpTimeUpdated(block.timestamp);\\n }\\n }\\n\\n function _calcRedemptionFee(\\n uint256 _redemptionRate,\\n uint256 _ETHDrawn\\n ) internal pure returns (uint256) {\\n uint256 redemptionFee = _redemptionRate.mul(_ETHDrawn).div(DECIMAL_PRECISION);\\n require(\\n redemptionFee < _ETHDrawn,\\n \\\"TroveManager: Fee would eat up all returned collateral\\\"\\n );\\n return redemptionFee;\\n }\\n\\n function _getRedemptionRate() public view returns (uint256) {\\n return _calcRedemptionRate(baseRate);\\n }\\n\\n function _getRedemptionFee(uint256 _ETHDrawn) internal view returns (uint256) {\\n return _calcRedemptionFee(_getRedemptionRate(), _ETHDrawn);\\n }\\n\\n function _calcRedemptionRate(uint256 _baseRate) internal view returns (uint256) {\\n return\\n LiquityMath._min(\\n liquityBaseParams.REDEMPTION_FEE_FLOOR().add(_baseRate),\\n DECIMAL_PRECISION // cap at a maximum of 100%\\n );\\n }\\n\\n /**\\n Remove a Trove owner from the TroveOwners array, not preserving array order. Removing owner 'B' does the following:\\n [A B C D E] => [A E C D], and updates E's Trove struct to point to its new array index.\\n */\\n function _removeTroveOwner(address _borrower, uint256 TroveOwnersArrayLength) internal {\\n Status troveStatus = Troves[_borrower].status;\\n // It\\u2019s set in caller function `_closeTrove`\\n assert(troveStatus != Status.nonExistent && troveStatus != Status.active);\\n\\n uint128 index = Troves[_borrower].arrayIndex;\\n uint256 length = TroveOwnersArrayLength;\\n uint256 idxLast = length.sub(1);\\n\\n assert(index <= idxLast);\\n\\n address addressToMove = TroveOwners[idxLast];\\n\\n TroveOwners[index] = addressToMove;\\n Troves[addressToMove].arrayIndex = index;\\n emit TroveIndexUpdated(addressToMove, index);\\n\\n TroveOwners.pop();\\n }\\n\\n // --- 'require' wrapper functions ---\\n\\n function _requireCallerIsBorrowerOperations() internal view {\\n require(\\n msg.sender == borrowerOperationsAddress,\\n \\\"TroveManager: Caller is not the BorrowerOperations contract\\\"\\n );\\n }\\n\\n function _requireTroveIsActive(address _borrower) internal view {\\n require(\\n Troves[_borrower].status == Status.active,\\n \\\"TroveManager: Trove does not exist or is closed\\\"\\n );\\n }\\n\\n function _requireZUSDBalanceCoversRedemption(\\n IZUSDToken _zusdToken,\\n address _redeemer,\\n uint256 _amount\\n ) internal view {\\n require(\\n _zusdToken.balanceOf(_redeemer) >= _amount,\\n \\\"TroveManager: Requested redemption amount must be <= user's ZUSD token balance\\\"\\n );\\n }\\n\\n function _requireMoreThanOneTroveInSystem(uint256 TroveOwnersArrayLength) internal view {\\n require(\\n TroveOwnersArrayLength > 1 && sortedTroves.getSize() > 1,\\n \\\"TroveManager: Only one trove in the system\\\"\\n );\\n }\\n\\n function _requireAmountGreaterThanZero(uint256 _amount) internal pure {\\n require(_amount > 0, \\\"TroveManager: Amount must be greater than zero\\\");\\n }\\n\\n function _requireTCRoverMCR(uint256 _price) internal view {\\n require(\\n _getTCR(_price) >= liquityBaseParams.MCR(),\\n \\\"TroveManager: Cannot redeem when TCR < MCR\\\"\\n );\\n }\\n\\n function _requireAfterBootstrapPeriod() internal view {\\n uint256 systemDeploymentTime = _zeroToken.getDeploymentStartTime();\\n require(\\n block.timestamp >= systemDeploymentTime.add(BOOTSTRAP_PERIOD),\\n \\\"TroveManager: Redemptions are not allowed during bootstrap phase\\\"\\n );\\n }\\n\\n function _requireValidMaxFeePercentage(uint256 _maxFeePercentage) internal view {\\n require(\\n _maxFeePercentage >= liquityBaseParams.REDEMPTION_FEE_FLOOR() &&\\n _maxFeePercentage <= DECIMAL_PRECISION,\\n \\\"Max fee percentage must be between 0.5% and 100%\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x83e1bfaa93cf973052c41df1cc0741a93f737659cd664f207c0d42256f78617b\",\"license\":\"MIT\"},\"contracts/Dependencies/TroveManagerRedeemOps.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/MyntLib.sol\\\";\\nimport \\\"../Interfaces/IBorrowerOperations.sol\\\";\\nimport \\\"./TroveManagerBase.sol\\\";\\nimport \\\"../Interfaces/IPermit2.sol\\\";\\n\\n/// This contract is designed to be used via delegatecall from the TroveManager contract\\n/// TroveManagerBase constructor param is bootsrap period when redemptions are not allowed\\ncontract TroveManagerRedeemOps is TroveManagerBase {\\n /** CONSTANT / IMMUTABLE VARIABLE ONLY */\\n IPermit2 public immutable permit2;\\n\\n /** Send _ZUSDamount ZUSD to the system and redeem the corresponding amount of collateral from as many Troves as are needed to fill the redemption\\n request. Applies pending rewards to a Trove before reducing its debt and coll.\\n \\n Note that if _amount is very large, this function can run out of gas, specially if traversed troves are small. This can be easily avoided by\\n splitting the total _amount in appropriate chunks and calling the function multiple times.\\n \\n Param `_maxIterations` can also be provided, so the loop through Troves is capped (if it\\u2019s zero, it will be ignored).This makes it easier to\\n avoid OOG for the frontend, as only knowing approximately the average cost of an iteration is enough, without needing to know the \\u201ctopology\\u201d\\n of the trove list. It also avoids the need to set the cap in stone in the contract, nor doing gas calculations, as both gas price and opcode\\n costs can vary.\\n \\n All Troves that are redeemed from -- with the likely exception of the last one -- will end up with no debt left, therefore they will be closed.\\n If the last Trove does have some remaining debt, it has a finite ICR, and the reinsertion could be anywhere in the list, therefore it requires a hint.\\n A frontend should use getRedemptionHints() to calculate what the ICR of this Trove will be after redemption, and pass a hint for its position\\n in the sortedTroves list along with the ICR value that the hint was found for.\\n \\n If another transaction modifies the list between calling getRedemptionHints() and passing the hints to redeemCollateral(), it\\n is very likely that the last (partially) redeemed Trove would end up with a different ICR than what the hint is for. In this case the\\n redemption will stop after the last completely redeemed Trove and the sender will keep the remaining ZUSD amount, which they can attempt\\n to redeem later.\\n */\\n\\n /** Constructor */\\n constructor(uint256 _bootstrapPeriod, address _permit2) public TroveManagerBase(_bootstrapPeriod) {\\n permit2 = IPermit2(_permit2);\\n }\\n\\n function redeemCollateral(\\n uint256 _ZUSDamount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage\\n ) external {\\n _redeemCollateral(\\n _ZUSDamount,\\n _firstRedemptionHint,\\n _upperPartialRedemptionHint,\\n _lowerPartialRedemptionHint,\\n _partialRedemptionHintNICR,\\n _maxIterations,\\n _maxFeePercentage\\n );\\n }\\n\\n function _redeemCollateral(\\n uint256 _ZUSDamount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage\\n ) internal {\\n ContractsCache memory contractsCache = ContractsCache(\\n activePool,\\n defaultPool,\\n _zusdToken,\\n _zeroStaking,\\n sortedTroves,\\n collSurplusPool,\\n gasPoolAddress\\n );\\n RedemptionTotals memory totals;\\n\\n _requireValidMaxFeePercentage(_maxFeePercentage);\\n _requireAfterBootstrapPeriod();\\n totals.price = priceFeed.fetchPrice();\\n _requireTCRoverMCR(totals.price);\\n _requireAmountGreaterThanZero(_ZUSDamount);\\n _requireZUSDBalanceCoversRedemption(contractsCache.zusdToken, msg.sender, _ZUSDamount);\\n\\n totals.totalZUSDSupplyAtStart = getEntireSystemDebt();\\n // Confirm redeemer's balance is less than total ZUSD supply\\n assert(contractsCache.zusdToken.balanceOf(msg.sender) <= totals.totalZUSDSupplyAtStart);\\n\\n totals.remainingZUSD = _ZUSDamount;\\n address currentBorrower;\\n\\n if (\\n _isValidFirstRedemptionHint(\\n contractsCache.sortedTroves,\\n _firstRedemptionHint,\\n totals.price\\n )\\n ) {\\n currentBorrower = _firstRedemptionHint;\\n } else {\\n currentBorrower = contractsCache.sortedTroves.getLast();\\n // Find the first trove with ICR >= MCR\\n while (\\n currentBorrower != address(0) &&\\n _getCurrentICR(currentBorrower, totals.price) < liquityBaseParams.MCR()\\n ) {\\n currentBorrower = contractsCache.sortedTroves.getPrev(currentBorrower);\\n }\\n }\\n\\n // Loop through the Troves starting from the one with lowest collateral ratio until _amount of ZUSD is exchanged for collateral\\n if (_maxIterations == 0) {\\n _maxIterations = uint256(-1);\\n }\\n while (currentBorrower != address(0) && totals.remainingZUSD > 0 && _maxIterations > 0) {\\n _maxIterations--;\\n // Save the address of the Trove preceding the current one, before potentially modifying the list\\n address nextUserToCheck = contractsCache.sortedTroves.getPrev(currentBorrower);\\n\\n _applyPendingRewards(\\n contractsCache.activePool,\\n contractsCache.defaultPool,\\n currentBorrower\\n );\\n\\n SingleRedemptionValues memory singleRedemption = _redeemCollateralFromTrove(\\n contractsCache,\\n currentBorrower,\\n totals.remainingZUSD,\\n totals.price,\\n _upperPartialRedemptionHint,\\n _lowerPartialRedemptionHint,\\n _partialRedemptionHintNICR\\n );\\n\\n if (singleRedemption.cancelledPartial) break; // Partial redemption was cancelled (out-of-date hint, or new net debt < minimum), therefore we could not redeem from the last Trove\\n\\n totals.totalZUSDToRedeem = totals.totalZUSDToRedeem.add(singleRedemption.ZUSDLot);\\n totals.totalETHDrawn = totals.totalETHDrawn.add(singleRedemption.ETHLot);\\n\\n totals.remainingZUSD = totals.remainingZUSD.sub(singleRedemption.ZUSDLot);\\n currentBorrower = nextUserToCheck;\\n }\\n require(totals.totalETHDrawn > 0, \\\"TroveManager: Unable to redeem any amount\\\");\\n\\n // Decay the baseRate due to time passed, and then increase it according to the size of this redemption.\\n // Use the saved total ZUSD supply value, from before it was reduced by the redemption.\\n _updateBaseRateFromRedemption(\\n totals.totalETHDrawn,\\n totals.price,\\n totals.totalZUSDSupplyAtStart\\n );\\n\\n // Calculate the ETH fee\\n totals.ETHFee = _getRedemptionFee(totals.totalETHDrawn);\\n\\n _requireUserAcceptsFee(totals.ETHFee, totals.totalETHDrawn, _maxFeePercentage);\\n\\n // Send the ETH fee to the feeDistributorContract address\\n contractsCache.activePool.sendETH(address(feeDistributor), totals.ETHFee);\\n feeDistributor.distributeFees();\\n\\n totals.ETHToSendToRedeemer = totals.totalETHDrawn.sub(totals.ETHFee);\\n\\n emit Redemption(\\n _ZUSDamount,\\n totals.totalZUSDToRedeem,\\n totals.totalETHDrawn,\\n totals.ETHFee\\n );\\n\\n // Burn the total ZUSD that is cancelled with debt, and send the redeemed ETH to msg.sender\\n contractsCache.zusdToken.burn(msg.sender, totals.totalZUSDToRedeem);\\n // Update Active Pool ZUSD, and send ETH to account\\n contractsCache.activePool.decreaseZUSDDebt(totals.totalZUSDToRedeem);\\n contractsCache.activePool.sendETH(msg.sender, totals.ETHToSendToRedeemer);\\n }\\n\\n ///DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\\n function redeemCollateralViaDLLR(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external {\\n uint256 _zusdAmount = MyntLib.redeemZusdFromDllrWithPermit(\\n IBorrowerOperations(borrowerOperationsAddress).getMassetManager(),\\n _dllrAmount,\\n address(_zusdToken),\\n _permitParams\\n );\\n _redeemCollateral(\\n _zusdAmount,\\n _firstRedemptionHint,\\n _upperPartialRedemptionHint,\\n _lowerPartialRedemptionHint,\\n _partialRedemptionHintNICR,\\n _maxIterations,\\n _maxFeePercentage\\n );\\n }\\n\\n ///DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\\n function redeemCollateralViaDllrWithPermit2(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external {\\n uint256 _zusdAmount = MyntLib.redeemZusdFromDllrWithPermit2(\\n IBorrowerOperations(borrowerOperationsAddress).getMassetManager(),\\n address(_zusdToken),\\n _permit,\\n permit2,\\n _signature\\n );\\n\\n _redeemCollateral(\\n _zusdAmount,\\n _firstRedemptionHint,\\n _upperPartialRedemptionHint,\\n _lowerPartialRedemptionHint,\\n _partialRedemptionHintNICR,\\n _maxIterations,\\n _maxFeePercentage\\n );\\n }\\n\\n function _isValidFirstRedemptionHint(\\n ISortedTroves _sortedTroves,\\n address _firstRedemptionHint,\\n uint256 _price\\n ) internal view returns (bool) {\\n if (\\n _firstRedemptionHint == address(0) ||\\n !_sortedTroves.contains(_firstRedemptionHint) ||\\n _getCurrentICR(_firstRedemptionHint, _price) < liquityBaseParams.MCR()\\n ) {\\n return false;\\n }\\n\\n address nextTrove = _sortedTroves.getNext(_firstRedemptionHint);\\n return\\n nextTrove == address(0) || _getCurrentICR(nextTrove, _price) < liquityBaseParams.MCR();\\n }\\n\\n /// Redeem as much collateral as possible from _borrower's Trove in exchange for ZUSD up to _maxZUSDamount\\n function _redeemCollateralFromTrove(\\n ContractsCache memory _contractsCache,\\n address _borrower,\\n uint256 _maxZUSDamount,\\n uint256 _price,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR\\n ) internal returns (SingleRedemptionValues memory singleRedemption) {\\n // Determine the remaining amount (lot) to be redeemed, capped by the entire debt of the Trove minus the liquidation reserve\\n singleRedemption.ZUSDLot = LiquityMath._min(\\n _maxZUSDamount,\\n Troves[_borrower].debt.sub(ZUSD_GAS_COMPENSATION)\\n );\\n\\n // Get the ETHLot of equivalent value in USD\\n singleRedemption.ETHLot = singleRedemption.ZUSDLot.mul(DECIMAL_PRECISION).div(_price);\\n\\n // Decrease the debt and collateral of the current Trove according to the ZUSD lot and corresponding ETH to send\\n uint256 newDebt = (Troves[_borrower].debt).sub(singleRedemption.ZUSDLot);\\n uint256 newColl = (Troves[_borrower].coll).sub(singleRedemption.ETHLot);\\n\\n if (newDebt == ZUSD_GAS_COMPENSATION) {\\n // No debt left in the Trove (except for the liquidation reserve), therefore the trove gets closed\\n _removeStake(_borrower);\\n _closeTrove(_borrower, Status.closedByRedemption);\\n _redeemCloseTrove(_contractsCache, _borrower, ZUSD_GAS_COMPENSATION, newColl);\\n emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.redeemCollateral);\\n } else {\\n uint256 newNICR = LiquityMath._computeNominalCR(newColl, newDebt);\\n\\n /*\\n * If the provided hint is out of date, we bail since trying to reinsert without a good hint will almost\\n * certainly result in running out of gas.\\n *\\n * If the resultant net debt of the partial is less than the minimum, net debt we bail.\\n */\\n if (newNICR != _partialRedemptionHintNICR || _getNetDebt(newDebt) < MIN_NET_DEBT) {\\n singleRedemption.cancelledPartial = true;\\n return singleRedemption;\\n }\\n\\n _contractsCache.sortedTroves.reInsert(\\n _borrower,\\n newNICR,\\n _upperPartialRedemptionHint,\\n _lowerPartialRedemptionHint\\n );\\n\\n Troves[_borrower].debt = newDebt;\\n Troves[_borrower].coll = newColl;\\n _updateStakeAndTotalStakes(_borrower);\\n\\n emit TroveUpdated(\\n _borrower,\\n newDebt,\\n newColl,\\n Troves[_borrower].stake,\\n TroveManagerOperation.redeemCollateral\\n );\\n }\\n\\n return singleRedemption;\\n }\\n\\n /**\\n This function has two impacts on the baseRate state variable:\\n 1) decays the baseRate based on time passed since last redemption or ZUSD borrowing operation.\\n then,\\n 2) increases the baseRate based on the amount redeemed, as a proportion of total supply\\n */\\n function _updateBaseRateFromRedemption(\\n uint256 _ETHDrawn,\\n uint256 _price,\\n uint256 _totalZUSDSupply\\n ) internal returns (uint256) {\\n uint256 decayedBaseRate = _calcDecayedBaseRate();\\n\\n /* Convert the drawn ETH back to ZUSD at face value rate (1 ZUSD:1 USD), in order to get\\n * the fraction of total supply that was redeemed at face value. */\\n uint256 redeemedZUSDFraction = _ETHDrawn.mul(_price).div(_totalZUSDSupply);\\n\\n uint256 newBaseRate = decayedBaseRate.add(redeemedZUSDFraction.div(BETA));\\n newBaseRate = LiquityMath._min(newBaseRate, DECIMAL_PRECISION); // cap baseRate at a maximum of 100%\\n //assert(newBaseRate <= DECIMAL_PRECISION); // This is already enforced in the line above\\n assert(newBaseRate > 0); // Base rate is always non-zero after redemption\\n\\n // Update the baseRate state variable\\n baseRate = newBaseRate;\\n emit BaseRateUpdated(newBaseRate);\\n\\n _updateLastFeeOpTime();\\n\\n return newBaseRate;\\n }\\n\\n /**\\n Called when a full redemption occurs, and closes the trove.\\n The redeemer swaps (debt - liquidation reserve) ZUSD for (debt - liquidation reserve) worth of ETH, so the ZUSD liquidation reserve left corresponds to the remaining debt.\\n In order to close the trove, the ZUSD liquidation reserve is burned, and the corresponding debt is removed from the active pool.\\n The debt recorded on the trove's struct is zero'd elswhere, in _closeTrove.\\n Any surplus ETH left in the trove, is sent to the Coll surplus pool, and can be later claimed by the borrower.\\n */\\n function _redeemCloseTrove(\\n ContractsCache memory _contractsCache,\\n address _borrower,\\n uint256 _ZUSD,\\n uint256 _ETH\\n ) internal {\\n _contractsCache.zusdToken.burn(gasPoolAddress, _ZUSD);\\n // Update Active Pool ZUSD, and send ETH to account\\n _contractsCache.activePool.decreaseZUSDDebt(_ZUSD);\\n\\n // send ETH from Active Pool to CollSurplus Pool\\n _contractsCache.collSurplusPool.accountSurplus(_borrower, _ETH);\\n _contractsCache.activePool.sendETH(address(_contractsCache.collSurplusPool), _ETH);\\n }\\n}\\n\",\"keccak256\":\"0xb88be6ccc4fb307fbbb8b599be53d96f1dc17c749effb9e97b88a030590101e3\",\"license\":\"MIT\"},\"contracts/Dependencies/console.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Buidler's helper contract for console logging\\nlibrary console {\\n\\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\\n\\n\\tfunction log() internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log()\\\"));\\n\\t\\tignored;\\n\\t}\\tfunction logInt(int p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(int)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logUint(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logString(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBool(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logAddress(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes(bytes memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logByte(byte p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(byte)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes1(bytes1 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes1)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes2(bytes2 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes2)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes3(bytes3 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes3)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes4(bytes4 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes4)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes5(bytes5 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes5)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes6(bytes6 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes6)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes7(bytes7 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes7)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes8(bytes8 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes8)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes9(bytes9 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes9)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes10(bytes10 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes10)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes11(bytes11 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes11)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes12(bytes12 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes12)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes13(bytes13 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes13)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes14(bytes14 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes14)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes15(bytes15 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes15)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes16(bytes16 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes16)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes17(bytes17 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes17)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes18(bytes18 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes18)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes19(bytes19 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes19)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes20(bytes20 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes20)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes21(bytes21 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes21)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes22(bytes22 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes22)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes23(bytes23 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes23)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes24(bytes24 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes24)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes25(bytes25 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes25)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes26(bytes26 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes26)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes27(bytes27 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes27)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes28(bytes28 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes28)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes29(bytes29 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes29)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes30(bytes30 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes30)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes31(bytes31 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes31)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes32(bytes32 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes32)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n}\\n\",\"keccak256\":\"0x6fa1de4ffe22b8f58b0b64d65db11dd5037be9b9db47b365a72adb489e217000\",\"license\":\"MIT\"},\"contracts/Interfaces/IActivePool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\n/**\\n * The Active Pool holds the ETH collateral and ZUSD debt (but not ZUSD tokens) for all active troves.\\n *\\n * When a trove is liquidated, it's ETH and ZUSD debt are transferred from the Active Pool, to either the\\n * Stability Pool, the Default Pool, or both, depending on the liquidation conditions.\\n *\\n */\\ninterface IActivePool is IPool {\\n // --- Events ---\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolZUSDDebtUpdated(uint _ZUSDDebt);\\n event ActivePoolETHBalanceUpdated(uint _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH amount to given account. Updates ActivePool balance. Only callable by BorrowerOperations, TroveManager or StabilityPool.\\n /// @param _account account to receive the ETH amount\\n /// @param _amount ETH amount to send\\n function sendETH(address _account, uint _amount) external;\\n}\\n\",\"keccak256\":\"0xdd5f1b6fae4050b4c885a85a10c2d0e73b82187a51736d009065aaeea33bf0d0\",\"license\":\"MIT\"},\"contracts/Interfaces/IAllowanceTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title AllowanceTransfer\\n/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface IAllowanceTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an ordered nonce.\\n event NonceInvalidation(\\n address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.\\n event Approval(\\n address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.\\n event Permit(\\n address indexed owner,\\n address indexed token,\\n address indexed spender,\\n uint160 amount,\\n uint48 expiration,\\n uint48 nonce\\n );\\n\\n /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.\\n event Lockdown(address indexed owner, address token, address spender);\\n\\n /// @notice The permit data for a token\\n struct PermitDetails {\\n // ERC20 token address\\n address token;\\n // the maximum amount allowed to spend\\n uint160 amount;\\n // timestamp at which a spender's token allowances become invalid\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice The permit message signed for a single token allowance\\n struct PermitSingle {\\n // the permit data for a single token alownce\\n PermitDetails details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The permit message signed for multiple token allowances\\n struct PermitBatch {\\n // the permit data for multiple token allowances\\n PermitDetails[] details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The saved permissions\\n /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n struct PackedAllowance {\\n // amount allowed\\n uint160 amount;\\n // permission expiry\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice A token spender pair.\\n struct TokenSpenderPair {\\n // the token the spender is approved\\n address token;\\n // the spender address\\n address spender;\\n }\\n\\n /// @notice Details for a token transfer.\\n struct AllowanceTransferDetails {\\n // the owner of the token\\n address from;\\n // the recipient of the token\\n address to;\\n // the amount of the token\\n uint160 amount;\\n // the token to be transferred\\n address token;\\n }\\n\\n /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.\\n /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]\\n /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.\\n function allowance(address user, address token, address spender)\\n external\\n view\\n returns (uint160 amount, uint48 expiration, uint48 nonce);\\n\\n /// @notice Approves the spender to use up to amount of the specified token up until the expiration\\n /// @param token The token to approve\\n /// @param spender The spender address to approve\\n /// @param amount The approved amount of the token\\n /// @param expiration The timestamp at which the approval is no longer valid\\n /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n function approve(address token, address spender, uint160 amount, uint48 expiration) external;\\n\\n /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitSingle Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;\\n\\n /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitBatch Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;\\n\\n /// @notice Transfer approved tokens from one address to another\\n /// @param from The address to transfer from\\n /// @param to The address of the recipient\\n /// @param amount The amount of the token to transfer\\n /// @param token The token address to transfer\\n /// @dev Requires the from address to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(address from, address to, uint160 amount, address token) external;\\n\\n /// @notice Transfer approved tokens in a batch\\n /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers\\n /// @dev Requires the from addresses to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;\\n\\n /// @notice Enables performing a \\\"lockdown\\\" of the sender's Permit2 identity\\n /// by batch revoking approvals\\n /// @param approvals Array of approvals to revoke.\\n function lockdown(TokenSpenderPair[] calldata approvals) external;\\n\\n /// @notice Invalidate nonces for a given (token, spender) pair\\n /// @param token The token to invalidate nonces for\\n /// @param spender The spender to invalidate nonces for\\n /// @param newNonce The new nonce to set. Invalidates all nonces less than it.\\n /// @dev Can't invalidate more than 2**16 nonces per transaction.\\n function invalidateNonces(address token, address spender, uint48 newNonce) external;\\n}\\n\",\"keccak256\":\"0xf15059fb68f89542908f963f22e18c0b0ae9997a6f9aaf6a9fb46aa2424acac9\",\"license\":\"MIT\"},\"contracts/Interfaces/IBorrowerOperations.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface IBorrowerOperations {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event TroveCreated(address indexed _borrower, uint256 arrayIndex);\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event ZUSDBorrowingFeePaid(address indexed _borrower, uint256 _ZUSDFee);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeDistributorAddress feeDistributor contract address\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _defaultPoolAddress DefaultPool contract address\\n * @param _stabilityPoolAddress StabilityPool contract address\\n * @param _gasPoolAddress GasPool contract address\\n * @param _collSurplusPoolAddress CollSurplusPool contract address\\n * @param _priceFeedAddress PrideFeed contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n address _feeDistributorAddress,\\n address _liquityBaseParamsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _defaultPoolAddress,\\n address _stabilityPoolAddress,\\n address _gasPoolAddress,\\n address _collSurplusPoolAddress,\\n address _priceFeedAddress,\\n address _sortedTrovesAddress,\\n address _zusdTokenAddress,\\n address _zeroStakingAddress\\n ) external;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice payable function that creates a Trove for the caller with the requested debt, and the Ether received as collateral.\\n * Successful execution is conditional mainly on the resulting collateralization ratio which must exceed the minimum (110% in Normal Mode, 150% in Recovery Mode).\\n * In addition to the requested debt, extra debt is issued to pay the issuance fee, and cover the gas compensation.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * This method is identical to `openTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _ZUSDAmount ZUSD requested debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function openNueTrove(\\n uint256 _maxFee,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /// @notice payable function that adds the received Ether to the caller's active Trove.\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function addColl(address _upperHint, address _lowerHint) external payable;\\n\\n /// @notice send ETH as collateral to a trove. Called by only the Stability Pool.\\n /// @param _user user trove address\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function moveETHGainToTrove(\\n address _user,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice withdraws `_amount` of collateral from the caller\\u2019s Trove.\\n * Executes only if the user has an active Trove, the withdrawal would not pull the user\\u2019s Trove below the minimum collateralization ratio,\\n * and the resulting total collateralization ratio of the system is above 150%.\\n * @param _amount collateral amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawColl(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice issues `_amount` of ZUSD from the caller\\u2019s Trove to the caller.\\n * Executes only if the Trove's collateralization ratio would remain above the minimum, and the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _amount ZUSD amount to withdraw\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawZUSD(\\n uint256 _maxFee,\\n uint256 _amount,\\n address _upperHint,\\n address _lowerHint\\n ) external;\\n\\n /// Borrow (withdraw) ZUSD tokens from a trove: mint new ZUSD tokens to the owner and convert it to DLLR in one transaction\\n function withdrawZusdAndConvertToDLLR(\\n uint256 _maxFeePercentage,\\n uint256 _ZUSDAmount,\\n address _upperHint,\\n address _lowerHint\\n ) external returns (uint256);\\n\\n /// @notice repay `_amount` of ZUSD to the caller\\u2019s Trove, subject to leaving 50 debt in the Trove (which corresponds to the 50 ZUSD gas compensation).\\n /// @param _amount ZUSD amount to repay\\n /// @param _upperHint upper trove id hint\\n /// @param _lowerHint lower trove id hint\\n function repayZUSD(uint256 _amount, address _upperHint, address _lowerHint) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLR(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n /// Repay ZUSD tokens to a Trove: Burn the repaid ZUSD tokens, and reduce the trove's debt accordingly\\n function repayZusdFromDLLRWithPermit2(\\n uint256 _dllrAmount,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a ZUSD balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` ZUSD.\\n */\\n function closeTrove() external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTrove(IMassetManager.PermitParams calldata _permitParams) external;\\n\\n /**\\n * @notice allows a borrower to repay all debt, withdraw all their collateral, and close their Trove.\\n * Requires the borrower have a NUE balance sufficient to repay their trove's debt, excluding gas compensation - i.e. `(debt - 50)` NUE.\\n * This method is identical to `closeTrove()`, but operates on NUE tokens instead of ZUSD.\\n */\\n function closeNueTroveWithPermit2(ISignatureTransfer.PermitTransferFrom memory _permit, bytes calldata _signature) external;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTrove(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external payable;\\n\\n /**\\n * @notice enables a borrower to simultaneously change both their collateral and debt, subject to all the restrictions that apply to individual increases/decreases of each quantity with the following particularity:\\n * if the adjustment reduces the collateralization ratio of the Trove, the function only executes if the resulting total collateralization ratio is above 150%.\\n * The borrower has to provide a `_maxFeePercentage` that he/she is willing to accept in case of a fee slippage, i.e. when a redemption transaction is processed first, driving up the issuance fee.\\n * The parameter is ignored if the debt is not increased with the transaction.\\n * This method is identical to `adjustTrove()`, but operates on NUE tokens instead of ZUSD.\\n * @param _maxFee max fee percentage to acept in case of a fee slippage\\n * @param _collWithdrawal collateral amount to withdraw\\n * @param _debtChange ZUSD amount to change\\n * @param isDebtIncrease indicates if increases debt\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function adjustNueTroveWithPermit2(\\n uint256 _maxFee,\\n uint256 _collWithdrawal,\\n uint256 _debtChange,\\n bool isDebtIncrease,\\n address _upperHint,\\n address _lowerHint,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external payable;\\n\\n /**\\n * @notice when a borrower\\u2019s Trove has been fully redeemed from and closed, or liquidated in Recovery Mode with a collateralization ratio above 110%,\\n * this function allows the borrower to claim their ETH collateral surplus that remains in the system (collateral - debt upon redemption; collateral - 110% of the debt upon liquidation).\\n */\\n function claimCollateral() external;\\n\\n function getCompositeDebt(uint256 _debt) external view returns (uint256);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint256);\\n\\n function getMassetManager() external view returns (IMassetManager);\\n}\\n\",\"keccak256\":\"0x75da117f4bc4cca15fc16ca0466c68894f1befed0471ea7a670fa9b466ef2bc5\",\"license\":\"MIT\"},\"contracts/Interfaces/ICollSurplusPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ICollSurplusPool {\\n // --- Events ---\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n\\n event CollBalanceUpdated(address indexed _account, uint256 _newBalance);\\n event EtherSent(address _to, uint256 _amount);\\n\\n // --- Contract setters ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH state variable\\n function getETH() external view returns (uint256);\\n\\n /// @param _account account to retrieve collateral\\n /// @return collateral\\n function getCollateral(address _account) external view returns (uint256);\\n\\n /// @notice adds amount to current account balance. Only callable by TroveManager.\\n /// @param _account account to add amount\\n /// @param _amount amount to add\\n function accountSurplus(address _account, uint256 _amount) external;\\n\\n /// @notice claims collateral for given account. Only callable by BorrowerOperations.\\n /// @param _account account to send claimable collateral\\n function claimColl(address _account) external;\\n}\\n\",\"keccak256\":\"0xac983936efe70d19205bff65a18b4e6000d489d4e4d1e2e92f951873cee91048\",\"license\":\"MIT\"},\"contracts/Interfaces/IDefaultPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\ninterface IDefaultPool is IPool {\\n // --- Events ---\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event DefaultPoolZUSDDebtUpdated(uint256 _ZUSDDebt);\\n event DefaultPoolETHBalanceUpdated(uint256 _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH to Active Pool\\n /// @param _amount ETH to send\\n function sendETHToActivePool(uint256 _amount) external;\\n}\\n\",\"keccak256\":\"0xfb2607676b2eb0f2defd248b4dd32895820048317f29aa6bdb572403a3e3d44e\",\"license\":\"MIT\"},\"contracts/Interfaces/IEIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\ninterface IEIP712 {\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xff52e9168eaa532ebacdad2ab6197f60171e3aa2fa2c1d6397d9da4d7782a543\",\"license\":\"MIT\"},\"contracts/Interfaces/IFeeDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/// Common interface for Fee Distributor.\\ninterface IFeeDistributor {\\n // --- Events ---\\n\\n event FeeSharingCollectorAddressChanged(address _feeSharingCollectorAddress);\\n event ZeroStakingAddressChanged(address _zeroStakingAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event WrbtcAddressChanged(address _wrbtcAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event ZUSDDistributed(uint256 _zusdDistributedAmount);\\n event RBTCistributed(uint256 _rbtcDistributedAmount);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeSharingCollectorAddress FeeSharingCollector address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n * @param _borrowerOperationsAddress borrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _wrbtcAddress wrbtc ERC20 contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _feeSharingCollectorAddress,\\n address _zeroStakingAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _wrbtcAddress,\\n address _zusdTokenAddress,\\n address _activePoolAddress\\n ) external;\\n\\n function distributeFees() external;\\n}\\n\",\"keccak256\":\"0x4b9bc6eaa8a9ea5e0570ffd84c0af2a92e74b001ae1ee1c8518d76382691a07f\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPriceFeed.sol\\\";\\nimport \\\"./ILiquityBaseParams.sol\\\";\\n\\ninterface ILiquityBase {\\n /// @return PriceFeed contract\\n function priceFeed() external view returns (IPriceFeed);\\n\\n /// @return LiquityBaseParams contract\\n function liquityBaseParams() external view returns (ILiquityBaseParams);\\n}\\n\",\"keccak256\":\"0xa4a57bd79e64d56a687c28d2a35c55b733fde8dda2a7ba861606eed3211724e1\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBaseParams.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ILiquityBaseParams {\\n\\n /// Minimum collateral ratio for individual troves\\n function MCR() external view returns (uint);\\n\\n /// Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.\\n function CCR() external view returns (uint);\\n\\n function PERCENT_DIVISOR() external view returns (uint);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint);\\n\\n /**\\n * Half-life of 12h. 12h = 720 min\\n * (1/2) = d^720 => d = (1/2)^(1/720)\\n */\\n function REDEMPTION_FEE_FLOOR() external view returns (uint);\\n\\n function MAX_BORROWING_FEE() external view returns (uint);\\n\\n}\",\"keccak256\":\"0xef8c0e8ad5d13d604c11b04983ff5bdd41768b646f2b33f45ddd988adec204e0\",\"license\":\"MIT\"},\"contracts/Interfaces/IPermit2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {ISignatureTransfer} from \\\"./ISignatureTransfer.sol\\\";\\nimport {IAllowanceTransfer} from \\\"./IAllowanceTransfer.sol\\\";\\n\\n/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer.\\n/// @dev Users must approve Permit2 before calling any of the transfer functions.\\ninterface IPermit2 is ISignatureTransfer, IAllowanceTransfer {\\n// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval.\\n}\\n\",\"keccak256\":\"0x3df819f5ca8de7324a676839d72e9f44c0f789c41c13bf0a892f3bb98d72ee86\",\"license\":\"MIT\"},\"contracts/Interfaces/IPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the Pools.\\ninterface IPool {\\n // --- Events ---\\n\\n event ETHBalanceUpdated(uint _newBalance);\\n event ZUSDBalanceUpdated(uint _newBalance);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event EtherSent(address _to, uint _amount);\\n\\n // --- Functions ---\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH pool balance\\n function getETH() external view returns (uint);\\n\\n /// @return ZUSD debt pool balance\\n function getZUSDDebt() external view returns (uint);\\n\\n /// @notice Increases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to add to the pool debt\\n function increaseZUSDDebt(uint _amount) external;\\n\\n /// @notice Decreases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to subtract to the pool debt\\n function decreaseZUSDDebt(uint _amount) external;\\n}\\n\",\"keccak256\":\"0x148e87ab38c6176d74f36c9e8989b99e768a7b18d8a045f1f01d6583b986806d\",\"license\":\"MIT\"},\"contracts/Interfaces/IPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IPriceFeed {\\n // --- Events ---\\n event LastGoodPriceUpdated(uint256 _lastGoodPrice);\\n\\n // --- Function ---\\n\\n /// @notice Returns the latest price obtained from the Oracle. Called by Zero functions that require a current price.\\n /// It uses the main price feed and fallback to the backup one in case of an error. If both fail return the last\\n /// good price seen.\\n /// @dev It's also callable by anyone externally\\n /// @return The price\\n function fetchPrice() external returns (uint256);\\n}\\n\",\"keccak256\":\"0x85fd97219a8156209d2cb5c6ae7c5ead01d893db000bf575023fcef0e62f9591\",\"license\":\"MIT\"},\"contracts/Interfaces/ISignatureTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title SignatureTransfer\\n/// @notice Handles ERC20 token transfers through signature based actions\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface ISignatureTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an unordered nonce.\\n event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);\\n\\n /// @notice The token and amount details for a transfer signed in the permit transfer signature\\n struct TokenPermissions {\\n // ERC20 token address\\n address token;\\n // the maximum amount that can be spent\\n uint256 amount;\\n }\\n\\n /// @notice The signed permit message for a single token transfer\\n struct PermitTransferFrom {\\n TokenPermissions permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice Specifies the recipient address and amount for batched transfers.\\n /// @dev Recipients and amounts correspond to the index of the signed token permissions array.\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount.\\n struct SignatureTransferDetails {\\n // recipient address\\n address to;\\n // spender requested amount\\n uint256 requestedAmount;\\n }\\n\\n /// @notice Used to reconstruct the signed permit message for multiple token transfers\\n /// @dev Do not need to pass in spender address as it is required that it is msg.sender\\n /// @dev Note that a user still signs over a spender address\\n struct PermitBatchTransferFrom {\\n // the tokens and corresponding amounts permitted for a transfer\\n TokenPermissions[] permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection\\n /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order\\n /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce\\n /// @dev It returns a uint256 bitmap\\n /// @dev The index, or wordPosition is capped at type(uint248).max\\n function nonceBitmap(address, uint256) external view returns (uint256);\\n\\n /// @notice Transfers a token using a signed permit message\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails The spender's requested transfer details for the permitted token\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitTransferFrom memory permit,\\n SignatureTransferDetails calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Transfers multiple tokens using a signed permit message\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails Specifies the recipient and requested amount for the token transfer\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitBatchTransferFrom memory permit,\\n SignatureTransferDetails[] calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Invalidates the bits specified in mask for the bitmap at the word position\\n /// @dev The wordPos is maxed at type(uint248).max\\n /// @param wordPos A number to index the nonceBitmap at\\n /// @param mask A bitmap masked against msg.sender's current bitmap at the word position\\n function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;\\n}\\n\",\"keccak256\":\"0x7efc63c119694e23dd76e44a5b125999829026bbc23409de7646a6a45e1ac341\",\"license\":\"MIT\"},\"contracts/Interfaces/ISortedTroves.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the SortedTroves Doubly Linked List.\\ninterface ISortedTroves {\\n // --- Events ---\\n\\n event SortedTrovesAddressChanged(address _sortedDoublyLLAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event NodeAdded(address _id, uint256 _NICR);\\n event NodeRemoved(address _id);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts and size. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _size max size of troves list\\n * @param _TroveManagerAddress TroveManager contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n */\\n function setParams(\\n uint256 _size,\\n address _TroveManagerAddress,\\n address _borrowerOperationsAddress\\n ) external;\\n\\n /**\\n * @dev Add a node to the list\\n * @param _id Node's id\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function insert(\\n address _id,\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Remove a node from the list\\n * @param _id Node's id\\n */\\n function remove(address _id) external;\\n\\n /**\\n * @dev Re-insert the node at a new position, based on its new NICR\\n * @param _id Node's id\\n * @param _newICR Node's new NICR\\n * @param _prevId Id of previous node for the new insert position\\n * @param _nextId Id of next node for the new insert position\\n */\\n function reInsert(\\n address _id,\\n uint256 _newICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Checks if the list contains a node\\n * @param _id Node's id\\n * @return true if list contains a node with given id\\n */\\n function contains(address _id) external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is full\\n * @return true if list is full\\n */\\n function isFull() external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is empty\\n * @return true if list is empty\\n */\\n function isEmpty() external view returns (bool);\\n\\n /**\\n * @return list current size\\n */\\n function getSize() external view returns (uint256);\\n\\n /**\\n * @return list max size\\n */\\n function getMaxSize() external view returns (uint256);\\n\\n /**\\n * @return the first node in the list (node with the largest NICR)\\n */\\n function getFirst() external view returns (address);\\n\\n /**\\n * @return the last node in the list (node with the smallest NICR)\\n */\\n function getLast() external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the next node (with a smaller NICR) in the list for a given node\\n */\\n function getNext(address _id) external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the previous node (with a larger NICR) in the list for a given node\\n */\\n function getPrev(address _id) external view returns (address);\\n\\n /**\\n * @notice Check if a pair of nodes is a valid insertion point for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function validInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (bool);\\n\\n /**\\n * @notice Find the insert position for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function findInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (address, address);\\n}\\n\",\"keccak256\":\"0x7328ad009da6230ddea1559564428464a5c3ace2258fb534dfbba5b5a8c7c60d\",\"license\":\"MIT\"},\"contracts/Interfaces/IStabilityPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/*\\n * The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors.\\n *\\n * When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with\\n * ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned.\\n *\\n * Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits.\\n * They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors,\\n * in the same proportion.\\n *\\n * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40%\\n * of the total ZUSD in the Stability Pool, depletes 40% of each deposit.\\n *\\n * A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit,\\n * multiplying it by some factor in range ]0,1[\\n *\\n * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations:\\n * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf\\n *\\n * --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS ---\\n *\\n * An SOV issuance event occurs at every deposit operation, and every liquidation.\\n *\\n * Each deposit is tagged with the address of the front end through which it was made.\\n *\\n * All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned\\n * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate.\\n *\\n * Please see the system Readme for an overview:\\n * https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers\\n */\\ninterface IStabilityPool {\\n // --- Events ---\\n\\n event StabilityPoolETHBalanceUpdated(uint _newBalance);\\n event StabilityPoolZUSDBalanceUpdated(uint _newBalance);\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event SortedTrovesAddressChanged(address _newSortedTrovesAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);\\n\\n event P_Updated(uint _P);\\n event S_Updated(uint _S, uint128 _epoch, uint128 _scale);\\n event G_Updated(uint _G, uint128 _epoch, uint128 _scale);\\n event EpochUpdated(uint128 _currentEpoch);\\n event ScaleUpdated(uint128 _currentScale);\\n\\n event FrontEndRegistered(address indexed _frontEnd, uint _kickbackRate);\\n event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd);\\n\\n event DepositSnapshotUpdated(address indexed _depositor, uint _P, uint _S, uint _G);\\n event FrontEndSnapshotUpdated(address indexed _frontEnd, uint _P, uint _G);\\n event UserDepositChanged(address indexed _depositor, uint _newDeposit);\\n event FrontEndStakeChanged(\\n address indexed _frontEnd,\\n uint _newFrontEndStake,\\n address _depositor\\n );\\n\\n event ETHGainWithdrawn(address indexed _depositor, uint _ETH, uint _ZUSDLoss);\\n event SOVPaidToDepositor(address indexed _depositor, uint _SOV);\\n event SOVPaidToFrontEnd(address indexed _frontEnd, uint _SOV);\\n event EtherSent(address _to, uint _amount);\\n\\n event WithdrawFromSpAndConvertToDLLR(\\n address _depositor,\\n uint256 _zusdAmountRequested,\\n uint256 _dllrAmountReceived\\n );\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Liquity contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _priceFeedAddress PriceFeed contract address\\n * @param _communityIssuanceAddress CommunityIssuanceAddress\\n */\\n function setAddresses(\\n address _liquityBaseParamsAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _zusdTokenAddress,\\n address _sortedTrovesAddress,\\n address _priceFeedAddress,\\n address _communityIssuanceAddress\\n ) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend is registered or zero address\\n * - Sender is not a registered frontend\\n * - _amount is not zero\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Tags the deposit with the provided front end tag param, if it's a new deposit\\n * - Sends depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Increases deposit and tagged front end's stake, and takes new snapshots for each.\\n * @param _amount amount to provide\\n * @param _frontEndTag frontend address to receive accumulated SOV gains\\n */\\n function provideToSP(uint _amount, address _frontEndTag) external;\\n\\n /**\\n * @notice Initial checks:\\n * - _amount is zero or there are no under collateralized troves left in the system\\n * - User has a non zero deposit\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Removes the deposit's front end tag if it is a full withdrawal\\n * - Sends all depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.\\n *\\n * If _amount > userDeposit, the user withdraws all of their compounded deposit.\\n * @param _amount amount to withdraw\\n */\\n function withdrawFromSP(uint _amount) external;\\n\\n /**\\n * @notice Initial checks:\\n * - User has a non zero deposit\\n * - User has an open trove\\n * - User has some ETH gain\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Sends all depositor's SOV gain to depositor\\n * - Sends all tagged front end's SOV gain to the tagged front end\\n * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove\\n * - Leaves their compounded deposit in the Stability Pool\\n * - Updates snapshots for deposit and tagged front end stake\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend (sender) not already registered\\n * - User (sender) has no deposit\\n * - _kickbackRate is in the range [0, 100%]\\n * ---\\n * Front end makes a one-time selection of kickback rate upon registering\\n * @param _kickbackRate kickback rate selected by frontend\\n */\\n function registerFrontEnd(uint _kickbackRate) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Caller is TroveManager\\n * ---\\n * Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible)\\n * and transfers the Trove's ETH collateral from ActivePool to StabilityPool.\\n * Only called by liquidation functions in the TroveManager.\\n * @param _debt debt to cancel\\n * @param _coll collateral to transfer\\n */\\n function offset(uint _debt, uint _coll) external;\\n\\n /**\\n * @return the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`,\\n * to exclude edge cases like ETH received from a self-destruct.\\n */\\n function getETH() external view returns (uint);\\n\\n /**\\n * @return ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\\n */\\n function getTotalZUSDDeposits() external view returns (uint);\\n\\n /**\\n * @notice Calculates the ETH gain earned by the deposit since its last snapshots were taken.\\n * @param _depositor address to calculate ETH gain\\n * @return ETH gain from given depositor\\n */\\n function getDepositorETHGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice Calculate the SOV gain earned by a deposit since its last snapshots were taken.\\n * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned.\\n * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through\\n * which they made their deposit.\\n * @param _depositor address to calculate ETH gain\\n * @return SOV gain from given depositor\\n */\\n function getDepositorSOVGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @param _frontEnd front end address\\n * @return the SOV gain earned by the front end.\\n */\\n function getFrontEndSOVGain(address _frontEnd) external view returns (uint);\\n\\n /**\\n * @param _depositor depositor address\\n * @return the user's compounded deposit.\\n */\\n function getCompoundedZUSDDeposit(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\\n * @param _frontEnd front end address\\n * @return the front end's compounded stake.\\n */\\n function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint);\\n\\n //DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDLLR(\\n uint _dllrAmount,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function provideToSpFromDllrWithPermit2(\\n uint256 _dllrAmount,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /// Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and optionally convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\\n function withdrawFromSpAndConvertToDLLR(uint256 _zusdAmount) external;\\n\\n /**\\n * Fallback function\\n * Only callable by Active Pool, it just accounts for ETH received\\n * receive() external payable;\\n */\\n}\\n\",\"keccak256\":\"0xb35c5ec991dd2b4f8ecb6b28ae29e97313fca6054aa0df14ebdb7336fcea84a6\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROStaking.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IZEROStaking {\\n // --- Events --\\n\\n event ZEROTokenAddressSet(address _zeroTokenAddress);\\n event ZUSDTokenAddressSet(address _zusdTokenAddress);\\n event FeeDistributorAddressAddressSet(address _feeDistributorAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event StakeChanged(address indexed staker, uint256 newStake);\\n event StakingGainsWithdrawn(address indexed staker, uint256 ZUSDGain, uint256 ETHGain);\\n event F_ETHUpdated(uint256 _F_ETH);\\n event F_ZUSDUpdated(uint256 _F_ZUSD);\\n event TotalZEROStakedUpdated(uint256 _totalZEROStaked);\\n event EtherSent(address _account, uint256 _amount);\\n event StakerSnapshotsUpdated(address _staker, uint256 _F_ETH, uint256 _F_ZUSD);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _zeroTokenAddress ZEROToken contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _feeDistributorAddress FeeDistributorAddress contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _zeroTokenAddress,\\n address _zusdTokenAddress,\\n address _feeDistributorAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice If caller has a pre-existing stake, send any accumulated ETH and ZUSD gains to them.\\n /// @param _ZEROamount ZERO tokens to stake\\n function stake(uint256 _ZEROamount) external;\\n\\n /**\\n * @notice Unstake the ZERO and send the it back to the caller, along with their accumulated ZUSD & ETH gains.\\n * If requested amount > stake, send their entire stake.\\n * @param _ZEROamount ZERO tokens to unstake\\n */\\n function unstake(uint256 _ZEROamount) external;\\n\\n /// @param _ETHFee ETH fee\\n /// @notice increase ETH fee\\n function increaseF_ETH(uint256 _ETHFee) external;\\n\\n /// @param _ZEROFee ZUSD fee\\n /// @notice increase ZUSD fee\\n function increaseF_ZUSD(uint256 _ZEROFee) external;\\n\\n /// @param _user user address\\n /// @return pending ETH gain of given user\\n function getPendingETHGain(address _user) external view returns (uint256);\\n\\n /// @param _user user address\\n /// @return pending ZUSD gain of given user\\n function getPendingZUSDGain(address _user) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x4c7948ce7dff9ea9b8495054e511eabcf44a91c7db8520ec58ff2a002327e0c5\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZEROToken is IERC20, IERC2612 { \\n\\n // --- Functions ---\\n\\n /// @notice send zero tokens to ZEROStaking contract\\n /// @param _sender sender address\\n /// @param _amount amount to send\\n function sendToZEROStaking(address _sender, uint256 _amount) external;\\n\\n /// @return deployment start time\\n function getDeploymentStartTime() external view returns (uint256);\\n\\n}\\n\",\"keccak256\":\"0xbcc0baabe4c4686563a09cf1486f2d152b70404996676a89d525691f69637f66\",\"license\":\"MIT\"},\"contracts/Interfaces/IZUSDToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZUSDToken is IERC20, IERC2612 { \\n \\n // --- Events ---\\n\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n\\n event ZUSDTokenBalanceUpdated(address _user, uint _amount);\\n\\n // --- Functions ---\\n\\n function mint(address _account, uint256 _amount) external;\\n\\n function burn(address _account, uint256 _amount) external;\\n\\n function sendToPool(address _sender, address poolAddress, uint256 _amount) external;\\n\\n function returnFromPool(address poolAddress, address user, uint256 _amount ) external;\\n}\\n\",\"keccak256\":\"0xe52df063aa08f709640c28888edd27310c820f6d08564855538ae245eb2f5a8c\",\"license\":\"MIT\"},\"contracts/TroveManagerStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./Interfaces/IStabilityPool.sol\\\";\\nimport \\\"./Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/IZEROToken.sol\\\";\\nimport \\\"./Interfaces/IZEROStaking.sol\\\";\\nimport \\\"./Interfaces/IFeeDistributor.sol\\\";\\nimport \\\"./Dependencies/Ownable.sol\\\";\\nimport \\\"./Dependencies/BaseMath.sol\\\";\\nimport \\\"./Dependencies/console.sol\\\";\\n\\ncontract TroveManagerStorage is Ownable, BaseMath {\\n string public constant NAME = \\\"TroveManager\\\";\\n\\n // --- Connected contract declarations ---\\n\\n address public troveManagerRedeemOps;\\n\\n address public borrowerOperationsAddress;\\n\\n IStabilityPool public _stabilityPool;\\n\\n address gasPoolAddress;\\n\\n ICollSurplusPool collSurplusPool;\\n\\n IZUSDToken public _zusdToken;\\n\\n IZEROToken public _zeroToken;\\n\\n IZEROStaking public _zeroStaking;\\n\\n IFeeDistributor public feeDistributor;\\n\\n // A doubly linked list of Troves, sorted by their sorted by their collateral ratios\\n ISortedTroves public sortedTroves;\\n\\n // --- Data structures ---\\n\\n uint256 public baseRate;\\n\\n // The timestamp of the latest fee operation (redemption or new ZUSD issuance)\\n uint256 public lastFeeOperationTime;\\n\\n enum Status {\\n nonExistent,\\n active,\\n closedByOwner,\\n closedByLiquidation,\\n closedByRedemption\\n }\\n\\n // Store the necessary data for a trove\\n struct Trove {\\n uint256 debt;\\n uint256 coll;\\n uint256 stake;\\n Status status;\\n uint128 arrayIndex;\\n }\\n\\n mapping(address => Trove) public Troves;\\n\\n uint256 public totalStakes;\\n\\n // Snapshot of the value of totalStakes, taken immediately after the latest liquidation\\n uint256 public totalStakesSnapshot;\\n\\n // Snapshot of the total collateral across the ActivePool and DefaultPool, immediately after the latest liquidation.\\n uint256 public totalCollateralSnapshot;\\n\\n /*\\n * L_ETH and L_ZUSDDebt track the sums of accumulated liquidation rewards per unit staked. During its lifetime, each stake earns:\\n *\\n * An ETH gain of ( stake * [L_ETH - L_ETH(0)] )\\n * A ZUSDDebt increase of ( stake * [L_ZUSDDebt - L_ZUSDDebt(0)] )\\n *\\n * Where L_ETH(0) and L_ZUSDDebt(0) are snapshots of L_ETH and L_ZUSDDebt for the active Trove taken at the instant the stake was made\\n */\\n uint256 public L_ETH;\\n uint256 public L_ZUSDDebt;\\n\\n // Map addresses with active troves to their RewardSnapshot\\n mapping(address => RewardSnapshot) public rewardSnapshots;\\n\\n // Object containing the ETH and ZUSD snapshots for a given active trove\\n struct RewardSnapshot {\\n uint256 ETH;\\n uint256 ZUSDDebt;\\n }\\n\\n // Array of all active trove addresses - used to to compute an approximate hint off-chain, for the sorted list insertion\\n address[] public TroveOwners;\\n\\n // Error trackers for the trove redistribution calculation\\n uint256 public lastETHError_Redistribution;\\n uint256 public lastZUSDDebtError_Redistribution;\\n}\\n\",\"keccak256\":\"0x979836e7db9988074cd7cbbaaa94d67a297a078a8f93ceb14430ffe548545145\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60c06040523480156200001157600080fd5b5060405162003dfe38038062003dfe833981016040819052620000349162000128565b8162000049336001600160e01b036200006316565b60805260601b6001600160601b03191660a05250620001c4565b6001600160a01b038116620000955760405162461bcd60e51b81526004016200008c9062000182565b60405180910390fd5b6001600160a01b038116620000b26001600160e01b036200010716565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f79062000165565b6040519081900390209190915550565b600080604051620001189062000165565b6040519081900390205492915050565b600080604083850312156200013b578182fd5b825160208401519092506001600160a01b03811681146200015a578182fd5b809150509250929050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160a05160601c613c09620001f56000398061059f5280610b08525080610bdc5280611d565250613c096000f3fe608060405234801561001057600080fd5b506004361061028a5760003560e01c8063797250e31161015c578063a3f4df7e116100ce578063bf9befb111610087578063bf9befb114610486578063c35bc5501461048e578063c7b5548114610496578063d380a37c1461049e578063d815e8e9146104a6578063e056e918146104ae5761028a565b8063a3f4df7e1461043e578063ae7bec1914610453578063ae9187541461045b578063b7f8cf9b14610463578063bcd375261461046b578063be4b03341461047e5761028a565b8063893d20e811610120578063893d20e81461040b57806396d711ff146104135780639708daf41461041b5780639dd233d21461042e5780639f07067014610436578063a20baee6146103b05761028a565b8063797250e3146103e35780637cf54e40146103eb5780637f7dde4a146103f3578063807d138d146103fb578063887105d3146104035761028a565b80633cc7422511610200578063716c47e6116101b9578063716c47e6146103a857806372fe25aa146103b0578063741bef1a146103b8578063756b253e146103c0578063759b3034146103d3578063795d26c3146103db5761028a565b80633cc742251461034657806342ccf1e41461034e5780634a767d681461036157806361ec893d146103745780636b4449521461037c5780636ef64338146103845761028a565b80631673c79a116102525780631673c79a146102f25780631a59a50e146103135780631bf43555146103265780631f68f20a1461032e57806331c903b0146103365780633a1285951461033e5761028a565b806305b6f5ca1461028f578063071a7541146102a45780630d43e8ad146102c257806312261ee7146102d757806313af4035146102df575b600080fd5b6102a261029d3660046132d7565b6104ce565b005b6102ac610589565b6040516102b99190613b05565b60405180910390f35b6102ca61058e565b6040516102b991906134cd565b6102ca61059d565b6102a26102ed3660046131b7565b6105c1565b6103056103003660046131b7565b61060e565b6040516102b9929190613b0e565b6102ac6103213660046131b7565b610627565b6102ac6106ef565b6102ac6106fc565b6102ac610702565b6102ca610714565b6102ca610723565b6102ac61035c3660046131b7565b610732565b6102ac61036f3660046131ef565b610763565b6102ac61078e565b6102ac610793565b6103976103923660046131b7565b610799565b6040516102b9959493929190613b1c565b6102ca6107d3565b6102ac6107e2565b6102ca6107ee565b6102ca6103ce36600461323a565b6107fd565b6102ac610824565b6102ac610831565b6102ac610950565b6102ca610956565b6102ca610965565b6102ac610974565b6102ac61097a565b6102ca610a49565b6102ac610a68565b6102a2610429366004613361565b610a6e565b6102ac610b4c565b6102ca610b52565b610446610b61565b6040516102b991906135e4565b6102ca610b89565b6102ca610b98565b6102ca610ba7565b6102a261047936600461326a565b610bb6565b6102ac610bce565b6102ac610bd4565b6102ac610bda565b6102ac610bfe565b6102ac610c0a565b6102ca610c10565b6104c16104bc3660046131b7565b610c1f565b6040516102b991906135ab565b600061056d600560009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561052157600080fd5b505afa158015610535573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055991906131d3565b6009548b906001600160a01b031685610c7d565b905061057e81898989898989610f2e565b505050505050505050565b600281565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6105c9610a49565b6001600160a01b0316336001600160a01b0316146106025760405162461bcd60e51b81526004016105f99061389f565b60405180910390fd5b61060b816116f5565b50565b6016602052600090815260409020805460019091015482565b6001600160a01b0381166000908152601660205260408120546014548290610655908363ffffffff61178016565b905080158061068e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561068b57fe5b14155b1561069e576000925050506106ea565b6001600160a01b038416600090815260106020526040812060020154906106e3670de0b6b3a76400006106d7848663ffffffff6117c916565b9063ffffffff61180316565b9450505050505b919050565b6809c2007651b250000081565b600e5481565b600061070f600e54611845565b905090565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290610655908363ffffffff61178016565b6000806000610771856118ee565b915091506000610782838387611974565b93505050505b92915050565b603c81565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b670de0b6b3a764000081565b6002546001600160a01b031681565b6017818154811061080a57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b15801561087557600080fd5b505afa158015610889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ad9190613252565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ff57600080fd5b505afa158015610913573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109379190613252565b9050610949828263ffffffff6119a616565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156109bf57600080fd5b505afa1580156109d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f79190613252565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ff57600080fd5b600080604051610a58906134b0565b6040519081900390205492915050565b60135481565b6000610b2e600560009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b158015610ac157600080fd5b505afa158015610ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af991906131d3565b6009546001600160a01b0316867f000000000000000000000000000000000000000000000000000000000000000087876119cb565b9050610b3f818b8b8b8b8b8b610f2e565b5050505050505050505050565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b6005546001600160a01b031681565b610bc587878787878787610f2e565b50505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b670ddd4b8c6c7d70d881565b600f5481565b6009546001600160a01b031681565b600060016001600160a01b03831660009081526010602052604090206003015460ff166004811115610c4d57fe5b14610c5a575060006106ea565b506014546001600160a01b03821660009081526016602052604090205410919050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015610cb957600080fd5b505afa158015610ccd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf191906131d3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610d2191906134cd565b60206040518083038186803b158015610d3957600080fd5b505afa158015610d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d719190613252565b9050306001600160a01b03831663605629d633838a8935610d9860408c0160208d01613477565b8b604001358c606001356040518863ffffffff1660e01b8152600401610dc497969594939291906134e1565b600060405180830381600087803b158015610dde57600080fd5b505af1158015610df2573d6000803e3d6000fd5b5050505086610e8383856001600160a01b03166370a08231856040518263ffffffff1660e01b8152600401610e2791906134cd565b60206040518083038186803b158015610e3f57600080fd5b505afa158015610e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e779190613252565b9063ffffffff61178016565b14610ea05760405162461bcd60e51b81526004016105f9906136ab565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390610ed09089908b90339060040161355d565b602060405180830381600087803b158015610eea57600080fd5b505af1158015610efe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f229190613252565b98975050505050505050565b610f366130b5565b506040805160e0810182526000546001600160a01b03908116825260015481166020830152600954811692820192909252600b5482166060820152600d5482166080820152600854821660a082015260075490911660c0820152610f986130f1565b610fa183611c18565b610fa9611cd1565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610ff957600080fd5b505af115801561100d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110319190613252565b60c0820181905261104190611d9f565b61104a89611e4c565b6110598260400151338b611e6c565b611061610831565b60e0820181905260408084015190516370a0823160e01b81526001600160a01b03909116906370a082319061109a9033906004016134cd565b60206040518083038186803b1580156110b257600080fd5b505afa1580156110c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ea9190613252565b11156110f257fe5b888152608082015160c082015160009161110d918b90611f0d565b156111195750876112c6565b82608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561115657600080fd5b505afa15801561116a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118e91906131d3565b90505b6001600160a01b0381161580159061123a5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156111f257600080fd5b505afa158015611206573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122a9190613252565b611238828460c00151610763565b105b156112c65782608001516001600160a01b031663b72703ac826040518263ffffffff1660e01b815260040161126f91906134cd565b60206040518083038186803b15801561128757600080fd5b505afa15801561129b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bf91906131d3565b9050611191565b846112d15760001994505b6001600160a01b038116158015906112e95750815115155b80156112f55750600085115b15611423576080830151604051632dc9c0eb60e21b8152600019909601956000916001600160a01b03169063b72703ac906113349085906004016134cd565b60206040518083038186803b15801561134c57600080fd5b505afa158015611360573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138491906131d3565b90506113998460000151856020015184612170565b6113a1613136565b6113b8858486600001518760c001518e8e8e612281565b90508060400151156113cb575050611423565b805160208501516113e19163ffffffff6119a616565b60208086019190915281015160408501516114019163ffffffff6119a616565b6040850152805184516114199163ffffffff61178016565b84525090506112d1565b60008260400151116114475760405162461bcd60e51b81526004016105f9906136f4565b61145e82604001518360c001518460e001516124f5565b5061146c82604001516125ac565b6060830181905260408301516114839190866125bf565b8251600c5460608401516040516364a197f360e01b81526001600160a01b03938416936364a197f3936114bb93911691600401613522565b600060405180830381600087803b1580156114d557600080fd5b505af11580156114e9573d6000803e3d6000fd5b50505050600c60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561153d57600080fd5b505af1158015611551573d6000803e3d6000fd5b505050506060820151604083015161156891611780565b60808301526020820151604080840151606085015191517f43a3f4082a4dbc33d78e317d2497d3a730bc7fc3574159dcea1056e62e5d9ad8936115ae938f939192613b5c565b60405180910390a182604001516001600160a01b0316639dc29fac3384602001516040518363ffffffff1660e01b81526004016115ec929190613522565b600060405180830381600087803b15801561160657600080fd5b505af115801561161a573d6000803e3d6000fd5b50508451602085015160405163121cbc4d60e11b81526001600160a01b039092169350632439789a925061165091600401613b05565b600060405180830381600087803b15801561166a57600080fd5b505af115801561167e573d6000803e3d6000fd5b5050845160808501516040516364a197f360e01b81526001600160a01b0390921693506364a197f392506116b791339190600401613522565b600060405180830381600087803b1580156116d157600080fd5b505af11580156116e5573d6000803e3d6000fd5b5050505050505050505050505050565b6001600160a01b03811661171b5760405162461bcd60e51b81526004016105f990613774565b806001600160a01b031661172d610a49565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611770906134b0565b6040519081900390209190915550565b60006117c283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612605565b9392505050565b6000826117d857506000610788565b828202828482816117e557fe5b04146117c25760405162461bcd60e51b81526004016105f99061385e565b60006117c283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612631565b60006107886118e083600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561189c57600080fd5b505afa1580156118b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d49190613252565b9063ffffffff6119a616565b670de0b6b3a7640000612668565b60008060006118fc84610627565b9050600061190985610732565b6001600160a01b03861660009081526010602052604081206001015491925090611939908463ffffffff6119a616565b6001600160a01b03871660009081526010602052604081205491925090611966908463ffffffff6119a616565b919550909350505050915091565b6000821561199b576000611992846106d7878663ffffffff6117c916565b91506117c29050565b506000199392505050565b6000828201838110156117c25760405162461bcd60e51b81526004016105f99061373d565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015611a0757600080fd5b505afa158015611a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3f91906131d3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611a6f91906134cd565b60206040518083038186803b158015611a8757600080fd5b505afa158015611a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abf9190613252565b87516020015190915030906001600160a01b0388166330f28b7a8a611ae4858561267e565b338b8b6040518663ffffffff1660e01b8152600401611b07959493929190613a94565b600060405180830381600087803b158015611b2157600080fd5b505af1158015611b35573d6000803e3d6000fd5b5050505080611b6a84866001600160a01b03166370a08231866040518263ffffffff1660e01b8152600401610e2791906134cd565b14611b875760405162461bcd60e51b81526004016105f9906136ab565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390611bb7908d908590339060040161355d565b602060405180830381600087803b158015611bd157600080fd5b505af1158015611be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c099190613252565b9b9a5050505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c6657600080fd5b505afa158015611c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9e9190613252565b8110158015611cb55750670de0b6b3a76400008111155b61060b5760405162461bcd60e51b81526004016105f990613974565b600a5460408051631e425be160e11b815290516000926001600160a01b031691633c84b7c2916004808301926020929190829003018186803b158015611d1657600080fd5b505afa158015611d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d4e9190613252565b9050611d80817f000000000000000000000000000000000000000000000000000000000000000063ffffffff6119a616565b42101561060b5760405162461bcd60e51b81526004016105f990613800565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015611ded57600080fd5b505afa158015611e01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e259190613252565b611e2e826126b0565b101561060b5760405162461bcd60e51b81526004016105f9906139c4565b6000811161060b5760405162461bcd60e51b81526004016105f9906138d0565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190611e9a9086906004016134cd565b60206040518083038186803b158015611eb257600080fd5b505afa158015611ec6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eea9190613252565b1015611f085760405162461bcd60e51b81526004016105f990613637565b505050565b60006001600160a01b0383161580611f9e5750604051630bb7c8fd60e31b81526001600160a01b03851690635dbe47e890611f4c9086906004016134cd565b60206040518083038186803b158015611f6457600080fd5b505afa158015611f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9c919061321a565b155b806120365750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015611ff257600080fd5b505afa158015612006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202a9190613252565b6120348484610763565b105b15612043575060006117c2565b60405163765e015960e01b81526000906001600160a01b0386169063765e0159906120729087906004016134cd565b60206040518083038186803b15801561208a57600080fd5b505afa15801561209e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c291906131d3565b90506001600160a01b03811615806121675750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561212357600080fd5b505afa158015612137573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215b9190613252565b6121658285610763565b105b95945050505050565b61217981610c1f565b15611f0857612187816126dc565b600061219282610627565b9050600061219f83610732565b6001600160a01b0384166000908152601060205260409020600101549091506121ce908363ffffffff6119a616565b6001600160a01b03841660009081526010602052604090206001810191909155546121ff908263ffffffff6119a616565b6001600160a01b03841660009081526010602052604090205561222183612725565b61222d8585838561278d565b6001600160a01b038316600081815260106020526040808220805460018201546002909201549251600080516020613bb48339815191529461227294929392916135b6565b60405180910390a25050505050565b612289613136565b6001600160a01b0387166000908152601060205260409020546122c69087906122c1906801158e460913d0000063ffffffff61178016565b612668565b8082526122e79086906106d790670de0b6b3a764000063ffffffff6117c916565b60208083019190915281516001600160a01b03891660009081526010909252604082205461231a9163ffffffff61178016565b6020808401516001600160a01b038b1660009081526010909252604082206001015492935090916123509163ffffffff61178016565b90506801158e460913d000008214156123c95761236c896128ad565b6123778960046128fd565b61238c8a8a6801158e460913d0000084612a09565b886001600160a01b0316600080516020613bb4833981519152600080600060036040516123bc94939291906135b6565b60405180910390a26124e7565b60006123d58284612b6c565b905084811415806123f657506809c2007651b25000006123f484612ba1565b105b1561240a57505060016040830152506124ea565b8a608001516001600160a01b0316632be212608b838a8a6040518563ffffffff1660e01b81526004016124409493929190613580565b600060405180830381600087803b15801561245a57600080fd5b505af115801561246e573d6000803e3d6000fd5b5050506001600160a01b038b1660009081526010602052604090208481556001018390555061249c8a612bbc565b506001600160a01b038a1660008181526010602052604090819020600201549051600080516020613bb4833981519152916124dd91879187916003906135b6565b60405180910390a2505b50505b979650505050505050565b600080612500612c63565b90506000612518846106d7888863ffffffff6117c916565b9050600061253d61253083600263ffffffff61180316565b849063ffffffff6119a616565b905061255181670de0b6b3a7640000612668565b90506000811161255d57fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c90612592908390613b05565b60405180910390a16125a2612ca7565b9695505050505050565b60006107886125b9610702565b83612cfc565b60006125dd836106d786670de0b6b3a764000063ffffffff6117c916565b9050818111156125ff5760405162461bcd60e51b81526004016105f990613a0e565b50505050565b600081848411156126295760405162461bcd60e51b81526004016105f991906135e4565b505050900390565b600081836126525760405162461bcd60e51b81526004016105f991906135e4565b50600083858161265e57fe5b0495945050505050565b600081831061267757816117c2565b5090919050565b612686613159565b61268e613159565b5050604080518082019091526001600160a01b03929092168252602082015290565b6000806126bb61097a565b905060006126c7610831565b90506126d4828286611974565b949350505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561270857fe5b1461060b5760405162461bcd60e51b81526004016105f990613a45565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92612782929091613b0e565b60405180910390a150565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a906127b9908590600401613b05565b600060405180830381600087803b1580156127d357600080fd5b505af11580156127e7573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150612817908590600401613b05565b600060405180830381600087803b15801561283157600080fd5b505af1158015612845573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150612875908490600401613b05565b600060405180830381600087803b15801561288f57600080fd5b505af11580156128a3573d6000803e3d6000fd5b5050505050505050565b6001600160a01b0381166000908152601060205260409020600201546011546128dc908263ffffffff61178016565b601155506001600160a01b0316600090815260106020526040812060020155565b600081600481111561290b57fe5b141580156129255750600181600481111561292257fe5b14155b61292b57fe5b60175461293781612d3c565b6001600160a01b0383166000908152601060205260409020600301805483919060ff1916600183600481111561296957fe5b02179055506001600160a01b03831660009081526010602090815260408083206001808201859055908490556016909252822082815501556129ab8382612de2565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e906129db9086906004016134cd565b600060405180830381600087803b1580156129f557600080fd5b505af1158015610bc5573d6000803e3d6000fd5b6040808501516007549151632770a7eb60e21b81526001600160a01b0391821692639dc29fac92612a41929116908690600401613522565b600060405180830381600087803b158015612a5b57600080fd5b505af1158015612a6f573d6000803e3d6000fd5b5050855160405163121cbc4d60e11b81526001600160a01b039091169250632439789a9150612aa2908590600401613b05565b600060405180830381600087803b158015612abc57600080fd5b505af1158015612ad0573d6000803e3d6000fd5b505050508360a001516001600160a01b0316633f10abab84836040518363ffffffff1660e01b8152600401612b06929190613522565b600060405180830381600087803b158015612b2057600080fd5b505af1158015612b34573d6000803e3d6000fd5b5050855160a08701516040516364a197f360e01b81526001600160a01b0390921693506364a197f39250612875918590600401613522565b60008115612b9857612b91826106d78568056bc75e2d6310000063ffffffff6117c916565b9050610788565b50600019610788565b6000610788826801158e460913d0000063ffffffff61178016565b6001600160a01b0381166000908152601060205260408120600101548190612be390612f83565b6001600160a01b038416600090815260106020526040902060020180549082905560115491925090612c219083906118d4908463ffffffff61178016565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae52038291612c5491613b05565b60405180910390a15092915050565b600080612c6e612fbf565b90506000612c84670ddd4b8c6c7d70d883612fdb565b9050610949670de0b6b3a76400006106d783600e546117c990919063ffffffff16565b6000612cbe600f544261178090919063ffffffff16565b9050603c811061060b5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc9161278291613b05565b600080612d1b670de0b6b3a76400006106d7868663ffffffff6117c916565b90508281106117c25760405162461bcd60e51b81526004016105f99061391e565b600181118015612dc65750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b158015612d8c57600080fd5b505afa158015612da0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc49190613252565b115b61060b5760405162461bcd60e51b81526004016105f9906137b6565b6001600160a01b03821660009081526010602052604081206003015460ff1690816004811115612e0e57fe5b14158015612e2857506001816004811115612e2557fe5b14155b612e2e57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b0316908390612e66826001611780565b905080836001600160801b03161115612e7b57fe5b600060178281548110612e8a57fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b038716908110612ebc57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a90612f45908390879061353b565b60405180910390a16017805480612f5857fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b60008060135460001415612f98575081610788565b600060125411612fa457fe5b6117c26013546106d7601254866117c990919063ffffffff16565b600061070f603c6106d7600f544261178090919063ffffffff16565b6000631f540500821115612ff157631f54050091505b816130055750670de0b6b3a7640000610788565b670de0b6b3a764000083835b600181111561307c57600281066130465761302c8283613082565b915061303f81600263ffffffff61180316565b9050613077565b6130508284613082565b925061305c8283613082565b915061307460026106d783600163ffffffff61178016565b90505b613011565b61078282845b600080613095848463ffffffff6117c916565b90506126d4670de0b6b3a76400006106d7836706f05b59d3b200006119a6565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806060016040528060008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b60008083601f840112613181578182fd5b50813567ffffffffffffffff811115613198578182fd5b6020830191508360208285010111156131b057600080fd5b9250929050565b6000602082840312156131c8578081fd5b81356117c281613b9e565b6000602082840312156131e4578081fd5b81516117c281613b9e565b60008060408385031215613201578081fd5b823561320c81613b9e565b946020939093013593505050565b60006020828403121561322b578081fd5b815180151581146117c2578182fd5b60006020828403121561324b578081fd5b5035919050565b600060208284031215613263578081fd5b5051919050565b600080600080600080600060e0888a031215613284578283fd5b87359650602088013561329681613b9e565b955060408801356132a681613b9e565b945060608801356132b681613b9e565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a036101608112156132f4578182fd5b8935985060208a013561330681613b9e565b975060408a013561331681613b9e565b965060608a013561332681613b9e565b955060808a810135955060a08b0135945060c08b0135935060df198201121561334d578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c03610180811215613381578283fd5b8b359a5060208c013561339381613b9e565b995060408c01356133a381613b9e565b985060608c01356133b381613b9e565b975060808c810135975060a08d0135965060c08d0135955060df198201908112156133dc578384fd5b6133e66060613b77565b915060408112156133f5578384fd5b506134006040613b77565b60e08d013561340e81613b9e565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff811115613453578283fd5b61345f8d828e01613170565b8194508093505050509295989b9194979a5092959850565b600060208284031215613488578081fd5b813560ff811681146117c2578182fd5b80516001600160a01b03168252602090810151910152565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b901515815260200190565b848152602081018490526040810183905260808101600483106135d557fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015613610578581018301518582016040015282016135f4565b818111156136215783604083870101525b50601f01601f1916929092016040019392505050565b6020808252604e908201527f54726f76654d616e616765723a2052657175657374656420726564656d70746960408201527f6f6e20616d6f756e74206d757374206265203c3d20757365722773205a55534460608201526d20746f6b656e2062616c616e636560901b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b60208082526029908201527f54726f76654d616e616765723a20556e61626c6520746f2072656465656d20616040820152681b9e48185b5bdd5b9d60ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b602080825260409082018190527f54726f76654d616e616765723a20526564656d7074696f6e7320617265206e6f908201527f7420616c6c6f77656420647572696e6720626f6f747374726170207068617365606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252602e908201527f54726f76654d616e616765723a20416d6f756e74206d7573742062652067726560408201526d61746572207468616e207a65726f60901b606082015260800190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252602a908201527f54726f76654d616e616765723a2043616e6e6f742072656465656d207768656e604082015269102a21a9101e1026a1a960b11b606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b6000610100613aa4838951613498565b6020880151604084015260408801516060840152613ac56080840188613498565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b918252602082015260400190565b858152602081018590526040810184905260a0810160058410613b3b57fe5b60608201939093526001600160801b03919091166080909101529392505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff81118282101715613b9657600080fd5b604052919050565b6001600160a01b038116811461060b57600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212207c16913f9245b09fe846c28a2b84344e3caf87f082e47e49ca0ae21a08915c2b64736f6c634300060b0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061028a5760003560e01c8063797250e31161015c578063a3f4df7e116100ce578063bf9befb111610087578063bf9befb114610486578063c35bc5501461048e578063c7b5548114610496578063d380a37c1461049e578063d815e8e9146104a6578063e056e918146104ae5761028a565b8063a3f4df7e1461043e578063ae7bec1914610453578063ae9187541461045b578063b7f8cf9b14610463578063bcd375261461046b578063be4b03341461047e5761028a565b8063893d20e811610120578063893d20e81461040b57806396d711ff146104135780639708daf41461041b5780639dd233d21461042e5780639f07067014610436578063a20baee6146103b05761028a565b8063797250e3146103e35780637cf54e40146103eb5780637f7dde4a146103f3578063807d138d146103fb578063887105d3146104035761028a565b80633cc7422511610200578063716c47e6116101b9578063716c47e6146103a857806372fe25aa146103b0578063741bef1a146103b8578063756b253e146103c0578063759b3034146103d3578063795d26c3146103db5761028a565b80633cc742251461034657806342ccf1e41461034e5780634a767d681461036157806361ec893d146103745780636b4449521461037c5780636ef64338146103845761028a565b80631673c79a116102525780631673c79a146102f25780631a59a50e146103135780631bf43555146103265780631f68f20a1461032e57806331c903b0146103365780633a1285951461033e5761028a565b806305b6f5ca1461028f578063071a7541146102a45780630d43e8ad146102c257806312261ee7146102d757806313af4035146102df575b600080fd5b6102a261029d3660046132d7565b6104ce565b005b6102ac610589565b6040516102b99190613b05565b60405180910390f35b6102ca61058e565b6040516102b991906134cd565b6102ca61059d565b6102a26102ed3660046131b7565b6105c1565b6103056103003660046131b7565b61060e565b6040516102b9929190613b0e565b6102ac6103213660046131b7565b610627565b6102ac6106ef565b6102ac6106fc565b6102ac610702565b6102ca610714565b6102ca610723565b6102ac61035c3660046131b7565b610732565b6102ac61036f3660046131ef565b610763565b6102ac61078e565b6102ac610793565b6103976103923660046131b7565b610799565b6040516102b9959493929190613b1c565b6102ca6107d3565b6102ac6107e2565b6102ca6107ee565b6102ca6103ce36600461323a565b6107fd565b6102ac610824565b6102ac610831565b6102ac610950565b6102ca610956565b6102ca610965565b6102ac610974565b6102ac61097a565b6102ca610a49565b6102ac610a68565b6102a2610429366004613361565b610a6e565b6102ac610b4c565b6102ca610b52565b610446610b61565b6040516102b991906135e4565b6102ca610b89565b6102ca610b98565b6102ca610ba7565b6102a261047936600461326a565b610bb6565b6102ac610bce565b6102ac610bd4565b6102ac610bda565b6102ac610bfe565b6102ac610c0a565b6102ca610c10565b6104c16104bc3660046131b7565b610c1f565b6040516102b991906135ab565b600061056d600560009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b15801561052157600080fd5b505afa158015610535573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055991906131d3565b6009548b906001600160a01b031685610c7d565b905061057e81898989898989610f2e565b505050505050505050565b600281565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b6105c9610a49565b6001600160a01b0316336001600160a01b0316146106025760405162461bcd60e51b81526004016105f99061389f565b60405180910390fd5b61060b816116f5565b50565b6016602052600090815260409020805460019091015482565b6001600160a01b0381166000908152601660205260408120546014548290610655908363ffffffff61178016565b905080158061068e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561068b57fe5b14155b1561069e576000925050506106ea565b6001600160a01b038416600090815260106020526040812060020154906106e3670de0b6b3a76400006106d7848663ffffffff6117c916565b9063ffffffff61180316565b9450505050505b919050565b6809c2007651b250000081565b600e5481565b600061070f600e54611845565b905090565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290610655908363ffffffff61178016565b6000806000610771856118ee565b915091506000610782838387611974565b93505050505b92915050565b603c81565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b670de0b6b3a764000081565b6002546001600160a01b031681565b6017818154811061080a57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b15801561087557600080fd5b505afa158015610889573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ad9190613252565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ff57600080fd5b505afa158015610913573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109379190613252565b9050610949828263ffffffff6119a616565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b1580156109bf57600080fd5b505afa1580156109d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f79190613252565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108ff57600080fd5b600080604051610a58906134b0565b6040519081900390205492915050565b60135481565b6000610b2e600560009054906101000a90046001600160a01b03166001600160a01b031663e9fc34616040518163ffffffff1660e01b815260040160206040518083038186803b158015610ac157600080fd5b505afa158015610ad5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610af991906131d3565b6009546001600160a01b0316867f000000000000000000000000000000000000000000000000000000000000000087876119cb565b9050610b3f818b8b8b8b8b8b610f2e565b5050505050505050505050565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b6005546001600160a01b031681565b610bc587878787878787610f2e565b50505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b670ddd4b8c6c7d70d881565b600f5481565b6009546001600160a01b031681565b600060016001600160a01b03831660009081526010602052604090206003015460ff166004811115610c4d57fe5b14610c5a575060006106ea565b506014546001600160a01b03821660009081526016602052604090205410919050565b600080856001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015610cb957600080fd5b505afa158015610ccd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf191906131d3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610d2191906134cd565b60206040518083038186803b158015610d3957600080fd5b505afa158015610d4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d719190613252565b9050306001600160a01b03831663605629d633838a8935610d9860408c0160208d01613477565b8b604001358c606001356040518863ffffffff1660e01b8152600401610dc497969594939291906134e1565b600060405180830381600087803b158015610dde57600080fd5b505af1158015610df2573d6000803e3d6000fd5b5050505086610e8383856001600160a01b03166370a08231856040518263ffffffff1660e01b8152600401610e2791906134cd565b60206040518083038186803b158015610e3f57600080fd5b505afa158015610e53573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e779190613252565b9063ffffffff61178016565b14610ea05760405162461bcd60e51b81526004016105f9906136ab565b60405163fb2c922360e01b81526001600160a01b0389169063fb2c922390610ed09089908b90339060040161355d565b602060405180830381600087803b158015610eea57600080fd5b505af1158015610efe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f229190613252565b98975050505050505050565b610f366130b5565b506040805160e0810182526000546001600160a01b03908116825260015481166020830152600954811692820192909252600b5482166060820152600d5482166080820152600854821660a082015260075490911660c0820152610f986130f1565b610fa183611c18565b610fa9611cd1565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610ff957600080fd5b505af115801561100d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110319190613252565b60c0820181905261104190611d9f565b61104a89611e4c565b6110598260400151338b611e6c565b611061610831565b60e0820181905260408084015190516370a0823160e01b81526001600160a01b03909116906370a082319061109a9033906004016134cd565b60206040518083038186803b1580156110b257600080fd5b505afa1580156110c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ea9190613252565b11156110f257fe5b888152608082015160c082015160009161110d918b90611f0d565b156111195750876112c6565b82608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561115657600080fd5b505afa15801561116a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118e91906131d3565b90505b6001600160a01b0381161580159061123a5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156111f257600080fd5b505afa158015611206573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122a9190613252565b611238828460c00151610763565b105b156112c65782608001516001600160a01b031663b72703ac826040518263ffffffff1660e01b815260040161126f91906134cd565b60206040518083038186803b15801561128757600080fd5b505afa15801561129b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112bf91906131d3565b9050611191565b846112d15760001994505b6001600160a01b038116158015906112e95750815115155b80156112f55750600085115b15611423576080830151604051632dc9c0eb60e21b8152600019909601956000916001600160a01b03169063b72703ac906113349085906004016134cd565b60206040518083038186803b15801561134c57600080fd5b505afa158015611360573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138491906131d3565b90506113998460000151856020015184612170565b6113a1613136565b6113b8858486600001518760c001518e8e8e612281565b90508060400151156113cb575050611423565b805160208501516113e19163ffffffff6119a616565b60208086019190915281015160408501516114019163ffffffff6119a616565b6040850152805184516114199163ffffffff61178016565b84525090506112d1565b60008260400151116114475760405162461bcd60e51b81526004016105f9906136f4565b61145e82604001518360c001518460e001516124f5565b5061146c82604001516125ac565b6060830181905260408301516114839190866125bf565b8251600c5460608401516040516364a197f360e01b81526001600160a01b03938416936364a197f3936114bb93911691600401613522565b600060405180830381600087803b1580156114d557600080fd5b505af11580156114e9573d6000803e3d6000fd5b50505050600c60009054906101000a90046001600160a01b03166001600160a01b031663bb57ad206040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561153d57600080fd5b505af1158015611551573d6000803e3d6000fd5b505050506060820151604083015161156891611780565b60808301526020820151604080840151606085015191517f43a3f4082a4dbc33d78e317d2497d3a730bc7fc3574159dcea1056e62e5d9ad8936115ae938f939192613b5c565b60405180910390a182604001516001600160a01b0316639dc29fac3384602001516040518363ffffffff1660e01b81526004016115ec929190613522565b600060405180830381600087803b15801561160657600080fd5b505af115801561161a573d6000803e3d6000fd5b50508451602085015160405163121cbc4d60e11b81526001600160a01b039092169350632439789a925061165091600401613b05565b600060405180830381600087803b15801561166a57600080fd5b505af115801561167e573d6000803e3d6000fd5b5050845160808501516040516364a197f360e01b81526001600160a01b0390921693506364a197f392506116b791339190600401613522565b600060405180830381600087803b1580156116d157600080fd5b505af11580156116e5573d6000803e3d6000fd5b5050505050505050505050505050565b6001600160a01b03811661171b5760405162461bcd60e51b81526004016105f990613774565b806001600160a01b031661172d610a49565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051611770906134b0565b6040519081900390209190915550565b60006117c283836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612605565b9392505050565b6000826117d857506000610788565b828202828482816117e557fe5b04146117c25760405162461bcd60e51b81526004016105f99061385e565b60006117c283836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612631565b60006107886118e083600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561189c57600080fd5b505afa1580156118b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118d49190613252565b9063ffffffff6119a616565b670de0b6b3a7640000612668565b60008060006118fc84610627565b9050600061190985610732565b6001600160a01b03861660009081526010602052604081206001015491925090611939908463ffffffff6119a616565b6001600160a01b03871660009081526010602052604081205491925090611966908463ffffffff6119a616565b919550909350505050915091565b6000821561199b576000611992846106d7878663ffffffff6117c916565b91506117c29050565b506000199392505050565b6000828201838110156117c25760405162461bcd60e51b81526004016105f99061373d565b600080876001600160a01b03166321df0da76040518163ffffffff1660e01b815260040160206040518083038186803b158015611a0757600080fd5b505afa158015611a1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3f91906131d3565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611a6f91906134cd565b60206040518083038186803b158015611a8757600080fd5b505afa158015611a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abf9190613252565b87516020015190915030906001600160a01b0388166330f28b7a8a611ae4858561267e565b338b8b6040518663ffffffff1660e01b8152600401611b07959493929190613a94565b600060405180830381600087803b158015611b2157600080fd5b505af1158015611b35573d6000803e3d6000fd5b5050505080611b6a84866001600160a01b03166370a08231866040518263ffffffff1660e01b8152600401610e2791906134cd565b14611b875760405162461bcd60e51b81526004016105f9906136ab565b60405163fb2c922360e01b81526001600160a01b038c169063fb2c922390611bb7908d908590339060040161355d565b602060405180830381600087803b158015611bd157600080fd5b505af1158015611be5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c099190613252565b9b9a5050505050505050505050565b600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c6657600080fd5b505afa158015611c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9e9190613252565b8110158015611cb55750670de0b6b3a76400008111155b61060b5760405162461bcd60e51b81526004016105f990613974565b600a5460408051631e425be160e11b815290516000926001600160a01b031691633c84b7c2916004808301926020929190829003018186803b158015611d1657600080fd5b505afa158015611d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d4e9190613252565b9050611d80817f000000000000000000000000000000000000000000000000000000000000000063ffffffff6119a616565b42101561060b5760405162461bcd60e51b81526004016105f990613800565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015611ded57600080fd5b505afa158015611e01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e259190613252565b611e2e826126b0565b101561060b5760405162461bcd60e51b81526004016105f9906139c4565b6000811161060b5760405162461bcd60e51b81526004016105f9906138d0565b6040516370a0823160e01b815281906001600160a01b038516906370a0823190611e9a9086906004016134cd565b60206040518083038186803b158015611eb257600080fd5b505afa158015611ec6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eea9190613252565b1015611f085760405162461bcd60e51b81526004016105f990613637565b505050565b60006001600160a01b0383161580611f9e5750604051630bb7c8fd60e31b81526001600160a01b03851690635dbe47e890611f4c9086906004016134cd565b60206040518083038186803b158015611f6457600080fd5b505afa158015611f78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9c919061321a565b155b806120365750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015611ff257600080fd5b505afa158015612006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202a9190613252565b6120348484610763565b105b15612043575060006117c2565b60405163765e015960e01b81526000906001600160a01b0386169063765e0159906120729087906004016134cd565b60206040518083038186803b15801561208a57600080fd5b505afa15801561209e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c291906131d3565b90506001600160a01b03811615806121675750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561212357600080fd5b505afa158015612137573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215b9190613252565b6121658285610763565b105b95945050505050565b61217981610c1f565b15611f0857612187816126dc565b600061219282610627565b9050600061219f83610732565b6001600160a01b0384166000908152601060205260409020600101549091506121ce908363ffffffff6119a616565b6001600160a01b03841660009081526010602052604090206001810191909155546121ff908263ffffffff6119a616565b6001600160a01b03841660009081526010602052604090205561222183612725565b61222d8585838561278d565b6001600160a01b038316600081815260106020526040808220805460018201546002909201549251600080516020613bb48339815191529461227294929392916135b6565b60405180910390a25050505050565b612289613136565b6001600160a01b0387166000908152601060205260409020546122c69087906122c1906801158e460913d0000063ffffffff61178016565b612668565b8082526122e79086906106d790670de0b6b3a764000063ffffffff6117c916565b60208083019190915281516001600160a01b03891660009081526010909252604082205461231a9163ffffffff61178016565b6020808401516001600160a01b038b1660009081526010909252604082206001015492935090916123509163ffffffff61178016565b90506801158e460913d000008214156123c95761236c896128ad565b6123778960046128fd565b61238c8a8a6801158e460913d0000084612a09565b886001600160a01b0316600080516020613bb4833981519152600080600060036040516123bc94939291906135b6565b60405180910390a26124e7565b60006123d58284612b6c565b905084811415806123f657506809c2007651b25000006123f484612ba1565b105b1561240a57505060016040830152506124ea565b8a608001516001600160a01b0316632be212608b838a8a6040518563ffffffff1660e01b81526004016124409493929190613580565b600060405180830381600087803b15801561245a57600080fd5b505af115801561246e573d6000803e3d6000fd5b5050506001600160a01b038b1660009081526010602052604090208481556001018390555061249c8a612bbc565b506001600160a01b038a1660008181526010602052604090819020600201549051600080516020613bb4833981519152916124dd91879187916003906135b6565b60405180910390a2505b50505b979650505050505050565b600080612500612c63565b90506000612518846106d7888863ffffffff6117c916565b9050600061253d61253083600263ffffffff61180316565b849063ffffffff6119a616565b905061255181670de0b6b3a7640000612668565b90506000811161255d57fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c90612592908390613b05565b60405180910390a16125a2612ca7565b9695505050505050565b60006107886125b9610702565b83612cfc565b60006125dd836106d786670de0b6b3a764000063ffffffff6117c916565b9050818111156125ff5760405162461bcd60e51b81526004016105f990613a0e565b50505050565b600081848411156126295760405162461bcd60e51b81526004016105f991906135e4565b505050900390565b600081836126525760405162461bcd60e51b81526004016105f991906135e4565b50600083858161265e57fe5b0495945050505050565b600081831061267757816117c2565b5090919050565b612686613159565b61268e613159565b5050604080518082019091526001600160a01b03929092168252602082015290565b6000806126bb61097a565b905060006126c7610831565b90506126d4828286611974565b949350505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561270857fe5b1461060b5760405162461bcd60e51b81526004016105f990613a45565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92612782929091613b0e565b60405180910390a150565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a906127b9908590600401613b05565b600060405180830381600087803b1580156127d357600080fd5b505af11580156127e7573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150612817908590600401613b05565b600060405180830381600087803b15801561283157600080fd5b505af1158015612845573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150612875908490600401613b05565b600060405180830381600087803b15801561288f57600080fd5b505af11580156128a3573d6000803e3d6000fd5b5050505050505050565b6001600160a01b0381166000908152601060205260409020600201546011546128dc908263ffffffff61178016565b601155506001600160a01b0316600090815260106020526040812060020155565b600081600481111561290b57fe5b141580156129255750600181600481111561292257fe5b14155b61292b57fe5b60175461293781612d3c565b6001600160a01b0383166000908152601060205260409020600301805483919060ff1916600183600481111561296957fe5b02179055506001600160a01b03831660009081526010602090815260408083206001808201859055908490556016909252822082815501556129ab8382612de2565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e906129db9086906004016134cd565b600060405180830381600087803b1580156129f557600080fd5b505af1158015610bc5573d6000803e3d6000fd5b6040808501516007549151632770a7eb60e21b81526001600160a01b0391821692639dc29fac92612a41929116908690600401613522565b600060405180830381600087803b158015612a5b57600080fd5b505af1158015612a6f573d6000803e3d6000fd5b5050855160405163121cbc4d60e11b81526001600160a01b039091169250632439789a9150612aa2908590600401613b05565b600060405180830381600087803b158015612abc57600080fd5b505af1158015612ad0573d6000803e3d6000fd5b505050508360a001516001600160a01b0316633f10abab84836040518363ffffffff1660e01b8152600401612b06929190613522565b600060405180830381600087803b158015612b2057600080fd5b505af1158015612b34573d6000803e3d6000fd5b5050855160a08701516040516364a197f360e01b81526001600160a01b0390921693506364a197f39250612875918590600401613522565b60008115612b9857612b91826106d78568056bc75e2d6310000063ffffffff6117c916565b9050610788565b50600019610788565b6000610788826801158e460913d0000063ffffffff61178016565b6001600160a01b0381166000908152601060205260408120600101548190612be390612f83565b6001600160a01b038416600090815260106020526040902060020180549082905560115491925090612c219083906118d4908463ffffffff61178016565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae52038291612c5491613b05565b60405180910390a15092915050565b600080612c6e612fbf565b90506000612c84670ddd4b8c6c7d70d883612fdb565b9050610949670de0b6b3a76400006106d783600e546117c990919063ffffffff16565b6000612cbe600f544261178090919063ffffffff16565b9050603c811061060b5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc9161278291613b05565b600080612d1b670de0b6b3a76400006106d7868663ffffffff6117c916565b90508281106117c25760405162461bcd60e51b81526004016105f99061391e565b600181118015612dc65750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b158015612d8c57600080fd5b505afa158015612da0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc49190613252565b115b61060b5760405162461bcd60e51b81526004016105f9906137b6565b6001600160a01b03821660009081526010602052604081206003015460ff1690816004811115612e0e57fe5b14158015612e2857506001816004811115612e2557fe5b14155b612e2e57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b0316908390612e66826001611780565b905080836001600160801b03161115612e7b57fe5b600060178281548110612e8a57fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b038716908110612ebc57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a90612f45908390879061353b565b60405180910390a16017805480612f5857fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b60008060135460001415612f98575081610788565b600060125411612fa457fe5b6117c26013546106d7601254866117c990919063ffffffff16565b600061070f603c6106d7600f544261178090919063ffffffff16565b6000631f540500821115612ff157631f54050091505b816130055750670de0b6b3a7640000610788565b670de0b6b3a764000083835b600181111561307c57600281066130465761302c8283613082565b915061303f81600263ffffffff61180316565b9050613077565b6130508284613082565b925061305c8283613082565b915061307460026106d783600163ffffffff61178016565b90505b613011565b61078282845b600080613095848463ffffffff6117c916565b90506126d4670de0b6b3a76400006106d7836706f05b59d3b200006119a6565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b60405180610100016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806060016040528060008152602001600081526020016000151581525090565b604080518082019091526000808252602082015290565b60008083601f840112613181578182fd5b50813567ffffffffffffffff811115613198578182fd5b6020830191508360208285010111156131b057600080fd5b9250929050565b6000602082840312156131c8578081fd5b81356117c281613b9e565b6000602082840312156131e4578081fd5b81516117c281613b9e565b60008060408385031215613201578081fd5b823561320c81613b9e565b946020939093013593505050565b60006020828403121561322b578081fd5b815180151581146117c2578182fd5b60006020828403121561324b578081fd5b5035919050565b600060208284031215613263578081fd5b5051919050565b600080600080600080600060e0888a031215613284578283fd5b87359650602088013561329681613b9e565b955060408801356132a681613b9e565b945060608801356132b681613b9e565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a036101608112156132f4578182fd5b8935985060208a013561330681613b9e565b975060408a013561331681613b9e565b965060608a013561332681613b9e565b955060808a810135955060a08b0135945060c08b0135935060df198201121561334d578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c03610180811215613381578283fd5b8b359a5060208c013561339381613b9e565b995060408c01356133a381613b9e565b985060608c01356133b381613b9e565b975060808c810135975060a08d0135965060c08d0135955060df198201908112156133dc578384fd5b6133e66060613b77565b915060408112156133f5578384fd5b506134006040613b77565b60e08d013561340e81613b9e565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff811115613453578283fd5b61345f8d828e01613170565b8194508093505050509295989b9194979a5092959850565b600060208284031215613488578081fd5b813560ff811681146117c2578182fd5b80516001600160a01b03168252602090810151910152565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b03948516815260208101939093529083166040830152909116606082015260800190565b901515815260200190565b848152602081018490526040810183905260808101600483106135d557fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015613610578581018301518582016040015282016135f4565b818111156136215783604083870101525b50601f01601f1916929092016040019392505050565b6020808252604e908201527f54726f76654d616e616765723a2052657175657374656420726564656d70746960408201527f6f6e20616d6f756e74206d757374206265203c3d20757365722773205a55534460608201526d20746f6b656e2062616c616e636560901b608082015260a00190565b60208082526029908201527f444c4c52207472616e7366657272656420616d6f756e742076616c69646174696040820152681bdb8819985a5b195960ba1b606082015260800190565b60208082526029908201527f54726f76654d616e616765723a20556e61626c6520746f2072656465656d20616040820152681b9e48185b5bdd5b9d60ba1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b602080825260409082018190527f54726f76654d616e616765723a20526564656d7074696f6e7320617265206e6f908201527f7420616c6c6f77656420647572696e6720626f6f747374726170207068617365606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b6020808252602e908201527f54726f76654d616e616765723a20416d6f756e74206d7573742062652067726560408201526d61746572207468616e207a65726f60901b606082015260800190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526030908201527f4d6178206665652070657263656e74616765206d75737420626520626574776560408201526f656e20302e352520616e64203130302560801b606082015260800190565b6020808252602a908201527f54726f76654d616e616765723a2043616e6e6f742072656465656d207768656e604082015269102a21a9101e1026a1a960b11b606082015260800190565b6020808252601d908201527f4665652065786365656465642070726f7669646564206d6178696d756d000000604082015260600190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b6000610100613aa4838951613498565b6020880151604084015260408801516060840152613ac56080840188613498565b6001600160a01b03861660c084015260e083018190528201839052610120838582850137828401810191909152601f909201601f19160101949350505050565b90815260200190565b918252602082015260400190565b858152602081018590526040810184905260a0810160058410613b3b57fe5b60608201939093526001600160801b03919091166080909101529392505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff81118282101715613b9657600080fd5b604052919050565b6001600160a01b038116811461060b57600080fdfec3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba26469706673582212207c16913f9245b09fe846c28a2b84344e3caf87f082e47e49ca0ae21a08915c2b64736f6c634300060b0033", + "devdoc": { + "kind": "dev", + "methods": { + "getOwner()": { + "returns": { + "_owner": "Address of the owner. " + } + }, + "setOwner(address)": { + "params": { + "_owner": "Address of the owner. " + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "BETA()": { + "notice": "BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption. Corresponds to (1 / ALPHA) in the white paper." + }, + "BOOTSTRAP_PERIOD()": { + "notice": "During bootsrap period redemptions are not allowed" + }, + "MIN_NET_DEBT()": { + "notice": "Minimum amount of net ZUSD debt a trove must have" + }, + "ZUSD_GAS_COMPENSATION()": { + "notice": "Amount of ZUSD to be locked in gas pool on opening troves" + }, + "_getCurrentICR(address,uint256)": { + "notice": "Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account." + }, + "_getPendingETHReward(address)": { + "notice": "Get the borrower's pending accumulated ETH reward, earned by their stake" + }, + "_getPendingZUSDDebtReward(address)": { + "notice": "Get the borrower's pending accumulated ZUSD reward, earned by their stake" + }, + "constructor": "Constructor ", + "getOwner()": { + "notice": "Return address of the owner." + }, + "permit2()": { + "notice": "CONSTANT / IMMUTABLE VARIABLE ONLY " + }, + "redeemCollateralViaDLLR(uint256,address,address,address,uint256,uint256,uint256,(uint256,uint8,bytes32,bytes32))": { + "notice": "DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction" + }, + "redeemCollateralViaDllrWithPermit2(uint256,address,address,address,uint256,uint256,uint256,((address,uint256),uint256,uint256),bytes)": { + "notice": "DLLR _owner can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction" + }, + "setOwner(address)": { + "notice": "Set address of the owner (only owner can call this function)" + } + }, + "notice": "This contract is designed to be used via delegatecall from the TroveManager contract TroveManagerBase constructor param is bootsrap period when redemptions are not allowed", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 5495, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "activePool", + "offset": 0, + "slot": "0", + "type": "t_contract(IActivePool)19557" + }, + { + "astId": 5497, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "defaultPool", + "offset": 0, + "slot": "1", + "type": "t_contract(IDefaultPool)20229" + }, + { + "astId": 5500, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "priceFeed", + "offset": 0, + "slot": "2", + "type": "t_contract(IPriceFeed)20458" + }, + { + "astId": 5503, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "liquityBaseParams", + "offset": 0, + "slot": "3", + "type": "t_contract(ILiquityBaseParams)20379" + }, + { + "astId": 35227, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "troveManagerRedeemOps", + "offset": 0, + "slot": "4", + "type": "t_address" + }, + { + "astId": 35229, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "borrowerOperationsAddress", + "offset": 0, + "slot": "5", + "type": "t_address" + }, + { + "astId": 35231, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "_stabilityPool", + "offset": 0, + "slot": "6", + "type": "t_contract(IStabilityPool)21101" + }, + { + "astId": 35233, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "gasPoolAddress", + "offset": 0, + "slot": "7", + "type": "t_address" + }, + { + "astId": 35235, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "collSurplusPool", + "offset": 0, + "slot": "8", + "type": "t_contract(ICollSurplusPool)20130" + }, + { + "astId": 35237, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "_zusdToken", + "offset": 0, + "slot": "9", + "type": "t_contract(IZUSDToken)21842" + }, + { + "astId": 35239, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "_zeroToken", + "offset": 0, + "slot": "10", + "type": "t_contract(IZEROToken)21783" + }, + { + "astId": 35241, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "_zeroStaking", + "offset": 0, + "slot": "11", + "type": "t_contract(IZEROStaking)21760" + }, + { + "astId": 35243, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "feeDistributor", + "offset": 0, + "slot": "12", + "type": "t_contract(IFeeDistributor)20298" + }, + { + "astId": 35245, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "sortedTroves", + "offset": 0, + "slot": "13", + "type": "t_contract(ISortedTroves)20817" + }, + { + "astId": 35247, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "baseRate", + "offset": 0, + "slot": "14", + "type": "t_uint256" + }, + { + "astId": 35249, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "lastFeeOperationTime", + "offset": 0, + "slot": "15", + "type": "t_uint256" + }, + { + "astId": 35270, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "Troves", + "offset": 0, + "slot": "16", + "type": "t_mapping(t_address,t_struct(Trove)35266_storage)" + }, + { + "astId": 35272, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "totalStakes", + "offset": 0, + "slot": "17", + "type": "t_uint256" + }, + { + "astId": 35274, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "totalStakesSnapshot", + "offset": 0, + "slot": "18", + "type": "t_uint256" + }, + { + "astId": 35276, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "totalCollateralSnapshot", + "offset": 0, + "slot": "19", + "type": "t_uint256" + }, + { + "astId": 35278, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "L_ETH", + "offset": 0, + "slot": "20", + "type": "t_uint256" + }, + { + "astId": 35280, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "L_ZUSDDebt", + "offset": 0, + "slot": "21", + "type": "t_uint256" + }, + { + "astId": 35284, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "rewardSnapshots", + "offset": 0, + "slot": "22", + "type": "t_mapping(t_address,t_struct(RewardSnapshot)35289_storage)" + }, + { + "astId": 35292, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "TroveOwners", + "offset": 0, + "slot": "23", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 35294, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "lastETHError_Redistribution", + "offset": 0, + "slot": "24", + "type": "t_uint256" + }, + { + "astId": 35296, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "lastZUSDDebtError_Redistribution", + "offset": 0, + "slot": "25", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_contract(IActivePool)19557": { + "encoding": "inplace", + "label": "contract IActivePool", + "numberOfBytes": "20" + }, + "t_contract(ICollSurplusPool)20130": { + "encoding": "inplace", + "label": "contract ICollSurplusPool", + "numberOfBytes": "20" + }, + "t_contract(IDefaultPool)20229": { + "encoding": "inplace", + "label": "contract IDefaultPool", + "numberOfBytes": "20" + }, + "t_contract(IFeeDistributor)20298": { + "encoding": "inplace", + "label": "contract IFeeDistributor", + "numberOfBytes": "20" + }, + "t_contract(ILiquityBaseParams)20379": { + "encoding": "inplace", + "label": "contract ILiquityBaseParams", + "numberOfBytes": "20" + }, + "t_contract(IPriceFeed)20458": { + "encoding": "inplace", + "label": "contract IPriceFeed", + "numberOfBytes": "20" + }, + "t_contract(ISortedTroves)20817": { + "encoding": "inplace", + "label": "contract ISortedTroves", + "numberOfBytes": "20" + }, + "t_contract(IStabilityPool)21101": { + "encoding": "inplace", + "label": "contract IStabilityPool", + "numberOfBytes": "20" + }, + "t_contract(IZEROStaking)21760": { + "encoding": "inplace", + "label": "contract IZEROStaking", + "numberOfBytes": "20" + }, + "t_contract(IZEROToken)21783": { + "encoding": "inplace", + "label": "contract IZEROToken", + "numberOfBytes": "20" + }, + "t_contract(IZUSDToken)21842": { + "encoding": "inplace", + "label": "contract IZUSDToken", + "numberOfBytes": "20" + }, + "t_enum(Status)35255": { + "encoding": "inplace", + "label": "enum TroveManagerStorage.Status", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_struct(RewardSnapshot)35289_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct TroveManagerStorage.RewardSnapshot)", + "numberOfBytes": "32", + "value": "t_struct(RewardSnapshot)35289_storage" + }, + "t_mapping(t_address,t_struct(Trove)35266_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct TroveManagerStorage.Trove)", + "numberOfBytes": "32", + "value": "t_struct(Trove)35266_storage" + }, + "t_struct(RewardSnapshot)35289_storage": { + "encoding": "inplace", + "label": "struct TroveManagerStorage.RewardSnapshot", + "members": [ + { + "astId": 35286, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "ETH", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 35288, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "ZUSDDebt", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Trove)35266_storage": { + "encoding": "inplace", + "label": "struct TroveManagerStorage.Trove", + "members": [ + { + "astId": 35257, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "debt", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 35259, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "coll", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 35261, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "stake", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 35263, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "status", + "offset": 0, + "slot": "3", + "type": "t_enum(Status)35255" + }, + { + "astId": 35265, + "contract": "contracts/Dependencies/TroveManagerRedeemOps.sol:TroveManagerRedeemOps", + "label": "arrayIndex", + "offset": 1, + "slot": "3", + "type": "t_uint128" + } + ], + "numberOfBytes": "128" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/external/deployments/rskTestnet/TroveManager_Implementation.json b/external/deployments/rskTestnet/TroveManager_Implementation.json new file mode 100644 index 000000000..8e3d863a6 --- /dev/null +++ b/external/deployments/rskTestnet/TroveManager_Implementation.json @@ -0,0 +1,2752 @@ +{ + "address": "0x2c51a1ff7a7dcb8e93d4bd137a9e402445ea4037", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_bootstrapPeriod", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_permit2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + } + ], + "name": "ActivePoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_baseRate", + "type": "uint256" + } + ], + "name": "BaseRateUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newBorrowerOperationsAddress", + "type": "address" + } + ], + "name": "BorrowerOperationsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + } + ], + "name": "CollSurplusPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + } + ], + "name": "DefaultPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + } + ], + "name": "FeeDistributorAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + } + ], + "name": "GasPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "LTermsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_lastFeeOpTime", + "type": "uint256" + } + ], + "name": "LastFeeOpTimeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedDebt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_liquidatedColl", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_collGasCompensation", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ZUSDGasCompensation", + "type": "uint256" + } + ], + "name": "Liquidation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + } + ], + "name": "LiquityBaseParamsAddressChanges", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newPriceFeedAddress", + "type": "address" + } + ], + "name": "PriceFeedAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_attemptedZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_actualZUSDAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHSent", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_ETHFee", + "type": "uint256" + } + ], + "name": "Redemption", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + } + ], + "name": "SortedTrovesAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + } + ], + "name": "StabilityPoolAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_totalStakesSnapshot", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_totalCollateralSnapshot", + "type": "uint256" + } + ], + "name": "SystemSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_newTotalStakes", + "type": "uint256" + } + ], + "name": "TotalStakesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_newIndex", + "type": "uint256" + } + ], + "name": "TroveIndexUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveLiquidated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + } + ], + "name": "TroveManagerRedeemOpsAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ETH", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_L_ZUSDDebt", + "type": "uint256" + } + ], + "name": "TroveSnapshotsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_debt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "_coll", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "operation", + "type": "uint8" + } + ], + "name": "TroveUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "name": "ZEROStakingAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_zeroTokenAddress", + "type": "address" + } + ], + "name": "ZEROTokenAddressChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "_newZUSDTokenAddress", + "type": "address" + } + ], + "name": "ZUSDTokenAddressChanged", + "type": "event" + }, + { + "inputs": [], + "name": "BETA", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BOOTSTRAP_PERIOD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "CCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DECIMAL_PRECISION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ETH", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L_ZUSDDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINUTE_DECAY_FACTOR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MIN_NET_DEBT", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "NAME", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SECONDS_IN_ONE_MINUTE", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "TroveOwners", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "Troves", + "outputs": [ + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coll", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "stake", + "type": "uint256" + }, + { + "internalType": "enum TroveManagerStorage.Status", + "name": "status", + "type": "uint8" + }, + { + "internalType": "uint128", + "name": "arrayIndex", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZUSD_GAS_COMPENSATION", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_100pct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "_getCurrentICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingETHReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_getPendingZUSDDebtReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_getRedemptionRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "_hasPendingRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_stabilityPool", + "outputs": [ + { + "internalType": "contract IStabilityPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroStaking", + "outputs": [ + { + "internalType": "contract IZEROStaking", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zeroToken", + "outputs": [ + { + "internalType": "contract IZEROToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "_zusdToken", + "outputs": [ + { + "internalType": "contract IZUSDToken", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activePool", + "outputs": [ + { + "internalType": "contract IActivePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "addTroveOwnerToArray", + "outputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "applyPendingRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "baseRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_troveArray", + "type": "address[]" + } + ], + "name": "batchLiquidateTroves", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "borrowerOperationsAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "checkRecoveryMode", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "closeTrove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decayBaseRateFromBorrowing", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_collDecrease", + "type": "uint256" + } + ], + "name": "decreaseTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_debtDecrease", + "type": "uint256" + } + ], + "name": "decreaseTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "defaultPool", + "outputs": [ + { + "internalType": "contract IDefaultPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeDistributor", + "outputs": [ + { + "internalType": "contract IFeeDistributor", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDDebt", + "type": "uint256" + } + ], + "name": "getBorrowingFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDDebt", + "type": "uint256" + } + ], + "name": "getBorrowingFeeWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBorrowingRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBorrowingRateWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "getCurrentICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getEntireDebtAndColl", + "outputs": [ + { + "internalType": "uint256", + "name": "debt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "coll", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pendingZUSDDebtReward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pendingETHReward", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemColl", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemColl", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getEntireSystemDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "entireSystemDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getNominalICR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getPendingETHReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getPendingZUSDDebtReward", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ETHDrawn", + "type": "uint256" + } + ], + "name": "getRedemptionFeeWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRedemptionRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRedemptionRateWithDecay", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_price", + "type": "uint256" + } + ], + "name": "getTCR", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_index", + "type": "uint256" + } + ], + "name": "getTroveFromTroveOwnersArray", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTroveOwnersCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveStake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "getTroveStatus", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "hasPendingRewards", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_collIncrease", + "type": "uint256" + } + ], + "name": "increaseTroveColl", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_debtIncrease", + "type": "uint256" + } + ], + "name": "increaseTroveDebt", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lastETHError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastFeeOperationTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastZUSDDebtError_Redistribution", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "liquidate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_n", + "type": "uint256" + } + ], + "name": "liquidateTroves", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "liquityBaseParams", + "outputs": [ + { + "internalType": "contract ILiquityBaseParams", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "permit2", + "outputs": [ + { + "internalType": "contract IPermit2", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "priceFeed", + "outputs": [ + { + "internalType": "contract IPriceFeed", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_ZUSDamount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + } + ], + "name": "redeemCollateral", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "internalType": "struct IMassetManager.PermitParams", + "name": "_permitParams", + "type": "tuple" + } + ], + "name": "redeemCollateralViaDLLR", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_dllrAmount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_firstRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_upperPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "address", + "name": "_lowerPartialRedemptionHint", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_partialRedemptionHintNICR", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxIterations", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxFeePercentage", + "type": "uint256" + }, + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.TokenPermissions", + "name": "permitted", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ISignatureTransfer.PermitTransferFrom", + "name": "_permit", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "redeemCollateralViaDllrWithPermit2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "removeStake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "rewardSnapshots", + "outputs": [ + { + "internalType": "uint256", + "name": "ETH", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "ZUSDDebt", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "_feeDistributorAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + }, + { + "internalType": "address", + "name": "_liquityBaseParamsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_borrowerOperationsAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_activePoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_defaultPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_stabilityPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_gasPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_collSurplusPoolAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_priceFeedAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zusdTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_sortedTrovesAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroTokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "_zeroStakingAddress", + "type": "address" + } + ], + "internalType": "struct ITroveManager.TroveManagerInitAddressesParams", + "name": "_troveManagerInitAddressesParams", + "type": "tuple" + } + ], + "name": "setAddresses", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_troveManagerRedeemOps", + "type": "address" + } + ], + "name": "setTroveManagerRedeemOps", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_num", + "type": "uint256" + } + ], + "name": "setTroveStatus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sortedTroves", + "outputs": [ + { + "internalType": "contract ISortedTroves", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalCollateralSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalStakesSnapshot", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "troveManagerRedeemOps", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "updateStakeAndTotalStakes", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_borrower", + "type": "address" + } + ], + "name": "updateTroveRewardSnapshots", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "receipt": { + "to": null, + "from": "0x13Be55487D37FE3C66EE7305e1e9C1ac85de75Ae", + "contractAddress": "0xdC03c72c1730b149E3178624FD4d9Bf51501A6E0", + "transactionIndex": 0, + "gasUsed": "6045491", + "logsBloom": "0x00000000000020000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000080000000000000000001000000000000000000000000000000000000020000000000000000001800000000000000000000000000000000400000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x63ae44ab567d090410beb39dd6c2dad30f27c33679e013ac466adf6afc60e169", + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "logs": [ + { + "transactionIndex": 0, + "blockNumber": 4748962, + "transactionHash": "0x98964a83f4dcaec9042a905d998f3351c02d6dae3c1608d5d9db1d696445f729", + "address": "0xdC03c72c1730b149E3178624FD4d9Bf51501A6E0", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000013be55487d37fe3c66ee7305e1e9c1ac85de75ae" + ], + "data": "0x", + "logIndex": 0, + "blockHash": "0x63ae44ab567d090410beb39dd6c2dad30f27c33679e013ac466adf6afc60e169" + } + ], + "blockNumber": 4748962, + "cumulativeGasUsed": "6045491", + "status": 1, + "byzantium": true + }, + "args": ["1209600", "0x000000000022d473030f116ddee9f6b43ac78ba3"], + "numDeployments": 2, + "solcInputHash": "849fadfa265e27de6fba2f2d99bdf763", + "metadata": "{\"compiler\":{\"version\":\"0.6.11+commit.5ef660b1\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_bootstrapPeriod\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_permit2\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_activePoolAddress\",\"type\":\"address\"}],\"name\":\"ActivePoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_baseRate\",\"type\":\"uint256\"}],\"name\":\"BaseRateUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newBorrowerOperationsAddress\",\"type\":\"address\"}],\"name\":\"BorrowerOperationsAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_collSurplusPoolAddress\",\"type\":\"address\"}],\"name\":\"CollSurplusPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_defaultPoolAddress\",\"type\":\"address\"}],\"name\":\"DefaultPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_feeDistributorAddress\",\"type\":\"address\"}],\"name\":\"FeeDistributorAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_gasPoolAddress\",\"type\":\"address\"}],\"name\":\"GasPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ETH\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"LTermsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_lastFeeOpTime\",\"type\":\"uint256\"}],\"name\":\"LastFeeOpTimeUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_liquidatedDebt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_liquidatedColl\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_collGasCompensation\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ZUSDGasCompensation\",\"type\":\"uint256\"}],\"name\":\"Liquidation\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_borrowerOperationsAddress\",\"type\":\"address\"}],\"name\":\"LiquityBaseParamsAddressChanges\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newPriceFeedAddress\",\"type\":\"address\"}],\"name\":\"PriceFeedAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_attemptedZUSDAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_actualZUSDAmount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ETHSent\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_ETHFee\",\"type\":\"uint256\"}],\"name\":\"Redemption\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_sortedTrovesAddress\",\"type\":\"address\"}],\"name\":\"SortedTrovesAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_stabilityPoolAddress\",\"type\":\"address\"}],\"name\":\"StabilityPoolAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalStakesSnapshot\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_totalCollateralSnapshot\",\"type\":\"uint256\"}],\"name\":\"SystemSnapshotsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newTotalStakes\",\"type\":\"uint256\"}],\"name\":\"TotalStakesUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_newIndex\",\"type\":\"uint256\"}],\"name\":\"TroveIndexUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_coll\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"operation\",\"type\":\"uint8\"}],\"name\":\"TroveLiquidated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_troveManagerRedeemOps\",\"type\":\"address\"}],\"name\":\"TroveManagerRedeemOpsAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ETH\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_L_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"TroveSnapshotsUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_debt\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"_coll\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"operation\",\"type\":\"uint8\"}],\"name\":\"TroveUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_zeroStakingAddress\",\"type\":\"address\"}],\"name\":\"ZEROStakingAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_zeroTokenAddress\",\"type\":\"address\"}],\"name\":\"ZEROTokenAddressChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"_newZUSDTokenAddress\",\"type\":\"address\"}],\"name\":\"ZUSDTokenAddressChanged\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BETA\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"BOOTSTRAP_PERIOD\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"CCR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DECIMAL_PRECISION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L_ETH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"L_ZUSDDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MCR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MINUTE_DECAY_FACTOR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MIN_NET_DEBT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"NAME\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SECONDS_IN_ONE_MINUTE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"TroveOwners\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"Troves\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"debt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"coll\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"stake\",\"type\":\"uint256\"},{\"internalType\":\"enum TroveManagerStorage.Status\",\"name\":\"status\",\"type\":\"uint8\"},{\"internalType\":\"uint128\",\"name\":\"arrayIndex\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ZUSD_GAS_COMPENSATION\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_100pct\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_price\",\"type\":\"uint256\"}],\"name\":\"_getCurrentICR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_getPendingETHReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_getPendingZUSDDebtReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_getRedemptionRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"_hasPendingRewards\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_stabilityPool\",\"outputs\":[{\"internalType\":\"contract IStabilityPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zeroStaking\",\"outputs\":[{\"internalType\":\"contract IZEROStaking\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zeroToken\",\"outputs\":[{\"internalType\":\"contract IZEROToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"_zusdToken\",\"outputs\":[{\"internalType\":\"contract IZUSDToken\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"activePool\",\"outputs\":[{\"internalType\":\"contract IActivePool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"addTroveOwnerToArray\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"applyPendingRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"baseRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_troveArray\",\"type\":\"address[]\"}],\"name\":\"batchLiquidateTroves\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"borrowerOperationsAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_price\",\"type\":\"uint256\"}],\"name\":\"checkRecoveryMode\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"closeTrove\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decayBaseRateFromBorrowing\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_collDecrease\",\"type\":\"uint256\"}],\"name\":\"decreaseTroveColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_debtDecrease\",\"type\":\"uint256\"}],\"name\":\"decreaseTroveDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"defaultPool\",\"outputs\":[{\"internalType\":\"contract IDefaultPool\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeDistributor\",\"outputs\":[{\"internalType\":\"contract IFeeDistributor\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"getBorrowingFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ZUSDDebt\",\"type\":\"uint256\"}],\"name\":\"getBorrowingFeeWithDecay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBorrowingRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBorrowingRateWithDecay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_price\",\"type\":\"uint256\"}],\"name\":\"getCurrentICR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getEntireDebtAndColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"debt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"coll\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pendingZUSDDebtReward\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"pendingETHReward\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemColl\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getEntireSystemDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"entireSystemDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getNominalICR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getPendingETHReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getPendingZUSDDebtReward\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ETHDrawn\",\"type\":\"uint256\"}],\"name\":\"getRedemptionFeeWithDecay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRedemptionRate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getRedemptionRateWithDecay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_price\",\"type\":\"uint256\"}],\"name\":\"getTCR\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getTroveColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getTroveDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_index\",\"type\":\"uint256\"}],\"name\":\"getTroveFromTroveOwnersArray\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTroveOwnersCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getTroveStake\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"getTroveStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"hasPendingRewards\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_collIncrease\",\"type\":\"uint256\"}],\"name\":\"increaseTroveColl\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_debtIncrease\",\"type\":\"uint256\"}],\"name\":\"increaseTroveDebt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastETHError_Redistribution\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastFeeOperationTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastZUSDDebtError_Redistribution\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"liquidate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_n\",\"type\":\"uint256\"}],\"name\":\"liquidateTroves\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquityBaseParams\",\"outputs\":[{\"internalType\":\"contract ILiquityBaseParams\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"permit2\",\"outputs\":[{\"internalType\":\"contract IPermit2\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"priceFeed\",\"outputs\":[{\"internalType\":\"contract IPriceFeed\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_ZUSDamount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"}],\"name\":\"redeemCollateral\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"struct IMassetManager.PermitParams\",\"name\":\"_permitParams\",\"type\":\"tuple\"}],\"name\":\"redeemCollateralViaDLLR\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_dllrAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_firstRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_upperPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_lowerPartialRedemptionHint\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_partialRedemptionHintNICR\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxIterations\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxFeePercentage\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.TokenPermissions\",\"name\":\"permitted\",\"type\":\"tuple\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"}],\"internalType\":\"struct ISignatureTransfer.PermitTransferFrom\",\"name\":\"_permit\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"_signature\",\"type\":\"bytes\"}],\"name\":\"redeemCollateralViaDllrWithPermit2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"removeStake\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"rewardSnapshots\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"ETH\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"ZUSDDebt\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"_feeDistributorAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_troveManagerRedeemOps\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_liquityBaseParamsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_borrowerOperationsAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_activePoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_defaultPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_stabilityPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_gasPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_collSurplusPoolAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_priceFeedAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zusdTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_sortedTrovesAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zeroTokenAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_zeroStakingAddress\",\"type\":\"address\"}],\"internalType\":\"struct ITroveManager.TroveManagerInitAddressesParams\",\"name\":\"_troveManagerInitAddressesParams\",\"type\":\"tuple\"}],\"name\":\"setAddresses\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_troveManagerRedeemOps\",\"type\":\"address\"}],\"name\":\"setTroveManagerRedeemOps\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_num\",\"type\":\"uint256\"}],\"name\":\"setTroveStatus\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"sortedTroves\",\"outputs\":[{\"internalType\":\"contract ISortedTroves\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalCollateralSnapshot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalStakesSnapshot\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"troveManagerRedeemOps\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"updateStakeAndTotalStakes\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_borrower\",\"type\":\"address\"}],\"name\":\"updateTroveRewardSnapshots\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"applyPendingRewards(address)\":{\"params\":{\"_borrower\":\"borrower address\"}},\"closeTrove(address)\":{\"params\":{\"_borrower\":\"borrower address\"}},\"constructor\":{\"params\":{\"_bootstrapPeriod\":\"During bootsrap period redemptions are not allowed\"}},\"decreaseTroveColl(address,uint256)\":{\"params\":{\"_borrower\":\"borrower address\",\"_collDecrease\":\"amount of collateral to decrease\"},\"returns\":{\"_0\":\"new trove collateral\"}},\"decreaseTroveDebt(address,uint256)\":{\"params\":{\"_borrower\":\"borrower address\",\"_debtDecrease\":\"amount of debt to decrease\"},\"returns\":{\"_0\":\"new trove debt\"}},\"getBorrowingFeeWithDecay(uint256)\":{\"params\":{\"_ZUSDDebt\":\"ZUSD debt amount to calculate fee\"},\"returns\":{\"_0\":\"borrowing fee using borrowing rate with decay\"}},\"getBorrowingRate()\":{\"returns\":{\"_0\":\"borrowing rate\"}},\"getBorrowingRateWithDecay()\":{\"returns\":{\"_0\":\"borrowing rate calculated using decayed as base rate\"}},\"getCurrentICR(address,uint256)\":{\"params\":{\"_borrower\":\"borrower address\",\"_price\":\"ETH price\"},\"returns\":{\"_0\":\"the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\"}},\"getNominalICR(address)\":{\"returns\":{\"_0\":\"the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account.\"}},\"getOwner()\":{\"returns\":{\"_owner\":\"Address of the owner. \"}},\"getPendingETHReward(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"the borrower's pending accumulated ETH reward, earned by their stake\"}},\"getPendingZUSDDebtReward(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"the borrower's pending accumulated ZUSD reward, earned by their stake\"}},\"getRedemptionFeeWithDecay(uint256)\":{\"params\":{\"_ETHDrawn\":\"ETH drawn\"}},\"getRedemptionRate()\":{\"returns\":{\"_0\":\"calculated redemption rate using baseRate\"}},\"getRedemptionRateWithDecay()\":{\"returns\":{\"_0\":\"calculated redemption rate using calculated decayed as base rate\"}},\"getTCR(uint256)\":{\"params\":{\"_price\":\"ETH price\"},\"returns\":{\"_0\":\"the total collateralization ratio (TCR) of the system. The TCR is based on the the entire system debt and collateral (including pending rewards).\"}},\"getTroveColl(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"Trove collateral from given trove\"}},\"getTroveDebt(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"Trove debt from given trove\"}},\"getTroveFromTroveOwnersArray(uint256)\":{\"params\":{\"_index\":\"Trove owner index\"},\"returns\":{\"_0\":\"Trove from TroveOwners array in given index\"}},\"getTroveOwnersCount()\":{\"returns\":{\"_0\":\"Trove owners count\"}},\"getTroveStake(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"Trove stake from given trove\"}},\"getTroveStatus(address)\":{\"params\":{\"_borrower\":\"borrower address\"},\"returns\":{\"_0\":\"Trove status from given trove\"}},\"increaseTroveColl(address,uint256)\":{\"params\":{\"_borrower\":\"borrower address\",\"_collIncrease\":\"amount of collateral to increase\"},\"returns\":{\"_0\":\"new trove collateral\"}},\"increaseTroveDebt(address,uint256)\":{\"params\":{\"_borrower\":\"borrower address\",\"_debtIncrease\":\"amount of debt to increase\"},\"returns\":{\"_0\":\"new trove debt\"}},\"redeemCollateral(uint256,address,address,address,uint256,uint256,uint256)\":{\"details\":\"this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed\"},\"redeemCollateralViaDLLR(uint256,address,address,address,uint256,uint256,uint256,(uint256,uint8,bytes32,bytes32))\":{\"details\":\"this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\"},\"redeemCollateralViaDllrWithPermit2(uint256,address,address,address,uint256,uint256,uint256,((address,uint256),uint256,uint256),bytes)\":{\"details\":\"this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\"},\"removeStake(address)\":{\"params\":{\"_borrower\":\"borrower address\"}},\"setOwner(address)\":{\"params\":{\"_owner\":\"Address of the owner. \"}},\"updateStakeAndTotalStakes(address)\":{\"params\":{\"_borrower\":\"borrower address\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"BETA()\":{\"notice\":\"BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption. Corresponds to (1 / ALPHA) in the white paper.\"},\"BOOTSTRAP_PERIOD()\":{\"notice\":\"During bootsrap period redemptions are not allowed\"},\"MIN_NET_DEBT()\":{\"notice\":\"Minimum amount of net ZUSD debt a trove must have\"},\"ZUSD_GAS_COMPENSATION()\":{\"notice\":\"Amount of ZUSD to be locked in gas pool on opening troves\"},\"_getCurrentICR(address,uint256)\":{\"notice\":\"Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\"},\"_getPendingETHReward(address)\":{\"notice\":\"Get the borrower's pending accumulated ETH reward, earned by their stake\"},\"_getPendingZUSDDebtReward(address)\":{\"notice\":\"Get the borrower's pending accumulated ZUSD reward, earned by their stake\"},\"addTroveOwnerToArray(address)\":{\"notice\":\"Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct\"},\"applyPendingRewards(address)\":{\"notice\":\"Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\"},\"batchLiquidateTroves(address[])\":{\"notice\":\"Attempt to liquidate a custom list of troves provided by the caller.\"},\"checkRecoveryMode(uint256)\":{\"notice\":\"reveals whether or not the system is in Recovery Mode (i.e. whether the Total Collateralization Ratio (TCR) is below the Critical Collateralization Ratio (CCR)).\"},\"closeTrove(address)\":{\"notice\":\"Close given trove. Called by BorrowerOperations.\"},\"decayBaseRateFromBorrowing()\":{\"notice\":\"Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation.\"},\"getCurrentICR(address,uint256)\":{\"notice\":\"computes the user\\u2019s individual collateralization ratio (ICR) based on their total collateral and total ZUSD debt. Returns 2^256 -1 if they have 0 debt.\"},\"getEntireDebtAndColl(address)\":{\"notice\":\"Return the Troves entire debt and coll, including pending rewards from redistributions.\"},\"getOwner()\":{\"notice\":\"Return address of the owner.\"},\"getRedemptionFeeWithDecay(uint256)\":{\"notice\":\"The redemption fee is taken as a cut of the total ETH drawn from the system in a redemption. It is based on the current redemption rate.\"},\"liquidate(address)\":{\"notice\":\"Single liquidation function. Closes the trove if its ICR is lower than the minimum collateral ratio.\"},\"liquidateTroves(uint256)\":{\"notice\":\"Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves, starting from the one with the lowest collateral ratio in the system, and moving upwards\"},\"permit2()\":{\"notice\":\"CONSTANT / IMMUTABLE VARIABLE ONLY \"},\"removeStake(address)\":{\"notice\":\"Remove borrower's stake from the totalStakes sum, and set their stake to 0\"},\"setOwner(address)\":{\"notice\":\"Set address of the owner (only owner can call this function)\"},\"updateStakeAndTotalStakes(address)\":{\"notice\":\"Update borrower's stake based on their latest collateral value\"},\"updateTroveRewardSnapshots(address)\":{\"notice\":\"Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/TroveManager.sol\":\"TroveManager\"},\"evmVersion\":\"istanbul\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"contracts/Dependencies/BaseMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\n\\ncontract BaseMath {\\n uint constant public DECIMAL_PRECISION = 1e18;\\n}\\n\",\"keccak256\":\"0x7e1369ca5cb09e818e345a2def19a261401f79c985a6030b55b7311dd6f53be4\",\"license\":\"MIT\"},\"contracts/Dependencies/CheckContract.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n\\ncontract CheckContract {\\n /**\\n * @dev Check that the account is an already deployed non-destroyed contract.\\n * See: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L12\\n */\\n function checkContract(address _account) internal view {\\n require(_account != address(0), \\\"Account cannot be zero address\\\");\\n\\n uint256 size;\\n // solhint-disable-next-line no-inline-assembly\\n assembly { size := extcodesize(_account) }\\n require(size > 0, \\\"Account code size cannot be zero\\\");\\n }\\n}\\n\",\"keccak256\":\"0x4c7dc4d0197c27ebc7de671b00458a9ff45f57223aeb520e6ddd2eb6d2d89e5c\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on the OpenZeppelin IER20 interface:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol\\n *\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n /**\\n * @dev Returns the amount of tokens in existence.\\n */\\n function totalSupply() external view returns (uint256);\\n\\n /**\\n * @dev Returns the amount of tokens owned by `account`.\\n */\\n function balanceOf(address account) external view returns (uint256);\\n\\n /**\\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transfer(address recipient, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Returns the remaining number of tokens that `spender` will be\\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n * zero by default.\\n *\\n * This value changes when {approve} or {transferFrom} are called.\\n */\\n function allowance(address owner, address spender) external view returns (uint256);\\n function increaseAllowance(address spender, uint256 addedValue) external returns (bool);\\n function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);\\n\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n * that someone may use both the old and the new allowance by unfortunate\\n * transaction ordering. One possible solution to mitigate this race\\n * condition is to first reduce the spender's allowance to 0 and set the\\n * desired value afterwards:\\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n *\\n * Emits an {Approval} event.\\n */\\n function approve(address spender, uint256 amount) external returns (bool);\\n\\n /**\\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\\n * allowance mechanism. `amount` is then deducted from the caller's\\n * allowance.\\n *\\n * Returns a boolean value indicating whether the operation succeeded.\\n *\\n * Emits a {Transfer} event.\\n */\\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\\n\\n function name() external view returns (string memory);\\n function symbol() external view returns (string memory);\\n function decimals() external view returns (uint8);\\n \\n /**\\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n * another (`to`).\\n *\\n * Note that `value` may be zero.\\n */\\n event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n /**\\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n * a call to {approve}. `value` is the new allowance.\\n */\\n event Approval(address indexed owner, address indexed spender, uint256 value);\\n}\",\"keccak256\":\"0xe0b2473eba89df8d27d7cea2a99fce788c212f3fd393c9508e449e51a3f220fa\",\"license\":\"MIT\"},\"contracts/Dependencies/IERC2612.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * @dev Interface of the ERC2612 standard as defined in the EIP.\\n *\\n * Adds the {permit} method, which can be used to change one's\\n * {IERC20-allowance} without having to send a transaction, by signing a\\n * message. This allows users to spend tokens without having to hold Ether.\\n *\\n * See https://eips.ethereum.org/EIPS/eip-2612.\\n * \\n * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/\\n */\\ninterface IERC2612 {\\n /**\\n * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,\\n * given `owner`'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `owner` cannot be the zero address.\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n */\\n function permit(address owner, address spender, uint256 amount, \\n uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;\\n \\n /**\\n * @dev Returns the current ERC2612 nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases `owner`'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n *\\n * `owner` can limit the time a Permit is valid for by setting `deadline` to \\n * a value in the near future. The deadline argument can be set to uint(-1) to \\n * create Permits that effectively never expire.\\n */\\n function nonces(address owner) external view returns (uint256);\\n \\n function version() external view returns (string memory);\\n function permitTypeHash() external view returns (bytes32);\\n function domainSeparator() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xd376458452f8b480bfea549637bd71d3f9eb1f12e9d59d1beff373417462d67f\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./BaseMath.sol\\\";\\nimport \\\"./LiquityMath.sol\\\";\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IPriceFeed.sol\\\";\\nimport \\\"../Interfaces/ILiquityBase.sol\\\";\\nimport \\\"../Interfaces/ILiquityBaseParams.sol\\\";\\n\\n/**\\n * Base contract for TroveManager, BorrowerOperations and StabilityPool. Contains global system constants and\\n * common functions.\\n */\\ncontract LiquityBase is BaseMath, ILiquityBase {\\n using SafeMath for uint256;\\n\\n uint256 public constant _100pct = 1000000000000000000; // 1e18 == 100%\\n\\n /// Amount of ZUSD to be locked in gas pool on opening troves\\n uint256 public constant ZUSD_GAS_COMPENSATION = 20e18;\\n\\n /// Minimum amount of net ZUSD debt a trove must have\\n uint256 public constant MIN_NET_DEBT = 180e18;\\n\\n IActivePool public activePool;\\n\\n IDefaultPool public defaultPool;\\n\\n IPriceFeed public override priceFeed;\\n\\n ILiquityBaseParams public override liquityBaseParams;\\n\\n // --- Gas compensation functions ---\\n\\n // Returns the composite debt (drawn debt + gas compensation) of a trove, for the purpose of ICR calculation\\n function _getCompositeDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.add(ZUSD_GAS_COMPENSATION);\\n }\\n\\n function _getNetDebt(uint256 _debt) internal pure returns (uint256) {\\n return _debt.sub(ZUSD_GAS_COMPENSATION);\\n }\\n\\n /// Return the amount of ETH to be drawn from a trove's collateral and sent as gas compensation.\\n function _getCollGasCompensation(uint256 _entireColl) internal view returns (uint256) {\\n return _entireColl / liquityBaseParams.PERCENT_DIVISOR();\\n }\\n\\n function getEntireSystemColl() public view returns (uint256 entireSystemColl) {\\n uint256 activeColl = activePool.getETH();\\n uint256 liquidatedColl = defaultPool.getETH();\\n\\n return activeColl.add(liquidatedColl);\\n }\\n\\n function getEntireSystemDebt() public view returns (uint256 entireSystemDebt) {\\n uint256 activeDebt = activePool.getZUSDDebt();\\n uint256 closedDebt = defaultPool.getZUSDDebt();\\n\\n return activeDebt.add(closedDebt);\\n }\\n\\n function _getTCR(uint256 _price) internal view returns (uint256 TCR) {\\n uint256 entireSystemColl = getEntireSystemColl();\\n uint256 entireSystemDebt = getEntireSystemDebt();\\n\\n TCR = LiquityMath._computeCR(entireSystemColl, entireSystemDebt, _price);\\n\\n return TCR;\\n }\\n\\n function _checkRecoveryMode(uint256 _price) internal view returns (bool) {\\n uint256 TCR = _getTCR(_price);\\n\\n return TCR < liquityBaseParams.CCR();\\n }\\n\\n function _requireUserAcceptsFee(\\n uint256 _fee,\\n uint256 _amount,\\n uint256 _maxFeePercentage\\n ) internal pure {\\n uint256 feePercentage = _fee.mul(DECIMAL_PRECISION).div(_amount);\\n require(feePercentage <= _maxFeePercentage, \\\"Fee exceeded provided maximum\\\");\\n }\\n}\\n\",\"keccak256\":\"0x100b8a1c17caa95f5c9977e88f9263847a1977a365ca0a795753dd74aa1d6d7c\",\"license\":\"MIT\"},\"contracts/Dependencies/LiquityMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./SafeMath.sol\\\";\\nimport \\\"./console.sol\\\";\\n\\nlibrary LiquityMath {\\n using SafeMath for uint;\\n\\n uint internal constant DECIMAL_PRECISION = 1e18;\\n\\n /* Precision for Nominal ICR (independent of price). Rationale for the value:\\n *\\n * - Making it \\u201ctoo high\\u201d could lead to overflows.\\n * - Making it \\u201ctoo low\\u201d could lead to an ICR equal to zero, due to truncation from Solidity floor division. \\n *\\n * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH,\\n * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.\\n *\\n */\\n uint internal constant NICR_PRECISION = 1e20;\\n\\n function _min(uint _a, uint _b) internal pure returns (uint) {\\n return (_a < _b) ? _a : _b;\\n }\\n\\n function _max(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a : _b;\\n }\\n\\n /* \\n * Multiply two decimal numbers and use normal rounding rules:\\n * -round product up if 19'th mantissa digit >= 5\\n * -round product down if 19'th mantissa digit < 5\\n *\\n * Used only inside the exponentiation, _decPow().\\n */\\n function decMul(uint x, uint y) internal pure returns (uint decProd) {\\n uint prod_xy = x.mul(y);\\n\\n decProd = prod_xy.add(DECIMAL_PRECISION / 2).div(DECIMAL_PRECISION);\\n }\\n\\n /* \\n * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.\\n * \\n * Uses the efficient \\\"exponentiation by squaring\\\" algorithm. O(log(n)) complexity. \\n * \\n * Called by two functions that represent time in units of minutes:\\n * 1) TroveManager._calcDecayedBaseRate\\n * 2) CommunityIssuance._getCumulativeIssuanceFraction \\n * \\n * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals\\n * \\\"minutes in 1000 years\\\": 60 * 24 * 365 * 1000\\n * \\n * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be\\n * negligibly different from just passing the cap, since: \\n *\\n * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years\\n * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible\\n */\\n function _decPow(uint _base, uint _minutes) internal pure returns (uint) {\\n \\n if (_minutes > 525600000) {_minutes = 525600000;} // cap to avoid overflow\\n \\n if (_minutes == 0) {return DECIMAL_PRECISION;}\\n\\n uint y = DECIMAL_PRECISION;\\n uint x = _base;\\n uint n = _minutes;\\n\\n // Exponentiation-by-squaring\\n while (n > 1) {\\n if (n % 2 == 0) {\\n x = decMul(x, x);\\n n = n.div(2);\\n } else { // if (n % 2 != 0)\\n y = decMul(x, y);\\n x = decMul(x, x);\\n n = (n.sub(1)).div(2);\\n }\\n }\\n\\n return decMul(x, y);\\n }\\n\\n function _getAbsoluteDifference(uint _a, uint _b) internal pure returns (uint) {\\n return (_a >= _b) ? _a.sub(_b) : _b.sub(_a);\\n }\\n\\n function _computeNominalCR(uint _coll, uint _debt) internal pure returns (uint) {\\n if (_debt > 0) {\\n return _coll.mul(NICR_PRECISION).div(_debt);\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1;\\n }\\n }\\n\\n function _computeCR(uint _coll, uint _debt, uint _price) internal pure returns (uint) {\\n if (_debt > 0) {\\n uint newCollRatio = _coll.mul(_price).div(_debt);\\n\\n return newCollRatio;\\n }\\n // Return the maximal value for uint256 if the Trove has a debt of 0. Represents \\\"infinite\\\" CR.\\n else { // if (_debt == 0)\\n return 2**256 - 1; \\n }\\n }\\n}\\n\",\"keccak256\":\"0x7a95ed70d8937e0896c054b433ad0dfc87a9cfd028cae1694098e9d5d68127cd\",\"license\":\"MIT\"},\"contracts/Dependencies/Mynt/IMassetManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IMassetManager {\\n struct PermitParams {\\n uint256 deadline;\\n uint8 v;\\n bytes32 r;\\n bytes32 s;\\n }\\n\\n function mintTo(\\n address _bAsset,\\n uint256 _bAssetQuantity,\\n address _recipient\\n ) external returns (uint256);\\n\\n function getToken() external view returns (address);\\n\\n /**\\n * @dev Credits a recipient with a certain quantity of selected bAsset, in exchange for burning the\\n * relative mAsset quantity from the sender. Sender also incurs a small fee, if any.\\n * @param _bAsset Address of the bAsset to redeem.\\n * @param _massetQuantity Units of the masset to redeem.\\n * @param _recipient Address to credit with withdrawn bAssets.\\n * @return massetRedeemed Relative number of mAsset units burned to pay for the bAssets.\\n */\\n function redeemTo(\\n address _bAsset,\\n uint256 _massetQuantity,\\n address _recipient\\n ) external returns (uint256 massetRedeemed);\\n}\\n\",\"keccak256\":\"0x3e8de462d45e8f07ef83b6b6e7eb90a5d09f21d3bcbb1225e8f781488ab4a771\",\"license\":\"MIT\"},\"contracts/Dependencies/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's Ownable contract:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol\\n *\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\ncontract Ownable {\\n bytes32 private constant KEY_OWNER = keccak256(\\\"key.ownable.owner\\\");\\n\\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n /**\\n * @dev Initializes the contract setting the deployer as the initial owner.\\n */\\n constructor () internal {\\n _setOwner(msg.sender);\\n }\\n\\n /**\\n * @dev Throws if called by any account other than the owner.\\n */\\n modifier onlyOwner() {\\n require(msg.sender == getOwner(), \\\"Ownable:: access denied\\\");\\n _;\\n }\\n\\n /**\\n * @notice Set address of the owner.\\n * @param _owner Address of the owner.\\n * */\\n function _setOwner(address _owner) internal {\\n require(_owner != address(0), \\\"Ownable::setOwner: invalid address\\\");\\n emit OwnershipTransferred(getOwner(), _owner);\\n\\n bytes32 key = KEY_OWNER;\\n assembly {\\n sstore(key, _owner)\\n }\\n }\\n\\n /**\\n * @notice Set address of the owner (only owner can call this function)\\n * @param _owner Address of the owner.\\n * */\\n function setOwner(address _owner) public onlyOwner {\\n _setOwner(_owner);\\n }\\n\\n /**\\n * @notice Return address of the owner.\\n * @return _owner Address of the owner.\\n * */\\n function getOwner() public view returns (address _owner) {\\n bytes32 key = KEY_OWNER;\\n assembly {\\n _owner := sload(key)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xb5fc626e0b227fc0feb1d84440585015a0a5f586547d298534a604dd113efec6\",\"license\":\"MIT\"},\"contracts/Dependencies/SafeMath.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/**\\n * Based on OpenZeppelin's SafeMath:\\n * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol\\n *\\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\\n * checks.\\n *\\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\\n * in bugs, because programmers usually assume that an overflow raises an\\n * error, which is the standard behavior in high level programming languages.\\n * `SafeMath` restores this intuition by reverting the transaction when an\\n * operation overflows.\\n *\\n * Using this library instead of the unchecked operations eliminates an entire\\n * class of bugs, so it's recommended to use it always.\\n */\\nlibrary SafeMath {\\n /**\\n * @dev Returns the addition of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `+` operator.\\n *\\n * Requirements:\\n * - Addition cannot overflow.\\n */\\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\\n uint256 c = a + b;\\n require(c >= a, \\\"SafeMath: addition overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n */\\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\\n return sub(a, b, \\\"SafeMath: subtraction overflow\\\");\\n }\\n\\n /**\\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\\n * overflow (when the result is negative).\\n *\\n * Counterpart to Solidity's `-` operator.\\n *\\n * Requirements:\\n * - Subtraction cannot overflow.\\n *\\n * _Available since v2.4.0._\\n */\\n function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b <= a, errorMessage);\\n uint256 c = a - b;\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the multiplication of two unsigned integers, reverting on\\n * overflow.\\n *\\n * Counterpart to Solidity's `*` operator.\\n *\\n * Requirements:\\n * - Multiplication cannot overflow.\\n */\\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\\n // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\\n // benefit is lost if 'b' is also tested.\\n // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\\n if (a == 0) {\\n return 0;\\n }\\n\\n uint256 c = a * b;\\n require(c / a == b, \\\"SafeMath: multiplication overflow\\\");\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function div(uint256 a, uint256 b) internal pure returns (uint256) {\\n return div(a, b, \\\"SafeMath: division by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\\n * division by zero. The result is rounded towards zero.\\n *\\n * Counterpart to Solidity's `/` operator. Note: this function uses a\\n * `revert` opcode (which leaves remaining gas untouched) while Solidity\\n * uses an invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n // Solidity only automatically asserts when dividing by 0\\n require(b > 0, errorMessage);\\n uint256 c = a / b;\\n // assert(a == b * c + a % b); // There is no case in which this doesn't hold\\n\\n return c;\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n */\\n function mod(uint256 a, uint256 b) internal pure returns (uint256) {\\n return mod(a, b, \\\"SafeMath: modulo by zero\\\");\\n }\\n\\n /**\\n * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\\n * Reverts with custom message when dividing by zero.\\n *\\n * Counterpart to Solidity's `%` operator. This function uses a `revert`\\n * opcode (which leaves remaining gas untouched) while Solidity uses an\\n * invalid opcode to revert (consuming all remaining gas).\\n *\\n * Requirements:\\n * - The divisor cannot be zero.\\n *\\n * _Available since v2.4.0._\\n */\\n function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\\n require(b != 0, errorMessage);\\n return a % b;\\n }\\n}\\n\",\"keccak256\":\"0x666b890992a066cc791f36c2975cd595d9761a014c654c385ed36ffaf658f3fd\",\"license\":\"MIT\"},\"contracts/Dependencies/TroveManagerBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Interfaces/IActivePool.sol\\\";\\nimport \\\"../Interfaces/IDefaultPool.sol\\\";\\nimport \\\"../Interfaces/IZUSDToken.sol\\\";\\nimport \\\"../Interfaces/IZEROStaking.sol\\\";\\nimport \\\"../Interfaces/ISortedTroves.sol\\\";\\nimport \\\"../Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"../TroveManagerStorage.sol\\\";\\nimport \\\"./LiquityBase.sol\\\";\\n\\ncontract TroveManagerBase is LiquityBase, TroveManagerStorage {\\n uint256 public constant SECONDS_IN_ONE_MINUTE = 60;\\n\\n uint256 public constant MINUTE_DECAY_FACTOR = 999037758833783000;\\n\\n /// During bootsrap period redemptions are not allowed\\n uint256 public immutable BOOTSTRAP_PERIOD;\\n\\n /**\\n BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption.\\n Corresponds to (1 / ALPHA) in the white paper.\\n */\\n uint256 public constant BETA = 2;\\n\\n /**\\n --- Variable container structs for liquidations ---\\n \\n These structs are used to hold, return and assign variables inside the liquidation functions,\\n in order to avoid the error: \\\"CompilerError: Stack too deep\\\".\\n */\\n\\n struct LocalVariables_OuterLiquidationFunction {\\n uint256 price;\\n uint256 ZUSDInStabPool;\\n bool recoveryModeAtStart;\\n uint256 liquidatedDebt;\\n uint256 liquidatedColl;\\n }\\n\\n struct LocalVariables_InnerSingleLiquidateFunction {\\n uint256 collToLiquidate;\\n uint256 pendingDebtReward;\\n uint256 pendingCollReward;\\n }\\n\\n struct LocalVariables_LiquidationSequence {\\n uint256 remainingZUSDInStabPool;\\n uint256 i;\\n uint256 ICR;\\n address user;\\n bool backToNormalMode;\\n uint256 entireSystemDebt;\\n uint256 entireSystemColl;\\n }\\n\\n struct LiquidationValues {\\n uint256 entireTroveDebt;\\n uint256 entireTroveColl;\\n uint256 collGasCompensation;\\n uint256 ZUSDGasCompensation;\\n uint256 debtToOffset;\\n uint256 collToSendToSP;\\n uint256 debtToRedistribute;\\n uint256 collToRedistribute;\\n uint256 collSurplus;\\n }\\n\\n struct LiquidationTotals {\\n uint256 totalCollInSequence;\\n uint256 totalDebtInSequence;\\n uint256 totalCollGasCompensation;\\n uint256 totalZUSDGasCompensation;\\n uint256 totalDebtToOffset;\\n uint256 totalCollToSendToSP;\\n uint256 totalDebtToRedistribute;\\n uint256 totalCollToRedistribute;\\n uint256 totalCollSurplus;\\n }\\n\\n struct ContractsCache {\\n IActivePool activePool;\\n IDefaultPool defaultPool;\\n IZUSDToken zusdToken;\\n IZEROStaking zeroStaking;\\n ISortedTroves sortedTroves;\\n ICollSurplusPool collSurplusPool;\\n address gasPoolAddress;\\n }\\n // --- Variable container structs for redemptions ---\\n\\n struct RedemptionTotals {\\n uint256 remainingZUSD;\\n uint256 totalZUSDToRedeem;\\n uint256 totalETHDrawn;\\n uint256 ETHFee;\\n uint256 ETHToSendToRedeemer;\\n uint256 decayedBaseRate;\\n uint256 price;\\n uint256 totalZUSDSupplyAtStart;\\n }\\n\\n struct SingleRedemptionValues {\\n uint256 ZUSDLot;\\n uint256 ETHLot;\\n bool cancelledPartial;\\n }\\n\\n // --- Events ---\\n\\n event Liquidation(\\n uint256 _liquidatedDebt,\\n uint256 _liquidatedColl,\\n uint256 _collGasCompensation,\\n uint256 _ZUSDGasCompensation\\n );\\n event Redemption(\\n uint256 _attemptedZUSDAmount,\\n uint256 _actualZUSDAmount,\\n uint256 _ETHSent,\\n uint256 _ETHFee\\n );\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 _stake,\\n TroveManagerOperation _operation\\n );\\n event TroveLiquidated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n TroveManagerOperation _operation\\n );\\n event BaseRateUpdated(uint256 _baseRate);\\n event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);\\n event TotalStakesUpdated(uint256 _newTotalStakes);\\n event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);\\n event LTermsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveIndexUpdated(address _borrower, uint256 _newIndex);\\n\\n enum TroveManagerOperation {\\n applyPendingRewards,\\n liquidateInNormalMode,\\n liquidateInRecoveryMode,\\n redeemCollateral\\n }\\n\\n constructor(uint256 _bootstrapPeriod) public {\\n BOOTSTRAP_PERIOD = _bootstrapPeriod;\\n }\\n\\n /// Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function _getCurrentICR(address _borrower, uint256 _price) public view returns (uint256) {\\n (uint256 currentETH, uint256 currentZUSDDebt) = _getCurrentTroveAmounts(_borrower);\\n\\n uint256 ICR = LiquityMath._computeCR(currentETH, currentZUSDDebt, _price);\\n return ICR;\\n }\\n\\n function _getCurrentTroveAmounts(address _borrower) internal view returns (uint256, uint256) {\\n uint256 pendingETHReward = _getPendingETHReward(_borrower);\\n uint256 pendingZUSDDebtReward = _getPendingZUSDDebtReward(_borrower);\\n\\n uint256 currentETH = Troves[_borrower].coll.add(pendingETHReward);\\n uint256 currentZUSDDebt = Troves[_borrower].debt.add(pendingZUSDDebtReward);\\n\\n return (currentETH, currentZUSDDebt);\\n }\\n\\n /// Get the borrower's pending accumulated ETH reward, earned by their stake\\n function _getPendingETHReward(address _borrower) public view returns (uint256) {\\n uint256 snapshotETH = rewardSnapshots[_borrower].ETH;\\n uint256 rewardPerUnitStaked = L_ETH.sub(snapshotETH);\\n\\n if (rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) {\\n return 0;\\n }\\n\\n uint256 stake = Troves[_borrower].stake;\\n\\n uint256 pendingETHReward = stake.mul(rewardPerUnitStaked).div(DECIMAL_PRECISION);\\n\\n return pendingETHReward;\\n }\\n\\n /// Get the borrower's pending accumulated ZUSD reward, earned by their stake\\n function _getPendingZUSDDebtReward(address _borrower) public view returns (uint256) {\\n uint256 snapshotZUSDDebt = rewardSnapshots[_borrower].ZUSDDebt;\\n uint256 rewardPerUnitStaked = L_ZUSDDebt.sub(snapshotZUSDDebt);\\n\\n if (rewardPerUnitStaked == 0 || Troves[_borrower].status != Status.active) {\\n return 0;\\n }\\n\\n uint256 stake = Troves[_borrower].stake;\\n\\n uint256 pendingZUSDDebtReward = stake.mul(rewardPerUnitStaked).div(DECIMAL_PRECISION);\\n\\n return pendingZUSDDebtReward;\\n }\\n\\n /// Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\\n function _applyPendingRewards(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n address _borrower\\n ) internal {\\n if (_hasPendingRewards(_borrower)) {\\n _requireTroveIsActive(_borrower);\\n\\n // Compute pending rewards\\n uint256 pendingETHReward = _getPendingETHReward(_borrower);\\n uint256 pendingZUSDDebtReward = _getPendingZUSDDebtReward(_borrower);\\n\\n // Apply pending rewards to trove's state\\n Troves[_borrower].coll = Troves[_borrower].coll.add(pendingETHReward);\\n Troves[_borrower].debt = Troves[_borrower].debt.add(pendingZUSDDebtReward);\\n\\n _updateTroveRewardSnapshots(_borrower);\\n\\n // Transfer from DefaultPool to ActivePool\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n pendingZUSDDebtReward,\\n pendingETHReward\\n );\\n\\n emit TroveUpdated(\\n _borrower,\\n Troves[_borrower].debt,\\n Troves[_borrower].coll,\\n Troves[_borrower].stake,\\n TroveManagerOperation.applyPendingRewards\\n );\\n }\\n }\\n\\n function _hasPendingRewards(address _borrower) public view returns (bool) {\\n /*\\n * A Trove has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:\\n * this indicates that rewards have occured since the snapshot was made, and the user therefore has\\n * pending rewards\\n */\\n if (Troves[_borrower].status != Status.active) {\\n return false;\\n }\\n\\n return (rewardSnapshots[_borrower].ETH < L_ETH);\\n }\\n\\n function _updateTroveRewardSnapshots(address _borrower) internal {\\n rewardSnapshots[_borrower].ETH = L_ETH;\\n rewardSnapshots[_borrower].ZUSDDebt = L_ZUSDDebt;\\n emit TroveSnapshotsUpdated(L_ETH, L_ZUSDDebt);\\n }\\n\\n /// Move a Trove's pending debt and collateral rewards from distributions, from the Default Pool to the Active Pool\\n function _movePendingTroveRewardsToActivePool(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _ZUSD,\\n uint256 _ETH\\n ) internal {\\n _defaultPool.decreaseZUSDDebt(_ZUSD);\\n _activePool.increaseZUSDDebt(_ZUSD);\\n _defaultPool.sendETHToActivePool(_ETH);\\n }\\n\\n /// Remove borrower's stake from the totalStakes sum, and set their stake to 0\\n function _removeStake(address _borrower) internal {\\n uint256 stake = Troves[_borrower].stake;\\n totalStakes = totalStakes.sub(stake);\\n Troves[_borrower].stake = 0;\\n }\\n\\n function _closeTrove(address _borrower, Status closedStatus) internal {\\n assert(closedStatus != Status.nonExistent && closedStatus != Status.active);\\n\\n uint256 TroveOwnersArrayLength = TroveOwners.length;\\n _requireMoreThanOneTroveInSystem(TroveOwnersArrayLength);\\n\\n Troves[_borrower].status = closedStatus;\\n Troves[_borrower].coll = 0;\\n Troves[_borrower].debt = 0;\\n\\n rewardSnapshots[_borrower].ETH = 0;\\n rewardSnapshots[_borrower].ZUSDDebt = 0;\\n\\n _removeTroveOwner(_borrower, TroveOwnersArrayLength);\\n sortedTroves.remove(_borrower);\\n }\\n\\n /// Update borrower's stake based on their latest collateral value\\n function _updateStakeAndTotalStakes(address _borrower) internal returns (uint256) {\\n uint256 newStake = _computeNewStake(Troves[_borrower].coll);\\n uint256 oldStake = Troves[_borrower].stake;\\n Troves[_borrower].stake = newStake;\\n\\n totalStakes = totalStakes.sub(oldStake).add(newStake);\\n emit TotalStakesUpdated(totalStakes);\\n\\n return newStake;\\n }\\n\\n // Calculate a new stake based on the snapshots of the totalStakes and totalCollateral taken at the last liquidation\\n function _computeNewStake(uint256 _coll) internal view returns (uint256) {\\n uint256 stake;\\n if (totalCollateralSnapshot == 0) {\\n stake = _coll;\\n } else {\\n /*\\n * The following assert() holds true because:\\n * - The system always contains >= 1 trove\\n * - When we close or liquidate a trove, we redistribute the pending rewards, so if all troves were closed/liquidated,\\n * rewards would\\u2019ve been emptied and totalCollateralSnapshot would be zero too.\\n */\\n assert(totalStakesSnapshot > 0);\\n stake = _coll.mul(totalStakesSnapshot).div(totalCollateralSnapshot);\\n }\\n return stake;\\n }\\n\\n function _calcDecayedBaseRate() internal view returns (uint256) {\\n uint256 minutesPassed = _minutesPassedSinceLastFeeOp();\\n uint256 decayFactor = LiquityMath._decPow(MINUTE_DECAY_FACTOR, minutesPassed);\\n\\n return baseRate.mul(decayFactor).div(DECIMAL_PRECISION);\\n }\\n\\n function _minutesPassedSinceLastFeeOp() internal view returns (uint256) {\\n return (block.timestamp.sub(lastFeeOperationTime)).div(SECONDS_IN_ONE_MINUTE);\\n }\\n\\n // Update the last fee operation time only if time passed >= decay interval. This prevents base rate griefing.\\n function _updateLastFeeOpTime() internal {\\n uint256 timePassed = block.timestamp.sub(lastFeeOperationTime);\\n\\n if (timePassed >= SECONDS_IN_ONE_MINUTE) {\\n lastFeeOperationTime = block.timestamp;\\n emit LastFeeOpTimeUpdated(block.timestamp);\\n }\\n }\\n\\n function _calcRedemptionFee(\\n uint256 _redemptionRate,\\n uint256 _ETHDrawn\\n ) internal pure returns (uint256) {\\n uint256 redemptionFee = _redemptionRate.mul(_ETHDrawn).div(DECIMAL_PRECISION);\\n require(\\n redemptionFee < _ETHDrawn,\\n \\\"TroveManager: Fee would eat up all returned collateral\\\"\\n );\\n return redemptionFee;\\n }\\n\\n function _getRedemptionRate() public view returns (uint256) {\\n return _calcRedemptionRate(baseRate);\\n }\\n\\n function _getRedemptionFee(uint256 _ETHDrawn) internal view returns (uint256) {\\n return _calcRedemptionFee(_getRedemptionRate(), _ETHDrawn);\\n }\\n\\n function _calcRedemptionRate(uint256 _baseRate) internal view returns (uint256) {\\n return\\n LiquityMath._min(\\n liquityBaseParams.REDEMPTION_FEE_FLOOR().add(_baseRate),\\n DECIMAL_PRECISION // cap at a maximum of 100%\\n );\\n }\\n\\n /**\\n Remove a Trove owner from the TroveOwners array, not preserving array order. Removing owner 'B' does the following:\\n [A B C D E] => [A E C D], and updates E's Trove struct to point to its new array index.\\n */\\n function _removeTroveOwner(address _borrower, uint256 TroveOwnersArrayLength) internal {\\n Status troveStatus = Troves[_borrower].status;\\n // It\\u2019s set in caller function `_closeTrove`\\n assert(troveStatus != Status.nonExistent && troveStatus != Status.active);\\n\\n uint128 index = Troves[_borrower].arrayIndex;\\n uint256 length = TroveOwnersArrayLength;\\n uint256 idxLast = length.sub(1);\\n\\n assert(index <= idxLast);\\n\\n address addressToMove = TroveOwners[idxLast];\\n\\n TroveOwners[index] = addressToMove;\\n Troves[addressToMove].arrayIndex = index;\\n emit TroveIndexUpdated(addressToMove, index);\\n\\n TroveOwners.pop();\\n }\\n\\n // --- 'require' wrapper functions ---\\n\\n function _requireCallerIsBorrowerOperations() internal view {\\n require(\\n msg.sender == borrowerOperationsAddress,\\n \\\"TroveManager: Caller is not the BorrowerOperations contract\\\"\\n );\\n }\\n\\n function _requireTroveIsActive(address _borrower) internal view {\\n require(\\n Troves[_borrower].status == Status.active,\\n \\\"TroveManager: Trove does not exist or is closed\\\"\\n );\\n }\\n\\n function _requireZUSDBalanceCoversRedemption(\\n IZUSDToken _zusdToken,\\n address _redeemer,\\n uint256 _amount\\n ) internal view {\\n require(\\n _zusdToken.balanceOf(_redeemer) >= _amount,\\n \\\"TroveManager: Requested redemption amount must be <= user's ZUSD token balance\\\"\\n );\\n }\\n\\n function _requireMoreThanOneTroveInSystem(uint256 TroveOwnersArrayLength) internal view {\\n require(\\n TroveOwnersArrayLength > 1 && sortedTroves.getSize() > 1,\\n \\\"TroveManager: Only one trove in the system\\\"\\n );\\n }\\n\\n function _requireAmountGreaterThanZero(uint256 _amount) internal pure {\\n require(_amount > 0, \\\"TroveManager: Amount must be greater than zero\\\");\\n }\\n\\n function _requireTCRoverMCR(uint256 _price) internal view {\\n require(\\n _getTCR(_price) >= liquityBaseParams.MCR(),\\n \\\"TroveManager: Cannot redeem when TCR < MCR\\\"\\n );\\n }\\n\\n function _requireAfterBootstrapPeriod() internal view {\\n uint256 systemDeploymentTime = _zeroToken.getDeploymentStartTime();\\n require(\\n block.timestamp >= systemDeploymentTime.add(BOOTSTRAP_PERIOD),\\n \\\"TroveManager: Redemptions are not allowed during bootstrap phase\\\"\\n );\\n }\\n\\n function _requireValidMaxFeePercentage(uint256 _maxFeePercentage) internal view {\\n require(\\n _maxFeePercentage >= liquityBaseParams.REDEMPTION_FEE_FLOOR() &&\\n _maxFeePercentage <= DECIMAL_PRECISION,\\n \\\"Max fee percentage must be between 0.5% and 100%\\\"\\n );\\n }\\n}\\n\",\"keccak256\":\"0x83e1bfaa93cf973052c41df1cc0741a93f737659cd664f207c0d42256f78617b\",\"license\":\"MIT\"},\"contracts/Dependencies/console.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Buidler's helper contract for console logging\\nlibrary console {\\n\\taddress constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);\\n\\n\\tfunction log() internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log()\\\"));\\n\\t\\tignored;\\n\\t}\\tfunction logInt(int p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(int)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logUint(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logString(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBool(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logAddress(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes(bytes memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logByte(byte p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(byte)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes1(bytes1 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes1)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes2(bytes2 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes2)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes3(bytes3 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes3)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes4(bytes4 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes4)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes5(bytes5 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes5)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes6(bytes6 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes6)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes7(bytes7 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes7)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes8(bytes8 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes8)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes9(bytes9 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes9)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes10(bytes10 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes10)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes11(bytes11 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes11)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes12(bytes12 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes12)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes13(bytes13 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes13)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes14(bytes14 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes14)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes15(bytes15 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes15)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes16(bytes16 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes16)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes17(bytes17 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes17)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes18(bytes18 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes18)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes19(bytes19 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes19)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes20(bytes20 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes20)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes21(bytes21 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes21)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes22(bytes22 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes22)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes23(bytes23 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes23)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes24(bytes24 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes24)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes25(bytes25 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes25)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes26(bytes26 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes26)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes27(bytes27 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes27)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes28(bytes28 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes28)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes29(bytes29 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes29)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes30(bytes30 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes30)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes31(bytes31 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes31)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction logBytes32(bytes32 p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bytes32)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address)\\\", p0));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address)\\\", p0, p1));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address)\\\", p0, p1, p2));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(uint p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(uint,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(string memory p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(string,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(bool p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(bool,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, uint p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,uint,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, string memory p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,string,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, bool p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,bool,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, uint p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,uint,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, string memory p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,string,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, bool p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,bool,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, uint p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,uint)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, string memory p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,string)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, bool p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,bool)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n\\tfunction log(address p0, address p1, address p2, address p3) internal view {\\n\\t\\t(bool ignored, ) = CONSOLE_ADDRESS.staticcall(abi.encodeWithSignature(\\\"log(address,address,address,address)\\\", p0, p1, p2, p3));\\n\\t\\tignored;\\n\\t}\\n\\n}\\n\",\"keccak256\":\"0x6fa1de4ffe22b8f58b0b64d65db11dd5037be9b9db47b365a72adb489e217000\",\"license\":\"MIT\"},\"contracts/Interfaces/IActivePool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\n/**\\n * The Active Pool holds the ETH collateral and ZUSD debt (but not ZUSD tokens) for all active troves.\\n *\\n * When a trove is liquidated, it's ETH and ZUSD debt are transferred from the Active Pool, to either the\\n * Stability Pool, the Default Pool, or both, depending on the liquidation conditions.\\n *\\n */\\ninterface IActivePool is IPool {\\n // --- Events ---\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolZUSDDebtUpdated(uint _ZUSDDebt);\\n event ActivePoolETHBalanceUpdated(uint _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH amount to given account. Updates ActivePool balance. Only callable by BorrowerOperations, TroveManager or StabilityPool.\\n /// @param _account account to receive the ETH amount\\n /// @param _amount ETH amount to send\\n function sendETH(address _account, uint _amount) external;\\n}\\n\",\"keccak256\":\"0xdd5f1b6fae4050b4c885a85a10c2d0e73b82187a51736d009065aaeea33bf0d0\",\"license\":\"MIT\"},\"contracts/Interfaces/IAllowanceTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title AllowanceTransfer\\n/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface IAllowanceTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an ordered nonce.\\n event NonceInvalidation(\\n address indexed owner, address indexed token, address indexed spender, uint48 newNonce, uint48 oldNonce\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions on a token for the spender.\\n event Approval(\\n address indexed owner, address indexed token, address indexed spender, uint160 amount, uint48 expiration\\n );\\n\\n /// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.\\n event Permit(\\n address indexed owner,\\n address indexed token,\\n address indexed spender,\\n uint160 amount,\\n uint48 expiration,\\n uint48 nonce\\n );\\n\\n /// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.\\n event Lockdown(address indexed owner, address token, address spender);\\n\\n /// @notice The permit data for a token\\n struct PermitDetails {\\n // ERC20 token address\\n address token;\\n // the maximum amount allowed to spend\\n uint160 amount;\\n // timestamp at which a spender's token allowances become invalid\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice The permit message signed for a single token allowance\\n struct PermitSingle {\\n // the permit data for a single token alownce\\n PermitDetails details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The permit message signed for multiple token allowances\\n struct PermitBatch {\\n // the permit data for multiple token allowances\\n PermitDetails[] details;\\n // address permissioned on the allowed tokens\\n address spender;\\n // deadline on the permit signature\\n uint256 sigDeadline;\\n }\\n\\n /// @notice The saved permissions\\n /// @dev This info is saved per owner, per token, per spender and all signed over in the permit message\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n struct PackedAllowance {\\n // amount allowed\\n uint160 amount;\\n // permission expiry\\n uint48 expiration;\\n // an incrementing value indexed per owner,token,and spender for each signature\\n uint48 nonce;\\n }\\n\\n /// @notice A token spender pair.\\n struct TokenSpenderPair {\\n // the token the spender is approved\\n address token;\\n // the spender address\\n address spender;\\n }\\n\\n /// @notice Details for a token transfer.\\n struct AllowanceTransferDetails {\\n // the owner of the token\\n address from;\\n // the recipient of the token\\n address to;\\n // the amount of the token\\n uint160 amount;\\n // the token to be transferred\\n address token;\\n }\\n\\n /// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.\\n /// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]\\n /// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.\\n function allowance(address user, address token, address spender)\\n external\\n view\\n returns (uint160 amount, uint48 expiration, uint48 nonce);\\n\\n /// @notice Approves the spender to use up to amount of the specified token up until the expiration\\n /// @param token The token to approve\\n /// @param spender The spender address to approve\\n /// @param amount The approved amount of the token\\n /// @param expiration The timestamp at which the approval is no longer valid\\n /// @dev The packed allowance also holds a nonce, which will stay unchanged in approve\\n /// @dev Setting amount to type(uint160).max sets an unlimited approval\\n function approve(address token, address spender, uint160 amount, uint48 expiration) external;\\n\\n /// @notice Permit a spender to a given amount of the owners token via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitSingle Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitSingle memory permitSingle, bytes calldata signature) external;\\n\\n /// @notice Permit a spender to the signed amounts of the owners tokens via the owner's EIP-712 signature\\n /// @dev May fail if the owner's nonce was invalidated in-flight by invalidateNonce\\n /// @param owner The owner of the tokens being approved\\n /// @param permitBatch Data signed over by the owner specifying the terms of approval\\n /// @param signature The owner's signature over the permit data\\n function permit(address owner, PermitBatch memory permitBatch, bytes calldata signature) external;\\n\\n /// @notice Transfer approved tokens from one address to another\\n /// @param from The address to transfer from\\n /// @param to The address of the recipient\\n /// @param amount The amount of the token to transfer\\n /// @param token The token address to transfer\\n /// @dev Requires the from address to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(address from, address to, uint160 amount, address token) external;\\n\\n /// @notice Transfer approved tokens in a batch\\n /// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers\\n /// @dev Requires the from addresses to have approved at least the desired amount\\n /// of tokens to msg.sender.\\n function transferFrom(AllowanceTransferDetails[] calldata transferDetails) external;\\n\\n /// @notice Enables performing a \\\"lockdown\\\" of the sender's Permit2 identity\\n /// by batch revoking approvals\\n /// @param approvals Array of approvals to revoke.\\n function lockdown(TokenSpenderPair[] calldata approvals) external;\\n\\n /// @notice Invalidate nonces for a given (token, spender) pair\\n /// @param token The token to invalidate nonces for\\n /// @param spender The spender to invalidate nonces for\\n /// @param newNonce The new nonce to set. Invalidates all nonces less than it.\\n /// @dev Can't invalidate more than 2**16 nonces per transaction.\\n function invalidateNonces(address token, address spender, uint48 newNonce) external;\\n}\\n\",\"keccak256\":\"0xf15059fb68f89542908f963f22e18c0b0ae9997a6f9aaf6a9fb46aa2424acac9\",\"license\":\"MIT\"},\"contracts/Interfaces/ICollSurplusPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ICollSurplusPool {\\n // --- Events ---\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n\\n event CollBalanceUpdated(address indexed _account, uint256 _newBalance);\\n event EtherSent(address _to, uint256 _amount);\\n\\n // --- Contract setters ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH state variable\\n function getETH() external view returns (uint256);\\n\\n /// @param _account account to retrieve collateral\\n /// @return collateral\\n function getCollateral(address _account) external view returns (uint256);\\n\\n /// @notice adds amount to current account balance. Only callable by TroveManager.\\n /// @param _account account to add amount\\n /// @param _amount amount to add\\n function accountSurplus(address _account, uint256 _amount) external;\\n\\n /// @notice claims collateral for given account. Only callable by BorrowerOperations.\\n /// @param _account account to send claimable collateral\\n function claimColl(address _account) external;\\n}\\n\",\"keccak256\":\"0xac983936efe70d19205bff65a18b4e6000d489d4e4d1e2e92f951873cee91048\",\"license\":\"MIT\"},\"contracts/Interfaces/IDefaultPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPool.sol\\\";\\n\\ninterface IDefaultPool is IPool {\\n // --- Events ---\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event DefaultPoolZUSDDebtUpdated(uint256 _ZUSDDebt);\\n event DefaultPoolETHBalanceUpdated(uint256 _ETH);\\n\\n // --- Functions ---\\n\\n /// @notice Send ETH to Active Pool\\n /// @param _amount ETH to send\\n function sendETHToActivePool(uint256 _amount) external;\\n}\\n\",\"keccak256\":\"0xfb2607676b2eb0f2defd248b4dd32895820048317f29aa6bdb572403a3e3d44e\",\"license\":\"MIT\"},\"contracts/Interfaces/IEIP712.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\n\\ninterface IEIP712 {\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0xff52e9168eaa532ebacdad2ab6197f60171e3aa2fa2c1d6397d9da4d7782a543\",\"license\":\"MIT\"},\"contracts/Interfaces/IFeeDistributor.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n/// Common interface for Fee Distributor.\\ninterface IFeeDistributor {\\n // --- Events ---\\n\\n event FeeSharingCollectorAddressChanged(address _feeSharingCollectorAddress);\\n event ZeroStakingAddressChanged(address _zeroStakingAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event WrbtcAddressChanged(address _wrbtcAddress);\\n event ZUSDTokenAddressChanged(address _zusdTokenAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event ZUSDDistributed(uint256 _zusdDistributedAmount);\\n event RBTCistributed(uint256 _rbtcDistributedAmount);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _feeSharingCollectorAddress FeeSharingCollector address\\n * @param _zeroStakingAddress ZEROStaking contract address\\n * @param _borrowerOperationsAddress borrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _wrbtcAddress wrbtc ERC20 contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _feeSharingCollectorAddress,\\n address _zeroStakingAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _wrbtcAddress,\\n address _zusdTokenAddress,\\n address _activePoolAddress\\n ) external;\\n\\n function distributeFees() external;\\n}\\n\",\"keccak256\":\"0x4b9bc6eaa8a9ea5e0570ffd84c0af2a92e74b001ae1ee1c8518d76382691a07f\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBase.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./IPriceFeed.sol\\\";\\nimport \\\"./ILiquityBaseParams.sol\\\";\\n\\ninterface ILiquityBase {\\n /// @return PriceFeed contract\\n function priceFeed() external view returns (IPriceFeed);\\n\\n /// @return LiquityBaseParams contract\\n function liquityBaseParams() external view returns (ILiquityBaseParams);\\n}\\n\",\"keccak256\":\"0xa4a57bd79e64d56a687c28d2a35c55b733fde8dda2a7ba861606eed3211724e1\",\"license\":\"MIT\"},\"contracts/Interfaces/ILiquityBaseParams.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface ILiquityBaseParams {\\n\\n /// Minimum collateral ratio for individual troves\\n function MCR() external view returns (uint);\\n\\n /// Critical system collateral ratio. If the system's total collateral ratio (TCR) falls below the CCR, Recovery Mode is triggered.\\n function CCR() external view returns (uint);\\n\\n function PERCENT_DIVISOR() external view returns (uint);\\n\\n function BORROWING_FEE_FLOOR() external view returns (uint);\\n\\n /**\\n * Half-life of 12h. 12h = 720 min\\n * (1/2) = d^720 => d = (1/2)^(1/720)\\n */\\n function REDEMPTION_FEE_FLOOR() external view returns (uint);\\n\\n function MAX_BORROWING_FEE() external view returns (uint);\\n\\n}\",\"keccak256\":\"0xef8c0e8ad5d13d604c11b04983ff5bdd41768b646f2b33f45ddd988adec204e0\",\"license\":\"MIT\"},\"contracts/Interfaces/IPermit2.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {ISignatureTransfer} from \\\"./ISignatureTransfer.sol\\\";\\nimport {IAllowanceTransfer} from \\\"./IAllowanceTransfer.sol\\\";\\n\\n/// @notice Permit2 handles signature-based transfers in SignatureTransfer and allowance-based transfers in AllowanceTransfer.\\n/// @dev Users must approve Permit2 before calling any of the transfer functions.\\ninterface IPermit2 is ISignatureTransfer, IAllowanceTransfer {\\n// IPermit2 unifies the two interfaces so users have maximal flexibility with their approval.\\n}\\n\",\"keccak256\":\"0x3df819f5ca8de7324a676839d72e9f44c0f789c41c13bf0a892f3bb98d72ee86\",\"license\":\"MIT\"},\"contracts/Interfaces/IPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the Pools.\\ninterface IPool {\\n // --- Events ---\\n\\n event ETHBalanceUpdated(uint _newBalance);\\n event ZUSDBalanceUpdated(uint _newBalance);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event EtherSent(address _to, uint _amount);\\n\\n // --- Functions ---\\n\\n /// @notice Not necessarily equal to the raw ether balance - ether can be forcibly sent to contracts.\\n /// @return ETH pool balance\\n function getETH() external view returns (uint);\\n\\n /// @return ZUSD debt pool balance\\n function getZUSDDebt() external view returns (uint);\\n\\n /// @notice Increases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to add to the pool debt\\n function increaseZUSDDebt(uint _amount) external;\\n\\n /// @notice Decreases ZUSD debt of the pool.\\n /// @param _amount ZUSD amount to subtract to the pool debt\\n function decreaseZUSDDebt(uint _amount) external;\\n}\\n\",\"keccak256\":\"0x148e87ab38c6176d74f36c9e8989b99e768a7b18d8a045f1f01d6583b986806d\",\"license\":\"MIT\"},\"contracts/Interfaces/IPriceFeed.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IPriceFeed {\\n // --- Events ---\\n event LastGoodPriceUpdated(uint256 _lastGoodPrice);\\n\\n // --- Function ---\\n\\n /// @notice Returns the latest price obtained from the Oracle. Called by Zero functions that require a current price.\\n /// It uses the main price feed and fallback to the backup one in case of an error. If both fail return the last\\n /// good price seen.\\n /// @dev It's also callable by anyone externally\\n /// @return The price\\n function fetchPrice() external returns (uint256);\\n}\\n\",\"keccak256\":\"0x85fd97219a8156209d2cb5c6ae7c5ead01d893db000bf575023fcef0e62f9591\",\"license\":\"MIT\"},\"contracts/Interfaces/ISignatureTransfer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport {IEIP712} from \\\"./IEIP712.sol\\\";\\n\\n/// @title SignatureTransfer\\n/// @notice Handles ERC20 token transfers through signature based actions\\n/// @dev Requires user's token approval on the Permit2 contract\\ninterface ISignatureTransfer is IEIP712 {\\n /// @notice Emits an event when the owner successfully invalidates an unordered nonce.\\n event UnorderedNonceInvalidation(address indexed owner, uint256 word, uint256 mask);\\n\\n /// @notice The token and amount details for a transfer signed in the permit transfer signature\\n struct TokenPermissions {\\n // ERC20 token address\\n address token;\\n // the maximum amount that can be spent\\n uint256 amount;\\n }\\n\\n /// @notice The signed permit message for a single token transfer\\n struct PermitTransferFrom {\\n TokenPermissions permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice Specifies the recipient address and amount for batched transfers.\\n /// @dev Recipients and amounts correspond to the index of the signed token permissions array.\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount.\\n struct SignatureTransferDetails {\\n // recipient address\\n address to;\\n // spender requested amount\\n uint256 requestedAmount;\\n }\\n\\n /// @notice Used to reconstruct the signed permit message for multiple token transfers\\n /// @dev Do not need to pass in spender address as it is required that it is msg.sender\\n /// @dev Note that a user still signs over a spender address\\n struct PermitBatchTransferFrom {\\n // the tokens and corresponding amounts permitted for a transfer\\n TokenPermissions[] permitted;\\n // a unique value for every token owner's signature to prevent signature replays\\n uint256 nonce;\\n // deadline on the permit signature\\n uint256 deadline;\\n }\\n\\n /// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection\\n /// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order\\n /// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce\\n /// @dev It returns a uint256 bitmap\\n /// @dev The index, or wordPosition is capped at type(uint248).max\\n function nonceBitmap(address, uint256) external view returns (uint256);\\n\\n /// @notice Transfers a token using a signed permit message\\n /// @dev Reverts if the requested amount is greater than the permitted signed amount\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails The spender's requested transfer details for the permitted token\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitTransferFrom memory permit,\\n SignatureTransferDetails calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Transfers multiple tokens using a signed permit message\\n /// @param permit The permit data signed over by the owner\\n /// @param owner The owner of the tokens to transfer\\n /// @param transferDetails Specifies the recipient and requested amount for the token transfer\\n /// @param signature The signature to verify\\n function permitTransferFrom(\\n PermitBatchTransferFrom memory permit,\\n SignatureTransferDetails[] calldata transferDetails,\\n address owner,\\n bytes calldata signature\\n ) external;\\n\\n /// @notice Invalidates the bits specified in mask for the bitmap at the word position\\n /// @dev The wordPos is maxed at type(uint248).max\\n /// @param wordPos A number to index the nonceBitmap at\\n /// @param mask A bitmap masked against msg.sender's current bitmap at the word position\\n function invalidateUnorderedNonces(uint256 wordPos, uint256 mask) external;\\n}\\n\",\"keccak256\":\"0x7efc63c119694e23dd76e44a5b125999829026bbc23409de7646a6a45e1ac341\",\"license\":\"MIT\"},\"contracts/Interfaces/ISortedTroves.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\n// Common interface for the SortedTroves Doubly Linked List.\\ninterface ISortedTroves {\\n // --- Events ---\\n\\n event SortedTrovesAddressChanged(address _sortedDoublyLLAddress);\\n event BorrowerOperationsAddressChanged(address _borrowerOperationsAddress);\\n event NodeAdded(address _id, uint256 _NICR);\\n event NodeRemoved(address _id);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts and size. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _size max size of troves list\\n * @param _TroveManagerAddress TroveManager contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n */\\n function setParams(\\n uint256 _size,\\n address _TroveManagerAddress,\\n address _borrowerOperationsAddress\\n ) external;\\n\\n /**\\n * @dev Add a node to the list\\n * @param _id Node's id\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function insert(\\n address _id,\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Remove a node from the list\\n * @param _id Node's id\\n */\\n function remove(address _id) external;\\n\\n /**\\n * @dev Re-insert the node at a new position, based on its new NICR\\n * @param _id Node's id\\n * @param _newICR Node's new NICR\\n * @param _prevId Id of previous node for the new insert position\\n * @param _nextId Id of next node for the new insert position\\n */\\n function reInsert(\\n address _id,\\n uint256 _newICR,\\n address _prevId,\\n address _nextId\\n ) external;\\n\\n /**\\n * @dev Checks if the list contains a node\\n * @param _id Node's id\\n * @return true if list contains a node with given id\\n */\\n function contains(address _id) external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is full\\n * @return true if list is full\\n */\\n function isFull() external view returns (bool);\\n\\n /**\\n * @dev Checks if the list is empty\\n * @return true if list is empty\\n */\\n function isEmpty() external view returns (bool);\\n\\n /**\\n * @return list current size\\n */\\n function getSize() external view returns (uint256);\\n\\n /**\\n * @return list max size\\n */\\n function getMaxSize() external view returns (uint256);\\n\\n /**\\n * @return the first node in the list (node with the largest NICR)\\n */\\n function getFirst() external view returns (address);\\n\\n /**\\n * @return the last node in the list (node with the smallest NICR)\\n */\\n function getLast() external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the next node (with a smaller NICR) in the list for a given node\\n */\\n function getNext(address _id) external view returns (address);\\n\\n /**\\n * @param _id Node's id\\n * @return the previous node (with a larger NICR) in the list for a given node\\n */\\n function getPrev(address _id) external view returns (address);\\n\\n /**\\n * @notice Check if a pair of nodes is a valid insertion point for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function validInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (bool);\\n\\n /**\\n * @notice Find the insert position for a new node with the given NICR\\n * @param _ICR Node's NICR\\n * @param _prevId Id of previous node for the insert position\\n * @param _nextId Id of next node for the insert position\\n */\\n function findInsertPosition(\\n uint256 _ICR,\\n address _prevId,\\n address _nextId\\n ) external view returns (address, address);\\n}\\n\",\"keccak256\":\"0x7328ad009da6230ddea1559564428464a5c3ace2258fb534dfbba5b5a8c7c60d\",\"license\":\"MIT\"},\"contracts/Interfaces/IStabilityPool.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/*\\n * The Stability Pool holds ZUSD tokens deposited by Stability Pool depositors.\\n *\\n * When a trove is liquidated, then depending on system conditions, some of its ZUSD debt gets offset with\\n * ZUSD in the Stability Pool: that is, the offset debt evaporates, and an equal amount of ZUSD tokens in the Stability Pool is burned.\\n *\\n * Thus, a liquidation causes each depositor to receive a ZUSD loss, in proportion to their deposit as a share of total deposits.\\n * They also receive an ETH gain, as the ETH collateral of the liquidated trove is distributed among Stability depositors,\\n * in the same proportion.\\n *\\n * When a liquidation occurs, it depletes every deposit by the same fraction: for example, a liquidation that depletes 40%\\n * of the total ZUSD in the Stability Pool, depletes 40% of each deposit.\\n *\\n * A deposit that has experienced a series of liquidations is termed a \\\"compounded deposit\\\": each liquidation depletes the deposit,\\n * multiplying it by some factor in range ]0,1[\\n *\\n * Please see the implementation spec in the proof document, which closely follows on from the compounded deposit / ETH gain derivations:\\n * https://github.com/liquity/liquity/blob/master/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf\\n *\\n * --- SOV ISSUANCE TO STABILITY POOL DEPOSITORS ---\\n *\\n * An SOV issuance event occurs at every deposit operation, and every liquidation.\\n *\\n * Each deposit is tagged with the address of the front end through which it was made.\\n *\\n * All deposits earn a share of the issued SOV in proportion to the deposit as a share of total deposits. The SOV earned\\n * by a given deposit, is split between the depositor and the front end through which the deposit was made, based on the front end's kickbackRate.\\n *\\n * Please see the system Readme for an overview:\\n * https://github.com/liquity/dev/blob/main/README.md#zero-issuance-to-stability-providers\\n */\\ninterface IStabilityPool {\\n // --- Events ---\\n\\n event StabilityPoolETHBalanceUpdated(uint _newBalance);\\n event StabilityPoolZUSDBalanceUpdated(uint _newBalance);\\n\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event TroveManagerAddressChanged(address _newTroveManagerAddress);\\n event ActivePoolAddressChanged(address _newActivePoolAddress);\\n event DefaultPoolAddressChanged(address _newDefaultPoolAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event SortedTrovesAddressChanged(address _newSortedTrovesAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event CommunityIssuanceAddressChanged(address _newCommunityIssuanceAddress);\\n\\n event P_Updated(uint _P);\\n event S_Updated(uint _S, uint128 _epoch, uint128 _scale);\\n event G_Updated(uint _G, uint128 _epoch, uint128 _scale);\\n event EpochUpdated(uint128 _currentEpoch);\\n event ScaleUpdated(uint128 _currentScale);\\n\\n event FrontEndRegistered(address indexed _frontEnd, uint _kickbackRate);\\n event FrontEndTagSet(address indexed _depositor, address indexed _frontEnd);\\n\\n event DepositSnapshotUpdated(address indexed _depositor, uint _P, uint _S, uint _G);\\n event FrontEndSnapshotUpdated(address indexed _frontEnd, uint _P, uint _G);\\n event UserDepositChanged(address indexed _depositor, uint _newDeposit);\\n event FrontEndStakeChanged(\\n address indexed _frontEnd,\\n uint _newFrontEndStake,\\n address _depositor\\n );\\n\\n event ETHGainWithdrawn(address indexed _depositor, uint _ETH, uint _ZUSDLoss);\\n event SOVPaidToDepositor(address indexed _depositor, uint _SOV);\\n event SOVPaidToFrontEnd(address indexed _frontEnd, uint _SOV);\\n event EtherSent(address _to, uint _amount);\\n\\n event WithdrawFromSpAndConvertToDLLR(\\n address _depositor,\\n uint256 _zusdAmountRequested,\\n uint256 _dllrAmountReceived\\n );\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Liquity contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _liquityBaseParamsAddress LiquidityBaseParams contract address\\n * @param _borrowerOperationsAddress BorrowerOperations contract address\\n * @param _troveManagerAddress TroveManager contract address\\n * @param _activePoolAddress ActivePool contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _sortedTrovesAddress SortedTroves contract address\\n * @param _priceFeedAddress PriceFeed contract address\\n * @param _communityIssuanceAddress CommunityIssuanceAddress\\n */\\n function setAddresses(\\n address _liquityBaseParamsAddress,\\n address _borrowerOperationsAddress,\\n address _troveManagerAddress,\\n address _activePoolAddress,\\n address _zusdTokenAddress,\\n address _sortedTrovesAddress,\\n address _priceFeedAddress,\\n address _communityIssuanceAddress\\n ) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend is registered or zero address\\n * - Sender is not a registered frontend\\n * - _amount is not zero\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Tags the deposit with the provided front end tag param, if it's a new deposit\\n * - Sends depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Increases deposit and tagged front end's stake, and takes new snapshots for each.\\n * @param _amount amount to provide\\n * @param _frontEndTag frontend address to receive accumulated SOV gains\\n */\\n function provideToSP(uint _amount, address _frontEndTag) external;\\n\\n /**\\n * @notice Initial checks:\\n * - _amount is zero or there are no under collateralized troves left in the system\\n * - User has a non zero deposit\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Removes the deposit's front end tag if it is a full withdrawal\\n * - Sends all depositor's accumulated gains (SOV, ETH) to depositor\\n * - Sends the tagged front end's accumulated SOV gains to the tagged front end\\n * - Decreases deposit and tagged front end's stake, and takes new snapshots for each.\\n *\\n * If _amount > userDeposit, the user withdraws all of their compounded deposit.\\n * @param _amount amount to withdraw\\n */\\n function withdrawFromSP(uint _amount) external;\\n\\n /**\\n * @notice Initial checks:\\n * - User has a non zero deposit\\n * - User has an open trove\\n * - User has some ETH gain\\n * ---\\n * - Triggers a SOV issuance, based on time passed since the last issuance. The SOV issuance is shared between *all* depositors and front ends\\n * - Sends all depositor's SOV gain to depositor\\n * - Sends all tagged front end's SOV gain to the tagged front end\\n * - Transfers the depositor's entire ETH gain from the Stability Pool to the caller's trove\\n * - Leaves their compounded deposit in the Stability Pool\\n * - Updates snapshots for deposit and tagged front end stake\\n * @param _upperHint upper trove id hint\\n * @param _lowerHint lower trove id hint\\n */\\n function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Frontend (sender) not already registered\\n * - User (sender) has no deposit\\n * - _kickbackRate is in the range [0, 100%]\\n * ---\\n * Front end makes a one-time selection of kickback rate upon registering\\n * @param _kickbackRate kickback rate selected by frontend\\n */\\n function registerFrontEnd(uint _kickbackRate) external;\\n\\n /**\\n * @notice Initial checks:\\n * - Caller is TroveManager\\n * ---\\n * Cancels out the specified debt against the ZUSD contained in the Stability Pool (as far as possible)\\n * and transfers the Trove's ETH collateral from ActivePool to StabilityPool.\\n * Only called by liquidation functions in the TroveManager.\\n * @param _debt debt to cancel\\n * @param _coll collateral to transfer\\n */\\n function offset(uint _debt, uint _coll) external;\\n\\n /**\\n * @return the total amount of ETH held by the pool, accounted in an internal variable instead of `balance`,\\n * to exclude edge cases like ETH received from a self-destruct.\\n */\\n function getETH() external view returns (uint);\\n\\n /**\\n * @return ZUSD held in the pool. Changes when users deposit/withdraw, and when Trove debt is offset.\\n */\\n function getTotalZUSDDeposits() external view returns (uint);\\n\\n /**\\n * @notice Calculates the ETH gain earned by the deposit since its last snapshots were taken.\\n * @param _depositor address to calculate ETH gain\\n * @return ETH gain from given depositor\\n */\\n function getDepositorETHGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice Calculate the SOV gain earned by a deposit since its last snapshots were taken.\\n * If not tagged with a front end, the depositor gets a 100% cut of what their deposit earned.\\n * Otherwise, their cut of the deposit's earnings is equal to the kickbackRate, set by the front end through\\n * which they made their deposit.\\n * @param _depositor address to calculate ETH gain\\n * @return SOV gain from given depositor\\n */\\n function getDepositorSOVGain(address _depositor) external view returns (uint);\\n\\n /**\\n * @param _frontEnd front end address\\n * @return the SOV gain earned by the front end.\\n */\\n function getFrontEndSOVGain(address _frontEnd) external view returns (uint);\\n\\n /**\\n * @param _depositor depositor address\\n * @return the user's compounded deposit.\\n */\\n function getCompoundedZUSDDeposit(address _depositor) external view returns (uint);\\n\\n /**\\n * @notice The front end's compounded stake is equal to the sum of its depositors' compounded deposits.\\n * @param _frontEnd front end address\\n * @return the front end's compounded stake.\\n */\\n function getCompoundedFrontEndStake(address _frontEnd) external view returns (uint);\\n\\n //DLLR _owner or _spender can convert a specified amount of DLLR into ZUSD via Sovryn Mynt and deposit the ZUSD into the Zero Stability Pool, all in a single transaction\\n function provideToSpFromDLLR(\\n uint _dllrAmount,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function provideToSpFromDllrWithPermit2(\\n uint256 _dllrAmount,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n\\n /// Stability Pool depositor can withdraw a specified amount of ZUSD from the Zero Stability Pool and optionally convert the ZUSD to DLLR via Sovryn Mynt, all in a single transaction\\n function withdrawFromSpAndConvertToDLLR(uint256 _zusdAmount) external;\\n\\n /**\\n * Fallback function\\n * Only callable by Active Pool, it just accounts for ETH received\\n * receive() external payable;\\n */\\n}\\n\",\"keccak256\":\"0xb35c5ec991dd2b4f8ecb6b28ae29e97313fca6054aa0df14ebdb7336fcea84a6\",\"license\":\"MIT\"},\"contracts/Interfaces/ITroveManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./ILiquityBase.sol\\\";\\nimport \\\"./IStabilityPool.sol\\\";\\nimport \\\"./IZUSDToken.sol\\\";\\nimport \\\"./IZEROToken.sol\\\";\\nimport \\\"./IZEROStaking.sol\\\";\\nimport \\\"../Dependencies/Mynt/IMassetManager.sol\\\";\\nimport { IPermit2, ISignatureTransfer } from \\\"./IPermit2.sol\\\";\\n\\n/// Common interface for the Trove Manager.\\ninterface ITroveManager is ILiquityBase {\\n // --- Events ---\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerRedeemOpsAddressChanged(address _troveManagerRedeemOps);\\n event LiquityBaseParamsAddressChanges(address _borrowerOperationsAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZEROTokenAddressChanged(address _zeroTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n event Liquidation(\\n uint256 _liquidatedDebt,\\n uint256 _liquidatedColl,\\n uint256 _collGasCompensation,\\n uint256 _ZUSDGasCompensation\\n );\\n event Redemption(\\n uint256 _attemptedZUSDAmount,\\n uint256 _actualZUSDAmount,\\n uint256 _ETHSent,\\n uint256 _ETHFee\\n );\\n event TroveUpdated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint256 stake,\\n uint8 operation\\n );\\n event TroveLiquidated(\\n address indexed _borrower,\\n uint256 _debt,\\n uint256 _coll,\\n uint8 operation\\n );\\n event BaseRateUpdated(uint256 _baseRate);\\n event LastFeeOpTimeUpdated(uint256 _lastFeeOpTime);\\n event TotalStakesUpdated(uint256 _newTotalStakes);\\n event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);\\n event LTermsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveSnapshotsUpdated(uint256 _L_ETH, uint256 _L_ZUSDDebt);\\n event TroveIndexUpdated(address _borrower, uint256 _newIndex);\\n\\n struct TroveManagerInitAddressesParams {\\n address _feeDistributorAddress;\\n address _troveManagerRedeemOps;\\n address _liquityBaseParamsAddress;\\n address _borrowerOperationsAddress;\\n address _activePoolAddress;\\n address _defaultPoolAddress;\\n address _stabilityPoolAddress;\\n address _gasPoolAddress;\\n address _collSurplusPoolAddress;\\n address _priceFeedAddress;\\n address _zusdTokenAddress;\\n address _sortedTrovesAddress;\\n address _zeroTokenAddress;\\n address _zeroStakingAddress;\\n }\\n\\n // --- Functions ---\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _troveManagerInitAddresses addresses list to intialize TroveManager with _\\n * _feeDistributorAddress feeDistributor contract address\\n * _troveManagerRedeemOps TroveManagerRedeemOps contract address\\n * _liquityBaseParamsAddress LiquityBaseParams contract address\\n * _borrowerOperationsAddress BorrowerOperations contract address\\n * _activePoolAddress ActivePool contract address\\n * _defaultPoolAddress DefaultPool contract address\\n * _stabilityPoolAddress StabilityPool contract address\\n * _gasPoolAddress GasPool contract address\\n * _collSurplusPoolAddress CollSurplusPool contract address\\n * _priceFeedAddress PriceFeed contract address\\n * _zusdTokenAddress ZUSDToken contract address\\n * _sortedTrovesAddress SortedTroves contract address\\n * _zeroTokenAddress ZEROToken contract address\\n * _zeroStakingAddress ZEROStaking contract address\\n */\\n function setAddresses(\\n TroveManagerInitAddressesParams memory _troveManagerInitAddresses\\n ) external;\\n\\n function setTroveManagerRedeemOps(address _troveManagerRedeemOps) external;\\n\\n /// @return Trove owners count\\n function getTroveOwnersCount() external view returns (uint256);\\n\\n /// @param _index Trove owner index\\n /// @return Trove from TroveOwners array in given index\\n function getTroveFromTroveOwnersArray(uint256 _index) external view returns (address);\\n\\n /// @param _borrower borrower address\\n /// @return the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getNominalICR(address _borrower) external view returns (uint256);\\n\\n /// @notice computes the user\\u2019s individual collateralization ratio (ICR) based on their total collateral and total ZUSD debt. Returns 2^256 -1 if they have 0 debt.\\n /// @param _borrower borrower address\\n /// @param _price ETH price\\n /// @return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getCurrentICR(address _borrower, uint256 _price) external view returns (uint256);\\n\\n /// @notice Closes the trove if its ICR is lower than the minimum collateral ratio.\\n /// @param _borrower borrower address\\n function liquidate(address _borrower) external;\\n\\n /**\\n * @notice Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves,\\n * starting from the one with the lowest collateral ratio in the system, and moving upwards\\n * @param _n max number of under-collateralized Troves to liquidate\\n */\\n function liquidateTroves(uint256 _n) external;\\n\\n /**\\n * @notice Attempt to liquidate a custom list of troves provided by the caller.\\n * @param _troveArray list of trove addresses\\n */\\n function batchLiquidateTroves(address[] calldata _troveArray) external;\\n\\n /**\\n * @notice Send _ZUSDamount ZUSD to the system and redeem the corresponding amount of collateral from as many Troves as are needed to fill the redemption\\n * request. Applies pending rewards to a Trove before reducing its debt and coll.\\n *\\n * Note that if _amount is very large, this function can run out of gas, specially if traversed troves are small. This can be easily avoided by\\n * splitting the total _amount in appropriate chunks and calling the function multiple times.\\n *\\n * Param `_maxIterations` can also be provided, so the loop through Troves is capped (if it\\u2019s zero, it will be ignored).This makes it easier to\\n * avoid OOG for the frontend, as only knowing approximately the average cost of an iteration is enough, without needing to know the \\u201ctopology\\u201d\\n * of the trove list. It also avoids the need to set the cap in stone in the contract, nor doing gas calculations, as both gas price and opcode\\n * costs can vary.\\n *\\n * All Troves that are redeemed from -- with the likely exception of the last one -- will end up with no debt left, therefore they will be closed.\\n * If the last Trove does have some remaining debt, it has a finite ICR, and the reinsertion could be anywhere in the list, therefore it requires a hint.\\n * A frontend should use getRedemptionHints() to calculate what the ICR of this Trove will be after redemption, and pass a hint for its position\\n * in the sortedTroves list along with the ICR value that the hint was found for.\\n *\\n * If another transaction modifies the list between calling getRedemptionHints() and passing the hints to redeemCollateral(), it\\n * is very likely that the last (partially) redeemed Trove would end up with a different ICR than what the hint is for. In this case the\\n * redemption will stop after the last completely redeemed Trove and the sender will keep the remaining ZUSD amount, which they can attempt\\n * to redeem later.\\n *\\n * @param _ZUSDAmount ZUSD amount to send to the system\\n * @param _firstRedemptionHint calculated ICR hint of first trove after redemption\\n * @param _maxIterations max Troves iterations (can be 0)\\n * @param _maxFee max fee percentage to accept\\n */\\n function redeemCollateral(\\n uint256 _ZUSDAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFee\\n ) external;\\n\\n function redeemCollateralViaDLLR(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external;\\n\\n function redeemCollateralViaDllrWithPermit2(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external;\\n \\n\\n /// @notice Update borrower's stake based on their latest collateral value\\n /// @param _borrower borrower address\\n function updateStakeAndTotalStakes(address _borrower) external returns (uint256);\\n\\n /// @notice Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values\\n /// @param _borrower borrower address\\n function updateTroveRewardSnapshots(address _borrower) external;\\n\\n /// @notice Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct\\n /// @param _borrower borrower address\\n /// @return index where Trove was inserted\\n function addTroveOwnerToArray(address _borrower) external returns (uint256 index);\\n\\n /// @notice Add the borrowers's coll and debt rewards earned from redistributions, to their Trove\\n /// @param _borrower borrower address\\n function applyPendingRewards(address _borrower) external;\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ETH reward, earned by their stake\\n function getPendingETHReward(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return the borrower's pending accumulated ZUSD reward, earned by their stake\\n function getPendingZUSDDebtReward(address _borrower) external view returns (uint256);\\n\\n /*\\n * @notice A Trove has pending rewards if its snapshot is less than the current rewards per-unit-staked sum:\\n * this indicates that rewards have occured since the snapshot was made, and the user therefore has\\n * pending rewards\\n *\\n * @param _borrower borrower address\\n * @return true if has pending rewards\\n */\\n function hasPendingRewards(address _borrower) external view returns (bool);\\n\\n /// @notice returns the Troves entire debt and coll, including pending rewards from redistributions.\\n /// @param _borrower borrower address\\n function getEntireDebtAndColl(\\n address _borrower\\n )\\n external\\n view\\n returns (\\n uint256 debt,\\n uint256 coll,\\n uint256 pendingZUSDDebtReward,\\n uint256 pendingETHReward\\n );\\n\\n /// @notice Close given trove. Called by BorrowerOperations.\\n /// @param _borrower borrower address\\n function closeTrove(address _borrower) external;\\n\\n /// @notice Remove borrower's stake from the totalStakes sum, and set their stake to 0\\n /// @param _borrower borrower address\\n function removeStake(address _borrower) external;\\n\\n /// @return calculated redemption rate using baseRate\\n function getRedemptionRate() external view returns (uint256);\\n\\n /// @return calculated redemption rate using calculated decayed as base rate\\n function getRedemptionRateWithDecay() external view returns (uint256);\\n\\n /// @notice The redemption fee is taken as a cut of the total ETH drawn from the system in a redemption. It is based on the current redemption rate.\\n /// @param _ETHDrawn ETH drawn\\n function getRedemptionFeeWithDecay(uint256 _ETHDrawn) external view returns (uint256);\\n\\n /// @return borrowing rate\\n function getBorrowingRate() external view returns (uint256);\\n\\n /// @return borrowing rate calculated using decayed as base rate\\n function getBorrowingRateWithDecay() external view returns (uint256);\\n\\n /// @param ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate\\n function getBorrowingFee(uint256 ZUSDDebt) external view returns (uint256);\\n\\n /// @param _ZUSDDebt ZUSD debt amount to calculate fee\\n /// @return borrowing fee using borrowing rate with decay\\n function getBorrowingFeeWithDecay(uint256 _ZUSDDebt) external view returns (uint256);\\n\\n /// @notice Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation.\\n function decayBaseRateFromBorrowing() external;\\n\\n /// @param _borrower borrower address\\n /// @return Trove status from given trove\\n function getTroveStatus(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove stake from given trove\\n function getTroveStake(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove debt from given trove\\n function getTroveDebt(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @return Trove collateral from given trove\\n function getTroveColl(address _borrower) external view returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param num status to set\\n function setTroveStatus(address _borrower, uint256 num) external;\\n\\n /// @param _borrower borrower address\\n /// @param _collIncrease amount of collateral to increase\\n /// @return new trove collateral\\n function increaseTroveColl(\\n address _borrower,\\n uint256 _collIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _collDecrease amount of collateral to decrease\\n /// @return new trove collateral\\n function decreaseTroveColl(\\n address _borrower,\\n uint256 _collDecrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtIncrease amount of debt to increase\\n /// @return new trove debt\\n function increaseTroveDebt(\\n address _borrower,\\n uint256 _debtIncrease\\n ) external returns (uint256);\\n\\n /// @param _borrower borrower address\\n /// @param _debtDecrease amount of debt to decrease\\n /// @return new trove debt\\n function decreaseTroveDebt(\\n address _borrower,\\n uint256 _debtDecrease\\n ) external returns (uint256);\\n\\n /**\\n * @param _price ETH price\\n * @return the total collateralization ratio (TCR) of the system.\\n * The TCR is based on the the entire system debt and collateral (including pending rewards).\\n */\\n function getTCR(uint256 _price) external view returns (uint256);\\n\\n function MCR() external view returns (uint256);\\n\\n function CCR() external view returns (uint256);\\n\\n /// @notice reveals whether or not the system is in Recovery Mode (i.e. whether the Total Collateralization Ratio (TCR) is below the Critical Collateralization Ratio (CCR)).\\n function checkRecoveryMode(uint256 _price) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x396367eb7763c289e419a025532150e2a1d9d99eead359ceb6a081787501a00b\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROStaking.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\ninterface IZEROStaking {\\n // --- Events --\\n\\n event ZEROTokenAddressSet(address _zeroTokenAddress);\\n event ZUSDTokenAddressSet(address _zusdTokenAddress);\\n event FeeDistributorAddressAddressSet(address _feeDistributorAddress);\\n event ActivePoolAddressSet(address _activePoolAddress);\\n\\n event StakeChanged(address indexed staker, uint256 newStake);\\n event StakingGainsWithdrawn(address indexed staker, uint256 ZUSDGain, uint256 ETHGain);\\n event F_ETHUpdated(uint256 _F_ETH);\\n event F_ZUSDUpdated(uint256 _F_ZUSD);\\n event TotalZEROStakedUpdated(uint256 _totalZEROStaked);\\n event EtherSent(address _account, uint256 _amount);\\n event StakerSnapshotsUpdated(address _staker, uint256 _F_ETH, uint256 _F_ZUSD);\\n\\n // --- Functions ---\\n\\n /**\\n * @notice Called only once on init, to set addresses of other Zero contracts. Callable only by owner\\n * @dev initializer function, checks addresses are contracts\\n * @param _zeroTokenAddress ZEROToken contract address\\n * @param _zusdTokenAddress ZUSDToken contract address\\n * @param _feeDistributorAddress FeeDistributorAddress contract address\\n * @param _activePoolAddress ActivePool contract address\\n */\\n function setAddresses(\\n address _zeroTokenAddress,\\n address _zusdTokenAddress,\\n address _feeDistributorAddress,\\n address _activePoolAddress\\n ) external;\\n\\n /// @notice If caller has a pre-existing stake, send any accumulated ETH and ZUSD gains to them.\\n /// @param _ZEROamount ZERO tokens to stake\\n function stake(uint256 _ZEROamount) external;\\n\\n /**\\n * @notice Unstake the ZERO and send the it back to the caller, along with their accumulated ZUSD & ETH gains.\\n * If requested amount > stake, send their entire stake.\\n * @param _ZEROamount ZERO tokens to unstake\\n */\\n function unstake(uint256 _ZEROamount) external;\\n\\n /// @param _ETHFee ETH fee\\n /// @notice increase ETH fee\\n function increaseF_ETH(uint256 _ETHFee) external;\\n\\n /// @param _ZEROFee ZUSD fee\\n /// @notice increase ZUSD fee\\n function increaseF_ZUSD(uint256 _ZEROFee) external;\\n\\n /// @param _user user address\\n /// @return pending ETH gain of given user\\n function getPendingETHGain(address _user) external view returns (uint256);\\n\\n /// @param _user user address\\n /// @return pending ZUSD gain of given user\\n function getPendingZUSDGain(address _user) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x4c7948ce7dff9ea9b8495054e511eabcf44a91c7db8520ec58ff2a002327e0c5\",\"license\":\"MIT\"},\"contracts/Interfaces/IZEROToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZEROToken is IERC20, IERC2612 { \\n\\n // --- Functions ---\\n\\n /// @notice send zero tokens to ZEROStaking contract\\n /// @param _sender sender address\\n /// @param _amount amount to send\\n function sendToZEROStaking(address _sender, uint256 _amount) external;\\n\\n /// @return deployment start time\\n function getDeploymentStartTime() external view returns (uint256);\\n\\n}\\n\",\"keccak256\":\"0xbcc0baabe4c4686563a09cf1486f2d152b70404996676a89d525691f69637f66\",\"license\":\"MIT\"},\"contracts/Interfaces/IZUSDToken.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"../Dependencies/IERC20.sol\\\";\\nimport \\\"../Dependencies/IERC2612.sol\\\";\\n\\ninterface IZUSDToken is IERC20, IERC2612 { \\n \\n // --- Events ---\\n\\n event TroveManagerAddressChanged(address _troveManagerAddress);\\n event StabilityPoolAddressChanged(address _newStabilityPoolAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n\\n event ZUSDTokenBalanceUpdated(address _user, uint _amount);\\n\\n // --- Functions ---\\n\\n function mint(address _account, uint256 _amount) external;\\n\\n function burn(address _account, uint256 _amount) external;\\n\\n function sendToPool(address _sender, address poolAddress, uint256 _amount) external;\\n\\n function returnFromPool(address poolAddress, address user, uint256 _amount ) external;\\n}\\n\",\"keccak256\":\"0xe52df063aa08f709640c28888edd27310c820f6d08564855538ae245eb2f5a8c\",\"license\":\"MIT\"},\"contracts/TroveManager.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\npragma experimental ABIEncoderV2;\\n\\nimport \\\"./Interfaces/ITroveManager.sol\\\";\\nimport \\\"./Interfaces/IStabilityPool.sol\\\";\\nimport \\\"./Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/IZEROToken.sol\\\";\\nimport \\\"./Interfaces/IZEROStaking.sol\\\";\\nimport \\\"./Interfaces/IFeeDistributor.sol\\\";\\nimport \\\"./Dependencies/LiquityBase.sol\\\";\\nimport \\\"./Dependencies/CheckContract.sol\\\";\\nimport \\\"./Dependencies/console.sol\\\";\\nimport \\\"./Dependencies/TroveManagerBase.sol\\\";\\nimport \\\"./TroveManagerStorage.sol\\\";\\nimport \\\"./Interfaces/IPermit2.sol\\\";\\n\\ncontract TroveManager is TroveManagerBase, CheckContract, ITroveManager {\\n /** CONSTANT / IMMUTABLE VARIABLE ONLY */\\n IPermit2 public immutable permit2;\\n\\n event FeeDistributorAddressChanged(address _feeDistributorAddress);\\n event TroveManagerRedeemOpsAddressChanged(address _troveManagerRedeemOps);\\n event LiquityBaseParamsAddressChanges(address _borrowerOperationsAddress);\\n event BorrowerOperationsAddressChanged(address _newBorrowerOperationsAddress);\\n event PriceFeedAddressChanged(address _newPriceFeedAddress);\\n event ZUSDTokenAddressChanged(address _newZUSDTokenAddress);\\n event ActivePoolAddressChanged(address _activePoolAddress);\\n event DefaultPoolAddressChanged(address _defaultPoolAddress);\\n event StabilityPoolAddressChanged(address _stabilityPoolAddress);\\n event GasPoolAddressChanged(address _gasPoolAddress);\\n event CollSurplusPoolAddressChanged(address _collSurplusPoolAddress);\\n event SortedTrovesAddressChanged(address _sortedTrovesAddress);\\n event ZEROTokenAddressChanged(address _zeroTokenAddress);\\n event ZEROStakingAddressChanged(address _zeroStakingAddress);\\n\\n ///@param _bootstrapPeriod During bootsrap period redemptions are not allowed\\n constructor(uint256 _bootstrapPeriod, address _permit2) public TroveManagerBase(_bootstrapPeriod) {\\n permit2 = IPermit2(_permit2);\\n }\\n\\n // --- Dependency setter ---\\n function setAddresses(\\n TroveManagerInitAddressesParams memory _troveManagerInitAddressesParams\\n ) external override onlyOwner {\\n {\\n checkContract(_troveManagerInitAddressesParams._feeDistributorAddress);\\n checkContract(_troveManagerInitAddressesParams._troveManagerRedeemOps);\\n checkContract(_troveManagerInitAddressesParams._liquityBaseParamsAddress);\\n checkContract(_troveManagerInitAddressesParams._borrowerOperationsAddress);\\n checkContract(_troveManagerInitAddressesParams._activePoolAddress);\\n checkContract(_troveManagerInitAddressesParams._defaultPoolAddress);\\n checkContract(_troveManagerInitAddressesParams._stabilityPoolAddress);\\n checkContract(_troveManagerInitAddressesParams._gasPoolAddress);\\n checkContract(_troveManagerInitAddressesParams._collSurplusPoolAddress);\\n checkContract(_troveManagerInitAddressesParams._priceFeedAddress);\\n checkContract(_troveManagerInitAddressesParams._zusdTokenAddress);\\n checkContract(_troveManagerInitAddressesParams._sortedTrovesAddress);\\n checkContract(_troveManagerInitAddressesParams._zeroTokenAddress);\\n checkContract(_troveManagerInitAddressesParams._zeroStakingAddress);\\n }\\n\\n feeDistributor = IFeeDistributor(_troveManagerInitAddressesParams._feeDistributorAddress);\\n troveManagerRedeemOps = _troveManagerInitAddressesParams._troveManagerRedeemOps;\\n liquityBaseParams = ILiquityBaseParams(\\n _troveManagerInitAddressesParams._liquityBaseParamsAddress\\n );\\n {\\n borrowerOperationsAddress = _troveManagerInitAddressesParams\\n ._borrowerOperationsAddress;\\n activePool = IActivePool(_troveManagerInitAddressesParams._activePoolAddress);\\n defaultPool = IDefaultPool(_troveManagerInitAddressesParams._defaultPoolAddress);\\n _stabilityPool = IStabilityPool(\\n _troveManagerInitAddressesParams._stabilityPoolAddress\\n );\\n gasPoolAddress = _troveManagerInitAddressesParams._gasPoolAddress;\\n collSurplusPool = ICollSurplusPool(\\n _troveManagerInitAddressesParams._collSurplusPoolAddress\\n );\\n priceFeed = IPriceFeed(_troveManagerInitAddressesParams._priceFeedAddress);\\n _zusdToken = IZUSDToken(_troveManagerInitAddressesParams._zusdTokenAddress);\\n sortedTroves = ISortedTroves(_troveManagerInitAddressesParams._sortedTrovesAddress);\\n _zeroToken = IZEROToken(_troveManagerInitAddressesParams._zeroTokenAddress);\\n _zeroStaking = IZEROStaking(_troveManagerInitAddressesParams._zeroStakingAddress);\\n }\\n\\n emit FeeDistributorAddressChanged(_troveManagerInitAddressesParams._feeDistributorAddress);\\n emit TroveManagerRedeemOpsAddressChanged(\\n _troveManagerInitAddressesParams._troveManagerRedeemOps\\n );\\n emit LiquityBaseParamsAddressChanges(\\n _troveManagerInitAddressesParams._borrowerOperationsAddress\\n );\\n emit BorrowerOperationsAddressChanged(\\n _troveManagerInitAddressesParams._borrowerOperationsAddress\\n );\\n emit ActivePoolAddressChanged(_troveManagerInitAddressesParams._activePoolAddress);\\n emit DefaultPoolAddressChanged(_troveManagerInitAddressesParams._defaultPoolAddress);\\n emit StabilityPoolAddressChanged(_troveManagerInitAddressesParams._stabilityPoolAddress);\\n emit GasPoolAddressChanged(_troveManagerInitAddressesParams._gasPoolAddress);\\n emit CollSurplusPoolAddressChanged(\\n _troveManagerInitAddressesParams._collSurplusPoolAddress\\n );\\n emit PriceFeedAddressChanged(_troveManagerInitAddressesParams._priceFeedAddress);\\n emit ZUSDTokenAddressChanged(_troveManagerInitAddressesParams._zusdTokenAddress);\\n emit SortedTrovesAddressChanged(_troveManagerInitAddressesParams._sortedTrovesAddress);\\n emit ZEROTokenAddressChanged(_troveManagerInitAddressesParams._zeroTokenAddress);\\n emit ZEROStakingAddressChanged(_troveManagerInitAddressesParams._zeroStakingAddress);\\n }\\n\\n function setTroveManagerRedeemOps(address _troveManagerRedeemOps) external override onlyOwner {\\n checkContract(_troveManagerRedeemOps);\\n troveManagerRedeemOps = _troveManagerRedeemOps;\\n emit TroveManagerRedeemOpsAddressChanged(_troveManagerRedeemOps);\\n }\\n\\n // --- Getters ---\\n\\n function getTroveOwnersCount() external view override returns (uint256) {\\n return TroveOwners.length;\\n }\\n\\n function getTroveFromTroveOwnersArray(\\n uint256 _index\\n ) external view override returns (address) {\\n return TroveOwners[_index];\\n }\\n\\n // --- Trove Liquidation functions ---\\n\\n /// Single liquidation function. Closes the trove if its ICR is lower than the minimum collateral ratio.\\n function liquidate(address _borrower) external override {\\n _requireTroveIsActive(_borrower);\\n\\n address[] memory borrowers = new address[](1);\\n borrowers[0] = _borrower;\\n batchLiquidateTroves(borrowers);\\n }\\n\\n // --- Inner single liquidation functions ---\\n\\n /// Liquidate one trove, in Normal Mode.\\n function _liquidateNormalMode(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n address _borrower,\\n uint256 _ZUSDInStabPool\\n ) internal returns (LiquidationValues memory singleLiquidation) {\\n LocalVariables_InnerSingleLiquidateFunction memory vars;\\n\\n (\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n ) = getEntireDebtAndColl(_borrower);\\n\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n );\\n _removeStake(_borrower);\\n\\n singleLiquidation.collGasCompensation = _getCollGasCompensation(\\n singleLiquidation.entireTroveColl\\n );\\n singleLiquidation.ZUSDGasCompensation = ZUSD_GAS_COMPENSATION;\\n uint256 collToLiquidate = singleLiquidation.entireTroveColl.sub(\\n singleLiquidation.collGasCompensation\\n );\\n\\n (\\n singleLiquidation.debtToOffset,\\n singleLiquidation.collToSendToSP,\\n singleLiquidation.debtToRedistribute,\\n singleLiquidation.collToRedistribute\\n ) = _getOffsetAndRedistributionVals(\\n singleLiquidation.entireTroveDebt,\\n collToLiquidate,\\n _ZUSDInStabPool\\n );\\n\\n _closeTrove(_borrower, Status.closedByLiquidation);\\n emit TroveLiquidated(\\n _borrower,\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n TroveManagerOperation.liquidateInNormalMode\\n );\\n emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInNormalMode);\\n return singleLiquidation;\\n }\\n\\n /// Liquidate one trove, in Recovery Mode.\\n function _liquidateRecoveryMode(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n address _borrower,\\n uint256 _ICR,\\n uint256 _ZUSDInStabPool,\\n uint256 _TCR,\\n uint256 _price\\n ) internal returns (LiquidationValues memory singleLiquidation) {\\n LocalVariables_InnerSingleLiquidateFunction memory vars;\\n if (TroveOwners.length <= 1) {\\n return singleLiquidation;\\n } // don't liquidate if last trove\\n (\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n ) = getEntireDebtAndColl(_borrower);\\n\\n singleLiquidation.collGasCompensation = _getCollGasCompensation(\\n singleLiquidation.entireTroveColl\\n );\\n singleLiquidation.ZUSDGasCompensation = ZUSD_GAS_COMPENSATION;\\n vars.collToLiquidate = singleLiquidation.entireTroveColl.sub(\\n singleLiquidation.collGasCompensation\\n );\\n\\n // If ICR <= 100%, purely redistribute the Trove across all active Troves\\n if (_ICR <= _100pct) {\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n );\\n _removeStake(_borrower);\\n\\n singleLiquidation.debtToOffset = 0;\\n singleLiquidation.collToSendToSP = 0;\\n singleLiquidation.debtToRedistribute = singleLiquidation.entireTroveDebt;\\n singleLiquidation.collToRedistribute = vars.collToLiquidate;\\n\\n _closeTrove(_borrower, Status.closedByLiquidation);\\n emit TroveLiquidated(\\n _borrower,\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n TroveManagerOperation.liquidateInRecoveryMode\\n );\\n emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode);\\n\\n // If 100% < ICR < MCR, offset as much as possible, and redistribute the remainder\\n } else if ((_ICR > _100pct) && (_ICR < liquityBaseParams.MCR())) {\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n );\\n _removeStake(_borrower);\\n\\n (\\n singleLiquidation.debtToOffset,\\n singleLiquidation.collToSendToSP,\\n singleLiquidation.debtToRedistribute,\\n singleLiquidation.collToRedistribute\\n ) = _getOffsetAndRedistributionVals(\\n singleLiquidation.entireTroveDebt,\\n vars.collToLiquidate,\\n _ZUSDInStabPool\\n );\\n\\n _closeTrove(_borrower, Status.closedByLiquidation);\\n emit TroveLiquidated(\\n _borrower,\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n TroveManagerOperation.liquidateInRecoveryMode\\n );\\n emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode);\\n /*\\n * If 110% <= ICR < current TCR (accounting for the preceding liquidations in the current sequence)\\n * and there is ZUSD in the Stability Pool, only offset, with no redistribution,\\n * but at a capped rate of 1.1 and only if the whole debt can be liquidated.\\n * The remainder due to the capped rate will be claimable as collateral surplus.\\n */\\n } else if (\\n (_ICR >= liquityBaseParams.MCR()) &&\\n (_ICR < _TCR) &&\\n (singleLiquidation.entireTroveDebt <= _ZUSDInStabPool)\\n ) {\\n _movePendingTroveRewardsToActivePool(\\n _activePool,\\n _defaultPool,\\n vars.pendingDebtReward,\\n vars.pendingCollReward\\n );\\n assert(_ZUSDInStabPool != 0);\\n\\n _removeStake(_borrower);\\n singleLiquidation = _getCappedOffsetVals(\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.entireTroveColl,\\n _price\\n );\\n\\n _closeTrove(_borrower, Status.closedByLiquidation);\\n if (singleLiquidation.collSurplus > 0) {\\n collSurplusPool.accountSurplus(_borrower, singleLiquidation.collSurplus);\\n }\\n\\n emit TroveLiquidated(\\n _borrower,\\n singleLiquidation.entireTroveDebt,\\n singleLiquidation.collToSendToSP,\\n TroveManagerOperation.liquidateInRecoveryMode\\n );\\n emit TroveUpdated(_borrower, 0, 0, 0, TroveManagerOperation.liquidateInRecoveryMode);\\n } else {\\n // if (_ICR >= liquityBaseParams.MCR() && ( _ICR >= _TCR || singleLiquidation.entireTroveDebt > _ZUSDInStabPool))\\n LiquidationValues memory zeroVals;\\n return zeroVals;\\n }\\n\\n return singleLiquidation;\\n }\\n\\n /** In a full liquidation, returns the values for a trove's coll and debt to be offset, and coll and debt to be\\n * redistributed to active troves.\\n */\\n function _getOffsetAndRedistributionVals(\\n uint256 _debt,\\n uint256 _coll,\\n uint256 _ZUSDInStabPool\\n )\\n internal\\n pure\\n returns (\\n uint256 debtToOffset,\\n uint256 collToSendToSP,\\n uint256 debtToRedistribute,\\n uint256 collToRedistribute\\n )\\n {\\n if (_ZUSDInStabPool > 0) {\\n /*\\n * Offset as much debt & collateral as possible against the Stability Pool, and redistribute the remainder\\n * between all active troves.\\n *\\n * If the trove's debt is larger than the deposited ZUSD in the Stability Pool:\\n *\\n * - Offset an amount of the trove's debt equal to the ZUSD in the Stability Pool\\n * - Send a fraction of the trove's collateral to the Stability Pool, equal to the fraction of its offset debt\\n *\\n */\\n debtToOffset = LiquityMath._min(_debt, _ZUSDInStabPool);\\n collToSendToSP = _coll.mul(debtToOffset).div(_debt);\\n debtToRedistribute = _debt.sub(debtToOffset);\\n collToRedistribute = _coll.sub(collToSendToSP);\\n } else {\\n debtToOffset = 0;\\n collToSendToSP = 0;\\n debtToRedistribute = _debt;\\n collToRedistribute = _coll;\\n }\\n }\\n\\n /**\\n * Get its offset coll/debt and ETH gas comp, and close the trove.\\n */\\n function _getCappedOffsetVals(\\n uint256 _entireTroveDebt,\\n uint256 _entireTroveColl,\\n uint256 _price\\n ) internal view returns (LiquidationValues memory singleLiquidation) {\\n singleLiquidation.entireTroveDebt = _entireTroveDebt;\\n singleLiquidation.entireTroveColl = _entireTroveColl;\\n uint256 collToOffset = _entireTroveDebt.mul(liquityBaseParams.MCR()).div(_price);\\n\\n singleLiquidation.collGasCompensation = _getCollGasCompensation(collToOffset);\\n singleLiquidation.ZUSDGasCompensation = ZUSD_GAS_COMPENSATION;\\n\\n singleLiquidation.debtToOffset = _entireTroveDebt;\\n singleLiquidation.collToSendToSP = collToOffset.sub(singleLiquidation.collGasCompensation);\\n singleLiquidation.collSurplus = _entireTroveColl.sub(collToOffset);\\n singleLiquidation.debtToRedistribute = 0;\\n singleLiquidation.collToRedistribute = 0;\\n }\\n\\n /**\\n * Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves,\\n * starting from the one with the lowest collateral ratio in the system, and moving upwards\\n */\\n function liquidateTroves(uint256 _n) external override {\\n ContractsCache memory contractsCache = ContractsCache(\\n activePool,\\n defaultPool,\\n IZUSDToken(address(0)),\\n IZEROStaking(address(0)),\\n sortedTroves,\\n ICollSurplusPool(address(0)),\\n address(0)\\n );\\n IStabilityPool stabilityPoolCached = _stabilityPool;\\n\\n LocalVariables_OuterLiquidationFunction memory vars;\\n\\n LiquidationTotals memory totals;\\n\\n vars.price = priceFeed.fetchPrice();\\n vars.ZUSDInStabPool = stabilityPoolCached.getTotalZUSDDeposits();\\n vars.recoveryModeAtStart = _checkRecoveryMode(vars.price);\\n\\n // Perform the appropriate liquidation sequence - tally the values, and obtain their totals\\n if (vars.recoveryModeAtStart) {\\n totals = _getTotalsFromLiquidateTrovesSequence_RecoveryMode(\\n contractsCache,\\n vars.price,\\n vars.ZUSDInStabPool,\\n _n\\n );\\n } else {\\n // if !vars.recoveryModeAtStart\\n totals = _getTotalsFromLiquidateTrovesSequence_NormalMode(\\n contractsCache.activePool,\\n contractsCache.defaultPool,\\n vars.price,\\n vars.ZUSDInStabPool,\\n _n\\n );\\n }\\n\\n require(totals.totalDebtInSequence > 0, \\\"TroveManager: nothing to liquidate\\\");\\n\\n // Move liquidated ETH and ZUSD to the appropriate pools\\n stabilityPoolCached.offset(totals.totalDebtToOffset, totals.totalCollToSendToSP);\\n _redistributeDebtAndColl(\\n contractsCache.activePool,\\n contractsCache.defaultPool,\\n totals.totalDebtToRedistribute,\\n totals.totalCollToRedistribute\\n );\\n if (totals.totalCollSurplus > 0) {\\n contractsCache.activePool.sendETH(address(collSurplusPool), totals.totalCollSurplus);\\n }\\n\\n // Update system snapshots\\n _updateSystemSnapshots_excludeCollRemainder(\\n contractsCache.activePool,\\n totals.totalCollGasCompensation\\n );\\n\\n vars.liquidatedDebt = totals.totalDebtInSequence;\\n vars.liquidatedColl = totals.totalCollInSequence.sub(totals.totalCollGasCompensation).sub(\\n totals.totalCollSurplus\\n );\\n emit Liquidation(\\n vars.liquidatedDebt,\\n vars.liquidatedColl,\\n totals.totalCollGasCompensation,\\n totals.totalZUSDGasCompensation\\n );\\n\\n // Send gas compensation to caller\\n _sendGasCompensation(\\n contractsCache.activePool,\\n msg.sender,\\n totals.totalZUSDGasCompensation,\\n totals.totalCollGasCompensation\\n );\\n }\\n\\n /**\\n * This function is used when the liquidateTroves sequence starts during Recovery Mode. However, it\\n * handle the case where the system *leaves* Recovery Mode, part way through the liquidation sequence\\n */\\n function _getTotalsFromLiquidateTrovesSequence_RecoveryMode(\\n ContractsCache memory _contractsCache,\\n uint256 _price,\\n uint256 _ZUSDInStabPool,\\n uint256 _n\\n ) internal returns (LiquidationTotals memory totals) {\\n LocalVariables_LiquidationSequence memory vars;\\n LiquidationValues memory singleLiquidation;\\n\\n vars.remainingZUSDInStabPool = _ZUSDInStabPool;\\n vars.backToNormalMode = false;\\n vars.entireSystemDebt = getEntireSystemDebt();\\n vars.entireSystemColl = getEntireSystemColl();\\n\\n vars.user = _contractsCache.sortedTroves.getLast();\\n address firstUser = _contractsCache.sortedTroves.getFirst();\\n for (vars.i = 0; vars.i < _n && vars.user != firstUser; vars.i++) {\\n // we need to cache it, because current user is likely going to be deleted\\n address nextUser = _contractsCache.sortedTroves.getPrev(vars.user);\\n\\n vars.ICR = _getCurrentICR(vars.user, _price);\\n\\n if (!vars.backToNormalMode) {\\n // Break the loop if ICR is greater than liquityBaseParams.MCR() and Stability Pool is empty\\n if (vars.ICR >= liquityBaseParams.MCR() && vars.remainingZUSDInStabPool == 0) {\\n break;\\n }\\n\\n uint256 TCR = LiquityMath._computeCR(\\n vars.entireSystemColl,\\n vars.entireSystemDebt,\\n _price\\n );\\n\\n singleLiquidation = _liquidateRecoveryMode(\\n _contractsCache.activePool,\\n _contractsCache.defaultPool,\\n vars.user,\\n vars.ICR,\\n vars.remainingZUSDInStabPool,\\n TCR,\\n _price\\n );\\n\\n // Update aggregate trackers\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n vars.entireSystemDebt = vars.entireSystemDebt.sub(singleLiquidation.debtToOffset);\\n vars.entireSystemColl = vars\\n .entireSystemColl\\n .sub(singleLiquidation.collToSendToSP)\\n .sub(singleLiquidation.collSurplus);\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n\\n vars.backToNormalMode = !_checkPotentialRecoveryMode(\\n vars.entireSystemColl,\\n vars.entireSystemDebt,\\n _price\\n );\\n } else if (vars.backToNormalMode && vars.ICR < liquityBaseParams.MCR()) {\\n singleLiquidation = _liquidateNormalMode(\\n _contractsCache.activePool,\\n _contractsCache.defaultPool,\\n vars.user,\\n vars.remainingZUSDInStabPool\\n );\\n\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n } else break; // break if the loop reaches a Trove with ICR >= MCR\\n\\n vars.user = nextUser;\\n }\\n }\\n\\n function _getTotalsFromLiquidateTrovesSequence_NormalMode(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _price,\\n uint256 _ZUSDInStabPool,\\n uint256 _n\\n ) internal returns (LiquidationTotals memory totals) {\\n LocalVariables_LiquidationSequence memory vars;\\n LiquidationValues memory singleLiquidation;\\n ISortedTroves sortedTrovesCached = sortedTroves;\\n\\n vars.remainingZUSDInStabPool = _ZUSDInStabPool;\\n\\n for (vars.i = 0; vars.i < _n; vars.i++) {\\n vars.user = sortedTrovesCached.getLast();\\n vars.ICR = _getCurrentICR(vars.user, _price);\\n\\n if (vars.ICR < liquityBaseParams.MCR()) {\\n singleLiquidation = _liquidateNormalMode(\\n _activePool,\\n _defaultPool,\\n vars.user,\\n vars.remainingZUSDInStabPool\\n );\\n\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n } else break; // break if the loop reaches a Trove with ICR >= MCR\\n }\\n }\\n\\n /**\\n * Attempt to liquidate a custom list of troves provided by the caller.\\n */\\n function batchLiquidateTroves(address[] memory _troveArray) public override {\\n require(_troveArray.length != 0, \\\"TroveManager: Calldata address array must not be empty\\\");\\n\\n IActivePool activePoolCached = activePool;\\n IDefaultPool defaultPoolCached = defaultPool;\\n IStabilityPool stabilityPoolCached = _stabilityPool;\\n\\n LocalVariables_OuterLiquidationFunction memory vars;\\n LiquidationTotals memory totals;\\n\\n vars.price = priceFeed.fetchPrice();\\n vars.ZUSDInStabPool = stabilityPoolCached.getTotalZUSDDeposits();\\n vars.recoveryModeAtStart = _checkRecoveryMode(vars.price);\\n\\n // Perform the appropriate liquidation sequence - tally values and obtain their totals.\\n if (vars.recoveryModeAtStart) {\\n totals = _getTotalFromBatchLiquidate_RecoveryMode(\\n activePoolCached,\\n defaultPoolCached,\\n vars.price,\\n vars.ZUSDInStabPool,\\n _troveArray\\n );\\n } else {\\n // if !vars.recoveryModeAtStart\\n totals = _getTotalsFromBatchLiquidate_NormalMode(\\n activePoolCached,\\n defaultPoolCached,\\n vars.price,\\n vars.ZUSDInStabPool,\\n _troveArray\\n );\\n }\\n\\n require(totals.totalDebtInSequence > 0, \\\"TroveManager: nothing to liquidate\\\");\\n\\n // Move liquidated ETH and ZUSD to the appropriate pools\\n stabilityPoolCached.offset(totals.totalDebtToOffset, totals.totalCollToSendToSP);\\n _redistributeDebtAndColl(\\n activePoolCached,\\n defaultPoolCached,\\n totals.totalDebtToRedistribute,\\n totals.totalCollToRedistribute\\n );\\n if (totals.totalCollSurplus > 0) {\\n activePoolCached.sendETH(address(collSurplusPool), totals.totalCollSurplus);\\n }\\n\\n // Update system snapshots\\n _updateSystemSnapshots_excludeCollRemainder(\\n activePoolCached,\\n totals.totalCollGasCompensation\\n );\\n\\n vars.liquidatedDebt = totals.totalDebtInSequence;\\n vars.liquidatedColl = totals.totalCollInSequence.sub(totals.totalCollGasCompensation).sub(\\n totals.totalCollSurplus\\n );\\n emit Liquidation(\\n vars.liquidatedDebt,\\n vars.liquidatedColl,\\n totals.totalCollGasCompensation,\\n totals.totalZUSDGasCompensation\\n );\\n\\n // Send gas compensation to caller\\n _sendGasCompensation(\\n activePoolCached,\\n msg.sender,\\n totals.totalZUSDGasCompensation,\\n totals.totalCollGasCompensation\\n );\\n }\\n\\n /**\\n * This function is used when the batch liquidation sequence starts during Recovery Mode. However, it\\n * handle the case where the system *leaves* Recovery Mode, part way through the liquidation sequence\\n */\\n function _getTotalFromBatchLiquidate_RecoveryMode(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _price,\\n uint256 _ZUSDInStabPool,\\n address[] memory _troveArray\\n ) internal returns (LiquidationTotals memory totals) {\\n LocalVariables_LiquidationSequence memory vars;\\n LiquidationValues memory singleLiquidation;\\n\\n vars.remainingZUSDInStabPool = _ZUSDInStabPool;\\n vars.backToNormalMode = false;\\n vars.entireSystemDebt = getEntireSystemDebt();\\n vars.entireSystemColl = getEntireSystemColl();\\n\\n for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {\\n vars.user = _troveArray[vars.i];\\n // Skip non-active troves\\n if (Troves[vars.user].status != Status.active) {\\n continue;\\n }\\n vars.ICR = _getCurrentICR(vars.user, _price);\\n\\n if (!vars.backToNormalMode) {\\n // Skip this trove if ICR is greater than liquityBaseParams.MCR() and Stability Pool is empty\\n if (vars.ICR >= liquityBaseParams.MCR() && vars.remainingZUSDInStabPool == 0) {\\n continue;\\n }\\n\\n uint256 TCR = LiquityMath._computeCR(\\n vars.entireSystemColl,\\n vars.entireSystemDebt,\\n _price\\n );\\n\\n singleLiquidation = _liquidateRecoveryMode(\\n _activePool,\\n _defaultPool,\\n vars.user,\\n vars.ICR,\\n vars.remainingZUSDInStabPool,\\n TCR,\\n _price\\n );\\n\\n // Update aggregate trackers\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n vars.entireSystemDebt = vars.entireSystemDebt.sub(singleLiquidation.debtToOffset);\\n vars.entireSystemColl = vars.entireSystemColl.sub(\\n singleLiquidation.collToSendToSP\\n );\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n\\n vars.backToNormalMode = !_checkPotentialRecoveryMode(\\n vars.entireSystemColl,\\n vars.entireSystemDebt,\\n _price\\n );\\n } else if (vars.backToNormalMode && vars.ICR < liquityBaseParams.MCR()) {\\n singleLiquidation = _liquidateNormalMode(\\n _activePool,\\n _defaultPool,\\n vars.user,\\n vars.remainingZUSDInStabPool\\n );\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n } else continue; // In Normal Mode skip troves with ICR >= MCR\\n }\\n }\\n\\n function _getTotalsFromBatchLiquidate_NormalMode(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _price,\\n uint256 _ZUSDInStabPool,\\n address[] memory _troveArray\\n ) internal returns (LiquidationTotals memory totals) {\\n LocalVariables_LiquidationSequence memory vars;\\n LiquidationValues memory singleLiquidation;\\n\\n vars.remainingZUSDInStabPool = _ZUSDInStabPool;\\n\\n for (vars.i = 0; vars.i < _troveArray.length; vars.i++) {\\n vars.user = _troveArray[vars.i];\\n vars.ICR = _getCurrentICR(vars.user, _price);\\n\\n if (vars.ICR < liquityBaseParams.MCR()) {\\n singleLiquidation = _liquidateNormalMode(\\n _activePool,\\n _defaultPool,\\n vars.user,\\n vars.remainingZUSDInStabPool\\n );\\n vars.remainingZUSDInStabPool = vars.remainingZUSDInStabPool.sub(\\n singleLiquidation.debtToOffset\\n );\\n\\n // Add liquidation values to their respective running totals\\n totals = _addLiquidationValuesToTotals(totals, singleLiquidation);\\n }\\n }\\n }\\n\\n // --- Liquidation helper functions ---\\n\\n function _addLiquidationValuesToTotals(\\n LiquidationTotals memory oldTotals,\\n LiquidationValues memory singleLiquidation\\n ) internal pure returns (LiquidationTotals memory newTotals) {\\n // Tally all the values with their respective running totals\\n newTotals.totalCollGasCompensation = oldTotals.totalCollGasCompensation.add(\\n singleLiquidation.collGasCompensation\\n );\\n newTotals.totalZUSDGasCompensation = oldTotals.totalZUSDGasCompensation.add(\\n singleLiquidation.ZUSDGasCompensation\\n );\\n newTotals.totalDebtInSequence = oldTotals.totalDebtInSequence.add(\\n singleLiquidation.entireTroveDebt\\n );\\n newTotals.totalCollInSequence = oldTotals.totalCollInSequence.add(\\n singleLiquidation.entireTroveColl\\n );\\n newTotals.totalDebtToOffset = oldTotals.totalDebtToOffset.add(\\n singleLiquidation.debtToOffset\\n );\\n newTotals.totalCollToSendToSP = oldTotals.totalCollToSendToSP.add(\\n singleLiquidation.collToSendToSP\\n );\\n newTotals.totalDebtToRedistribute = oldTotals.totalDebtToRedistribute.add(\\n singleLiquidation.debtToRedistribute\\n );\\n newTotals.totalCollToRedistribute = oldTotals.totalCollToRedistribute.add(\\n singleLiquidation.collToRedistribute\\n );\\n newTotals.totalCollSurplus = oldTotals.totalCollSurplus.add(singleLiquidation.collSurplus);\\n\\n return newTotals;\\n }\\n\\n function _sendGasCompensation(\\n IActivePool _activePool,\\n address _liquidator,\\n uint256 _ZUSD,\\n uint256 _ETH\\n ) internal {\\n if (_ZUSD > 0) {\\n _zusdToken.returnFromPool(gasPoolAddress, _liquidator, _ZUSD);\\n }\\n\\n if (_ETH > 0) {\\n _activePool.sendETH(_liquidator, _ETH);\\n }\\n }\\n\\n // --- Helper functions ---\\n\\n /// @return the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account.\\n function getNominalICR(address _borrower) public view override returns (uint256) {\\n (uint256 currentETH, uint256 currentZUSDDebt) = _getCurrentTroveAmounts(_borrower);\\n\\n uint256 NICR = LiquityMath._computeNominalCR(currentETH, currentZUSDDebt);\\n return NICR;\\n }\\n\\n function applyPendingRewards(address _borrower) external override {\\n _requireCallerIsBorrowerOperations();\\n return _applyPendingRewards(activePool, defaultPool, _borrower);\\n }\\n\\n /// Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values\\n function updateTroveRewardSnapshots(address _borrower) external override {\\n _requireCallerIsBorrowerOperations();\\n return _updateTroveRewardSnapshots(_borrower);\\n }\\n\\n /// Return the Troves entire debt and coll, including pending rewards from redistributions.\\n function getEntireDebtAndColl(\\n address _borrower\\n )\\n public\\n view\\n override\\n returns (\\n uint256 debt,\\n uint256 coll,\\n uint256 pendingZUSDDebtReward,\\n uint256 pendingETHReward\\n )\\n {\\n debt = Troves[_borrower].debt;\\n coll = Troves[_borrower].coll;\\n\\n pendingZUSDDebtReward = getPendingZUSDDebtReward(_borrower);\\n pendingETHReward = getPendingETHReward(_borrower);\\n\\n debt = debt.add(pendingZUSDDebtReward);\\n coll = coll.add(pendingETHReward);\\n }\\n\\n function removeStake(address _borrower) external override {\\n _requireCallerIsBorrowerOperations();\\n return _removeStake(_borrower);\\n }\\n\\n function updateStakeAndTotalStakes(address _borrower) external override returns (uint256) {\\n _requireCallerIsBorrowerOperations();\\n return _updateStakeAndTotalStakes(_borrower);\\n }\\n\\n function _redistributeDebtAndColl(\\n IActivePool _activePool,\\n IDefaultPool _defaultPool,\\n uint256 _debt,\\n uint256 _coll\\n ) internal {\\n if (_debt == 0) {\\n return;\\n }\\n\\n /*\\n * Add distributed coll and debt rewards-per-unit-staked to the running totals. Division uses a \\\"feedback\\\"\\n * error correction, to keep the cumulative error low in the running totals L_ETH and L_ZUSDDebt:\\n *\\n * 1) Form numerators which compensate for the floor division errors that occurred the last time this\\n * function was called.\\n * 2) Calculate \\\"per-unit-staked\\\" ratios.\\n * 3) Multiply each ratio back by its denominator, to reveal the current floor division error.\\n * 4) Store these errors for use in the next correction when this function is called.\\n * 5) Note: static analysis tools complain about this \\\"division before multiplication\\\", however, it is intended.\\n */\\n uint256 ETHNumerator = _coll.mul(DECIMAL_PRECISION).add(lastETHError_Redistribution);\\n uint256 ZUSDDebtNumerator = _debt.mul(DECIMAL_PRECISION).add(\\n lastZUSDDebtError_Redistribution\\n );\\n\\n // Get the per-unit-staked terms\\n uint256 ETHRewardPerUnitStaked = ETHNumerator.div(totalStakes);\\n uint256 ZUSDDebtRewardPerUnitStaked = ZUSDDebtNumerator.div(totalStakes);\\n\\n lastETHError_Redistribution = ETHNumerator.sub(ETHRewardPerUnitStaked.mul(totalStakes));\\n lastZUSDDebtError_Redistribution = ZUSDDebtNumerator.sub(\\n ZUSDDebtRewardPerUnitStaked.mul(totalStakes)\\n );\\n\\n // Add per-unit-staked terms to the running totals\\n L_ETH = L_ETH.add(ETHRewardPerUnitStaked);\\n L_ZUSDDebt = L_ZUSDDebt.add(ZUSDDebtRewardPerUnitStaked);\\n\\n emit LTermsUpdated(L_ETH, L_ZUSDDebt);\\n\\n // Transfer coll and debt from ActivePool to DefaultPool\\n _activePool.decreaseZUSDDebt(_debt);\\n _defaultPool.increaseZUSDDebt(_debt);\\n _activePool.sendETH(address(_defaultPool), _coll);\\n }\\n\\n function closeTrove(address _borrower) external override {\\n _requireCallerIsBorrowerOperations();\\n return _closeTrove(_borrower, Status.closedByOwner);\\n }\\n\\n /**\\n * Updates snapshots of system total stakes and total collateral, excluding a given collateral remainder from the calculation.\\n * Used in a liquidation sequence.\\n *\\n * The calculation excludes a portion of collateral that is in the ActivePool:\\n *\\n * the total ETH gas compensation from the liquidation sequence\\n *\\n * The ETH as compensation must be excluded as it is always sent out at the very end of the liquidation sequence.\\n */\\n function _updateSystemSnapshots_excludeCollRemainder(\\n IActivePool _activePool,\\n uint256 _collRemainder\\n ) internal {\\n totalStakesSnapshot = totalStakes;\\n\\n uint256 activeColl = _activePool.getETH();\\n uint256 liquidatedColl = defaultPool.getETH();\\n totalCollateralSnapshot = activeColl.sub(_collRemainder).add(liquidatedColl);\\n\\n emit SystemSnapshotsUpdated(totalStakesSnapshot, totalCollateralSnapshot);\\n }\\n\\n /// Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct\\n function addTroveOwnerToArray(address _borrower) external override returns (uint256 index) {\\n _requireCallerIsBorrowerOperations();\\n return _addTroveOwnerToArray(_borrower);\\n }\\n\\n function _addTroveOwnerToArray(address _borrower) internal returns (uint128 index) {\\n /* Max array size is 2**128 - 1, i.e. ~3e30 troves. No risk of overflow, since troves have minimum ZUSD\\n debt of liquidation reserve plus MIN_NET_DEBT. 3e30 ZUSD dwarfs the value of all wealth in the world ( which is < 1e15 USD). */\\n\\n // Push the Troveowner to the array\\n TroveOwners.push(_borrower);\\n\\n // Record the index of the new Troveowner on their Trove struct\\n index = uint128(TroveOwners.length.sub(1));\\n Troves[_borrower].arrayIndex = index;\\n\\n return index;\\n }\\n\\n // --- Recovery Mode and TCR functions ---\\n\\n function getTCR(uint256 _price) external view override returns (uint256) {\\n return _getTCR(_price);\\n }\\n\\n function MCR() external view override returns (uint256) {\\n return liquityBaseParams.MCR();\\n }\\n\\n function CCR() external view override returns (uint256) {\\n return liquityBaseParams.CCR();\\n }\\n\\n function checkRecoveryMode(uint256 _price) external view override returns (bool) {\\n return _checkRecoveryMode(_price);\\n }\\n\\n // Check whether or not the system *would be* in Recovery Mode, given an ETH:USD price, and the entire system coll and debt.\\n function _checkPotentialRecoveryMode(\\n uint256 _entireSystemColl,\\n uint256 _entireSystemDebt,\\n uint256 _price\\n ) internal view returns (bool) {\\n uint256 TCR = LiquityMath._computeCR(_entireSystemColl, _entireSystemDebt, _price);\\n\\n return TCR < liquityBaseParams.CCR();\\n }\\n\\n function getRedemptionRateWithDecay() public view override returns (uint256) {\\n return _calcRedemptionRate(_calcDecayedBaseRate());\\n }\\n\\n function getRedemptionFeeWithDecay(\\n uint256 _ETHDrawn\\n ) external view override returns (uint256) {\\n return _calcRedemptionFee(getRedemptionRateWithDecay(), _ETHDrawn);\\n }\\n\\n // --- Borrowing fee functions ---\\n\\n function getBorrowingRate() public view override returns (uint256) {\\n return _calcBorrowingRate(baseRate);\\n }\\n\\n function getBorrowingRateWithDecay() public view override returns (uint256) {\\n return _calcBorrowingRate(_calcDecayedBaseRate());\\n }\\n\\n function _calcBorrowingRate(uint256 _baseRate) internal view returns (uint256) {\\n return\\n LiquityMath._min(\\n liquityBaseParams.BORROWING_FEE_FLOOR().add(_baseRate),\\n liquityBaseParams.MAX_BORROWING_FEE()\\n );\\n }\\n\\n function getBorrowingFee(uint256 _ZUSDDebt) external view override returns (uint256) {\\n return _calcBorrowingFee(getBorrowingRate(), _ZUSDDebt);\\n }\\n\\n function getBorrowingFeeWithDecay(uint256 _ZUSDDebt) external view override returns (uint256) {\\n return _calcBorrowingFee(getBorrowingRateWithDecay(), _ZUSDDebt);\\n }\\n\\n function _calcBorrowingFee(\\n uint256 _borrowingRate,\\n uint256 _ZUSDDebt\\n ) internal pure returns (uint256) {\\n return _borrowingRate.mul(_ZUSDDebt).div(DECIMAL_PRECISION);\\n }\\n\\n /// Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation.\\n function decayBaseRateFromBorrowing() external override {\\n _requireCallerIsBorrowerOperations();\\n\\n uint256 decayedBaseRate = _calcDecayedBaseRate();\\n assert(decayedBaseRate <= DECIMAL_PRECISION); // The baseRate can decay to 0\\n\\n baseRate = decayedBaseRate;\\n emit BaseRateUpdated(decayedBaseRate);\\n\\n _updateLastFeeOpTime();\\n }\\n\\n // --- Internal fee functions ---\\n\\n // --- Trove property getters ---\\n\\n function getTroveStatus(address _borrower) external view override returns (uint256) {\\n return uint256(Troves[_borrower].status);\\n }\\n\\n function getTroveStake(address _borrower) external view override returns (uint256) {\\n return Troves[_borrower].stake;\\n }\\n\\n function getTroveDebt(address _borrower) external view override returns (uint256) {\\n return Troves[_borrower].debt;\\n }\\n\\n function getTroveColl(address _borrower) external view override returns (uint256) {\\n return Troves[_borrower].coll;\\n }\\n\\n // --- Trove property setters, called by BorrowerOperations ---\\n\\n function setTroveStatus(address _borrower, uint256 _num) external override {\\n _requireCallerIsBorrowerOperations();\\n Troves[_borrower].status = Status(_num);\\n }\\n\\n function increaseTroveColl(\\n address _borrower,\\n uint256 _collIncrease\\n ) external override returns (uint256) {\\n _requireCallerIsBorrowerOperations();\\n uint256 newColl = Troves[_borrower].coll.add(_collIncrease);\\n Troves[_borrower].coll = newColl;\\n return newColl;\\n }\\n\\n function decreaseTroveColl(\\n address _borrower,\\n uint256 _collDecrease\\n ) external override returns (uint256) {\\n _requireCallerIsBorrowerOperations();\\n uint256 newColl = Troves[_borrower].coll.sub(_collDecrease);\\n Troves[_borrower].coll = newColl;\\n return newColl;\\n }\\n\\n function increaseTroveDebt(\\n address _borrower,\\n uint256 _debtIncrease\\n ) external override returns (uint256) {\\n _requireCallerIsBorrowerOperations();\\n uint256 newDebt = Troves[_borrower].debt.add(_debtIncrease);\\n Troves[_borrower].debt = newDebt;\\n return newDebt;\\n }\\n\\n function decreaseTroveDebt(\\n address _borrower,\\n uint256 _debtDecrease\\n ) external override returns (uint256) {\\n _requireCallerIsBorrowerOperations();\\n uint256 newDebt = Troves[_borrower].debt.sub(_debtDecrease);\\n Troves[_borrower].debt = newDebt;\\n return newDebt;\\n }\\n\\n function getCurrentICR(\\n address _borrower,\\n uint256 _price\\n ) external view override returns (uint256) {\\n return _getCurrentICR(_borrower, _price);\\n }\\n\\n function getPendingETHReward(address _borrower) public view override returns (uint256) {\\n return _getPendingETHReward(_borrower);\\n }\\n\\n function getPendingZUSDDebtReward(address _borrower) public view override returns (uint256) {\\n return _getPendingZUSDDebtReward(_borrower);\\n }\\n\\n function hasPendingRewards(address _borrower) public view override returns (bool) {\\n return _hasPendingRewards(_borrower);\\n }\\n\\n function getRedemptionRate() public view override returns (uint256) {\\n return _getRedemptionRate();\\n }\\n\\n /// @dev this function forwards the call to the troveManagerRedeemOps in a delegate call fashion\\n /// so the parameters are not needed\\n function redeemCollateral(\\n uint256 _ZUSDamount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage\\n ) external override {\\n (bool success, bytes memory returndata) = troveManagerRedeemOps.delegatecall(msg.data);\\n require(success, string(returndata));\\n }\\n\\n /// @dev this function forwards the call to the troveManagerRedeemOps in a delegate call fashion\\n /// so the parameters are not needed\\n ///DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\\n function redeemCollateralViaDLLR(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n IMassetManager.PermitParams calldata _permitParams\\n ) external override {\\n (bool success, bytes memory returndata) = troveManagerRedeemOps.delegatecall(msg.data);\\n require(success, string(returndata));\\n }\\n\\n /// @dev this function forwards the call to the troveManagerRedeemOps in a delegate call fashion\\n /// so the parameters are not needed\\n ///DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction\\n function redeemCollateralViaDllrWithPermit2(\\n uint256 _dllrAmount,\\n address _firstRedemptionHint,\\n address _upperPartialRedemptionHint,\\n address _lowerPartialRedemptionHint,\\n uint256 _partialRedemptionHintNICR,\\n uint256 _maxIterations,\\n uint256 _maxFeePercentage,\\n ISignatureTransfer.PermitTransferFrom memory _permit,\\n bytes calldata _signature\\n ) external override {\\n (bool success, bytes memory returndata) = troveManagerRedeemOps.delegatecall(msg.data);\\n require(success, string(returndata));\\n }\\n}\\n\",\"keccak256\":\"0xbe8cf91ac61c6634335c692e9d285827666fbee79db0032cd1bd0bc49762cfc0\",\"license\":\"MIT\"},\"contracts/TroveManagerStorage.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n\\npragma solidity 0.6.11;\\n\\nimport \\\"./Interfaces/IStabilityPool.sol\\\";\\nimport \\\"./Interfaces/ICollSurplusPool.sol\\\";\\nimport \\\"./Interfaces/IZUSDToken.sol\\\";\\nimport \\\"./Interfaces/ISortedTroves.sol\\\";\\nimport \\\"./Interfaces/IZEROToken.sol\\\";\\nimport \\\"./Interfaces/IZEROStaking.sol\\\";\\nimport \\\"./Interfaces/IFeeDistributor.sol\\\";\\nimport \\\"./Dependencies/Ownable.sol\\\";\\nimport \\\"./Dependencies/BaseMath.sol\\\";\\nimport \\\"./Dependencies/console.sol\\\";\\n\\ncontract TroveManagerStorage is Ownable, BaseMath {\\n string public constant NAME = \\\"TroveManager\\\";\\n\\n // --- Connected contract declarations ---\\n\\n address public troveManagerRedeemOps;\\n\\n address public borrowerOperationsAddress;\\n\\n IStabilityPool public _stabilityPool;\\n\\n address gasPoolAddress;\\n\\n ICollSurplusPool collSurplusPool;\\n\\n IZUSDToken public _zusdToken;\\n\\n IZEROToken public _zeroToken;\\n\\n IZEROStaking public _zeroStaking;\\n\\n IFeeDistributor public feeDistributor;\\n\\n // A doubly linked list of Troves, sorted by their sorted by their collateral ratios\\n ISortedTroves public sortedTroves;\\n\\n // --- Data structures ---\\n\\n uint256 public baseRate;\\n\\n // The timestamp of the latest fee operation (redemption or new ZUSD issuance)\\n uint256 public lastFeeOperationTime;\\n\\n enum Status {\\n nonExistent,\\n active,\\n closedByOwner,\\n closedByLiquidation,\\n closedByRedemption\\n }\\n\\n // Store the necessary data for a trove\\n struct Trove {\\n uint256 debt;\\n uint256 coll;\\n uint256 stake;\\n Status status;\\n uint128 arrayIndex;\\n }\\n\\n mapping(address => Trove) public Troves;\\n\\n uint256 public totalStakes;\\n\\n // Snapshot of the value of totalStakes, taken immediately after the latest liquidation\\n uint256 public totalStakesSnapshot;\\n\\n // Snapshot of the total collateral across the ActivePool and DefaultPool, immediately after the latest liquidation.\\n uint256 public totalCollateralSnapshot;\\n\\n /*\\n * L_ETH and L_ZUSDDebt track the sums of accumulated liquidation rewards per unit staked. During its lifetime, each stake earns:\\n *\\n * An ETH gain of ( stake * [L_ETH - L_ETH(0)] )\\n * A ZUSDDebt increase of ( stake * [L_ZUSDDebt - L_ZUSDDebt(0)] )\\n *\\n * Where L_ETH(0) and L_ZUSDDebt(0) are snapshots of L_ETH and L_ZUSDDebt for the active Trove taken at the instant the stake was made\\n */\\n uint256 public L_ETH;\\n uint256 public L_ZUSDDebt;\\n\\n // Map addresses with active troves to their RewardSnapshot\\n mapping(address => RewardSnapshot) public rewardSnapshots;\\n\\n // Object containing the ETH and ZUSD snapshots for a given active trove\\n struct RewardSnapshot {\\n uint256 ETH;\\n uint256 ZUSDDebt;\\n }\\n\\n // Array of all active trove addresses - used to to compute an approximate hint off-chain, for the sorted list insertion\\n address[] public TroveOwners;\\n\\n // Error trackers for the trove redistribution calculation\\n uint256 public lastETHError_Redistribution;\\n uint256 public lastZUSDDebtError_Redistribution;\\n}\\n\",\"keccak256\":\"0x979836e7db9988074cd7cbbaaa94d67a297a078a8f93ceb14430ffe548545145\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x60c06040523480156200001157600080fd5b50604051620058f2380380620058f2833981016040819052620000349162000128565b8162000049336001600160e01b036200006316565b60805260601b6001600160601b03191660a05250620001c4565b6001600160a01b038116620000955760405162461bcd60e51b81526004016200008c9062000182565b60405180910390fd5b6001600160a01b038116620000b26001600160e01b036200010716565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a36000604051620000f79062000165565b6040519081900390209190915550565b600080604051620001189062000165565b6040519081900390205492915050565b600080604083850312156200013b578182fd5b825160208401519092506001600160a01b03811681146200015a578182fd5b809150509250929050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b60805160a05160601c615707620001eb60003980610ff152508061223252506157076000f3fe608060405234801561001057600080fd5b50600436106104c25760003560e01c8063756b253e11610278578063b0d8e1811161015c578063d293c710116100ce578063d815e8e911610092578063d815e8e91461095a578063d9a7244414610962578063e056e91814610975578063e2ac77b014610988578063f36b24251461099b578063fe2ba848146109a3576104c2565b8063d293c71014610906578063d380a37c14610919578063d3d6f84314610921578063d5b3563514610934578063d66a255314610947576104c2565b8063be4b033411610120578063be4b0334146108cb578063bf9befb1146108d3578063c35bc550146108db578063c52861f2146108e3578063c7b55481146108eb578063cbd138ae146108f3576104c2565b8063b0d8e18114610867578063b7f8cf9b1461087a578063b82f263d14610882578063b91af97c14610895578063bcd37526146108b8576104c2565b8063887105d3116101f55780639dd233d2116101b95780639dd233d2146108325780639f0706701461083a578063a20baee614610773578063a3f4df7e14610842578063ae7bec1914610857578063ae9187541461085f576104c2565b8063887105d3146107f4578063893d20e8146107fc57806396d711ff146108045780639708daf41461080c5780639976cf451461081f576104c2565b80637cf54e401161023c5780637cf54e40146107b65780637f7dde4a146107be578063807d138d146107c657806382fe3eb9146107ce57806387436936146107e1576104c2565b8063756b253e14610783578063759b303414610796578063794e57241461079e578063795d26c3146107a6578063797250e3146107ae576104c2565b80633cc74225116103aa57806361ec893d1161031c5780636b444952116102e05780636b4449521461072c5780636ef6433814610734578063716c47e61461075857806372423c171461076057806372fe25aa14610773578063741bef1a1461077b576104c2565b806361ec893d146106e3578063631203b0146106eb57806364cee260146106fe578063653d46e71461071157806366ca4a2114610724576104c2565b80634a767d681161036e5780634a767d681461067a5780634e443d9e1461068d5780635733d58f146106ad5780635d6b480f146106b55780635d8c9609146106c85780635dba4c4a146106db576104c2565b80633cc742251461063157806342ccf1e414610639578063477d66cf1461064c578063480cd5781461065f57806349eefeee14610672576104c2565b806317c62b17116104435780631f68f20a116104075780631f68f20a146105eb57806321e37801146105f35780632b11551a146106065780632f8655681461060e57806331c903b0146106215780633a12859514610629576104c2565b806317c62b171461059757806318f2817a146105aa5780631a59a50e146105bd5780631bf43555146105d05780631e8b1c2b146105d8576104c2565b806312261ee71161048a57806312261ee71461053557806312610e921461053d57806313af40351461055057806315d549f1146105635780631673c79a14610576576104c2565b806301f16e18146104c757806305b6f5ca146104dc578063071a7541146104ef5780630b0765571461050d5780630d43e8ad14610520575b600080fd5b6104da6104d5366004614d96565b6109b6565b005b6104da6104ea366004614f61565b610f1c565b6104f7610fb3565b6040516105049190615568565b60405180910390f35b6104da61051b366004614c9f565b610fb8565b610528610fe0565b604051610504919061512e565b610528610fef565b6104f761054b366004614cd7565b611013565b6104da61055e366004614c9f565b61106b565b6104f7610571366004614c9f565b6110ac565b610589610584366004614c9f565b6110d0565b604051610504929190615571565b6104f76105a5366004614c9f565b6110e9565b6104f76105b8366004614c9f565b6110f4565b6104f76105cb366004614c9f565b611107565b6104f76111cd565b6104da6105e6366004614d02565b6111da565b6104f761153b565b6104f7610601366004614c9f565b611541565b6104f761156b565b6104da61061c366004614c9f565b61157a565b6104f76115e0565b6105286115ed565b6105286115fc565b6104f7610647366004614c9f565b61160b565b6104f761065a366004614ec4565b61163c565b6104f761066d366004614c9f565b61164f565b6104f761166d565b6104f7610688366004614cd7565b611673565b6106a061069b366004614ec4565b611692565b60405161050491906151a1565b6104f761169d565b6104da6106c3366004614cd7565b61171a565b6104f76106d6366004614c9f565b611766565b6104da611771565b6104f76117dc565b6104f76106f9366004614ec4565b6117e1565b6104f761070c366004614c9f565b6117ee565b6104da61071f366004614ec4565b61180c565b6104f7611b96565b6104f7611ba8565b610747610742366004614c9f565b611bae565b6040516105049594939291906155a3565b610528611be8565b6104f761076e366004614cd7565b611bf7565b6104f7611c54565b610528611c60565b610528610791366004614ec4565b611c6f565b6104f7611c96565b6104f7611ca3565b6104f7611ce8565b6104f7611e07565b610528611e0d565b610528611e1c565b6104f7611e2b565b6104da6107dc366004614c9f565b611e31565b6104da6107ef366004614c9f565b611e42565b6104f7611ece565b610528611f9d565b6104f7611fbc565b6104da61081a366004614feb565b611fc2565b6104f761082d366004614cd7565b61205b565b6104f761208e565b610528612094565b61084a6120a3565b60405161050491906151da565b6105286120cb565b6105286120da565b6104f7610875366004614c9f565b6120e9565b610528612110565b6104f7610890366004614ec4565b61211f565b6108a86108a3366004614c9f565b61212a565b604051610504949392919061560f565b6104da6108c6366004614ef4565b61218e565b6104f7612224565b6104f761222a565b6104f7612230565b6104f7612254565b6104f7612266565b6104da610901366004614c9f565b612272565b6104f7610914366004614cd7565b612285565b6104f7612298565b6104f761092f366004614cd7565b61229e565b6104f7610942366004614ec4565b6122d4565b6104f7610955366004614c9f565b6122e7565b610528612302565b610528610970366004614ec4565b612311565b6106a0610983366004614c9f565b61233b565b6106a0610996366004614c9f565b612399565b6104f76123a4565b6104da6109b1366004614c9f565b6123b1565b6109be611f9d565b6001600160a01b0316336001600160a01b0316146109f75760405162461bcd60e51b81526004016109ee906153c5565b60405180910390fd5b8051610a02906123c2565b610a0f81602001516123c2565b610a1c81604001516123c2565b610a2981606001516123c2565b610a3681608001516123c2565b610a438160a001516123c2565b610a508160c001516123c2565b610a5d8160e001516123c2565b610a6b8161010001516123c2565b610a798161012001516123c2565b610a878161014001516123c2565b610a958161016001516123c2565b610aa38161018001516123c2565b610ab1816101a001516123c2565b8051600c80546001600160a01b03199081166001600160a01b038085169190911790925560208401516004805483169184169190911790556040808501516003805484169185169190911790556060850151600580548416918516919091179055608085015160008054841691851691909117905560a085015160018054841691851691909117905560c085015160068054841691851691909117905560e0850151600780548416918516919091179055610100850151600880548416918516919091179055610120850151600280548416918516919091179055610140850151600980548416918516919091179055610160850151600d80548416918516919091179055610180850151600a805484169185169190911790556101a0850151600b80549093169316929092179055517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db991610c0c9161512e565b60405180910390a17f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b18160200151604051610c47919061512e565b60405180910390a17fbf65195e6d5213f6fcbce65b1454c925197a45e616dabd2e243542b039b050928160600151604051610c82919061512e565b60405180910390a17f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed9858160600151604051610cbd919061512e565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828160800151604051610cf8919061512e565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b8160a00151604051610d33919061512e565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f8160c00151604051610d6e919061512e565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa08160e00151604051610da9919061512e565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d816101000151604051610de5919061512e565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264816101200151604051610e21919061512e565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d816101400151604051610e5d919061512e565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800816101600151604051610e99919061512e565b60405180910390a17f61e0c29d5028a9e4facaa476a46e78912e99f1ba945c9560b86b82ebe36ee52d816101800151604051610ed5919061512e565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd816101a00151604051610f11919061512e565b60405180910390a150565b6004546040516000916060916001600160a01b0390911690610f419084903690615101565b600060405180830381855af49150503d8060008114610f7c576040519150601f19603f3d011682016040523d82523d6000602084013e610f81565b606091505b5091509150818190610fa65760405162461bcd60e51b81526004016109ee91906151da565b5050505050505050505050565b600281565b610fc0612407565b600054600154610fdd916001600160a01b03908116911683612433565b50565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061101d612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff61254516565b6001600160a01b03851660009081526010602052604090208190559150505b92915050565b611073611f9d565b6001600160a01b0316336001600160a01b0316146110a35760405162461bcd60e51b81526004016109ee906153c5565b610fdd81612587565b60006110b6612407565b6110bf82612612565b6001600160801b031690505b919050565b6016602052600090815260409020805460019091015482565b60006110658261160b565b60006110fe612407565b611065826126ac565b6001600160a01b0381166000908152601660205260408120546014548290611135908363ffffffff61254516565b905080158061116e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561116b57fe5b14155b1561117e576000925050506110cb565b6001600160a01b038416600090815260106020526040812060020154906111c3670de0b6b3a76400006111b7848663ffffffff61275f16565b9063ffffffff61279916565b9695505050505050565b6809c2007651b250000081565b80516111f85760405162461bcd60e51b81526004016109ee906153f6565b6000546001546006546001600160a01b0392831692918216911661121a614b2b565b611222614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ec57600080fd5b505afa158015611300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113249190614edc565b60208301528151611334906127db565b158015604084015261135c576113558585846000015185602001518a612876565b9050611374565b6113718585846000015185602001518a612b8b565b90505b60008160200151116113985760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad926113cc92600401615571565b600060405180830381600087803b1580156113e657600080fd5b505af11580156113fa573d6000803e3d6000fd5b5050505061141285858360c001518460e00151612ccb565b61010081015115611489576008546101008201516040516364a197f360e01b81526001600160a01b03888116936364a197f393611456939290911691600401615188565b600060405180830381600087803b15801561147057600080fd5b505af1158015611484573d6000803e3d6000fd5b505050505b611497858260400151612f2f565b60208101516060830152610100810151604082015182516114cf92916114c3919063ffffffff61254516565b9063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611517949092909161560f565b60405180910390a1611533853383606001518460400151613090565b505050505050565b600e5481565b6001600160a01b03811660009081526010602052604081206003015460ff16600481111561106557fe5b60006115756115e0565b905090565b6115838161316d565b6040805160018082528183019092526060916020808301908036833701905050905081816000815181106115b357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506115dc816111da565b5050565b6000611575600e546131b6565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290611135908363ffffffff61254516565b6000611065611649611b96565b83613253565b6001600160a01b031660009081526010602052604090206001015490565b60175490565b600080600061168185613271565b9150915060006111c38383876132f7565b6000611065826127db565b60035460408051635733d58f60e01b815290516000926001600160a01b031691635733d58f916004808301926020929190829003018186803b1580156116e257600080fd5b505afa1580156116f6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115759190614edc565b611722612407565b80600481111561172e57fe5b6001600160a01b0383166000908152601060205260409020600301805460ff1916600183600481111561175d57fe5b02179055505050565b600061106582611107565b611779612407565b6000611783613329565b9050670de0b6b3a764000081111561179757fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c906117cc908390615568565b60405180910390a1610fdd61336d565b603c81565b60006110656116496123a4565b6001600160a01b031660009081526010602052604090206002015490565b611814614ba8565b506040805160e081018252600080546001600160a01b0390811683526001548116602084015292820181905260608201819052600d548316608083015260a0820181905260c082015260065490911661186b614b2b565b611873614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fb9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b15801561193d57600080fd5b505afa158015611951573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119759190614edc565b60208301528151611985906127db565b15801560408401526119ac576119a58483600001518460200151886133c2565b90506119cc565b6119c9846000015185602001518460000151856020015189613869565b90505b60008160200151116119f05760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad92611a2492600401615571565b600060405180830381600087803b158015611a3e57600080fd5b505af1158015611a52573d6000803e3d6000fd5b50505050611a72846000015185602001518360c001518460e00151612ccb565b61010081015115611ae95783516008546101008301516040516364a197f360e01b81526001600160a01b03938416936364a197f393611ab693911691600401615188565b600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050505b611afb84600001518260400151612f2f565b6020810151606083015261010081015160408201518251611b2792916114c3919063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611b6f949092909161560f565b60405180910390a1611b8f84600001513383606001518460400151613090565b5050505050565b6000611575611ba3613329565b613a1f565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b6000611c01612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff613b0116565b6001600160a01b038516600090815260106020526040902060010181905591505092915050565b670de0b6b3a764000081565b6002546001600160a01b031681565b60178181548110611c7c57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60035460408051631e5395c960e21b815290516000926001600160a01b03169163794e5724916004808301926020929190829003018186803b1580156116e257600080fd5b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015611d2c57600080fd5b505afa158015611d40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d649190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b505afa158015611dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dee9190614edc565b9050611e00828263ffffffff613b0116565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b611e39612407565b610fdd81613b26565b611e4a611f9d565b6001600160a01b0316336001600160a01b031614611e7a5760405162461bcd60e51b81526004016109ee906153c5565b611e83816123c2565b600480546001600160a01b0319166001600160a01b0383161790556040517f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b190610f1190839061512e565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b158015611f1357600080fd5b505afa158015611f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4b9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b600080604051611fac90615111565b6040519081900390205492915050565b60135481565b6004546040516000916060916001600160a01b0390911690611fe79084903690615101565b600060405180830381855af49150503d8060008114612022576040519150601f19603f3d011682016040523d82523d6000602084013e612027565b606091505b509150915081819061204c5760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050505050565b6000612065612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff613b0116565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b60008060006120f784613271565b9150915060006121078383613b83565b95945050505050565b6005546001600160a01b031681565b600061106582613bb8565b6001600160a01b03811660009081526010602052604081208054600190910154909180612156856110e9565b915061216185611766565b9050612173848363ffffffff613b0116565b9350612185838263ffffffff613b0116565b92509193509193565b6004546040516000916060916001600160a01b03909116906121b39084903690615101565b600060405180830381855af49150503d80600081146121ee576040519150601f19603f3d011682016040523d82523d6000602084013e6121f3565b606091505b50915091508181906122185760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000611575612261613329565b6131b6565b670ddd4b8c6c7d70d881565b61227a612407565b610fdd816002613be4565b60006122918383611673565b9392505050565b600f5481565b60006122a8612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff61254516565b60006110656122e1612254565b83613cf9565b6001600160a01b031660009081526010602052604090205490565b6009546001600160a01b031681565b60006017828154811061232057fe5b6000918252602090912001546001600160a01b031692915050565b600060016001600160a01b03831660009081526010602052604090206003015460ff16600481111561236957fe5b14612376575060006110cb565b506014546001600160a01b03821660009081526016602052604090205410919050565b60006110658261233b565b6000611575600e54613a1f565b6123b9612407565b610fdd81613d39565b6001600160a01b0381166123e85760405162461bcd60e51b81526004016109ee906152a6565b803b806115dc5760405162461bcd60e51b81526004016109ee9061544c565b6005546001600160a01b031633146124315760405162461bcd60e51b81526004016109ee90615368565b565b61243c8161233b565b156125405761244a8161316d565b600061245582611107565b905060006124628361160b565b6001600160a01b038416600090815260106020526040902060010154909150612491908363ffffffff613b0116565b6001600160a01b03841660009081526010602052604090206001810191909155546124c2908263ffffffff613b0116565b6001600160a01b0384166000908152601060205260409020556124e483613b26565b6124f085858385613d89565b6001600160a01b0383166000818152601060205260408082208054600182015460029092015492516000805160206156b28339815191529461253594929392916155e3565b60405180910390a250505b505050565b600061229183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613e71565b6001600160a01b0381166125ad5760405162461bcd60e51b81526004016109ee90615264565b806001600160a01b03166125bf611f9d565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600060405161260290615111565b6040519081900390209190915550565b601780546001808201835560008381527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1590920180546001600160a01b0319166001600160a01b0386161790559154909161266d9190612545565b6001600160a01b039290921660009081526010602052604090206003018054610100600160881b0319166101006001600160801b038516021790555090565b6001600160a01b03811660009081526010602052604081206001015481906126d390613e9d565b6001600160a01b03841660009081526010602052604090206002018054908290556011549192509061271d908390612711908463ffffffff61254516565b9063ffffffff613b0116565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829161275091615568565b60405180910390a15092915050565b60008261276e57506000611065565b8282028284828161277b57fe5b04146122915760405162461bcd60e51b81526004016109ee90615327565b600061229183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ed9565b6000806127e783613bb8565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561283757600080fd5b505afa15801561284b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286f9190614edc565b1192915050565b61287e614b5c565b612886614be4565b61288e614b5c565b848252600060808301526128a0611ce8565b60a08301526128ad611ece565b60c0830152600060208301525b835182602001511015612b8057838260200151815181106128d757fe5b6020908102919091018101516001600160a01b03166060840181905260009081526010909152604090206003015460019060ff16600481111561291657fe5b1461292057612b70565b61292e826060015187611673565b60408301526080820151612a9557600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561298a57600080fd5b505afa15801561299e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c29190614edc565b8260400151101580156129d457508151155b156129de57612b70565b60006129f38360c001518460a00151896132f7565b9050612a108989856060015186604001518760000151868d613f10565b60808101518451919350612a2a919063ffffffff61254516565b8352608082015160a0840151612a459163ffffffff61254516565b60a08085019190915282015160c0840151612a659163ffffffff61254516565b60c0840152612a7484836142e6565b9350612a898360c001518460a00151896143fd565b15608084015250612b70565b81608001518015612b2e5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015612aef57600080fd5b505afa158015612b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b279190614edc565b8260400151105b15612b7057612b4788888460600151856000015161449c565b60808101518351919250612b61919063ffffffff61254516565b8252612b6d83826142e6565b92505b60208201805160010190526128ba565b505095945050505050565b612b93614b5c565b612b9b614be4565b612ba3614b5c565b848252600060208301525b835182602001511015612b805783826020015181518110612bcb57fe5b60209081029190910101516001600160a01b031660608301819052612bf09087611673565b6040808401919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c739190614edc565b82604001511015612cbb57612c9288888460600151856000015161449c565b60808101518351919250612cac919063ffffffff61254516565b8252612cb883826142e6565b92505b6020820180516001019052612bae565b81612cd557612f29565b601854600090612cf79061271184670de0b6b3a764000063ffffffff61275f16565b90506000612d1c601954612711670de0b6b3a76400008761275f90919063ffffffff16565b90506000612d356011548461279990919063ffffffff16565b90506000612d4e6011548461279990919063ffffffff16565b9050612d75612d686011548461275f90919063ffffffff16565b859063ffffffff61254516565b601855601154612d9d90612d9090839063ffffffff61275f16565b849063ffffffff61254516565b601955601454612db3908363ffffffff613b0116565b601455601554612dc9908263ffffffff613b0116565b60158190556014546040517f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e392612e009291615571565b60405180910390a160405163121cbc4d60e11b81526001600160a01b03891690632439789a90612e34908990600401615568565b600060405180830381600087803b158015612e4e57600080fd5b505af1158015612e62573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038a16925063f2e91d719150612e92908990600401615568565b600060405180830381600087803b158015612eac57600080fd5b505af1158015612ec0573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b038b1692506364a197f39150612ef2908a908990600401615188565b600060405180830381600087803b158015612f0c57600080fd5b505af1158015612f20573d6000803e3d6000fd5b50505050505050505b50505050565b6011546012819055506000826001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7357600080fd5b505afa158015612f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fab9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ffd57600080fd5b505afa158015613011573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130359190614edc565b905061304b81612711848663ffffffff61254516565b60138190556012546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf60926130829291615571565b60405180910390a150505050565b811561310157600954600754604051631062c15f60e11b81526001600160a01b03928316926320c582be926130ce9291169087908790600401615142565b600060405180830381600087803b1580156130e857600080fd5b505af11580156130fc573d6000803e3d6000fd5b505050505b8015612f29576040516364a197f360e01b81526001600160a01b038516906364a197f3906131359086908590600401615188565b600060405180830381600087803b15801561314f57600080fd5b505af1158015613163573d6000803e3d6000fd5b5050505050505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561319957fe5b14610fdd5760405162461bcd60e51b81526004016109ee90615519565b600061106561324583600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b505afa158015613221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127119190614edc565b670de0b6b3a76400006145ce565b6000612291670de0b6b3a76400006111b7858563ffffffff61275f16565b600080600061327f84611107565b9050600061328c8561160b565b6001600160a01b038616600090815260106020526040812060010154919250906132bc908463ffffffff613b0116565b6001600160a01b038716600090815260106020526040812054919250906132e9908463ffffffff613b0116565b919550909350505050915091565b6000821561331e576000613315846111b7878663ffffffff61275f16565b91506122919050565b506000199392505050565b6000806133346145e4565b9050600061334a670ddd4b8c6c7d70d883614600565b9050611e00670de0b6b3a76400006111b783600e5461275f90919063ffffffff16565b6000613384600f544261254590919063ffffffff16565b9050603c8110610fdd5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc91610f1191615568565b6133ca614b5c565b6133d2614be4565b6133da614b5c565b848252600060808301526133ec611ce8565b60a08301526133f9611ece565b8260c001818152505086608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561343f57600080fd5b505afa158015613453573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134779190614cbb565b82606001906001600160a01b031690816001600160a01b031681525050600087608001516001600160a01b0316631e2231436040518163ffffffff1660e01b815260040160206040518083038186803b1580156134d357600080fd5b505afa1580156134e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350b9190614cbb565b6000602085015290505b84836020015110801561353e5750806001600160a01b031683606001516001600160a01b031614155b1561385e5760808801516060840151604051632dc9c0eb60e21b81526000926001600160a01b03169163b72703ac9161357a919060040161512e565b60206040518083038186803b15801561359257600080fd5b505afa1580156135a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ca9190614cbb565b90506135da846060015189611673565b6040850152608084015161375357600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561363657600080fd5b505afa15801561364a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061366e9190614edc565b84604001511015801561368057508351155b1561368b575061385e565b60006136a08560c001518660a001518b6132f7565b8a5160208c01516060880151604089015189519495506136c194868f613f10565b608081015186519195506136db919063ffffffff61254516565b8552608084015160a08601516136f69163ffffffff61254516565b8560a00181815250506137238461010001516114c38660a001518860c0015161254590919063ffffffff16565b60c086015261373286856142e6565b95506137478560c001518660a001518b6143fd565b15608086015250613840565b836080015180156137ec5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156137ad57600080fd5b505afa1580156137c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e59190614edc565b8460400151105b1561383a5761380d89600001518a602001518660600151876000015161449c565b60808101518551919450613827919063ffffffff61254516565b845261383385846142e6565b9450613840565b5061385e565b6001600160a01b031660608401526020830180516001019052613515565b505050949350505050565b613871614b5c565b613879614be4565b613881614b5c565b600d54858352600060208401526001600160a01b03165b8483602001511015613a1357806001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156138dd57600080fd5b505afa1580156138f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139159190614cbb565b6001600160a01b03166060840181905261392f9088611673565b6040808501919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b15801561397a57600080fd5b505afa15801561398e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b29190614edc565b836040015110156139fe576139d189898560600151866000015161449c565b608081015184519193506139eb919063ffffffff61254516565b83526139f784836142e6565b9350613a03565b613a13565b6020830180516001019052613898565b50505095945050505050565b6000611065613a7683600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b031663240926696040518163ffffffff1660e01b815260040160206040518083038186803b158015613ac457600080fd5b505afa158015613ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613afc9190614edc565b6145ce565b6000828201838110156122915760405162461bcd60e51b81526004016109ee9061522d565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92610f11929091615571565b60008115613baf57613ba8826111b78568056bc75e2d6310000063ffffffff61275f16565b9050611065565b50600019611065565b600080613bc3611ece565b90506000613bcf611ce8565b9050613bdc8282866132f7565b949350505050565b6000816004811115613bf257fe5b14158015613c0c57506001816004811115613c0957fe5b14155b613c1257fe5b601754613c1e816146ab565b6001600160a01b0383166000908152601060205260409020600301805483919060ff19166001836004811115613c5057fe5b02179055506001600160a01b0383166000908152601060209081526040808320600180820185905590849055601690925282208281550155613c928382614751565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e90613cc290869060040161512e565b600060405180830381600087803b158015613cdc57600080fd5b505af1158015613cf0573d6000803e3d6000fd5b50505050505050565b600080613d18670de0b6b3a76400006111b7868663ffffffff61275f16565b90508281106122915760405162461bcd60e51b81526004016109ee90615481565b6001600160a01b038116600090815260106020526040902060020154601154613d68908263ffffffff61254516565b601155506001600160a01b0316600090815260106020526040812060020155565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a90613db5908590600401615568565b600060405180830381600087803b158015613dcf57600080fd5b505af1158015613de3573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150613e13908590600401615568565b600060405180830381600087803b158015613e2d57600080fd5b505af1158015613e41573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150613135908490600401615568565b60008184841115613e955760405162461bcd60e51b81526004016109ee91906151da565b505050900390565b60008060135460001415613eb2575081611065565b600060125411613ebe57fe5b6122916013546111b76012548661275f90919063ffffffff16565b60008183613efa5760405162461bcd60e51b81526004016109ee91906151da565b506000838581613f0657fe5b0495945050505050565b613f18614b5c565b613f20614c2c565b601754600110613f3057506142db565b613f398761212a565b60408501526020848101919091528401819052908352613f58906148f2565b604083018190526801158e460913d0000060608401526020830151613f829163ffffffff61254516565b8152670de0b6b3a7640000861161404d57613fa7898983602001518460400151613d89565b613fb087613d39565b60006080830181905260a0830152815160c0830152805160e0830152613fd7876003613be4565b815160208301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b60405180910390a2866001600160a01b03166000805160206156b28339815191526000806000600260405161404094939291906151ac565b60405180910390a26142d9565b670de0b6b3a7640000861180156140e85750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156140ad57600080fd5b505afa1580156140c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e59190614edc565b86105b1561413857614101898983602001518460400151613d89565b61410a87613d39565b8151815161411991908761497e565b60e086015260c085015260a08401526080830152613fd7876003613be4565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561418657600080fd5b505afa15801561419a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141be9190614edc565b86101580156141cc57508386105b80156141d9575081518510155b156142c8576141f2898983602001518460400151613d89565b846141f957fe5b61420287613d39565b61421582600001518360200151856149ea565b9150614222876003613be4565b6101008201511561429757600854610100830151604051633f10abab60e01b81526001600160a01b0390921691633f10abab91614264918b9190600401615188565b600060405180830381600087803b15801561427e57600080fd5b505af1158015614292573d6000803e3d6000fd5b505050505b815160a08301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b6142d0614b5c565b91506142db9050565b505b979650505050505050565b6142ee614b5c565b604080830151908401516143079163ffffffff613b0116565b6040820152606080830151908401516143259163ffffffff613b0116565b6060820152815160208401516143409163ffffffff613b0116565b602080830191909152820151835161435d9163ffffffff613b0116565b8152608080830151908401516143789163ffffffff613b0116565b608082015260a080830151908401516143969163ffffffff613b0116565b60a082015260c080830151908401516143b49163ffffffff613b0116565b60c082015260e080830151908401516143d29163ffffffff613b0116565b60e082015261010080830151908401516143f19163ffffffff613b0116565b61010082015292915050565b60008061440b8585856132f7565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561445b57600080fd5b505afa15801561446f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144939190614edc565b11949350505050565b6144a4614b5c565b6144ac614c2c565b6144b58461212a565b604085019081526020858101928352860192909252918452905190516144df918891889190613d89565b6144e884613d39565b6144f582602001516148f2565b604083018190526801158e460913d0000060608401526020830151600091614523919063ffffffff61254516565b90506145348360000151828661497e565b60e087015260c086015260a08501526080840152614553856003613be4565b825160208401516040516001600160a01b03881692600080516020615692833981519152926145849260019061557f565b60405180910390a2846001600160a01b03166000805160206156b2833981519152600080600060016040516145bc94939291906151ac565b60405180910390a25050949350505050565b60008183106145dd5781612291565b5090919050565b6000611575603c6111b7600f544261254590919063ffffffff16565b6000631f54050082111561461657631f54050091505b8161462a5750670de0b6b3a7640000611065565b670de0b6b3a764000083835b60018111156146a1576002810661466b576146518283614af8565b915061466481600263ffffffff61279916565b905061469c565b6146758284614af8565b92506146818283614af8565b915061469960026111b783600163ffffffff61254516565b90505b614636565b6111c38284614af8565b6001811180156147355750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b1580156146fb57600080fd5b505afa15801561470f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147339190614edc565b115b610fdd5760405162461bcd60e51b81526004016109ee906152dd565b6001600160a01b03821660009081526010602052604081206003015460ff169081600481111561477d57fe5b141580156147975750600181600481111561479457fe5b14155b61479d57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b03169083906147d5826001612545565b905080836001600160801b031611156147ea57fe5b6000601782815481106147f957fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b03871690811061482b57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a906148b49083908790615166565b60405180910390a160178054806148c757fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b600354604080516324386ecd60e11b815290516000926001600160a01b031691634870dd9a916004808301926020929190829003018186803b15801561493757600080fd5b505afa15801561494b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496f9190614edc565b828161497757fe5b0492915050565b600080808084156149d45761499387866145ce565b93506149a9876111b7888763ffffffff61275f16565b92506149bb878563ffffffff61254516565b91506149cd868463ffffffff61254516565b90506149e1565b5060009250829150859050845b93509350935093565b6149f2614b5c565b838152602080820184905260035460408051631e5395c960e21b81529051600093614a8e9387936111b7936001600160a01b039092169263794e572492600480840193829003018186803b158015614a4957600080fd5b505afa158015614a5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a819190614edc565b889063ffffffff61275f16565b9050614a99816148f2565b604083018190526801158e460913d00000606084015260808301869052614ac790829063ffffffff61254516565b60a0830152614adc848263ffffffff61254516565b61010083015250600060c0820181905260e08201529392505050565b600080614b0b848463ffffffff61275f16565b9050613bdc670de0b6b3a76400006111b7836706f05b59d3b20000613b01565b6040518060a00160405280600081526020016000815260200160001515815260200160008152602001600081525090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040518060e0016040528060008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b80356110658161567c565b60008083601f840112614c69578081fd5b50813567ffffffffffffffff811115614c80578182fd5b602083019150836020828501011115614c9857600080fd5b9250929050565b600060208284031215614cb0578081fd5b81356122918161567c565b600060208284031215614ccc578081fd5b81516122918161567c565b60008060408385031215614ce9578081fd5b8235614cf48161567c565b946020939093013593505050565b60006020808385031215614d14578182fd5b823567ffffffffffffffff811115614d2a578283fd5b80840185601f820112614d3b578384fd5b80359150614d50614d4b83615651565b61562a565b8281528381019082850185850284018601891015614d6c578687fd5b8693505b848410156142d957614d828982614c4d565b835260019390930192918501918501614d70565b60006101c0808385031215614da9578182fd5b614db28161562a565b614dbc8585614c4d565b8152614dcb8560208601614c4d565b6020820152614ddd8560408601614c4d565b6040820152614def8560608601614c4d565b6060820152614e018560808601614c4d565b6080820152614e138560a08601614c4d565b60a0820152614e258560c08601614c4d565b60c0820152614e378560e08601614c4d565b60e08201526101009150614e4d85838601614c4d565b828201526101209150614e6285838601614c4d565b828201526101409150614e7785838601614c4d565b828201526101609150614e8c85838601614c4d565b828201526101809150614ea185838601614c4d565b828201526101a09150614eb685838601614c4d565b918101919091529392505050565b600060208284031215614ed5578081fd5b5035919050565b600060208284031215614eed578081fd5b5051919050565b600080600080600080600060e0888a031215614f0e578283fd5b873596506020880135614f208161567c565b95506040880135614f308161567c565b94506060880135614f408161567c565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a03610160811215614f7e578182fd5b8935985060208a0135614f908161567c565b975060408a0135614fa08161567c565b965060608a0135614fb08161567c565b955060808a810135955060a08b0135945060c08b0135935060df1982011215614fd7578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c0361018081121561500b578485fd5b8b359a5060208c013561501d8161567c565b995060408c013561502d8161567c565b985060608c013561503d8161567c565b975060808c810135975060a08d0135965060c08d0135955060df19820190811215615066578384fd5b615070606061562a565b9150604081121561507f578384fd5b5061508a604061562a565b60e08d01356150988161567c565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff8111156150dd578283fd5b6150e98d828e01614c58565b8194508093505050509295989b9194979a5092959850565b6000828483379101908152919050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b848152602081018490526040810183905260808101600483106151cb57fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015615206578581018301518582016040015282016151ea565b818111156152175783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252603b908201527f54726f76654d616e616765723a2043616c6c6572206973206e6f74207468652060408201527f426f72726f7765724f7065726174696f6e7320636f6e74726163740000000000606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2043616c6c646174612061646472657373206160408201527572726179206d757374206e6f7420626520656d70747960501b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526022908201527f54726f76654d616e616765723a206e6f7468696e6720746f206c697175696461604082015261746560f01b606082015260800190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b90815260200190565b918252602082015260400190565b838152602081018390526060810161559683615671565b6040830152949350505050565b858152602081018590526040810184905260a08101600584106155c257fe5b60608201939093526001600160801b03919091166080909101529392505050565b84815260208101849052604081018390526080810161560183615671565b606083015295945050505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff8111828210171561564957600080fd5b604052919050565b600067ffffffffffffffff821115615667578081fd5b5060209081020190565b80600481106110cb57fe5b6001600160a01b0381168114610fdd57600080fdfeea67486ed7ebe3eea8ab3390efd4a3c8aae48be5bea27df104a8af786c408434c3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba2646970667358221220a4c2a9a9ec603c1ba14143d02dd4e890d8f91d610315ce69bf8078c0892e8c2464736f6c634300060b0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106104c25760003560e01c8063756b253e11610278578063b0d8e1811161015c578063d293c710116100ce578063d815e8e911610092578063d815e8e91461095a578063d9a7244414610962578063e056e91814610975578063e2ac77b014610988578063f36b24251461099b578063fe2ba848146109a3576104c2565b8063d293c71014610906578063d380a37c14610919578063d3d6f84314610921578063d5b3563514610934578063d66a255314610947576104c2565b8063be4b033411610120578063be4b0334146108cb578063bf9befb1146108d3578063c35bc550146108db578063c52861f2146108e3578063c7b55481146108eb578063cbd138ae146108f3576104c2565b8063b0d8e18114610867578063b7f8cf9b1461087a578063b82f263d14610882578063b91af97c14610895578063bcd37526146108b8576104c2565b8063887105d3116101f55780639dd233d2116101b95780639dd233d2146108325780639f0706701461083a578063a20baee614610773578063a3f4df7e14610842578063ae7bec1914610857578063ae9187541461085f576104c2565b8063887105d3146107f4578063893d20e8146107fc57806396d711ff146108045780639708daf41461080c5780639976cf451461081f576104c2565b80637cf54e401161023c5780637cf54e40146107b65780637f7dde4a146107be578063807d138d146107c657806382fe3eb9146107ce57806387436936146107e1576104c2565b8063756b253e14610783578063759b303414610796578063794e57241461079e578063795d26c3146107a6578063797250e3146107ae576104c2565b80633cc74225116103aa57806361ec893d1161031c5780636b444952116102e05780636b4449521461072c5780636ef6433814610734578063716c47e61461075857806372423c171461076057806372fe25aa14610773578063741bef1a1461077b576104c2565b806361ec893d146106e3578063631203b0146106eb57806364cee260146106fe578063653d46e71461071157806366ca4a2114610724576104c2565b80634a767d681161036e5780634a767d681461067a5780634e443d9e1461068d5780635733d58f146106ad5780635d6b480f146106b55780635d8c9609146106c85780635dba4c4a146106db576104c2565b80633cc742251461063157806342ccf1e414610639578063477d66cf1461064c578063480cd5781461065f57806349eefeee14610672576104c2565b806317c62b17116104435780631f68f20a116104075780631f68f20a146105eb57806321e37801146105f35780632b11551a146106065780632f8655681461060e57806331c903b0146106215780633a12859514610629576104c2565b806317c62b171461059757806318f2817a146105aa5780631a59a50e146105bd5780631bf43555146105d05780631e8b1c2b146105d8576104c2565b806312261ee71161048a57806312261ee71461053557806312610e921461053d57806313af40351461055057806315d549f1146105635780631673c79a14610576576104c2565b806301f16e18146104c757806305b6f5ca146104dc578063071a7541146104ef5780630b0765571461050d5780630d43e8ad14610520575b600080fd5b6104da6104d5366004614d96565b6109b6565b005b6104da6104ea366004614f61565b610f1c565b6104f7610fb3565b6040516105049190615568565b60405180910390f35b6104da61051b366004614c9f565b610fb8565b610528610fe0565b604051610504919061512e565b610528610fef565b6104f761054b366004614cd7565b611013565b6104da61055e366004614c9f565b61106b565b6104f7610571366004614c9f565b6110ac565b610589610584366004614c9f565b6110d0565b604051610504929190615571565b6104f76105a5366004614c9f565b6110e9565b6104f76105b8366004614c9f565b6110f4565b6104f76105cb366004614c9f565b611107565b6104f76111cd565b6104da6105e6366004614d02565b6111da565b6104f761153b565b6104f7610601366004614c9f565b611541565b6104f761156b565b6104da61061c366004614c9f565b61157a565b6104f76115e0565b6105286115ed565b6105286115fc565b6104f7610647366004614c9f565b61160b565b6104f761065a366004614ec4565b61163c565b6104f761066d366004614c9f565b61164f565b6104f761166d565b6104f7610688366004614cd7565b611673565b6106a061069b366004614ec4565b611692565b60405161050491906151a1565b6104f761169d565b6104da6106c3366004614cd7565b61171a565b6104f76106d6366004614c9f565b611766565b6104da611771565b6104f76117dc565b6104f76106f9366004614ec4565b6117e1565b6104f761070c366004614c9f565b6117ee565b6104da61071f366004614ec4565b61180c565b6104f7611b96565b6104f7611ba8565b610747610742366004614c9f565b611bae565b6040516105049594939291906155a3565b610528611be8565b6104f761076e366004614cd7565b611bf7565b6104f7611c54565b610528611c60565b610528610791366004614ec4565b611c6f565b6104f7611c96565b6104f7611ca3565b6104f7611ce8565b6104f7611e07565b610528611e0d565b610528611e1c565b6104f7611e2b565b6104da6107dc366004614c9f565b611e31565b6104da6107ef366004614c9f565b611e42565b6104f7611ece565b610528611f9d565b6104f7611fbc565b6104da61081a366004614feb565b611fc2565b6104f761082d366004614cd7565b61205b565b6104f761208e565b610528612094565b61084a6120a3565b60405161050491906151da565b6105286120cb565b6105286120da565b6104f7610875366004614c9f565b6120e9565b610528612110565b6104f7610890366004614ec4565b61211f565b6108a86108a3366004614c9f565b61212a565b604051610504949392919061560f565b6104da6108c6366004614ef4565b61218e565b6104f7612224565b6104f761222a565b6104f7612230565b6104f7612254565b6104f7612266565b6104da610901366004614c9f565b612272565b6104f7610914366004614cd7565b612285565b6104f7612298565b6104f761092f366004614cd7565b61229e565b6104f7610942366004614ec4565b6122d4565b6104f7610955366004614c9f565b6122e7565b610528612302565b610528610970366004614ec4565b612311565b6106a0610983366004614c9f565b61233b565b6106a0610996366004614c9f565b612399565b6104f76123a4565b6104da6109b1366004614c9f565b6123b1565b6109be611f9d565b6001600160a01b0316336001600160a01b0316146109f75760405162461bcd60e51b81526004016109ee906153c5565b60405180910390fd5b8051610a02906123c2565b610a0f81602001516123c2565b610a1c81604001516123c2565b610a2981606001516123c2565b610a3681608001516123c2565b610a438160a001516123c2565b610a508160c001516123c2565b610a5d8160e001516123c2565b610a6b8161010001516123c2565b610a798161012001516123c2565b610a878161014001516123c2565b610a958161016001516123c2565b610aa38161018001516123c2565b610ab1816101a001516123c2565b8051600c80546001600160a01b03199081166001600160a01b038085169190911790925560208401516004805483169184169190911790556040808501516003805484169185169190911790556060850151600580548416918516919091179055608085015160008054841691851691909117905560a085015160018054841691851691909117905560c085015160068054841691851691909117905560e0850151600780548416918516919091179055610100850151600880548416918516919091179055610120850151600280548416918516919091179055610140850151600980548416918516919091179055610160850151600d80548416918516919091179055610180850151600a805484169185169190911790556101a0850151600b80549093169316929092179055517f84861842e6a98dd759145eb5e7b48279d0f02ebeabc8a69e5196b2f4c5023db991610c0c9161512e565b60405180910390a17f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b18160200151604051610c47919061512e565b60405180910390a17fbf65195e6d5213f6fcbce65b1454c925197a45e616dabd2e243542b039b050928160600151604051610c82919061512e565b60405180910390a17f3ca631ffcd2a9b5d9ae18543fc82f58eb4ca33af9e6ab01b7a8e95331e6ed9858160600151604051610cbd919061512e565b60405180910390a17f78f058b189175430c48dc02699e3a0031ea4ff781536dc2fab847de4babdd8828160800151604051610cf8919061512e565b60405180910390a17f5ee0cae2f063ed938bb55046f6a932fb6ae792bf43624806bb90abe68a50be9b8160a00151604051610d33919061512e565b60405180910390a17f82966d27eea39b038ee0fa30cd16532bb24f6e65d31cb58fb227aa5766cdcc7f8160c00151604051610d6e919061512e565b60405180910390a17fcfb07d791fcafc032b35837b50eb84b74df518cf4cc287e8084f47630fa70fa08160e00151604051610da9919061512e565b60405180910390a17fe67f36a6e961157d6eff83b91f3af5a62131ceb6f04954ef74f51c1c05e7f88d816101000151604051610de5919061512e565b60405180910390a17f8c537274438aa850a330284665d81a85dd38267d09e4050d416bfc94142db264816101200151604051610e21919061512e565b60405180910390a17fcdf33850c44a1a874b5fefb51dae615ac6afebd581ef90d571f81b06541d8e9d816101400151604051610e5d919061512e565b60405180910390a17f65f4cf077bc01e4742eb5ad98326f6e95b63548ea24b17f8d5e823111fe78800816101600151604051610e99919061512e565b60405180910390a17f61e0c29d5028a9e4facaa476a46e78912e99f1ba945c9560b86b82ebe36ee52d816101800151604051610ed5919061512e565b60405180910390a17f7624075ed781e3aa34b0f492d70d1bb5a6fcde04534165e20f990d2e546be4dd816101a00151604051610f11919061512e565b60405180910390a150565b6004546040516000916060916001600160a01b0390911690610f419084903690615101565b600060405180830381855af49150503d8060008114610f7c576040519150601f19603f3d011682016040523d82523d6000602084013e610f81565b606091505b5091509150818190610fa65760405162461bcd60e51b81526004016109ee91906151da565b5050505050505050505050565b600281565b610fc0612407565b600054600154610fdd916001600160a01b03908116911683612433565b50565b600c546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000081565b600061101d612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff61254516565b6001600160a01b03851660009081526010602052604090208190559150505b92915050565b611073611f9d565b6001600160a01b0316336001600160a01b0316146110a35760405162461bcd60e51b81526004016109ee906153c5565b610fdd81612587565b60006110b6612407565b6110bf82612612565b6001600160801b031690505b919050565b6016602052600090815260409020805460019091015482565b60006110658261160b565b60006110fe612407565b611065826126ac565b6001600160a01b0381166000908152601660205260408120546014548290611135908363ffffffff61254516565b905080158061116e575060016001600160a01b03851660009081526010602052604090206003015460ff16600481111561116b57fe5b14155b1561117e576000925050506110cb565b6001600160a01b038416600090815260106020526040812060020154906111c3670de0b6b3a76400006111b7848663ffffffff61275f16565b9063ffffffff61279916565b9695505050505050565b6809c2007651b250000081565b80516111f85760405162461bcd60e51b81526004016109ee906153f6565b6000546001546006546001600160a01b0392831692918216911661121a614b2b565b611222614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112ec57600080fd5b505afa158015611300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113249190614edc565b60208301528151611334906127db565b158015604084015261135c576113558585846000015185602001518a612876565b9050611374565b6113718585846000015185602001518a612b8b565b90505b60008160200151116113985760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad926113cc92600401615571565b600060405180830381600087803b1580156113e657600080fd5b505af11580156113fa573d6000803e3d6000fd5b5050505061141285858360c001518460e00151612ccb565b61010081015115611489576008546101008201516040516364a197f360e01b81526001600160a01b03888116936364a197f393611456939290911691600401615188565b600060405180830381600087803b15801561147057600080fd5b505af1158015611484573d6000803e3d6000fd5b505050505b611497858260400151612f2f565b60208101516060830152610100810151604082015182516114cf92916114c3919063ffffffff61254516565b9063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611517949092909161560f565b60405180910390a1611533853383606001518460400151613090565b505050505050565b600e5481565b6001600160a01b03811660009081526010602052604081206003015460ff16600481111561106557fe5b60006115756115e0565b905090565b6115838161316d565b6040805160018082528183019092526060916020808301908036833701905050905081816000815181106115b357fe5b60200260200101906001600160a01b031690816001600160a01b0316815250506115dc816111da565b5050565b6000611575600e546131b6565b600b546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152601660205260408120600101546015548290611135908363ffffffff61254516565b6000611065611649611b96565b83613253565b6001600160a01b031660009081526010602052604090206001015490565b60175490565b600080600061168185613271565b9150915060006111c38383876132f7565b6000611065826127db565b60035460408051635733d58f60e01b815290516000926001600160a01b031691635733d58f916004808301926020929190829003018186803b1580156116e257600080fd5b505afa1580156116f6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115759190614edc565b611722612407565b80600481111561172e57fe5b6001600160a01b0383166000908152601060205260409020600301805460ff1916600183600481111561175d57fe5b02179055505050565b600061106582611107565b611779612407565b6000611783613329565b9050670de0b6b3a764000081111561179757fe5b600e8190556040517fc454ee9b76c52f782a256af821b857ca6e125d1e3333bcede402fec2bed9600c906117cc908390615568565b60405180910390a1610fdd61336d565b603c81565b60006110656116496123a4565b6001600160a01b031660009081526010602052604090206002015490565b611814614ba8565b506040805160e081018252600080546001600160a01b0390811683526001548116602084015292820181905260608201819052600d548316608083015260a0820181905260c082015260065490911661186b614b2b565b611873614b5c565b600260009054906101000a90046001600160a01b03166001600160a01b0316630fdb11cf6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156118c357600080fd5b505af11580156118d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fb9190614edc565b826000018181525050826001600160a01b031663bdaf37ea6040518163ffffffff1660e01b815260040160206040518083038186803b15801561193d57600080fd5b505afa158015611951573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119759190614edc565b60208301528151611985906127db565b15801560408401526119ac576119a58483600001518460200151886133c2565b90506119cc565b6119c9846000015185602001518460000151856020015189613869565b90505b60008160200151116119f05760405162461bcd60e51b81526004016109ee906154d7565b608081015160a082015160405163335525ad60e01b81526001600160a01b0386169263335525ad92611a2492600401615571565b600060405180830381600087803b158015611a3e57600080fd5b505af1158015611a52573d6000803e3d6000fd5b50505050611a72846000015185602001518360c001518460e00151612ccb565b61010081015115611ae95783516008546101008301516040516364a197f360e01b81526001600160a01b03938416936364a197f393611ab693911691600401615188565b600060405180830381600087803b158015611ad057600080fd5b505af1158015611ae4573d6000803e3d6000fd5b505050505b611afb84600001518260400151612f2f565b6020810151606083015261010081015160408201518251611b2792916114c3919063ffffffff61254516565b608083018190526060808401516040808501519285015190517f4152c73dd2614c4f9fc35e8c9cf16013cd588c75b49a4c1673ecffdcbcda940394611b6f949092909161560f565b60405180910390a1611b8f84600001513383606001518460400151613090565b5050505050565b6000611575611ba3613329565b613a1f565b60195481565b60106020526000908152604090208054600182015460028301546003909301549192909160ff81169061010090046001600160801b031685565b6004546001600160a01b031681565b6000611c01612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff613b0116565b6001600160a01b038516600090815260106020526040902060010181905591505092915050565b670de0b6b3a764000081565b6002546001600160a01b031681565b60178181548110611c7c57fe5b6000918252602090912001546001600160a01b0316905081565b6801158e460913d0000081565b60035460408051631e5395c960e21b815290516000926001600160a01b03169163794e5724916004808301926020929190829003018186803b1580156116e257600080fd5b60008054604080516272c7d360e71b8152905183926001600160a01b031691633963e980916004808301926020929190829003018186803b158015611d2c57600080fd5b505afa158015611d40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d649190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b0316633963e9806040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b505afa158015611dca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dee9190614edc565b9050611e00828263ffffffff613b0116565b9250505090565b60185481565b600a546001600160a01b031681565b6000546001600160a01b031681565b60125481565b611e39612407565b610fdd81613b26565b611e4a611f9d565b6001600160a01b0316336001600160a01b031614611e7a5760405162461bcd60e51b81526004016109ee906153c5565b611e83816123c2565b600480546001600160a01b0319166001600160a01b0383161790556040517f6493041f605f233753d9b16dd158c9f297b8eaca22b2d0dc402a454f5683a5b190610f1190839061512e565b6000805460408051630a7b61df60e11b8152905183926001600160a01b0316916314f6c3be916004808301926020929190829003018186803b158015611f1357600080fd5b505afa158015611f27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4b9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015611db657600080fd5b600080604051611fac90615111565b6040519081900390205492915050565b60135481565b6004546040516000916060916001600160a01b0390911690611fe79084903690615101565b600060405180830381855af49150503d8060008114612022576040519150601f19603f3d011682016040523d82523d6000602084013e612027565b606091505b509150915081819061204c5760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050505050565b6000612065612407565b6001600160a01b038316600090815260106020526040812054611046908463ffffffff613b0116565b60145481565b6003546001600160a01b031681565b6040518060400160405280600c81526020016b2a3937bb32a6b0b730b3b2b960a11b81525081565b6006546001600160a01b031681565b600d546001600160a01b031681565b60008060006120f784613271565b9150915060006121078383613b83565b95945050505050565b6005546001600160a01b031681565b600061106582613bb8565b6001600160a01b03811660009081526010602052604081208054600190910154909180612156856110e9565b915061216185611766565b9050612173848363ffffffff613b0116565b9350612185838263ffffffff613b0116565b92509193509193565b6004546040516000916060916001600160a01b03909116906121b39084903690615101565b600060405180830381855af49150503d80600081146121ee576040519150601f19603f3d011682016040523d82523d6000602084013e6121f3565b606091505b50915091508181906122185760405162461bcd60e51b81526004016109ee91906151da565b50505050505050505050565b60155481565b60115481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000611575612261613329565b6131b6565b670ddd4b8c6c7d70d881565b61227a612407565b610fdd816002613be4565b60006122918383611673565b9392505050565b600f5481565b60006122a8612407565b6001600160a01b038316600090815260106020526040812060010154611c2d908463ffffffff61254516565b60006110656122e1612254565b83613cf9565b6001600160a01b031660009081526010602052604090205490565b6009546001600160a01b031681565b60006017828154811061232057fe5b6000918252602090912001546001600160a01b031692915050565b600060016001600160a01b03831660009081526010602052604090206003015460ff16600481111561236957fe5b14612376575060006110cb565b506014546001600160a01b03821660009081526016602052604090205410919050565b60006110658261233b565b6000611575600e54613a1f565b6123b9612407565b610fdd81613d39565b6001600160a01b0381166123e85760405162461bcd60e51b81526004016109ee906152a6565b803b806115dc5760405162461bcd60e51b81526004016109ee9061544c565b6005546001600160a01b031633146124315760405162461bcd60e51b81526004016109ee90615368565b565b61243c8161233b565b156125405761244a8161316d565b600061245582611107565b905060006124628361160b565b6001600160a01b038416600090815260106020526040902060010154909150612491908363ffffffff613b0116565b6001600160a01b03841660009081526010602052604090206001810191909155546124c2908263ffffffff613b0116565b6001600160a01b0384166000908152601060205260409020556124e483613b26565b6124f085858385613d89565b6001600160a01b0383166000818152601060205260408082208054600182015460029092015492516000805160206156b28339815191529461253594929392916155e3565b60405180910390a250505b505050565b600061229183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613e71565b6001600160a01b0381166125ad5760405162461bcd60e51b81526004016109ee90615264565b806001600160a01b03166125bf611f9d565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600060405161260290615111565b6040519081900390209190915550565b601780546001808201835560008381527fc624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c1590920180546001600160a01b0319166001600160a01b0386161790559154909161266d9190612545565b6001600160a01b039290921660009081526010602052604090206003018054610100600160881b0319166101006001600160801b038516021790555090565b6001600160a01b03811660009081526010602052604081206001015481906126d390613e9d565b6001600160a01b03841660009081526010602052604090206002018054908290556011549192509061271d908390612711908463ffffffff61254516565b9063ffffffff613b0116565b60118190556040517f6bac5e0eb3c44eb03a60ab11ec3a2c051771616aecadbcfff2630aabae5203829161275091615568565b60405180910390a15092915050565b60008261276e57506000611065565b8282028284828161277b57fe5b04146122915760405162461bcd60e51b81526004016109ee90615327565b600061229183836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ed9565b6000806127e783613bb8565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561283757600080fd5b505afa15801561284b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286f9190614edc565b1192915050565b61287e614b5c565b612886614be4565b61288e614b5c565b848252600060808301526128a0611ce8565b60a08301526128ad611ece565b60c0830152600060208301525b835182602001511015612b8057838260200151815181106128d757fe5b6020908102919091018101516001600160a01b03166060840181905260009081526010909152604090206003015460019060ff16600481111561291657fe5b1461292057612b70565b61292e826060015187611673565b60408301526080820151612a9557600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561298a57600080fd5b505afa15801561299e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129c29190614edc565b8260400151101580156129d457508151155b156129de57612b70565b60006129f38360c001518460a00151896132f7565b9050612a108989856060015186604001518760000151868d613f10565b60808101518451919350612a2a919063ffffffff61254516565b8352608082015160a0840151612a459163ffffffff61254516565b60a08085019190915282015160c0840151612a659163ffffffff61254516565b60c0840152612a7484836142e6565b9350612a898360c001518460a00151896143fd565b15608084015250612b70565b81608001518015612b2e5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b158015612aef57600080fd5b505afa158015612b03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b279190614edc565b8260400151105b15612b7057612b4788888460600151856000015161449c565b60808101518351919250612b61919063ffffffff61254516565b8252612b6d83826142e6565b92505b60208201805160010190526128ba565b505095945050505050565b612b93614b5c565b612b9b614be4565b612ba3614b5c565b848252600060208301525b835182602001511015612b805783826020015181518110612bcb57fe5b60209081029190910101516001600160a01b031660608301819052612bf09087611673565b6040808401919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b158015612c3b57600080fd5b505afa158015612c4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c739190614edc565b82604001511015612cbb57612c9288888460600151856000015161449c565b60808101518351919250612cac919063ffffffff61254516565b8252612cb883826142e6565b92505b6020820180516001019052612bae565b81612cd557612f29565b601854600090612cf79061271184670de0b6b3a764000063ffffffff61275f16565b90506000612d1c601954612711670de0b6b3a76400008761275f90919063ffffffff16565b90506000612d356011548461279990919063ffffffff16565b90506000612d4e6011548461279990919063ffffffff16565b9050612d75612d686011548461275f90919063ffffffff16565b859063ffffffff61254516565b601855601154612d9d90612d9090839063ffffffff61275f16565b849063ffffffff61254516565b601955601454612db3908363ffffffff613b0116565b601455601554612dc9908263ffffffff613b0116565b60158190556014546040517f9f8bc8ab0daf5bceef75ecfd2085d1fcc6548c657ea970d9a23a60610d0737e392612e009291615571565b60405180910390a160405163121cbc4d60e11b81526001600160a01b03891690632439789a90612e34908990600401615568565b600060405180830381600087803b158015612e4e57600080fd5b505af1158015612e62573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038a16925063f2e91d719150612e92908990600401615568565b600060405180830381600087803b158015612eac57600080fd5b505af1158015612ec0573d6000803e3d6000fd5b50506040516364a197f360e01b81526001600160a01b038b1692506364a197f39150612ef2908a908990600401615188565b600060405180830381600087803b158015612f0c57600080fd5b505af1158015612f20573d6000803e3d6000fd5b50505050505050505b50505050565b6011546012819055506000826001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f7357600080fd5b505afa158015612f87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fab9190614edc565b90506000600160009054906101000a90046001600160a01b03166001600160a01b03166314f6c3be6040518163ffffffff1660e01b815260040160206040518083038186803b158015612ffd57600080fd5b505afa158015613011573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130359190614edc565b905061304b81612711848663ffffffff61254516565b60138190556012546040517f51bf4c63ec3cba9d03d43238abbdd979dd91bd16d9895c74ceea9118c7baaf60926130829291615571565b60405180910390a150505050565b811561310157600954600754604051631062c15f60e11b81526001600160a01b03928316926320c582be926130ce9291169087908790600401615142565b600060405180830381600087803b1580156130e857600080fd5b505af11580156130fc573d6000803e3d6000fd5b505050505b8015612f29576040516364a197f360e01b81526001600160a01b038516906364a197f3906131359086908590600401615188565b600060405180830381600087803b15801561314f57600080fd5b505af1158015613163573d6000803e3d6000fd5b5050505050505050565b60016001600160a01b03821660009081526010602052604090206003015460ff16600481111561319957fe5b14610fdd5760405162461bcd60e51b81526004016109ee90615519565b600061106561324583600360009054906101000a90046001600160a01b03166001600160a01b03166328d28b5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b505afa158015613221573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127119190614edc565b670de0b6b3a76400006145ce565b6000612291670de0b6b3a76400006111b7858563ffffffff61275f16565b600080600061327f84611107565b9050600061328c8561160b565b6001600160a01b038616600090815260106020526040812060010154919250906132bc908463ffffffff613b0116565b6001600160a01b038716600090815260106020526040812054919250906132e9908463ffffffff613b0116565b919550909350505050915091565b6000821561331e576000613315846111b7878663ffffffff61275f16565b91506122919050565b506000199392505050565b6000806133346145e4565b9050600061334a670ddd4b8c6c7d70d883614600565b9050611e00670de0b6b3a76400006111b783600e5461275f90919063ffffffff16565b6000613384600f544261254590919063ffffffff16565b9050603c8110610fdd5742600f8190556040517f860f8d2f0c74dd487e89e2883e3b25b8159ce1e1b3433a291cba7b82c508f3bc91610f1191615568565b6133ca614b5c565b6133d2614be4565b6133da614b5c565b848252600060808301526133ec611ce8565b60a08301526133f9611ece565b8260c001818152505086608001516001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b15801561343f57600080fd5b505afa158015613453573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134779190614cbb565b82606001906001600160a01b031690816001600160a01b031681525050600087608001516001600160a01b0316631e2231436040518163ffffffff1660e01b815260040160206040518083038186803b1580156134d357600080fd5b505afa1580156134e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350b9190614cbb565b6000602085015290505b84836020015110801561353e5750806001600160a01b031683606001516001600160a01b031614155b1561385e5760808801516060840151604051632dc9c0eb60e21b81526000926001600160a01b03169163b72703ac9161357a919060040161512e565b60206040518083038186803b15801561359257600080fd5b505afa1580156135a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ca9190614cbb565b90506135da846060015189611673565b6040850152608084015161375357600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561363657600080fd5b505afa15801561364a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061366e9190614edc565b84604001511015801561368057508351155b1561368b575061385e565b60006136a08560c001518660a001518b6132f7565b8a5160208c01516060880151604089015189519495506136c194868f613f10565b608081015186519195506136db919063ffffffff61254516565b8552608084015160a08601516136f69163ffffffff61254516565b8560a00181815250506137238461010001516114c38660a001518860c0015161254590919063ffffffff16565b60c086015261373286856142e6565b95506137478560c001518660a001518b6143fd565b15608086015250613840565b836080015180156137ec5750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156137ad57600080fd5b505afa1580156137c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e59190614edc565b8460400151105b1561383a5761380d89600001518a602001518660600151876000015161449c565b60808101518551919450613827919063ffffffff61254516565b845261383385846142e6565b9450613840565b5061385e565b6001600160a01b031660608401526020830180516001019052613515565b505050949350505050565b613871614b5c565b613879614be4565b613881614b5c565b600d54858352600060208401526001600160a01b03165b8483602001511015613a1357806001600160a01b0316634d6228316040518163ffffffff1660e01b815260040160206040518083038186803b1580156138dd57600080fd5b505afa1580156138f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139159190614cbb565b6001600160a01b03166060840181905261392f9088611673565b6040808501919091526003548151631e5395c960e21b815291516001600160a01b039091169163794e5724916004808301926020929190829003018186803b15801561397a57600080fd5b505afa15801561398e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b29190614edc565b836040015110156139fe576139d189898560600151866000015161449c565b608081015184519193506139eb919063ffffffff61254516565b83526139f784836142e6565b9350613a03565b613a13565b6020830180516001019052613898565b50505095945050505050565b6000611065613a7683600360009054906101000a90046001600160a01b03166001600160a01b031663f92d34336040518163ffffffff1660e01b815260040160206040518083038186803b15801561320d57600080fd5b600360009054906101000a90046001600160a01b03166001600160a01b031663240926696040518163ffffffff1660e01b815260040160206040518083038186803b158015613ac457600080fd5b505afa158015613ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613afc9190614edc565b6145ce565b6000828201838110156122915760405162461bcd60e51b81526004016109ee9061522d565b601480546001600160a01b038316600090815260166020526040908190209182556015546001909201829055915491517fc437f324d85e369394148dd9d62f98f534b382e01ed3dd2eb98138fb6d3ab49a92610f11929091615571565b60008115613baf57613ba8826111b78568056bc75e2d6310000063ffffffff61275f16565b9050611065565b50600019611065565b600080613bc3611ece565b90506000613bcf611ce8565b9050613bdc8282866132f7565b949350505050565b6000816004811115613bf257fe5b14158015613c0c57506001816004811115613c0957fe5b14155b613c1257fe5b601754613c1e816146ab565b6001600160a01b0383166000908152601060205260409020600301805483919060ff19166001836004811115613c5057fe5b02179055506001600160a01b0383166000908152601060209081526040808320600180820185905590849055601690925282208281550155613c928382614751565b600d54604051631484968760e11b81526001600160a01b03909116906329092d0e90613cc290869060040161512e565b600060405180830381600087803b158015613cdc57600080fd5b505af1158015613cf0573d6000803e3d6000fd5b50505050505050565b600080613d18670de0b6b3a76400006111b7868663ffffffff61275f16565b90508281106122915760405162461bcd60e51b81526004016109ee90615481565b6001600160a01b038116600090815260106020526040902060020154601154613d68908263ffffffff61254516565b601155506001600160a01b0316600090815260106020526040812060020155565b60405163121cbc4d60e11b81526001600160a01b03841690632439789a90613db5908590600401615568565b600060405180830381600087803b158015613dcf57600080fd5b505af1158015613de3573d6000803e3d6000fd5b505060405163f2e91d7160e01b81526001600160a01b038716925063f2e91d719150613e13908590600401615568565b600060405180830381600087803b158015613e2d57600080fd5b505af1158015613e41573d6000803e3d6000fd5b505060405163be41205f60e01b81526001600160a01b038616925063be41205f9150613135908490600401615568565b60008184841115613e955760405162461bcd60e51b81526004016109ee91906151da565b505050900390565b60008060135460001415613eb2575081611065565b600060125411613ebe57fe5b6122916013546111b76012548661275f90919063ffffffff16565b60008183613efa5760405162461bcd60e51b81526004016109ee91906151da565b506000838581613f0657fe5b0495945050505050565b613f18614b5c565b613f20614c2c565b601754600110613f3057506142db565b613f398761212a565b60408501526020848101919091528401819052908352613f58906148f2565b604083018190526801158e460913d0000060608401526020830151613f829163ffffffff61254516565b8152670de0b6b3a7640000861161404d57613fa7898983602001518460400151613d89565b613fb087613d39565b60006080830181905260a0830152815160c0830152805160e0830152613fd7876003613be4565b815160208301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b60405180910390a2866001600160a01b03166000805160206156b28339815191526000806000600260405161404094939291906151ac565b60405180910390a26142d9565b670de0b6b3a7640000861180156140e85750600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b1580156140ad57600080fd5b505afa1580156140c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140e59190614edc565b86105b1561413857614101898983602001518460400151613d89565b61410a87613d39565b8151815161411991908761497e565b60e086015260c085015260a08401526080830152613fd7876003613be4565b600360009054906101000a90046001600160a01b03166001600160a01b031663794e57246040518163ffffffff1660e01b815260040160206040518083038186803b15801561418657600080fd5b505afa15801561419a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141be9190614edc565b86101580156141cc57508386105b80156141d9575081518510155b156142c8576141f2898983602001518460400151613d89565b846141f957fe5b61420287613d39565b61421582600001518360200151856149ea565b9150614222876003613be4565b6101008201511561429757600854610100830151604051633f10abab60e01b81526001600160a01b0390921691633f10abab91614264918b9190600401615188565b600060405180830381600087803b15801561427e57600080fd5b505af1158015614292573d6000803e3d6000fd5b505050505b815160a08301516040516001600160a01b038a1692600080516020615692833981519152926140089260029061557f565b6142d0614b5c565b91506142db9050565b505b979650505050505050565b6142ee614b5c565b604080830151908401516143079163ffffffff613b0116565b6040820152606080830151908401516143259163ffffffff613b0116565b6060820152815160208401516143409163ffffffff613b0116565b602080830191909152820151835161435d9163ffffffff613b0116565b8152608080830151908401516143789163ffffffff613b0116565b608082015260a080830151908401516143969163ffffffff613b0116565b60a082015260c080830151908401516143b49163ffffffff613b0116565b60c082015260e080830151908401516143d29163ffffffff613b0116565b60e082015261010080830151908401516143f19163ffffffff613b0116565b61010082015292915050565b60008061440b8585856132f7565b9050600360009054906101000a90046001600160a01b03166001600160a01b0316635733d58f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561445b57600080fd5b505afa15801561446f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144939190614edc565b11949350505050565b6144a4614b5c565b6144ac614c2c565b6144b58461212a565b604085019081526020858101928352860192909252918452905190516144df918891889190613d89565b6144e884613d39565b6144f582602001516148f2565b604083018190526801158e460913d0000060608401526020830151600091614523919063ffffffff61254516565b90506145348360000151828661497e565b60e087015260c086015260a08501526080840152614553856003613be4565b825160208401516040516001600160a01b03881692600080516020615692833981519152926145849260019061557f565b60405180910390a2846001600160a01b03166000805160206156b2833981519152600080600060016040516145bc94939291906151ac565b60405180910390a25050949350505050565b60008183106145dd5781612291565b5090919050565b6000611575603c6111b7600f544261254590919063ffffffff16565b6000631f54050082111561461657631f54050091505b8161462a5750670de0b6b3a7640000611065565b670de0b6b3a764000083835b60018111156146a1576002810661466b576146518283614af8565b915061466481600263ffffffff61279916565b905061469c565b6146758284614af8565b92506146818283614af8565b915061469960026111b783600163ffffffff61254516565b90505b614636565b6111c38284614af8565b6001811180156147355750600d546040805163de8fa43160e01b815290516001926001600160a01b03169163de8fa431916004808301926020929190829003018186803b1580156146fb57600080fd5b505afa15801561470f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147339190614edc565b115b610fdd5760405162461bcd60e51b81526004016109ee906152dd565b6001600160a01b03821660009081526010602052604081206003015460ff169081600481111561477d57fe5b141580156147975750600181600481111561479457fe5b14155b61479d57fe5b6001600160a01b03831660009081526010602052604081206003015461010090046001600160801b03169083906147d5826001612545565b905080836001600160801b031611156147ea57fe5b6000601782815481106147f957fe5b600091825260209091200154601780546001600160a01b03909216925082916001600160801b03871690811061482b57fe5b600091825260208083209190910180546001600160a01b0319166001600160a01b03948516179055918316815260109091526040908190206003018054610100600160881b0319166101006001600160801b03881602179055517f02b04ae5f7be9ca7c103293a2aa15f3c339d15d6eda53b721fef7b0e609c831a906148b49083908790615166565b60405180910390a160178054806148c757fe5b600082815260209020810160001990810180546001600160a01b031916905501905550505050505050565b600354604080516324386ecd60e11b815290516000926001600160a01b031691634870dd9a916004808301926020929190829003018186803b15801561493757600080fd5b505afa15801561494b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061496f9190614edc565b828161497757fe5b0492915050565b600080808084156149d45761499387866145ce565b93506149a9876111b7888763ffffffff61275f16565b92506149bb878563ffffffff61254516565b91506149cd868463ffffffff61254516565b90506149e1565b5060009250829150859050845b93509350935093565b6149f2614b5c565b838152602080820184905260035460408051631e5395c960e21b81529051600093614a8e9387936111b7936001600160a01b039092169263794e572492600480840193829003018186803b158015614a4957600080fd5b505afa158015614a5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a819190614edc565b889063ffffffff61275f16565b9050614a99816148f2565b604083018190526801158e460913d00000606084015260808301869052614ac790829063ffffffff61254516565b60a0830152614adc848263ffffffff61254516565b61010083015250600060c0820181905260e08201529392505050565b600080614b0b848463ffffffff61275f16565b9050613bdc670de0b6b3a76400006111b7836706f05b59d3b20000613b01565b6040518060a00160405280600081526020016000815260200160001515815260200160008152602001600081525090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040518060e0016040528060008152602001600081526020016000815260200160006001600160a01b0316815260200160001515815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b80356110658161567c565b60008083601f840112614c69578081fd5b50813567ffffffffffffffff811115614c80578182fd5b602083019150836020828501011115614c9857600080fd5b9250929050565b600060208284031215614cb0578081fd5b81356122918161567c565b600060208284031215614ccc578081fd5b81516122918161567c565b60008060408385031215614ce9578081fd5b8235614cf48161567c565b946020939093013593505050565b60006020808385031215614d14578182fd5b823567ffffffffffffffff811115614d2a578283fd5b80840185601f820112614d3b578384fd5b80359150614d50614d4b83615651565b61562a565b8281528381019082850185850284018601891015614d6c578687fd5b8693505b848410156142d957614d828982614c4d565b835260019390930192918501918501614d70565b60006101c0808385031215614da9578182fd5b614db28161562a565b614dbc8585614c4d565b8152614dcb8560208601614c4d565b6020820152614ddd8560408601614c4d565b6040820152614def8560608601614c4d565b6060820152614e018560808601614c4d565b6080820152614e138560a08601614c4d565b60a0820152614e258560c08601614c4d565b60c0820152614e378560e08601614c4d565b60e08201526101009150614e4d85838601614c4d565b828201526101209150614e6285838601614c4d565b828201526101409150614e7785838601614c4d565b828201526101609150614e8c85838601614c4d565b828201526101809150614ea185838601614c4d565b828201526101a09150614eb685838601614c4d565b918101919091529392505050565b600060208284031215614ed5578081fd5b5035919050565b600060208284031215614eed578081fd5b5051919050565b600080600080600080600060e0888a031215614f0e578283fd5b873596506020880135614f208161567c565b95506040880135614f308161567c565b94506060880135614f408161567c565b9699959850939660808101359560a0820135955060c0909101359350915050565b600080600080600080600080888a03610160811215614f7e578182fd5b8935985060208a0135614f908161567c565b975060408a0135614fa08161567c565b965060608a0135614fb08161567c565b955060808a810135955060a08b0135945060c08b0135935060df1982011215614fd7578182fd5b5060e0890190509295985092959890939650565b6000806000806000806000806000808a8c0361018081121561500b578485fd5b8b359a5060208c013561501d8161567c565b995060408c013561502d8161567c565b985060608c013561503d8161567c565b975060808c810135975060a08d0135965060c08d0135955060df19820190811215615066578384fd5b615070606061562a565b9150604081121561507f578384fd5b5061508a604061562a565b60e08d01356150988161567c565b81526101008d01356020808301919091529082526101208d0135908201526101408c0135604082015292506101608b013567ffffffffffffffff8111156150dd578283fd5b6150e98d828e01614c58565b8194508093505050509295989b9194979a5092959850565b6000828483379101908152919050565b7035b2bc9737bbb730b136329737bbb732b960791b815260110190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b848152602081018490526040810183905260808101600483106151cb57fe5b82606083015295945050505050565b6000602080835283518082850152825b81811015615206578581018301518582016040015282016151ea565b818111156152175783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526022908201527f4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265604082015261737360f01b606082015260800190565b6020808252601e908201527f4163636f756e742063616e6e6f74206265207a65726f20616464726573730000604082015260600190565b6020808252602a908201527f54726f76654d616e616765723a204f6e6c79206f6e652074726f766520696e206040820152697468652073797374656d60b01b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252603b908201527f54726f76654d616e616765723a2043616c6c6572206973206e6f74207468652060408201527f426f72726f7765724f7065726174696f6e7320636f6e74726163740000000000606082015260800190565b60208082526017908201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2043616c6c646174612061646472657373206160408201527572726179206d757374206e6f7420626520656d70747960501b606082015260800190565b6020808252818101527f4163636f756e7420636f64652073697a652063616e6e6f74206265207a65726f604082015260600190565b60208082526036908201527f54726f76654d616e616765723a2046656520776f756c642065617420757020616040820152751b1b081c995d1d5c9b99590818dbdb1b185d195c985b60521b606082015260800190565b60208082526022908201527f54726f76654d616e616765723a206e6f7468696e6720746f206c697175696461604082015261746560f01b606082015260800190565b6020808252602f908201527f54726f76654d616e616765723a2054726f766520646f6573206e6f742065786960408201526e1cdd081bdc881a5cc818db1bdcd959608a1b606082015260800190565b90815260200190565b918252602082015260400190565b838152602081018390526060810161559683615671565b6040830152949350505050565b858152602081018590526040810184905260a08101600584106155c257fe5b60608201939093526001600160801b03919091166080909101529392505050565b84815260208101849052604081018390526080810161560183615671565b606083015295945050505050565b93845260208401929092526040830152606082015260800190565b60405181810167ffffffffffffffff8111828210171561564957600080fd5b604052919050565b600067ffffffffffffffff821115615667578081fd5b5060209081020190565b80600481106110cb57fe5b6001600160a01b0381168114610fdd57600080fdfeea67486ed7ebe3eea8ab3390efd4a3c8aae48be5bea27df104a8af786c408434c3770d654ed33aeea6bf11ac8ef05d02a6a04ed4686dd2f624d853bbec43cc8ba2646970667358221220a4c2a9a9ec603c1ba14143d02dd4e890d8f91d610315ce69bf8078c0892e8c2464736f6c634300060b0033", + "devdoc": { + "kind": "dev", + "methods": { + "applyPendingRewards(address)": { + "params": { + "_borrower": "borrower address" + } + }, + "closeTrove(address)": { + "params": { + "_borrower": "borrower address" + } + }, + "constructor": { + "params": { + "_bootstrapPeriod": "During bootsrap period redemptions are not allowed" + } + }, + "decreaseTroveColl(address,uint256)": { + "params": { + "_borrower": "borrower address", + "_collDecrease": "amount of collateral to decrease" + }, + "returns": { + "_0": "new trove collateral" + } + }, + "decreaseTroveDebt(address,uint256)": { + "params": { + "_borrower": "borrower address", + "_debtDecrease": "amount of debt to decrease" + }, + "returns": { + "_0": "new trove debt" + } + }, + "getBorrowingFeeWithDecay(uint256)": { + "params": { + "_ZUSDDebt": "ZUSD debt amount to calculate fee" + }, + "returns": { + "_0": "borrowing fee using borrowing rate with decay" + } + }, + "getBorrowingRate()": { + "returns": { + "_0": "borrowing rate" + } + }, + "getBorrowingRateWithDecay()": { + "returns": { + "_0": "borrowing rate calculated using decayed as base rate" + } + }, + "getCurrentICR(address,uint256)": { + "params": { + "_borrower": "borrower address", + "_price": "ETH price" + }, + "returns": { + "_0": "the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account." + } + }, + "getNominalICR(address)": { + "returns": { + "_0": "the nominal collateral ratio (ICR) of a given Trove, without the price. Takes a trove's pending coll and debt rewards from redistributions into account." + } + }, + "getOwner()": { + "returns": { + "_owner": "Address of the owner. " + } + }, + "getPendingETHReward(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "the borrower's pending accumulated ETH reward, earned by their stake" + } + }, + "getPendingZUSDDebtReward(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "the borrower's pending accumulated ZUSD reward, earned by their stake" + } + }, + "getRedemptionFeeWithDecay(uint256)": { + "params": { + "_ETHDrawn": "ETH drawn" + } + }, + "getRedemptionRate()": { + "returns": { + "_0": "calculated redemption rate using baseRate" + } + }, + "getRedemptionRateWithDecay()": { + "returns": { + "_0": "calculated redemption rate using calculated decayed as base rate" + } + }, + "getTCR(uint256)": { + "params": { + "_price": "ETH price" + }, + "returns": { + "_0": "the total collateralization ratio (TCR) of the system. The TCR is based on the the entire system debt and collateral (including pending rewards)." + } + }, + "getTroveColl(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "Trove collateral from given trove" + } + }, + "getTroveDebt(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "Trove debt from given trove" + } + }, + "getTroveFromTroveOwnersArray(uint256)": { + "params": { + "_index": "Trove owner index" + }, + "returns": { + "_0": "Trove from TroveOwners array in given index" + } + }, + "getTroveOwnersCount()": { + "returns": { + "_0": "Trove owners count" + } + }, + "getTroveStake(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "Trove stake from given trove" + } + }, + "getTroveStatus(address)": { + "params": { + "_borrower": "borrower address" + }, + "returns": { + "_0": "Trove status from given trove" + } + }, + "increaseTroveColl(address,uint256)": { + "params": { + "_borrower": "borrower address", + "_collIncrease": "amount of collateral to increase" + }, + "returns": { + "_0": "new trove collateral" + } + }, + "increaseTroveDebt(address,uint256)": { + "params": { + "_borrower": "borrower address", + "_debtIncrease": "amount of debt to increase" + }, + "returns": { + "_0": "new trove debt" + } + }, + "redeemCollateral(uint256,address,address,address,uint256,uint256,uint256)": { + "details": "this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed" + }, + "redeemCollateralViaDLLR(uint256,address,address,address,uint256,uint256,uint256,(uint256,uint8,bytes32,bytes32))": { + "details": "this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction" + }, + "redeemCollateralViaDllrWithPermit2(uint256,address,address,address,uint256,uint256,uint256,((address,uint256),uint256,uint256),bytes)": { + "details": "this function forwards the call to the troveManagerRedeemOps in a delegate call fashion so the parameters are not needed DLLR _owner or _spender can use Sovryn Mynt to convert DLLR to ZUSD, then use the Zero redemption mechanism to redeem ZUSD for RBTC, all in a single transaction" + }, + "removeStake(address)": { + "params": { + "_borrower": "borrower address" + } + }, + "setOwner(address)": { + "params": { + "_owner": "Address of the owner. " + } + }, + "updateStakeAndTotalStakes(address)": { + "params": { + "_borrower": "borrower address" + } + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "BETA()": { + "notice": "BETA: 18 digit decimal. Parameter by which to divide the redeemed fraction, in order to calc the new base rate from a redemption. Corresponds to (1 / ALPHA) in the white paper." + }, + "BOOTSTRAP_PERIOD()": { + "notice": "During bootsrap period redemptions are not allowed" + }, + "MIN_NET_DEBT()": { + "notice": "Minimum amount of net ZUSD debt a trove must have" + }, + "ZUSD_GAS_COMPENSATION()": { + "notice": "Amount of ZUSD to be locked in gas pool on opening troves" + }, + "_getCurrentICR(address,uint256)": { + "notice": "Return the current collateral ratio (ICR) of a given Trove. Takes a trove's pending coll and debt rewards from redistributions into account." + }, + "_getPendingETHReward(address)": { + "notice": "Get the borrower's pending accumulated ETH reward, earned by their stake" + }, + "_getPendingZUSDDebtReward(address)": { + "notice": "Get the borrower's pending accumulated ZUSD reward, earned by their stake" + }, + "addTroveOwnerToArray(address)": { + "notice": "Push the owner's address to the Trove owners list, and record the corresponding array index on the Trove struct" + }, + "applyPendingRewards(address)": { + "notice": "Add the borrowers's coll and debt rewards earned from redistributions, to their Trove" + }, + "batchLiquidateTroves(address[])": { + "notice": "Attempt to liquidate a custom list of troves provided by the caller." + }, + "checkRecoveryMode(uint256)": { + "notice": "reveals whether or not the system is in Recovery Mode (i.e. whether the Total Collateralization Ratio (TCR) is below the Critical Collateralization Ratio (CCR))." + }, + "closeTrove(address)": { + "notice": "Close given trove. Called by BorrowerOperations." + }, + "decayBaseRateFromBorrowing()": { + "notice": "Updates the baseRate state variable based on time elapsed since the last redemption or ZUSD borrowing operation." + }, + "getCurrentICR(address,uint256)": { + "notice": "computes the user’s individual collateralization ratio (ICR) based on their total collateral and total ZUSD debt. Returns 2^256 -1 if they have 0 debt." + }, + "getEntireDebtAndColl(address)": { + "notice": "Return the Troves entire debt and coll, including pending rewards from redistributions." + }, + "getOwner()": { + "notice": "Return address of the owner." + }, + "getRedemptionFeeWithDecay(uint256)": { + "notice": "The redemption fee is taken as a cut of the total ETH drawn from the system in a redemption. It is based on the current redemption rate." + }, + "liquidate(address)": { + "notice": "Single liquidation function. Closes the trove if its ICR is lower than the minimum collateral ratio." + }, + "liquidateTroves(uint256)": { + "notice": "Liquidate a sequence of troves. Closes a maximum number of n under-collateralized Troves, starting from the one with the lowest collateral ratio in the system, and moving upwards" + }, + "permit2()": { + "notice": "CONSTANT / IMMUTABLE VARIABLE ONLY " + }, + "removeStake(address)": { + "notice": "Remove borrower's stake from the totalStakes sum, and set their stake to 0" + }, + "setOwner(address)": { + "notice": "Set address of the owner (only owner can call this function)" + }, + "updateStakeAndTotalStakes(address)": { + "notice": "Update borrower's stake based on their latest collateral value" + }, + "updateTroveRewardSnapshots(address)": { + "notice": "Update borrower's snapshots of L_ETH and L_ZUSDDebt to reflect the current values" + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 5495, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "activePool", + "offset": 0, + "slot": "0", + "type": "t_contract(IActivePool)19557" + }, + { + "astId": 5497, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "defaultPool", + "offset": 0, + "slot": "1", + "type": "t_contract(IDefaultPool)20229" + }, + { + "astId": 5500, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "priceFeed", + "offset": 0, + "slot": "2", + "type": "t_contract(IPriceFeed)20458" + }, + { + "astId": 5503, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "liquityBaseParams", + "offset": 0, + "slot": "3", + "type": "t_contract(ILiquityBaseParams)20379" + }, + { + "astId": 35227, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "troveManagerRedeemOps", + "offset": 0, + "slot": "4", + "type": "t_address" + }, + { + "astId": 35229, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "borrowerOperationsAddress", + "offset": 0, + "slot": "5", + "type": "t_address" + }, + { + "astId": 35231, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "_stabilityPool", + "offset": 0, + "slot": "6", + "type": "t_contract(IStabilityPool)21101" + }, + { + "astId": 35233, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "gasPoolAddress", + "offset": 0, + "slot": "7", + "type": "t_address" + }, + { + "astId": 35235, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "collSurplusPool", + "offset": 0, + "slot": "8", + "type": "t_contract(ICollSurplusPool)20130" + }, + { + "astId": 35237, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "_zusdToken", + "offset": 0, + "slot": "9", + "type": "t_contract(IZUSDToken)21842" + }, + { + "astId": 35239, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "_zeroToken", + "offset": 0, + "slot": "10", + "type": "t_contract(IZEROToken)21783" + }, + { + "astId": 35241, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "_zeroStaking", + "offset": 0, + "slot": "11", + "type": "t_contract(IZEROStaking)21760" + }, + { + "astId": 35243, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "feeDistributor", + "offset": 0, + "slot": "12", + "type": "t_contract(IFeeDistributor)20298" + }, + { + "astId": 35245, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "sortedTroves", + "offset": 0, + "slot": "13", + "type": "t_contract(ISortedTroves)20817" + }, + { + "astId": 35247, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "baseRate", + "offset": 0, + "slot": "14", + "type": "t_uint256" + }, + { + "astId": 35249, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "lastFeeOperationTime", + "offset": 0, + "slot": "15", + "type": "t_uint256" + }, + { + "astId": 35270, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "Troves", + "offset": 0, + "slot": "16", + "type": "t_mapping(t_address,t_struct(Trove)35266_storage)" + }, + { + "astId": 35272, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "totalStakes", + "offset": 0, + "slot": "17", + "type": "t_uint256" + }, + { + "astId": 35274, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "totalStakesSnapshot", + "offset": 0, + "slot": "18", + "type": "t_uint256" + }, + { + "astId": 35276, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "totalCollateralSnapshot", + "offset": 0, + "slot": "19", + "type": "t_uint256" + }, + { + "astId": 35278, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "L_ETH", + "offset": 0, + "slot": "20", + "type": "t_uint256" + }, + { + "astId": 35280, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "L_ZUSDDebt", + "offset": 0, + "slot": "21", + "type": "t_uint256" + }, + { + "astId": 35284, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "rewardSnapshots", + "offset": 0, + "slot": "22", + "type": "t_mapping(t_address,t_struct(RewardSnapshot)35289_storage)" + }, + { + "astId": 35292, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "TroveOwners", + "offset": 0, + "slot": "23", + "type": "t_array(t_address)dyn_storage" + }, + { + "astId": 35294, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "lastETHError_Redistribution", + "offset": 0, + "slot": "24", + "type": "t_uint256" + }, + { + "astId": 35296, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "lastZUSDDebtError_Redistribution", + "offset": 0, + "slot": "25", + "type": "t_uint256" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "base": "t_address", + "encoding": "dynamic_array", + "label": "address[]", + "numberOfBytes": "32" + }, + "t_contract(IActivePool)19557": { + "encoding": "inplace", + "label": "contract IActivePool", + "numberOfBytes": "20" + }, + "t_contract(ICollSurplusPool)20130": { + "encoding": "inplace", + "label": "contract ICollSurplusPool", + "numberOfBytes": "20" + }, + "t_contract(IDefaultPool)20229": { + "encoding": "inplace", + "label": "contract IDefaultPool", + "numberOfBytes": "20" + }, + "t_contract(IFeeDistributor)20298": { + "encoding": "inplace", + "label": "contract IFeeDistributor", + "numberOfBytes": "20" + }, + "t_contract(ILiquityBaseParams)20379": { + "encoding": "inplace", + "label": "contract ILiquityBaseParams", + "numberOfBytes": "20" + }, + "t_contract(IPriceFeed)20458": { + "encoding": "inplace", + "label": "contract IPriceFeed", + "numberOfBytes": "20" + }, + "t_contract(ISortedTroves)20817": { + "encoding": "inplace", + "label": "contract ISortedTroves", + "numberOfBytes": "20" + }, + "t_contract(IStabilityPool)21101": { + "encoding": "inplace", + "label": "contract IStabilityPool", + "numberOfBytes": "20" + }, + "t_contract(IZEROStaking)21760": { + "encoding": "inplace", + "label": "contract IZEROStaking", + "numberOfBytes": "20" + }, + "t_contract(IZEROToken)21783": { + "encoding": "inplace", + "label": "contract IZEROToken", + "numberOfBytes": "20" + }, + "t_contract(IZUSDToken)21842": { + "encoding": "inplace", + "label": "contract IZUSDToken", + "numberOfBytes": "20" + }, + "t_enum(Status)35255": { + "encoding": "inplace", + "label": "enum TroveManagerStorage.Status", + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_struct(RewardSnapshot)35289_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct TroveManagerStorage.RewardSnapshot)", + "numberOfBytes": "32", + "value": "t_struct(RewardSnapshot)35289_storage" + }, + "t_mapping(t_address,t_struct(Trove)35266_storage)": { + "encoding": "mapping", + "key": "t_address", + "label": "mapping(address => struct TroveManagerStorage.Trove)", + "numberOfBytes": "32", + "value": "t_struct(Trove)35266_storage" + }, + "t_struct(RewardSnapshot)35289_storage": { + "encoding": "inplace", + "label": "struct TroveManagerStorage.RewardSnapshot", + "members": [ + { + "astId": 35286, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "ETH", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 35288, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "ZUSDDebt", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Trove)35266_storage": { + "encoding": "inplace", + "label": "struct TroveManagerStorage.Trove", + "members": [ + { + "astId": 35257, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "debt", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 35259, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "coll", + "offset": 0, + "slot": "1", + "type": "t_uint256" + }, + { + "astId": 35261, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "stake", + "offset": 0, + "slot": "2", + "type": "t_uint256" + }, + { + "astId": 35263, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "status", + "offset": 0, + "slot": "3", + "type": "t_enum(Status)35255" + }, + { + "astId": 35265, + "contract": "contracts/TroveManager.sol:TroveManager", + "label": "arrayIndex", + "offset": 1, + "slot": "3", + "type": "t_uint128" + } + ], + "numberOfBytes": "128" + }, + "t_uint128": { + "encoding": "inplace", + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} diff --git a/external/deployments/rskTestnet/TroveManager_Proxy.json b/external/deployments/rskTestnet/TroveManager_Proxy.json new file mode 100644 index 000000000..2dd2ccc39 --- /dev/null +++ b/external/deployments/rskTestnet/TroveManager_Proxy.json @@ -0,0 +1,110 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "UpgradableProxy", + "sourceName": "contracts/Proxy/UpgradableProxy.sol", + "address": "0xd8aB7EC3bd20A0Ce3084e124bFBC9Aa96a6D7FdD", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "_oldImplementation", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "_newImplementation", + "type": "address" + } + ], + "name": "ImplementationChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "getImplementation", + "outputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "name": "setImplementation", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b50610023336001600160e01b0361002816565b610110565b6001600160a01b03811661006d5760405162461bcd60e51b81526004018080602001828103825260228152602001806105e26022913960400191505060405180910390fd5b6001600160a01b0381166100886001600160e01b036100e616565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b6104c38061011f6000396000f3fe6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b00334f776e61626c653a3a7365744f776e65723a20696e76616c69642061646472657373", + "deployedBytecode": "0x6080604052600436106100435760003560e01c806313af40351461005a578063893d20e81461008d578063aaf10f42146100be578063d784d426146100d357610052565b3661005257610050610106565b005b610050610106565b34801561006657600080fd5b506100506004803603602081101561007d57600080fd5b50356001600160a01b031661017c565b34801561009957600080fd5b506100a26101ef565b604080516001600160a01b039092168252519081900360200190f35b3480156100ca57600080fd5b506100a2610219565b3480156100df57600080fd5b50610050600480360360208110156100f657600080fd5b50356001600160a01b0316610244565b6000610110610219565b90506001600160a01b0381166101575760405162461bcd60e51b815260040180806020018281038252602381526020018061046b6023913960400191505060405180910390fd5b60405136600082376000803683855af43d806000843e818015610178578184f35b8184fd5b6101846101ef565b6001600160a01b0316336001600160a01b0316146101e3576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec816102b4565b50565b604080517035b2bc9737bbb730b136329737bbb732b960791b815290519081900360110190205490565b604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205490565b61024c6101ef565b6001600160a01b0316336001600160a01b0316146102ab576040805162461bcd60e51b815260206004820152601760248201527613dddb98589b194e8e881858d8d95cdcc819195b9a5959604a1b604482015290519081900360640190fd5b6101ec81610369565b6001600160a01b0381166102f95760405162461bcd60e51b81526004018080602001828103825260228152602001806104206022913960400191505060405180910390fd5b806001600160a01b031661030b6101ef565b6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3604080517035b2bc9737bbb730b136329737bbb732b960791b8152905190819003601101902055565b6001600160a01b0381166103ae5760405162461bcd60e51b81526004018080602001828103825260298152602001806104426029913960400191505060405180910390fd5b806001600160a01b03166103c0610219565b6001600160a01b03167fcfbf4028add9318bbf716f08c348595afb063b0e9feed1f86d33681a4b3ed4d360405160405180910390a3604080517135b2bc9734b6b83632b6b2b73a30ba34b7b760711b815290519081900360120190205556fe4f776e61626c653a3a7365744f776e65723a20696e76616c6964206164647265737350726f78793a3a736574496d706c656d656e746174696f6e3a20696e76616c6964206164647265737350726f78793a3a28293a20696d706c656d656e746174696f6e206e6f7420666f756e64a2646970667358221220f84db5b0f5dd60cbb7d66141de13219d0da4edbe3006d54bb4d362cbc0da0dfa64736f6c634300060b0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/hardhat/tasks/sips/args/sipArgs.js b/hardhat/tasks/sips/args/sipArgs.js index 6de299cab..95435a727 100644 --- a/hardhat/tasks/sips/args/sipArgs.js +++ b/hardhat/tasks/sips/args/sipArgs.js @@ -763,6 +763,34 @@ const getArgsSip0047 = async (hre) => { return { args, governor: "GovernorOwner" }; }; +const getArgsSipSov625 = async (hre) => { + const { + ethers, + deployments: { get }, + } = hre; + const abiCoder = new ethers.utils.AbiCoder(); + const staking = await get("Staking"); + const stakingAddress = staking.address; + const vestingLogicDeployment = await get("VestingLogic"); + const vestingRegistryDeployment = await get("VestingRegistry"); + const vestingFactoryDeployment = await get("VestingFactory"); + + const args = { + targets: [vestingRegistryDeployment.address, stakingAddress], + values: [0, 0], + signatures: ["setVestingFactory(address)", "addContractCodeHash(address)"], + data: [ + abiCoder.encode(["address"], [vestingFactoryDeployment.address]), + abiCoder.encode(["address"], [vestingLogicDeployment.address]), + ], + /** @todo change SIP description */ + description: + "SIP-Sov625: Set vestingFactory in vestingRegistry & Add vestingLogic contract code hash to staking contract", + }; + + return { args, governor: "GovernorOwner" }; +}; + const getArgsSip0073 = async (hre) => { const { ethers, @@ -828,6 +856,130 @@ const getArgsSip0073 = async (hre) => { }; return { args, governor: "GovernorOwner" }; }; +const getArgsSip_SOV_3161 = async (hre) => { + const { + ethers, + deployments: { get }, + } = hre; + const abiCoder = new ethers.utils.AbiCoder(); + const protocol = await ethers.getContract("ISovryn"); + const loanOpeningsModule = await get("LoanOpenings"); + + //validate + if (!network.tags.mainnet) { + logger.error("Unknown network"); + process.exit(1); + } + + if ( + (await protocol.getTarget("setDelegatedManager(bytes32,address,bool)")) == + loanOpeningsModule.address + ) { + logger.error("LoanOpenings module deployment already registered in the protocol"); + process.exit(1); + } + + const args = { + targets: [protocol.address], + values: [0], + signatures: ["replaceContract(address)"], + data: [abiCoder.encode(["address"], [loanOpeningsModule.address])], + description: + "SIP-XXXX: _______________, Details: https://github.com/DistributedCollective/SIPS/blob/_______/________.md, sha256: ____________", + }; + return { args, governor: "GovernorOwner" }; +}; + +const getArgsSip0074 = async (hre) => { + // Electron release + const { + ethers, + deployments: { get }, + } = hre; + const abiCoder = new ethers.utils.AbiCoder(); + + /** SOV3161 */ + const protocol = await ethers.getContract("ISovryn"); + const loanOpeningsModule = await get("LoanOpenings"); + + /** SOV625 */ + const staking = await get("Staking"); + const stakingAddress = staking.address; + const vestingLogicDeployment = await get("VestingLogic"); + const vestingRegistryDeployment = await get("VestingRegistry"); + const vestingFactoryDeployment = await get("VestingFactory"); + + /** SOV3564 Zero */ + const newStabilityPoolImplementation = await get("StabilityPool_Implementation"); + const newBorrowerOperationsImplementation = await get("BorrowerOperations_Implementation"); + const newTroveManagerImplementation = await get("TroveManager_Implementation"); + const newTroveManagerRedeemOps = await get("TroveManagerRedeemOps"); + + const stabilityPoolProxy = await get("StabilityPool_Proxy"); + const borrowerOperationsProxy = await get("BorrowerOperations_Proxy"); + const troveManagerProxy = await get("TroveManager_Proxy"); + + /** SOV3564 Mynt */ + const myntAdminProxy = await get("MyntAdminProxy"); + + const mocIntegrationProxy = await get("MocIntegration"); // MocIntegration + const newMocIntegrationImpl = await get("MocIntegration_Implementation"); + + //validate + if (!network.tags.mainnet) { + logger.error("Unknown network"); + process.exit(1); + } + + if ( + (await protocol.getTarget("setDelegatedManager(bytes32,address,bool)")) == + loanOpeningsModule.address + ) { + logger.error("LoanOpenings module deployment already registered in the protocol"); + process.exit(1); + } + + const args = { + targets: [ + protocol.address, + vestingRegistryDeployment.address, + stakingAddress, + stabilityPoolProxy.address, + borrowerOperationsProxy.address, + troveManagerProxy.address, + troveManagerProxy.address, + myntAdminProxy.address, + ], + values: [0, 0, 0, 0, 0, 0, 0, 0], + signatures: [ + "replaceContract(address)", + "setVestingFactory(address)", + "addContractCodeHash(address)", + "setImplementation(address)", + "setImplementation(address)", + "setImplementation(address)", + "setTroveManagerRedeemOps(address)", + "upgrade(address,address)", + ], + data: [ + abiCoder.encode(["address"], [loanOpeningsModule.address]), + abiCoder.encode(["address"], [vestingFactoryDeployment.address]), + abiCoder.encode(["address"], [vestingLogicDeployment.address]), + abiCoder.encode(["address"], [newStabilityPoolImplementation.address]), + abiCoder.encode(["address"], [newBorrowerOperationsImplementation.address]), + abiCoder.encode(["address"], [newTroveManagerImplementation.address]), + abiCoder.encode(["address"], [newTroveManagerRedeemOps.address]), + abiCoder.encode( + ["address", "address"], + [mocIntegrationProxy.address, newMocIntegrationImpl.address] + ), + ], + // @todo updatee sip description + description: + "SIP-0074: Smart Contracts Upgrade Electron, Details: https://github.com/DistributedCollective/SIPS/blob/a86ac0e/SIP-0074.md, sha256: c595e86f84b392ca38c027b911631eba0cbe212871b66425005647a22381313a", + }; + return { args, governor: "GovernorOwner" }; +}; module.exports = { sampleGovernorAdminSIP, @@ -841,5 +993,8 @@ module.exports = { getArgsSip0046Part2, getArgsSip0046Part3, getArgsSip0046Part4, + getArgsSipSov625, getArgsSip0073, + getArgsSip_SOV_3161, + getArgsSip0074, }; diff --git a/hardhat/tasks/utils.js b/hardhat/tasks/utils.js index 50fb1ef13..1b5b93a21 100644 --- a/hardhat/tasks/utils.js +++ b/hardhat/tasks/utils.js @@ -126,7 +126,6 @@ task( } } }); - task("utils:replace-tx", "Replace tx in mempool") .addParam("hash", "Replaced transaction hash", undefined, types.string) .addOptionalParam("newFrom", "New 'from' address") diff --git a/remix-compiler.config.js b/remix-compiler.config.js new file mode 100644 index 000000000..6137b9e73 --- /dev/null +++ b/remix-compiler.config.js @@ -0,0 +1,9 @@ +module.exports = { + solidity: "0.5.17", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, +}; diff --git a/tests-onchain/sip0074.test.js b/tests-onchain/sip0074.test.js new file mode 100644 index 000000000..f5a032a22 --- /dev/null +++ b/tests-onchain/sip0074.test.js @@ -0,0 +1,208 @@ +// first run a local forked mainnet node in a separate terminal window: +// npx hardhat node --fork https://mainnet-dev.sovryn.app/rpc --no-deploy +// now run the test: +// npx hardhat test tests-onchain/sov3613.test.js --network rskForkedMainnet + +const { + impersonateAccount, + mine, + time, + setBalance, +} = require("@nomicfoundation/hardhat-network-helpers"); +const hre = require("hardhat"); +const { getProtocolModules } = require("../deployment/helpers/helpers"); + +const { + ethers, + deployments: { createFixture, get }, +} = hre; + +const MAX_DURATION = ethers.BigNumber.from(24 * 60 * 60).mul(1092); + +const ONE_RBTC = ethers.utils.parseEther("1.0"); + +const getImpersonatedSigner = async (addressToImpersonate) => { + await impersonateAccount(addressToImpersonate); + return await ethers.getSigner(addressToImpersonate); +}; + +describe("Protocol Modules Deployments and Upgrades via Governance", () => { + const getImpersonatedSignerFromJsonRpcProvider = async (addressToImpersonate) => { + const provider = new ethers.providers.JsonRpcProvider("http://localhost:8545"); + await provider.send("hardhat_impersonateAccount", [addressToImpersonate]); + return provider.getSigner(addressToImpersonate); + }; + + const setupTest = createFixture(async ({ deployments }) => { + const deployer = (await ethers.getSigners())[0].address; + const deployerSigner = await ethers.getSigner(deployer); + + const multisigAddress = (await get("MultiSigWallet")).address; + const multisigSigner = await getImpersonatedSignerFromJsonRpcProvider(multisigAddress); + + await setBalance(deployer, ONE_RBTC.mul(10)); + await deployments.fixture(["ProtocolModules"], { + keepExistingDeployments: true, + }); // start from a fresh deployments + + const staking = await ethers.getContract("Staking", deployerSigner); + const sovrynProtocol = await ethers.getContract("SovrynProtocol", deployerSigner); + + const god = await deployments.get("GovernorOwner"); + const governorOwner = await ethers.getContractAt( + "GovernorAlpha", + god.address, + deployerSigner + ); + const governorOwnerSigner = await getImpersonatedSigner(god.address); + + await setBalance(governorOwnerSigner.address, ONE_RBTC); + const timelockOwner = await ethers.getContract("TimelockOwner", governorOwnerSigner); + + const timelockOwnerSigner = await getImpersonatedSignerFromJsonRpcProvider( + timelockOwner.address + ); + await setBalance(timelockOwnerSigner._address, ONE_RBTC); + + // + return { + deployer, + deployerSigner, + staking, + sovrynProtocol, + governorOwner, + governorOwnerSigner, + timelockOwner, + timelockOwnerSigner, + multisigAddress, + multisigSigner, + }; + }); + + /// @todo change the SIP name + describe("SIP-0074 Test creation and execution", () => { + it("SIP-0074 is executable and valid", async () => { + if (!hre.network.tags["forked"]) { + console.error("ERROR: Must run on a forked net"); + return; + } + await hre.network.provider.request({ + method: "hardhat_reset", + params: [ + { + forking: { + jsonRpcUrl: "https://mainnet-dev.sovryn.app/rpc", + blockNumber: 6037998, + }, + }, + ], + }); + + console.log("asd"); + const { + deployer, + deployerSigner, + staking, + sovrynProtocol, + governorOwner, + timelockOwnerSigner, + multisigAddress, + multisigSigner, + } = await setupTest(); + console.log("asd2"); + + // CREATE PROPOSAL + const sov = await ethers.getContract("SOV", timelockOwnerSigner); + const whaleAmount = (await sov.totalSupply()).mul(ethers.BigNumber.from(5)); + await sov.mint(deployer, whaleAmount); + + await sov.connect(deployerSigner).approve(staking.address, whaleAmount); + + if (await staking.paused()) await staking.connect(multisigSigner).pauseUnpause(false); + const kickoffTS = await staking.kickoffTS(); + await staking.stake(whaleAmount, kickoffTS.add(MAX_DURATION), deployer, deployer); + await mine(); + + // CREATE PROPOSAL AND VERIFY + const proposalIdBeforeSIP = await governorOwner.latestProposalIds(deployer); + await hre.run("sips:create", { argsFunc: "getArgsSip0074" }); + const proposalId = await governorOwner.latestProposalIds(deployer); + expect( + proposalId, + "Proposal was not created. Check the SIP creation is not commented out." + ).is.gt(proposalIdBeforeSIP); + + // VOTE FOR PROPOSAL + + await mine(); + await governorOwner.connect(deployerSigner).castVote(proposalId, true); + + // QUEUE PROPOSAL + let proposal = await governorOwner.proposals(proposalId); + await mine(proposal.endBlock); + await governorOwner.queue(proposalId); + + // EXECUTE PROPOSAL + proposal = await governorOwner.proposals(proposalId); + await time.increaseTo(proposal.eta); + await expect(governorOwner.execute(proposalId)) + .to.emit(governorOwner, "ProposalExecuted") + .withArgs(proposalId); + + // VERIFY execution + expect((await governorOwner.proposals(proposalId)).executed).to.be.true; + + // VERIFY LoanOpenings + expect( + (await sovrynProtocol.getTarget("setDelegatedManager(bytes32,address,bool)")) == + (await get("LoanOpenings")).address + ).to.be.true; + + // VERIFY vesting factory has been registered in vestingRegistry + const vestingRegistry = await ethers.getContract("VestingRegistry"); + const vestingFactoryDeployment = await get("VestingFactory"); + expect(await vestingRegistry.vestingFactory()).to.equal( + vestingFactoryDeployment.address + ); + + // VERIFY contract code hash has been registered + const vestingLogicDeployment = await get("VestingLogic"); + expect(await staking.isVestingContract(vestingLogicDeployment.address)).to.be.true; + + /** VALIDATE MOC NEW IMPLEMENTATION */ + const myntAdminProxy = await ethers.getContract("MyntAdminProxy"); + const miProxyDeployment = await get("MocIntegration_Proxy"); + const miDeployment = await get("MocIntegration"); + expect( + await myntAdminProxy.getProxyImplementation(miProxyDeployment.address) + ).to.equal(miDeployment.implementation); + + // Validate zero contracs upgrade + const stabilityPoolProxy = await ethers.getContract("StabilityPool_Proxy"); + const stabilityPoolImpl = await get("StabilityPool_Implementation"); + + const borrowerOperationsProxy = await ethers.getContract("BorrowerOperations_Proxy"); + const borrowerOperationsImpl = await get("BorrowerOperations_Implementation"); + + const troveManagerProxy = await ethers.getContract("TroveManager_Proxy"); + const troveManagerImpl = await get("TroveManager_Implementation"); + + const troveManager = await ethers.getContract("TroveManager"); + const troveManagerRedeemOps = await get("TroveManagerRedeemOps"); + + expect(await stabilityPoolProxy.getImplementation()).to.equal( + stabilityPoolImpl.address + ); + + expect(await borrowerOperationsProxy.getImplementation()).to.equal( + borrowerOperationsImpl.address + ); + + expect(await troveManagerProxy.getImplementation()).to.equal(troveManagerImpl.address); + + expect(await troveManager.troveManagerRedeemOps()).to.equal( + troveManagerRedeemOps.address + ); + }); + }); +}); diff --git a/tests-onchain/sipSov625.test.js b/tests-onchain/sipSov625.test.js new file mode 100644 index 000000000..d027f9d7f --- /dev/null +++ b/tests-onchain/sipSov625.test.js @@ -0,0 +1,165 @@ +// first run a local forked mainnet node in a separate terminal window: +// npx hardhat node --fork https://mainnet-dev.sovryn.app/rpc --no-deploy +// now run the test: +// npx hardhat test tests-onchain/sipSov3497.test.js --network rskForkedMainnet + +const { + impersonateAccount, + mine, + time, + setBalance, +} = require("@nomicfoundation/hardhat-network-helpers"); +const hre = require("hardhat"); +const { getProtocolModules } = require("../deployment/helpers/helpers"); + +const { + ethers, + deployments: { createFixture, get }, +} = hre; + +const MAX_DURATION = ethers.BigNumber.from(24 * 60 * 60).mul(1092); + +const ONE_RBTC = ethers.utils.parseEther("1.0"); + +const getImpersonatedSigner = async (addressToImpersonate) => { + await impersonateAccount(addressToImpersonate); + return await ethers.getSigner(addressToImpersonate); +}; + +describe("Protocol Modules Deployments and Upgrades via Governance", () => { + const getImpersonatedSignerFromJsonRpcProvider = async (addressToImpersonate) => { + const provider = new ethers.providers.JsonRpcProvider("http://localhost:8545"); + await provider.send("hardhat_impersonateAccount", [addressToImpersonate]); + return provider.getSigner(addressToImpersonate); + }; + + const setupTest = createFixture(async ({ deployments }) => { + const deployer = (await ethers.getSigners())[0].address; + const deployerSigner = await ethers.getSigner(deployer); + + const multisigAddress = (await get("MultiSigWallet")).address; + const multisigSigner = await getImpersonatedSignerFromJsonRpcProvider(multisigAddress); + + await setBalance(deployer, ONE_RBTC.mul(10)); + await deployments.fixture(["ProtocolModules"], { + keepExistingDeployments: true, + }); // start from a fresh deployments + + const staking = await ethers.getContract("Staking", deployerSigner); + const sovrynProtocol = await ethers.getContract("SovrynProtocol", deployerSigner); + + const god = await deployments.get("GovernorOwner"); + const governorOwner = await ethers.getContractAt( + "GovernorAlpha", + god.address, + deployerSigner + ); + const governorOwnerSigner = await getImpersonatedSigner(god.address); + + await setBalance(governorOwnerSigner.address, ONE_RBTC); + const timelockOwner = await ethers.getContract("TimelockOwner", governorOwnerSigner); + + const timelockOwnerSigner = await getImpersonatedSignerFromJsonRpcProvider( + timelockOwner.address + ); + await setBalance(timelockOwnerSigner._address, ONE_RBTC); + + // + return { + deployer, + deployerSigner, + staking, + sovrynProtocol, + governorOwner, + governorOwnerSigner, + timelockOwner, + timelockOwnerSigner, + multisigAddress, + multisigSigner, + }; + }); + + /// @todo change the SIP name + describe("SIP-Sov625 Test creation and execution", () => { + it("SIP-Sov625 is executable and valid", async () => { + if (!hre.network.tags["forked"]) { + console.error("ERROR: Must run on a forked net"); + return; + } + await hre.network.provider.request({ + method: "hardhat_reset", + params: [ + { + forking: { + jsonRpcUrl: "https://mainnet-dev.sovryn.app/rpc", + blockNumber: 5937831, // block num at the time no new modules deployed yet + }, + }, + ], + }); + + const { + deployer, + deployerSigner, + staking, + sovrynProtocol, + governorOwner, + timelockOwnerSigner, + multisigAddress, + multisigSigner, + } = await setupTest(); + + // CREATE PROPOSAL + const sov = await ethers.getContract("SOV", timelockOwnerSigner); + const whaleAmount = (await sov.totalSupply()).mul(ethers.BigNumber.from(5)); + await sov.mint(deployer, whaleAmount); + + await sov.connect(deployerSigner).approve(staking.address, whaleAmount); + + if (await staking.paused()) await staking.connect(multisigSigner).pauseUnpause(false); + const kickoffTS = await staking.kickoffTS(); + await staking.stake(whaleAmount, kickoffTS.add(MAX_DURATION), deployer, deployer); + await mine(); + + // CREATE PROPOSAL AND VERIFY + const proposalIdBeforeSIP = await governorOwner.latestProposalIds(deployer); + await hre.run("sips:create", { argsFunc: "getArgsSipSov625" }); + const proposalId = await governorOwner.latestProposalIds(deployer); + expect( + proposalId, + "Proposal was not created. Check the SIP creation is not commented out." + ).is.gt(proposalIdBeforeSIP); + + // VOTE FOR PROPOSAL + + await mine(); + await governorOwner.connect(deployerSigner).castVote(proposalId, true); + + // QUEUE PROPOSAL + let proposal = await governorOwner.proposals(proposalId); + await mine(proposal.endBlock); + await governorOwner.queue(proposalId); + + // EXECUTE PROPOSAL + proposal = await governorOwner.proposals(proposalId); + await time.increaseTo(proposal.eta); + await expect(governorOwner.execute(proposalId)) + .to.emit(governorOwner, "ProposalExecuted") + .withArgs(proposalId); + + // VERIFY execution + expect((await governorOwner.proposals(proposalId)).executed).to.be.true; + + // VERIFY vesting factory has been registered in vestingRegistry + const vestingRegistry = await ethers.getContract("VestingRegistry"); + const vestingFactoryDeployment = await get("VestingFactory"); + expect(await vestingRegistry.vestingFactory()).to.equal( + vestingFactoryDeployment.address + ); + + // VERIFY contract code hash has been registered + const vestingLogicDeployment = await get("VestingLogic"); + expect(await staking.isVestingContract(vestingLogicDeployment.address)).to.be.true; + }); + }); +}); diff --git a/tests-onchain/sip_sov3161.test.js b/tests-onchain/sip_sov3161.test.js new file mode 100644 index 000000000..e0e738f41 --- /dev/null +++ b/tests-onchain/sip_sov3161.test.js @@ -0,0 +1,152 @@ +//@note hh test tests-onchain/sip0047.test.js --network rskForkedMainnet + +const { + impersonateAccount, + mine, + time, + setBalance, +} = require("@nomicfoundation/hardhat-network-helpers"); +const hre = require("hardhat"); + +const { + ethers, + deployments: { createFixture, get }, +} = hre; + +const MAX_DURATION = ethers.BigNumber.from(24 * 60 * 60).mul(1092); + +const ONE_RBTC = ethers.utils.parseEther("1.0"); + +const getImpersonatedSigner = async (addressToImpersonate) => { + await impersonateAccount(addressToImpersonate); + return await ethers.getSigner(addressToImpersonate); +}; + +describe("Replace LoanOpenings module - borrowing from existing loan bug fix", () => { + const getImpersonatedSignerFromJsonRpcProvider = async (addressToImpersonate) => { + const provider = new ethers.providers.JsonRpcProvider("http://localhost:8545"); + await provider.send("hardhat_impersonateAccount", [addressToImpersonate]); + return provider.getSigner(addressToImpersonate); + }; + + const setupTest = createFixture(async ({ deployments, getNamedAccounts }) => { + //const { deployer } = await getNamedAccounts(); + //const deployerSigner = await ethers.getSigner(deployer); + //const deployer = "0xFEe171A152C02F336021fb9E79b4fAc2304a9E7E"; // has enough voting power to create a SIP + // const deployerSigner = await getImpersonatedSignerFromJsonRpcProvider( + // deployerAddress.toLowerCase() + // ); + const deployerSigner = (await ethers.getSigners())[0]; + const deployer = deployerSigner.address; + + await setBalance(deployer, ONE_RBTC.mul(10)); + + const staking = await ethers.getContract("Staking", deployerSigner); + const protocol = await ethers.getContract("ISovryn"); + + const god = await deployments.get("GovernorOwner"); + const governorOwner = await ethers.getContractAt( + "GovernorAlpha", + god.address, + deployerSigner + ); + const governorOwnerSigner = await getImpersonatedSigner(god.address); + + await setBalance(governorOwnerSigner.address, ONE_RBTC); + const timelockOwner = await ethers.getContract("TimelockOwner", governorOwnerSigner); + + const timelockOwnerSigner = await getImpersonatedSignerFromJsonRpcProvider( + timelockOwner.address + ); + await setBalance(timelockOwnerSigner._address, ONE_RBTC); + + await deployments.fixture("ReplaceProtocolModules", { + keepExistingDeployments: true, + }); + + // + return { + deployer, + deployerSigner, + governorOwner, + governorOwnerSigner, + timelockOwner, + timelockOwnerSigner, + staking, + protocol, + }; + }); + + describe("SIP for SOV-3161 Testing", () => { + it("SIP is executable and valid", async () => { + if (!(hre.network.tags["forked"] && hre.network.tags["mainnet"])) { + console.error("ERROR: Must run on a forked mainnet"); + return; + } + await hre.network.provider.request({ + method: "hardhat_reset", + params: [ + { + forking: { + jsonRpcUrl: "https://mainnet-dev.sovryn.app/rpc", + blockNumber: 5796574, // block num at the time of the test creation with no fix applied yet + }, + }, + ], + }); + + const { + deployer, + deployerSigner, + governorOwner, + timelockOwnerSigner, + staking, + protocol, + } = await setupTest(); + + // CREATE PROPOSAL + const sov = await ethers.getContract("SOV", timelockOwnerSigner); + const whaleAmount = (await sov.totalSupply()).mul(ethers.BigNumber.from(5)); + await sov.mint(deployer, whaleAmount); + + await sov.connect(deployerSigner).approve(staking.address, whaleAmount); + + if (await staking.paused()) await staking.connect(multisigSigner).pauseUnpause(false); + const kickoffTS = await staking.kickoffTS(); + await staking.stake(whaleAmount, kickoffTS.add(MAX_DURATION), deployer, deployer); + await mine(); + + // CREATE PROPOSAL AND VERIFY + const proposalIdBeforeSIP = await governorOwner.latestProposalIds(deployer); + await hre.run("sips:create", { argsFunc: "getArgsSip_SOV_3161" }); + const proposalId = await governorOwner.latestProposalIds(deployer); + expect( + proposalId, + "Proposal was not created. Check the SIP creation is not commented out." + ).is.gt(proposalIdBeforeSIP); + + // VOTE FOR PROPOSAL + + await mine(); + await governorOwner.connect(deployerSigner).castVote(proposalId, true); + + // QUEUE PROPOSAL + let proposal = await governorOwner.proposals(proposalId); + await mine(proposal.endBlock); + await governorOwner.queue(proposalId); + + // EXECUTE PROPOSAL + proposal = await governorOwner.proposals(proposalId); + await time.increaseTo(proposal.eta); + await expect(governorOwner.execute(proposalId)) + .to.emit(governorOwner, "ProposalExecuted") + .withArgs(proposalId); + + // VALIDATE EXECUTION + expect( + (await protocol.getTarget("setDelegatedManager(bytes32,address,bool)")) == + (await get("LoanOpenings")).address + ).to.be.true; + }); + }); +}); diff --git a/tests-onchain/sov3161.test.js b/tests-onchain/sov3161.test.js new file mode 100644 index 000000000..e9b1855e8 --- /dev/null +++ b/tests-onchain/sov3161.test.js @@ -0,0 +1,463 @@ +// @todo run on a local forked rsk testnet or mainnet nodes +// npx hardhat node --fork https://testnet.sovryn.app/rpc --no-deploy +// npx hardhat node --fork https://mainnet-dev.sovryn.app/rpc --no-deploy +const Logs = require("node-logs"); +const log = console.log; +const { expect } = require("chai"); +const { + loadFixture, + impersonateAccount, + stopImpersonatingAccount, + mine, + time, + setBalance, + setCode, + takeSnapshot, +} = require("@nomicfoundation/hardhat-network-helpers"); +const hre = require("hardhat"); +const logger = new Logs().showInConsole(true); +const { decodeLogs } = require("../tests/Utils/initializer.js"); + +const { + ethers, + deployments, + deployments: { createFixture, get, deploy }, + getNamedAccounts, + network, +} = hre; + +const oneEth = ethers.utils.parseEther("1.0"); +const { AddressZero } = ethers.constants; +const { BN, expectRevert } = require("@openzeppelin/test-helpers"); +const emptyBytes32 = ethers.utils.hexZeroPad("0x", 32); +const LoanOpenings = artifacts.require("LoanOpenings"); + +const testnetUrl = "https://testnet.sovryn.app/rpc"; +const mainnetUrl = "https://mainnet-dev.sovryn.app/rpc"; + +testnetData = { + protocolOwner: "MultiSigWallet", + url: testnetUrl, + chainId: 31, + //atBlock: 4418245, + tokens: [], +}; +mainnetData = { + protocolOwner: "TimelockOwner", + url: mainnetUrl, + chainId: 30, + //atBlock: 5749587, //5692524 + tokens: [], +}; +const { url, chainId, atBlock, users, tokens, protocolOwner } = network.tags.mainnet + ? mainnetData + : testnetData; + +// we need this if using named accounts in config +const getImpersonatedSignerFromJsonRpcProvider = async (addressToImpersonate) => { + const provider = new ethers.providers.JsonRpcProvider("http://localhost:8545"); + await provider.send("hardhat_impersonateAccount", [addressToImpersonate]); + return provider.getSigner(addressToImpersonate); +}; + +const getImpersonatedSigner = async (addressToImpersonate) => { + await impersonateAccount(addressToImpersonate); + return await ethers.getSigner(addressToImpersonate); +}; + +// QA Tests +describe("Check if Borrowing from existing loan using excessive collateral of the loan works", async () => { + let snapshot, accounts, borrower, borrowerSigner, receiver, receiverSigner, lendingPools; + let feeSharingCollectorProxy, + feeSharingCollectorDeployment, + feeSharingCollector, + protocol, + priceFeeds, + wRBTC; + + before(async () => { + /*await network.provider.request({ + method: "hardhat_reset", + params: [ + { + forking: { + jsonRpcUrl: url, + blockNumber: atBlock, + }, + }, + ], + });*/ + lendingPools = [ + { pool: "LoanToken_iXUSD", token: "XUSD" }, + { pool: "LoanToken_iDLLR", token: "DLLR" }, + { pool: "LoanToken_iDOC", token: "DoC" }, + // { pool: "LoanToken_iBPRO", token: "BPro" }, + // {pool: "LoanToken_iRBTC", token: "WRBTC"}, // ? + // { pool: "LoanToken_iUSDT", token: "USDT" }, + ]; + + accounts = await ethers.getSigners(); + borrowerSigner = accounts[1]; //(await get("MultiSigWallet")).address; + borrower = borrowerSigner.address; //accounts[1]; //(await get("MultiSigWallet")).address; + receiverSigner = accounts[1]; // (await get("MultiSigWallet")).address; + receiver = receiverSigner.address; //accounts[1]; // (await get("MultiSigWallet")).address; + + deployResult = await deploy("LoanOpenings", { + contract: "LoanOpenings", + from: (await ethers.getSigners())[0].address, + }); + + snapshot = await takeSnapshot(); + const protocolOwnerAddress = (await get(protocolOwner)).address; + ownerSigner = await getImpersonatedSignerFromJsonRpcProvider(protocolOwnerAddress); + + await setBalance(protocolOwnerAddress, ethers.utils.parseEther("5")); + + protocol = await ethers.getContract("ISovryn", ownerSigner); + (await protocol.replaceContract(deployResult.address)).wait(); + + priceFeeds = await ethers.getContract("PriceFeeds", ownerSigner); + wRBTC = await ethers.getContract("WRBTC"); + + await wRBTC.connect(accounts[1]).deposit({ value: ethers.utils.parseEther("1") }); + + // await deployments.fixture(["FeeSharingCollector"], { + // keepExistingDeployments: true, + // }); + + // await deployments.save("FeeSharingCollector", { + // address: feeSharingCollectorProxy.address, + // implementation: deployResult.address, + // abi: deployResult.abi, + // bytecode: deployResult.bytecode, + // deployedBytecode: deployResult.deployedBytecode, + // devdoc: deployResult.devdoc, + // userdoc: deployResult.userdoc, + // storageLayout: deployResult.storageLayout, + // }); + + // feeSharingCollector = await ethers.getContract("FeeSharingCollector"); + }); + + after(async () => { + await snapshot.restore(); + }); + + it("Test increasing existing loan debt by borrowing with 0 collateral", async () => { + // determine borrowing parameter + const withdrawAmount = oneEth.mul(100); //borrow 100 USD + + for (let i = 0; i < lendingPools.length; i++) { + log(`======= TESTING ${lendingPools[i].pool} =======`); + const loanToken = await ethers.getContract(lendingPools[i].pool); + const underlyingToken = await ethers.getContract(lendingPools[i].token); + + // compute the required collateral. params: address loanToken, address collateralToken, uint256 newPrincipal,uint256 marginAmount, bool isTorqueLoan + // console.log(`lendingPools[i].token: ${lendingPools[i].token}`); + let collateralTokenSent = await protocol.getRequiredCollateral( + underlyingToken.address, + wRBTC.address, + withdrawAmount, + ethers.utils.parseEther("50"), // <- minInitialMargin // new BN(10).pow(new BN(18)).mul(new BN(50)), // + true + ); + // console.log( + // `collateralTokenSent: required RBTC collateral to borrow 100 USD with 50% margin: ${collateralTokenSent}` + // ); + + const durationInSeconds = 60 * 60 * 24 * 10; //10 days + // getDepositAmountForBorrow uses getRequiredCollateral, but adds borrowing fee first to calculate total principal amout for loan token + collateralTokenSent = await loanToken.getDepositAmountForBorrow( + withdrawAmount, + durationInSeconds, + wRBTC.address + ); + + // console.log( + // `getDepositAmountForBorrow: required RBTC collateral to borrow 100 USD with 50% margin: ${collateralTokenSent}` + // ); + + // console.log( + // `required RBTC collateral to borrow 100 USD using loanToken.getDepositAmountForBorrow for 10 days: ${collateralTokenSent}` + // ); + + // const { rate: exchange_rate, precision } = await priceFeeds.queryRate( + // wRBTC.address, + // underlyingToken.address + // ); + // console.log(`ex rate: ${exchange_rate}`); + + // approve the transfer of the collateral + await wRBTC + .connect(borrowerSigner) + .approve(loanToken.address, collateralTokenSent.mul(2)); + + // console.log("sender wrbtc balance: ", (await wRBTC.balanceOf(borrower)).toString()); + // console.log("collateral sent: ", collateralTokenSent.mul(2).toString()); + + const receipt = await ( + await loanToken.connect(borrowerSigner).borrow( + emptyBytes32, // bytes32 loanId + withdrawAmount, // uint256 withdrawAmount + durationInSeconds, // uint256 initialLoanDuration + collateralTokenSent.mul(2), // uint256 collateralTokenSent + wRBTC.address, // address collateralTokenAddress + borrower, // address borrower + receiver, // address receiver + emptyBytes32 // bytes memory loanDataBytes + ) + ).wait(); + + let decode = decodeLogs(receipt.events, LoanOpenings, "Borrow"); + const loanId = decode[0].args["loanId"]; + + // console.log("loanId: ", loanId); + // console.log("decode[0].args: ", decode[0].args); + + const newPrincipal = decode[0].args["newPrincipal"]; + const newCollateral = decode[0].args["newCollateral"]; + // console.log(`new principal: ${newPrincipal / 1e18}`); + // console.log(`new collateral: ${newCollateral / 1e18}`); + const maxDrawdown = await priceFeeds.getMaxDrawdown( + underlyingToken.address, //borrowing token address + wRBTC.address, // collateral token address + newPrincipal, //withdrawAmount, + newCollateral, //collateralTokenSent.mul(2), + ethers.utils.parseEther("50") + ); + + // console.log(`old principal (withdrawAmount): ${withdrawAmount / 1e18}`); + // console.log( + // `old collateral (collateralTokenSent x 2: ${collateralTokenSent.mul(2) / 1e18}` + // ); + // const oldMaxDrawdown = await priceFeeds.getMaxDrawdown( + // underlyingToken.address, + // wRBTC.address, + // withdrawAmount, // decode[0].args["newPrincipal"], + // collateralTokenSent.mul(2), // decode[0].args["newCollateral"], + // ethers.utils.parseEther("50") + // ); + // console.log(`old MaxDrawdown: ${oldMaxDrawdown / 1e18}`); + // console.log(`new MaxDrawdown: ${maxDrawdown / 1e18}`); + + let borrowAmountForMaxDrawdown = await loanToken.getBorrowAmountForDeposit( + maxDrawdown, + durationInSeconds, + wRBTC.address + ); + + const requiredCollateral = await loanToken.getDepositAmountForBorrow( + borrowAmountForMaxDrawdown, + durationInSeconds, + wRBTC.address + ); + + if (requiredCollateral > borrowAmountForMaxDrawdown) { + const coef = requiredCollateral.mul(oneEth).div(maxDrawdown); + borrowAmountForMaxDrawdown = borrowAmountForMaxDrawdown.mul(oneEth).div(coef); + } + + // console.log(`maxDrawdown: ${maxDrawdown}`); + // console.log(`borrowAmount for maxDrawdown: ${borrowAmountForMaxDrawdown}`); + // console.log( + // `requiredCollateral for borrowAmount for maxDrawdown ${ + // borrowAmountForMaxDrawdown / 1e18 + // }: ${requiredCollateral / 1e18}` + // ); + //console.log(`coef = requiredCollateral.mul(oneEth).div(maxDrawdown): ${coef / 1e18}`); + //console.log(`adjustedBorrowAmount: ${adjustedBorrowAmount / 1e18}`); + + // console.log(` + // borrowAmountForMaxDrawdown.mul(1012).div(1000): ${borrowAmountForMaxDrawdown + // .mul(1012) + // .div(1000)}`); + + await expectRevert( + loanToken.connect(borrowerSigner).borrow( + loanId, // bytes32 loanId + borrowAmountForMaxDrawdown.mul(1025).div(1000), // uint256 withdrawAmount - less than 1.5% error tolerance + durationInSeconds, // uint256 initialLoanDuration + "0", // uint256 collateralTokenSent + wRBTC.address, // address collateralTokenAddress + borrower, // address borrower + receiver, // address receiver + emptyBytes32 // bytes memory loanDataBytes + ), + "collateral insufficient" + ); + + const receipt2 = await ( + await loanToken.connect(borrowerSigner).borrow( + loanId, // bytes32 loanId + borrowAmountForMaxDrawdown, // uint256 withdrawAmount + durationInSeconds, // uint256 initialLoanDuration + "0", // uint256 collateralTokenSent + wRBTC.address, // address collateralTokenAddress + borrower, // address borrower + receiver, // address receiver + emptyBytes32 // bytes memory loanDataBytes + ) + ).wait(); + + decode = decodeLogs(receipt2.events, LoanOpenings, "Borrow"); + const currentMargin = decode[0].args["currentMargin"]; + expect( + ethers.BigNumber.from(currentMargin).gte(ethers.utils.parseEther("15")), + "Invalid margin" + ); // wei("15", "ether") - maintenance margin + log(">>> test passed"); + } + }); + + it("Test increasing existing loan debt by borrowing collateral < required collateral", async () => { + const withdrawAmount = oneEth.mul(100); //borrow 100 USD + for (let i = 0; i < lendingPools.length; i++) { + log(`======= TESTING ${lendingPools[i].pool} =======`); + const loanToken = await ethers.getContract(lendingPools[i].pool); + const underlyingToken = await ethers.getContract(lendingPools[i].token); + // determine borrowing parameter + + let collateralTokenSent = await protocol.getRequiredCollateral( + underlyingToken.address, + wRBTC.address, + withdrawAmount, + ethers.utils.parseEther("50"), // <- minInitialMargin // new BN(10).pow(new BN(18)).mul(new BN(50)), // + true + ); + // console.log( + // `required RBTC collateral to borrow 100 USD with 50% margin: ${collateralTokenSent}` + // ); + + const durationInSeconds = 60 * 60 * 24 * 10; //10 days + collateralTokenSent = await loanToken.getDepositAmountForBorrow( + withdrawAmount, + durationInSeconds, + wRBTC.address + ); + + // console.log( + // `required RBTC collateral to borrow 100 USD using loanToken.getDepositAmountForBorrow for 10 days: ${collateralTokenSent}` + // ); + + const { rate: exchange_rate, precision } = await priceFeeds.queryRate( + wRBTC.address, + underlyingToken.address + ); + // console.log(`ex rate: ${exchange_rate}`); + + // approve the transfer of the collateral + await wRBTC + .connect(borrowerSigner) + .approve(loanToken.address, collateralTokenSent.mul(5)); + + // console.log("borrower balance:", await ethers.provider.getBalance(borrower)); + await setBalance(borrower, ethers.utils.parseEther("5")); + // console.log("sender wrbtc balance: ", (await wRBTC.balanceOf(borrower)).toString()); + // console.log("collateral sent: ", collateralTokenSent.mul(2).toString()); + + const receipt = await ( + await loanToken.connect(borrowerSigner).borrow( + emptyBytes32, // bytes32 loanId + withdrawAmount, // uint256 withdrawAmount + durationInSeconds, // uint256 initialLoanDuration + collateralTokenSent.mul(2), // uint256 collateralTokenSent + wRBTC.address, // address collateralTokenAddress + borrower, // address borrower + receiver, // address receiver + emptyBytes32 // bytes memory loanDataBytes + ) + ).wait(); + + let decode = decodeLogs(receipt.events, LoanOpenings, "Borrow"); + const loanId = decode[0].args["loanId"]; + + // console.log("loanId: ", loanId); + // console.log("decode[0].args: ", decode[0].args); + + const newPrincipal = decode[0].args["newPrincipal"]; + const newCollateral = decode[0].args["newCollateral"]; + console.log(`newPrincipal: ${newPrincipal / 1e18}`); + console.log(`newCollateral: ${newCollateral / 1e18}`); + const maxDrawdown = await priceFeeds.getMaxDrawdown( + underlyingToken.address, + wRBTC.address, + newPrincipal, //withdrawAmount, + newCollateral, //collateralTokenSent.mul(2), + ethers.utils.parseEther("50") + ); + + const borrowAmountForMaxDrawdown = await loanToken.getBorrowAmountForDeposit( + maxDrawdown, + durationInSeconds, + wRBTC.address + ); + + const requiredCollateral = await loanToken.getDepositAmountForBorrow( + borrowAmountForMaxDrawdown, + durationInSeconds, + wRBTC.address + ); + + log(`required collateral: ${requiredCollateral / 1e18}`); + + // const coef = requiredCollateral.mul(oneEth).div(maxDrawdown); + // const adjustedBorrowAmount = borrowAmountForMaxDrawdown.div(coef).mul(oneEth); + + // console.log(`maxDrawdown: ${maxDrawdown}`); + // console.log(`borrowAmount for maxDrawdown: ${borrowAmountForMaxDrawdown}`); + // console.log( + // `requiredCollateral for borrowAmount for maxDrawdown: ${requiredCollateral}` + // ); + // console.log(`coef = requiredCollateral.mul(oneEth).div(maxDrawdown): ${coef}`); + // console.log(`adjustedBorrowAmount: ${adjustedBorrowAmount}`); + + // approve the transfer of the collateral + + const receipt2 = await ( + await loanToken.connect(borrowerSigner).borrow( + loanId, // bytes32 loanId + borrowAmountForMaxDrawdown, // uint256 withdrawAmount + durationInSeconds, // uint256 initialLoanDuration + requiredCollateral.div(2), // uint256 collateralTokenSent + wRBTC.address, // address collateralTokenAddress + borrower, // address borrower + receiver, // address receiver + emptyBytes32 // bytes memory loanDataBytes + ) + ).wait(); + + decode = decodeLogs(receipt2.events, LoanOpenings, "Borrow"); + let newPrincipal2 = decode[0].args["newPrincipal"]; + let newCollateral2 = decode[0].args["newCollateral"]; + console.log(`newPrincipal2 log: ${newPrincipal2 / 1e18}`); + console.log(`newCollateral2 log: ${newCollateral2 / 1e18}`); + + const loan = await protocol.getLoan(loanId); + newPrincipal2 = loan.principal; + newCollateral2 = loan.collateral; + console.log(`newPrincipal2: ${newPrincipal2 / 1e18}`); + console.log(`newCollateral2: ${newCollateral2 / 1e18}`); + + const currentMargin = decode[0].args["currentMargin"]; + expect( + ethers.BigNumber.from(currentMargin).gte(ethers.utils.parseEther("15")), + "Invalid margin" + ); // wei("15", "ether") - maintenance margin + + const postMaxDrawdown = await priceFeeds.getMaxDrawdown( + underlyingToken.address, + wRBTC.address, + newPrincipal2, + newCollateral2, + ethers.utils.parseEther("50") + ); + console.log(`postMaxDrawdown: ${postMaxDrawdown / 1e18}`); + console.log(`maxDrawdown: ${maxDrawdown / 1e18}`); + expect(maxDrawdown.div(2).sub(postMaxDrawdown).toNumber() / 1e18).to.be.closeTo( + 0, + 0.0001 + ); + log(">>> test passed"); + } + }); +}); diff --git a/tests/loan-token/BorrowingTestToken.test.js b/tests/loan-token/BorrowingTestToken.test.js index 819b099d2..bc44ecc0f 100644 --- a/tests/loan-token/BorrowingTestToken.test.js +++ b/tests/loan-token/BorrowingTestToken.test.js @@ -585,6 +585,254 @@ contract("LoanTokenBorrowing", (accounts) => { ); }); + it("Test increasing existing loan debt by borrowing with 0 collateral", async () => { + // prepare the test + + await lend_to_pool(loanToken, SUSD, owner); + await set_demand_curve(loanToken); + + // determine borrowing parameter + const withdrawAmount = oneEth.mul(new BN(100)); // I want to borrow 100 USD + // compute the required collateral. params: address loanToken, address collateralToken, uint256 newPrincipal,uint256 marginAmount, bool isTorqueLoan + let collateralTokenSent = await sovryn.getRequiredCollateral( + SUSD.address, + RBTC.address, + withdrawAmount, + wei("20", "ether"), // <- minInitialMargin // new BN(10).pow(new BN(18)).mul(new BN(50)), // + true + ); + // console.log( + // `required RBTC collateral to borrow 100 USD with 50% margin: ${collateralTokenSent}` + // ); + + const durationInSeconds = 60 * 60 * 24 * 10; //10 days + collateralTokenSent = await loanToken.getDepositAmountForBorrow( + withdrawAmount, + durationInSeconds, + RBTC.address + ); + + // console.log( + // `required RBTC collateral to borrow 100 USD using loanToken.getDepositAmountForBorrow for 10 days: ${collateralTokenSent}` + // ); + + const { rate: exchange_rate, precision } = await priceFeeds.queryRate( + RBTC.address, + SUSD.address + ); + // console.log(`ex rate: ${exchange_rate}`); + + // approve the transfer of the collateral + await RBTC.approve(loanToken.address, collateralTokenSent.muln(2)); + const borrower = accounts[0]; + + const { receipt } = await loanToken.borrow( + "0x0", // bytes32 loanId + withdrawAmount, // uint256 withdrawAmount + durationInSeconds, // uint256 initialLoanDuration + collateralTokenSent.muln(2), // uint256 collateralTokenSent + RBTC.address, // address collateralTokenAddress + borrower, // address borrower + account1, // address receiver + "0x0" // bytes memory loanDataBytes + ); + + let decode = decodeLogs(receipt.rawLogs, LoanOpenings, "Borrow"); + // console.log(decode); + const loanId = decode[0].args["loanId"]; + + const maxDrawdown = await priceFeeds.getMaxDrawdown( + SUSD.address, + RBTC.address, + withdrawAmount, + collateralTokenSent.muln(2), + wei("20", "ether") + ); + + const borrowAmountForMaxDrawdown = await loanToken.getBorrowAmountForDeposit( + maxDrawdown, + durationInSeconds, + RBTC.address + ); + + const requiredCollateral = await loanToken.getDepositAmountForBorrow( + borrowAmountForMaxDrawdown, + durationInSeconds, + RBTC.address + ); + + // const coef = requiredCollateral.mul(oneEth).div(maxDrawdown); + // const adjustedBorrowAmount = borrowAmountForMaxDrawdown.div(coef).mul(oneEth); + + // console.log(`maxDrawdown: ${maxDrawdown}`); + // console.log(`borrowAmount for maxDrawdown: ${borrowAmountForMaxDrawdown}`); + // console.log( + // `requiredCollateral for borrowAmount for maxDrawdown: ${requiredCollateral}` + // ); + // console.log(`coef = requiredCollateral.mul(oneEth).div(maxDrawdown): ${coef}`); + // console.log(`adjustedBorrowAmount: ${adjustedBorrowAmount}`); + + await expectRevert( + loanToken.borrow( + loanId, // bytes32 loanId + borrowAmountForMaxDrawdown.muln(1.009), // uint256 withdrawAmount - less than 0.9% error tolerance + durationInSeconds, // uint256 initialLoanDuration + new BN(0), // uint256 collateralTokenSent + RBTC.address, // address collateralTokenAddress + borrower, // address borrower + account1, // address receiver + "0x0" // bytes memory loanDataBytes + ), + "collateral insufficient" + ); + + const { receipt: receipt2 } = await loanToken.borrow( + loanId, // bytes32 loanId + borrowAmountForMaxDrawdown, // uint256 withdrawAmount + durationInSeconds, // uint256 initialLoanDuration + new BN(0), // uint256 collateralTokenSent + RBTC.address, // address collateralTokenAddress + borrower, // address borrower + account1, // address receiver + "0x0" // bytes memory loanDataBytes + ); + + decode = decodeLogs(receipt2.rawLogs, LoanOpenings, "Borrow"); + const currentMargin = decode[0].args["currentMargin"]; + expect(ethers.BigNumber.from(currentMargin).gte(wei("15", "ether")), "Invalid margin"); // wei("15", "ether") - maintenance margin + //console.log(decode); + }); + + it("Test increasing existing loan debt by borrowing collateral < required collateral", async () => { + // prepare the test + + await lend_to_pool(loanToken, SUSD, owner); + await set_demand_curve(loanToken); + + // determine borrowing parameter + const withdrawAmount = oneEth.mul(new BN(100)); // I want to borrow 100 USD + // compute the required collateral. params: address loanToken, address collateralToken, uint256 newPrincipal,uint256 marginAmount, bool isTorqueLoan + let collateralTokenSent = await sovryn.getRequiredCollateral( + SUSD.address, + RBTC.address, + withdrawAmount, + wei("20", "ether"), // <- minInitialMargin // new BN(10).pow(new BN(18)).mul(new BN(50)), // + true + ); + // console.log( + // `required RBTC collateral to borrow 100 USD with 50% margin: ${collateralTokenSent}` + // ); + + const durationInSeconds = 60 * 60 * 24 * 10; //10 days + collateralTokenSent = await loanToken.getDepositAmountForBorrow( + withdrawAmount, + durationInSeconds, + RBTC.address + ); + + // console.log( + // `required RBTC collateral to borrow 100 USD using loanToken.getDepositAmountForBorrow for 10 days: ${collateralTokenSent}` + // ); + + const { rate: exchange_rate, precision } = await priceFeeds.queryRate( + RBTC.address, + SUSD.address + ); + // console.log(`ex rate: ${exchange_rate}`); + + // approve the transfer of the collateral + await RBTC.approve(loanToken.address, collateralTokenSent.muln(2)); + const borrower = accounts[0]; + + const { receipt } = await loanToken.borrow( + "0x0", // bytes32 loanId + withdrawAmount, // uint256 withdrawAmount + durationInSeconds, // uint256 initialLoanDuration + collateralTokenSent.muln(2), // uint256 collateralTokenSent + RBTC.address, // address collateralTokenAddress + borrower, // address borrower + account1, // address receiver + "0x0" // bytes memory loanDataBytes + ); + + let decode = decodeLogs(receipt.rawLogs, LoanOpenings, "Borrow"); + // console.log(decode); + const loanId = decode[0].args["loanId"]; + + const maxDrawdown = await priceFeeds.getMaxDrawdown( + SUSD.address, + RBTC.address, + withdrawAmount, + collateralTokenSent.muln(2), + wei("20", "ether") + ); + + const borrowAmountForMaxDrawdown = await loanToken.getBorrowAmountForDeposit( + maxDrawdown, + durationInSeconds, + RBTC.address + ); + + const requiredCollateral = await loanToken.getDepositAmountForBorrow( + borrowAmountForMaxDrawdown, + durationInSeconds, + RBTC.address + ); + + // const coef = requiredCollateral.mul(oneEth).div(maxDrawdown); + // const adjustedBorrowAmount = borrowAmountForMaxDrawdown.div(coef).mul(oneEth); + + // console.log(`maxDrawdown: ${maxDrawdown}`); + // console.log(`borrowAmount for maxDrawdown: ${borrowAmountForMaxDrawdown}`); + // console.log( + // `requiredCollateral for borrowAmount for maxDrawdown: ${requiredCollateral}` + // ); + // console.log(`coef = requiredCollateral.mul(oneEth).div(maxDrawdown): ${coef}`); + // console.log(`adjustedBorrowAmount: ${adjustedBorrowAmount}`); + + // approve the transfer of the collateral + await expectRevert( + loanToken.borrow( + loanId, // bytes32 loanId + borrowAmountForMaxDrawdown.muln(1.009), // uint256 withdrawAmount - less than 0.9% error tolerance + durationInSeconds, // uint256 initialLoanDuration + new BN(0), // uint256 collateralTokenSent + RBTC.address, // address collateralTokenAddress + borrower, // address borrower + account1, // address receiver + "0x0" // bytes memory loanDataBytes + ), + "collateral insufficient" + ); + + await RBTC.approve(loanToken.address, requiredCollateral.divn(2)); + const { receipt: receipt2 } = await loanToken.borrow( + loanId, // bytes32 loanId + borrowAmountForMaxDrawdown, // uint256 withdrawAmount + durationInSeconds, // uint256 initialLoanDuration + requiredCollateral.divn(2), // uint256 collateralTokenSent + RBTC.address, // address collateralTokenAddress + borrower, // address borrower + account1, // address receiver + "0x0" // bytes memory loanDataBytes + ); + + decode = decodeLogs(receipt2.rawLogs, LoanOpenings, "Borrow"); + const currentMargin = decode[0].args["currentMargin"]; + expect(ethers.BigNumber.from(currentMargin).gte(wei("15", "ether")), "Invalid margin"); // wei("15", "ether") - maintenance margin + //console.log(decode); + + const postMaxDrawdown = await priceFeeds.getMaxDrawdown( + SUSD.address, + RBTC.address, + withdrawAmount, + collateralTokenSent.muln(2), + wei("20", "ether") + ); + //console.log(`postMaxDrawdown: ${postMaxDrawdown}`); + expect(postMaxDrawdown.eq(maxDrawdown.divn(2))); + }); + // borrows some funds from account 0 and then takes out some more from account 2 with a marginTrade without paying should fail. it("Test margin trade from foreign loan should fail", async () => { // prepare the test diff --git a/tests/staking/PauseStaking.test.js b/tests/staking/PauseStaking.test.js index 5c36e7759..7139bfdba 100644 --- a/tests/staking/PauseStaking.test.js +++ b/tests/staking/PauseStaking.test.js @@ -438,7 +438,9 @@ contract("Staking", (accounts) => { "TeamVestingPartiallyCancelled" )[0].args; // last processed date = starIteration + ( (max_iterations - 1) * 1209600 ) // 1209600 is TWO_WEEKS - expect(decodedIncompleteEvent["lastProcessedDate"].toString()).to.equal( + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( startIteration .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) .toString() @@ -448,7 +450,7 @@ contract("Staking", (accounts) => { await staking.cancelTeamVesting( vesting.address, root, - new BN(decodedIncompleteEvent["lastProcessedDate"]).add(new BN(TWO_WEEKS)) + new BN(decodedIncompleteEvent["nextStartFrom"]) ); // verify amount @@ -489,6 +491,14 @@ contract("Staking", (accounts) => { let previousAmount = await token.balanceOf(root); let toStake = ONE_MILLON; + // Upgradable Vesting Registry + vestingRegistryLogic = await VestingRegistryLogic.new(); + vestingRegistry = await VestingRegistryProxy.new(); + await vestingRegistry.setImplementation(vestingRegistryLogic.address); + vestingRegistry = await VestingRegistryLogic.at(vestingRegistry.address); + + await staking.setVestingRegistry(vestingRegistry.address); + // Stake vesting = await Vesting.new( vestingLogic.address, @@ -499,7 +509,9 @@ contract("Staking", (accounts) => { 36 * WEEK, feeSharingCollectorProxy.address ); + vesting = await VestingLogic.at(vesting.address); + await staking.addContractCodeHash(vesting.address); await token.approve(vesting.address, toStake); await vesting.stakeTokens(toStake); @@ -518,6 +530,20 @@ contract("Staking", (accounts) => { "paused" ); // WS04 : frozen + const sampleVesting = vesting.address; + const vestingType = new BN(0); // TeamVesting + const vestingCreationType = new BN(3); + const vestingCreationAndTypes = { + isSet: true, + vestingType: vestingType.toString(), + vestingCreationType: vestingCreationType.toString(), + }; + + await vestingRegistry.registerVestingToVestingCreationAndTypes( + [sampleVesting], + [vestingCreationAndTypes] + ); + await staking.freezeUnfreeze(false); // Unfreeze // governance withdraw until duration must withdraw all staked tokens without fees let tx = await staking.governanceWithdrawVesting(vesting.address, root, { @@ -554,6 +580,14 @@ contract("Staking", (accounts) => { let previousAmount = await token.balanceOf(root); let toStake = ONE_MILLON; + // Upgradable Vesting Registry + vestingRegistryLogic = await VestingRegistryLogic.new(); + vestingRegistry = await VestingRegistryProxy.new(); + await vestingRegistry.setImplementation(vestingRegistryLogic.address); + vestingRegistry = await VestingRegistryLogic.at(vestingRegistry.address); + + await staking.setVestingRegistry(vestingRegistry.address); + // Stake vesting = await Vesting.new( vestingLogic.address, @@ -565,6 +599,7 @@ contract("Staking", (accounts) => { feeSharingCollectorProxy.address ); vesting = await VestingLogic.at(vesting.address); + await staking.addContractCodeHash(vesting.address); await token.approve(vesting.address, toStake); await vesting.stakeTokens(toStake); @@ -583,6 +618,20 @@ contract("Staking", (accounts) => { "paused" ); // WS04 : frozen + let sampleVesting = vesting.address; + let vestingType = new BN(0); // TeamVesting + let vestingCreationType = new BN(3); + let vestingCreationAndTypes = { + isSet: true, + vestingType: vestingType.toString(), + vestingCreationType: vestingCreationType.toString(), + }; + + await vestingRegistry.registerVestingToVestingCreationAndTypes( + [sampleVesting], + [vestingCreationAndTypes] + ); + await staking.freezeUnfreeze(false); // Unfreeze // governance withdraw until duration must withdraw all staked tokens without fees let tx = await staking.governanceWithdrawVesting(vesting.address, root, { @@ -620,10 +669,10 @@ contract("Staking", (accounts) => { await staking.setVestingRegistry(vestingRegistry.address); - const sampleVesting = vesting.address; - const vestingType = new BN(0); // TeamVesting - const vestingCreationType = new BN(3); - const vestingCreationAndTypes = { + sampleVesting = vesting.address; + vestingType = new BN(0); // TeamVesting + vestingCreationType = new BN(3); + vestingCreationAndTypes = { isSet: true, vestingType: vestingType.toString(), vestingCreationType: vestingCreationType.toString(), @@ -739,8 +788,11 @@ contract("Staking", (accounts) => { StakingWithdrawModule, "TeamVestingPartiallyCancelled" )[0].args; + // last processed date = starIteration + ( (max_iterations - 1) * 1209600 ) // 1209600 is TWO_WEEKS - expect(decodedIncompleteEvent["lastProcessedDate"].toString()).to.equal( + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( startIteration .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) .toString() @@ -750,7 +802,7 @@ contract("Staking", (accounts) => { await staking.cancelTeamVesting( vesting.address, root, - new BN(decodedIncompleteEvent["lastProcessedDate"]).add(new BN(TWO_WEEKS)) + new BN(decodedIncompleteEvent["nextStartFrom"]) ); // verify amount diff --git a/tests/vesting/Vesting.js b/tests/vesting/Vesting.js index 2a12d22de..a47b8f04e 100644 --- a/tests/vesting/Vesting.js +++ b/tests/vesting/Vesting.js @@ -40,6 +40,7 @@ const WEEK = new BN(7 * 24 * 60 * 60); const TOTAL_SUPPLY = "20000000000000000000000000"; const ONE_MILLON = "1000000000000000000000000"; const TWO_WEEKS = 1209600; +const FOUR_WEEKS = 2419200; const { ZERO_ADDRESS } = require("@openzeppelin/test-helpers/src/constants"); @@ -1001,7 +1002,9 @@ contract("Vesting", (accounts) => { expect(decodedIncompleteEvent["caller"]).to.equal(root); expect(decodedIncompleteEvent["receiver"]).to.equal(root); // last processed date = starIteration + ( (max_iterations - 1) * 1209600 ) // 1209600 is TWO_WEEKS - expect(decodedIncompleteEvent["lastProcessedDate"].toString()).to.equal( + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( startIteration .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) .toString() @@ -1048,16 +1051,16 @@ contract("Vesting", (accounts) => { expect(decodedIncompleteEvent["caller"]).to.equal(root); expect(decodedIncompleteEvent["receiver"]).to.equal(root); // last processed date = starIteration + ( (max_iterations - 1) * 1209600 ) // 1209600 is TWO_WEEKS - expect(decodedIncompleteEvent["lastProcessedDate"].toString()).to.equal( + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( startIteration .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) .toString() ); // Withdrawn another one (next start from should be added by TWO WEEKS) - const nextStartIteration = new BN(decodedIncompleteEvent["lastProcessedDate"]).add( - new BN(TWO_WEEKS) - ); + const nextStartIteration = new BN(decodedIncompleteEvent["nextStartFrom"]); const tx2 = await staking.cancelTeamVesting(vesting.address, root, nextStartIteration); decodedIncompleteEvent = decodeLogs( tx2.receipt.rawLogs, @@ -1067,7 +1070,9 @@ contract("Vesting", (accounts) => { expect(decodedIncompleteEvent["caller"]).to.equal(root); expect(decodedIncompleteEvent["receiver"]).to.equal(root); // last processed date = starIteration + ( (max_iterations - 1) * 1209600 ) // 1209600 is TWO_WEEKS - expect(decodedIncompleteEvent["lastProcessedDate"].toString()).to.equal( + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( nextStartIteration .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) .toString() @@ -1114,22 +1119,22 @@ contract("Vesting", (accounts) => { expect(decodedIncompleteEvent["caller"]).to.equal(root); expect(decodedIncompleteEvent["receiver"]).to.equal(root); // last processed date = starIteration + ( (max_iterations - 1) * 1209600 ) // 1209600 is TWO_WEEKS - expect(decodedIncompleteEvent["lastProcessedDate"].toString()).to.equal( + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( startIteration .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) .toString() ); // Withdrawn another one but skip 10 iterations - const nextStartIteration = new BN(decodedIncompleteEvent["lastProcessedDate"]).add( + const nextStartIteration = new BN(decodedIncompleteEvent["nextStartFrom"]).add( new BN(15).mul(new BN(TWO_WEEKS)) ); await staking.cancelTeamVesting(vesting.address, root, nextStartIteration); // Withdrawn skipped iterations - const skippedIterations = new BN(decodedIncompleteEvent["lastProcessedDate"]).add( - new BN(TWO_WEEKS) - ); + const skippedIterations = new BN(decodedIncompleteEvent["nextStartFrom"]); let block = await ethers.provider.getBlock("latest"); let currentBlockNumber = block.number; @@ -1186,7 +1191,9 @@ contract("Vesting", (accounts) => { )[0].args; expect(decodedIncompleteEvent["caller"]).to.equal(root); expect(decodedIncompleteEvent["receiver"]).to.equal(root); - expect(decodedIncompleteEvent["lastProcessedDate"].toString()).to.equal( + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( skippedIterations .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) .toString() @@ -1385,7 +1392,9 @@ contract("Vesting", (accounts) => { "TeamVestingPartiallyCancelled" )[0].args; // last processed date = starIteration + ( (max_iterations - 1) * 1209600 ) // 1209600 is TWO_WEEKS - expect(decodedIncompleteEvent["lastProcessedDate"].toString()).to.equal( + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( startIteration .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) .toString() @@ -1395,7 +1404,7 @@ contract("Vesting", (accounts) => { await staking.cancelTeamVesting( vesting.address, root, - new BN(decodedIncompleteEvent["lastProcessedDate"]).add(new BN(TWO_WEEKS)) + new BN(decodedIncompleteEvent["nextStartFrom"]) ); // verify amount @@ -1431,6 +1440,991 @@ contract("Vesting", (accounts) => { }); }); + describe("withdrawTokensStartingFrom", () => { + let vesting; + + it("should withdraw unlocked tokens (cliff = 3 weeks)", async () => { + // Save current amount + let previousAmount = await token.balanceOf(root); + let toStake = ONE_MILLON; + const cliff = 3 * WEEK; + const maxWithdrawIterations = 20; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + cliff, + 3 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + + await staking.setMaxVestingWithdrawIterations(maxWithdrawIterations); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + const start = await vesting.startDate(); + + let amountAfterStake = await token.balanceOf(root); + + // time travel + await increaseTimeEthers(3 * WEEK); + + // withdraw + // let tx = await vesting.withdrawTokens(root); + let tx = await vesting.withdrawTokensStartingFrom( + root, + start.add(new BN(cliff)), + maxWithdrawIterations + ); + + const endDate = await vesting.endDate(); + const regularEndDateWithMaxIterations = start.add( + new BN(FOUR_WEEKS).mul(new BN(maxWithdrawIterations).sub(new BN(1))) + ); + const expectedEnd = + regularEndDateWithMaxIterations < endDate + ? regularEndDateWithMaxIterations + : endDate; + + // check event + expectEvent(tx, "TokensWithdrawn", { + caller: root, + receiver: root, + }); + + // verify amount + let amount = await token.balanceOf(root); + + assert.equal( + previousAmount.sub(new BN(toStake)).toString(), + amountAfterStake.toString() + ); + assert.equal(previousAmount.toString(), amount.toString()); + }); + + it("should withdraw unlocked tokens", async () => { + // Save current amount + let previousAmount = await token.balanceOf(root); + let toStake = ONE_MILLON; + const cliff = 26 * WEEK; + const maxWithdrawIterations = 20; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + cliff, + 104 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + + await staking.setMaxVestingWithdrawIterations(maxWithdrawIterations); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + let amountAfterStake = await token.balanceOf(root); + + // time travel + await increaseTimeEthers(104 * WEEK); + + // withdraw + const start = await vesting.startDate(); + + let tx = await vesting.withdrawTokensStartingFrom( + root, + start.add(new BN(cliff)), + maxWithdrawIterations + ); + + // check event + expectEvent(tx, "TokensWithdrawn", { + caller: root, + receiver: root, + }); + + // verify amount + let amount = await token.balanceOf(root); + + assert.equal( + previousAmount.sub(new BN(toStake)).toString(), + amountAfterStake.toString() + ); + assert.equal(previousAmount.toString(), amount.toString()); + }); + + it("should withdraw unlocked tokens with multiple iteration", async () => { + // Save current amount + let previousAmount = await token.balanceOf(root); + let toStake = ONE_MILLON; + const cliff = 26 * WEEK; + let maxWithdrawIterations = 10; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + cliff, + 104 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + + await staking.setMaxVestingWithdrawIterations(maxWithdrawIterations); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + let amountAfterStake = await token.balanceOf(root); + + // time travel + await increaseTimeEthers(104 * WEEK); + + // withdraw + const start = await vesting.startDate(); + + let tx = await vesting.withdrawTokensStartingFrom( + root, + start.add(new BN(cliff)), + maxWithdrawIterations + ); + + const decodedIncompleteEvent = decodeLogs( + tx.receipt.rawLogs, + VestingLogic, + "TokensWithdrawn" + )[0].args; + await staking.setMaxVestingWithdrawIterations(15); + maxWithdrawIterations = 15; + let tx2 = await vesting.withdrawTokensStartingFrom( + root, + new BN(decodedIncompleteEvent["end"]), + maxWithdrawIterations + ); + + // check event + expectEvent(tx, "TokensWithdrawn", { + caller: root, + receiver: root, + }); + + expectEvent(tx2, "TokensWithdrawn", { + caller: root, + receiver: root, + }); + + // verify amount + let amount = await token.balanceOf(root); + + assert.equal( + previousAmount.sub(new BN(toStake)).toString(), + amountAfterStake.toString() + ); + assert.equal(previousAmount.toString(), amount.toString()); + }); + + it("should be able to withdraw all after the partial withdraw", async () => { + // Save current amount + let previousAmount = await token.balanceOf(root); + let toStake = ONE_MILLON; + const cliff = 26 * WEEK; + const maxWithdrawIterations = 10; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + cliff, + 104 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + + await staking.setMaxVestingWithdrawIterations(maxWithdrawIterations); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + let amountAfterStake = await token.balanceOf(root); + + // time travel + await increaseTimeEthers(104 * WEEK); + + // withdraw + const start = await vesting.startDate(); + + /** Withdraw Partial */ + let tx = await vesting.withdrawTokensStartingFrom( + root, + start.add(new BN(cliff)), + maxWithdrawIterations + ); + + /** Withdraw all */ + let tx2 = await vesting.withdrawTokens(root); + + // check event + expectEvent(tx, "TokensWithdrawn", { + caller: root, + receiver: root, + }); + + expectEvent(tx2, "TokensWithdrawn", { + caller: root, + receiver: root, + }); + + // verify amount + let amount = await token.balanceOf(root); + + assert.equal( + previousAmount.sub(new BN(toStake)).toString(), + amountAfterStake.toString() + ); + assert.equal(previousAmount.toString(), amount.toString()); + }); + + it("should withdraw unlocked tokens for 2 stakes", async () => { + // Save current amount + let previousAmount = await token.balanceOf(root); + let toStake = ONE_MILLON; + const cliff = 16 * WEEK; + const maxWithdrawIterations = 20; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + cliff, + 34 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + + await staking.setMaxVestingWithdrawIterations(maxWithdrawIterations); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + await increaseTimeEthers(20 * WEEK); + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + let amountAfterStake = await token.balanceOf(root); + + // time travel + await increaseTimeEthers(34 * WEEK); + + // withdraw + const start = await vesting.startDate(); + let tx = await vesting.withdrawTokensStartingFrom( + root, + start.add(new BN(cliff)), + maxWithdrawIterations + ); + + const endDate = await vesting.endDate(); + const regularEndDateWithMaxIterations = start.add( + new BN(FOUR_WEEKS).mul(new BN(maxWithdrawIterations).sub(new BN(1))) + ); + const expectedEnd = + regularEndDateWithMaxIterations < endDate + ? regularEndDateWithMaxIterations + : endDate; + + // check event + expectEvent(tx, "TokensWithdrawn", { + caller: root, + receiver: root, + startFrom: start.add(new BN(cliff)), + end: expectedEnd, + }); + + // verify amount + let amount = await token.balanceOf(root); + assert.equal( + previousAmount.sub(new BN(toStake).mul(new BN(2))).toString(), + amountAfterStake.toString() + ); + assert.equal(previousAmount.toString(), amount.toString()); + }); + + it("should withdraw unlocked tokens for 2 stakes (current time >= last locking date of the second stake)", async () => { + // Save current amount + let previousAmount = await token.balanceOf(root); + let toStake = ONE_MILLON; + const cliff = 4 * WEEK; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + cliff, + 20 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + + await staking.setMaxVestingWithdrawIterations(maxWithdrawIterations); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + await increaseTimeEthers(2 * WEEK); + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + let amountAfterStake = await token.balanceOf(root); + + // time travel + await increaseTimeEthers(20 * WEEK); + + // withdraw + const start = await vesting.startDate(); + let tx = await vesting.withdrawTokensStartingFrom( + root, + start.add(new BN(cliff)), + maxWithdrawIterations + ); + + const endDate = await vesting.endDate(); + const regularEndDateWithMaxIterations = start.add( + new BN(FOUR_WEEKS).mul(new BN(maxWithdrawIterations).sub(new BN(1))) + ); + const expectedEnd = + regularEndDateWithMaxIterations < endDate + ? regularEndDateWithMaxIterations + : endDate; + // check event + expectEvent(tx, "TokensWithdrawn", { + caller: root, + receiver: root, + startFrom: start.add(new BN(cliff)), + end: expectedEnd, + }); + + // verify amount + let amount = await token.balanceOf(root); + + assert.equal( + previousAmount.sub(new BN(toStake).mul(new BN(2))).toString(), + amountAfterStake.toString() + ); + + assert.equal(previousAmount.toString(), amount.toString()); + }); + + it("should withdraw unlocked tokens for 2 stakes (shouldn't withdraw the latest stake)", async () => { + // Save current amount + let previousAmount = await token.balanceOf(root); + let toStake = ONE_MILLON; + const cliff = 4 * WEEK; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + 4 * WEEK, + 20 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + + await staking.setMaxVestingWithdrawIterations(maxWithdrawIterations); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + await increaseTimeEthers(2 * WEEK); + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + let amountAfterStake = await token.balanceOf(root); + + // time travel + await increaseTimeEthers(18 * WEEK); + + // withdraw + const start = await vesting.startDate(); + await vesting.withdrawTokensStartingFrom( + root, + start.add(new BN(cliff)), + maxWithdrawIterations + ); + + let stakes = await staking.getStakes(vesting.address); + expect(stakes.dates.length).equal(1); + }); + + it("should do nothing if withdrawing a second time", async () => { + // This part should be tested on staking contract, function getPriorUserStakeByDate + let previousAmount = await token.balanceOf(root); + const start = await vesting.startDate(); + const cliff = await vesting.cliff(); + await vesting.withdrawTokensStartingFrom( + root, + start.add(cliff), + maxWithdrawIterations + ); + let amount = await token.balanceOf(root); + + assert.equal(previousAmount.toString(), amount.toString()); + }); + + it("should do n othing if withdrawing before reaching the cliff", async () => { + let toStake = ONE_MILLON; + const cliff = 26 * WEEK; + + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + a1, + cliff, + 104 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + + await staking.setMaxVestingWithdrawIterations(maxWithdrawIterations); + + let previousAmount = await token.balanceOf(root); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + let amountAfterStake = await token.balanceOf(root); + + // time travel + await increaseTimeEthers(25 * WEEK); + + const start = await vesting.startDate(); + await vesting.withdrawTokensStartingFrom( + root, + start.add(new BN(cliff)), + maxWithdrawIterations, + { from: a1 } + ); + let amount = await token.balanceOf(root); + + assert.equal( + previousAmount.sub(new BN(toStake)).toString(), + amountAfterStake.toString() + ); + assert.equal(amountAfterStake.toString(), amount.toString()); + }); + + it("should fail if the caller is neither owner nor token owner", async () => { + const start = await vesting.startDate(); + const cliff = await vesting.cliff(); + const startTime = start.add(cliff); + await expectRevert( + vesting.withdrawTokensStartingFrom(root, startTime, maxWithdrawIterations, { + from: a2, + }), + "unauthorized" + ); + await expectRevert( + vesting.withdrawTokensStartingFrom(root, startTime, maxWithdrawIterations, { + from: a3, + }), + "unauthorized" + ); + + await vesting.withdrawTokensStartingFrom(root, startTime, maxWithdrawIterations, { + from: root, + }); + await vesting.withdrawTokensStartingFrom(root, startTime, maxWithdrawIterations, { + from: a1, + }); + }); + + it("cancelTeamVesting should fail if recipient is zero address", async () => { + let toStake = ONE_MILLON; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + 26 * WEEK, + 142 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + await vestingReg.setTeamVesting(vesting.address, 0); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + await expectRevert( + staking.cancelTeamVesting(vesting.address, ZERO_ADDRESS, 0), + "receiver address invalid" + ); + }); + + it("cancelTeamVesting should emit incompletion event if greater the max iterations (with 0 starting iteration)", async () => { + let toStake = ONE_MILLON; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + 26 * WEEK, + 142 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + await vestingReg.setTeamVesting(vesting.address, 0); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + const getStartDate = vesting.startDate(); + const getCliff = vesting.cliff(); + const getMaxIterations = staking.getMaxVestingWithdrawIterations(); + + const [startDate, cliff, maxIterations] = await Promise.all([ + getStartDate, + getCliff, + getMaxIterations, + ]); + const startIteration = startDate.add(cliff); + + const { receipt } = await staking.cancelTeamVesting(vesting.address, root, 0); + + const decodedIncompleteEvent = decodeLogs( + receipt.rawLogs, + StakingWithdrawModule, + "TeamVestingPartiallyCancelled" + )[0].args; + expect(decodedIncompleteEvent["caller"]).to.equal(root); + expect(decodedIncompleteEvent["receiver"]).to.equal(root); + // last processed date = starIteration + ( (max_iterations - 1) * 1209600 ) // 1209600 is TWO_WEEKS + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( + startIteration + .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) + .toString() + ); + }); + + it("cancelTeamVesting utilizing lastProcessedDate from incompletion event", async () => { + let toStake = ONE_MILLON; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + 26 * WEEK, + 142 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + await vestingReg.setTeamVesting(vesting.address, 0); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + const getStartDate = vesting.startDate(); + const getCliff = vesting.cliff(); + const getMaxIterations = staking.getMaxVestingWithdrawIterations(); + + const [startDate, cliff, maxIterations] = await Promise.all([ + getStartDate, + getCliff, + getMaxIterations, + ]); + const startIteration = startDate.add(cliff); + + const tx = await staking.cancelTeamVesting(vesting.address, root, 0); + + let decodedIncompleteEvent = decodeLogs( + tx.receipt.rawLogs, + StakingWithdrawModule, + "TeamVestingPartiallyCancelled" + )[0].args; + expect(decodedIncompleteEvent["caller"]).to.equal(root); + expect(decodedIncompleteEvent["receiver"]).to.equal(root); + // last processed date = starIteration + ( (max_iterations - 1) * 1209600 ) // 1209600 is TWO_WEEKS + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( + startIteration + .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) + .toString() + ); + + // Withdrawn another one (next start from should be added by TWO WEEKS) + const nextStartIteration = new BN(decodedIncompleteEvent["nextStartFrom"]); + const tx2 = await staking.cancelTeamVesting(vesting.address, root, nextStartIteration); + decodedIncompleteEvent = decodeLogs( + tx2.receipt.rawLogs, + StakingWithdrawModule, + "TeamVestingPartiallyCancelled" + )[0].args; + expect(decodedIncompleteEvent["caller"]).to.equal(root); + expect(decodedIncompleteEvent["receiver"]).to.equal(root); + // last processed date = starIteration + ( (max_iterations - 1) * 1209600 ) // 1209600 is TWO_WEEKS + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( + nextStartIteration + .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) + .toString() + ); + }); + + it("cancelTeamVesting utilizing lastProcessedDate from incompletion event (should be able to retrieve reward for the accidental skip date)", async () => { + let toStake = ONE_MILLON; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + 26 * WEEK, + 142 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + await vestingReg.setTeamVesting(vesting.address, 0); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + const getStartDate = vesting.startDate(); + const getCliff = vesting.cliff(); + const getMaxIterations = staking.getMaxVestingWithdrawIterations(); + + const [startDate, cliff, maxIterations] = await Promise.all([ + getStartDate, + getCliff, + getMaxIterations, + ]); + const startIteration = startDate.add(cliff); + + const tx = await staking.cancelTeamVesting(vesting.address, root, 0); + + let decodedIncompleteEvent = decodeLogs( + tx.receipt.rawLogs, + StakingWithdrawModule, + "TeamVestingPartiallyCancelled" + )[0].args; + expect(decodedIncompleteEvent["caller"]).to.equal(root); + expect(decodedIncompleteEvent["receiver"]).to.equal(root); + // last processed date = starIteration + ( (max_iterations - 1) * 1209600 ) // 1209600 is TWO_WEEKS + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( + startIteration + .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) + .toString() + ); + + // Withdrawn another one but skip 10 iterations + const nextStartIteration = new BN(decodedIncompleteEvent["nextStartFrom"]) + .sub(new BN(TWO_WEEKS)) + .add(new BN(15).mul(new BN(TWO_WEEKS))); + await staking.cancelTeamVesting(vesting.address, root, nextStartIteration); + + // Withdrawn skipped iterations + const skippedIterations = new BN(decodedIncompleteEvent["nextStartFrom"]); + let block = await ethers.provider.getBlock("latest"); + let currentBlockNumber = block.number; + + const previousStake = await staking.getPriorUserStakeByDate( + vesting.address, + skippedIterations, + currentBlockNumber - 1 + ); + + expect(previousStake).to.be.bignumber.to.greaterThan(new BN(1)); + + const previousReceiverBalance = await token.balanceOf(root); + const previousTotalStakesForDate = []; + const previousVestingStakeByDate = []; + const previousStakeByDelegatee = []; + + for ( + let i = skippedIterations.toNumber(); + i < skippedIterations.add(maxIterations.mul(new BN(TWO_WEEKS))).toNumber(); + i += TWO_WEEKS + ) { + let lockedTS = await staking.timestampToLockDate(i); + // caching the stakeByDateForDelegatee for each lock dates before cancellation + previousStakeByDelegatee[i] = await staking.getPriorStakeByDateForDelegatee( + root, + lockedTS, + currentBlockNumber - 1 + ); + + // caching the totalStakesForDate for each lock dates before cancellation + previousTotalStakesForDate[i] = await staking.getPriorTotalStakesForDate( + lockedTS, + currentBlockNumber - 1 + ); + + // caching the vestingStakeByDate for each lock dates before cancellation + previousVestingStakeByDate[i] = await staking.getPriorVestingStakeByDate( + lockedTS, + currentBlockNumber - 1 + ); + } + + const tx2 = await staking.cancelTeamVesting(vesting.address, root, skippedIterations); + await increaseTimeEthers(1000); + + const latestReceiverBalance = await token.balanceOf(root); + + expect(latestReceiverBalance).to.be.bignumber.greaterThan(previousReceiverBalance); + + decodedIncompleteEvent = decodeLogs( + tx2.receipt.rawLogs, + StakingWithdrawModule, + "TeamVestingPartiallyCancelled" + )[0].args; + expect(decodedIncompleteEvent["caller"]).to.equal(root); + expect(decodedIncompleteEvent["receiver"]).to.equal(root); + expect( + new BN(decodedIncompleteEvent["nextStartFrom"]).sub(new BN(TWO_WEEKS)).toString() + ).to.equal( + skippedIterations + .add(new BN(maxIterations.sub(new BN(1))).mul(new BN(TWO_WEEKS))) + .toString() + ); + + block = await ethers.provider.getBlock("latest"); + currentBlockNumber = block.number; + const latestTotalStakesForDate = []; + const latestVestingStakeByDate = []; + const latestStakeByDelegatee = []; + + for ( + let i = skippedIterations.toNumber(); + i < skippedIterations.add(maxIterations.mul(new BN(TWO_WEEKS))).toNumber(); + i += TWO_WEEKS + ) { + let lockedTS = await staking.timestampToLockDate(i); + + const latestStake = await staking.getPriorUserStakeByDate( + vesting.address, + i, + currentBlockNumber - 1 + ); + + // caching the stakeByDateForDelegatee for each lock dates after cancellation + latestStakeByDelegatee[i] = await staking.getPriorStakeByDateForDelegatee( + root, + lockedTS, + currentBlockNumber - 1 + ); + + // caching the totalStakesForDate for each lock dates after cancellation + latestTotalStakesForDate[i] = await staking.getPriorTotalStakesForDate( + lockedTS, + currentBlockNumber - 1 + ); + + // caching the vestingStakeByDate for each lock dates after cancellation + latestVestingStakeByDate[i] = await staking.getPriorVestingStakeByDate( + lockedTS, + currentBlockNumber - 1 + ); + + // the stakeByDateForDelegatee will be decreased after cancellation + if (latestStakeByDelegatee[i] > 0 && previousStakeByDelegatee[i] > 0) { + expect(latestStakeByDelegatee[i]).to.be.bignumber.lessThan( + previousStakeByDelegatee[i] + ); + } + + // the totalStakesForDate will be decreased after cancellation + if (latestTotalStakesForDate[i] > 0 && previousTotalStakesForDate[i] > 0) { + expect(latestTotalStakesForDate[i]).to.be.bignumber.lessThan( + previousTotalStakesForDate[i] + ); + } + + // the vestingStakeByDate will be decreased after cancellation + if (latestVestingStakeByDate[i] > 0 && previousVestingStakeByDate[i] > 0) { + expect(latestVestingStakeByDate[i]).to.be.bignumber.lessThan( + previousVestingStakeByDate[i] + ); + } + + expect(latestStake.toString()).to.equal("1"); + } + }); + + it("should not allow other than team vesting to withdraw from cancelTeamVesting", async () => { + const WEEK = new BN(7 * 24 * 60 * 60); + let vestingLogic = await VestingLogic.new(); + let previousAmount = await token.balanceOf(root); + let toStake = 100; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + 16 * WEEK, + 38 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + await increaseTimeEthers(20 * WEEK); + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + // governance withdraw until duration must withdraw all staked tokens without fees + await expectRevert( + staking.cancelTeamVesting(vesting.address, root, 0), + "Only team vesting allowed" + ); + }); + + it("should withdraw unlocked tokens with all unlocked (endAt < vesting endDate)", async () => { + // Save current amount + let previousAmount = await token.balanceOf(root); + let toStake = ONE_MILLON; + const cliff = 26 * WEEK; + const maxWithdrawIterations = 20; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + cliff, + 104 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + + await staking.setMaxVestingWithdrawIterations(maxWithdrawIterations); + await staking.unlockAllTokens(); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + let amountAfterStake = await token.balanceOf(root); + + // time travel + await increaseTimeEthers(104 * WEEK); + + // withdraw + const start = await vesting.startDate(); + + let tx = await vesting.withdrawTokensStartingFrom( + root, + start.add(new BN(cliff)), + maxWithdrawIterations + ); + + // check event + expectEvent(tx, "TokensWithdrawn", { + caller: root, + receiver: root, + }); + + // verify amount + let amount = await token.balanceOf(root); + + assert.equal( + previousAmount.sub(new BN(toStake)).toString(), + amountAfterStake.toString() + ); + assert.equal(previousAmount.toString(), amount.toString()); + }); + + it("should withdraw unlocked tokens with all unlocked (endAt > vesting endDate)", async () => { + // Save current amount + let previousAmount = await token.balanceOf(root); + let toStake = ONE_MILLON; + const cliff = 26 * WEEK; + const maxWithdrawIterations = 20; + + // Stake + vesting = await Vesting.new( + vestingLogic.address, + token.address, + staking.address, + root, + cliff, + 104 * WEEK, + feeSharingCollectorProxy.address + ); + vesting = await VestingLogic.at(vesting.address); + + await staking.setMaxVestingWithdrawIterations(maxWithdrawIterations); + await staking.unlockAllTokens(); + + await token.approve(vesting.address, toStake); + await vesting.stakeTokens(toStake); + + let amountAfterStake = await token.balanceOf(root); + + // time travel + await increaseTimeEthers(104 * WEEK); + + // withdraw + const start = await vesting.startDate(); + + let tx = await vesting.withdrawTokensStartingFrom( + root, + start.add(new BN(cliff)), + maxWithdrawIterations * 105 // exceed the duration + ); + + // check event + expectEvent(tx, "TokensWithdrawn", { + caller: root, + receiver: root, + }); + + // verify amount + let amount = await token.balanceOf(root); + + assert.equal( + previousAmount.sub(new BN(toStake)).toString(), + amountAfterStake.toString() + ); + assert.equal(previousAmount.toString(), amount.toString()); + }); + }); + describe("collectDividends", async () => { it("should fail if the caller is neither owner nor token owner", async () => { let vesting = await Vesting.new(